GNU bug report logs - #62563
[FR] Expose `interactive' arg handling as an Elisp function

Previous Next

Package: emacs;

Reported by: Ruijie Yu <ruijie <at> netyu.xyz>

Date: Fri, 31 Mar 2023 07:29:01 UTC

Severity: wishlist

Tags: moreinfo

Done: Stefan Kangas <stefankangas <at> gmail.com>

Bug is archived. No further changes may be made.

To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 62563 in the body.
You can then email your comments to 62563 AT debbugs.gnu.org in the normal way.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-gnu-emacs <at> gnu.org:
bug#62563; Package emacs. (Fri, 31 Mar 2023 07:29:01 GMT) Full text and rfc822 format available.

Acknowledgement sent to Ruijie Yu <ruijie <at> netyu.xyz>:
New bug report received and forwarded. Copy sent to bug-gnu-emacs <at> gnu.org. (Fri, 31 Mar 2023 07:29:01 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Ruijie Yu <ruijie <at> netyu.xyz>
To: Emacs Bug Tracker <bug-gnu-emacs <at> gnu.org>
Subject: [FR] Expose `interactive' arg handling as an Elisp function
Date: Fri, 31 Mar 2023 15:27:47 +0800
Hello,

I find myself sometimes needing to manually write code that do the same
job as the string-form `interactive' would do, like "read for an
existing file name" (the "f" form), etc.  This happens because I want to
do the following conversion.  

--8<---------------cut here---------------start------------->8---
(defun foo (fname)
  (interactive "f")
  (ignore fname))

(defun foo (fname bar)
  (interactive
   (list (simulate-interactive-f)
         (get-bar)))
  (ignore fname bar))
--8<---------------cut here---------------end--------------->8---

In short, this is useful when I need to add an interactive argument that
is not already covered by interactive codes, so I have to use the more
verbose interactive list form.

Currently, the code that handles interactive codes is written as part of
`call-interactively'.  This is in src/callint.c,
DEFUN("call-interactively").

In fact, there is already _a way_ to do it (I consider it more like a
workaround).  However, I think my proposal might be more concise than
the workaround for readers.  And also more performant, since the
workaround unnecessarily creates a lambda and then extracts its
interactive form, only to make use of the result of its interactive
code.

--8<---------------cut here---------------start------------->8---
(call-interactively (lambda (f) (interactive "f") f))
--8<---------------cut here---------------end--------------->8---

If people are in favor of exposing the interactive codes, I imagine it
can be defined as `interactive-handle-code (code &optional prompt)', and
I would be able to do this:

--8<---------------cut here---------------start------------->8---
(interactive-handle-code ?f)
(interactive-handle-code ?M "Insert some random text: ")
;; etc
--8<---------------cut here---------------end--------------->8---

Alternatively, if we believe that my c-i + λ workaround is sufficiently
small, we could advise people in the same boat to follow suit?  That
implies modifying the `interactive' docstring and (info "(elisp)
Interactive Codes").

-- 
Best,


RY




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#62563; Package emacs. (Fri, 31 Mar 2023 07:39:01 GMT) Full text and rfc822 format available.

Message #8 received at 62563 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Ruijie Yu <ruijie <at> netyu.xyz>
Cc: 62563 <at> debbugs.gnu.org
Subject: Re: bug#62563: [FR] Expose `interactive' arg handling as an Elisp
 function
