Using advice-add
from nadvice.el
, I am trying to add a :filter-args
advice to an interactive function. Is it somehow possible for it to detect, whether the advised function has been called interactively?
I was trying to use called-interactively-p
, but M-x describe-function called-interactively-p
says:
This function is very brittle, it may fail to return the intended result when the code is debugged, advised, or instrumented in some form. [...]
Instead of using this function, it is cleaner and more reliable to give your function an extra optional argument whose ‘interactive’ spec specifies non-nil unconditionally ("p" is a good way to do this), or via
(not (or executing-kbd-macro noninteractive))
.
Sadly, neither works:
- The brittleness of
called-interactively-p
makes it useless here; Only around advise will detect interactiveness correctly withcalled-interactively-p
, but then the original function doesn't see the interactive call that way anymore. - The suggested workaround is actually wrong.
noninteractive
determines whether the emacs session is interactive, not whether the command was called interactively.
Minimal working example for called-interactively-p
(defun tmpdemo-command (&rest args)
(interactive '(was called interactively))
(message "tmpdemo-command: %-3S %-3S"
(called-interactively-p)
(not (or executing-kbd-macro noninteractive)))
(message "%S" args))
(advice-add #'tmpdemo-command :around #'tmpdemo-around)
(advice-add #'tmpdemo-command :filter-args #'tmpdemo-filter-args)
(defun tmpdemo-around (oldfun &rest args)
(message "tmpdemo-around: %-3S %-3S"
(called-interactively-p)
(not (or executing-kbd-macro noninteractive)))
(apply oldfun args))
(defun tmpdemo-filter-args (args)
(message "tmpdemo-filter-args: %-3S %-3S"
(called-interactively-p)
(not (or executing-kbd-macro noninteractive)))
args)
When executing it interactively as M-x tmpdemo-command
:
tmpdemo-filter-args: nil t
tmpdemo-around: t t <-- Only the around advise sees the
tmpdemo-command: nil t expected result.
(was called interactively)
When running it non-interactively as (tmpdemo-command 'noninteractive)
tmpdemo-filter-args: nil t <-- the suggested workaround gives
tmpdemo-around: nil t the wrong result!!
tmpdemo-command: nil t
(noninteractive)