我想在之前建议一些使用交互式参数的函数,例如: find-dired
:
(defadvice find-dired (before eab-find-dired activate)
(message "before!")
(setq find-args '("-iname '**'" . 10)))
但emacs仅在find-dired
交互式会话后执行此建议,而我之前无法设置find-args
。如何解决矛盾?
UPD。请注意,defadvice
宏是deprecated。
答案 0 :(得分:8)
artscan用一个可行的答案回答了他自己的问题,但它有点不完整和误导。这也涉及'interactive
,它本身可能令人困惑 - 因为它看起来像是在命令体内定义的,但实际上在输入函数之前使用了 - 并且在执行任何建议之前(除非该建议有'interactive
个电话......)
documentation for advice缺少一些有助于这种情况的细节,因此更好的观察点实际上是来源:advice.el
。看一下,找到评论部分@ Foo games: An advice tutorial
。您还可以使用 M-x查找库建议RET 在Emacs中找到源代码。
具体而言,对于此问题,请查看标有advice.el
的{{1}}部分 - 因为这正是您要做的事情。
如果你仔细阅读,你会发现不的建议必须是@@ Advising interactive behavior:
形式,但也可以是around
。可以before
- 虽然这只是在寻找麻烦。这是因为after
是(并且必须)处理特殊。
因此,以下代码有效(请注意interactive
):
before
正如其他人建议的那样,可能更简洁的方法就是编写自己的函数,我认为最简单的方法是Lindydancer的answer。
建议是一个非常诱人的工具,但很容易过度使用。我不会说它很危险,但应该谨慎使用。当编写自己的函数不起作用时,似乎最好使用它 - 例如,更改由您无法修改的代码调用的函数的行为。我认为这种情况的好例子可以在here,here和here找到(我自己的号角)。
答案 1 :(得分:4)
Emacs在调用函数之前会选择interactive
规范。
一般来说,使用defadvice
是一个坏主意,所以我建议您定义自己的函数并将其绑定到适当的密钥。例如:
(defun my-find-dired ()
(interactive)
(let ((find-args '("-iname '**'" . 10)))
(call-interactively 'find-dired)))
当然,如果您认为此设置适用于find-dired
的所有来电,您也可以执行以下操作:
(setq find-args '("-iname '**'" . 10))
答案 2 :(得分:2)
为什么要建议互动功能?
您可以轻松定义自己的命令
(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)
尽管wiki告诉你,最终用户几乎不必使用defadvice
。
编辑:@ Lindydancer的答案在这个例子中更好,但我会在这里留下这个答案,以阻止未来的读者以这种人为的方式使用defadvice
答案 3 :(得分:1)
有效:
(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
的{{1}}替换:在表单中直接放置必要的表达式find-dired
而不是'("-iname '**'" . 10)
。使用带有参数find-args
的{{1}}代替around-advice
。
答案 4 :(得分:0)
我遇到了这个问题,寻找一种简单的方法来扩展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)
在这种简单的情况下,与建议功能相关的开销很小,但对于更现实的情况,尽可能高效地保持检查,建议是否应该产生效果可能很重要。