6

私は前にしたい-インタラクティブな引数を使用するいくつかの関数をアドバイスします、例えばfind-dired

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

find-diredしかし、emacsはインタラクティブセッションの後でのみこのアドバイスを実行し、私は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:てください。それがまさにあなたがやろうとしていることだからです。

よく読んでみると、アドバイスがの形式である必要はなく、その形式でもかまいませ。これは、が特別に扱われている (そしてそうしなければならない) ためです。aroundbeforeafterinteractive

したがって、次のコードが機能します ( に注意してください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 's answerだと思います。

アドバイスは非常に魅力的なツールですが、使いすぎがちです。危険とまでは言いませんが、慎重に使用してください。独自の関数を作成してもうまくいかない場合に使用するのが最適なようです。たとえば、変更できないコードによって呼び出される関数の動作を変更する場合などです。この状況の良い例は、ここここ、およびここで見つけることができると思います(自分の角を鳴らすために)。

于 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)

defadvicewiki の説明にかかわらず、エンド ユーザーが使用する必要はほとんどありません。

編集:この場合、@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ます。の代わりに引数付きが使用されます。find-dired'("-iname '**'" . 10)find-argsaround-advice(dir args)before-advice

于 2013-01-30T15:45:04.230 に答える
0

eval-last-sexpdescribe-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)

この単純なケースでは、アドバイス関数に関連するオーバーヘッドは小さいですが、より現実的な状況では、アドバイスが効果を持つべきかどうかをできるだけ効率的にチェックし続けることがおそらく重要です。

于 2016-02-29T09:46:59.570 に答える