【问题标题】:How can I create a `with-eval-after-load-all` in Emacs Lisp?如何在 Emacs Lisp 中创建“with-eval-after-load-all”?
【发布时间】:2019-06-30 03:14:34
【问题描述】:

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

【问题讨论】:

  • 看看函数eval-after-load - 它在运行时可能比宏更容易使用。
  • 也许您的问题可以通过提供一个需要 A 和B 的模块“my-module”来解决(或者遍历一个列表并全部需要它们)?这样你只需要(with-eval-after-load 'my-module ...)?
  • 不幸的是,我的用例与此相反。 A 和 B 可能尚未提供,在这种情况下 require 会发出错误信号。
  • 我目前正在为每个功能使用 with-eval-after-load 并使用谓词保护代码。这种工作,但除了需要知道是否提供了所有功能之外,谓词还需要知道其他 eval-after-loads 是否已执行其代码,如果是则不执行。一旦受保护的代码执行完毕,就会提供另一个功能,所以也许我可以对其进行测试,但这开始感觉像是一种竞争条件(或者至少我不确定 emacs 是如何处理这种事情的)。
  • 竞争条件是,受保护的代码是在调用其他 with-eval-after-loads 之前还是之后完成执行。

标签: macros elisp


【解决方案1】:
  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))))))

【讨论】:

    猜你喜欢
    • 2014-03-19
    • 1970-01-01
    • 2014-12-07
    • 1970-01-01
    • 2013-04-23
    • 1970-01-01
    • 2011-02-13
    • 1970-01-01
    • 2012-07-01
    相关资源
    最近更新 更多