11

I was having fun adding some advice to a function:

(advice-add 'executable-find :around
            (lambda (f &rest args)
              (apply g args)))
               ;;;   ^

Ouch, a typo. Fixed it and evaluated above code again. But now I have both, the "corrected" and the "broken" advice around that function.

How do I get rid of these? Given that advice-remove needs either the function object or the around advice (which is empty here)?

(Obviously I can just quit and restart, but there's another way, is it?)

Drew
  • 75,699
  • 9
  • 109
  • 225
Daniel Jour
  • 415
  • 2
  • 10

3 Answers3

12

There's advice-mapc, which let's one iterate over all advices of some function, applying a given function to each. With it, it's easy to remove all advices:

(advice-mapc
  (lambda (adv prop)
    (advice-remove 'executable-find adv))
  'executable-find)

This could be extended to remove only advices which don't have a name property by looking in the second (props) argument (which is an alist) for those which do not have something associated to key name.

Daniel Jour
  • 415
  • 2
  • 10
7

You can also call advice-remove with the same lambda expression, i.e., replace advice-add with advice-remove and delete :around, then C-x C-e.

xuchunyang
  • 14,302
  • 1
  • 18
  • 39
  • This works! I thought it wouldn't, I assumed that (1) each time you evaluate a lambda form you get a new function not `eq` to the previous ones, (2) advice-remove would compare the function you pass it to the advices until it finds one that is `eq` to it and remove that, (3) even if advice-remove used a different test, like `equal`, it still wouldn't work, because different evaluations of a lambda form would not `equal` each other. Turns out (1) is correct, but (2) and (3) are wrong: advice-remove uses `equal`, and evaluating the same `lambda` twice produces `equal` results! – Omar Jun 06 '17 at 16:14
  • Noticed I didn't accept an answer back when I asked the question. I choose Yours because it's the IMO most helpful in the situation. – Daniel Jour Feb 24 '19 at 10:48
1

Here's some code to help doing just that, interactively.

This defines two functions. The first function gets the list of all advices on a given symbol, the second function interactively asks for a symbol and an advice on that symbol, then removes the latter from the former. As this all happens with completion, it's easier (to me) than copy pasting the lambda expression.

(defun yf/advice-list (symbol)
  (let (result)
    (advice-mapc
     (lambda (ad props)
       (push ad result))
     symbol)
    (nreverse result)))

(defun yf/kill-advice (symbol advice)
  "Kill ADVICE from SYMBOL."
  (interactive (let* ((sym (intern (completing-read "Function: " obarray #'yf/advice-list t)))
                      (advice (let ((advices-and-their-name
                                     (mapcar (lambda (ad) (cons (prin1-to-string ad)
                                                                ad))
                                             (yf/advice-list sym))))
                                (cdr (assoc (completing-read "Remove advice: " advices-and-their-name nil t)
                                            advices-and-their-name)))))
                 (list sym advice)))
  (advice-remove symbol advice))
YoungFrog
  • 3,496
  • 15
  • 27