Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 615
artscan Avatar asked Jan 30 '13 14:01

artscan


2 Answers

Emacs picks up the interactive specification before it calls the function.

In general, it is a bad idea to use defadvice, so instead I would suggest that you define your own function and bind it to an appropriate key. For example:

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

Of course, you can also simply do the following, if you think that this setting is something that you want for all calls to find-dired:

(setq find-args '("-iname '**'" . 10))
like image 41
Lindydancer Avatar answered Sep 28 '22 08:09

Lindydancer


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

like image 71
Trey Jackson Avatar answered Sep 28 '22 09:09

Trey Jackson