Emacs Lisp: How to use ad-get-arg and ad-get-args?

2019-07-19 07:33发布

问题:

I'm not sure I am using ad-get-args and ad-get-arg right.

For example, the following code doesn't work.

(defun my-add (a b)
  (+ a b))
(defadvice my-add (after my-log-on activate)
  (message "my-add: %s" (ad-get-args)))
(my-add 1 2)

The last expression causes an error:

Debugger entered--Lisp error: (void-function ad-get-args).

The following doesn't work either.

(defun my-substract (a b)
  (- a b))
(defadvice my-substract (around my-log-on activate)
  (message "my-substract: %s" (ad-get-arg 0))
  (ad-do-it))
(my-substract 10 1)

The defadvice gives a warning:

Warning: `(setq ad-return-value (ad-Orig-my-substract a b))' is a malformed
    function

And the last expression gives an error:

Debugger entered--Lisp error: (invalid-function (setq ad-return-value (ad-Orig-my-substract a b)))
  (setq ad-return-value (ad-Orig-my-substract a b))()

I was trying to use defadvice to watch start-process arguments for debugging purposes and I found my way of using ad-get-arg didn't work.

Update: Answer,

From the answers it turns out that I should have used (ad-get-args 0) instead of (ad-get-args) in (defadvice my-add ..), and I should have used ad-do-it instead of (ad-do-it) in in (defadvice my-substract ..). And it's better to use trace-function.

回答1:

You have two problems in your code. First (as you noted), you're using ad-get-args incorrectly. The docs say:

(ad-get-args <position>) will return the list of actual arguments supplied starting at <position>.

It looks like what you want is:

(defadvice my-add (after my-log-on activate)
  (message "my-add: %s" (ad-get-args 0)))

In your my-subtract, the problem is your use of ad-do-it, you have it surrounded by parentheses, it should not be. This is the correct use:

(defadvice my-substract (around my-log-on activate)
  (message "my-substract: %s" (ad-get-arg 0))
  ad-do-it)

From the docs in the advice library:

An around advice can specify where the forms of the wrapped or surrounded forms should go with the special keyword ad-do-it, which will be substituted with a progn containing the forms of the surrounded code.

The best tutorial and introduction to advice I've found is in the advice library itself (in the comments in the beginning).

M-x find-library advice RET


回答2:

This works:

(defun my-add (a b) 
  (+ a b))

(defadvice my-add (after my-log-on activate) 
  (message "my-add: %d %d" (ad-get-arg 0) (ad-get-arg 1)))

(my-add 1 2) 

You have to consider the type of the argument you are retrieving, when passing it to the message function. I think the errors you are getting are obscured by the fact that they occur within advice. If the errors were not in advice, you'd see a clearer message, indicating a type mismatch.

When in doubt, or when you are passing an arg that is not a string to message, use (prin1-to-string arg)

like this:

(defadvice my-add (after my-log-on activate) 
  (message "my-add: %s %s"
           (prin1-to-string (ad-get-arg 0))
           (prin1-to-string (ad-get-arg 1))))


回答3:

There is no need to use ad-get-arg, you can use the same names in the body of the advice:

(defun my-add (a b)
  (+ a b))
(defadvice my-add (after my-add-log activate)
  (message "my-add: %d %d" a b))

Update:

If you just want to trace function calls for debugging purpose, emacs can generate a proper trace advice for you:

(defun my-add (a b)
  (+ a b))
(trace-function 'my-add)