Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create a `with-eval-after-load-all` in Emacs Lisp?

Tags:

macros

elisp

I'm trying to create something similar to with-eval-after-load except that the body evaluates after all features have been provided. Additionally, the feature list must be provided at runtime.

For example, I want something like

(setq feature-list '(a b))
(something feature-list (message "a and b both provided"))

where this performs functionality equivalent to

(with-eval-after-load 'a
  (with-eval-after-load 'b
    (message "a and b both provided")))

Providing the list at runtime seems to be the tricky part. Without that requirement I could write a macro:

(defmacro eval-after-load-all (features body)
  (if (null features)
      body
    `(with-eval-after-load (quote ,(car features))
       (eval-after-load-all ,(cdr features) ,body))))

and pass the list with:

(eval-after-load-all (a b) (message "a and b both provided"))

But passing it feature-list will cause it to use the literal characters "feature-list".

I've tried defining a recursive function:

(defun eval-after-load-all (features body)
  (if (null features)
      body
    (with-eval-after-load (car features)
      (eval-after-load-all (cdr features) body))))

But when I evaluate

(eval-after-load-all feature-list (message "a and b both provided"))
(provide 'a)
;; (provide 'b)

It triggers an error at the (provide 'a) call complaining about void-variable body in the recursive call step (i.e. last expression in the function). This scope confuses me. Why is body void here?

I also tried to wrap the macro in a function so that I could pass it the evaluated arguments:

(defun macro-wrapper (features body)
  (eval-after-load-all features body))

but this complains at function definition that features is not a list: wrong-type-argument listp features.

like image 785
MattHusz Avatar asked Dec 05 '25 08:12

MattHusz


1 Answers

  1. You may not use the symbol features as an argument since that is (I cite the doc of features):

    A list of symbols which are the features of the executing Emacs. Used by featurep and require, and altered by provide.

  2. The following code for eval-after-load-all works as expected. It is derived from your recursive function definition.
    I added the evaluation of the form as function or as expression with funcall or eval, respectively, I used the backquote for the lambda, and I introduced the quoting for the list and the expression in the generated lambda expression.
(defun eval-after-load-all (my-features form)
  "Run FORM after all MY-FEATURES are loaded.
See `eval-after-load' for the possible formats of FORM."
  (if (null my-features)
      (if (functionp form)
      (funcall form)
    (eval form))
    (eval-after-load (car my-features)
      `(lambda ()
     (eval-after-load-all
      (quote ,(cdr my-features))
      (quote ,form))))))
like image 109
Tobias Avatar answered Dec 08 '25 01:12

Tobias



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!