Subject: bug#62563: [FR] Expose `interactive' arg handling as an Elisp function

From: Michael Heerdegen <[email-masked]>
Date: Mon, 18 Sep 2023 06:28:14 +0200

Stefan Kangas <[email-masked]> writes:

> Could you point to one (or more) examples of real code that would have
> been made significantly simpler by this?  The idea sounds good in
> theory, but it is important to understand if it will also be useful in
> practice.  That will give us a better basis for deciding if this is
> something we would want to add or not.

[ Note I only asked about renaming `advice-eval-interactive-spec' to
`eval-interactive-spec', not about adding something new.  Because the
function is not only useful in nadvice.el.  Dunno if I made that clear. ]

People can of course already use the name `advice-eval-interactive-spec'
- but it is probably not well known.

Ehm - examples, ok.  Whenever a package or config file wants to define a
variant of an existing command that needs to read in the same arguments
in the same order (i.e. the user wants to have multiple commands instead
of one, an additional definition, not an advice), one has to copy the
interactive spec of the original definition.  Or one can use
`advice-eval-interactive-spec'.  The body of the variant also may or may
not reuse the other function.  This is all very similar to defining
advices - only that it doesn't involve an advice, as I described.

When the variant of an existing command wants to skip reading one
argument, `advice-eval-interactive-spec' is not of much use.  But the
same is true of advices of interactive functions that want to skip
reading an argument.

In the Emacs sources it's possible to factor the interactive spec out
into its own defun and reuse it in several places.  So this kind of use
case is mostly relevant for external packages and user configurations.

Ok, you wanted a real life example.  In my init file I have a command
like this:

#+begin_src emacs-lisp
(defun my-dired-restrict-marks ()
  "Restrict marks using the following command.

Only files that are currently marked and are marked again with
the subsequent command will be marked afterwards.  Thereby only
`dired-marker-char' marked files are considered - other marks are
not touched.

The next key sequence can optionally be prefixed with key ! to
mean \"not\" - then only marked files that would _not_ be marked
again with the next command keep their mark [...]
  ...
  )
#+end_src

That way I can combine several marking commands to have files marked
fulfill more than one condition.  If I bind the above command to `&', I
can use * / & * % to mark directories whose name is matched by a certain
regexp, for example.

The implementation saves the current file marks, reads a key sequence,
determines the bound command, then evals the interactive spec to get the
arguments (it is better to do this using the original buffer state, this
is the important part here).

Then all marks are removed, the command is called with the read in
arguments (simply using `apply'), then the marks are merged with the
remembered marks.

A similar case is my command `my-profiler-profile-next-command': It
similarly reads in a key sequence and the according arguments using the
interactive spec, but only after that starts the profiler and calls the
body of the command.  This is nice if you want to avoid that the
argument reading messes the profiler results of the command's code.

Yes, such things, but admittedly, the large majority of calls of
`advice-eval-interactive-spec' is still for defining advices.

I also want to add that what I describe here is related, but not the
same as the request in the original report which, AFAIU, more asked
about a convenient way to simulate (interactive "f") conveniently from
Lisp.  If we would have access to the code reading in the individual
arguments that would be even nicer, but it's not possible in the general
case because the interactive spec returns a list that is the result of
any arbitrary code that returns a list (i.e. there is no separate code
for each single argument in every case).

I let you decide whether my examples are enough to justify this
renaming.  There are probably not that many use cases, still, there are
a few.

Michael.