nadvice.el: Make it easier to find how to change an interactive-form

* lisp/emacs-lisp/nadvice.el (advice--how-alist): Add ':interactive-only'.
* doc/lispref/functions.texi (Advice Combinators): Document it.
(Core Advising Primitives): Use it.
This commit is contained in:
Stefan Monnier 2026-05-04 20:21:31 -04:00
parent bc4a4500fc
commit ed1fe2ca95
3 changed files with 26 additions and 7 deletions

View file

@ -2100,6 +2100,7 @@ Call the function @var{f} for every piece of advice that was added to
and its properties. and its properties.
@end defun @end defun
@anchor{advice-eval-interactive-spec}
@defun advice-eval-interactive-spec spec @defun advice-eval-interactive-spec spec
Evaluate the interactive @var{spec} just like an interactive call to a function Evaluate the interactive @var{spec} just like an interactive call to a function
with such a spec would, and then return the corresponding list of arguments with such a spec would, and then return the corresponding list of arguments
@ -2112,7 +2113,7 @@ For instance, if you want to make the @kbd{C-x m}
could say something like this: could say something like this:
@example @example
(defun my-compose-mail-advice (orig &rest args) (defun my-compose-mail-advice (&rest _)
"Read From: address interactively." "Read From: address interactively."
(interactive (interactive
(lambda (spec) (lambda (spec)
@ -2126,9 +2127,10 @@ could say something like this:
;; Put the From header into the OTHER-HEADERS argument. ;; Put the From header into the OTHER-HEADERS argument.
(push (cons 'From from) (nth 2 spec)) (push (cons 'From from) (nth 2 spec))
spec))) spec)))
(apply orig args)) ;; This body is not used.
nil)
(advice-add 'compose-mail :around #'my-compose-mail-advice) (advice-add 'compose-mail :interactive-only #'my-compose-mail-advice)
@end example @end example
@end defun @end defun
@ -2148,8 +2150,8 @@ instead. This separate set of functions to manipulate pieces of advice applied
to named functions, offers the following extra features compared to to named functions, offers the following extra features compared to
@code{add-function}: they know how to deal with macros and autoloaded @code{add-function}: they know how to deal with macros and autoloaded
functions, they let @code{describe-function} preserve the original docstring as functions, they let @code{describe-function} preserve the original docstring as
well as document the added advice, and they let you add and remove advice well as document the added advice, and they let you add and remove
before a function is even defined. pieces of advice before a function is even defined.
@code{advice-add} can be useful for altering the behavior of existing calls @code{advice-add} can be useful for altering the behavior of existing calls
to an existing function without having to redefine the whole function. to an existing function without having to redefine the whole function.
@ -2338,8 +2340,18 @@ More specifically, the composition of the two functions behaves like:
@example @example
(lambda (&rest r) (funcall @var{function} (apply @var{oldfun} r))) (lambda (&rest r) (funcall @var{function} (apply @var{oldfun} r)))
@end example @end example
@end table
@item :interactive-only
While the @var{where} option controls how the body of the two functions
are composed, it does not actually affect the way interactive forms are
composed. So, in a sense, this does the opposite of @code{:override}:
call only the old function as if no advice was applied. But it still
affects the interactive form like any other @var{where} value would: The
interactive form of @var{function}, if any, overrides that of
@var{oldfun} and if it is a lambda expression, it receives
@var{function}'s interactive form as argument.
See @pxref{advice-eval-interactive-spec} for an example.
@end table
@node Porting Old Advice @node Porting Old Advice
@subsection Adapting code using the old defadvice @subsection Adapting code using the old defadvice

View file

@ -4601,6 +4601,12 @@ The response to SIGINT in interactive sessions is unaffected,
e.g. in a normal GUI session it still kills Emacs whereas in a terminal e.g. in a normal GUI session it still kills Emacs whereas in a terminal
it causes 'quit' since it is used for 'C-g'. it causes 'quit' since it is used for 'C-g'.
+++
** New ':interactive-only' way to add an advice.
While it is marginally more efficient than ':after' or ':before',
the main purpose it to make the intention more obvious when the advice
modifies only the interactive form and not the actual behavior
of the function.
* Changes in Emacs 31.1 on Non-Free Operating Systems * Changes in Emacs 31.1 on Non-Free Operating Systems

View file

@ -74,7 +74,8 @@
(:before-until (or (apply car r) (apply cdr r))) (:before-until (or (apply car r) (apply cdr r)))
(:before-while (and (apply car r) (apply cdr r))) (:before-while (and (apply car r) (apply cdr r)))
(:filter-args (apply cdr (funcall car r))) (:filter-args (apply cdr (funcall car r)))
(:filter-return (funcall car (apply cdr r)))) (:filter-return (funcall car (apply cdr r)))
(:interactive-only (apply cdr r)))
"List of descriptions of how to add a function. "List of descriptions of how to add a function.
Each element has the form (HOW OCL DOC) where HOW is a keyword, Each element has the form (HOW OCL DOC) where HOW is a keyword,
OCL is a \"prototype\" function of type `advice', and OCL is a \"prototype\" function of type `advice', and