这个 Emacs Lisp 钩子函数从哪里得到它的参数?

Where does this Emacs Lisp hook function get its argument from?

我刚刚学习 emacs,遇到了一个 configuration that demonstrates quite a bit of the functionality I want in my own configuration. It uses init.el 作为 org 文件的入口点,该文件处理大量配置和大量文档。我对以下功能感到困惑:

(put 'after-save-hook 'safe-local-variable
       (lambda (value) (equal value '(org-babel-tangle t))))

我想我的理解是,这将 lambda 表达式的值放入 属性 名称 safe-local-variable 下的 after-save-hook 的 属性 列表中,并且如果一个值在传递给 safe-local-variable-p 函数时 returns 是一个非零值,则该值是安全的。然后这个 lambda 似乎在 value 和列表 (org-babel-tangle t) 之间进行相等比较,所以大概这意味着 value 只有在它等于列表 (org-babel-tangle t) 时才是安全的?

我难以理解的是双重的。首先,lambda 从哪里得到 value?其次,这一切到底在做什么?我在 after-save-hookorg-babel-tangle 上找不到的文档都没有为我阐明这一点。作者的评论说“早点标记安全变量,这样缠结就不会中断”,但我还是不明白。

参数为 value 的匿名函数从 after-save-hook 的值中获取其参数。

after-save-hook 是一个变量。它的值是一个钩子列表。

这段代码把匿名函数作为符号after-save-hooksafe-local-variable属性值,这样当after-save-hook被处理时就看它是否安全局部变量,调用该函数。该函数根据变量的当前值调用,after-save-hook.

参见 Elisp 手册,节点 File Local Variables

原因是文件 DESKTOP.org 以这一行开始:

# -*- after-save-hook: (org-babel-tangle t); -*-

也就是说,当您在 Emacs 中打开该文件时,after-save-hook 的本地值变为 (org-babel-tangle t)。因此,无论何时保存该文件,它都会不带任何参数地调用函数 org-babel-tangle,以生成一些 shell 脚本,例如scripts/screenshot.region.sh。 hook变量中的值t表示在调用了hook变量的local值中的所有函数后,run-hooks会去查看global after-save-hook 的值并调用其中列出的任何函数。

显然,允许任何文件将任意 Lisp 代码指定为 运行 将是一个安全漏洞,只有 Microsoft Word 宏才能解决,因此默认情况下,风险变量的文件本地设置将被忽略。由于我们知道这个特定值是安全的,* 我们使用了您所询问的 safe-local-variable 技巧。根据 documentation:

You can specify safe values for a variable with a ‘safe-local-variable’ property. The property has to be a function of one argument; any value is safe if the function returns non-‘nil’ given that value.

这就是我们这里的内容:

(lambda (value) (equal value '(org-babel-tangle t)))

这是一个接受一个参数的函数,并检查参数是否等于我们想要允许的特定值。 safe-local-variable-p 将在指定的文件本地值上调用此函数,并且仅当函数 returns 非零时才允许它。因此,value 将成为即将分配给 after-save-hook 的值。我们可以在 M-x ielm:

中看到
*** Welcome to IELM ***  Type (describe-mode) for help.
ELISP> (setq my-function (lambda (value) (equal value '(org-babel-tangle t))))
(lambda
  (value)
  (equal value
         '(org-babel-tangle t)))

ELISP> (funcall my-function '(org-babel-tangle t))
t
ELISP> (funcall my-function 'something-else)
nil

* 这样安全吗?...如果攻击者可以让您下载特制文件并 运行 org-babel-tangle ,他们可以使用您的用户权限覆盖文件系统中的任意文件。这不是在这种情况下发生的事情,只是需要注意的事情。