emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Setting global variables


From: Stefan Monnier
Subject: Re: Setting global variables
Date: Fri, 25 Feb 2022 13:01:51 -0500
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux)

>   > The idea is very much like advice-add/remove but for variables instead
>   > of functions.
> How would it work?

However we decide it should.

> is your ides to advise each function that uses `bar'?

I don't really know.  Last time I took a more serious look at it,
I ended up with the code below.


        Stefan


;;; Changing variables in general (not just function-valued ones)

;; TODO: Make it work for arbitrary gv-places?
;; TODO: Maybe use it or something similar to keep track of effects of
;;       loading a file (where `id' would be the file name)?

(defun advice-var--sym (var)
  (or (get var 'advice--var)
      (let ((sym (make-symbol "fun")))
        (put var 'advice--var sym)
        ;; FIXME: We store the ground value in the function cell so that it can
        ;; be easily accessed/changed without having to search for it hidden in
        ;; the middle of a function.
        (fset sym (default-value var))
        (set sym (lambda () (symbol-function sym)))
        sym)))

(defun advice-var--make-local (var sym)
  (when (and (not (local-variable-p sym))
             (local-variable-p var))
    (add-function :override (local sym)
                  ;; FIXME: Should we store this value in a more accessible
                  ;; place, like we do for the global default?
                  (let ((lv (symbol-value var))) (lambda () lv)))))

(defun advice-var--refresh (var sym)
  ;; (cl-assert (eq sym (advice-var--sym var)))
  (if (local-variable-p sym)
      (make-local-variable var)
    (kill-local-variable var))
  (set var (funcall (symbol-value sym))))

(defun advice-var-add (var f &optional id local)
  (let ((sym (advice-var--sym var))
        ;; FIXME: This small function which calls two other functions, combined
        ;; with the advice object in which it'll be placed, results in "many"
        ;; small functions calling other small functions.
        ;; This is not handled efficiently by our ELisp engine, neither in
        ;; terms of space nor in terms of time.
        (advice (lambda (orig-fun) (funcall f (funcall orig-fun))))
        (props (if id `((name . ,id)))))
    (when local (advice-var--make-local var sym))
    (if local (add-function :around (local sym) advice props)
      (add-function :around (symbol-value sym) advice props))
    (advice-var--refresh var sym)))

(defun advice-var-set (var val &optional id local)
  (let ((sym (advice-var--sym var))
        (props (if id `((name . ,id)))))
    (when local (advice-var--make-local var sym))
    (if local
        (add-function :override (local sym) (lambda () val) props)
      (add-function :override (symbol-value sym) (lambda () val) props))
    (advice-var--refresh var sym)))

(defun advice-var-unset (var f-or-id &optional local)
  (let ((sym (advice-var--sym var)))
    (if local
        (remove-function (local sym) f-or-id)
      (remove-function (symbol-value sym) f-or-id))
    (advice-var--refresh var sym)))






reply via email to

[Prev in Thread] Current Thread [Next in Thread]