用 Advice 修改函数大家都知道,但它也能用来修改命令的 Interactive Spec,从而改变命令参数的读取方式。规则如下:
(advice-add SYMBOL WHERE FUNCTION &optional PROPS)
(advice-add 'display-buffer :around #'his-tracing-function)
- 如果
FUNCTION没写 Interactive Spec 则继承SYMBOL的; - 如果
FUNCTION写了 Interactive Spec 则覆盖SYMBOL的; - 特例:如果
FUNCTION的 Interactive Spec 是个函数,则调用这个函数,参数是SYMBOL的 Interactive Spec。
相关文档见 add-function 的 Info 文档或者 Docstring,分别用 C-h S 和 C-h f。
下面举两个例子,分别对应情况 2 和情况 3:
例1 comint-run
比如 comint-run 这个命令这么写不会有补全:
(defun comint-run (program)
"..."
(interactive "sRun program: ")
...)
同样读取命令,应该跟 M-! (shell-command) 一样提供补全才对吗:
(define-advice comint-run (:before (_program) fix-interactive-form)
"Fix the original interactive form."
(interactive (list (read-shell-command "Run program: "))))
例2 goto-line
执行 goto-line 时希望能够预览当前行号:
图:左边默认没行号 V.S. 右边定制有行号
(define-advice goto-line (:before (&rest _) preview-line-number)
"Preview line number when prompting for line number.
Idea from URL `https://www.reddit.com/r/emacs/comments/as83e2/weekly_tipstricketc_thread/egu2sve'."
(interactive
(lambda (spec)
(if (and (boundp 'display-line-numbers) ; `display-line-numbers' was added in Emacs 26.1
(not display-line-numbers))
(unwind-protect
(progn (display-line-numbers-mode)
(advice-eval-interactive-spec spec))
(display-line-numbers-mode -1))
(advice-eval-interactive-spec spec)))))
