如何在 Emacs Lisp 中创建"with-eval-after-load-all"?



我正在尝试创建类似于with-eval-after-load的东西,只是正文在提供所有功能后进行评估。此外,必须在运行时提供功能列表。

例如,我想要类似的东西

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

其中,它执行的功能等效于

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

在运行时提供列表似乎是棘手的部分。如果没有这个要求,我可以编写一个宏:

(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))))

并将列表传递:

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

但是feature-list传递它会导致它使用文字字符"功能列表"。

我尝试定义一个递归函数:

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

但是当我评估

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

它在(provide 'a)调用时触发错误,抱怨递归调用步骤(即函数中的最后一个表达式)中的void-variable body。这个范围让我感到困惑。为什么body在这里无效?

我还尝试将宏包装在一个函数中,以便我可以将计算的参数传递给它:

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

但这在函数定义中抱怨features不是一个列表:wrong-type-argument listp features

  1. 您不能使用符号features作为参数,因为那是(我引用features的文档):

    一个符号列表,这些符号是执行 Emacs 的特性。featureprequire使用,并被provide更改。

  2. 以下用于eval-after-load-all的代码按预期工作。它派生自递归函数定义。
    我分别将表单的求值添加为函数或表达式,分别带有funcalleval,我使用了 lambda 的反引号,并在生成的 lambda 表达式中引入了列表和表达式的引用。
(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))))))

最新更新