Search code examples
emacsdefadviceadvising-functions

Advising an emacs interactive function: before


I want to before-advice some function, which uses interactive arguments, e.g. find-dired:

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

But emacs executes this advice only after find-dired interactive session and I can't setup find-args before. How to resolve the contradiction?

Upd. Note that defadvice macro is deprecated.


Solution

  • artscan answered his own question with a workable answer, but it's a bit incomplete and misleading. This also involves 'interactive, which can be confusing in and of itself - in that it looks like it is defined inside the body of the command, but is actually used before the function is entered - and before any advice is executed (unless that advice has 'interactive calls...)

    The documentation for advice lacks a number of details that would help in this situation, so the better place to look is actually the source: advice.el. Look at that and find the comment section @ Foo games: An advice tutorial. You can also find the source in your Emacs itself with M-x find-library advice RET.

    Specifically, for this problem, look at the section in advice.el labeled @@ Advising interactive behavior: - because that's exactly what you're trying to do.

    If you read it closely, you'll notice that the advice does not need to be of the form around, but can be before as well, and it can be after - though that's just asking for trouble. This is because the interactive is (and has to be) treated special.

    So, the following code works (note the 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)))))
    

    Probably a cleaner way to do this, as others suggested, is writing your own function, and I think the easiest is Lindydancer's answer.

    Advice is a pretty enticing tool, but is easy to overuse. I wouldn't go as far as saying it is dangerous, but should be used sparingly. It seems to be best used when writing your own function doesn't work - for instance, changing the behavior of a function that is called by code you can't modify. I think good examples of this situation can be found here, here, and here (to toot my own horn).