Date: Fri, 31 Mar 2023 10:38:21 +0300
> Date: Fri, 31 Mar 2023 15:27:47 +0800
> From:  Ruijie Yu via "Bug reports for GNU Emacs,
>  the Swiss army knife of text editors" <bug-gnu-emacs <at> gnu.org>
> 
> I find myself sometimes needing to manually write code that do the same
> job as the string-form `interactive' would do, like "read for an
> existing file name" (the "f" form), etc.  This happens because I want to
> do the following conversion.  
> 
> --8<---------------cut here---------------start------------->8---
> (defun foo (fname)
>   (interactive "f")
>   (ignore fname))
> 
> (defun foo (fname bar)
>   (interactive
>    (list (simulate-interactive-f)
>          (get-bar)))
>   (ignore fname bar))
> --8<---------------cut here---------------end--------------->8---
> 
> In short, this is useful when I need to add an interactive argument that
> is not already covered by interactive codes, so I have to use the more
> verbose interactive list form.

I don't think I understand the rationale, so please tell more.  The
interactive spec can be used like this:

  (interactive "bBuffer to rename: \nsRename buffer %s to: ")

So basically, you can prompt for anything using the 's' descriptor and
the following prompt string with %-constructs.  In what use cases is
this not enough, so much so that it would require exposing the guts of
this to Lisp?




Added tag(s) moreinfo. Request was from Stefan Kangas <stefankangas <at> gmail.com> to control <at> debbugs.gnu.org. (Mon, 04 Sep 2023 08:42:02 GMT) Full text and rfc822 format available.

Severity set to 'wishlist' from 'normal' Request was from Stefan Kangas <stefankangas <at> gmail.com> to control <at> debbugs.gnu.org. (Mon, 11 Sep 2023 23:55:01 GMT) Full text and rfc822 format available.

Reply sent to Stefan Kangas <stefankangas <at> gmail.com>:
You have taken responsibility. (Mon, 11 Sep 2023 23:56:02 GMT) Full text and rfc822 format available.

Notification sent to Ruijie Yu <ruijie <at> netyu.xyz>:
bug acknowledged by developer. (Mon, 11 Sep 2023 23:56:02 GMT) Full text and rfc822 format available.

Message #17 received at 62563-done <at> debbugs.gnu.org (full text, mbox):

From: Stefan Kangas <stefankangas <at> gmail.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: Ruijie Yu <ruijie <at> netyu.xyz>, 62563-done <at> debbugs.gnu.org
Subject: Re: bug#62563: [FR] Expose `interactive' arg handling as an Elisp
 function
Date: Mon, 11 Sep 2023 16:54:50 -0700
Eli Zaretskii <eliz <at> gnu.org> writes:

>> Date: Fri, 31 Mar 2023 15:27:47 +0800
>> From:  Ruijie Yu via "Bug reports for GNU Emacs,
>>  the Swiss army knife of text editors" <bug-gnu-emacs <at> gnu.org>
>>
>> I find myself sometimes needing to manually write code that do the same
>> job as the string-form `interactive' would do, like "read for an
>> existing file name" (the "f" form), etc.  This happens because I want to
>> do the following conversion.
>>
>> --8<---------------cut here---------------start------------->8---
>> (defun foo (fname)
>>   (interactive "f")
>>   (ignore fname))
>>
>> (defun foo (fname bar)
>>   (interactive
>>    (list (simulate-interactive-f)
>>          (get-bar)))
>>   (ignore fname bar))
>> --8<---------------cut here---------------end--------------->8---
>>
>> In short, this is useful when I need to add an interactive argument that
>> is not already covered by interactive codes, so I have to use the more
>> verbose interactive list form.
>
> I don't think I understand the rationale, so please tell more.  The
> interactive spec can be used like this:
>
>   (interactive "bBuffer to rename: \nsRename buffer %s to: ")
>
> So basically, you can prompt for anything using the 's' descriptor and
> the following prompt string with %-constructs.  In what use cases is
> this not enough, so much so that it would require exposing the guts of
> this to Lisp?

More information was requested, but none was given within 6 months, so
I'm closing this bug.  If this is still an issue, please reply to this
email (use "Reply to all" in your email client) and we can reopen the
bug report.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#62563; Package emacs. (Sun, 17 Sep 2023 00:51:02 GMT) Full text and rfc822 format available.

Message #20 received at 62563 <at> debbugs.gnu.org (full text, mbox):

From: Michael Heerdegen <michael_heerdegen <at> web.de>
To: 62563 <at> debbugs.gnu.org
Cc: ruijie <at> netyu.xyz, stefankangas <at> gmail.com
Subject: Re: bug#62563: [FR] Expose `interactive' arg handling as an Elisp
 function
Date: Sun, 17 Sep 2023 02:50:12 +0200
Stefan Kangas <stefankangas <at> gmail.com> writes:

> >> --8<---------------cut here---------------start------------->8---
> >> (defun foo (fname)
> >>   (interactive "f")
> >>   (ignore fname))
> >>
> >> (defun foo (fname bar)
> >>   (interactive
> >>    (list (simulate-interactive-f)
> >>          (get-bar)))
> >>   (ignore fname bar))
> >> --8<---------------cut here---------------end--------------->8---

