该宏用于便捷地将建议函数 function 添加到存储在 place 中的函数上(see 广义变量)。
where 用于指定 function 与已有函数的组合方式,例如是在原函数之前执行,还是之后执行。两种函数的可用组合方式列表,see 建议的组合方式。
当修改一个变量(变量名通常以 -function 结尾)时,你可以指定 function 是全局生效,还是仅在当前缓冲区生效:
如果 place 只是一个符号,那么 function 会被添加到 place 的全局值上。
如果 place 是 (local symbol) 形式(其中 symbol 是返回变量名的表达式),
则 function 仅在当前缓冲区生效。
最后,如果你要修改词法变量,则需要使用 (var variable)。
通过 add-function 添加的每个函数,都可以附带一个属性关联列表 props。目前其中只有两个属性具有特殊含义:
name为这段建议(advice)指定一个名称,remove-function 可通过该名称识别要移除的函数。通常在 function 是匿名函数时使用。
depth用于指定当存在多段建议时,这些建议的执行顺序。默认深度为 0。深度为 100 表示这段建议应尽量放在最内层;深度为 −100 表示它应放在最外层。如果两段建议的深度相同,后添加的那段会位于外层。
对于 :before 类型的建议:
位于最外层表示它会最先执行,在其他所有建议之前;
位于最内层表示它刚好在原函数之前执行,与原函数之间没有其他建议。
对于 :after 类型的建议:
位于最内层表示它刚好在原函数之后执行,中间无其他建议;
位于最外层表示它会在最后执行,在所有其他建议之后。
对于 :override 类型的建议:
最内层的建议只会覆盖原函数,其他建议仍会对它生效;
最外层的建议不仅会覆盖原函数,还会覆盖所有其他已应用的建议。
若 function 非交互式函数,则组合后的函数会继承原函数的交互式规范(若原函数有定义);反之,组合后的函数会成为交互式函数,并使用 function 的交互式规范。有一个例外情况:如果 function 的交互式规范是一个函数(即 lambda 表达式或已定义的符号(fbound),而非普通表达式或字符串),那么组合函数的交互式规范会表现为调用该函数,并将原函数的交互式规范作为唯一参数传入。如需解析作为参数接收的这份规范,可使用 advice-eval-interactive-spec 函数。
注意:function 的交互式规范会作用于组合后的函数,因此它应遵循组合函数的调用约定,而非 function 自身的调用约定。在多数场景下这两者并无差异(因为调用约定完全相同),但对于 :around、:filter-args 和 :filter-return 类型的建议而言,这一点至关重要 —— 因为这些场景下 function 接收的参数,与存储在 place 中的原函数参数并不相同。
该宏用于将 function 从存储在 place 中的函数上移除。此操作仅在 function 是通过 add-function 添加到 place 时有效。
function 会通过 equal 函数与添加到 place 中的函数进行比较,以确保该逻辑对 lambda 表达式也能生效。此外,还会与添加到 place 的函数的 name 属性做比对 —— 这种方式比用 equal 比较 lambda 表达式更可靠。
若 advice 已存在于 function-def 中,则返回非 nil 值。与上文的 remove-function 类似,这里的 advice 不必是实际的函数,也可以是该段建议(advice)的 name 名称。
对所有添加到 function-def 中的建议片段,依次调用函数 f。调用 f 时会传入两个参数:建议函数本身,以及该建议的属性列表。
按照「带有该交互式规范的函数被交互式调用」的规则来解析 spec,并返回由此构建的参数列表。例如,(advice-eval-interactive-spec "r\nP")会返回一个包含三个元素的列表,其中包含选区的边界值和当前的前缀参数。
例如,如果你想让 C-x m(compose-mail)命令提示输入 ‘From:’ 邮件头,可以这样写:
(defun my-compose-mail-advice (orig &rest args)
"Read From: address interactively."
(interactive
(lambda (spec)
(let* ((user-mail-address
(completing-read "From: "
'("one.address@example.net"
"alternative.address@example.net")))
(from (message-make-from user-full-name
user-mail-address))
(spec (advice-eval-interactive-spec spec)))
;; Put the From header into the OTHER-HEADERS argument.
(push (cons 'From from) (nth 2 spec))
spec)))
(apply orig args))
(advice-add 'compose-mail :around #'my-compose-mail-advice)