我想预先建议一些使用交互式参数的函数,例如find-dired
:
(defadvice find-dired (before eab-find-dired activate)
(message "before!")
(setq find-args '("-iname '**'" . 10)))
但是 emacs 仅在find-dired
交互式会话之后执行此建议,而我之前无法设置find-args
。如何化解矛盾?
更新。请注意,不推荐使用defadvice
宏。
我想预先建议一些使用交互式参数的函数,例如find-dired
:
(defadvice find-dired (before eab-find-dired activate)
(message "before!")
(setq find-args '("-iname '**'" . 10)))
但是 emacs 仅在find-dired
交互式会话之后执行此建议,而我之前无法设置find-args
。如何化解矛盾?
更新。请注意,不推荐使用defadvice
宏。
artscan用一个可行的答案回答了他自己的问题,但这有点不完整和误导。这也涉及'interactive
,它本身可能会令人困惑 - 因为它看起来像是在命令主体内定义的,但实际上是在输入函数之前使用的 - 并且在执行任何建议之前(除非建议有'interactive
调用...)
建议的文档缺少在这种情况下会有所帮助的许多细节,因此更好的查看位置实际上是源:advice.el
. 看看那个并找到评论部分@ Foo games: An advice tutorial
。你也可以在你的 Emacs 中找到源代码M-x find-library advice RET。
具体来说,对于这个问题,请查看advice.el
标记部分@@ Advising interactive behavior:
- 因为这正是您想要做的。
如果你仔细阅读它,你会注意到建议不需要是这种形式around
,但也可以是before
,而且它也可以是after
——尽管那只是自找麻烦。这是因为interactive
(并且必须)被特殊对待。
因此,以下代码有效(注意before
):
(defadvice find-dired (before eab-find-dired (dir args) activate)
"ignore find-args, hard code \"-iname '**'\""
(interactive
(list (read-directory-name "Run find in directory: " nil "" t)
(read-string "Run find (with args): " '("-iname '**'" . 10)
'(find-args-history . 1)))))
正如其他人所建议的那样,可能一种更清洁的方法是编写自己的函数,我认为最简单的是Lindydancer的答案。
建议是一个非常诱人的工具,但很容易过度使用。我不会说它很危险,但应该谨慎使用。当编写自己的函数不起作用时,最好使用它 - 例如,更改由您无法修改的代码调用的函数的行为。我认为可以在此处、此处和此处(按我自己的号角)找到这种情况的好例子。
Emacsinteractive
在调用函数之前获取规范。
一般来说,使用 是一个坏主意defadvice
,因此我建议您定义自己的函数并将其绑定到适当的键。例如:
(defun my-find-dired ()
(interactive)
(let ((find-args '("-iname '**'" . 10)))
(call-interactively 'find-dired)))
当然,您也可以简单地执行以下操作,如果您认为此设置是您希望所有调用的内容find-dired
:
(setq find-args '("-iname '**'" . 10))
为什么要建议交互功能?
您可以轻松定义自己的命令
(defun find-dired-my-defaults (dir args)
"just like `find-dired' but with defaults."
(interactive
(list (read-directory-name "Run find in directory: " nil "" t)
(read-string "Run find (with args): " '("-iname '**'" . 1)
'(find-args-history . 1))))
(find-dired dir args))
如果它已经绑定在一个键映射中,您可以轻松地重新映射它:
(define-key foo-mode-map [remap find-dired] 'find-dired-my-defaults)
defadvice
尽管 wiki 告诉您什么,最终用户几乎不必使用。
编辑:@Lindydancer 的答案在这种情况下更好,但我将把这个答案留在这里,以阻止未来的读者defadvice
以这种人为的方式使用。
有用:
(defadvice find-dired (around eab-find-dired (dir args) activate)
(interactive
(list (read-directory-name "Run find in directory: " nil "" t)
(read-string "Run find (with args): " '("-iname '**'" . 10)
'(find-args-history . 1))))
ad-do-it)
我使用带有替换interactive form
的函数:直接在表单中放入必要的表达式。使用 with arguments而不是.find-dired
'("-iname '**'" . 10)
find-args
around-advice
(dir args)
before-advice
我遇到了这个问题,寻找一种简单的方法来扩展eval-last-sexp
,describe-function
和类似函数的交互行为,而不必为每个函数编写专门的建议函数。为此,我使用toggle-debug-on-error
和一个虚拟函数分析了交互式使用的调用堆栈(defun x () (interactive (list :interactiveform (error "Int"))))
。
call-interactively
.command-execute
,它调用call-interactively
.M-x COMMAND
时,函数名首先作为字符串传递给execute-extended-command
(这是由 调用的命令M-x
),然后调用command-execute
, ...根据interactive
表单的所有调用是否应受通知影响,或者仅直接热键或M-x
调用,可以建议这些功能之一,例如使用现代nadvice.el
界面:
(defun setup-var-advice (oldfun command &rest r)
(if (eq command 'save-buffer)
(let ((myvar t)) (apply oldfun command r)) ;; Advice sets up variable
(apply oldfun command r))) ;; Advice has no effect
(advice-add #'call-interactively :around #'setup-var-advice)
在这种简单的情况下,与通知功能相关的开销很小,但对于更实际的情况,保持检查通知是否应该有效可能很重要。