Fri, 15 Aug 2008
< Fun With Emacs: Unicode and #'describe-char | MAIN | Fun with Lisp: notf and cdrf >
Fun with Emacs: eval-after-load*
Archives
Ok, suppose you want to evaluate a particular bit of code after emacs loads a particular emacs-lisp file, but you want to pass values of local variables into that code. The function eval-after-load makes you quote the expression and doesn't allow passing values into the expression. How about this?
(require 'cl)
(defmacro* eval-after-load* (file varlist &rest body)
"Like `eval-after-load', but bind variables according to VARLIST in
the current environment of the `eval-after-load' expression, not the
environment when BODY is evaluated. This allows easy passing of values
into BODY.
Each element of VARLIST is a symbol (which is bound to the current value
of that symbol) or a list (SYMBOL VALUEFORM) (which binds SYMBOL to the
value of VALUEFORM in the environment of the `eval-after-load' expression."
`(eval-after-load ,file
'(let ,(loop for v in varlist
collect (if (symbolp v)
`(,v ,(eval v))
`(,(car v) ,(eval (cadr v))))
into new-varlist
finally return new-varlist) ,@body)))
(put 'eval-after-load* 'lisp-indent-function
(1+ (get 'eval-after-load 'lisp-indent-function)))
Here's a contrived example which demonstrates when things happen.
(let ((f (make-temp-file "tkb-madness" nil ".el"))
(x 1))
(unwind-protect
(progn
(save-excursion
(let ((buf (find-file f)))
(insert (format "(y-or-n-p \"In the file '%s'! \")" f))
(save-buffer)
(kill-buffer buf)))
(y-or-n-p "This happens before the eval-after-load*")
(eval-after-load* f
(x
(y (y-or-n-p "This happens when the eval-after-load* is executed?"))
(z 2))
(y-or-n-p (format "x: %d y: %S z: %d" x y z))
(y-or-n-p "This happends during the delayed expressions"))
(y-or-n-p "This happens after the eval-after-load* expression")
(load f))
(when (file-exists-p f) (delete-file f))))
You should see something like:
Wrote /tmp/tkb-madness88647vuE.el This happens before the eval-after-load*(y or n) This happens when the eval-after-load* is executed?(y or n) This happens after the eval-after-load* expression(y or n) Loading /tmp/tkb-madness88647vuE.el (source)... In the file '/tmp/tkb-madness88647vuE.el'! (y or n) x: 1 y: t z: 2(y or n) This happends during the delayed expressions(y or n) Loading /tmp/tkb-madness88647vuE.el (source)...done
(y-or-n-p is used instead of message so you see each message when it happens.)
Does the eval-after-load* macro make sense?