6

我想预先建议一些使用交互式参数的函数,例如find-dired

(defadvice find-dired (before eab-find-dired activate)
  (message "before!")
  (setq find-args '("-iname '**'" . 10)))

但是 emacs 仅在find-dired交互式会话之后执行此建议,而我之前无法设置find-args。如何化解矛盾?

更新。请注意,不推荐使用defadvice宏。

4

5 回答 5

9

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答案

建议是一个非常诱人的工具,但很容易过度使用。我不会说它很危险,但应该谨慎使用。当编写自己的函数不起作用时,最好使用它 - 例如,更改由您无法修改的代码调用的函数的行为。我认为可以在此处此处此处(按我自己的号角)找到这种情况的好例子。

于 2013-01-30T17:07:27.227 回答
5

Emacsinteractive在调用函数之前获取规范。

一般来说,使用 是一个坏主意defadvice,因此我建议您定义自己的函数并将其绑定到适当的键。例如:

(defun my-find-dired ()
  (interactive)
  (let ((find-args '("-iname '**'" . 10)))
    (call-interactively 'find-dired)))

当然,您也可以简单地执行以下操作,如果您认为此设置是您希望所有调用的内容find-dired

(setq find-args '("-iname '**'" . 10))
于 2013-01-30T15:41:54.707 回答
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)

defadvice尽管 wiki 告诉您什么,最终用户几乎不必使用。

编辑:@Lindydancer 的答案在这种情况下更好,但我将把这个答案留在这里,以阻止未来的读者defadvice以这种人为的方式使用。

于 2013-01-30T16:05:27.453 回答
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的函数:直接在表单中放入必要的表达式。使用 with arguments而不是.find-dired'("-iname '**'" . 10)find-argsaround-advice(dir args)before-advice

于 2013-01-30T15:45:04.230 回答
0

我遇到了这个问题,寻找一种简单的方法来扩展eval-last-sexp,describe-function和类似函数的交互行为,而不必为每个函数编写专门的建议函数。为此,我使用toggle-debug-on-error和一个虚拟函数分析了交互式使用的调用堆栈(defun x () (interactive (list :interactiveform (error "Int"))))

  • 交互使用总是需要调用call-interactively.
  • 当通过按下热键执行命令时,该命令被传递给command-execute,它调用call-interactively.
  • 当执行 asM-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)

在这种简单的情况下,与通知功能相关的开销很小,但对于更实际的情况,保持检查通知是否应该有效可能很重要。

于 2016-02-29T09:46:59.570 回答