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

时间:2019-06-30 03:14:34

标签: macros elisp

我正在尝试创建类似于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 个答案:

答案 0 :(得分:0)

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