Something like this can be useful if you need to read an additional
argument in a way that involves the need to run some Lisp, where using a
normal code letter is not enough.  Then you need to substitute the other
code letters you still want to have been read also with Lisp code.  Is
that understandable?

We have `advice-eval-interactive-spec' which can be used like
(advice-eval-interactive-spec "f") - that comes very close to what is
requested here.  Combined with `interactive-form' one can use this to
simulate the argument reading from a given command from Lisp.

`advice-eval-interactive-spec' has a FIXME:

| ;; FIXME: How about renaming this to just `eval-interactive-spec'?
| ;; It's not specific to the advice system.

Any opinions whether we want to do that?  If the implementation is not
something ugly (it probably is, a bit, though), I would vote for it.

Michael.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#62563; Package emacs. (Sun, 17 Sep 2023 11:33:01 GMT) Full text and rfc822 format available.

Message #23 received at 62563 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Kangas <stefankangas <at> gmail.com>
To: Michael Heerdegen <michael_heerdegen <at> web.de>, 62563 <at> debbugs.gnu.org
Subject: Re: bug#62563: [FR] Expose `interactive' arg handling as an Elisp
 function
Date: Sun, 17 Sep 2023 04:31:57 -0700
Michael Heerdegen <michael_heerdegen <at> web.de> writes:

> Stefan Kangas <stefankangas <at> gmail.com> writes:
>
>> >> --8<---------------cut here---------------start------------->8---
>> >> (defun foo (fname)
>> >>   (interactive "f")
>> >>   (ignore fname))
>> >>
>> >> (defun foo (fname bar)
>> >>   (interactive
>> >>    (list (simulate-interactive-f)
>> >>          (get-bar)))
>> >>   (ignore fname bar))
>> >> --8<---------------cut here---------------end--------------->8---
>
> Something like this can be useful if you need to read an additional
> argument in a way that involves the need to run some Lisp, where using a
> normal code letter is not enough.  Then you need to substitute the other
> code letters you still want to have been read also with Lisp code.  Is
> that understandable?

Yes, I think that explanation is clear.

> We have `advice-eval-interactive-spec' which can be used like
> (advice-eval-interactive-spec "f") - that comes very close to what is
> requested here.  Combined with `interactive-form' one can use this to
> simulate the argument reading from a given command from Lisp.
>
> `advice-eval-interactive-spec' has a FIXME:
>
> | ;; FIXME: How about renaming this to just `eval-interactive-spec'?
> | ;; It's not specific to the advice system.
>
> Any opinions whether we want to do that?  If the implementation is not
> something ugly (it probably is, a bit, though), I would vote for it.

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.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#62563; Package emacs. (Mon, 18 Sep 2023 04:29:02 GMT) Full text and rfc822 format available.

Message #26 received at 62563 <at> debbugs.gnu.org (full text, mbox):

From: Michael Heerdegen <michael_heerdegen <at> web.de>
To: Stefan Kangas <stefankangas <at> gmail.com>
Cc: 62563 <at> debbugs.gnu.org
Subject: Re: bug#62563: [FR] Expose `interactive' arg handling as an Elisp
 function
Date: Mon, 18 Sep 2023 06:28:14 +0200
Stefan Kangas <stefankangas <at> gmail.com> 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.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#62563; Package emacs. (Tue, 19 Sep 2023 10:22:02 GMT) Full text and rfc822 format available.

Message #29 received at 62563 <at> debbugs.gnu.org (full text, mbox):

From: Richard Stallman <rms <at> gnu.org>
To: Stefan Kangas <stefankangas <at> gmail.com>
Cc: michael_heerdegen <at> web.de, 62563 <at> debbugs.gnu.org
Subject: Re: bug#62563: [FR] Expose `interactive' arg handling as an Elisp
 function
Date: Tue, 19 Sep 2023 06:21:04 -0400
[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

In general, each interactive spec can be programmed with Lisp code
inside `interactive'.  But maybe there are some exceptions, Which ones
are exceptions?  If we post the list of those, maybe we can provide a
simple specific solutions for them.

Also, maybe people will point out existing ways to handle some of the
codes that were first thought to be "missing".


-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)






bug archived. Request was from Debbugs Internal Request <help-debbugs <at> gnu.org> to internal_control <at> debbugs.gnu.org. (Tue, 17 Oct 2023 11:24:09 GMT) Full text and rfc822 format available.

This bug report was last modified 190 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.