GNU bug report logs - #78737
sit-for behavior changes when byte-compiled

Previous Next

Package: emacs;

Reported by: Daniel Colascione <dancol <at> dancol.org>

Date: Mon, 9 Jun 2025 20:50:02 UTC

Severity: normal

To reply to this bug, email your comments to 78737 AT debbugs.gnu.org.

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#78737; Package emacs. (Mon, 09 Jun 2025 20:50:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to Daniel Colascione <dancol <at> dancol.org>:
New bug report received and forwarded. Copy sent to bug-gnu-emacs <at> gnu.org. (Mon, 09 Jun 2025 20:50:02 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: bug-gnu-emacs <at> gnu.org
Subject: sit-for behavior changes when byte-compiled
Date: Mon, 09 Jun 2025 13:48:59 -0700
Consider (while-no-input (sit-for 100)).

Run it and press any key, say, f to terminate the wait. You'll see "f"
inserted wherever point was.

Now eval-defun on sit-for from subr.el and try (while-no-input (sit-for
100)) again. The "f" disappears.

Why? Because Fread_event returns with Vquit_flag set; the byte-compiled
sit-for is able to push the event onto Vunread_command_events before
Lisp does something quit-able, but the interpreted sit-for doesn't get
so far and loses Fread_event's return value.

Fread_event should probably look for Vquit_flag and !Vinhibit_quit and
in this case stick the event on Vunread_command_events itself and
return nil.

WDYT?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Tue, 10 Jun 2025 09:14:01 GMT) Full text and rfc822 format available.

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

From: Pip Cet <pipcet <at> protonmail.com>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Tue, 10 Jun 2025 09:13:03 +0000
"Daniel Colascione" <dancol <at> dancol.org> writes:

> Consider (while-no-input (sit-for 100)).
>
> Run it and press any key, say, f to terminate the wait. You'll see "f"
> inserted wherever point was.
>
> Now eval-defun on sit-for from subr.el and try (while-no-input (sit-for
> 100)) again. The "f" disappears.
>
> Why? Because Fread_event returns with Vquit_flag set; the byte-compiled
> sit-for is able to push the event onto Vunread_command_events before
> Lisp does something quit-able, but the interpreted sit-for doesn't get
> so far and loses Fread_event's return value.
>
> Fread_event should probably look for Vquit_flag and !Vinhibit_quit and
> in this case stick the event on Vunread_command_events itself and
> return nil.

Until we fix sit-for by adding a mechanism to peek at rather than read
and dequeue input events, would it be sufficient just to bind
inhibit-quit while reading and unreading the event?  It appears to work,
at least.

Pip





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Tue, 10 Jun 2025 09:33:06 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Pip Cet <pipcet <at> protonmail.com>
Cc: 78737 <at> debbugs.gnu.org
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Tue, 10 Jun 2025 02:32:50 -0700
Pip Cet <pipcet <at> protonmail.com> writes:

> "Daniel Colascione" <dancol <at> dancol.org> writes:
>
>> Consider (while-no-input (sit-for 100)).
>>
>> Run it and press any key, say, f to terminate the wait. You'll see "f"
>> inserted wherever point was.
>>
>> Now eval-defun on sit-for from subr.el and try (while-no-input (sit-for
>> 100)) again. The "f" disappears.
>>
>> Why? Because Fread_event returns with Vquit_flag set; the byte-compiled
>> sit-for is able to push the event onto Vunread_command_events before
>> Lisp does something quit-able, but the interpreted sit-for doesn't get
>> so far and loses Fread_event's return value.
>>
>> Fread_event should probably look for Vquit_flag and !Vinhibit_quit and
>> in this case stick the event on Vunread_command_events itself and
>> return nil.
>
> Until we fix sit-for by adding a mechanism to peek at rather than read
> and dequeue input events, would it be sufficient just to bind
> inhibit-quit while reading and unreading the event?  It appears to work,
> at least.

And the other callers of read-event?  Might as well just fix it at the source.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Tue, 10 Jun 2025 11:04:01 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Daniel Colascione <dancol <at> dancol.org>,
 Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Tue, 10 Jun 2025 14:03:22 +0300
> Cc: 78737 <at> debbugs.gnu.org
> From: Daniel Colascione <dancol <at> dancol.org>
> Date: Tue, 10 Jun 2025 02:32:50 -0700
> 
> Pip Cet <pipcet <at> protonmail.com> writes:
> 
> > "Daniel Colascione" <dancol <at> dancol.org> writes:
> >
> >> Consider (while-no-input (sit-for 100)).
> >>
> >> Run it and press any key, say, f to terminate the wait. You'll see "f"
> >> inserted wherever point was.
> >>
> >> Now eval-defun on sit-for from subr.el and try (while-no-input (sit-for
> >> 100)) again. The "f" disappears.
> >>
> >> Why? Because Fread_event returns with Vquit_flag set; the byte-compiled
> >> sit-for is able to push the event onto Vunread_command_events before
> >> Lisp does something quit-able, but the interpreted sit-for doesn't get
> >> so far and loses Fread_event's return value.
> >>
> >> Fread_event should probably look for Vquit_flag and !Vinhibit_quit and
> >> in this case stick the event on Vunread_command_events itself and
> >> return nil.
> >
> > Until we fix sit-for by adding a mechanism to peek at rather than read
> > and dequeue input events, would it be sufficient just to bind
> > inhibit-quit while reading and unreading the event?  It appears to work,
> > at least.
> 
> And the other callers of read-event?  Might as well just fix it at the source.

Stefan, any comments or suggestions?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Tue, 10 Jun 2025 11:23:03 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com,
 Daniel Colascione <dancol <at> dancol.org>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Tue, 10 Jun 2025 07:22:38 -0400
>> > Until we fix sit-for by adding a mechanism to peek at rather than read
>> > and dequeue input events, would it be sufficient just to bind
>> > inhibit-quit while reading and unreading the event?  It appears to work,
>> > at least.
>> 
>> And the other callers of read-event?  Might as well just fix it at the source.
>
> Stefan, any comments or suggestions?

As Pip says, it would be nice to have way to peek rather than
read+unread (the reason we don't AFAIK is that we don't just want to
peek at the next event but at "some" next event while ignoring
presumably irrelevant others, like mouse movements, so it's a bit less
trivial than it sounds).

Our handling of `inhibit-quit` is not very systematic, right now (and
we've recently seen some of the impact, with the patch for
`transient.el`).  E.g. it's bound while running timers but not while
running jit-lock code.  It's never really clear why it's done at one
place and not at others.

Maybe doing it whenever we're waiting for user input (i.e. in
`read_char`), like Daniel suggests, is not a bad idea and might be
closer to The Right Way to use `inhibit-quit`.

But then we need to make sure that when `read_char` returns a quit
event, the caller eventually acts on this event.


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Tue, 10 Jun 2025 15:08:05 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>, Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Tue, 10 Jun 2025 08:06:46 -0700

On June 10, 2025 4:22:38 AM PDT, Stefan Monnier <monnier <at> iro.umontreal.ca> wrote:
>>> > Until we fix sit-for by adding a mechanism to peek at rather than read
>>> > and dequeue input events, would it be sufficient just to bind
>>> > inhibit-quit while reading and unreading the event?  It appears to work,
>>> > at least.
>>> 
>>> And the other callers of read-event?  Might as well just fix it at the source.
>>
>> Stefan, any comments or suggestions?
>
>As Pip says, it would be nice to have way to peek rather than
>read+unread (the reason we don't AFAIK is that we don't just want to
>peek at the next event but at "some" next event while ignoring
>presumably irrelevant others, like mouse movements, so it's a bit less
>trivial than it sounds).
>
>Our handling of `inhibit-quit` is not very systematic, right now (and
>we've recently seen some of the impact, with the patch for
>`transient.el`).  E.g. it's bound while running timers but not while
>running jit-lock code.  It's never really clear why it's done at one
>place and not at others.

The disappearing C-g problem?

The right fix for the transient.el thing is not to randomly bind inhibit-quit around swaths of user code, but to make sure event reading functions return quit_char when the user presses them, just like we've documented read-key-sequence to do. 

IOW, C-g in the command loop can mean cmderror or does it mean C-g. How do you know? Roll the dice. The user cannot predict whether redisplay is going to run at the exact moment he whacks a key. This particular aspect of the system has been ambiguous for a long time (ever since redisplay got the ability to run Lisp?) and ultimately comes from C-g being overloaded in the first place.

That's *not* the same as just binding inhibit-quit around reading events like transient tries to do. The problem with binding inhibit-quit is that, well, you can't quit. Quitting restartable things that tend to get wedged like redisplay is useful. Instead, the event reading functions should internally translate quits.to quit_char returns even if a quit happened internally. And they definitely shouldn't return with quit-flag set.

This way, you can quit things that are useful to quit and not muck with things that aren't. Binding inhibit-quit around timers and filters remain useful because those aren't idempotent.






Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Tue, 10 Jun 2025 15:57:03 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Tue, 10 Jun 2025 18:56:22 +0300
> Date: Tue, 10 Jun 2025 08:06:46 -0700
> From: Daniel Colascione <dancol <at> dancol.org>
> CC: pipcet <at> protonmail.com, 78737 <at> debbugs.gnu.org
> 
> IOW, C-g in the command loop can mean cmderror or does it mean C-g. How do you know? Roll the dice. The user cannot predict whether redisplay is going to run at the exact moment he whacks a key. This particular aspect of the system has been ambiguous for a long time (ever since redisplay got the ability to run Lisp?) and ultimately comes from C-g being overloaded in the first place.

First, redisplay is not part of the command loop, at least not
conceptually: when redisplay runs, we don't respond to user input.

And second, where we call Lisp from redisplay and cannot tolerate C-g
(or don't think it would be useful), we bind inhibit-quit already.

So I don't think I follow what you are saying here.

> That's *not* the same as just binding inhibit-quit around reading events like transient tries to do. The problem with binding inhibit-quit is that, well, you can't quit. Quitting restartable things that tend to get wedged like redisplay is useful.

It might be useful in principle, but if you allow that, you'll have an
infinite redisplay loop on your hands.  Why? because quitting has the
side effect of showing "Quit" in the echo area, which re-enters
redisplay right away, and will then wedge the same way as the one from
which you wanted to escape.  And second, because it isn't restartable.

So aborting redisplay is tricky at best.  We have an optional feature,
by default off, which does that, see max-redisplay-ticks.  If you
follow how this is implemented when we decide to abort, you will see
it isn't simple.  And my personal experience from using this is that
sometimes you are left with a partially-redrawn screen that you (as
the user) don't always know how to fix.

> Instead, the event reading functions should internally translate quits.to quit_char returns even if a quit happened internally. And they definitely shouldn't return with quit-flag set.

How can this support breaking out of a runaway synchronous subprocess?
Or any of the similar situations which today we can interrupt with a
C-g? are we going to give up on them?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Tue, 10 Jun 2025 16:23:06 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Tue, 10 Jun 2025 09:21:56 -0700

On June 10, 2025 8:56:22 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
>> Date: Tue, 10 Jun 2025 08:06:46 -0700
>> From: Daniel Colascione <dancol <at> dancol.org>
>> CC: pipcet <at> protonmail.com, 78737 <at> debbugs.gnu.org
>> 
>> IOW, C-g in the command loop can mean cmderror or does it mean C-g. How do you know? Roll the dice. The user cannot predict whether redisplay is going to run at the exact moment he whacks a key. This particular aspect of the system has been ambiguous for a long time (ever since redisplay got the ability to run Lisp?) and ultimately comes from C-g being overloaded in the first place.
>
>First, redisplay is not part of the command loop, at least not
>conceptually: when redisplay runs, we don't respond to user input.
>
>And second, where we call Lisp from redisplay and cannot tolerate C-g
>(or don't think it would be useful), we bind inhibit-quit already.
>
>So I don't think I follow what you are saying here.
>
>> That's *not* the same as just binding inhibit-quit around reading events like transient tries to do. The problem with binding inhibit-quit is that, well, you can't quit. Quitting restartable things that tend to get wedged like redisplay is useful.
>
>It might be useful in principle, but if you allow that, you'll have an
>infinite redisplay loop on your hands.  Why? because quitting has the
>side effect of showing "Quit" in the echo area,

No, in the command loop, it would have the side effect of running whatever C-g is bound to in the command map, and that's not necessarily (although usually is) going to show Quit.

But maybe the redisplay you're interrupting has a transient problem. Maybe you've arranged the debugger to start on quit. Maybe you have a runaway compile and you want it to stop.

> which re-enters
>redisplay right away, and will then wedge the same way as the one from
>which you wanted to escape.  And second, because it isn't restartable.

Sure it is. You can quit redisplay today and it restarts just fine. 

>So aborting redisplay is tricky at best.  We have an optional feature,
>by default off, which does that, see max-redisplay-ticks.  If you
>follow how this is implemented when we decide to abort, you will see
>it isn't simple.  And my personal experience from using this is that
>sometimes you are left with a partially-redrawn screen that you (as
>the user) don't always know how to fix.

If you don't want to support making redisplay interruptable, fine. Bind inhibit-quit around it in every invocation by default. read_char still has to do something with the Vquit_flag and the only sensible thing for this function to do is translating it to quit_char and returning normally.

>> Instead, the event reading functions should internally translate quits.to quit_char returns even if a quit happened internally. And they definitely shouldn't return with quit-flag set.
>
>How can this support breaking out of a runaway synchronous subprocess?
>Or any of the similar situations which today we can interrupt with a
>C-g? are we going to give up on them?

Huh? I'm talking only about translating quit to quit_char *inside read_char*, not in general!

If you're waiting on a synchronous subprocess, you're not in read_char --- not unless you have such a synchronous operation in, say, a timer, and you already can't quit one of those.

Basically, in the command loop, once we've decided to start running a command, then quits should be reflected as errors. If a quit happens while we're reading description of the command to run, control should always flow to the binding of quit_char in the appropriate keymaps. It's the only way to keep user experience consistent.

BTW: the problem isn't just with transient. It also manifests with read-extended-command! It's a nasty race that, AFAICT, has been with us since the 90s. I think defining read_char to translate quits to quit_char solves the problem. 




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Tue, 10 Jun 2025 17:24:02 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>, pipcet <at> protonmail.com
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Tue, 10 Jun 2025 13:23:29 -0400
> BTW: the problem isn't just with transient. It also manifests with
> read-extended-command! It's a nasty race that, AFAICT, has been with us
> since the 90s. I think defining read_char to translate quits to quit_char
> solves the problem.

I like your way of thinking.  I'm not completely sure it will solve
world hunger, and it may come with regressions, but it's worth a try.
Given the pervasive impact, it might be best to have a global config var
to enable/disable it (with some scary internal name) until we're
confident that it's an improvement.


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Tue, 10 Jun 2025 17:41:02 GMT) Full text and rfc822 format available.

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

From: Pip Cet <pipcet <at> protonmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 Daniel Colascione <dancol <at> dancol.org>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Tue, 10 Jun 2025 17:40:39 +0000
"Stefan Monnier" <monnier <at> iro.umontreal.ca> writes:

>> BTW: the problem isn't just with transient. It also manifests with
>> read-extended-command! It's a nasty race that, AFAICT, has been with us
>> since the 90s. I think defining read_char to translate quits to quit_char
>> solves the problem.
>
> I like your way of thinking.  I'm not completely sure it will solve
> world hunger, and it may come with regressions, but it's worth a try.

I must be missing something: read_char translates quits to quit_char if
called with inhibit-quit bound to t, and never returns with quit-flag
set to t in that case.  I don't think it should do that, it doesn't
match the quit-flag documentation, but it is what happens right now.  Do
we really need a new function which is precisely equivalent to

(let ((inhibit-quit t)) (read-event ...)) ?

As for throw-on-input, I don't know what Daniel is proposing to do to
handle it.  Is every caller of read-event supposed to check
throw-on-input and simulate it?  How is that better than looking at
quit-flag, or simply keeping inhibit-quit bound for the critical
section?

As for peeking at events, the easiest way seems to me to be to let-bind
unread-command-events to nil around a call to read-event.  That'll make
it ignore them, read the next event, which you can then append to
unread-command-events or not depending on whether you want the command
loop to handle it.

> Given the pervasive impact, it might be best to have a global config var
> to enable/disable it (with some scary internal name) until we're
> confident that it's an improvement.

I agree it would make sense to separate inhibit-quit meaning "inhibit
acting on the quit flag" and inhibit-quit meaning "inhibit setting the
quit flag", but that seems a minor change.

Pip





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Tue, 10 Jun 2025 19:35:02 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>, pipcet <at> protonmail.com
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Tue, 10 Jun 2025 12:34:34 -0700
Stefan Monnier <monnier <at> iro.umontreal.ca> writes:

>> BTW: the problem isn't just with transient. It also manifests with
>> read-extended-command! It's a nasty race that, AFAICT, has been with us
>> since the 90s. I think defining read_char to translate quits to quit_char
>> solves the problem.
>
> I like your way of thinking.  I'm not completely sure it will solve
> world hunger, and it may come with regressions, but it's worth a try.
> Given the pervasive impact, it might be best to have a global config var
> to enable/disable it (with some scary internal name) until we're
> confident that it's an improvement.

Check out the branch dancol/quit-improvements2 with a fix for this
problem and multiple others I found along the way.  There, we make
read_char report quits as quit_char, protect timer callbacks against
quits properly, inhibit quits in redisplay by default, attempt to quit
more often reading process output, and fix the original
throw-on-input bug.

It's now robust against the (compile "cat /dev/urandom") test, which is
actually a pretty good poor man's fuzz and load test!

(It's dancol/quit-improvements2 not dancol/quit-improvements because I
can't force-push even to a non-mainline branch.  Shouldn't we allow
off-mainline force pushes?)




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Tue, 10 Jun 2025 19:47:01 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Pip Cet <pipcet <at> protonmail.com>, Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Tue, 10 Jun 2025 12:46:19 -0700

On June 10, 2025 10:40:39 AM PDT, Pip Cet <pipcet <at> protonmail.com> wrote:
>"Stefan Monnier" <monnier <at> iro.umontreal.ca> writes:
>
>>> BTW: the problem isn't just with transient. It also manifests with
>>> read-extended-command! It's a nasty race that, AFAICT, has been with us
>>> since the 90s. I think defining read_char to translate quits to quit_char
>>> solves the problem.
>>
>> I like your way of thinking.  I'm not completely sure it will solve
>> world hunger, and it may come with regressions, but it's worth a try.
>
>I must be missing something: read_char translates quits to quit_char if
>called with inhibit-quit bound to t, and never returns with quit-flag
>set to t in that case. 

You shouldn't have to call it with inhibit-quit for it do that. It should just happen all the time.

 I don't think it should do that, it doesn't
>match the quit-flag documentation, but it is what happens right now.  Do
>we really need a new function which is precisely equivalent to
>
>(let ((inhibit-quit t)) (read-event ...)) ?
>
>As for throw-on-input, I don't know what Daniel is proposing to do to
>handle it.  Is every caller of read-event supposed to check
>throw-on-input and simulate it?  How is that better than looking at
>quit-flag, or simply keeping inhibit-quit bound for the critical
>section?

See the fix in the fix i mentioned a message ago. Now the read event functions detect that they're in a context in which quitting is inevitable and try to save the event before control even gets to Lisp. Should be transparent change.


>As for peeking at events, the easiest way seems to me to be to let-bind
>unread-command-events to nil around a call to read-event.  That'll make
>it ignore them, read the next event, which you can then append to
>unread-command-events or not depending on whether you want the command
>loop to handle it.

Isn't unread command events kind of lossy and not something we want to use all the time?

>> Given the pervasive impact, it might be best to have a global config var
>> to enable/disable it (with some scary internal name) until we're
>> confident that it's an improvement.


Changes seem pretty safe. I did add kill switch for inhibiting quit in redisplay.

>I agree it would make sense to separate inhibit-quit meaning "inhibit
>acting on the quit flag" and inhibit-quit meaning "inhibit setting the
>quit flag", but that seems a minor change.

We have a lot of code that makes subtle assumptions about the meaning of the quit flag. I wouldn't change it lightly. The more local changes on my branch seem sufficient. 




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Tue, 10 Jun 2025 20:34:01 GMT) Full text and rfc822 format available.

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

From: Stephen Berman <stephen.berman <at> gmx.net>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 Stefan Monnier <monnier <at> iro.umontreal.ca>, pipcet <at> protonmail.com
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Tue, 10 Jun 2025 22:33:06 +0200
On Tue, 10 Jun 2025 12:34:34 -0700 Daniel Colascione <dancol <at> dancol.org> wrote:

[...]
> (It's dancol/quit-improvements2 not dancol/quit-improvements because I
> can't force-push even to a non-mainline branch.  Shouldn't we allow
> off-mainline force pushes?)

See admin/notes/repo in the Emacs sources:
  
  * feature and scratch branches
  
  Besides the master branch, which is where development takes place, and
  the "emacs-NN" release branches, we also have branches whose names
  start with "scratch/" and "feature/".  The "feature/" prefix is used
  for feature branches that are intended to live for some time, while
  "scratch/" is for one-off throw-away-after-use branches.
  
  We do not intend to "git merge" from scratch branches, so force-pushes
                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  are tolerated, as well as commits with poor style, incomplete commit
  ^^^^^^^^^^^^^
  messages, etc.

Steve Berman




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Tue, 10 Jun 2025 20:47:02 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Stephen Berman <stephen.berman <at> gmx.net>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 Stefan Monnier <monnier <at> iro.umontreal.ca>, pipcet <at> protonmail.com
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Tue, 10 Jun 2025 13:46:06 -0700
Stephen Berman <stephen.berman <at> gmx.net> writes:

> On Tue, 10 Jun 2025 12:34:34 -0700 Daniel Colascione <dancol <at> dancol.org> wrote:
>
> [...]
>> (It's dancol/quit-improvements2 not dancol/quit-improvements because I
>> can't force-push even to a non-mainline branch.  Shouldn't we allow
>> off-mainline force pushes?)
>
> See admin/notes/repo in the Emacs sources:
>   
>   * feature and scratch branches
>   
>   Besides the master branch, which is where development takes place, and
>   the "emacs-NN" release branches, we also have branches whose names
>   start with "scratch/" and "feature/".  The "feature/" prefix is used
>   for feature branches that are intended to live for some time, while
>   "scratch/" is for one-off throw-away-after-use branches.
>   
>   We do not intend to "git merge" from scratch branches, so force-pushes
>                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>   are tolerated, as well as commits with poor style, incomplete commit
>   ^^^^^^^^^^^^^
>   messages, etc.

I tried git push -f and it literally didn't work. Something about the
remote not supporting fast-forward...

Oh.  The scratch/ is semantically meaningful!  It's not just convention.
I'll keep that in mind next time.  Thanks!

Maybe it's worth requiring that branches have one of these two prefixes?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Wed, 11 Jun 2025 02:57:02 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>, pipcet <at> protonmail.com
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Tue, 10 Jun 2025 19:56:49 -0700
Daniel Colascione <dancol <at> dancol.org> writes:

> Stefan Monnier <monnier <at> iro.umontreal.ca> writes:
>
>>> BTW: the problem isn't just with transient. It also manifests with
>>> read-extended-command! It's a nasty race that, AFAICT, has been with us
>>> since the 90s. I think defining read_char to translate quits to quit_char
>>> solves the problem.
>>
>> I like your way of thinking.  I'm not completely sure it will solve
>> world hunger, and it may come with regressions, but it's worth a try.
>> Given the pervasive impact, it might be best to have a global config var
>> to enable/disable it (with some scary internal name) until we're
>> confident that it's an improvement.
>
> Check out the branch dancol/quit-improvements2 with a fix for this
> problem and multiple others I found along the way.  There, we make
> read_char report quits as quit_char, protect timer callbacks against
> quits properly, inhibit quits in redisplay by default, attempt to quit
> more often reading process output, and fix the original
> throw-on-input bug.
>
> It's now robust against the (compile "cat /dev/urandom") test, which is
> actually a pretty good poor man's fuzz and load test!
>
> (It's dancol/quit-improvements2 not dancol/quit-improvements because I
> can't force-push even to a non-mainline branch.  Shouldn't we allow
> off-mainline force pushes?)

BTW: I've also fixed the longstanding NS quit bug.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Wed, 11 Jun 2025 10:33:02 GMT) Full text and rfc822 format available.

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

From: Pip Cet <pipcet <at> protonmail.com>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Wed, 11 Jun 2025 10:32:00 +0000
"Daniel Colascione" <dancol <at> dancol.org> writes:

> On June 10, 2025 10:40:39 AM PDT, Pip Cet <pipcet <at> protonmail.com> wrote:
>>"Stefan Monnier" <monnier <at> iro.umontreal.ca> writes:
>>
>>>> BTW: the problem isn't just with transient. It also manifests with
>>>> read-extended-command! It's a nasty race that, AFAICT, has been with us
>>>> since the 90s. I think defining read_char to translate quits to quit_char
>>>> solves the problem.
>>>
>>> I like your way of thinking.  I'm not completely sure it will solve
>>> world hunger, and it may come with regressions, but it's worth a try.
>>
>>I must be missing something: read_char translates quits to quit_char if
>>called with inhibit-quit bound to t, and never returns with quit-flag
>>set to t in that case.
>
> You shouldn't have to call it with inhibit-quit for it do that. It should just happen all the time.

But we don't usually want read-event to eat quits and report them by
returning quit_char.  The old behavior gave me a choice.

(while t (read-event))

on your branch appears to hang the Emacs session unquittably (even
SIGUSR2 doesn't seem to work).  It should permit quits, because that
code says nothing about wanting quits to be reported.

Reporting them as quit_char doesn't always make sense, since there are
other ways to generate a quit, such as SIGUSR2, and quit_char can
change.

>  I don't think it should do that, it doesn't
>>match the quit-flag documentation, but it is what happens right now.  Do
>>we really need a new function which is precisely equivalent to
>>
>>(let ((inhibit-quit t)) (read-event ...)) ?
>>
>>As for throw-on-input, I don't know what Daniel is proposing to do to
>>handle it.  Is every caller of read-event supposed to check
>>throw-on-input and simulate it?  How is that better than looking at
>>quit-flag, or simply keeping inhibit-quit bound for the critical
>>section?
>
> See the fix in the fix i mentioned a message ago. Now the read event
> functions detect that they're in a context in which quitting is
> inevitable and try to save the event before control even gets to
> Lisp. Should be transparent change.

It's pushing the event without the (cons t event) wrapper now?  Won't
that change behavior of sit-for (and adding the wrapper would change
behavior of other users)?

Maybe we should just fix the original problem by making read_char call
maybe_quit instead of removing an event from the queue, if Vquit_flag is
set.

No reason to change anything about the API, read_char already calls Lisp
so quitting should not be a problem (famous last words).

Of course, the ability to peek at/wait for events would still be a good
thing, as would the ability to nest while-no-input invocations.

>>As for peeking at events, the easiest way seems to me to be to let-bind
>>unread-command-events to nil around a call to read-event.  That'll make
>>it ignore them, read the next event, which you can then append to
>>unread-command-events or not depending on whether you want the command
>>loop to handle it.
>
> Isn't unread command events kind of lossy and not something we want to use all the time?

How is it "kind of lossy"?  Anyway, you're using it on your branch, so
if it's unsafe it'll be unsafe for you, too.

If your concern is that unread-command-events might be updated
asynchronously as quit-flag is, I don't think we do that.

>>I agree it would make sense to separate inhibit-quit meaning "inhibit
>>acting on the quit flag" and inhibit-quit meaning "inhibit setting the
>>quit flag", but that seems a minor change.
>
> We have a lot of code that makes subtle assumptions about the meaning
> of the quit flag. I wouldn't change it lightly. The more local changes
> on my branch seem sufficient.

Er, you just did change it, in a way that breaks existing behavior.  But
I agree, no changes such as that one are necessary.

Anyway, here are the minor changes to keyboard.c to avoid the original
problem (the third change is somewhat independent and avoids quitting in
kbd_buffer_get_event):

diff --git a/src/keyboard.c b/src/keyboard.c
index 5db11ad6379..5c65111f649 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -3045,6 +3045,9 @@ read_char (int commandflag, Lisp_Object map,
     timer_stop_idle ();
   RESUME_POLLING;
 
+  input_was_pending = input_pending;
+  maybe_quit ();
+
   if (NILP (c))
     {
       if (commandflag >= 0
@@ -4118,6 +4121,11 @@ kbd_buffer_get_event (KBOARD **kbp,
     x_handle_pending_selection_requests ();
 #endif
 
+  /* We're about to dequeue an event; if quit-flag is set, we might
+     never get around to handling it, so it would be lost.  */
+  if (!NILP (Vquit_flag))
+    quit_throw_to_read_char (0);
+
   if (CONSP (Vunread_command_events))
     {
       Lisp_Object first;
@@ -12992,7 +13000,7 @@ is_ignored_event (union buffered_input_event *event)
     default: ignore_event = Qnil; break;
     }
 
-  return !NILP (Fmemq (ignore_event, Vwhile_no_input_ignore_events));
+  return !NILP (memq_no_quit (ignore_event, Vwhile_no_input_ignore_events));
 }
 
 static void syms_of_keyboard_for_pdumper (void);


Pip





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Wed, 11 Jun 2025 12:41:02 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Pip Cet <pipcet <at> protonmail.com>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Wed, 11 Jun 2025 05:40:29 -0700
Pip Cet <pipcet <at> protonmail.com> writes:

> "Daniel Colascione" <dancol <at> dancol.org> writes:
>
>> On June 10, 2025 10:40:39 AM PDT, Pip Cet <pipcet <at> protonmail.com> wrote:
>>>"Stefan Monnier" <monnier <at> iro.umontreal.ca> writes:
>>>
>>>>> BTW: the problem isn't just with transient. It also manifests with
>>>>> read-extended-command! It's a nasty race that, AFAICT, has been with us
>>>>> since the 90s. I think defining read_char to translate quits to quit_char
>>>>> solves the problem.
>>>>
>>>> I like your way of thinking.  I'm not completely sure it will solve
>>>> world hunger, and it may come with regressions, but it's worth a try.
>>>
>>>I must be missing something: read_char translates quits to quit_char if
>>>called with inhibit-quit bound to t, and never returns with quit-flag
>>>set to t in that case.
>>
>> You shouldn't have to call it with inhibit-quit for it do that. It should just happen all the time.
>
> But we don't usually want read-event to eat quits and report them by
> returning quit_char.  The old behavior gave me a choice.

You still have a choice.  You can signal quit if you get a quit event.

> (while t (read-event))
>
> on your branch appears to hang the Emacs session unquittably (even
> SIGUSR2 doesn't seem to work).  It should permit quits, because that
> code says nothing about wanting quits to be reported.

By calling read-event, you're asking Emacs read an event.  C-g is an
event.  Lisp isn't saying
read-event-unless-it's-C-g-in-which-case-exit-non-locally.  Lisp says
read-event.  Emacs is doing exactly what Lisp is asking it to do.
If Lisp wants to quit in response to a char_char event, it can just
(signal 'quit nil).

Besides, (let ((inhibit-quit t)) (while t (read-event))) will be
similarly unquittable on master today.

(while t ((read-key-sequence "))) is unquittable too.

On current master, (read-event) then C-g signals quit but
(read-key-sequence "") C-g returns a quit_char key.  Why?  Why should we
expect (while t (read-event)) to be quittable but not (while t
(read-key-sequence "")), which can't be quit today on master?  Why would
the _high level_ event reading function report quit as a character but
the low-level one exit nonlocally?

Consider, say, (let ((unread-command-events '(\?C-g))) (read-event)).
That'll return \?C-g, not quit.  Therefore, anyone who calls
(read-event) has to account for both ways of C-g being reported.
What's the benefit of this complexity?

So what if the behavior of read-event changes?  Does having read-event
report a quit as an event actually break anything considering that
_sometimes_ it already can report a C-g as an event and not a
quit signal.

We need to be consistent about how we treat C-g when reading events.
It makes no sense to quit while reading an event because in order to
quit, you must first read an event!

The current ambiguity is confusing and leads to real-world actual bugs.
A lisp-visible behavior change isn't dispositive by itself: any
resolution of the current ambiguity will result in new behavior, so we
might as well make it good new behavior.

If C-g means quit, we should resolve the inconsistency above by having
read-event quit if it finds a C-g events in a queue.  We also need to
change cmd_error to detect quits, push a synthetic quit_char to
unread_command_events, return Qt, and have the command loop look up the
event on the next loop.  That'll fix the transient bug.

If C-g means quit_char, which is the better behavior, we need to
document that functions that read events report quits as quit_char.

Thanks for pointing out the SIGUSR2 thing.  That's just a bug we'll fix
on the branch.  Likewise, we should try to get the emergency quit
mechanism working somehow too.  None of this means that (read-event)
then physically hitting C-g means (read-event) should quit rather
than return.

> Reporting them as quit_char doesn't always make sense, since there are
> other ways to generate a quit, such as SIGUSR2,

We can make SIGUSR2 generate a subtype of quit and have read_char
translate only the basic event.  Likewise for emergency quits.

> and quit_char can change.

Can it in practice?  Lots of stuff hardcodes C-g and I'm not confident
that a non-default quit_char would produce usable behavior.  I'd rather
just remove set-quit-char than worry about quit_char changing.

>>  I don't think it should do that, it doesn't
>>>match the quit-flag documentation, but it is what happens right now.  Do
>>>we really need a new function which is precisely equivalent to
>>>
>>>(let ((inhibit-quit t)) (read-event ...)) ?
>>>
>>>As for throw-on-input, I don't know what Daniel is proposing to do to
>>>handle it.  Is every caller of read-event supposed to check
>>>throw-on-input and simulate it?  How is that better than looking at
>>>quit-flag, or simply keeping inhibit-quit bound for the critical
>>>section?
>>
>> See the fix in the fix i mentioned a message ago. Now the read event
>> functions detect that they're in a context in which quitting is
>> inevitable and try to save the event before control even gets to
>> Lisp. Should be transparent change.
>
> It's pushing the event without the (cons t event) wrapper now?  Won't
> that change behavior of sit-for (and adding the wrapper would change
> behavior of other users)?
>
> Maybe we should just fix the original problem by making read_char call
> maybe_quit instead of removing an event from the queue, if Vquit_flag is
> set.

I don't think it's a good idea to have parallel event processing paths,
one for events delivered as Lisp objects and one for events delivered
as signals.

> No reason to change anything about the API, read_char already calls Lisp
> so quitting should not be a problem (famous last words).
>
> Of course, the ability to peek at/wait for events would still be a good
> thing, as would the ability to nest while-no-input invocations.
>
>>>As for peeking at events, the easiest way seems to me to be to let-bind
>>>unread-command-events to nil around a call to read-event.  That'll make
>>>it ignore them, read the next event, which you can then append to
>>>unread-command-events or not depending on whether you want the command
>>>loop to handle it.
>>
>> Isn't unread command events kind of lossy and not something we want to use all the time?
>
> How is it "kind of lossy"?  Anyway, you're using it on your branch, so
> if it's unsafe it'll be unsafe for you, too.
>
> If your concern is that unread-command-events might be updated
> asynchronously as quit-flag is, I don't think we do that.
>
>>>I agree it would make sense to separate inhibit-quit meaning "inhibit
>>>acting on the quit flag" and inhibit-quit meaning "inhibit setting the
>>>quit flag", but that seems a minor change.
>>
>> We have a lot of code that makes subtle assumptions about the meaning
>> of the quit flag. I wouldn't change it lightly. The more local changes
>> on my branch seem sufficient.
>
> Er, you just did change it, in a way that breaks existing behavior.  But
> I agree, no changes such as that one are necessary.

The above is talking about changing the low-level meaning of
Vinhibit_quit in C.  Lots of code assumes that binding Vinhibit_quit
will result in Vquit_flag being set and I'm a lot more worried about
breaking things as a result of changing _that_ behavior than I am about
making read_char consistent about how it reports C-g.

> Anyway, here are the minor changes to keyboard.c to avoid the original
> problem (the third change is somewhat independent and avoids quitting in
> kbd_buffer_get_event):

This change papers over the problem of ambiguous C-g representation
without trying to fix it or address the even worse problem of the quits
going to the event loop and not being looked up as commands.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Wed, 11 Jun 2025 13:25:06 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: dancol <at> dancol.org, Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Wed, 11 Jun 2025 16:23:40 +0300
> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
> Cc: Eli Zaretskii <eliz <at> gnu.org>,  pipcet <at> protonmail.com,
>   78737 <at> debbugs.gnu.org
> Date: Tue, 10 Jun 2025 13:23:29 -0400
> 
> > BTW: the problem isn't just with transient. It also manifests with
> > read-extended-command! It's a nasty race that, AFAICT, has been with us
> > since the 90s. I think defining read_char to translate quits to quit_char
> > solves the problem.
> 
> I like your way of thinking.  I'm not completely sure it will solve
> world hunger, and it may come with regressions, but it's worth a try.
> Given the pervasive impact, it might be best to have a global config var
> to enable/disable it (with some scary internal name) until we're
> confident that it's an improvement.

This code is used everywhere, and we have no one on board who knows it
(and its many quirks and platform-dependent subtleties) well enough.
It isn't an accident that we prefer not to make changes in it: each
time we made even small changes in this code we ended up with
regressions.  We don't have any decent test suite for the this part of
Emacs.  We don't even have an exhaustive list of
features/commands/operations to test in order to make sure some change
doesn't break them.  Notable corners that get frequently broken by
changes in this area: keyboard macros, Leim input methods, and
non-keyboard input events.

So yes, we definitely need such a knob, if we are seriously
considering to merge these changes.  Daniel, would you please add such
a knob?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Wed, 11 Jun 2025 13:39:02 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Wed, 11 Jun 2025 16:38:28 +0300
> From: Daniel Colascione <dancol <at> dancol.org>
> Cc: Stefan Monnier <monnier <at> iro.umontreal.ca>,  Eli Zaretskii
>  <eliz <at> gnu.org>,  78737 <at> debbugs.gnu.org
> Date: Wed, 11 Jun 2025 05:40:29 -0700
> 
> Pip Cet <pipcet <at> protonmail.com> writes:
> 
> > (while t (read-event))
> >
> > on your branch appears to hang the Emacs session unquittably (even
> > SIGUSR2 doesn't seem to work).  It should permit quits, because that
> > code says nothing about wanting quits to be reported.
> 
> By calling read-event, you're asking Emacs read an event.  C-g is an
> event.  Lisp isn't saying
> read-event-unless-it's-C-g-in-which-case-exit-non-locally.  Lisp says
> read-event.  Emacs is doing exactly what Lisp is asking it to do.

How is calling read-event different from calling any other primitive
in this context?  Typing C-g while any Lisp primitive is called is
expected to throw to top-level, instead of doing whatever the
primitive's contract says.  Why is read-event different in this
regard?

> Besides, (let ((inhibit-quit t)) (while t (read-event))) will be
> similarly unquittable on master today.

Because the caller explicitly didn't want it to be quittable.

> On current master, (read-event) then C-g signals quit but
> (read-key-sequence "") C-g returns a quit_char key.  Why?  Why should we
> expect (while t (read-event)) to be quittable but not (while t
> (read-key-sequence "")), which can't be quit today on master?  Why would
> the _high level_ event reading function report quit as a character but
> the low-level one exit nonlocally?

Because a higher-level function knows the context better?  I don't see
anything wrong with that.

> So what if the behavior of read-event changes?  Does having read-event
> report a quit as an event actually break anything considering that
> _sometimes_ it already can report a C-g as an event and not a
> quit signal.

Sorry, we cannot assume that attitude, not in this case.  Making
incompatible behavior changes in this area means we will definitely
break enough use cases to cause a flood of bug reports.  We cannot do
that so freely and nonchalantly.  We could perhaps make it an optional
behavior, but that's all.

I appreciate the urge to fix what you perceive as inconsistencies, but
that alone doesn't IMO justify risky incompatible changes in default
behavior, especially if they leave no "fire escape".  Please
understand where I stand on this.  This position isn't arbitrary, it
is based on our experience from making changes in this area in the
recent years.

> The current ambiguity is confusing and leads to real-world actual bugs.
> A lisp-visible behavior change isn't dispositive by itself: any
> resolution of the current ambiguity will result in new behavior, so we
> might as well make it good new behavior.

We could also leave the old behavior alone.  It isn't bad behavior.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Wed, 11 Jun 2025 14:10:01 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Wed, 11 Jun 2025 07:08:45 -0700
Eli Zaretskii <eliz <at> gnu.org> writes:

>> From: Daniel Colascione <dancol <at> dancol.org>
>> Cc: Stefan Monnier <monnier <at> iro.umontreal.ca>,  Eli Zaretskii
>>  <eliz <at> gnu.org>,  78737 <at> debbugs.gnu.org
>> Date: Wed, 11 Jun 2025 05:40:29 -0700
>> 
>> Pip Cet <pipcet <at> protonmail.com> writes:
>> 
>> > (while t (read-event))
>> >
>> > on your branch appears to hang the Emacs session unquittably (even
>> > SIGUSR2 doesn't seem to work).  It should permit quits, because that
>> > code says nothing about wanting quits to be reported.
>> 
>> By calling read-event, you're asking Emacs read an event.  C-g is an
>> event.  Lisp isn't saying
>> read-event-unless-it's-C-g-in-which-case-exit-non-locally.  Lisp says
>> read-event.  Emacs is doing exactly what Lisp is asking it to do.
>
> How is calling read-event different from calling any other primitive
> in this context?  Typing C-g while any Lisp primitive is called is
> expected to throw to top-level, instead of doing whatever the
> primitive's contract says.  Why is read-event different in this
> regard?

Why is it good that read-key-sequence swallows quits but not read-char?
C-g is an event.  Why should read-event (but not read-key-sequence?)
translate one kind of input event (C-g) to an action (signal quit) but
return other kinds of events as they're given?

>> Besides, (let ((inhibit-quit t)) (while t (read-event))) will be
>> similarly unquittable on master today.
>
> Because the caller explicitly didn't want it to be quittable.

The caller asked to read an event.  That's exactly what we did.  The way
to reduce the likelihood of bugs is not to freeze the code, but to
understand it, simplify its contract, and probably write some tests
and documentation.

What specifically do you think might break here?

>> On current master, (read-event) then C-g signals quit but
>> (read-key-sequence "") C-g returns a quit_char key.  Why?  Why should we
>> expect (while t (read-event)) to be quittable but not (while t
>> (read-key-sequence "")), which can't be quit today on master?  Why would
>> the _high level_ event reading function report quit as a character but
>> the low-level one exit nonlocally?
>
> Because a higher-level function knows the context better?  I don't see
> anything wrong with that.

The higher level function wants to read an event.  That's exactly what
this function does now.

>> So what if the behavior of read-event changes?  Does having read-event
>> report a quit as an event actually break anything considering that
>> _sometimes_ it already can report a C-g as an event and not a
>> quit signal.
>
> Sorry, we cannot assume that attitude, not in this case.  Making
> incompatible behavior changes in this area means we will definitely
> break enough use cases to cause a flood of bug reports.  We cannot do
> that so freely and nonchalantly.  We could perhaps make it an optional
> behavior, but that's all.
>
> I appreciate the urge to fix what you perceive as inconsistencies, but
> that alone doesn't IMO justify risky incompatible changes in default
> behavior, especially if they leave no "fire escape".  Please
> understand where I stand on this.  This position isn't arbitrary, it
> is based on our experience from making changes in this area in the
> recent years.

We can't just avoid changing things because we don't understand the
code.  I put a fair bit of time into understanding this code, and that
means

>> The current ambiguity is confusing and leads to real-world actual bugs.
>> A lisp-visible behavior change isn't dispositive by itself: any
>> resolution of the current ambiguity will result in new behavior, so we
>> might as well make it good new behavior.
>
> We could also leave the old behavior alone.  It isn't bad behavior.


So you're saying it's a good thing that the behavior of the code changes
depending on whether it's compiled?  You're right: that's not bad
behavior.  It's abysmal behavior.

This whole area is full of bugs.  Are we seriously in "fixing bugs is
bad because something might change" territory?  In a development branch?
With a knob (for now) to revert to the old, broken behavior?

One way to make the code more understandable is to
make it consistent and clearly define its contract.  When code has a
regular structure, you don't need to keep a thousand special cases in
your mind when working on it.  Regularity allows you to substitute
reason for memory.  The code is pretty irregular right now.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Wed, 11 Jun 2025 14:24:02 GMT) Full text and rfc822 format available.

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

From: Pip Cet <pipcet <at> protonmail.com>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Wed, 11 Jun 2025 14:23:07 +0000
"Daniel Colascione" <dancol <at> dancol.org> writes:

> Pip Cet <pipcet <at> protonmail.com> writes:
>
>> "Daniel Colascione" <dancol <at> dancol.org> writes:
>>
>>> On June 10, 2025 10:40:39 AM PDT, Pip Cet <pipcet <at> protonmail.com> wrote:
>>>>"Stefan Monnier" <monnier <at> iro.umontreal.ca> writes:
>>>>
>>>>>> BTW: the problem isn't just with transient. It also manifests with
>>>>>> read-extended-command! It's a nasty race that, AFAICT, has been with us
>>>>>> since the 90s. I think defining read_char to translate quits to quit_char
>>>>>> solves the problem.
>>>>>
>>>>> I like your way of thinking.  I'm not completely sure it will solve
>>>>> world hunger, and it may come with regressions, but it's worth a try.
>>>>
>>>>I must be missing something: read_char translates quits to quit_char if
>>>>called with inhibit-quit bound to t, and never returns with quit-flag
>>>>set to t in that case.
>>>
>>> You shouldn't have to call it with inhibit-quit for it do that. It should just happen all the time.
>>
>> But we don't usually want read-event to eat quits and report them by
>> returning quit_char.  The old behavior gave me a choice.
>
> You still have a choice.  You can signal quit if you get a quit event.

Making

(while t (read-event))

infloop without being able to quit is a bad idea.  We shouldn't do it.

>> (while t (read-event))
>>
>> on your branch appears to hang the Emacs session unquittably (even
>> SIGUSR2 doesn't seem to work).  It should permit quits, because that
>> code says nothing about wanting quits to be reported.
>
> By calling read-event, you're asking Emacs read an event.  C-g is an
> event.

It's not an ordinary event. It's an event that should be handled
specially, which is what we do now and should continue doing. There's a
way around that, but the vast majority of callers don't need to worry
about it: (read-event) should read an ordinary event and return it,
without breaking quit.

> Lisp isn't saying
> read-event-unless-it's-C-g-in-which-case-exit-non-locally.  Lisp says
> read-event.

That's implicit as for any other Lisp command that isn't specifically
documented not to quit.  (As, for example, read-key-sequence is).

>> Anyway, here are the minor changes to keyboard.c to avoid the original
>> problem (the third change is somewhat independent and avoids quitting in
>> kbd_buffer_get_event):
>
> This change papers over the problem of ambiguous C-g representation

It doesn't paper over anything.  It merely quits before dequeueing
events when throw-on-input is in effect, without any major changes.

> without trying to fix it or address the even worse problem of the quits
> going to the event loop and not being looked up as commands.

Are you saying quits should *generally* be treated as commands rather
than by the event loop?  Because my opinion is precisely the opposite:
quits should always be handled by C code, never by keyboard-quit,
because that's what they are used for: to break out of misbehaving Lisp
code, with minimal involvement of Lisp machinery which may be
misbehaving.

We'd need new, incompatible versions of almost all callers, because
those do want to quit when we hit C-g.  And, again, we're taking away
the choice "act on C-g as usual", replacing it by a new "identify
(somehow) quit events and (somehow) quit when you see one".

Pip





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Wed, 11 Jun 2025 14:31:01 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Wed, 11 Jun 2025 17:29:48 +0300
> From: Daniel Colascione <dancol <at> dancol.org>
> Cc: pipcet <at> protonmail.com,  monnier <at> iro.umontreal.ca,  78737 <at> debbugs.gnu.org
> Date: Wed, 11 Jun 2025 07:08:45 -0700
> 
> Why is it good that read-key-sequence swallows quits but not read-char?

I don't know.  No one does.  maybe there's a good reason for it, maybe
there was one at some point but there isn't anymore, maybe it's just a
historical accident.

But being unable to answer such questions doesn't mean changing the
behavior is safe.  It usually is the other way around, in a program as
old and complex as |Emacs.

> C-g is an event.  Why should read-event (but not read-key-sequence?)
> translate one kind of input event (C-g) to an action (signal quit) but
> return other kinds of events as they're given?

You consider this to be an inconsistency based only on the name of the
API.  But that's not necessarily the whole contract of the API.  It
doesn't need to be called get-char-quit-when-c-g to behave like it
does.

Anyway, I think arguing about this aspect is not useful.  My problem
is not theoretical, it is practical: how much will break due to these
changes, and how long will it take us to become aware of the breakage
and attempt fixing it?

> What specifically do you think might break here?

Not in those toy examples, but in much larger programs where these are
used.

And I know what will break.  As I told, we don't have a good set of
tests for it.  I only know that every time we changed something in
read_char and its ilk in recent years, we ended up with regressions.

> The higher level function wants to read an event.  That's exactly what
> this function does now.

How do we know that is all that's expected from it? just because its
name says so?

> > Sorry, we cannot assume that attitude, not in this case.  Making
> > incompatible behavior changes in this area means we will definitely
> > break enough use cases to cause a flood of bug reports.  We cannot do
> > that so freely and nonchalantly.  We could perhaps make it an optional
> > behavior, but that's all.
> >
> > I appreciate the urge to fix what you perceive as inconsistencies, but
> > that alone doesn't IMO justify risky incompatible changes in default
> > behavior, especially if they leave no "fire escape".  Please
> > understand where I stand on this.  This position isn't arbitrary, it
> > is based on our experience from making changes in this area in the
> > recent years.
> 
> We can't just avoid changing things because we don't understand the
> code.  I put a fair bit of time into understanding this code, and that
> means

I didn't say we cannot make changes there.  I said we should be very
cautious if and when we do.  Which means:

 . we should think hard and then think again whether the change is
   really necessary and how important are the problems that it solves
   or new features it allows
 . we should have a knob to revert to previous behavior

> > We could also leave the old behavior alone.  It isn't bad behavior.
> 
> 
> So you're saying it's a good thing that the behavior of the code changes
> depending on whether it's compiled?

No, I'm saying that in this case it could be minor enough and rare
enough to fail to outweigh the risks.

> This whole area is full of bugs.  Are we seriously in "fixing bugs is
> bad because something might change" territory?  In a development branch?
> With a knob (for now) to revert to the old, broken behavior?

See above: that's not what I'm saying.

> One way to make the code more understandable is to
> make it consistent and clearly define its contract.  When code has a
> regular structure, you don't need to keep a thousand special cases in
> your mind when working on it.  Regularity allows you to substitute
> reason for memory.  The code is pretty irregular right now.

I agree, but when dealing with old and very complex code that
thousands of programs rely upon, we need to consider the risks of
changing the old behavior even if it is somewhat inconsistent.
Because sometimes an old, known, and minor problem is better than new,
unknown, and exciting ones.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Wed, 11 Jun 2025 14:50:02 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Pip Cet <pipcet <at> protonmail.com>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Wed, 11 Jun 2025 07:49:23 -0700
Pip Cet <pipcet <at> protonmail.com> writes:

> "Daniel Colascione" <dancol <at> dancol.org> writes:
>
>> Pip Cet <pipcet <at> protonmail.com> writes:
>>
>>> "Daniel Colascione" <dancol <at> dancol.org> writes:
>>>
>>>> On June 10, 2025 10:40:39 AM PDT, Pip Cet <pipcet <at> protonmail.com> wrote:
>>>>>"Stefan Monnier" <monnier <at> iro.umontreal.ca> writes:
>>>>>
>>>>>>> BTW: the problem isn't just with transient. It also manifests with
>>>>>>> read-extended-command! It's a nasty race that, AFAICT, has been with us
>>>>>>> since the 90s. I think defining read_char to translate quits to quit_char
>>>>>>> solves the problem.
>>>>>>
>>>>>> I like your way of thinking.  I'm not completely sure it will solve
>>>>>> world hunger, and it may come with regressions, but it's worth a try.
>>>>>
>>>>>I must be missing something: read_char translates quits to quit_char if
>>>>>called with inhibit-quit bound to t, and never returns with quit-flag
>>>>>set to t in that case.
>>>>
>>>> You shouldn't have to call it with inhibit-quit for it do that. It should just happen all the time.
>>>
>>> But we don't usually want read-event to eat quits and report them by
>>> returning quit_char.  The old behavior gave me a choice.
>>
>> You still have a choice.  You can signal quit if you get a quit event.
>
> Making
>
> (while t (read-event))
>
> infloop without being able to quit is a bad idea.  We shouldn't do it.

So we should "fix" read-key-sequence so that it, too, quits?

>>> (while t (read-event))
>>>
>>> on your branch appears to hang the Emacs session unquittably (even
>>> SIGUSR2 doesn't seem to work).  It should permit quits, because that
>>> code says nothing about wanting quits to be reported.
>>
>> By calling read-event, you're asking Emacs read an event.  C-g is an
>> event.
>
> It's not an ordinary event.

The problem is that C-g is ordinary event on some code paths and
not others.

> It's an event that should be handled
> specially, which is what we do now and should continue doing.

So if I stuff C-g into unread-command-events and then call (read-event),
I should get a quit?  It's even more confusing to say that C-g is a
special event _unless_ it's been unread (perhaps transparently by
something somewhere), in which case it's actually a regular event.

> There's a
> way around that, but the vast majority of callers don't need to worry
> about it: (read-event) should read an ordinary event and return it,
> without breaking quit.
>
>> Lisp isn't saying
>> read-event-unless-it's-C-g-in-which-case-exit-non-locally.  Lisp says
>> read-event.
>
> That's implicit as for any other Lisp command that isn't specifically
> documented not to quit.  (As, for example, read-key-sequence is).

Yes, and one or the other function should change, along with its
documentation.  What _reason_ is there to quit from one and not
the other?

>>> Anyway, here are the minor changes to keyboard.c to avoid the original
>>> problem (the third change is somewhat independent and avoids quitting in
>>> kbd_buffer_get_event):
>>
>> This change papers over the problem of ambiguous C-g representation
>
> It doesn't paper over anything.  It merely quits before dequeueing
> events when throw-on-input is in effect, without any major changes.
>
>> without trying to fix it or address the even worse problem of the quits
>> going to the event loop and not being looked up as commands.
>
> Are you saying quits should *generally* be treated as commands rather
> than by the event loop?  Because my opinion is precisely the opposite:
> quits should always be handled by C code, never by keyboard-quit,
> because that's what they are used for: to break out of misbehaving Lisp
> code, with minimal involvement of Lisp machinery which may be
> misbehaving.

_Quits_ are intended to break out of Lisp code, but C-g doesn't always
mean quit.  Transient, for example, uses C-g to dismiss its menus.
execute-extended-command does too, as does completion.  Like it or not,
C-g is not merely a signal to Lisp to stop what it's doing, but also a
legitimate event to which people bind regular commands, and it's a bug
if we don't respect these bindings because in a certain circumstance
invisible to users we decided that the C-g is really a
stop-the-Lisp-world-now pseudo-error and not the user telling us he
wants to run a command.

> We'd need new, incompatible versions of almost all callers, because
> those do want to quit when we hit C-g.  And, again, we're taking away
> the choice "act on C-g as usual", replacing it by a new "identify
> (somehow) quit events and (somehow) quit when you see one".

I haven't seen anything actually malfunction due to having (read-event)
return C-g as an event instead of quitting, and some code actually
expects it.

Some code actually _works_ better.  Consider, for example,
calc-get-user-defn.

(defun calc-get-user-defn ()
  (interactive)
  (calc-wrapper
   (message "Get definition of command: z-")
   (let* ((key (read-char))
	  (def (or (assq key (calc-user-key-map))
		   (assq (upcase key) (calc-user-key-map))
		   (assq (downcase key) (calc-user-key-map))
		   (error "No command defined for that key")))
  ...)

If read-char returns \?C-g, the code above produces a _better_ message,
"No command defined for that key" (which is the truth) where it used to
just say "Quit".  Even hairy code like kbd-macro-query works fine when
read-char, read-event, and so on report C-g as an event.

If you can find something that actually breaks when we do that, we can
do something else, but so far, I haven't seen reporting C-g break
anything and have seen it make things a bit better.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Wed, 11 Jun 2025 14:59:02 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Wed, 11 Jun 2025 07:57:52 -0700
Eli Zaretskii <eliz <at> gnu.org> writes:

>> From: Daniel Colascione <dancol <at> dancol.org>
>> Cc: pipcet <at> protonmail.com,  monnier <at> iro.umontreal.ca,  78737 <at> debbugs.gnu.org
>> Date: Wed, 11 Jun 2025 07:08:45 -0700
>> 
>> Why is it good that read-key-sequence swallows quits but not read-char?
>
> I don't know.  No one does.  maybe there's a good reason for it, maybe
> there was one at some point but there isn't anymore, maybe it's just a
> historical accident.
>
> But being unable to answer such questions doesn't mean changing the
> behavior is safe.  It usually is the other way around, in a program as
> old and complex as |Emacs.
>
>> C-g is an event.  Why should read-event (but not read-key-sequence?)
>> translate one kind of input event (C-g) to an action (signal quit) but
>> return other kinds of events as they're given?
>
> You consider this to be an inconsistency based only on the name of the
> API.  But that's not necessarily the whole contract of the API.  It
> doesn't need to be called get-char-quit-when-c-g to behave like it
> does.
>
> Anyway, I think arguing about this aspect is not useful.  My problem
> is not theoretical, it is practical: how much will break due to these
> changes, and how long will it take us to become aware of the breakage
> and attempt fixing it?

I went through all the uses of read-char, read-char-exclusively, and
read-event in the tree and didn't find anything that'll break if we make
these functions return C-g as an event.  I did some things that worked
marginally better, as I mentioned in my previous message.  It's possible
something breaks, but I haven't seen evidence of breakage yet.

>> What specifically do you think might break here?
>
> Not in those toy examples, but in much larger programs where these are
> used.
>
> And I know what will break.  As I told, we don't have a good set of
> tests for it.  I only know that every time we changed something in
> read_char and its ilk in recent years, we ended up with regressions.

All the more reason to simplify its contract.

>> The higher level function wants to read an event.  That's exactly what
>> this function does now.
>
>> So you're saying it's a good thing that the behavior of the code changes
>> depending on whether it's compiled?
>
> No, I'm saying that in this case it could be minor enough and rare
> enough to fail to outweigh the risks.
>
>> This whole area is full of bugs.  Are we seriously in "fixing bugs is
>> bad because something might change" territory?  In a development branch?
>> With a knob (for now) to revert to the old, broken behavior?
>
> See above: that's not what I'm saying.
>
>> One way to make the code more understandable is to
>> make it consistent and clearly define its contract.  When code has a
>> regular structure, you don't need to keep a thousand special cases in
>> your mind when working on it.  Regularity allows you to substitute
>> reason for memory.  The code is pretty irregular right now.
>
> I agree, but when dealing with old and very complex code that
> thousands of programs rely upon, we need to consider the risks of
> changing the old behavior even if it is somewhat inconsistent.
> Because sometimes an old, known, and minor problem is better than new,
> unknown, and exciting ones.

Yes, and for cases in which we're changing user-visible semantics in a
way that'll break workflows --- like beginning-of-defun, perhaps ---
then I agree with you.  I don't think this particular change belongs to
that category.  I've looked for evidence that would change my mind and
haven't found any yet.  You're right that changes to the input loop are
risky, but they're going to be necessary sooner or later anyway, so
wouldn't you prefer to change simpler code?

Along the same lines, we could get rid of getcjmp too.  I'm not afraid
of rationalizing the contract of read-event or tweaking any other part
of keyboard.c, but that thing and quit_throw_to_read_char are extremely
confusing and do scare me a bit --- all the more reason, in my mind, to
get rid of them, like Gerd wanted to do years ago.  When is the right
time to do that?  It's not like an Emacs 31 release is imminent.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Wed, 11 Jun 2025 15:20:04 GMT) Full text and rfc822 format available.

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

From: Pip Cet <pipcet <at> protonmail.com>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Wed, 11 Jun 2025 15:19:07 +0000
"Daniel Colascione" <dancol <at> dancol.org> writes:

> Eli Zaretskii <eliz <at> gnu.org> writes:
>
>> We could also leave the old behavior alone.  It isn't bad behavior.
>
> So you're saying it's a good thing that the behavior of the code changes
> depending on whether it's compiled?  You're right: that's not bad
> behavior.  It's abysmal behavior.

Fixing the sit-for bug does not in any way require breaking quit.

We should decide how we want to fix this bug, independently of
considering major changes to the quitting mechanism in general.

Binding inhibit-quit works; not removing events from the queue when
we're about to quit works; re-queueing events from C would work, even
though we'd need an extra flag to know how to requeue them so it'd be an
API change.

What would work best, IMHO, is a non-destructive way to wait for the
next event.

My suggestion would be:

    (while-no-input (sleep-for seconds))

That doesn't currently work in nested while-no-input because
while-no-input nests the wrong way around (the outermost while-no-input
should win, not the innermost one), but that's trivial to fix.

diff --git a/lisp/subr.el b/lisp/subr.el
index 729f8b3e09b..56575259ff9 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -3696,28 +3696,9 @@ sit-for
     (or nodisp (redisplay)))
    (t
     (or nodisp (redisplay))
-    ;; FIXME: we should not read-event here at all, because it's much too
-    ;; difficult to reliably "undo" a read-event by pushing it onto
-    ;; unread-command-events.
-    ;; For bug#14782, we need read-event to do the keyboard-coding-system
-    ;; decoding (hence non-nil as second arg under POSIX ttys).
-    ;; For bug#15614, we need read-event not to inherit-input-method.
-    ;; So we temporarily suspend input-method-function.
-    (let ((read (let ((input-method-function nil))
-                  (read-event nil t seconds))))
-      (or (null read)
-	  (progn
-            ;; https://lists.gnu.org/r/emacs-devel/2006-10/msg00394.html
-            ;; We want `read' appear in the next command's this-command-event
-            ;; but not in the current one.
-            ;; By pushing (cons t read), we indicate that `read' has not
-            ;; yet been recorded in this-command-keys, so it will be recorded
-            ;; next time it's read.
-            ;; And indeed the `seconds' argument to read-event correctly
-            ;; prevented recording this event in the current command's
-            ;; this-command-keys.
-	    (push (cons t read) unread-command-events)
-	    nil))))))
+    (not (if throw-on-input
+             (sleep-for seconds)
+           (while-no-input (sleep-for seconds)))))))
 
 (defun goto-char--read-natnum-interactive (prompt)
   "Get a natural number argument, optionally prompting with PROMPT.

This appears to fix the original bug and the FIXME without any C
changes, though we might have to hack sleep-for to prevent the hourglass
from showing.

Pip





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Wed, 11 Jun 2025 15:39:01 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Pip Cet <pipcet <at> protonmail.com>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Wed, 11 Jun 2025 08:38:26 -0700
Pip Cet <pipcet <at> protonmail.com> writes:

> "Daniel Colascione" <dancol <at> dancol.org> writes:
>
>> Eli Zaretskii <eliz <at> gnu.org> writes:
>>
>>> We could also leave the old behavior alone.  It isn't bad behavior.
>>
>> So you're saying it's a good thing that the behavior of the code changes
>> depending on whether it's compiled?  You're right: that's not bad
>> behavior.  It's abysmal behavior.
>
> Fixing the sit-for bug does not in any way require breaking quit.
>
> We should decide how we want to fix this bug, independently of
> considering major changes to the quitting mechanism in general.
>
> Binding inhibit-quit works; not removing events from the queue when
> we're about to quit works; re-queueing events from C would work, even
> though we'd need an extra flag to know how to requeue them so it'd be an
> API change.
>
> What would work best, IMHO, is a non-destructive way to wait for the
> next event.
>
> My suggestion would be:
>
>     (while-no-input (sleep-for seconds))
>
> That doesn't currently work in nested while-no-input because
> while-no-input nests the wrong way around (the outermost while-no-input
> should win, not the innermost one), but that's trivial to fix.
>
> diff --git a/lisp/subr.el b/lisp/subr.el
> index 729f8b3e09b..56575259ff9 100644
> --- a/lisp/subr.el
> +++ b/lisp/subr.el
> @@ -3696,28 +3696,9 @@ sit-for
>      (or nodisp (redisplay)))
>     (t
>      (or nodisp (redisplay))
> -    ;; FIXME: we should not read-event here at all, because it's much too
> -    ;; difficult to reliably "undo" a read-event by pushing it onto
> -    ;; unread-command-events.
> -    ;; For bug#14782, we need read-event to do the keyboard-coding-system
> -    ;; decoding (hence non-nil as second arg under POSIX ttys).
> -    ;; For bug#15614, we need read-event not to inherit-input-method.
> -    ;; So we temporarily suspend input-method-function.
> -    (let ((read (let ((input-method-function nil))
> -                  (read-event nil t seconds))))
> -      (or (null read)
> -	  (progn
> -            ;; https://lists.gnu.org/r/emacs-devel/2006-10/msg00394.html
> -            ;; We want `read' appear in the next command's this-command-event
> -            ;; but not in the current one.
> -            ;; By pushing (cons t read), we indicate that `read' has not
> -            ;; yet been recorded in this-command-keys, so it will be recorded
> -            ;; next time it's read.
> -            ;; And indeed the `seconds' argument to read-event correctly
> -            ;; prevented recording this event in the current command's
> -            ;; this-command-keys.
> -	    (push (cons t read) unread-command-events)
> -	    nil))))))
> +    (not (if throw-on-input
> +             (sleep-for seconds)
> +           (while-no-input (sleep-for seconds)))))))

That's a good idea.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Wed, 11 Jun 2025 16:00:03 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Wed, 11 Jun 2025 18:59:11 +0300
> From: Daniel Colascione <dancol <at> dancol.org>
> Cc: pipcet <at> protonmail.com,  monnier <at> iro.umontreal.ca,  78737 <at> debbugs.gnu.org
> Date: Wed, 11 Jun 2025 07:57:52 -0700
> 
> Eli Zaretskii <eliz <at> gnu.org> writes:
> 
> > Anyway, I think arguing about this aspect is not useful.  My problem
> > is not theoretical, it is practical: how much will break due to these
> > changes, and how long will it take us to become aware of the breakage
> > and attempt fixing it?
> 
> I went through all the uses of read-char, read-char-exclusively, and
> read-event in the tree and didn't find anything that'll break if we make
> these functions return C-g as an event.

How did you look for potential problems?  E.g., the C-g flow is
impossible to see in the code, you need to try it; doing that in all
the possible places where we use this stuff and with all the different
timings is practically impossible, I think.

The number of possible combinations of affected APIs with
while-no-input and other stuff sensitive to this is also quite close
to infinite.  And then there are keyboard macros, input methods (which
not all of them work the same with unread-command-events etc.) and
more.

> > And I know what will break.  As I told, we don't have a good set of
> > tests for it.  I only know that every time we changed something in
> > read_char and its ilk in recent years, we ended up with regressions.
> 
> All the more reason to simplify its contract.

If simplifying the contract removes support for valid use cases, we
break something, and need to somehow restore it (after we discover
what broke, which might take time).  And who knows what new complexity
that will bring us.  But even if overall it means simplification, the
energy invested in that is not free, and could be used in other areas
of Emacs, where ROI is higher.

> > I agree, but when dealing with old and very complex code that
> > thousands of programs rely upon, we need to consider the risks of
> > changing the old behavior even if it is somewhat inconsistent.
> > Because sometimes an old, known, and minor problem is better than new,
> > unknown, and exciting ones.
> 
> Yes, and for cases in which we're changing user-visible semantics in a
> way that'll break workflows --- like beginning-of-defun, perhaps ---
> then I agree with you.  I don't think this particular change belongs to
> that category.

Not sure I follow: response to keyboard input and C-g is pretty much
in users' faces.  Changes in it could well break workflows, when C-g
has special meanings, like in C-s.

> I've looked for evidence that would change my mind and
> haven't found any yet.  You're right that changes to the input loop are
> risky, but they're going to be necessary sooner or later anyway, so
> wouldn't you prefer to change simpler code?
> 
> Along the same lines, we could get rid of getcjmp too.  I'm not afraid
> of rationalizing the contract of read-event or tweaking any other part
> of keyboard.c, but that thing and quit_throw_to_read_char are extremely
> confusing and do scare me a bit --- all the more reason, in my mind, to
> get rid of them, like Gerd wanted to do years ago.  When is the right
> time to do that?  It's not like an Emacs 31 release is imminent.

It depends how you interpret "imminent".  Once Emacs 30.2 is released
(which should be soon), the emacs-31 release branch will be cut soon
afterwards, and development of Emacs 31 is basically frozen after
that, only bug fixes and last-minute changes of existing features are
allowed.  Fingers crossed, that should happen in 3 or 4 months.  The
release itself is probably at least 6 months after that, but we can no
longer make breaking changes during that period.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Wed, 11 Jun 2025 16:37:03 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Wed, 11 Jun 2025 09:35:48 -0700
Eli Zaretskii <eliz <at> gnu.org> writes:

>> From: Daniel Colascione <dancol <at> dancol.org>
>> Cc: pipcet <at> protonmail.com,  monnier <at> iro.umontreal.ca,  78737 <at> debbugs.gnu.org
>> Date: Wed, 11 Jun 2025 07:57:52 -0700
>> 
>> Eli Zaretskii <eliz <at> gnu.org> writes:
>> 
>> > Anyway, I think arguing about this aspect is not useful.  My problem
>> > is not theoretical, it is practical: how much will break due to these
>> > changes, and how long will it take us to become aware of the breakage
>> > and attempt fixing it?
>> 
>> I went through all the uses of read-char, read-char-exclusively, and
>> read-event in the tree and didn't find anything that'll break if we make
>> these functions return C-g as an event.
>
> How did you look for potential problems?  E.g., the C-g flow is
> impossible to see in the code, you need to try it; doing that in all
> the possible places where we use this stuff and with all the different
> timings is practically impossible, I think.


I tried everything (e.g. kbd-macro-query) where the effect wasn't
obvious from the code.  And I'm not sure what "timings" you're talking
about here: read-char, etc. will now _deterministically_ return \?C-g on
quit, so there's no timing involved.

For the broader change to quit, well, I've been using the thing and have
seen no problems.  isearch works fine.  Macros work fine.
minibuffer-quit in a macro works just as it did before too.

Input methods work fine --- at least greek, russian-typewriter, and
Chinese 4-corners.  Any others you think might be particularly hairy?

With the exception of read-char, read-char-exclusively, and read-event,
the Lisp API contract hasn't changed: wherever we would previously run
the command bound to C-g most of the time, we now run all the time.
That's not going to break anything: we're merely taking something that
was 1) supposed to happen, and 2) usually did happen, and make it happen
in all the cases users expect it to happen.  Keep in mind that you've
always been able to bind commands to C-g: it's just that previously, C-g
would occasionally fail to invoke these commands.  Now it does.

Quit in redisplay is now inhibited by default, but you said that was a
bad idea to allow in the first place.

Lisp quits work normally.  Better, actually: the NS port now even
reliably quits where it's supposed to quit.  The debugger works fine.
edebug works too.  debug-on-quit works.  Recursive edits ---
no difference.

The C-g eating test I've been using is to start a (compile "cat
/dev/urandom") and try to interact with Emacs.  Previously, the Emacs
command loop would eat tons of C-g presses as quits during this stress
test instead of running the command bound to C-g: now we reliably run
the bound command.  I've run the same test under a TTY too.  Works fine.

Transient, execute-extended-command, and other things that bind commands
to C-g all work fine and more reliably.  Quitting in minibuffer read
still works fine, even when we have a message popup like "complete but
not unique".

sit-for works fine.  while-no-input works fine: better now that it
doesn't drop events.

I'm really not seeing what there is to be worried about.  I'm especially
not worried about timing considering that we've made the system more
deterministic and reduced the number of timing-related bugs we might
have had.

I'll add the kill switch you wanted.  I don't think it's necessary, but
it's not going to do any harm.  Other than this kill switch and making
sure SIGUSR2 quits out of read-event, it seems fine to me.

>
> The number of possible combinations of affected APIs with
> while-no-input and other stuff sensitive to this is also quite close
> to infinite.  And then there are keyboard macros, input methods (which
> not all of them work the same with unread-command-events etc.) and
> more.
>
>> > And I know what will break.  As I told, we don't have a good set of
>> > tests for it.  I only know that every time we changed something in
>> > read_char and its ilk in recent years, we ended up with regressions.
>> 
>> All the more reason to simplify its contract.
>
> If simplifying the contract removes support for valid use cases

It doesn't remove support for any use cases.  It regularizes the API and
the implementation.  There are no lost capabilities.  The contract of
read_char (the C function, not to be confused with read-char the Lisp
function, which is confusingly totally different) has changed to not
internally quit, bu.

> we
> break something, and need to somehow restore it (after we discover
> what broke, which might take time).

One can imagine unlimited unknown unknowns.

> And who knows what new complexity
> that will bring us.  But even if overall it means simplification, the
> energy invested in that is not free, and could be used in other areas
> of Emacs, where ROI is higher.

Energy isn't fungible.

>> > I agree, but when dealing with old and very complex code that
>> > thousands of programs rely upon, we need to consider the risks of
>> > changing the old behavior even if it is somewhat inconsistent.
>> > Because sometimes an old, known, and minor problem is better than new,
>> > unknown, and exciting ones.
>> 
>> Yes, and for cases in which we're changing user-visible semantics in a
>> way that'll break workflows --- like beginning-of-defun, perhaps ---
>> then I agree with you.  I don't think this particular change belongs to
>> that category.
>
> Not sure I follow: response to keyboard input and C-g is pretty much
> in users' faces.  Changes in it could well break workflows, when C-g
> has special meanings, like in C-s.

The only thing users will notice is Emacs behaving more predictably, and
in the case of the NS port, being more responsive to quits.  We're not
talking about something in users' faces.

>> I've looked for evidence that would change my mind and
>> haven't found any yet.  You're right that changes to the input loop are
>> risky, but they're going to be necessary sooner or later anyway, so
>> wouldn't you prefer to change simpler code?
>> 
>> Along the same lines, we could get rid of getcjmp too.  I'm not afraid
>> of rationalizing the contract of read-event or tweaking any other part
>> of keyboard.c, but that thing and quit_throw_to_read_char are extremely
>> confusing and do scare me a bit --- all the more reason, in my mind, to
>> get rid of them, like Gerd wanted to do years ago.  When is the right
>> time to do that?  It's not like an Emacs 31 release is imminent.
>
> It depends how you interpret "imminent".  Once Emacs 30.2 is released
> (which should be soon), the emacs-31 release branch will be cut soon
> afterwards, and development of Emacs 31 is basically frozen after
> that, only bug fixes and last-minute changes of existing features are
> allowed.  Fingers crossed, that should happen in 3 or 4 months.  The
> release itself is probably at least 6 months after that, but we can no
> longer make breaking changes during that period.

3-4 months is plenty of time for testing.  If it doesn't smell right by
then, it doesn't have to be in Emacs 31.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Wed, 11 Jun 2025 19:22:02 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Wed, 11 Jun 2025 22:21:00 +0300
> From: Daniel Colascione <dancol <at> dancol.org>
> Cc: pipcet <at> protonmail.com,  monnier <at> iro.umontreal.ca,  78737 <at> debbugs.gnu.org
> Date: Wed, 11 Jun 2025 09:35:48 -0700
> 
> Eli Zaretskii <eliz <at> gnu.org> writes:
> 
> >> I went through all the uses of read-char, read-char-exclusively, and
> >> read-event in the tree and didn't find anything that'll break if we make
> >> these functions return C-g as an event.
> >
> > How did you look for potential problems?  E.g., the C-g flow is
> > impossible to see in the code, you need to try it; doing that in all
> > the possible places where we use this stuff and with all the different
> > timings is practically impossible, I think.
> 
> 
> I tried everything (e.g. kbd-macro-query) where the effect wasn't
> obvious from the code.  And I'm not sure what "timings" you're talking
> about here: read-char, etc. will now _deterministically_ return \?C-g on
> quit, so there's no timing involved.

I mean with the current code: C-g pressed at different times could
produce different effects.

> For the broader change to quit, well, I've been using the thing and have
> seen no problems.  isearch works fine.  Macros work fine.
> minibuffer-quit in a macro works just as it did before too.

The problem with this stuff, in our experience, is that different
people use different setups and workflows, and problems tend to depend
on that.  Which is why it takes time until they get reported.

> Input methods work fine --- at least greek, russian-typewriter, and
> Chinese 4-corners.  Any others you think might be particularly hairy?

Some of the East Asian, perhaps.  Also, using input methods as part of
recording keyboard macros caused trouble at some point.

> With the exception of read-char, read-char-exclusively, and read-event,
> the Lisp API contract hasn't changed: wherever we would previously run
> the command bound to C-g most of the time, we now run all the time.
> That's not going to break anything: we're merely taking something that
> was 1) supposed to happen, and 2) usually did happen, and make it happen
> in all the cases users expect it to happen.  Keep in mind that you've
> always been able to bind commands to C-g: it's just that previously, C-g
> would occasionally fail to invoke these commands.  Now it does.

What about the effect of quit-flag?

> Lisp quits work normally.  Better, actually: the NS port now even
> reliably quits where it's supposed to quit.  The debugger works fine.
> edebug works too.  debug-on-quit works.  Recursive edits ---
> no difference.

What about C-g on Unix TTYs?  Including when there are additional Lisp
threads?

> I'll add the kill switch you wanted.  I don't think it's necessary, but
> it's not going to do any harm.  Other than this kill switch and making
> sure SIGUSR2 quits out of read-event, it seems fine to me.

We should ask more people to try the branch, especially on other
platforms.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Wed, 11 Jun 2025 21:46:02 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Wed, 11 Jun 2025 14:44:57 -0700
Eli Zaretskii <eliz <at> gnu.org> writes:

>> From: Daniel Colascione <dancol <at> dancol.org>
>> Cc: pipcet <at> protonmail.com,  monnier <at> iro.umontreal.ca,  78737 <at> debbugs.gnu.org
>> Date: Wed, 11 Jun 2025 09:35:48 -0700
>> 
>> Eli Zaretskii <eliz <at> gnu.org> writes:
>> 
>> >> I went through all the uses of read-char, read-char-exclusively, and
>> >> read-event in the tree and didn't find anything that'll break if we make
>> >> these functions return C-g as an event.
>> >
>> > How did you look for potential problems?  E.g., the C-g flow is
>> > impossible to see in the code, you need to try it; doing that in all
>> > the possible places where we use this stuff and with all the different
>> > timings is practically impossible, I think.
>> 
>> 
>> I tried everything (e.g. kbd-macro-query) where the effect wasn't
>> obvious from the code.  And I'm not sure what "timings" you're talking
>> about here: read-char, etc. will now _deterministically_ return \?C-g on
>> quit, so there's no timing involved.
>
> I mean with the current code: C-g pressed at different times could
> produce different effects.

Given that these "different times" have been nondeterministic and that
there's no legitimate reason a program would rely on them, I don't see
our having introduced any timing issues, and none have shown up in
my tests.

>> For the broader change to quit, well, I've been using the thing and have
>> seen no problems.  isearch works fine.  Macros work fine.
>> minibuffer-quit in a macro works just as it did before too.
>
> The problem with this stuff, in our experience, is that different
> people use different setups and workflows, and problems tend to depend
> on that.  Which is why it takes time until they get reported.

In theory, Hyrum's law can bite you any time, but I'm just not seeing
behavior depend on a timing bug.  The read-event contract could in
theory break someone, but I still haven't seen evidence of it
actually happening.

>> Input methods work fine --- at least greek, russian-typewriter, and
>> Chinese 4-corners.  Any others you think might be particularly hairy?
>
> Some of the East Asian, perhaps.  Also, using input methods as part of
> recording keyboard macros caused trouble at some point.

There's one East Asian input method in the list already.

>> With the exception of read-char, read-char-exclusively, and read-event,
>> the Lisp API contract hasn't changed: wherever we would previously run
>> the command bound to C-g most of the time, we now run all the time.
>> That's not going to break anything: we're merely taking something that
>> was 1) supposed to happen, and 2) usually did happen, and make it happen
>> in all the cases users expect it to happen.  Keep in mind that you've
>> always been able to bind commands to C-g: it's just that previously, C-g
>> would occasionally fail to invoke these commands.  Now it does.
>
> What about the effect of quit-flag?

Nothing about the meaning of quit-flag has changed.

>> Lisp quits work normally.  Better, actually: the NS port now even
>> reliably quits where it's supposed to quit.  The debugger works fine.
>> edebug works too.  debug-on-quit works.  Recursive edits ---
>> no difference.
>
> What about C-g on Unix TTYs?  Including when there are additional Lisp
> threads?

Unix TTYs work fine.

Threads work as well as they ever have: both in master and on my branch,
this puts Emacs into an unresponsive and unquittable state:

    (make-thread (lambda () (while t)) "spinner")

At least it's not a regression.

Basic accept-process-output with a reasonable timeout on a thread works
fine and doesn't interfere with interactive quitting and other
UI interactions.

>
>> I'll add the kill switch you wanted.  I don't think it's necessary, but
>> it's not going to do any harm.  Other than this kill switch and making
>> sure SIGUSR2 quits out of read-event, it seems fine to me.
>
> We should ask more people to try the branch, especially on other
> platforms.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Thu, 12 Jun 2025 01:04:01 GMT) Full text and rfc822 format available.

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

From: Lynn Winebarger <owinebar <at> gmail.com>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>, pipcet <at> protonmail.com,
 monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Wed, 11 Jun 2025 21:03:17 -0400
On Wed, Jun 11, 2025 at 12:37 PM Daniel Colascione <dancol <at> dancol.org> wrote:
>  The contract of
> read_char (the C function, not to be confused with read-char the Lisp
> function, which is confusingly totally different) [...]

You are so right, but don't forget the bypassing of the function cell
for Qread_char in Fread to hardwire a call to Qread_minibuffer
instead.


Lynn




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Thu, 12 Jun 2025 05:23:02 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Thu, 12 Jun 2025 08:22:10 +0300
> From: Daniel Colascione <dancol <at> dancol.org>
> Cc: pipcet <at> protonmail.com,  monnier <at> iro.umontreal.ca,  78737 <at> debbugs.gnu.org
> Date: Wed, 11 Jun 2025 14:44:57 -0700
> 
> >> I tried everything (e.g. kbd-macro-query) where the effect wasn't
> >> obvious from the code.  And I'm not sure what "timings" you're talking
> >> about here: read-char, etc. will now _deterministically_ return \?C-g on
> >> quit, so there's no timing involved.
> >
> > I mean with the current code: C-g pressed at different times could
> > produce different effects.
> 
> Given that these "different times" have been nondeterministic and that
> there's no legitimate reason a program would rely on them, I don't see
> our having introduced any timing issues, and none have shown up in
> my tests.

Time will tell.  IME, these assumptions tend to break, at least
sometimes.

> >> For the broader change to quit, well, I've been using the thing and have
> >> seen no problems.  isearch works fine.  Macros work fine.
> >> minibuffer-quit in a macro works just as it did before too.
> >
> > The problem with this stuff, in our experience, is that different
> > people use different setups and workflows, and problems tend to depend
> > on that.  Which is why it takes time until they get reported.
> 
> In theory, Hyrum's law can bite you any time, but I'm just not seeing
> behavior depend on a timing bug.  The read-event contract could in
> theory break someone, but I still haven't seen evidence of it
> actually happening.

I hear you.  I'm just saying that if experience has taught us anything
in this area, it's that we should encourage as many people as possible
on as many different platforms as possible to try the new code and
report back.

> >> Input methods work fine --- at least greek, russian-typewriter, and
> >> Chinese 4-corners.  Any others you think might be particularly hairy?
> >
> > Some of the East Asian, perhaps.  Also, using input methods as part of
> > recording keyboard macros caused trouble at some point.
> 
> There's one East Asian input method in the list already.

Yes, but they work differently, so a few more won't hurt.

> >> With the exception of read-char, read-char-exclusively, and read-event,
> >> the Lisp API contract hasn't changed: wherever we would previously run
> >> the command bound to C-g most of the time, we now run all the time.
> >> That's not going to break anything: we're merely taking something that
> >> was 1) supposed to happen, and 2) usually did happen, and make it happen
> >> in all the cases users expect it to happen.  Keep in mind that you've
> >> always been able to bind commands to C-g: it's just that previously, C-g
> >> would occasionally fail to invoke these commands.  Now it does.
> >
> > What about the effect of quit-flag?
> 
> Nothing about the meaning of quit-flag has changed.

You mean, you didn't intend for it to change, right?  But the changes
on the branch definitely access and set it in several places, so it
_could_ change, albeit inadvertently.  Thus, I think it would be good
to test that as well.  The test suite uses inhibit-quit in 2 places,
so maybe run those tests, both interactively and noninteractively?
Also, searching the tree for "quit-flag" comes up with a few dozen
matches, so maybe look into those places and see if they still work as
expected?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Thu, 12 Jun 2025 13:30:03 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Thu, 12 Jun 2025 06:29:13 -0700
Eli Zaretskii <eliz <at> gnu.org> writes:

>> From: Daniel Colascione <dancol <at> dancol.org>
>> Cc: pipcet <at> protonmail.com,  monnier <at> iro.umontreal.ca,  78737 <at> debbugs.gnu.org
>> Date: Wed, 11 Jun 2025 14:44:57 -0700
>> 
>> >> I tried everything (e.g. kbd-macro-query) where the effect wasn't
>> >> obvious from the code.  And I'm not sure what "timings" you're talking
>> >> about here: read-char, etc. will now _deterministically_ return \?C-g on
>> >> quit, so there's no timing involved.
>> >
>> > I mean with the current code: C-g pressed at different times could
>> > produce different effects.
>> 
>> Given that these "different times" have been nondeterministic and that
>> there's no legitimate reason a program would rely on them, I don't see
>> our having introduced any timing issues, and none have shown up in
>> my tests.
>
> Time will tell.  IME, these assumptions tend to break, at least
> sometimes.
>
> >> For the broader change to quit, well, I've been using the thing and have
>> >> seen no problems.  isearch works fine.  Macros work fine.
>> >> minibuffer-quit in a macro works just as it did before too.
>> >
>> > The problem with this stuff, in our experience, is that different
>> > people use different setups and workflows, and problems tend to depend
>> > on that.  Which is why it takes time until they get reported.
>> 
>> In theory, Hyrum's law can bite you any time, but I'm just not seeing
>> behavior depend on a timing bug.  The read-event contract could in
>> theory break someone, but I still haven't seen evidence of it
>> actually happening.
>
> I hear you.  I'm just saying that if experience has taught us anything
> in this area, it's that we should encourage as many people as possible
> on as many different platforms as possible to try the new code and
> report back.
>
>> >> Input methods work fine --- at least greek, russian-typewriter, and
>> >> Chinese 4-corners.  Any others you think might be particularly hairy?
>> >
>> > Some of the East Asian, perhaps.  Also, using input methods as part of
>> > recording keyboard macros caused trouble at some point.
>> 
>> There's one East Asian input method in the list already.
>
> Yes, but they work differently, so a few more won't hurt.
>
>> >> With the exception of read-char, read-char-exclusively, and read-event,
>> >> the Lisp API contract hasn't changed: wherever we would previously run
>> >> the command bound to C-g most of the time, we now run all the time.
>> >> That's not going to break anything: we're merely taking something that
>> >> was 1) supposed to happen, and 2) usually did happen, and make it happen
>> >> in all the cases users expect it to happen.  Keep in mind that you've
>> >> always been able to bind commands to C-g: it's just that previously, C-g
>> >> would occasionally fail to invoke these commands.  Now it does.
>> >
>> > What about the effect of quit-flag?
>> 
>> Nothing about the meaning of quit-flag has changed.
>
> You mean, you didn't intend for it to change, right?  But the changes
> on the branch definitely access and set it in several places, so it
> _could_ change, albeit inadvertently.  Thus, I think it would be good
> to test that as well.  The test suite uses inhibit-quit in 2 places,
> so maybe run those tests, both interactively and noninteractively?
> Also, searching the tree for "quit-flag" comes up with a few dozen
> matches, so maybe look into those places and see if they still work as
> expected?

I've already tried everything that AFAICT might reasonably have broken
as a result of the change, including its use of quit-flag, and didn't
see anything wrong. I've been using the thing too. I'd expect that if
I'd broken something fundamental, bugs would have shown up by now. But
sure, let's test the branch and see whether anyone else can find
something wrong.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Thu, 12 Jun 2025 14:00:02 GMT) Full text and rfc822 format available.

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

From: Pip Cet <pipcet <at> protonmail.com>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Thu, 12 Jun 2025 13:58:51 +0000
"Daniel Colascione" <dancol <at> dancol.org> writes:

> Eli Zaretskii <eliz <at> gnu.org> writes:
>
>>> From: Daniel Colascione <dancol <at> dancol.org>
>>> Cc: pipcet <at> protonmail.com,  monnier <at> iro.umontreal.ca,  78737 <at> debbugs.gnu.org
>>> Date: Wed, 11 Jun 2025 07:08:45 -0700
>>>
>>> Why is it good that read-key-sequence swallows quits but not read-char?
>>
>> I don't know.  No one does.  maybe there's a good reason for it, maybe
>> there was one at some point but there isn't anymore, maybe it's just a
>> historical accident.
>>
>> But being unable to answer such questions doesn't mean changing the
>> behavior is safe.  It usually is the other way around, in a program as
>> old and complex as |Emacs.
>>
>>> C-g is an event.  Why should read-event (but not read-key-sequence?)
>>> translate one kind of input event (C-g) to an action (signal quit) but
>>> return other kinds of events as they're given?
>>
>> You consider this to be an inconsistency based only on the name of the
>> API.  But that's not necessarily the whole contract of the API.  It
>> doesn't need to be called get-char-quit-when-c-g to behave like it
>> does.
>>
>> Anyway, I think arguing about this aspect is not useful.  My problem
>> is not theoretical, it is practical: how much will break due to these
>> changes, and how long will it take us to become aware of the breakage
>> and attempt fixing it?
>
> I went through all the uses of read-char, read-char-exclusively, and
> read-event in the tree and didn't find anything that'll break if we make
> these functions return C-g as an event.  I did some things that worked

The first thing I looked at was mouse-drag-secondary.  It breaks (not
too badly: it just loses a quit event, but it's still an undesirable
change in behavior).

> marginally better, as I mentioned in my previous message.  It's possible
> something breaks, but I haven't seen evidence of breakage yet.

I'd say breaking (read-event) called in a loop is bad enough, because
how else are you supposed to start developing code which uses it?

> Yes, and for cases in which we're changing user-visible semantics in a
> way that'll break workflows --- like beginning-of-defun, perhaps ---
> then I agree with you.  I don't think this particular change belongs to
> that category.  I've looked for evidence that would change my mind and
> haven't found any yet.  You're right that changes to the input loop are
> risky, but they're going to be necessary sooner or later anyway, so
> wouldn't you prefer to change simpler code?

Since we've progressed to testing the branch, with the implication being
that we'll merge it soon, it may be too late to make alternative
suggestions.  In case it's not, though:

I think this discussion is concerned too much with what existing code
will break if we change quit not to quit, not enough with how much more
difficult it will be to develop code if we do, and not at all, so far,
with what the advantages of handling quit in Lisp (if Lisp decides to
handle it at all) are.

C-g isn't an input event in the same way that kicking someone in the
shin is not a dance move.  I want it to kick Emacs in the shin, and
break out of bad Lisp code, in *more* situations than it does now.

That would simplify things, and give us a more powerful quit rather than
one subject to innocent mistakes in Lisp code that looks just fine.  The
"C-g quits" rule would simply take precedence over all other input
handling rules, simplifying the contract if that's what you think of it
as.

People who don't want quit to quit could then call (set-quit-char nil)
or something similar and reuse the quit character for something else.
Something like that should be the only way to disable this extremely
useful feature, though.

We could even make it the default behavior and let people who want quit
put it in their init files.

Independently of all this, we should change our triple C-g detection to
work in cases where a Lisp user or keyboard.c clears quit-flag without
actually handling the quit.  If we change things so C-g is ordinary
input, we can at least limit the damage and let people use triple C-g in
the unquittable infloops that will result (triple C-g isn't safe and you
should restart your Emacs session after using it, but that's less
inconvenient than losing the entire session).

Maybe a compromise would be to continue the arms race and downgrade C-g
to normal input, C-g C-g C-g to a quit, and require even more C-g's for
a force-quit?

> Along the same lines, we could get rid of getcjmp too.  I'm not afraid
> of rationalizing the contract of read-event or tweaking any other part
> of keyboard.c, but that thing and quit_throw_to_read_char are extremely
> confusing and do scare me a bit --- all the more reason, in my mind, to
> get rid of them, like Gerd wanted to do years ago.  When is the right
> time to do that?  It's not like an Emacs 31 release is imminent.

I think that's a different discussion, to be honest.

getcjmp should be changed, definitely: it's currently updated
non-atomically using memcpy, which means we might longjmp to an
inconsistent jmp_buf from a signal handler and crash, IIUC.

Pip





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Thu, 12 Jun 2025 14:37:02 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Pip Cet <pipcet <at> protonmail.com>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Thu, 12 Jun 2025 07:35:51 -0700
Pip Cet <pipcet <at> protonmail.com> writes:

> "Daniel Colascione" <dancol <at> dancol.org> writes:
>
>> Eli Zaretskii <eliz <at> gnu.org> writes:
>>
>>>> From: Daniel Colascione <dancol <at> dancol.org>
>>>> Cc: pipcet <at> protonmail.com,  monnier <at> iro.umontreal.ca,  78737 <at> debbugs.gnu.org
>>>> Date: Wed, 11 Jun 2025 07:08:45 -0700
>>>>
>>>> Why is it good that read-key-sequence swallows quits but not read-char?
>>>
>>> I don't know.  No one does.  maybe there's a good reason for it, maybe
>>> there was one at some point but there isn't anymore, maybe it's just a
>>> historical accident.
>>>
>>> But being unable to answer such questions doesn't mean changing the
>>> behavior is safe.  It usually is the other way around, in a program as
>>> old and complex as |Emacs.
>>>
>>>> C-g is an event.  Why should read-event (but not read-key-sequence?)
>>>> translate one kind of input event (C-g) to an action (signal quit) but
>>>> return other kinds of events as they're given?
>>>
>>> You consider this to be an inconsistency based only on the name of the
>>> API.  But that's not necessarily the whole contract of the API.  It
>>> doesn't need to be called get-char-quit-when-c-g to behave like it
>>> does.
>>>
>>> Anyway, I think arguing about this aspect is not useful.  My problem
>>> is not theoretical, it is practical: how much will break due to these
>>> changes, and how long will it take us to become aware of the breakage
>>> and attempt fixing it?
>>
>> I went through all the uses of read-char, read-char-exclusively, and
>> read-event in the tree and didn't find anything that'll break if we make
>> these functions return C-g as an event.  I did some things that worked
>
> The first thing I looked at was mouse-drag-secondary.  It breaks (not
> too badly: it just loses a quit event, but it's still an undesirable
> change in behavior).

Recipe?  mouse-drag-secondary seems to be working all right for me, but
I never use the feature in anger so I might be missing something.

>> marginally better, as I mentioned in my previous message.  It's possible
>> something breaks, but I haven't seen evidence of breakage yet.
>
> I'd say breaking (read-event) called in a loop is bad enough, because
> how else are you supposed to start developing code which uses it?

No worse than calling read-key-sequence.

>> Yes, and for cases in which we're changing user-visible semantics in a
>> way that'll break workflows --- like beginning-of-defun, perhaps ---
>> then I agree with you.  I don't think this particular change belongs to
>> that category.  I've looked for evidence that would change my mind and
>> haven't found any yet.  You're right that changes to the input loop are
>> risky, but they're going to be necessary sooner or later anyway, so
>> wouldn't you prefer to change simpler code?
>
> Since we've progressed to testing the branch, with the implication being
> that we'll merge it soon, it may be too late to make alternative
> suggestions.  In case it's not, though:
>
> I think this discussion is concerned too much with what existing code
> will break if we change quit not to quit, not enough with how much more
> difficult it will be to develop code if we do, and not at all, so far,
> with what the advantages of handling quit in Lisp (if Lisp decides to
> handle it at all) are.

Lisp can quit just fine.  What are you talking about?

> C-g isn't an input event in the same way that kicking someone in the
> shin is not a dance move.  I want it to kick Emacs in the shin, and
> break out of bad Lisp code, in *more* situations than it does now.

C-g is an event.  The quit mechanism is a low-level mechanism for
breaking out of Lisp code in response to this event.  It makes no sense
one key on the keyboard with longjmp when we use a value for the two
keys next to it.  When code says it wants an event, it should get an
event.  That we interpret this event to mean quit in other circumstances
doesn't mean it's no longer an event.

> That would simplify things, and give us a more powerful quit rather than
> one subject to innocent mistakes in Lisp code that looks just fine.  The
> "C-g quits" rule would simply take precedence over all other input
> handling rules, simplifying the contract if that's what you think of it
> as.

I don't believe it's easier if we handle all keyboard events except one
by returning a value but longjmp on this one special one.

> People who don't want quit to quit could then call (set-quit-char nil)
> or something similar and reuse the quit character for something else.
> Something like that should be the only way to disable this extremely
> useful feature, though.

Huh?  Nobody's disabling quit.

> We could even make it the default behavior and let people who want quit
> put it in their init files.
>
> Independently of all this, we should change our triple C-g detection to
> work in cases where a Lisp user or keyboard.c clears quit-flag without
> actually handling the quit.  If we change things so C-g is ordinary
> input, we can at least limit the damage and let people use triple C-g in
> the unquittable infloops that will result (triple C-g isn't safe and you
> should restart your Emacs session after using it, but that's less
> inconvenient than losing the entire session).

Have you gotten your branches mixed up?  You seem to be ranting about a
set of patches with little resemblance to the ones we're discussing.
The branch we're talking about doesn't stop C-g quitting Lisp.

> Maybe a compromise would be to continue the arms race and downgrade C-g
> to normal input, C-g C-g C-g to a quit, and require even more C-g's for
> a force-quit?
>
>> Along the same lines, we could get rid of getcjmp too.  I'm not afraid
>> of rationalizing the contract of read-event or tweaking any other part
>> of keyboard.c, but that thing and quit_throw_to_read_char are extremely
>> confusing and do scare me a bit --- all the more reason, in my mind, to
>> get rid of them, like Gerd wanted to do years ago.  When is the right
>> time to do that?  It's not like an Emacs 31 release is imminent.
>
> I think that's a different discussion, to be honest.
>
> getcjmp should be changed, definitely: it's currently updated
> non-atomically using memcpy, which means we might longjmp to an
> inconsistent jmp_buf from a signal handler and crash, IIUC.

We don't jump in signal handlers for input.  If we did, we'd have much
bigger problems.  when's the last time you read keyboard.c?
handle_input_available_signal doesn't jump anywhere.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Thu, 12 Jun 2025 16:12:02 GMT) Full text and rfc822 format available.

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

From: Pip Cet <pipcet <at> protonmail.com>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Thu, 12 Jun 2025 16:11:35 +0000
1"Daniel Colascione" <dancol <at> dancol.org> writes:

> Pip Cet <pipcet <at> protonmail.com> writes:
>
>> The first thing I looked at was mouse-drag-secondary.  It breaks (not
>> too badly: it just loses a quit event, but it's still an undesirable
>> change in behavior).
>
> Recipe?  mouse-drag-secondary seems to be working all right for me, but
> I never use the feature in anger so I might be missing something.

Start dragging.  Quit.

Result on your branch: drag ends, no quit happens
Expected result: drag ends, quit happens

(I'm not sure about the behavior change of event-apply-*-modifier.  Maybe
those functions should bind inhibit-quit around the read-event call so
you can compose M-C-g as "C-x @ m C-g".  However, binding M-C-g is still
a bad idea, because someone might type "ESC C-g" for it and that would
cause a quit when in Lisp code.)

>>> marginally better, as I mentioned in my previous message.  It's possible
>>> something breaks, but I haven't seen evidence of breakage yet.
>>
>> I'd say breaking (read-event) called in a loop is bad enough, because
>> how else are you supposed to start developing code which uses it?
>
> No worse than calling read-key-sequence.

Yes, worse than that, if only because read-event is usually called
within a loop, while read-key-sequence isn't.

I disagree with the implication that every piece of Emacs source code
that is broken in some way justifies breaking other places in the same
way.

>> Since we've progressed to testing the branch, with the implication being
>> that we'll merge it soon, it may be too late to make alternative
>> suggestions.  In case it's not, though:
>>
>> I think this discussion is concerned too much with what existing code
>> will break if we change quit not to quit, not enough with how much more
>> difficult it will be to develop code if we do, and not at all, so far,
>> with what the advantages of handling quit in Lisp (if Lisp decides to
>> handle it at all) are.
>
> Lisp can quit just fine.  What are you talking about?

With your patches, Lisp now has the responsibility to handle quits in
many more situations, such as when it calls read-event.

>> People who don't want quit to quit could then call (set-quit-char nil)
>> or something similar and reuse the quit character for something else.
>> Something like that should be the only way to disable this extremely
>> useful feature, though.
>
> Huh?  Nobody's disabling quit.

You are, for some Lisp programs.

(while t
  (read-event))

is Lisp code which should be quittable.  On your branch, it's not
quittable.  Thus, you've disabled quit in this situation.

>> Independently of all this, we should change our triple C-g detection to
>> work in cases where a Lisp user or keyboard.c clears quit-flag without
>> actually handling the quit.  If we change things so C-g is ordinary
>> input, we can at least limit the damage and let people use triple C-g in
>> the unquittable infloops that will result (triple C-g isn't safe and you
>> should restart your Emacs session after using it, but that's less
>> inconvenient than losing the entire session).
>
> The branch we're talking about doesn't stop C-g quitting Lisp.

You're making Lisp programs (which use C subroutines) unquittable when
they weren't before.  I did not say that means "stop C-g quitting Lisp".

> Have you gotten your branches mixed up?  You seem to be ranting about a
> set of patches with little resemblance to the ones we're discussing.

> when's the last time you read keyboard.c?

What's the point of such personal attacks?  It's totally inappropriate
to suggest I did not read the source code, regardless of whether it's
correct or not.  And even if I misunderstood your patches, that tone is
inappropriate.

(It doesn't matter much, but I was correct in both of these cases: your
patch disables quit in some (too many) situaitons, and we do longjmp
from signal handlers in keyboard.c, as the code clearly states.)

> We don't jump in signal handlers for input.  If we did, we'd have much
> bigger problems.

Of course we do.

#0  0x00007ffff5bba260 in __longjmp_chk () at /lib64/libc.so.6
#1  0x00005555555aa1b8 in quit_throw_to_read_char (from_signal=from_signal <at> entry=true) at keyboard.c:12425
#2  0x00005555555aa24f in handle_interrupt (in_signal_handler=<optimized out>) at keyboard.c:12400
#3  0x000055555570cfca in deliver_process_signal (sig=2, handler=0x5555556eab10 <handle_interrupt_signal>) at sysdep.c:1751
#4  0x00007ffff5adaed0 in <signal handler called> () at /lib64/libc.so.6

As for the rest of your email, you mention longjmp a few times.  We
don't disagree on that point: if we can handle quits without using
longjmp (including longjmp from signal handlers), we should do that.

I hope you'll understand I might take a break from this discussion.

Pip





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Thu, 12 Jun 2025 16:33:02 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Pip Cet <pipcet <at> protonmail.com>
Cc: 78737 <at> debbugs.gnu.org, dancol <at> dancol.org, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Thu, 12 Jun 2025 19:32:26 +0300
> Date: Thu, 12 Jun 2025 13:58:51 +0000
> From: Pip Cet <pipcet <at> protonmail.com>
> Cc: Eli Zaretskii <eliz <at> gnu.org>, monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
> 
> I'd say breaking (read-event) called in a loop is bad enough, because
> how else are you supposed to start developing code which uses it?

Maybe this regression should be fixed, then.

> Since we've progressed to testing the branch, with the implication being
> that we'll merge it soon, it may be too late to make alternative
> suggestions.

We will merge only after we agree that (a) it does TRT, and (b) that
it was tested sufficiently well and all the problems it might cause
have been dealt with.

So it isn't too late to argue that the branch does something
incorrectly or sub-optimally.

> I think this discussion is concerned too much with what existing code
> will break if we change quit not to quit, not enough with how much more
> difficult it will be to develop code if we do, and not at all, so far,
> with what the advantages of handling quit in Lisp (if Lisp decides to
> handle it at all) are.
> 
> C-g isn't an input event in the same way that kicking someone in the
> shin is not a dance move.  I want it to kick Emacs in the shin, and
> break out of bad Lisp code, in *more* situations than it does now.

Please describe the situations where you'd like it to throw to top
level and it doesn't now.  Also, can this behavior be optional, like
debug-on-error and friends are?  Not everyone debugs Lisp code all the
time, so we definitely can have an "easy-break-out" feature that is by
default off.

> Maybe a compromise would be to continue the arms race and downgrade C-g
> to normal input, C-g C-g C-g to a quit, and require even more C-g's for
> a force-quit?

That's also possible, though less desirable: counting C-g presses when
you are desperate is not easy and we cannot rely on users to do that
reliably.

> > Along the same lines, we could get rid of getcjmp too.  I'm not afraid
> > of rationalizing the contract of read-event or tweaking any other part
> > of keyboard.c, but that thing and quit_throw_to_read_char are extremely
> > confusing and do scare me a bit --- all the more reason, in my mind, to
> > get rid of them, like Gerd wanted to do years ago.  When is the right
> > time to do that?  It's not like an Emacs 31 release is imminent.
> 
> I think that's a different discussion, to be honest.

I agree, and I think so does Daniel.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Thu, 12 Jun 2025 16:44:01 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Pip Cet <pipcet <at> protonmail.com>
Cc: 78737 <at> debbugs.gnu.org, dancol <at> dancol.org, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Thu, 12 Jun 2025 19:43:12 +0300
> Date: Thu, 12 Jun 2025 16:11:35 +0000
> From: Pip Cet <pipcet <at> protonmail.com>
> Cc: Eli Zaretskii <eliz <at> gnu.org>, monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
> 
> > when's the last time you read keyboard.c?
> 
> What's the point of such personal attacks?  It's totally inappropriate
> to suggest I did not read the source code, regardless of whether it's
> correct or not.  And even if I misunderstood your patches, that tone is
> inappropriate.
> 
> (It doesn't matter much, but I was correct in both of these cases: your
> patch disables quit in some (too many) situaitons, and we do longjmp
> from signal handlers in keyboard.c, as the code clearly states.)
> 
> > We don't jump in signal handlers for input.  If we did, we'd have much
> > bigger problems.
> 
> Of course we do.

You are both right: on TTY's C-g triggers SIGINT, and we do longjmp
from the SIGINT handler; on X C-g (like any keypress) triggers SIGIO,
and we do NOT longjmp from the SIGIO handler.

Anyway, can we please cool down and discuss this in a more friendly
fashion?  Daniel, if Pip has some reservations about the design or the
implementation on the branch, please make the effort to explain your
ideas and goals, and please try to address the concerns.  We should
strive to arrive at changes on which we all agree, and we should be on
the same page regarding the goals and the means to reach those goals.

> I hope you'll understand I might take a break from this discussion.

I hope no one takes a break because they feel attacked.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Thu, 12 Jun 2025 16:53:01 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Eli Zaretskii <eliz <at> gnu.org>, Pip Cet <pipcet <at> protonmail.com>
Cc: 78737 <at> debbugs.gnu.org, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Thu, 12 Jun 2025 09:52:22 -0700

On June 12, 2025 9:32:26 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
>> Date: Thu, 12 Jun 2025 13:58:51 +0000
>> From: Pip Cet <pipcet <at> protonmail.com>
>> Cc: Eli Zaretskii <eliz <at> gnu.org>, monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
>> 
>> I'd say breaking (read-event) called in a loop is bad enough, because
>> how else are you supposed to start developing code which uses it?
>
>Maybe this regression should be fixed, then.

It's not a regression. It's a bug fix. Not every behavior change is a problem. Who starts coding something by calling it in a loop? That's like learning to drive by crashing into a wall.

And besides, like I keep saying, read-key-sequence works the same way read-event does and over lots of decades nobody to my knowledge has called it unprogrammable.

You have to think about these things, not just reflexively conclude that it's bad because it's different.

>> Since we've progressed to testing the branch, with the implication being
>> that we'll merge it soon, it may be too late to make alternative
>> suggestions.
>
>We will merge only after we agree that (a) it does TRT, and (b) that
>it was tested sufficiently well and all the problems it might cause
>have been dealt with.
>
>So it isn't too late to argue that the branch does something
>incorrectly or sub-optimally.
>
>> I think this discussion is concerned too much with what existing code
>> will break if we change quit not to quit, not enough with how much more
>> difficult it will be to develop code if we do, and not at all, so far,
>> with what the advantages of handling quit in Lisp (if Lisp decides to
>> handle it at all) are.
>> 
>> C-g isn't an input event in the same way that kicking someone in the
>> shin is not a dance move.  I want it to kick Emacs in the shin, and
>> break out of bad Lisp code, in *more* situations than it does now.
>
>Please describe the situations where you'd like it to throw to top
>level and it doesn't now.  Also, can this behavior be optional, like
>debug-on-error and friends are?  Not everyone debugs Lisp code all the
>time, so we definitely can have an "easy-break-out" feature that is by
>default off.
>
>> Maybe a compromise would be to continue the arms race and downgrade C-g
>> to normal input, C-g C-g C-g to a quit, and require even more C-g's for
>> a force-quit?

Yes, that's what I have in mind, and it'll help in other situations in which we eat C-g today. Don't think of it as upgrading a quit, but rather hinting to Emacs that it should interpret C-g as quit in situations it would otherwise interpret it as an event. Not every C-g is a quit.

The branch creates a simple mental model of how this works:

1. By default, C-g is an input event like everything else. You can read it, read a key sequence involving it, and bind it to keymaps like any other key.

2. As a special feature, Emacs interprets C-g while Lisp is running (not blocked on input) to mean that it should raise a special signal, called quit, and take you back to the command loop ASAP.

3. Lisp code can disable #2 in a section of code by binding inhibit-quit around anything that's important to run without interruption.

4. If you hit C-g enough times in a short enough time, we treat C-g as a quit even in contexts where we're trying to read input. We display a message when doing so. For example, at this stage, we can break out of (while t (read-char)).

5. If you continue to hit C-g, we conclude Emacs is hooked and disable inhibit-quit so you can break out of sections of code marked ordinarily unbreakable. Doing so may break your Emacs, so we'll display a message saying this has happened.

#4 and #5 aren't implemented on the branch, but will be. We do have a legacy force quit feature, but it skips #4 and goes straight to #5, and it never worked for me in GUI Emacs anyway.

>That's also possible, though less desirable: counting C-g presses when
>you are desperate is not easy and we cannot rely on users to do that
>reliably.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Thu, 12 Jun 2025 16:57:01 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Thu, 12 Jun 2025 19:56:26 +0300
> Date: Thu, 12 Jun 2025 09:52:22 -0700
> From: Daniel Colascione <dancol <at> dancol.org>
> CC: monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
> 
> 
> 
> On June 12, 2025 9:32:26 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
> >> Date: Thu, 12 Jun 2025 13:58:51 +0000
> >> From: Pip Cet <pipcet <at> protonmail.com>
> >> Cc: Eli Zaretskii <eliz <at> gnu.org>, monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
> >> 
> >> I'd say breaking (read-event) called in a loop is bad enough, because
> >> how else are you supposed to start developing code which uses it?
> >
> >Maybe this regression should be fixed, then.
> 
> It's not a regression. It's a bug fix. Not every behavior change is a problem. Who starts coding something by calling it in a loop? That's like learning to drive by crashing into a wall.

Did it never happen to you that you wrote a loop and forgot the part
that advances the counter or some other thing that will prevent an
infloop?  Stuff happens when developing code.

> You have to think about these things, not just reflexively conclude that it's bad because it's different.

Daniel, you are not the only one who thinks about this.  The fact that
people disagree doesn't necessarily mean they didn't think.  Let's try
to leave such "arguments" out of the discussion.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Thu, 12 Jun 2025 17:48:01 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Pip Cet <pipcet <at> protonmail.com>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Thu, 12 Jun 2025 10:46:56 -0700
Pip Cet <pipcet <at> protonmail.com> writes:

> 1"Daniel Colascione" <dancol <at> dancol.org> writes:
>
>> Pip Cet <pipcet <at> protonmail.com> writes:
>>
>>> The first thing I looked at was mouse-drag-secondary.  It breaks (not
>>> too badly: it just loses a quit event, but it's still an undesirable
>>> change in behavior).
>>
>> Recipe?  mouse-drag-secondary seems to be working all right for me, but
>> I never use the feature in anger so I might be missing something.
>
> Start dragging.  Quit.
>
> Result on your branch: drag ends, no quit happens
> Expected result: drag ends, quit happens

I'd classify that as code working better.  No user scenario has
"broken".  If we want to display a message that the drag has ended,
let's display a message saying that in particular.

> (I'm not sure about the behavior change of event-apply-*-modifier.  Maybe
> those functions should bind inhibit-quit around the read-event call so
> you can compose M-C-g as "C-x @ m C-g".  However, binding M-C-g is still
> a bad idea, because someone might type "ESC C-g" for it and that would
> cause a quit when in Lisp code.)

Users can do plenty of things that are bad ideas.

>>>> marginally better, as I mentioned in my previous message.  It's possible
>>>> something breaks, but I haven't seen evidence of breakage yet.
>>>
>>> I'd say breaking (read-event) called in a loop is bad enough, because
>>> how else are you supposed to start developing code which uses it?
>>
>> No worse than calling read-key-sequence.
>
> Yes, worse than that, if only because read-event is usually called
> within a loop, while read-key-sequence isn't.

If it were a problem, we'd have seen more things break.  What user
scenario is broken?

> I disagree with the implication that every piece of Emacs source code
> that is broken in some way justifies breaking other places in the same
> way.

It's not broken.

>>> Since we've progressed to testing the branch, with the implication being
>>> that we'll merge it soon, it may be too late to make alternative
>>> suggestions.  In case it's not, though:
>>>
>>> I think this discussion is concerned too much with what existing code
>>> will break if we change quit not to quit, not enough with how much more
>>> difficult it will be to develop code if we do, and not at all, so far,
>>> with what the advantages of handling quit in Lisp (if Lisp decides to
>>> handle it at all) are.
>>
>> Lisp can quit just fine.  What are you talking about?
>
> With your patches, Lisp now has the responsibility to handle quits in
> many more situations, such as when it calls read-event.

No, read-event _reads an event_.  It's not the job of read-event to also
quit.  Quitting is for breaking out of running code.  It's not a side
channel for general input.

>>> People who don't want quit to quit could then call (set-quit-char nil)
>>> or something similar and reuse the quit character for something else.
>>> Something like that should be the only way to disable this extremely
>>> useful feature, though.
>>
>> Huh?  Nobody's disabling quit.
>
> You are, for some Lisp programs.
>
> (while t
>   (read-event))
>
> is Lisp code which should be quittable.  On your branch, it's not
> quittable.  Thus, you've disabled quit in this situation.

This is a "doctor, it hurts when I do this" situation.  If we had a bug
causing (/ 8 2) to report 3 instead of 4, you could argue that we
regressed a function calling (and (= (/ 8 2) 3) (insert "blah")).

>>> Independently of all this, we should change our triple C-g detection to
>>> work in cases where a Lisp user or keyboard.c clears quit-flag without
>>> actually handling the quit.  If we change things so C-g is ordinary
>>> input, we can at least limit the damage and let people use triple C-g in
>>> the unquittable infloops that will result (triple C-g isn't safe and you
>>> should restart your Emacs session after using it, but that's less
>>> inconvenient than losing the entire session).
>>
>> The branch we're talking about doesn't stop C-g quitting Lisp.
>
> You're making Lisp programs (which use C subroutines) unquittable when
> they weren't before.  I did not say that means "stop C-g quitting
> Lisp".

You constructed an unrealistic program.  People do call (read-event) in
a loop, but they _do something_ with the event.  Otherwise, why would
they call it and not (sit-for) or something?

>> Have you gotten your branches mixed up?  You seem to be ranting about a
>> set of patches with little resemblance to the ones we're discussing.
>
>> when's the last time you read keyboard.c?
>
> What's the point of such personal attacks?  It's totally inappropriate
> to suggest I did not read the source code, regardless of whether it's
> correct or not.  And even if I misunderstood your patches, that tone is
> inappropriate.
>
> (It doesn't matter much, but I was correct in both of these cases: your
> patch disables quit in some (too many) situaitons, and we do longjmp
> from signal handlers in keyboard.c, as the code clearly states.)
>
>> We don't jump in signal handlers for input.  If we did, we'd have much
>> bigger problems.
>
> Of course we do.
>
> #0  0x00007ffff5bba260 in __longjmp_chk () at /lib64/libc.so.6
> #1  0x00005555555aa1b8 in quit_throw_to_read_char (from_signal=from_signal <at> entry=true) at keyboard.c:12425
> #2  0x00005555555aa24f in handle_interrupt (in_signal_handler=<optimized out>) at keyboard.c:12400
> #3  0x000055555570cfca in deliver_process_signal (sig=2, handler=0x5555556eab10 <handle_interrupt_signal>) at sysdep.c:1751
> #4  0x00007ffff5adaed0 in <signal handler called> () at
> /lib64/libc.so.6

In my testing, on macOS (even without a window system), I see this
happen _only_ inside pselect, which doesn't really count: that's a
singular known point, not arbitrary code.  That's correct, if ugly.

In this part of the code, there's no chance of a write to getcjmp being
torn: the system call functions as a memory barrier.

If we can jump through _arbitrary code_ on other platforms, that's a big
problem, since if I'm reading this right, we can call arbitrary Lisp via
Fdo_auto_save.  That would be dangerous and would always have been.

But even if we _could_ call through arbitrary code this way, we still
wouldn't tear getcjmp because we call pthread_sigmask (SIG_SETMASK,
&empty_mask, 0) after we set it, and the system call acts as a memory
barrier again.  (We don't handle this signal on non-main threads either
if I'm reading this right.)

But who knows?  This code is tangled and the safer thing would be to get
rid of signal handlers that do more than set flags.

> As for the rest of your email, you mention longjmp a few times.  We
> don't disagree on that point: if we can handle quits without using
> longjmp (including longjmp from signal handlers), we should do that.

We should just treat TTY quits like GUI quits and quits from secondary TTYs.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Thu, 12 Jun 2025 18:05:02 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Thu, 12 Jun 2025 11:04:06 -0700

On June 12, 2025 9:56:26 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
>> Date: Thu, 12 Jun 2025 09:52:22 -0700
>> From: Daniel Colascione <dancol <at> dancol.org>
>> CC: monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
>> 
>> 
>> 
>> On June 12, 2025 9:32:26 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
>> >> Date: Thu, 12 Jun 2025 13:58:51 +0000
>> >> From: Pip Cet <pipcet <at> protonmail.com>
>> >> Cc: Eli Zaretskii <eliz <at> gnu.org>, monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
>> >> 
>> >> I'd say breaking (read-event) called in a loop is bad enough, because
>> >> how else are you supposed to start developing code which uses it?
>> >
>> >Maybe this regression should be fixed, then.
>> 
>> It's not a regression. It's a bug fix. Not every behavior change is a problem. Who starts coding something by calling it in a loop? That's like learning to drive by crashing into a wall.
>
>Did it never happen to you that you wrote a loop and forgot the part
>that advances the counter or some other thing that will prevent an
>infloop?  Stuff happens when developing code.

And the mechanism I described just now addresses the problem of recovering from programmer error.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Thu, 12 Jun 2025 18:35:02 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Thu, 12 Jun 2025 21:34:31 +0300
> Date: Thu, 12 Jun 2025 11:04:06 -0700
> From: Daniel Colascione <dancol <at> dancol.org>
> CC: pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
> 
> 
> 
> On June 12, 2025 9:56:26 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
> >> Date: Thu, 12 Jun 2025 09:52:22 -0700
> >> From: Daniel Colascione <dancol <at> dancol.org>
> >> CC: monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
> >> 
> >> 
> >> 
> >> On June 12, 2025 9:32:26 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
> >> >> Date: Thu, 12 Jun 2025 13:58:51 +0000
> >> >> From: Pip Cet <pipcet <at> protonmail.com>
> >> >> Cc: Eli Zaretskii <eliz <at> gnu.org>, monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
> >> >> 
> >> >> I'd say breaking (read-event) called in a loop is bad enough, because
> >> >> how else are you supposed to start developing code which uses it?
> >> >
> >> >Maybe this regression should be fixed, then.
> >> 
> >> It's not a regression. It's a bug fix. Not every behavior change is a problem. Who starts coding something by calling it in a loop? That's like learning to drive by crashing into a wall.
> >
> >Did it never happen to you that you wrote a loop and forgot the part
> >that advances the counter or some other thing that will prevent an
> >infloop?  Stuff happens when developing code.
> 
> And the mechanism I described just now addresses the problem of recovering from programmer error.

Sorry, I must have missed it (assuming that was in your previous
message).  Could you please point me to that description, or repeat
it?

Specifically, what I'm interested in is how come

 (while t
   (read-event))

cannot be interrupted by C-g, but you seem to be saying that

 (while t
   (let (evt (read-event))
     (do-something-with evt)))

_can_ be interrupted?  Let's say when I type C-g, the loop is stuck
inside read-event: could you then describe how this latter loop could
be interrupted in that case?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Thu, 12 Jun 2025 18:39:02 GMT) Full text and rfc822 format available.

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

From: Pip Cet <pipcet <at> protonmail.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, dancol <at> dancol.org, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Thu, 12 Jun 2025 18:37:58 +0000
"Eli Zaretskii" <eliz <at> gnu.org> writes:

>> Date: Thu, 12 Jun 2025 13:58:51 +0000
>> From: Pip Cet <pipcet <at> protonmail.com>
>> Cc: Eli Zaretskii <eliz <at> gnu.org>, monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
>>
>> I'd say breaking (read-event) called in a loop is bad enough, because
>> how else are you supposed to start developing code which uses it?
>
> Maybe this regression should be fixed, then.

I agree it should be, if we can agree it is a regression; the other
issues I see are SIGUSR2 handling (which seems fixable) and the question
of whether saving unhandled events in unread-command-events is always
the right choice.

>> I think this discussion is concerned too much with what existing code
>> will break if we change quit not to quit, not enough with how much more
>> difficult it will be to develop code if we do, and not at all, so far,
>> with what the advantages of handling quit in Lisp (if Lisp decides to
>> handle it at all) are.
>>
>> C-g isn't an input event in the same way that kicking someone in the
>> shin is not a dance move.  I want it to kick Emacs in the shin, and
>> break out of bad Lisp code, in *more* situations than it does now.
>
> Please describe the situations where you'd like it to throw to top
> level and it doesn't now.

One situation for ordinary quits; three for force-quit.

Situation 1:

I'd like read-event, when called while inhibit-quit is t, to report
quits by setting quit-flag in addition to returning quit_char: it'll
simplify the C code, and it would make

(while t
  (let ((inhibit-quit t))
    (read-event)))

quittable, as I naively expected it to be.  The old behavior would
remain available, but require an extra let binding.

Note that this isn't

(let ((inhibit-quit t))
  (while t
    (read-event)))

While I'd like to change the C code to make this second case
force-quittable, I see no way to perform an ordinary quit for this code.
The reason I mention it is that removing

      /* If we report the quit char as an event,
	 don't do so more than once.  */
      if (!NILP (Vinhibit_quit))
	Vquit_flag = Qnil;

changes behavior for both loops: the first becomes quittable, the second
becomes force-quittable.

Situation 2:

(while t
  (read-key-sequence ""))

It'd be nice for this situation to be force-quittable; I don't see why
it shouldn't be, even though what I implemented is a bit of a hack...

Situation 3:

Several force-quits in the same session.  Reset force_quit_count to 0
once it reaches 3.  I've seen force_quit_count reach higher values than
3 (there was no regular quit in between force quit attempts).

> Also, can this behavior be optional, like debug-on-error and friends
> are?  Not everyone debugs Lisp code all the time, so we definitely can
> have an "easy-break-out" feature that is by default off.

Absolutely.  We could easily make it customizable whether read-event
sets quit-flag after a quit:

1. never
2. only when !inhibit-quit
3. always

>> Maybe a compromise would be to continue the arms race and downgrade C-g
>> to normal input, C-g C-g C-g to a quit, and require even more C-g's for
>> a force-quit?
>
> That's also possible, though less desirable: counting C-g presses when
> you are desperate is not easy and we cannot rely on users to do that
> reliably.

And we'd need a way to detect when a quit is handled (however we define
"handled") so we could reset force_quit_counter.  Not a trivial change.

Pip





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Thu, 12 Jun 2025 18:50:01 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Pip Cet <pipcet <at> protonmail.com>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Thu, 12 Jun 2025 11:48:50 -0700
Pip Cet <pipcet <at> protonmail.com> writes:

> "Eli Zaretskii" <eliz <at> gnu.org> writes:
>
>>> Date: Thu, 12 Jun 2025 13:58:51 +0000
>>> From: Pip Cet <pipcet <at> protonmail.com>
>>> Cc: Eli Zaretskii <eliz <at> gnu.org>, monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
>>>
>>> I'd say breaking (read-event) called in a loop is bad enough, because
>>> how else are you supposed to start developing code which uses it?
>>
>> Maybe this regression should be fixed, then.
>
> I agree it should be, if we can agree it is a regression; the other
> issues I see are SIGUSR2 handling (which seems fixable) and the question
> of whether saving unhandled events in unread-command-events is always
> the right choice.
>
>>> I think this discussion is concerned too much with what existing code
>>> will break if we change quit not to quit, not enough with how much more
>>> difficult it will be to develop code if we do, and not at all, so far,
>>> with what the advantages of handling quit in Lisp (if Lisp decides to
>>> handle it at all) are.
>>>
>>> C-g isn't an input event in the same way that kicking someone in the
>>> shin is not a dance move.  I want it to kick Emacs in the shin, and
>>> break out of bad Lisp code, in *more* situations than it does now.
>>
>> Please describe the situations where you'd like it to throw to top
>> level and it doesn't now.
>
> One situation for ordinary quits; three for force-quit.
>
> Situation 1:
>
> I'd like read-event, when called while inhibit-quit is t, to report
> quits by setting quit-flag in addition to returning quit_char: it'll
> simplify the C code, and it would make
>
> (while t
>   (let ((inhibit-quit t))
>     (read-event)))

I strongly disagree.  read-event should read an event.
Setting quit-flag by side effect when it happens to read one key and not
others makes the interface less regular and understandable.

read-key-sequence is the high-level function.  read-event is the
low-level function.  It makes zero sense for the high-level function to
report a key event as a low-level event and for the low-level function
to do special non-local flow control in response to that event.

> quittable, as I naively expected it to be.

The naive expectation is that this function do its job.

> The old behavior would
> remain available, but require an extra let binding.
>
> Note that this isn't
>
> (let ((inhibit-quit t))
>   (while t
>     (read-event)))

Then fix read-key-sequence, which acts the same way.

> While I'd like to change the C code to make this second case
> force-quittable, I see no way to perform an ordinary quit for this code.
> The reason I mention it is that removing
>
>       /* If we report the quit char as an event,
> 	 don't do so more than once.  */
>       if (!NILP (Vinhibit_quit))
> 	Vquit_flag = Qnil;
>
> changes behavior for both loops: the first becomes quittable, the second
> becomes force-quittable.

There is no reason for these loops to behave differently.  If we want to
make both force-quittable, as I described in
https://lists.gnu.org/archive/html/bug-gnu-emacs/2025-06/msg00629.html,
but an ordinary press of C-g should not cause a quit when Lisp has
explicitly asked to read an event by calling a function whose job it is
to read events.

> Situation 2:
>
> (while t
>   (read-key-sequence ""))
>
> It'd be nice for this situation to be force-quittable; I don't see why
> it shouldn't be, even though what I implemented is a bit of a hack...
>
> Situation 3:
>
> Several force-quits in the same session.  Reset force_quit_count to 0
> once it reaches 3.  I've seen force_quit_count reach higher values than
> 3 (there was no regular quit in between force quit attempts).

Get rid of force_quit_count entirely and just detect (by writing into a
ring buffer) whether we've received N quits in the last T milliseconds.
That'll work the same way regardless of how quits gets detected.  We can
change N and T freely.

On your Emacs, you can set N to one and T to zero.

>> Also, can this behavior be optional, like debug-on-error and friends
>> are?  Not everyone debugs Lisp code all the time, so we definitely can
>> have an "easy-break-out" feature that is by default off.

> Absolutely.  We could easily make it customizable whether read-event
> sets quit-flag after a quit:
>
> 1. never
> 2. only when !inhibit-quit
> 3. always

We can customize thresholds for general behavior, but I don't think we
should not have preferences that alter the operation of fundamental
Emacs primitives.  You couldn't add a preference that made if regard 0
as well as nil as false, would you? 

>>> Maybe a compromise would be to continue the arms race and downgrade C-g
>>> to normal input, C-g C-g C-g to a quit, and require even more C-g's for
>>> a force-quit?
>>
>> That's also possible, though less desirable: counting C-g presses when
>> you are desperate is not easy and we cannot rely on users to do that
>> reliably.
>
> And we'd need a way to detect when a quit is handled (however we define
> "handled") so we could reset force_quit_counter.  Not a trivial change.

You don't.  You just upgrade any quit that happens under the N and T
threshold above.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Thu, 12 Jun 2025 19:08:02 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Thu, 12 Jun 2025 12:07:32 -0700
Eli Zaretskii <eliz <at> gnu.org> writes:

>> Date: Thu, 12 Jun 2025 11:04:06 -0700
>> From: Daniel Colascione <dancol <at> dancol.org>
>> CC: pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
>> 
>> 
>> 
>> On June 12, 2025 9:56:26 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
>> >> Date: Thu, 12 Jun 2025 09:52:22 -0700
>> >> From: Daniel Colascione <dancol <at> dancol.org>
>> >> CC: monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
>> >> 
>> >> 
>> >> 
>> >> On June 12, 2025 9:32:26 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
>> >> >> Date: Thu, 12 Jun 2025 13:58:51 +0000
>> >> >> From: Pip Cet <pipcet <at> protonmail.com>
>> >> >> Cc: Eli Zaretskii <eliz <at> gnu.org>, monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
>> >> >> 
>> >> >> I'd say breaking (read-event) called in a loop is bad enough, because
>> >> >> how else are you supposed to start developing code which uses it?
>> >> >
>> >> >Maybe this regression should be fixed, then.
>> >> 
>> >> It's not a regression. It's a bug fix. Not every behavior change is a problem. Who starts coding something by calling it in a loop? That's like learning to drive by crashing into a wall.
>> >
>> >Did it never happen to you that you wrote a loop and forgot the part
>> >that advances the counter or some other thing that will prevent an
>> >infloop?  Stuff happens when developing code.
>> 
>> And the mechanism I described just now addresses the problem of recovering from programmer error.
>
> Sorry, I must have missed it (assuming that was in your previous
> message).  Could you please point me to that description, or repeat
> it?

It's near the bottom of 
https://lists.gnu.org/archive/html/bug-gnu-emacs/2025-06/msg00629.html

> Specifically, what I'm interested in is how come
>
>  (while t
>    (read-event))
>
> cannot be interrupted by C-g, but you seem to be saying that
>
>  (while t
>    (let (evt (read-event))
>      (do-something-with evt)))
>
> _can_ be interrupted?

(read-event) returns \?C-g.  If the C-g arrives when Lisp code is
running (e.g. inside (do-something-with evt), then we quit --- unless
that code is also reading an event, in which case we return it.

> Let's say when I type C-g, the loop is stuck
> inside read-event: could you then describe how this latter loop could
> be interrupted in that case?

As I mentioned just now in yet another message, we impose a threshold.

N quits in T milliseconds -> upgrade quit to immediate-quit when we
Fsignal, with quit on immediate-quit's condition list, just like we do
for minibuffer-quit.  immediate-quit means "I definitely meant to exit
whatever I'm doing, even if the code says to read an event or key
sequence".

N_emergency quits in T_emergency milliseconds -> do same as above,
except that we ignore inhibit-quit when deciding whether to signal:

/* Have we gotten at least N quits in last T milliseconds?  */
static bool
check_recent_quits (int n, int t)
{
  return <whether we've received N_emergency quits
  in last T_emergency milliseconds>;
}

void
probably_quit (void)
{
  specpdl_ref gc_count = inhibit_garbage_collection ();

  /* Quit promptly if processing pending signals makes us want to
     quit.  */
  if (!QUITP && pending_signals)
    process_pending_signals ();
  if (QUITP || check_recent_quit(quit_emergency_count, quit_emergency_window))
    process_quit_flag ();

  unbind_to (gc_count, Qnil);
}

and then,

Lisp_Object
quit (void)
{
  bool upgrade =
    check_recent_quit (quit_upgrade_count, quit_upgrade_count);
  /* Only non-upgraded quits count as continuable.  */
  return signal_or_quit (upgrade ? Qquit_immediate : Qquit,
    Qnil, !upgrade);
}

and then in read_char, we change from

  if (convert_quits && !NILP (Vquit_flag))
    {
      Vquit_flag = Qnil;
      result = make_fixnum (quit_char);
    }

to

  if (convert_quits && !NILP (Vquit_flag)
     && check_recent_quit(quit_upgrade_count, quit_upgrade_count))
  {
    Vquit_flag = Qnil;
    result = make_fixnum (quit_char);
  }

and then...

  DEFVAR_INT ("quit-upgrade-count", quit_upgrade_count,
	      doc: /* Number of quits received in quit-upgrade-period
  to count as an urgent quit that quits out of functions meant to read
  input events.  */)
  quit_upgrade_count = 3;

  DEFVAR_INT ("quit-upgrade-period", quit_upgrade_period,
	      doc: /* Time in which if we see at least quit-upgrade-count
    quits we quit out of functions meant to read input events.  */)
  quit_upgrade_period = 500;

  DEFVAR_INT ("quit-emergency-count", quit_emergency_count,
	      doc: /* Number of quits received in quit-emergency-period
    after which we disable safeguards that normally prevent quitting
    from protected code paths.  */);
  quit_emergency_count = 6;
 a
  DEFVAR_INT ("quit-emergency-period", quit_emergency_period,
	      doc: {you get the idea});
  quit_emergency_period = 1000;

At the top of command_loop_1, we reset the quit ring.  The above
thresholds count only between command invocations.

TIMTOWTDI of course.  This is a sketch.  But something like this should
make us both happy, yes?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 05:53:05 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Pip Cet <pipcet <at> protonmail.com>
Cc: 78737 <at> debbugs.gnu.org, dancol <at> dancol.org, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 08:52:40 +0300
> Date: Thu, 12 Jun 2025 18:37:58 +0000
> From: Pip Cet <pipcet <at> protonmail.com>
> Cc: dancol <at> dancol.org, monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
> 
> "Eli Zaretskii" <eliz <at> gnu.org> writes:
> 
> > Please describe the situations where you'd like it to throw to top
> > level and it doesn't now.
> 
> One situation for ordinary quits; three for force-quit.
> 
> Situation 1:
> 
> I'd like read-event, when called while inhibit-quit is t, to report
> quits by setting quit-flag in addition to returning quit_char: it'll
> simplify the C code, and it would make
> 
> (while t
>   (let ((inhibit-quit t))
>     (read-event)))
> 
> quittable, as I naively expected it to be.  The old behavior would
> remain available, but require an extra let binding.

But isn't it confusing that to have something quittable one needs to
bind inhibit-quit non-nil?  The naïve expectation from this is that
the code affected by inhibit-quit non-nil is _not_ quittable, no?

> Note that this isn't
> 
> (let ((inhibit-quit t))
>   (while t
>     (read-event)))

Which is also confusing by its inconsistency.  In general, the order
of let-bindings doesn't matter.

> Situation 3:
> 
> Several force-quits in the same session.  Reset force_quit_count to 0
> once it reaches 3.  I've seen force_quit_count reach higher values than
> 3 (there was no regular quit in between force quit attempts).

If you are talking about a GUI session, then IME the 'emergency exit"
procedure isn't reliably working in that case, and I'm not sure the
implementation intends to support that.  I always knew that it's only
reliably working on TTY frames.

Or are you talking about the effect of the changes on the branch?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 06:26:03 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 09:25:36 +0300
> From: Daniel Colascione <dancol <at> dancol.org>
> Cc: Eli Zaretskii <eliz <at> gnu.org>,  monnier <at> iro.umontreal.ca,
>   78737 <at> debbugs.gnu.org
> Date: Thu, 12 Jun 2025 11:48:50 -0700
> 
> Pip Cet <pipcet <at> protonmail.com> writes:
> 
> > I'd like read-event, when called while inhibit-quit is t, to report
> > quits by setting quit-flag in addition to returning quit_char: it'll
> > simplify the C code, and it would make
> >
> > (while t
> >   (let ((inhibit-quit t))
> >     (read-event)))
> 
> I strongly disagree.  read-event should read an event.
> Setting quit-flag by side effect when it happens to read one key and not
> others makes the interface less regular and understandable.

We should start by agreeing that the capability of interrupting a
running Lisp program is a real need.  Are we in agreement about that?
If not, let's first hear the arguments why not.

If we _are_ in agreement about that, we should discuss how this should
be possible if read-event (and perhaps others?) return C-g instead of
raising quit-flag.  The alternatives mentioned until now are:

 . restore the old behavior, whereby C-g interrupts read-event
 . have a variable that, if set, will restore the old behavior in
   read-event and other affected primitives, to be interruptible by a
   single C-g
 . make two C-g presses "in quick succession" set quit-flag, IOW
   "C-g C-g" will have the same effect as C-g previously

Are there other alternatives?

> read-key-sequence is the high-level function.  read-event is the
> low-level function.  It makes zero sense for the high-level function to
> report a key event as a low-level event and for the low-level function
> to do special non-local flow control in response to that event.
> 
> > quittable, as I naively expected it to be.
> 
> The naive expectation is that this function do its job.

I don't think there's disagreement on that level.  So let's drop this
kind of arguments, because they are not useful for this discussion.
The problem we face is how to allow Lisp code to be quittable.  A Lisp
program that calls read-event is not different from a Lisp program
calling any other function, so we still need such programs to be
quittable somehow.  Let's discuss how best to do it, okay?

> > Several force-quits in the same session.  Reset force_quit_count to 0
> > once it reaches 3.  I've seen force_quit_count reach higher values than
> > 3 (there was no regular quit in between force quit attempts).
> 
> Get rid of force_quit_count entirely and just detect (by writing into a
> ring buffer) whether we've received N quits in the last T milliseconds.
> That'll work the same way regardless of how quits gets detected.  We can
> change N and T freely.

This is the last alternative I described above.  It is IMO less
desirable, because it is not always easy to press C-g twice quickly,
for whatever reasons.  It is even less desirable to define "quick
succession" in terms of time, because timings can differ a lot
depending on the free computing resources and the CPU power in
general, so determining the best default values will be very
challenging, to say the least.

> On your Emacs, you can set N to one and T to zero.

If read-event still returns a keyboard input event when C-g is
pressed, I don't see how N = 1 would work.  Can you describe how it
would work?

> >> Also, can this behavior be optional, like debug-on-error and friends
> >> are?  Not everyone debugs Lisp code all the time, so we definitely can
> >> have an "easy-break-out" feature that is by default off.
> 
> > Absolutely.  We could easily make it customizable whether read-event
> > sets quit-flag after a quit:
> >
> > 1. never
> > 2. only when !inhibit-quit
> > 3. always
> 
> We can customize thresholds for general behavior, but I don't think we
> should not have preferences that alter the operation of fundamental
> Emacs primitives.  You couldn't add a preference that made if regard 0
> as well as nil as false, would you? 

Why not?  If it helps debugging, we could definitely do that.  We
already have --enable-checking, which changes how some primitives
work, in a very real sense.  As long as the feature is for debugging
Emacs, anything useful goes, IMO.

> >>> Maybe a compromise would be to continue the arms race and downgrade C-g
> >>> to normal input, C-g C-g C-g to a quit, and require even more C-g's for
> >>> a force-quit?
> >>
> >> That's also possible, though less desirable: counting C-g presses when
> >> you are desperate is not easy and we cannot rely on users to do that
> >> reliably.
> >
> > And we'd need a way to detect when a quit is handled (however we define
> > "handled") so we could reset force_quit_counter.  Not a trivial change.
> 
> You don't.  You just upgrade any quit that happens under the N and T
> threshold above.

I'm skeptical that we will be able to count C-g presses so as to
reliably differentiate between double or triple press and two or three
separate C-g presses.  Different machines and OSes, and different
system loads, can make it nigh impossible to do reliably.  And that's
_bad_, because when I want something interrupted right away, I don't
want or even cannot try again and again and again until it works.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 07:30:02 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 00:28:45 -0700
Eli Zaretskii <eliz <at> gnu.org> writes:

>> From: Daniel Colascione <dancol <at> dancol.org>
>> Cc: Eli Zaretskii <eliz <at> gnu.org>,  monnier <at> iro.umontreal.ca,
>>   78737 <at> debbugs.gnu.org
>> Date: Thu, 12 Jun 2025 11:48:50 -0700
>> 
>> Pip Cet <pipcet <at> protonmail.com> writes:
>> 
>> > I'd like read-event, when called while inhibit-quit is t, to report
>> > quits by setting quit-flag in addition to returning quit_char: it'll
>> > simplify the C code, and it would make
>> >
>> > (while t
>> >   (let ((inhibit-quit t))
>> >     (read-event)))
>> 
>> I strongly disagree.  read-event should read an event.
>> Setting quit-flag by side effect when it happens to read one key and not
>> others makes the interface less regular and understandable.
>
> We should start by agreeing that the capability of interrupting a
> running Lisp program is a real need.  Are we in agreement about that?
> If not, let's first hear the arguments why not.

Which Lisp programs? One that calls (while t (read-event))?  One that
calls (let ((inhibit-quit t)) (while t (read-event))?  How about one
that calls (while t (read-key-sequence ""))?  How about one that calls
(let ((inhibit-quit t)) (while t (read-key-sequence ""))?  If you adopt
the tenet that Lisp programs always be uninterruptible, _something_ has
to change from the present, because 3/4 of my examples above cannot
be quit.

(Today's force quit doesn't count: it doesn't practically work outside
primary TTY.)

> If we _are_ in agreement about that, we should discuss how this should
> be possible if read-event (and perhaps others?) return C-g instead of
> raising quit-flag.  The alternatives mentioned until now are:
>
>  . restore the old behavior, whereby C-g interrupts read-event

Does not satisfy the "lisp programs always be
interruptible" requirement.

>  . have a variable that, if set, will restore the old behavior in

Same as above.

>    read-event and other affected primitives, to be interruptible by a
>    single C-g

Same as above.

>  . make two C-g presses "in quick succession" set quit-flag, IOW
>    "C-g C-g" will have the same effect as C-g previously

Only for read-event.

If you want to adopt a principled stance that every Lisp program be
interruptible, you necessarily, as a matter of logic, regard multiple
behaviors of current Emacs to be bugs worth fixing.

> Are there other alternatives?

Get in a time machine, go back 40 years and stop overloading C-g?

>> read-key-sequence is the high-level function.  read-event is the
>> low-level function.  It makes zero sense for the high-level function to
>> report a key event as a low-level event and for the low-level function
>> to do special non-local flow control in response to that event.
>> 
>> > quittable, as I naively expected it to be.
>> 
>> The naive expectation is that this function do its job.
>
> I don't think there's disagreement on that level.  So let's drop this
> kind of arguments, because they are not useful for this discussion.
> The problem we face is how to allow Lisp code to be quittable.  A Lisp
> program that calls read-event is not different from a Lisp program
> calling any other function, so we still need such programs to be
> quittable somehow.  Let's discuss how best to do it, okay?

Yes or no: should (while t (read-key-sequence)) be quittable?

If yes, maintaining today's behavior isn't an option.  There are plenty
of other Lisp programs that cannot be quit --- even (let ((inhibit-quit
t)) (while t)) cannot be quit!

If no, what is the problem with cleaning up Emacs by regularizing how we
treat C-g as an event versus some kind of longjmp?

>> > Several force-quits in the same session.  Reset force_quit_count to 0
>> > once it reaches 3.  I've seen force_quit_count reach higher values than
>> > 3 (there was no regular quit in between force quit attempts).
>> 
>> Get rid of force_quit_count entirely and just detect (by writing into a
>> ring buffer) whether we've received N quits in the last T milliseconds.
>> That'll work the same way regardless of how quits gets detected.  We can
>> change N and T freely.
>
> This is the last alternative I described above.  It is IMO less
> desirable, because it is not always easy to press C-g twice quickly,
> for whatever reasons.  It is even less desirable to define "quick
> succession" in terms of time, because timings can differ a lot
> depending on the free computing resources and the CPU power in
> general, so determining the best default values will be very
> challenging, to say the least.

I don't see the ambiguity being a realistic problem.  How often do you
press C-g three times while a single command is running?

We're not talking about, say, six times in multiple rounds of M-x this,
select that, deactivate mark over here.  Those are multiple commands.
In between multiple commands, a C-g will cause a keyboard-quit and
you'll regain control over Emacs.  I'm asking, during _one_ command, how
many times you typically press C-g and _don't_ mean it as a quit.

We already have a force quit mechanism that kicks in at N=3.  How often
do you activate it?

>> On your Emacs, you can set N to one and T to zero.
>
> If read-event still returns a keyboard input event when C-g is
> pressed, I don't see how N = 1 would work.  Can you describe how it
> would work?

It wouldn't.  Such a setting would prevent read-input returning C-g.
That shouldn't be the default.  Maybe some people would customize the
setting to make Emacs behave this way.  I would not.

>> >> Also, can this behavior be optional, like debug-on-error and friends
>> >> are?  Not everyone debugs Lisp code all the time, so we definitely can
>> >> have an "easy-break-out" feature that is by default off.
>> 
>> > Absolutely.  We could easily make it customizable whether read-event
>> > sets quit-flag after a quit:
>> >
>> > 1. never
>> > 2. only when !inhibit-quit
>> > 3. always
>> 
>> We can customize thresholds for general behavior, but I don't think we
>> should not have preferences that alter the operation of fundamental
>> Emacs primitives.  You couldn't add a preference that made if regard 0
>> as well as nil as false, would you? 
>
> Why not?  If it helps debugging, we could definitely do that.  We
> already have --enable-checking, which changes how some primitives
> work, in a very real sense.  As long as the feature is for debugging
> Emacs, anything useful goes, IMO.

Because when you add a user option, people expect code you write to
operate under any value of that option, increasing implementation
complexity because you have to account for the _possibility_ someone
might operate in a certain way.  Complexity is insidious, and the
solution to a technical problem is rarely to add yet another technical
knob nobody is going to realistically touch but for which logic
must account.

>> >>> Maybe a compromise would be to continue the arms race and downgrade C-g
>> >>> to normal input, C-g C-g C-g to a quit, and require even more C-g's for
>> >>> a force-quit?
>> >>
>> >> That's also possible, though less desirable: counting C-g presses when
>> >> you are desperate is not easy and we cannot rely on users to do that
>> >> reliably.
>> >
>> > And we'd need a way to detect when a quit is handled (however we define
>> > "handled") so we could reset force_quit_counter.  Not a trivial change.
>> 
>> You don't.  You just upgrade any quit that happens under the N and T
>> threshold above.
>
> I'm skeptical that we will be able to count C-g presses so as to
> reliably differentiate between double or triple press and two or three
> separate C-g presses.

There is logically no difference between these two concepts.  A double
keypress *is* two keypresses in a certain window of time.  What other
concept could the combination of the words "double" and "press" convey?

> Different machines and OSes, and different
> system loads, can make it nigh impossible to do reliably.  And that's
> _bad_, because when I want something interrupted right away, I don't
> want or even cannot try again and again and again until it works.

Then define a separate key that means _only_ quit and that cannot be
bound to a regular command.  C-g can't be that command without breaking
existing code.

Treating repeated C-g presses made in a reasonable window of time within
the scope of a single command in such a way that we're almost certainly
not confusing this series of keystrokes with C-g-as-command input solves
the problem.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 07:54:01 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, Pip Cet <pipcet <at> protonmail.com>,
 monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 00:53:38 -0700
Eli Zaretskii <eliz <at> gnu.org> writes:

>> Date: Thu, 12 Jun 2025 18:37:58 +0000
>> From: Pip Cet <pipcet <at> protonmail.com>
>> Cc: dancol <at> dancol.org, monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
>> 
>> "Eli Zaretskii" <eliz <at> gnu.org> writes:
>> 
>> > Please describe the situations where you'd like it to throw to top
>> > level and it doesn't now.
>> 
>> One situation for ordinary quits; three for force-quit.
>> 
>> Situation 1:
>> 
>> I'd like read-event, when called while inhibit-quit is t, to report
>> quits by setting quit-flag in addition to returning quit_char: it'll
>> simplify the C code, and it would make
>> 
>> (while t
>>   (let ((inhibit-quit t))
>>     (read-event)))
>> 
>> quittable, as I naively expected it to be.  The old behavior would
>> remain available, but require an extra let binding.
>
> But isn't it confusing that to have something quittable one needs to
> bind inhibit-quit non-nil?  The naïve expectation from this is that
> the code affected by inhibit-quit non-nil is _not_ quittable, no?
>
>> Note that this isn't
>> 
>> (let ((inhibit-quit t))
>>   (while t
>>     (read-event)))
>
> Which is also confusing by its inconsistency.  In general, the order
> of let-bindings doesn't matter.
>
>> Situation 3:
>> 
>> Several force-quits in the same session.  Reset force_quit_count to 0
>> once it reaches 3.  I've seen force_quit_count reach higher values than
>> 3 (there was no regular quit in between force quit attempts).
>
> If you are talking about a GUI session, then IME the 'emergency exit"
> procedure isn't reliably working in that case, and I'm not sure the
> implementation intends to support that.  I always knew that it's only
> reliably working on TTY frames.
>
> Or are you talking about the effect of the changes on the branch?

FWIW, the purpose of my N-times-in-T-milliseconds-within-one-command
formulation of emergency exit is to get the mechanism working reliably
in all cases.

I can definitely type 4-5 C-gs in a GUI Emacs (well, NS, but I recall
PGTK being similar?) and not have Emacs quit.  If I mash C-g, it
sometimes does, and sometimes doesn't.

Right now, the logic is this:

    {
      /* Request quit when it's safe.  */
      int count = NILP (Vquit_flag) ? 1 : force_quit_count + 1;
      force_quit_count = count;
      if (count == 3)
	Vinhibit_quit = Qnil;
      Vquit_flag = Qt;
    }

IOW, the first quit after clearing Vquit_flag resets the count to one.
Maybe that's why it isn't working reliably right now.  If we reformulate
this mechanism not in terms of count == 3 (which is fiddly for all sorts
of reasons, since Vquit_flag can get reset) but in terms of the UX
directly --- N recent quits in T time in a single command --- we make
the whole thing more reliable.

If you set T=infinity and N=3, you get the current force quit UX (modulo
my upgrade-before-disabling-inhibit-quit thing), just more reliably, and
you can break out of arbitrary Lisp code.





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 11:35:01 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 14:34:06 +0300
> From: Daniel Colascione <dancol <at> dancol.org>
> Cc: pipcet <at> protonmail.com,  monnier <at> iro.umontreal.ca,  78737 <at> debbugs.gnu.org
> Date: Fri, 13 Jun 2025 00:28:45 -0700
> 
> Eli Zaretskii <eliz <at> gnu.org> writes:
> 
> >> From: Daniel Colascione <dancol <at> dancol.org>
> >> Cc: Eli Zaretskii <eliz <at> gnu.org>,  monnier <at> iro.umontreal.ca,
> >>   78737 <at> debbugs.gnu.org
> >> Date: Thu, 12 Jun 2025 11:48:50 -0700
> >> 
> >> Pip Cet <pipcet <at> protonmail.com> writes:
> >> 
> >> > I'd like read-event, when called while inhibit-quit is t, to report
> >> > quits by setting quit-flag in addition to returning quit_char: it'll
> >> > simplify the C code, and it would make
> >> >
> >> > (while t
> >> >   (let ((inhibit-quit t))
> >> >     (read-event)))
> >> 
> >> I strongly disagree.  read-event should read an event.
> >> Setting quit-flag by side effect when it happens to read one key and not
> >> others makes the interface less regular and understandable.
> >
> > We should start by agreeing that the capability of interrupting a
> > running Lisp program is a real need.  Are we in agreement about that?
> > If not, let's first hear the arguments why not.
> 
> Which Lisp programs?

All of them.

> One that calls (while t (read-event))?  One that
> calls (let ((inhibit-quit t)) (while t (read-event))?  How about one
> that calls (while t (read-key-sequence ""))?  How about one that calls
> (let ((inhibit-quit t)) (while t (read-key-sequence ""))?  If you adopt
> the tenet that Lisp programs always be uninterruptible, _something_ has
> to change from the present, because 3/4 of my examples above cannot
> be quit.

So because we currently cannot interrupt some programs we should give
up the ability to interrupt all of them?  Please be serious.
Arguments like the above are a red herring, and don't help advancing
this discussion towards some kind of agreement.

Do you want the branch merged at some point?  Then please drop the
attitude and start participating in the discussion seriously.  You
understand very well what I meant above, even though it is somewhat
vague.  We all know what Emacs can and cannot do today, so I allow
myself not to write too many well-known details.

Let's consider the current capabilities of interrupting Lisp programs
as base line, and try to maintain that base line, if not improve on
it.  Okay?  Or does it still not satisfy your intentionally-pedantic
interpretation of what I write?

> > If we _are_ in agreement about that, we should discuss how this should
> > be possible if read-event (and perhaps others?) return C-g instead of
> > raising quit-flag.  The alternatives mentioned until now are:
> >
> >  . restore the old behavior, whereby C-g interrupts read-event
> 
> Does not satisfy the "lisp programs always be
> interruptible" requirement.
> 
> >  . have a variable that, if set, will restore the old behavior in
> 
> Same as above.
> 
> >    read-event and other affected primitives, to be interruptible by a
> >    single C-g
> 
> Same as above.

Please reconsider your responses with a more serious and cooperative
attitude.

> >  . make two C-g presses "in quick succession" set quit-flag, IOW
> >    "C-g C-g" will have the same effect as C-g previously
> 
> Only for read-event.

Why "only"?

Having the behavior vary depending on whether the program does or
doesn't call read-event will bring inconsistency, something we want to
avoid (and which I think you argued against).

> If you want to adopt a principled stance that every Lisp program be
> interruptible, you necessarily, as a matter of logic, regard multiple
> behaviors of current Emacs to be bugs worth fixing.

Not useful.  I didn't mean that, and you know it.

> > Are there other alternatives?
> 
> Get in a time machine, go back 40 years and stop overloading C-g?

Even less useful.  Again, do you want this branch to be merged any
time soon?  Because I'm this close to losing my patience.  Life's too
short to waste it on "arguments" such as this one.

> > I don't think there's disagreement on that level.  So let's drop this
> > kind of arguments, because they are not useful for this discussion.
> > The problem we face is how to allow Lisp code to be quittable.  A Lisp
> > program that calls read-event is not different from a Lisp program
> > calling any other function, so we still need such programs to be
> > quittable somehow.  Let's discuss how best to do it, okay?
> 
> Yes or no: should (while t (read-key-sequence)) be quittable?

Why is that relevant?  I asked about read-event, not
read-key-sequence.  Can we first discuss the read-event case?  Once we
are done with that, we can move to other cases.

> If yes, maintaining today's behavior isn't an option.  There are plenty
> of other Lisp programs that cannot be quit --- even (let ((inhibit-quit
> t)) (while t)) cannot be quit!

If inhibit-quit is bound to a non-nil value, the program cannot be
quit, and that's a feature.  Why are we discussing this?

> If no, what is the problem with cleaning up Emacs by regularizing how we
> treat C-g as an event versus some kind of longjmp?

Again, let's discuss the read-key-sequence case after we are done with
the read-event case.

> >> > Several force-quits in the same session.  Reset force_quit_count to 0
> >> > once it reaches 3.  I've seen force_quit_count reach higher values than
> >> > 3 (there was no regular quit in between force quit attempts).
> >> 
> >> Get rid of force_quit_count entirely and just detect (by writing into a
> >> ring buffer) whether we've received N quits in the last T milliseconds.
> >> That'll work the same way regardless of how quits gets detected.  We can
> >> change N and T freely.
> >
> > This is the last alternative I described above.  It is IMO less
> > desirable, because it is not always easy to press C-g twice quickly,
> > for whatever reasons.  It is even less desirable to define "quick
> > succession" in terms of time, because timings can differ a lot
> > depending on the free computing resources and the CPU power in
> > general, so determining the best default values will be very
> > challenging, to say the least.
> 
> I don't see the ambiguity being a realistic problem.  How often do you
> press C-g three times while a single command is running?

I usually expect a single C-g to quit.  If it doesn't help, I can
press C-g several times, I'm not sure I count them.

> We're not talking about, say, six times in multiple rounds of M-x this,
> select that, deactivate mark over here.  Those are multiple commands.
> In between multiple commands, a C-g will cause a keyboard-quit and
> you'll regain control over Emacs.  I'm asking, during _one_ command, how
> many times you typically press C-g and _don't_ mean it as a quit.

See above.

> We already have a force quit mechanism that kicks in at N=3.  How often
> do you activate it?

I never saw it at work, except on TTY frames.  But then Windows
doesn't have SIGIO, it emulates that.  Maybe that's the reason.

> >> On your Emacs, you can set N to one and T to zero.
> >
> > If read-event still returns a keyboard input event when C-g is
> > pressed, I don't see how N = 1 would work.  Can you describe how it
> > would work?
> 
> It wouldn't.  Such a setting would prevent read-input returning C-g.
> That shouldn't be the default.

Sorry, I don't understand.  If N = 1, what will read-event do when the
user presses C-g while inside read-event?  Will it return the input
event C-g, or will it quit?  I thought your changes make read-event
always return the input event, was I mistaken?

> >> We can customize thresholds for general behavior, but I don't think we
> >> should not have preferences that alter the operation of fundamental
> >> Emacs primitives.  You couldn't add a preference that made if regard 0
> >> as well as nil as false, would you? 
> >
> > Why not?  If it helps debugging, we could definitely do that.  We
> > already have --enable-checking, which changes how some primitives
> > work, in a very real sense.  As long as the feature is for debugging
> > Emacs, anything useful goes, IMO.
> 
> Because when you add a user option, people expect code you write to
> operate under any value of that option, increasing implementation
> complexity because you have to account for the _possibility_ someone
> might operate in a certain way.

No, people need not expect the code to operate the same under those
special debugging-oriented values.  We already have such features:
debug-on-error = t might well cause some command cease working
normally, and similarly condition-case-unless-debug.

So I think you are bothered by a problem that doesn't need to be
solved.

> >> >>> Maybe a compromise would be to continue the arms race and downgrade C-g
> >> >>> to normal input, C-g C-g C-g to a quit, and require even more C-g's for
> >> >>> a force-quit?
> >> >>
> >> >> That's also possible, though less desirable: counting C-g presses when
> >> >> you are desperate is not easy and we cannot rely on users to do that
> >> >> reliably.
> >> >
> >> > And we'd need a way to detect when a quit is handled (however we define
> >> > "handled") so we could reset force_quit_counter.  Not a trivial change.
> >> 
> >> You don't.  You just upgrade any quit that happens under the N and T
> >> threshold above.
> >
> > I'm skeptical that we will be able to count C-g presses so as to
> > reliably differentiate between double or triple press and two or three
> > separate C-g presses.
> 
> There is logically no difference between these two concepts.  A double
> keypress *is* two keypresses in a certain window of time.  What other
> concept could the combination of the words "double" and "press" convey?

I don't understand what you are saying here.  Yes, there's no logical
difference between these, which is why I'm saying that reliably
detecting "double C-g" is a challenge.  We already have that with
double-mouse.  The difference between double-mouse and "double C-g" is
that with the latter you cannot afford low reliability: when you want
to quit, you want to do it immediately, because the runaway operation
you want to interrupt could be harmful.

> > Different machines and OSes, and different
> > system loads, can make it nigh impossible to do reliably.  And that's
> > _bad_, because when I want something interrupted right away, I don't
> > want or even cannot try again and again and again until it works.
> 
> Then define a separate key that means _only_ quit and that cannot be
> bound to a regular command.  C-g can't be that command without breaking
> existing code.

It's too late to define a separate key _instead_ of C-g.  We could
define a separate key _in_addition_ to C-g, but that doesn't solve the
problem: people have C-g hardwired into their muscle memory, and it
will take a lot of time for them to re-learn.  Meanwhile, we get bug
reports about C-g not working like it did before.

So minimizing the behavior changes is still a requirement, even if we
add another key.  And that's before we even consider what other key
could serve that purpose, which is not a trivial problem to solve
portably.

> Treating repeated C-g presses made in a reasonable window of time within
> the scope of a single command in such a way that we're almost certainly
> not confusing this series of keystrokes with C-g-as-command input solves
> the problem.

That's possible, but it is not the best alternative IMO, for the
reasons I explained.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 11:37:06 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 14:36:42 +0300
> From: Daniel Colascione <dancol <at> dancol.org>
> Cc: Pip Cet <pipcet <at> protonmail.com>,  monnier <at> iro.umontreal.ca,
>   78737 <at> debbugs.gnu.org
> Date: Fri, 13 Jun 2025 00:53:38 -0700
> 
> > If you are talking about a GUI session, then IME the 'emergency exit"
> > procedure isn't reliably working in that case, and I'm not sure the
> > implementation intends to support that.  I always knew that it's only
> > reliably working on TTY frames.
> >
> > Or are you talking about the effect of the changes on the branch?
> 
> FWIW, the purpose of my N-times-in-T-milliseconds-within-one-command
> formulation of emergency exit is to get the mechanism working reliably
> in all cases.
> 
> I can definitely type 4-5 C-gs in a GUI Emacs (well, NS, but I recall
> PGTK being similar?) and not have Emacs quit.  If I mash C-g, it
> sometimes does, and sometimes doesn't.
> 
> Right now, the logic is this:
> 
>     {
>       /* Request quit when it's safe.  */
>       int count = NILP (Vquit_flag) ? 1 : force_quit_count + 1;
>       force_quit_count = count;
>       if (count == 3)
> 	Vinhibit_quit = Qnil;
>       Vquit_flag = Qt;
>     }
> 
> IOW, the first quit after clearing Vquit_flag resets the count to one.
> Maybe that's why it isn't working reliably right now.  If we reformulate
> this mechanism not in terms of count == 3 (which is fiddly for all sorts
> of reasons, since Vquit_flag can get reset) but in terms of the UX
> directly --- N recent quits in T time in a single command --- we make
> the whole thing more reliable.
> 
> If you set T=infinity and N=3, you get the current force quit UX (modulo
> my upgrade-before-disabling-inhibit-quit thing), just more reliably, and
> you can break out of arbitrary Lisp code.

I suggest to leave the emergency exit feature alone for now, and focus
on the interruptibility of Lisp programs.  They are not independent,
but the emergency exit is a separate feature, so mixing these two
discussions makes the argument less effective.  We can return to the
emergency exit later.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 11:50:01 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 04:49:21 -0700

On June 13, 2025 4:36:42 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
>> From: Daniel Colascione <dancol <at> dancol.org>
>> Cc: Pip Cet <pipcet <at> protonmail.com>,  monnier <at> iro.umontreal.ca,
>>   78737 <at> debbugs.gnu.org
>> Date: Fri, 13 Jun 2025 00:53:38 -0700
>> 
>> > If you are talking about a GUI session, then IME the 'emergency exit"
>> > procedure isn't reliably working in that case, and I'm not sure the
>> > implementation intends to support that.  I always knew that it's only
>> > reliably working on TTY frames.
>> >
>> > Or are you talking about the effect of the changes on the branch?
>> 
>> FWIW, the purpose of my N-times-in-T-milliseconds-within-one-command
>> formulation of emergency exit is to get the mechanism working reliably
>> in all cases.
>> 
>> I can definitely type 4-5 C-gs in a GUI Emacs (well, NS, but I recall
>> PGTK being similar?) and not have Emacs quit.  If I mash C-g, it
>> sometimes does, and sometimes doesn't.
>> 
>> Right now, the logic is this:
>> 
>>     {
>>       /* Request quit when it's safe.  */
>>       int count = NILP (Vquit_flag) ? 1 : force_quit_count + 1;
>>       force_quit_count = count;
>>       if (count == 3)
>> 	Vinhibit_quit = Qnil;
>>       Vquit_flag = Qt;
>>     }
>> 
>> IOW, the first quit after clearing Vquit_flag resets the count to one.
>> Maybe that's why it isn't working reliably right now.  If we reformulate
>> this mechanism not in terms of count == 3 (which is fiddly for all sorts
>> of reasons, since Vquit_flag can get reset) but in terms of the UX
>> directly --- N recent quits in T time in a single command --- we make
>> the whole thing more reliable.
>> 
>> If you set T=infinity and N=3, you get the current force quit UX (modulo
>> my upgrade-before-disabling-inhibit-quit thing), just more reliably, and
>> you can break out of arbitrary Lisp code.
>
>I suggest to leave the emergency exit feature alone for now, and focus
>on the interruptibility of Lisp programs.

That *is* the interruptabiltity of Lisp programs.l




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 12:24:01 GMT) Full text and rfc822 format available.

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

From: Lynn Winebarger <owinebar <at> gmail.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, Pip Cet <pipcet <at> protonmail.com>,
 Daniel Colascione <dancol <at> dancol.org>,
 Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 08:23:34 -0400
[Message part 1 (text/plain, inline)]
On Fri, Jun 13, 2025, 2:26 AM Eli Zaretskii <eliz <at> gnu.org> wrote:

> > From: Daniel Colascione <dancol <at> dancol.org>
> > Cc: Eli Zaretskii <eliz <at> gnu.org>,  monnier <at> iro.umontreal.ca,
> >   78737 <at> debbugs.gnu.org
> > Date: Thu, 12 Jun 2025 11:48:50 -0700
> >
> > Pip Cet <pipcet <at> protonmail.com> writes:
> >
> > > I'd like read-event, when called while inhibit-quit is t, to report
> > > quits by setting quit-flag in addition to returning quit_char: it'll
> > > simplify the C code, and it would make
> > >
> > > (while t
> > >   (let ((inhibit-quit t))
> > >     (read-event)))
> >
> > I strongly disagree.  read-event should read an event.
> > Setting quit-flag by side effect when it happens to read one key and not
> > others makes the interface less regular and understandable.
>
> We should start by agreeing that the capability of interrupting a
> running Lisp program is a real need.  Are we in agreement about that?
> If not, let's first hear the arguments why not.
>
> If we _are_ in agreement about that, we should discuss how this should
> be possible if read-event (and perhaps others?) return C-g instead of
> raising quit-flag.  The alternatives mentioned until now are:
>
>  . restore the old behavior, whereby C-g interrupts read-event
>  . have a variable that, if set, will restore the old behavior in
>    read-event and other affected primitives, to be interruptible by a
>    single C-g
>  . make two C-g presses "in quick succession" set quit-flag, IOW
>    "C-g C-g" will have the same effect as C-g previously
>
> Are there other alternatives?
>

What about keeping a (possibly buffer-local?) lisp variable holding a list
of keystrokes mapped to thunks that are treated as generating lisp machine
"interrupts"?  The key strokes would be processed by C machinery and never
seen directly by lisp code and not be considered "events".
Then C-g could be bound to a thunk signalling quit, and the effect of
"inhibit-quit" achieved by removing C-g from the list in a given dynamic
scope.  Then user code could make other key-strokes "special" without
resorting to read-event.  For example, this read-event call in term.el:
(message "Hit space to flush")
      (let ((ch (read-event)))
 (if (eq ch ?\s)
     (set-window-configuration conf)
   (push ch unread-command-events)))

Could be replaced by something like
(with-interrupts ((?\s (signal term-flush)))
  (condition-case nil
    (while t (sit-for 100))
     (term-flush (set-window-configuration conf))))

Then some of these use-case concerns could be mooted altogether.

Lynn
[Message part 2 (text/html, inline)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 12:27:01 GMT) Full text and rfc822 format available.

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

From: Pip Cet <pipcet <at> protonmail.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, dancol <at> dancol.org, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 12:26:19 +0000
"Eli Zaretskii" <eliz <at> gnu.org> writes:

>> Date: Thu, 12 Jun 2025 18:37:58 +0000
>> From: Pip Cet <pipcet <at> protonmail.com>
>> Cc: dancol <at> dancol.org, monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
>>
>> "Eli Zaretskii" <eliz <at> gnu.org> writes:
>>
>> > Please describe the situations where you'd like it to throw to top
>> > level and it doesn't now.
>>
>> One situation for ordinary quits; three for force-quit.
>>
>> Situation 1:
>>
>> I'd like read-event, when called while inhibit-quit is t, to report
>> quits by setting quit-flag in addition to returning quit_char: it'll
>> simplify the C code, and it would make
>>
>> (while t
>>   (let ((inhibit-quit t))
>>     (read-event)))
>>
>> quittable, as I naively expected it to be.  The old behavior would
>> remain available, but require an extra let binding.
>
> But isn't it confusing that to have something quittable one needs to
> bind inhibit-quit non-nil?

I'm confused: the code above should be quittable whether or not the
"let" line is present, as long as the "let" line comes after the "while"
line: we unbind inhibit-quit after each iteration, and I'm expecting
Emacs to take this opportunity to quit.

I want to expand the number of situations in which a simple C-g quits,
and expand the number of situations in which a triple C-g force-quits.

(while t (read-event))

is quittable now, and should remain so, IMHO.

> The naïve expectation from this is that the code affected by
> inhibit-quit non-nil is _not_ quittable, no?

Indeed, but the code outside of the let, once per loop iteration, should
be.

>> Note that this isn't
>>
>> (let ((inhibit-quit t))
>>   (while t
>>     (read-event)))
>
> Which is also confusing by its inconsistency.  In general, the order
> of let-bindings doesn't matter.

I don't see how it's inconsistent, sorry.  If I bind inhibit-quit and
keep it bound while clearing quit-flag, I get an unquittable loop.  If I
repeatedly bind and unbind inhibit-quit so it becomes nil once per
iteration, I should get a quit when it does become nil, after the
binding has been unwound but before the next iteration's binding goes
into effect.

>> Situation 3:
>>
>> Several force-quits in the same session.  Reset force_quit_count to 0
>> once it reaches 3.  I've seen force_quit_count reach higher values than
>> 3 (there was no regular quit in between force quit attempts).
>
> If you are talking about a GUI session, then IME the 'emergency exit"
> procedure isn't reliably working in that case, and I'm not sure the
> implementation intends to support that.  I always knew that it's only
> reliably working on TTY frames.

I'm talking about the GUI case, yes.

It seems like an oversight to me.  Two successive emergency quits don't
work if both of these conditions hold:

1. there's no intervening regular C-g
2. quit-flag is non-nil

So a recipe would be:

(let ((inhibit-quit t))
  (setq quit-flag t)
  (while t))

C-x C-e
C-g C-g C-g
C-x C-e
C-g C-g C-g

Expected outcome: two emergency quits
Actual outcome: one emergency quit, no further emergency quits possible.

> Or are you talking about the effect of the changes on the branch?

I'm not, no.

Pip





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 13:37:02 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 06:35:40 -0700

On June 13, 2025 4:34:06 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
>> From: Daniel Colascione <dancol <at> dancol.org>
>> Cc: pipcet <at> protonmail.com,  monnier <at> iro.umontreal.ca,  78737 <at> debbugs.gnu.org
>> Date: Fri, 13 Jun 2025 00:28:45 -0700
>> 
>> Eli Zaretskii <eliz <at> gnu.org> writes:
>> 
>> >> From: Daniel Colascione <dancol <at> dancol.org>
>> >> Cc: Eli Zaretskii <eliz <at> gnu.org>,  monnier <at> iro.umontreal.ca,
>> >>   78737 <at> debbugs.gnu.org
>> >> Date: Thu, 12 Jun 2025 11:48:50 -0700
>> >> 
>> >> Pip Cet <pipcet <at> protonmail.com> writes:
>> >> 
>> >> > I'd like read-event, when called while inhibit-quit is t, to report
>> >> > quits by setting quit-flag in addition to returning quit_char: it'll
>> >> > simplify the C code, and it would make
>> >> >
>> >> > (while t
>> >> >   (let ((inhibit-quit t))
>> >> >     (read-event)))
>> >> 
>> >> I strongly disagree.  read-event should read an event.
>> >> Setting quit-flag by side effect when it happens to read one key and not
>> >> others makes the interface less regular and understandable.
>> >
>> > We should start by agreeing that the capability of interrupting a
>> > running Lisp program is a real need.  Are we in agreement about that?
>> > If not, let's first hear the arguments why not.
>> 
>> Which Lisp programs?
>
>All of them.

Do you want a mechanism that can interrupt all Lisp programs or not? I have such a mechanism.

>> One that calls (while t (read-event))?  One that
>> calls (let ((inhibit-quit t)) (while t (read-event))?  How about one
>> that calls (while t (read-key-sequence ""))?  How about one that calls
>> (let ((inhibit-quit t)) (while t (read-key-sequence ""))?  If you adopt
>> the tenet that Lisp programs always be uninterruptible, _something_ has
>> to change from the present, because 3/4 of my examples above cannot
>> be quit.
>
>So because we currently cannot interrupt some programs we should give
>up the ability to interrupt all of them?

My proposal allows us to interrupt all Lisp programs. I don't know how many times I have to say this to get the point across.

> Please be serious.

Please engage with what I'm saying and at least try to say things that make internal sense.

>Arguments like the above are a red herring, and don't help advancing
>this discussion towards some kind of agreement.

You just said above that we should consider the interruptabiltity of all Lisp programs. I cited examples of Lisp programs. That means these Lisp programs are relevant to the conversation, as they, being Lisp programs, belong to the category of all Lisp programs.

>Do you want the branch merged at some point? 

Do you want bugs fixed and behaviors improved at some point?

> Then please drop the
>attitude and start participating in the discussion seriously.  You
>understand very well what I meant above, even though it is somewhat
>vague. 

Actually, I have no idea what you mean: you say things like you're not sure whether we can distinguish two C-g presses from a double C-g press. There are the same thing. It's like asking whether we can distinguish #00f from #0000ff.

> We all know what Emacs can and cannot do today, so I allow
>myself not to write too many well-known details.
>
>Let's consider the current capabilities of interrupting Lisp programs
>as base line, and try to maintain that base line, if not improve on
>it.  Okay?  

I'm suggesting being able to interrupt all Lisp programs. Not all Lisp programs can be interrupted today. I have explained in multiple places how that is to be done. I am happy to explain further if you give me some substantial technical questions about the mechanisms involved.

When Lisp writes (while t (some-event-reading-function)), programmer intent is not clear. It's not clear because C-g is overloaded and can be either an event or a quit command. On the one hand, the Lisp is running Lisp and we have a general contract that Lisp can be interrupted with C-g. On the other hand, Lisp is asking to read an event, and C-g can be an event. We have to resolve the ambiguity SOMEHOW. Right now, Emacs resolves the ambiguity in an inconsistent and ad-hoc manner. If the some-event-reading-function above is read-event, we resolve the ambiguity in favor of quitting. If instead some-event-reading-function is read-key-sequence, we resolve the ambiguity in favor of event reading. This inconsistency is real, confusing, and illogical. In my proposal, we resolve the ambiguity in favor of event reading and use multiple C-g presses to indicate user intent to quit instead of provide input. I don't believe there's a practical, real world use case in which a single C-g will be insufficient, but the ability to press C-g multiple times will be there regardless. If you'd like to configure your Emacs to resolve the ambiguity in favor of quitting, you can do that by changing one variable. Either way, behavior will be consistent among all Lisp functions that read events.

Would you please engage substantively with the previous paragraph instead of calling it a distraction and then raising points germane to exactly what the previous paragraph covers?

Again, nobody is talking about making users count C-g. Nobody is talking about requiring multiple C-g presses in any real world case. The change I'm talking about will make Emacs more consistent, and I've yet to see anything in the real world it would break.

My change also makes Emacs safer, because in my model, you *can* break out of (while t (read-key-sequence)) and in master today you cannot. There will be *one* uniform and consistent (and easy to understand) model for how we address the *inherent* ambiguity about what control-g on a keyboard means.

Or does it still not satisfy your intentionally-pedantic
>interpretation of what I write?

I wouldn't have to be pedantic if you would be clear about what you want.

>> > If we _are_ in agreement about that, should discuss how this should
>> > be possible if read-event (and perhaps others?) return C-g instead of
>> > raising quit-flag.  The alternatives mentioned until now are:
>> >
>> >  . restore the old behavior, whereby C-g interrupts read-event
>> 
>> Does not satisfy the "lisp programs always be
>> interruptible" requirement.
>> 
>> >  . have a variable that, if set, will restore the old behavior in
>> 
>> Same as above.
>> 
>> >    read-event and other affected primitives, to be interruptible by a
>> >    single C-g
>> 
>> Same as above.
>
>Please reconsider your responses with a more serious and cooperative
>attitude.

Then make some sense. You talk about requirements. I explain how we meet those requirements. That's pedantry?

>> >  . make two C-g presses "in quick succession" set quit-flag, IOW
>> >    "C-g C-g" will have the same effect as C-g previously
>> 
>> Only for read-event.
>
>Why "only"?
>
>Having the behavior vary depending on whether the program does or
>doesn't call read-event will bring inconsistency, something we want to
>avoid (and which I think you argued against).

It is logically impossible to combine two things:

1) all Lisp programs can be interrupted with a single C-g

2) a Lisp program can read a C-g as an event.

This isn't pedantry. It's foundational logic. Demanding a solution that satisfies both constraints is impossible. It would require reading the user's mind.

>> If you want to adopt a principled stance that every Lisp program be
>> interruptible, you necessarily, as a matter of logic, regard multiple
>> behaviors of current Emacs to be bugs worth fixing.
>
>Not useful.  I didn't mean that, and you know it.

You just said at the start of this email that you're considering the interruptabiltity of all Lisp programs. I have a scheme to make all of them interruptible. Nobody else has proposed one.

>> > Are there other alternatives?
>> 
>> Get in a time machine, go back 40 years and stop overloading C-g?
>
>Even less useful.  Again, do you want this branch to be merged any
>time soon?  Because I'm this close to losing my patience.  Life's too
>short to waste it on "arguments" such as this one.
>

And I'm losing patience with objections that contradict themselves and fail to address my points.

>> > I don't think there's disagreement on that level.  So let's drop this
>> > kind of arguments, because they are not useful for this discussion.
>> > The problem we face is how to allow Lisp code to be quittable.  A Lisp
>> > program that calls read-event is not different from a Lisp program
>> > calling any other function, so we still need such programs to be
>> > quittable somehow.  Let's discuss how best to do it, okay?
>> 
>> Yes or no: should (while t (read-key-sequence)) be quittable?
>
>Why is that relevant?

If you'd like to cooperate seriously, I'm happy to do so provided you do so as well, and part serious cooperation is answering clarifying technical questions instead of questioning their relevance.

So, yes or no?

> I asked about read-event, not
>read-key-sequence.  Can we first discuss the read-event case?  Once we
>are done with that, we can move to other cases.

You just said above you want to consider the interruptabiltity of all Lisp programs. Now you're calling the interruptabiltity of some Lisp programs irrelevant. Which is it?

It's important to consider the input model as a whole. I don't think we can get to a good place by focusing on one function at a time and be wilfully oblivious about whether different functions together form a coherent whole.

>> If yes, maintaining today's behavior isn't an option.  There are plenty
>> of other Lisp programs that cannot be quit --- even (let ((inhibit-quit
>> t)) (while t)) cannot be quit!
>
>If inhibit-quit is bound to a non-nil value, the program cannot be
>quit, and that's a feature.

This seems like both a contradiction and poor UX: you want some Lisp programs to be interruptible and others not. Why is it a feature that some Lisp programs cannot be quit? I thought you wanted to talk about all Lisp programs being quittable. Why is it desirable that Emacs be left in an unrecoverable state?

In my proposal, users will be able to interrupt *any* program of the form (let ((inhibit-quit t)) (while t (anything))) by pressing C-g enough times to override the inhibit-quit. Emacs already provides this feature, but only (AFAICT) on primary TTYs.  

If this ability to break out of a loop wrapped in inhibit-quit is bad, should we remove the existing force-quit feature? Yes or no, please.

My proposal is a generalization of a feature we've had for decades. It is not a brand new concept.

Is it a bug to allow these programs to be interrupted? Yes or no. If yes, why isn't the existing force quit feature being removed? If not, why is being unable to quit some Lisp programs a "feature"?

You say I know what you mean. I'm really not sure I do, because from where I'm sitting, you're not answering questions that would resolve the contradictions in what you're saying.

> Why are we discussing this?


Because we're talking about interrupting Lisp programs. That's the subject of the whole conversation.

>
>> If no, what is the problem with cleaning up Emacs by regularizing how we
>> treat C-g as an event versus some kind of longjmp?
>
>Again, let's discuss the read-key-sequence case after we are done with
>the read-event case.

How can we consider what to do with read-event without thinking about how it fits into the broader picture?

>> >> > Several force-quits in the same session.  Reset force_quit_count to 0
>> >> > once it reaches 3.  I've seen force_quit_count reach higher values than
>> >> > 3 (there was no regular quit in between force quit attempts).
>> >> 
>> >> Get rid of force_quit_count entirely and just detect (by writing into a
>> >> ring buffer) whether we've received N quits in the last T milliseconds.
>> >> That'll work the same way regardless of how quits gets detected.  We can
>> >> change N and T freely.
>> >
>> > This is the last alternative I described above.  It is IMO less
>> > desirable, because it is not always easy to press C-g twice quickly,
>> > for whatever reasons.  It is even less desirable to define "quick
>> > succession" in terms of time, because timings can differ a lot
>> > depending on the free computing resources and the CPU power in
>> > general, so determining the best default values will be very
>> > challenging, to say the least.
>> 
>> I don't see the ambiguity being a realistic problem.  How often do you
>> press C-g three times while a single command is running?
>
>I usually expect a single C-g to quit.  If it doesn't help, I can
>press C-g several times, I'm not sure I count them.

In my proposal, on every real world case, C-g returns you to the command loop when you want to go there and lets Lisp read C-g as an event when you want to do that. You can construct buggy or pathologically written programs that you can't exit with a single C-g because the meaning of that keystroke is overloaded. You can still get back to the main loop in these rare cases by pressing C-g repeatedly. You don't have to count them. You just keep pressing C-g until you are back in the command loop, just like today's force quit feature.

>> We're not talking about, say, six times in multiple rounds of M-x this,
>> select that, deactivate mark over here.  Those are multiple commands.
>> In between multiple commands, a C-g will cause a keyboard-quit and
>> you'll regain control over Emacs.  I'm asking, during _one_ command, how
>> many times you typically press C-g and _don't_ mean it as a quit.
>
>See above.
>
>> We already have a force quit mechanism that kicks in at N=3.  How often
>> do you activate it?
>
>I never saw it at work, except on TTY frames. 

We can make it work everywhere. Is that not an improvement?

> But then Windows
>doesn't have SIGIO, it emulates that.  Maybe that's the reason.

SIGIO isn't the reason. The reason force quit doesn't work is the way it's implemented. We can implement it better. That's my proposal, if you'd like to consider it in more detail.

>> >> On your Emacs, you can set N to one and T to zero.
>> >
>> > If read-event still returns a keyboard input event when C-g is
>> > pressed, I don't see how N = 1 would work.  Can you describe how it
>> > would work?
>> 
>> It wouldn't.  Such a setting would prevent read-input returning C-g.
>> That shouldn't be the default.
>
>Sorry, I don't understand.  If N = 1, what will read-event do when the
>user presses C-g while inside read-event?  

If N=1, it will quit after a single C-g. Specifically, it will raise a quit signal. It will raise this signal instead of returning normally. It will not return it as C-g to Lisp. If N=1, all the Lisp level input reading functions, including read-key-sequence, will interpret a single C-g as quit.

> Will it return the input
>event C-g, or will it quit?  I thought your changes make read-event
>always return the input event, was I mistaken?

You're asking about the N=1 case.  I'm not proposing that N=1 be the default.

For all values of 1 <= N <= M, I'm specifically proposing:

When inhibit-quit is nil:

#quits in [1,N-1]: event reading functions interpret C-g as an event called \?C-g, aka the number 7. They return this event without quit-flag set.

#quits in [N, infinity): event reading functions interpret C-g as a quit. They do not return. They end by calling Fsignal with quit error symbol.

When inhibit-quit is non-nil:

#quits in [1,N-1]: same as above 

#quits in [N,M-1]: return \?C-g with quit-flag set

#quits in [M, anything): exit nonlocality by calling Fsignal with quit error signal, effectively ignoring inhibit-quit. Print a message saying we've done so.

If debug-on-quit is set, we enter the debugger when the above table says the word "Fsignal".

If throw-on-input, we raise quit on any input event whatsoever, never returning to Lisp, no matter the value of #quits, N, or M.

My proposal, by the way, does not change the meaning of quit-flag.

If you find the above proposal unacceptable, can you please point to a specific behavior it encodes and talk about what you'd rather it do differently?

Assume we can reliably detect #quits, please. I'm happy to talk about *how* we detect repeated C-g, but the mechanism by which we do is independent of rhe policy we want.

>> >> We can customize thresholds for general behavior, but I don't think we
>> >> should not have preferences that alter the operation of fundamental
>> >> Emacs primitives.  You couldn't add a preference that made if regard 0
>> >> as well as nil as false, would you? 
>> >
>> > Why not?  If it helps debugging, we could definitely do that. 

In the exceedingly rare case that it is important to allow one C-g instead of C-g C-g C-g to break out of an read-event or read-key-sequence loop (and I have never seen one not deliberately constructed) users can customize N to be one. I anticipate exactly zero people going that, but if you want the knob, we have it.

> We
>> > already have --enable-checking, which changes how some primitives
>> > work, in a very real sense.  

I'm not aware of any interface contracts that checking changes. What might those be?

> As long as the feature is for debugging
>> > Emacs, anything useful goes, IMO.
>> 
>> Because when you add a user option, people expect code you write to
>> operate under any value of that option, increasing implementation
>> complexity because you have to account for the _possibility_ someone
>> might operate in a certain way.
>
>No, people need not expect the code to operate the same under those
>special debugging-oriented values.  We already have such features:
>debug-on-error = t might well cause some command cease working
>normally, and similarly condition-case-unless-debug

Because I don't think this debugging mode is needed in any real world scenario. Nobody I've seen infloops on read event outside a specially crafted scenario.

But if you want the knob to enable it, the knob is there in my proposal. Set N=1. If you set N=1, then *both* read-event and read-key-sequence will quit the first time you press C-g 

>So I think you are bothered by a problem that doesn't need to be
>solved.
>
>> >> >>> Maybe a compromise would be to continue the arms race and downgrade C-g
>> >> >>> to normal input, C-g C-g C-g to a quit, and require even more C-g's for
>> >> >>> a force-quit?
>> >> >>
>> >> >> That's also possible, though less desirable: counting C-g presses when
>> >> >> you are desperate is not easy and we cannot rely on users to do that
>> >> >> reliably.
>> >> >
>> >> > And we'd need a way to detect when a quit is handled (however we define
>> >> > "handled") so we could reset force_quit_counter.  Not a trivial change.
>> >> 
>> >> You don't.  You just upgrade any quit that happens under the N and T
>> >> threshold above.
>> >
>> > I'm skeptical that we will be able to count C-g presses so as to
>> > reliably differentiate between double or triple press and two or three
>> > separate C-g presses.
>> 
>> There is logically no difference between these two concepts.  A double
>> keypress *is* two keypresses in a certain window of time.  What other
>> concept could the combination of the words "double" and "press" convey?
>
>I don't understand what you are saying here.  Yes, there's no logical
>difference between these, which is why I'm saying that reliably
>detecting "double C-g" is a challenge.  We already have that with
>double-mouse.  The difference between double-mouse and "double C-g" is
>that with the latter you cannot afford low reliability: when you want
>to quit, you want to do it immediately, because the runaway operation
>you want to interrupt could be harmful.

I'm honestly not sure what reliability problems you're talking about. We count the C-g key presses since we last entered the command loop and since T milliseconds ago. If you say T to be a month and N=2 then if you're in a read-event or read-key-sequence loop, press C-g once, suspend your computer for a day, and press C-g again, we'll interpret the second C-g as a quit and break out of the loop.

Can you please give me some specific and concrete scenarios you have in mind that might clarify these reliability issues you're talking about?

>> > Different machines and OSes, and different
>> > system loads, can make it nigh impossible to do reliably.  And that's
>> > _bad_, because when I want something interrupted right away, I don't
>> > want or even cannot try again and again and again until it works.
>> 
>> Then define a separate key that means _only_ quit and that cannot be
>> bound to a regular command.  C-g can't be that command without breaking
>> existing code.
>
>It's too late to define a separate key _instead_ of C-g.  We could
>define a separate key _in_addition_ to C-g, but that doesn't solve the
>problem: people have C-g hardwired into their muscle memory, and it
>will take a lot of time for them to re-learn.  Meanwhile, we get bug
>reports about C-g not working like it did before.

No, we didn't get a bug report. We got a specially constructed program that exercised a beneficial behavior change and called it a bug. I've yet to see a real world problem. The person who constructed that program complained that a loop that could be quit before was unquittable now. I am trying to explain that it will, in fact, be quittable.

>So minimizing the behavior changes is still a requirement, even if we
>add another key.  And that's before we even consider what other key
>could serve that purpose, which is not a trivial problem to solve
>portably

I'm not talking about adding another quit key. That's not the right solution. I don't see a real world scenario in which multiple C-g doesn't work well enough, and we have, what, decades of experience with this mechanism on TTYs? Why is taking the force quit mechanism, fixing its reliability issues, and generalizing it to GUIs suddenly a problem?

>> Treating repeated C-g presses made in a reasonable window of time within
>> the scope of a single command in such a way that we're almost certainly
>> not confusing this series of keystrokes with C-g-as-command input solves
>> the problem.
>
>That's possible, but it is not the best alternative IMO, for the
>reasons I explained.

I've yet to see you propose a different solution. All I've seen is resistance to change whether it's beneficial or not.

My proposal allows you to interrupt any Lisp program. In every real world scenario, you can interrupt with one C-g. In pathological cases, you can interrupt by pressing C-g multiple times. This mechanism is reliable.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 13:44:02 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Lynn Winebarger <owinebar <at> gmail.com>, Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, Pip Cet <pipcet <at> protonmail.com>,
 Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 06:42:58 -0700

On June 13, 2025 5:23:34 AM PDT, Lynn Winebarger <owinebar <at> gmail.com> wrote:
>On Fri, Jun 13, 2025, 2:26 AM Eli Zaretskii <eliz <at> gnu.org> wrote:
>
>> > From: Daniel Colascione <dancol <at> dancol.org>
>> > Cc: Eli Zaretskii <eliz <at> gnu.org>,  monnier <at> iro.umontreal.ca,
>> >   78737 <at> debbugs.gnu.org
>> > Date: Thu, 12 Jun 2025 11:48:50 -0700
>> >
>> > Pip Cet <pipcet <at> protonmail.com> writes:
>> >
>> > > I'd like read-event, when called while inhibit-quit is t, to report
>> > > quits by setting quit-flag in addition to returning quit_char: it'll
>> > > simplify the C code, and it would make
>> > >
>> > > (while t
>> > >   (let ((inhibit-quit t))
>> > >     (read-event)))
>> >
>> > I strongly disagree.  read-event should read an event.
>> > Setting quit-flag by side effect when it happens to read one key and not
>> > others makes the interface less regular and understandable.
>>
>> We should start by agreeing that the capability of interrupting a
>> running Lisp program is a real need.  Are we in agreement about that?
>> If not, let's first hear the arguments why not.
>>
>> If we _are_ in agreement about that, we should discuss how this should
>> be possible if read-event (and perhaps others?) return C-g instead of
>> raising quit-flag.  The alternatives mentioned until now are:
>>
>>  . restore the old behavior, whereby C-g interrupts read-event
>>  . have a variable that, if set, will restore the old behavior in
>>    read-event and other affected primitives, to be interruptible by a
>>    single C-g
>>  . make two C-g presses "in quick succession" set quit-flag, IOW
>>    "C-g C-g" will have the same effect as C-g previously
>>
>> Are there other alternatives?
>>
>
>What about keeping a (possibly buffer-local?) lisp variable holding a list
>of keystrokes mapped to thunks that are treated as generating lisp machine
>"interrupts"?  The key strokes would be processed by C machinery and never
>seen directly by lisp code and not be considered "events".
>Then C-g could be bound to a thunk signalling quit, and the effect of
>"inhibit-quit" achieved by removing C-g from the list in a given dynamic
>scope.  Then user code could make other key-strokes "special" without
>resorting to read-event.  For example, this read-event call in term.el:
>(message "Hit space to flush")
>      (let ((ch (read-event)))
> (if (eq ch ?\s)
>     (set-window-configuration conf)
>   (push ch unread-command-events)))
>
>Could be replaced by something like
>(with-interrupts ((?\s (signal term-flush)))
>  (condition-case nil
>    (while t (sit-for 100))
>     (term-flush (set-window-configuration conf))))
>
>Then some of these use-case concerns could be mooted altogether.

We already have something like that. :-) read-event already runs the events it reads through special-event-map, right? We don't even need to create a separate thunk list concept: we could just bind C-g in special event map and do what we want, right?

The only special thing about C-g is how we treat it when Lisp is running. When it's instead reading an event, it can and be a boring event processed the same way every other event is.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 14:02:02 GMT) Full text and rfc822 format available.

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

From: Gerd Möllmann <gerd.moellmann <at> gmail.com>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 Pip Cet <pipcet <at> protonmail.com>, Lynn Winebarger <owinebar <at> gmail.com>,
 Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 16:01:01 +0200
Daniel Colascione <dancol <at> dancol.org> writes:

> We already have something like that. :-) read-event already runs the
> events it reads through special-event-map, right?

Entirely unrelated, I just came across this because I searched for
read-event. Let me just mention that read-event does not respect
input-decode-map. This is a problem on ttys, see bug#75886.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 14:03:02 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Lynn Winebarger <owinebar <at> gmail.com>, Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, Pip Cet <pipcet <at> protonmail.com>,
 Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 07:02:14 -0700

On June 13, 2025 6:42:58 AM PDT, Daniel Colascione <dancol <at> dancol.org> wrote:
>
>
>On June 13, 2025 5:23:34 AM PDT, Lynn Winebarger <owinebar <at> gmail.com> wrote:
>>On Fri, Jun 13, 2025, 2:26 AM Eli Zaretskii <eliz <at> gnu.org> wrote:
>>
>>> > From: Daniel Colascione <dancol <at> dancol.org>
>>> > Cc: Eli Zaretskii <eliz <at> gnu.org>,  monnier <at> iro.umontreal.ca,
>>> >   78737 <at> debbugs.gnu.org
>>> > Date: Thu, 12 Jun 2025 11:48:50 -0700
>>> >
>>> > Pip Cet <pipcet <at> protonmail.com> writes:
>>> >
>>> > > I'd like read-event, when called while inhibit-quit is t, to report
>>> > > quits by setting quit-flag in addition to returning quit_char: it'll
>>> > > simplify the C code, and it would make
>>> > >
>>> > > (while t
>>> > >   (let ((inhibit-quit t))
>>> > >     (read-event)))
>>> >
>>> > I strongly disagree.  read-event should read an event.
>>> > Setting quit-flag by side effect when it happens to read one key and not
>>> > others makes the interface less regular and understandable.
>>>
>>> We should start by agreeing that the capability of interrupting a
>>> running Lisp program is a real need.  Are we in agreement about that?
>>> If not, let's first hear the arguments why not.
>>>
>>> If we _are_ in agreement about that, we should discuss how this should
>>> be possible if read-event (and perhaps others?) return C-g instead of
>>> raising quit-flag.  The alternatives mentioned until now are:
>>>
>>>  . restore the old behavior, whereby C-g interrupts read-event
>>>  . have a variable that, if set, will restore the old behavior in
>>>    read-event and other affected primitives, to be interruptible by a
>>>    single C-g
>>>  . make two C-g presses "in quick succession" set quit-flag, IOW
>>>    "C-g C-g" will have the same effect as C-g previously
>>>
>>> Are there other alternatives?
>>>
>>
>>What about keeping a (possibly buffer-local?) lisp variable holding a list
>>of keystrokes mapped to thunks that are treated as generating lisp machine
>>"interrupts"?  The key strokes would be processed by C machinery and never
>>seen directly by lisp code and not be considered "events".
>>Then C-g could be bound to a thunk signalling quit, and the effect of
>>"inhibit-quit" achieved by removing C-g from the list in a given dynamic
>>scope.  Then user code could make other key-strokes "special" without
>>resorting to read-event.  For example, this read-event call in term.el:
>>(message "Hit space to flush")
>>      (let ((ch (read-event)))
>> (if (eq ch ?\s)
>>     (set-window-configuration conf)
>>   (push ch unread-command-events)))
>>
>>Could be replaced by something like
>>(with-interrupts ((?\s (signal term-flush)))
>>  (condition-case nil
>>    (while t (sit-for 100))
>>     (term-flush (set-window-configuration conf))))
>>
>>Then some of these use-case concerns could be mooted altogether.
>
>We already have something like that. :-) read-event already runs the events it reads through special-event-map, right? We don't even need to create a separate thunk list concept: we could just bind C-g in special event map and do what we want, right?
>
>The only special thing about C-g is how we treat it when Lisp is running. When it's instead reading an event, it can and be a boring event processed the same way every other event is.

Oh yeah, one thing I forgot to mention: for the *asynchronous* case, the C code is pretty deeply coupled to quit_char, and IIRC, even hard codes 7, C-g, in some places instead of quit_char. In your proposal, we'd references to quit_char and literal 7 to calls to a new bool is_quit_char(int c) function -- and this function would return true for any raw keys bound in special-event-map. In this way, you'd be able to define as many asynchronous-input characters as you wanted.

We wouldn't get the special SIGINT behavior this way (because in termios there can be only one interrupt key, right?), but I think that's okay, since quitting works without the SIGINT wiring and I suspect that we could remove the SIGINT wiring and simplify the codebase without losing any actual functionality. 




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 14:14:02 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Gerd Möllmann <gerd.moellmann <at> gmail.com>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 Pip Cet <pipcet <at> protonmail.com>, Lynn Winebarger <owinebar <at> gmail.com>,
 Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 07:12:56 -0700

On June 13, 2025 7:01:01 AM PDT, "Gerd Möllmann" <gerd.moellmann <at> gmail.com> wrote:
>Daniel Colascione <dancol <at> dancol.org> writes:
>
>> We already have something like that. :-) read-event already runs the
>> events it reads through special-event-map, right?
>
>Entirely unrelated, I just came across this because I searched for
>read-event. Let me just mention that read-event does not respect
>input-decode-map. This is a problem on ttys, see bug#75886.


Seems at least a little related, doesn't it? It's another example of a real world problem caused by inconsistent input reading strategy, isn't it?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 14:29:02 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>, pipcet <at> protonmail.com
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 10:28:23 -0400
>> I like your way of thinking.  I'm not completely sure it will solve
>> world hunger, and it may come with regressions, but it's worth a try.
>> Given the pervasive impact, it might be best to have a global config var
>> to enable/disable it (with some scary internal name) until we're
>> confident that it's an improvement.
>
> Check out the branch dancol/quit-improvements2 with a fix for this
> problem and multiple others I found along the way.  There, we make
> read_char report quits as quit_char, protect timer callbacks against
> quits properly, inhibit quits in redisplay by default, attempt to quit
> more often reading process output, and fix the original
> throw-on-input bug.

Regarding "inhibit quits in redisplay by default": I've several times
got my way out of a jit-lock hang (not necessarily an info-loop,
e.g. a nasty regexp explosion) by leaning on `C-g` (the actual behavior
sucks, because the quit is caught by the redisplay which then jumps
right back into the same jit-lock code, toh apparently there's a bit of
progress made along the way, hence the need to lean on `C-g` for a while).

Maybe `kill -USR2` would work better?  Still, while I agree that we
should generally inhibit quits during redisplay, inhibiting all quits is
a problem, so I often wish we had two notions of quits: the "normal
quit" and the "emergency quit", where the emergency quit puts more
emphasis on making sure we stop what we're doing than on preserving
a "clean" state (e.g. I don't mind some redisplay glitches after an
emergency quit from jit-lock).  We'd still want to stay away from core
dumps, of course.

> (It's dancol/quit-improvements2 not dancol/quit-improvements because I
> can't force-push even to a non-mainline branch.  Shouldn't we allow
> off-mainline force pushes?)

Someone mentioned the `scratch/` convention.  Note that the repository
will still refuse `git push --force`: you need to first delete the old
branch with `git push :scratch/foo` and then push the new branch on top.


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 14:38:02 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>, pipcet <at> protonmail.com
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 07:36:57 -0700
On June 13, 2025 7:28:23 AM PDT, Stefan Monnier <monnier <at> iro.umontreal.ca> wrote:
>>> I like your way of thinking.  I'm not completely sure it will solve
>>> world hunger, and it may come with regressions, but it's worth a try.
>>> Given the pervasive impact, it might be best to have a global config var
>>> to enable/disable it (with some scary internal name) until we're
>>> confident that it's an improvement.
>>
>> Check out the branch dancol/quit-improvements2 with a fix for this
>> problem and multiple others I found along the way.  There, we make
>> read_char report quits as quit_char, protect timer callbacks against
>> quits properly, inhibit quits in redisplay by default, attempt to quit
>> more often reading process output, and fix the original
>> throw-on-input bug.
>
>Regarding "inhibit quits in redisplay by default": I've several times
>got my way out of a jit-lock hang (not necessarily an info-loop,
>e.g. a nasty regexp explosion) by leaning on `C-g` (the actual behavior
>sucks, because the quit is caught by the redisplay which then jumps
>right back into the same jit-lock code, toh apparently there's a bit of
>progress made along the way, hence the need to lean on `C-g` for a while).

Agreed. See my spec on the other thread. In terms of that post, we'd break out of redisplay when #quits >= M: this condition means we'd ignore the inhibit-quit when deciding whether to Fsignal in response to a quit. It's also worth putting an explicit maybe_quit at the end of redisplay_internal if we don't have one already.

>Maybe `kill -USR2` would work better? 

Thanks for reminding me to mention SIGUSR2. We'll treat it like #quits >= M.

> Still, while I agree that we
>should generally inhibit quits during redisplay, inhibiting all quits is
>a problem, so I often wish we had two notions of quits: the "normal
>quit" and the "emergency quit", where the emergency quit puts more
>emphasis on making sure we stop what we're doing than on preserving
>a "clean" state (e.g. I don't mind some redisplay glitches after an
>emergency quit from jit-lock).  We'd still want to stay away from core
>dumps, of course

That's what I'm proposing.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 14:40:01 GMT) Full text and rfc822 format available.

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

From: Gerd Möllmann <gerd.moellmann <at> gmail.com>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 Pip Cet <pipcet <at> protonmail.com>, Lynn Winebarger <owinebar <at> gmail.com>,
 Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 16:39:05 +0200
Daniel Colascione <dancol <at> dancol.org> writes:

> On June 13, 2025 7:01:01 AM PDT, "Gerd Möllmann" <gerd.moellmann <at> gmail.com> wrote:
>>Daniel Colascione <dancol <at> dancol.org> writes:
>>
>>> We already have something like that. :-) read-event already runs the
>>> events it reads through special-event-map, right?
>>
>>Entirely unrelated, I just came across this because I searched for
>>read-event. Let me just mention that read-event does not respect
>>input-decode-map. This is a problem on ttys, see bug#75886.
>
>
> Seems at least a little related, doesn't it? It's another example of a
> real world problem caused by inconsistent input reading strategy,
> isn't it?

True :-). And C-g in this case is an escape sequence, and so on. My old
friend keyboard.c :-(.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 14:47:02 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 17:46:41 +0300
> Date: Fri, 13 Jun 2025 04:49:21 -0700
> From: Daniel Colascione <dancol <at> dancol.org>
> CC: pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
> 
> 
> 
> On June 13, 2025 4:36:42 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
> >> From: Daniel Colascione <dancol <at> dancol.org>
> >> Cc: Pip Cet <pipcet <at> protonmail.com>,  monnier <at> iro.umontreal.ca,
> >>   78737 <at> debbugs.gnu.org
> >> Date: Fri, 13 Jun 2025 00:53:38 -0700
> >> 
> >> > If you are talking about a GUI session, then IME the 'emergency exit"
> >> > procedure isn't reliably working in that case, and I'm not sure the
> >> > implementation intends to support that.  I always knew that it's only
> >> > reliably working on TTY frames.
> >> >
> >> > Or are you talking about the effect of the changes on the branch?
> >> 
> >> FWIW, the purpose of my N-times-in-T-milliseconds-within-one-command
> >> formulation of emergency exit is to get the mechanism working reliably
> >> in all cases.
> >> 
> >> I can definitely type 4-5 C-gs in a GUI Emacs (well, NS, but I recall
> >> PGTK being similar?) and not have Emacs quit.  If I mash C-g, it
> >> sometimes does, and sometimes doesn't.
> >> 
> >> Right now, the logic is this:
> >> 
> >>     {
> >>       /* Request quit when it's safe.  */
> >>       int count = NILP (Vquit_flag) ? 1 : force_quit_count + 1;
> >>       force_quit_count = count;
> >>       if (count == 3)
> >> 	Vinhibit_quit = Qnil;
> >>       Vquit_flag = Qt;
> >>     }
> >> 
> >> IOW, the first quit after clearing Vquit_flag resets the count to one.
> >> Maybe that's why it isn't working reliably right now.  If we reformulate
> >> this mechanism not in terms of count == 3 (which is fiddly for all sorts
> >> of reasons, since Vquit_flag can get reset) but in terms of the UX
> >> directly --- N recent quits in T time in a single command --- we make
> >> the whole thing more reliable.
> >> 
> >> If you set T=infinity and N=3, you get the current force quit UX (modulo
> >> my upgrade-before-disabling-inhibit-quit thing), just more reliably, and
> >> you can break out of arbitrary Lisp code.
> >
> >I suggest to leave the emergency exit feature alone for now, and focus
> >on the interruptibility of Lisp programs.
> 
> That *is* the interruptabiltity of Lisp programs.l

No, not in my book.  A Lisp program should be interruptible without
killing the Emacs session.  "Emergency exit", OTOH, kills the Emacs
session.

So we should discuss these two features separately.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 14:50:01 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 07:48:54 -0700
On June 13, 2025 7:46:41 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
>> Date: Fri, 13 Jun 2025 04:49:21 -0700
>> From: Daniel Colascione <dancol <at> dancol.org>
>> CC: pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
>> 
>> 
>> 
>> On June 13, 2025 4:36:42 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
>> >> From: Daniel Colascione <dancol <at> dancol.org>
>> >> Cc: Pip Cet <pipcet <at> protonmail.com>,  monnier <at> iro.umontreal.ca,
>> >>   78737 <at> debbugs.gnu.org
>> >> Date: Fri, 13 Jun 2025 00:53:38 -0700
>> >> 
>> >> > If you are talking about a GUI session, then IME the 'emergency exit"
>> >> > procedure isn't reliably working in that case, and I'm not sure the
>> >> > implementation intends to support that.  I always knew that it's only
>> >> > reliably working on TTY frames.
>> >> >
>> >> > Or are you talking about the effect of the changes on the branch?
>> >> 
>> >> FWIW, the purpose of my N-times-in-T-milliseconds-within-one-command
>> >> formulation of emergency exit is to get the mechanism working reliably
>> >> in all cases.
>> >> 
>> >> I can definitely type 4-5 C-gs in a GUI Emacs (well, NS, but I recall
>> >> PGTK being similar?) and not have Emacs quit.  If I mash C-g, it
>> >> sometimes does, and sometimes doesn't.
>> >> 
>> >> Right now, the logic is this:
>> >> 
>> >>     {
>> >>       /* Request quit when it's safe.  */
>> >>       int count = NILP (Vquit_flag) ? 1 : force_quit_count + 1;
>> >>       force_quit_count = count;
>> >>       if (count == 3)
>> >> 	Vinhibit_quit = Qnil;
>> >>       Vquit_flag = Qt;
>> >>     }
>> >> 
>> >> IOW, the first quit after clearing Vquit_flag resets the count to one.
>> >> Maybe that's why it isn't working reliably right now.  If we reformulate
>> >> this mechanism not in terms of count == 3 (which is fiddly for all sorts
>> >> of reasons, since Vquit_flag can get reset) but in terms of the UX
>> >> directly --- N recent quits in T time in a single command --- we make
>> >> the whole thing more reliable.
>> >> 
>> >> If you set T=infinity and N=3, you get the current force quit UX (modulo
>> >> my upgrade-before-disabling-inhibit-quit thing), just more reliably, and
>> >> you can break out of arbitrary Lisp code.
>> >
>> >I suggest to leave the emergency exit feature alone for now, and focus
>> >on the interruptibility of Lisp programs.
>> 
>> That *is* the interruptabiltity of Lisp programs.l
>
>No, not in my book.  A Lisp program should be interruptible without
>killing the Emacs session.  "Emergency exit", OTOH, kills the Emacs
>session.

Maybe we're talking past each other? I'm not proposing anything that automatically kills Emacs. I'm not sure what would have given you the impression we were talking about killing Emacs.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 14:52:01 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Pip Cet <pipcet <at> protonmail.com>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 Daniel Colascione <dancol <at> dancol.org>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 10:51:37 -0400
> Making
>
>     (while t (read-event))
>
> infloop without being able to quit is a bad idea.  We shouldn't do it.

I don't find this terribly problematic, If you think of what that loop
means it *is* a "please shoot me in the foot" kind of thing.

I agree that not being able to escape is a problem, but it's not the
only way to get into such trouble.  IOW I think it just gets us back to
the fact that we need an "emergency quit" for bugs (which `kill -USR2`
can sometimes provide, tho it's not a quit per-se).


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 14:54:02 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Pip Cet <pipcet <at> protonmail.com>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 Daniel Colascione <dancol <at> dancol.org>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 10:53:43 -0400
> -    ;; FIXME: we should not read-event here at all, because it's much too
> -    ;; difficult to reliably "undo" a read-event by pushing it onto
> -    ;; unread-command-events.
> -    ;; For bug#14782, we need read-event to do the keyboard-coding-system
> -    ;; decoding (hence non-nil as second arg under POSIX ttys).
> -    ;; For bug#15614, we need read-event not to inherit-input-method.
> -    ;; So we temporarily suspend input-method-function.
> -    (let ((read (let ((input-method-function nil))
> -                  (read-event nil t seconds))))
> -      (or (null read)
> -	  (progn
> -            ;; https://lists.gnu.org/r/emacs-devel/2006-10/msg00394.html
> -            ;; We want `read' appear in the next command's this-command-event
> -            ;; but not in the current one.
> -            ;; By pushing (cons t read), we indicate that `read' has not
> -            ;; yet been recorded in this-command-keys, so it will be recorded
> -            ;; next time it's read.
> -            ;; And indeed the `seconds' argument to read-event correctly
> -            ;; prevented recording this event in the current command's
> -            ;; this-command-keys.
> -	    (push (cons t read) unread-command-events)
> -	    nil))))))
> +    (not (if throw-on-input
> +             (sleep-for seconds)
> +           (while-no-input (sleep-for seconds)))))))

I'm not sure this will wake up on the same events (i.e. whether its
notion of what is "not a real input event" is the same).  `sit-for` has
seen several iterations because of "corner cases", so I wouldn't be
surprised to bump into regressions, but I agree that it would be nice to
"align" the notion of "relevant" events used by `sit-for` with that used
by `while-no-input`.
[ IIRC part of the differences are the events handled by
  `special-event-map`.  ]

Note also that I'm not sure `sleep-for` will actually do what we want
here (does it run process filters and timers?  And update the display
accordingly?).


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 14:55:02 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Pip Cet <pipcet <at> protonmail.com>
Cc: 78737 <at> debbugs.gnu.org, dancol <at> dancol.org, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 17:54:40 +0300
> Date: Fri, 13 Jun 2025 12:26:19 +0000
> From: Pip Cet <pipcet <at> protonmail.com>
> Cc: dancol <at> dancol.org, monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
> 
> "Eli Zaretskii" <eliz <at> gnu.org> writes:
> 
> >> (while t
> >>   (let ((inhibit-quit t))
> >>     (read-event)))
> >>
> >> quittable, as I naively expected it to be.  The old behavior would
> >> remain available, but require an extra let binding.
> >
> > But isn't it confusing that to have something quittable one needs to
> > bind inhibit-quit non-nil?
> 
> I'm confused: the code above should be quittable whether or not the
> "let" line is present, as long as the "let" line comes after the "while"
> line: we unbind inhibit-quit after each iteration, and I'm expecting
> Emacs to take this opportunity to quit.

You are looking at this from the implementation POV, while I look at
this from the user POV.  Telling users to bind inhibit-quit non-nil to
make a program quittable will make very little sense to users.

> >> Note that this isn't
> >>
> >> (let ((inhibit-quit t))
> >>   (while t
> >>     (read-event)))
> >
> > Which is also confusing by its inconsistency.  In general, the order
> > of let-bindings doesn't matter.
> 
> I don't see how it's inconsistent, sorry.  If I bind inhibit-quit and
> keep it bound while clearing quit-flag, I get an unquittable loop.  If I
> repeatedly bind and unbind inhibit-quit so it becomes nil once per
> iteration, I should get a quit when it does become nil, after the
> binding has been unwound but before the next iteration's binding goes
> into effect.

You are again looking at the implementation aspects.

> >> Situation 3:
> >>
> >> Several force-quits in the same session.  Reset force_quit_count to 0
> >> once it reaches 3.  I've seen force_quit_count reach higher values than
> >> 3 (there was no regular quit in between force quit attempts).
> >
> > If you are talking about a GUI session, then IME the 'emergency exit"
> > procedure isn't reliably working in that case, and I'm not sure the
> > implementation intends to support that.  I always knew that it's only
> > reliably working on TTY frames.
> 
> I'm talking about the GUI case, yes.
> 
> It seems like an oversight to me.  Two successive emergency quits don't
> work if both of these conditions hold:
> 
> 1. there's no intervening regular C-g
> 2. quit-flag is non-nil
> 
> So a recipe would be:
> 
> (let ((inhibit-quit t))
>   (setq quit-flag t)
>   (while t))
> 
> C-x C-e
> C-g C-g C-g
> C-x C-e
> C-g C-g C-g
> 
> Expected outcome: two emergency quits
> Actual outcome: one emergency quit, no further emergency quits possible.

I suggest to leave the emergency exit feature alone for now, and focus
on the interruptibility of Lisp programs first.  We have enough issues
to agree on and fix there.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 15:05:01 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Eli Zaretskii <eliz <at> gnu.org>, Pip Cet <pipcet <at> protonmail.com>
Cc: 78737 <at> debbugs.gnu.org, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 08:00:04 -0700
On June 13, 2025 7:54:40 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
>> Date: Fri, 13 Jun 2025 12:26:19 +0000
>> From: Pip Cet <pipcet <at> protonmail.com>
>> Cc: dancol <at> dancol.org, monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
>> 
>> "Eli Zaretskii" <eliz <at> gnu.org> writes:
>> 
>> >> (while t
>> >>   (let ((inhibit-quit t))
>> >>     (read-event)))
>> >>
>> >> quittable, as I naively expected it to be.  The old behavior would
>> >> remain available, but require an extra let binding.
>> >
>> > But isn't it confusing that to have something quittable one needs to
>> > bind inhibit-quit non-nil?
>> 
>> I'm confused: the code above should be quittable whether or not the
>> "let" line is present, as long as the "let" line comes after the "while"
>> line: we unbind inhibit-quit after each iteration, and I'm expecting
>> Emacs to take this opportunity to quit.
>
>You are looking at this from the implementation POV, while I look at
>this from the user POV.  Telling users to bind inhibit-quit non-nil to
>make a program quittable will make very little sense to users.

I *am* talking about this from the UX POV, and nobody AFAICT is proposing a mechanism that involves a program becoming quittable when adding a t binding to inhibit-quit. I agree that's a bad idea. That's why nobody is suggesting it.


>> >> Note that this isn't
>> >>
>> >> (let ((inhibit-quit t))
>> >>   (while t
>> >>     (read-event)))
>> >
>> > Which is also confusing by its inconsistency.  In general, the order
>> > of let-bindings doesn't matter.
>> 
>> I don't see how it's inconsistent, sorry.  If I bind inhibit-quit and
>> keep it bound while clearing quit-flag, I get an unquittable loop.  If I
>> repeatedly bind and unbind inhibit-quit so it becomes nil once per
>> iteration, I should get a quit when it does become nil, after the
>> binding has been unwound but before the next iteration's binding goes
>> into effect.
>
>You are again looking at the implementation aspects.

How many times do I have to put the situation in terms of UX? I mention user experience over and over, yet I see you insist I'm not considering UX. What specific aspect am I not considering?

>
>> >> Situation 3:
>> >>
>> >> Several force-quits in the same session.  Reset force_quit_count to 0
>> >> once it reaches 3.  I've seen force_quit_count reach higher values than
>> >> 3 (there was no regular quit in between force quit attempts).
>> >
>> > If you are talking about a GUI session, then IME the 'emergency exit"
>> > procedure isn't reliably working in that case, and I'm not sure the
>> > implementation intends to support that.  I always knew that it's only
>> > reliably working on TTY frames.
>> 
>> I'm talking about the GUI case, yes.
>> 
>> It seems like an oversight to me.  Two successive emergency quits don't
>> work if both of these conditions hold:
>> 
>> 1. there's no intervening regular C-g
>> 2. quit-flag is non-nil
>> 
>> So a recipe would be:
>> 
>> (let ((inhibit-quit t))
>>   (setq quit-flag t)
>>   (while t))
>> 
>> C-x C-e
>> C-g C-g C-g
>> C-x C-e
>> C-g C-g C-g
>> 
>> Expected outcome: two emergency quits
>> Actual outcome: one emergency quit, no further emergency quits possible.
>
>I suggest to leave the emergency exit feature alone for now, and focus
>on the interruptibility of Lisp programs first.  We have enough issues
>to agree on and fix there.

The emergency exit aspect of the proposal is *how* we ensure that all Lisp programs can be interrupted.  I am not proposing that we make some Lisp programs uninterruptible. I am not proposing some system for automatically killing Emacs. I am proposing a more robust version of the mechanics we already have. Normal users in ordinary use will not see a UX difference, except on NS, where quits will start working reliably where they don't today.





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 15:05:02 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, dancol <at> dancol.org
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 11:04:27 -0400
> This code is used everywhere, and we have no one on board who knows it
> (and its many quirks and platform-dependent subtleties) well enough.
> It isn't an accident that we prefer not to make changes in it: each
> time we made even small changes in this code we ended up with
> regressions.  We don't have any decent test suite for the this part of
> Emacs.  We don't even have an exhaustive list of
> features/commands/operations to test in order to make sure some change
> doesn't break them.  Notable corners that get frequently broken by
> changes in this area: keyboard macros, Leim input methods, and
> non-keyboard input events.

Yes, that's what I see as the main benefit of Daniel's suggestion: it
makes the behavior a bit simpler to describe (assuming there isn't some
nasty implementation detail which leaves some corner case open), so it
would help make that code a bit more manageable.

Ideally it should come with some documented design rationale of how
`inhibit-quit` is expected to be used and behave in general (i.e. in
what kind of circumstances it should be bound and where/when it
shouldn't, ...).

I have no delusion that it can be done without introducing some
regressions.


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 15:10:02 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com,
 Daniel Colascione <dancol <at> dancol.org>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 11:09:33 -0400
> Specifically, what I'm interested in is how come
>
>  (while t
>    (read-event))
>
> cannot be interrupted by C-g, but you seem to be saying that
>
>  (while t
>    (let (evt (read-event))
>      (do-something-with evt)))
>
> _can_ be interrupted?

Usually the `(do-something-with evt)` part will offer some way to end
the loop.


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 15:25:03 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com,
 Daniel Colascione <dancol <at> dancol.org>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 11:24:29 -0400
> We should start by agreeing that the capability of interrupting a
> running Lisp program is a real need.  Are we in agreement about that?
> If not, let's first hear the arguments why not.

It's a real need, but there's also a real need for some ELisp functions
to catch normal quits.  So we can't have "normal quits" as the universal
answer to "interrupting a running Lisp program".

What we have instead is that "normal quit" should work to interrupt any
well-behaved ELisp programs, plus it should also work to interrupt most
other ELisp programs (IOW it shouldn't be hard to write well-behaved
ELisp code), but there has always been and will always be cases where we
need an "emergency quit" to interrupt some ELisp programs (and that
feature has been missing in GUI builds for a while).


        Stefan


PS: BTW, since we're talking about uses of `inhibit-quit`, I just
    remembered that correctness reasons, `unbind_to` *should* run with
    `inhibit-quit` set.





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 15:35:01 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Gerd Möllmann <gerd.moellmann <at> gmail.com>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 Daniel Colascione <dancol <at> dancol.org>, Pip Cet <pipcet <at> protonmail.com>,
 Lynn Winebarger <owinebar <at> gmail.com>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 11:34:31 -0400
>> We already have something like that. :-) read-event already runs the
>> events it reads through special-event-map, right?
> Entirely unrelated, I just came across this because I searched for
> read-event. Let me just mention that read-event does not respect
> input-decode-map. This is a problem on ttys, see bug#75886.

Currently the only "decoding" we have to turn the TTY input bytes into
events is limited to the keyboard-coding-system thingy.  🙁

Maybe I should have implemented `input-decode-map` directly inside
`read-event`, but I think it goes contrary to the design.

It's usually better to change the users to use a higher-level function
instead, such as `read-key`.

Admittedly, if you want to recognize a quit event encoded as an escape
sequence, that's not going to help you because we need/want those events
to be decoded at as-low a level as we can. 🙁


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 15:39:04 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Daniel Colascione <dancol <at> dancol.org>, Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 11:37:51 -0400
Ladies and gentlemen, please let's try and keep this civil.
Let's remember that misunderstandings and implicit assumptions are part
of human life.


        Stefan


Daniel Colascione [2025-06-13 06:35:40] wrote:

> On June 13, 2025 4:34:06 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
>>> From: Daniel Colascione <dancol <at> dancol.org>
>>> Cc: pipcet <at> protonmail.com,  monnier <at> iro.umontreal.ca,  78737 <at> debbugs.gnu.org
>>> Date: Fri, 13 Jun 2025 00:28:45 -0700
>>> 
>>> Eli Zaretskii <eliz <at> gnu.org> writes:
>>> 
>>> >> From: Daniel Colascione <dancol <at> dancol.org>
>>> >> Cc: Eli Zaretskii <eliz <at> gnu.org>,  monnier <at> iro.umontreal.ca,
>>> >>   78737 <at> debbugs.gnu.org
>>> >> Date: Thu, 12 Jun 2025 11:48:50 -0700
>>> >> 
>>> >> Pip Cet <pipcet <at> protonmail.com> writes:
>>> >> 
>>> >> > I'd like read-event, when called while inhibit-quit is t, to report
>>> >> > quits by setting quit-flag in addition to returning quit_char: it'll
>>> >> > simplify the C code, and it would make
>>> >> >
>>> >> > (while t
>>> >> >   (let ((inhibit-quit t))
>>> >> >     (read-event)))
>>> >> 
>>> >> I strongly disagree.  read-event should read an event.
>>> >> Setting quit-flag by side effect when it happens to read one key and not
>>> >> others makes the interface less regular and understandable.
>>> >
>>> > We should start by agreeing that the capability of interrupting a
>>> > running Lisp program is a real need.  Are we in agreement about that?
>>> > If not, let's first hear the arguments why not.
>>> 
>>> Which Lisp programs?
>>
>>All of them.
>
> Do you want a mechanism that can interrupt all Lisp programs or not? I have such a mechanism.
>
>>> One that calls (while t (read-event))?  One that
>>> calls (let ((inhibit-quit t)) (while t (read-event))?  How about one
>>> that calls (while t (read-key-sequence ""))?  How about one that calls
>>> (let ((inhibit-quit t)) (while t (read-key-sequence ""))?  If you adopt
>>> the tenet that Lisp programs always be uninterruptible, _something_ has
>>> to change from the present, because 3/4 of my examples above cannot
>>> be quit.
>>
>>So because we currently cannot interrupt some programs we should give
>>up the ability to interrupt all of them?
>
> My proposal allows us to interrupt all Lisp programs. I don't know how many
> times I have to say this to get the point across.
>
>> Please be serious.
>
> Please engage with what I'm saying and at least try to say things that make internal sense.
>
>>Arguments like the above are a red herring, and don't help advancing
>>this discussion towards some kind of agreement.
>
> You just said above that we should consider the interruptabiltity of all
> Lisp programs. I cited examples of Lisp programs. That means these Lisp
> programs are relevant to the conversation, as they, being Lisp programs,
> belong to the category of all Lisp programs.
>
>>Do you want the branch merged at some point? 
>
> Do you want bugs fixed and behaviors improved at some point?
>
>> Then please drop the
>>attitude and start participating in the discussion seriously.  You
>>understand very well what I meant above, even though it is somewhat
>>vague. 
>
> Actually, I have no idea what you mean: you say things like you're not sure
> whether we can distinguish two C-g presses from a double C-g press. There
> are the same thing. It's like asking whether we can distinguish #00f from
> #0000ff.
>
>> We all know what Emacs can and cannot do today, so I allow
>>myself not to write too many well-known details.
>>
>>Let's consider the current capabilities of interrupting Lisp programs
>>as base line, and try to maintain that base line, if not improve on
>>it.  Okay?  
>
> I'm suggesting being able to interrupt all Lisp programs. Not all Lisp
> programs can be interrupted today. I have explained in multiple places how
> that is to be done. I am happy to explain further if you give me some
> substantial technical questions about the mechanisms involved.
>
> When Lisp writes (while t (some-event-reading-function)), programmer intent
> is not clear. It's not clear because C-g is overloaded and can be either an
> event or a quit command. On the one hand, the Lisp is running Lisp and we
> have a general contract that Lisp can be interrupted with C-g. On the other
> hand, Lisp is asking to read an event, and C-g can be an event. We have to
> resolve the ambiguity SOMEHOW. Right now, Emacs resolves the ambiguity in an
> inconsistent and ad-hoc manner. If the some-event-reading-function above is
> read-event, we resolve the ambiguity in favor of quitting. If instead
> some-event-reading-function is read-key-sequence, we resolve the ambiguity
> in favor of event reading. This inconsistency is real, confusing, and
> illogical. In my proposal, we resolve the ambiguity in favor of event
> reading and use multiple C-g presses to indicate user intent to quit instead
> of provide input. I don't believe there's a practical, real world use case
> in which a single C-g will be insufficient, but the ability to press C-g
> multiple times will be there regardless. If you'd like to configure your
> Emacs to resolve the ambiguity in favor of quitting, you can do that by
> changing one variable. Either way, behavior will be consistent among all
> Lisp functions that read events.
>
> Would you please engage substantively with the previous paragraph instead of
> calling it a distraction and then raising points germane to exactly what the
> previous paragraph covers?
>
> Again, nobody is talking about making users count C-g. Nobody is talking
> about requiring multiple C-g presses in any real world case. The change I'm
> talking about will make Emacs more consistent, and I've yet to see anything
> in the real world it would break.
>
> My change also makes Emacs safer, because in my model, you *can* break out
> of (while t (read-key-sequence)) and in master today you cannot. There will
> be *one* uniform and consistent (and easy to understand) model for how we
> address the *inherent* ambiguity about what control-g on a keyboard means.
>
> Or does it still not satisfy your intentionally-pedantic
>>interpretation of what I write?
>
> I wouldn't have to be pedantic if you would be clear about what you want.
>
>>> > If we _are_ in agreement about that, should discuss how this should
>>> > be possible if read-event (and perhaps others?) return C-g instead of
>>> > raising quit-flag.  The alternatives mentioned until now are:
>>> >
>>> >  . restore the old behavior, whereby C-g interrupts read-event
>>> 
>>> Does not satisfy the "lisp programs always be
>>> interruptible" requirement.
>>> 
>>> >  . have a variable that, if set, will restore the old behavior in
>>> 
>>> Same as above.
>>> 
>>> >    read-event and other affected primitives, to be interruptible by a
>>> >    single C-g
>>> 
>>> Same as above.
>>
>>Please reconsider your responses with a more serious and cooperative
>>attitude.
>
> Then make some sense. You talk about requirements. I explain how we meet
> those requirements. That's pedantry?
>
>>> >  . make two C-g presses "in quick succession" set quit-flag, IOW
>>> >    "C-g C-g" will have the same effect as C-g previously
>>> 
>>> Only for read-event.
>>
>>Why "only"?
>>
>>Having the behavior vary depending on whether the program does or
>>doesn't call read-event will bring inconsistency, something we want to
>>avoid (and which I think you argued against).
>
> It is logically impossible to combine two things:
>
> 1) all Lisp programs can be interrupted with a single C-g
>
> 2) a Lisp program can read a C-g as an event.
>
> This isn't pedantry. It's foundational logic. Demanding a solution that
> satisfies both constraints is impossible. It would require reading the
> user's mind.
>
>>> If you want to adopt a principled stance that every Lisp program be
>>> interruptible, you necessarily, as a matter of logic, regard multiple
>>> behaviors of current Emacs to be bugs worth fixing.
>>
>>Not useful.  I didn't mean that, and you know it.
>
> You just said at the start of this email that you're considering the
> interruptabiltity of all Lisp programs. I have a scheme to make all of them
> interruptible. Nobody else has proposed one.
>
>>> > Are there other alternatives?
>>> 
>>> Get in a time machine, go back 40 years and stop overloading C-g?
>>
>>Even less useful.  Again, do you want this branch to be merged any
>>time soon?  Because I'm this close to losing my patience.  Life's too
>>short to waste it on "arguments" such as this one.
>>
>
> And I'm losing patience with objections that contradict themselves and fail to address my points.
>
>>> > I don't think there's disagreement on that level.  So let's drop this
>>> > kind of arguments, because they are not useful for this discussion.
>>> > The problem we face is how to allow Lisp code to be quittable.  A Lisp
>>> > program that calls read-event is not different from a Lisp program
>>> > calling any other function, so we still need such programs to be
>>> > quittable somehow.  Let's discuss how best to do it, okay?
>>> 
>>> Yes or no: should (while t (read-key-sequence)) be quittable?
>>
>>Why is that relevant?
>
> If you'd like to cooperate seriously, I'm happy to do so provided you do so
> as well, and part serious cooperation is answering clarifying technical
> questions instead of questioning their relevance.
>
> So, yes or no?
>
>> I asked about read-event, not
>>read-key-sequence.  Can we first discuss the read-event case?  Once we
>>are done with that, we can move to other cases.
>
> You just said above you want to consider the interruptabiltity of all Lisp
> programs. Now you're calling the interruptabiltity of some Lisp programs
> irrelevant. Which is it?
>
> It's important to consider the input model as a whole. I don't think we can
> get to a good place by focusing on one function at a time and be wilfully
> oblivious about whether different functions together form a coherent whole.
>
>>> If yes, maintaining today's behavior isn't an option.  There are plenty
>>> of other Lisp programs that cannot be quit --- even (let ((inhibit-quit
>>> t)) (while t)) cannot be quit!
>>
>>If inhibit-quit is bound to a non-nil value, the program cannot be
>>quit, and that's a feature.
>
> This seems like both a contradiction and poor UX: you want some Lisp
> programs to be interruptible and others not. Why is it a feature that some
> Lisp programs cannot be quit? I thought you wanted to talk about all Lisp
> programs being quittable. Why is it desirable that Emacs be left in an
> unrecoverable state?
>
> In my proposal, users will be able to interrupt *any* program of the form
> (let ((inhibit-quit t)) (while t (anything))) by pressing C-g enough times
> to override the inhibit-quit. Emacs already provides this feature, but only
> (AFAICT) on primary TTYs.  
>
> If this ability to break out of a loop wrapped in inhibit-quit is bad,
> should we remove the existing force-quit feature? Yes or no, please.
>
> My proposal is a generalization of a feature we've had for decades. It is not a brand new concept.
>
> Is it a bug to allow these programs to be interrupted? Yes or no. If yes,
> why isn't the existing force quit feature being removed? If not, why is
> being unable to quit some Lisp programs a "feature"?
>
> You say I know what you mean. I'm really not sure I do, because from where
> I'm sitting, you're not answering questions that would resolve the
> contradictions in what you're saying.
>
>> Why are we discussing this?
>
>
> Because we're talking about interrupting Lisp programs. That's the subject
> of the whole conversation.
>
>>
>>> If no, what is the problem with cleaning up Emacs by regularizing how we
>>> treat C-g as an event versus some kind of longjmp?
>>
>>Again, let's discuss the read-key-sequence case after we are done with
>>the read-event case.
>
> How can we consider what to do with read-event without thinking about how it
> fits into the broader picture?
>
>>> >> > Several force-quits in the same session.  Reset force_quit_count to 0
>>> >> > once it reaches 3.  I've seen force_quit_count reach higher values than
>>> >> > 3 (there was no regular quit in between force quit attempts).
>>> >> 
>>> >> Get rid of force_quit_count entirely and just detect (by writing into a
>>> >> ring buffer) whether we've received N quits in the last T milliseconds.
>>> >> That'll work the same way regardless of how quits gets detected.  We can
>>> >> change N and T freely.
>>> >
>>> > This is the last alternative I described above.  It is IMO less
>>> > desirable, because it is not always easy to press C-g twice quickly,
>>> > for whatever reasons.  It is even less desirable to define "quick
>>> > succession" in terms of time, because timings can differ a lot
>>> > depending on the free computing resources and the CPU power in
>>> > general, so determining the best default values will be very
>>> > challenging, to say the least.
>>> 
>>> I don't see the ambiguity being a realistic problem.  How often do you
>>> press C-g three times while a single command is running?
>>
>>I usually expect a single C-g to quit.  If it doesn't help, I can
>>press C-g several times, I'm not sure I count them.
>
> In my proposal, on every real world case, C-g returns you to the command
> loop when you want to go there and lets Lisp read C-g as an event when you
> want to do that. You can construct buggy or pathologically written programs
> that you can't exit with a single C-g because the meaning of that keystroke
> is overloaded. You can still get back to the main loop in these rare cases
> by pressing C-g repeatedly. You don't have to count them. You just keep
> pressing C-g until you are back in the command loop, just like today's force
> quit feature.
>
>>> We're not talking about, say, six times in multiple rounds of M-x this,
>>> select that, deactivate mark over here.  Those are multiple commands.
>>> In between multiple commands, a C-g will cause a keyboard-quit and
>>> you'll regain control over Emacs.  I'm asking, during _one_ command, how
>>> many times you typically press C-g and _don't_ mean it as a quit.
>>
>>See above.
>>
>>> We already have a force quit mechanism that kicks in at N=3.  How often
>>> do you activate it?
>>
>>I never saw it at work, except on TTY frames. 
>
> We can make it work everywhere. Is that not an improvement?
>
>> But then Windows
>>doesn't have SIGIO, it emulates that.  Maybe that's the reason.
>
> SIGIO isn't the reason. The reason force quit doesn't work is the way it's
> implemented. We can implement it better. That's my proposal, if you'd like
> to consider it in more detail.
>
>>> >> On your Emacs, you can set N to one and T to zero.
>>> >
>>> > If read-event still returns a keyboard input event when C-g is
>>> > pressed, I don't see how N = 1 would work.  Can you describe how it
>>> > would work?
>>> 
>>> It wouldn't.  Such a setting would prevent read-input returning C-g.
>>> That shouldn't be the default.
>>
>>Sorry, I don't understand.  If N = 1, what will read-event do when the
>>user presses C-g while inside read-event?  
>
> If N=1, it will quit after a single C-g. Specifically, it will raise a quit
> signal. It will raise this signal instead of returning normally. It will not
> return it as C-g to Lisp. If N=1, all the Lisp level input reading
> functions, including read-key-sequence, will interpret a single C-g as quit.
>
>> Will it return the input
>>event C-g, or will it quit?  I thought your changes make read-event
>>always return the input event, was I mistaken?
>
> You're asking about the N=1 case.  I'm not proposing that N=1 be the default.
>
> For all values of 1 <= N <= M, I'm specifically proposing:
>
> When inhibit-quit is nil:
>
> #quits in [1,N-1]: event reading functions interpret C-g as an event called
> \?C-g, aka the number 7. They return this event without quit-flag set.
>
> #quits in [N, infinity): event reading functions interpret C-g as
> a quit. They do not return. They end by calling Fsignal with quit
> error symbol.
>
> When inhibit-quit is non-nil:
>
> #quits in [1,N-1]: same as above 
>
> #quits in [N,M-1]: return \?C-g with quit-flag set
>
> #quits in [M, anything): exit nonlocality by calling Fsignal with quit error
> signal, effectively ignoring inhibit-quit. Print a message saying we've
> done so.
>
> If debug-on-quit is set, we enter the debugger when the above table says the word "Fsignal".
>
> If throw-on-input, we raise quit on any input event whatsoever, never
> returning to Lisp, no matter the value of #quits, N, or M.
>
> My proposal, by the way, does not change the meaning of quit-flag.
>
> If you find the above proposal unacceptable, can you please point to
> a specific behavior it encodes and talk about what you'd rather it
> do differently?
>
> Assume we can reliably detect #quits, please. I'm happy to talk about *how*
> we detect repeated C-g, but the mechanism by which we do is independent of
> rhe policy we want.
>
>>> >> We can customize thresholds for general behavior, but I don't think we
>>> >> should not have preferences that alter the operation of fundamental
>>> >> Emacs primitives.  You couldn't add a preference that made if regard 0
>>> >> as well as nil as false, would you? 
>>> >
>>> > Why not?  If it helps debugging, we could definitely do that. 
>
> In the exceedingly rare case that it is important to allow one C-g instead
> of C-g C-g C-g to break out of an read-event or read-key-sequence loop (and
> I have never seen one not deliberately constructed) users can customize N to
> be one. I anticipate exactly zero people going that, but if you want the
> knob, we have it.
>
>> We
>>> > already have --enable-checking, which changes how some primitives
>>> > work, in a very real sense.  
>
> I'm not aware of any interface contracts that checking changes. What might those be?
>
>> As long as the feature is for debugging
>>> > Emacs, anything useful goes, IMO.
>>> 
>>> Because when you add a user option, people expect code you write to
>>> operate under any value of that option, increasing implementation
>>> complexity because you have to account for the _possibility_ someone
>>> might operate in a certain way.
>>
>>No, people need not expect the code to operate the same under those
>>special debugging-oriented values.  We already have such features:
>>debug-on-error = t might well cause some command cease working
>>normally, and similarly condition-case-unless-debug
>
> Because I don't think this debugging mode is needed in any real world
> scenario. Nobody I've seen infloops on read event outside a specially
> crafted scenario.
>
> But if you want the knob to enable it, the knob is there in my proposal. Set
> N=1. If you set N=1, then *both* read-event and read-key-sequence will quit
> the first time you press C-g 
>
>>So I think you are bothered by a problem that doesn't need to be
>>solved.
>>
>>> >> >>> Maybe a compromise would be to continue the arms race and downgrade C-g
>>> >> >>> to normal input, C-g C-g C-g to a quit, and require even more C-g's for
>>> >> >>> a force-quit?
>>> >> >>
>>> >> >> That's also possible, though less desirable: counting C-g presses when
>>> >> >> you are desperate is not easy and we cannot rely on users to do that
>>> >> >> reliably.
>>> >> >
>>> >> > And we'd need a way to detect when a quit is handled (however we define
>>> >> > "handled") so we could reset force_quit_counter.  Not a trivial change.
>>> >> 
>>> >> You don't.  You just upgrade any quit that happens under the N and T
>>> >> threshold above.
>>> >
>>> > I'm skeptical that we will be able to count C-g presses so as to
>>> > reliably differentiate between double or triple press and two or three
>>> > separate C-g presses.
>>> 
>>> There is logically no difference between these two concepts.  A double
>>> keypress *is* two keypresses in a certain window of time.  What other
>>> concept could the combination of the words "double" and "press" convey?
>>
>>I don't understand what you are saying here.  Yes, there's no logical
>>difference between these, which is why I'm saying that reliably
>>detecting "double C-g" is a challenge.  We already have that with
>>double-mouse.  The difference between double-mouse and "double C-g" is
>>that with the latter you cannot afford low reliability: when you want
>>to quit, you want to do it immediately, because the runaway operation
>>you want to interrupt could be harmful.
>
> I'm honestly not sure what reliability problems you're talking about. We
> count the C-g key presses since we last entered the command loop and since
> T milliseconds ago. If you say T to be a month and N=2 then if you're in
> a read-event or read-key-sequence loop, press C-g once, suspend your
> computer for a day, and press C-g again, we'll interpret the second C-g as
> a quit and break out of the loop.
>
> Can you please give me some specific and concrete scenarios you have in mind
> that might clarify these reliability issues you're talking about?
>
>>> > Different machines and OSes, and different
>>> > system loads, can make it nigh impossible to do reliably.  And that's
>>> > _bad_, because when I want something interrupted right away, I don't
>>> > want or even cannot try again and again and again until it works.
>>> 
>>> Then define a separate key that means _only_ quit and that cannot be
>>> bound to a regular command.  C-g can't be that command without breaking
>>> existing code.
>>
>>It's too late to define a separate key _instead_ of C-g.  We could
>>define a separate key _in_addition_ to C-g, but that doesn't solve the
>>problem: people have C-g hardwired into their muscle memory, and it
>>will take a lot of time for them to re-learn.  Meanwhile, we get bug
>>reports about C-g not working like it did before.
>
> No, we didn't get a bug report. We got a specially constructed program that
> exercised a beneficial behavior change and called it a bug. I've yet to see
> a real world problem. The person who constructed that program complained
> that a loop that could be quit before was unquittable now. I am trying to
> explain that it will, in fact, be quittable.
>
>>So minimizing the behavior changes is still a requirement, even if we
>>add another key.  And that's before we even consider what other key
>>could serve that purpose, which is not a trivial problem to solve
>>portably
>
> I'm not talking about adding another quit key. That's not the right
> solution. I don't see a real world scenario in which multiple C-g doesn't
> work well enough, and we have, what, decades of experience with this
> mechanism on TTYs? Why is taking the force quit mechanism, fixing its
> reliability issues, and generalizing it to GUIs suddenly a problem?
>
>>> Treating repeated C-g presses made in a reasonable window of time within
>>> the scope of a single command in such a way that we're almost certainly
>>> not confusing this series of keystrokes with C-g-as-command input solves
>>> the problem.
>>
>>That's possible, but it is not the best alternative IMO, for the
>>reasons I explained.
>
> I've yet to see you propose a different solution. All I've seen is
> resistance to change whether it's beneficial or not.
>
> My proposal allows you to interrupt any Lisp program. In every real world
> scenario, you can interrupt with one C-g. In pathological cases, you can
> interrupt by pressing C-g multiple times. This mechanism is reliable.





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 15:51:05 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 18:50:10 +0300
> Date: Fri, 13 Jun 2025 07:48:54 -0700
> From: Daniel Colascione <dancol <at> dancol.org>
> CC: pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
> 
> On June 13, 2025 7:46:41 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
> >> Date: Fri, 13 Jun 2025 04:49:21 -0700
> >> From: Daniel Colascione <dancol <at> dancol.org>
> >> CC: pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
> >> 
> >> 
> >> 
> >> On June 13, 2025 4:36:42 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
> >> >> From: Daniel Colascione <dancol <at> dancol.org>
> >> >> Cc: Pip Cet <pipcet <at> protonmail.com>,  monnier <at> iro.umontreal.ca,
> >> >>   78737 <at> debbugs.gnu.org
> >> >> Date: Fri, 13 Jun 2025 00:53:38 -0700
> >> >> 
> >> >> > If you are talking about a GUI session, then IME the 'emergency exit"
> >> >> > procedure isn't reliably working in that case, and I'm not sure the
> >> >> > implementation intends to support that.  I always knew that it's only
> >> >> > reliably working on TTY frames.
> >> >> >
> >> >> > Or are you talking about the effect of the changes on the branch?
> >> >> 
> >> >> FWIW, the purpose of my N-times-in-T-milliseconds-within-one-command
> >> >> formulation of emergency exit is to get the mechanism working reliably
> >> >> in all cases.
> >> >> 
> >> >> I can definitely type 4-5 C-gs in a GUI Emacs (well, NS, but I recall
> >> >> PGTK being similar?) and not have Emacs quit.  If I mash C-g, it
> >> >> sometimes does, and sometimes doesn't.
> >> >> 
> >> >> Right now, the logic is this:
> >> >> 
> >> >>     {
> >> >>       /* Request quit when it's safe.  */
> >> >>       int count = NILP (Vquit_flag) ? 1 : force_quit_count + 1;
> >> >>       force_quit_count = count;
> >> >>       if (count == 3)
> >> >> 	Vinhibit_quit = Qnil;
> >> >>       Vquit_flag = Qt;
> >> >>     }
> >> >> 
> >> >> IOW, the first quit after clearing Vquit_flag resets the count to one.
> >> >> Maybe that's why it isn't working reliably right now.  If we reformulate
> >> >> this mechanism not in terms of count == 3 (which is fiddly for all sorts
> >> >> of reasons, since Vquit_flag can get reset) but in terms of the UX
> >> >> directly --- N recent quits in T time in a single command --- we make
> >> >> the whole thing more reliable.
> >> >> 
> >> >> If you set T=infinity and N=3, you get the current force quit UX (modulo
> >> >> my upgrade-before-disabling-inhibit-quit thing), just more reliably, and
> >> >> you can break out of arbitrary Lisp code.
> >> >
> >> >I suggest to leave the emergency exit feature alone for now, and focus
> >> >on the interruptibility of Lisp programs.
> >> 
> >> That *is* the interruptabiltity of Lisp programs.l
> >
> >No, not in my book.  A Lisp program should be interruptible without
> >killing the Emacs session.  "Emergency exit", OTOH, kills the Emacs
> >session.
> 
> Maybe we're talking past each other? I'm not proposing anything that automatically kills Emacs. I'm not sure what would have given you the impression we were talking about killing Emacs.

I was talking about "emergency exit", and you responded to that,
that's what gave me the impression.  Emergency exit, as its name
implies, exist the Emacs session.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 15:59:05 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 08:55:08 -0700
On June 13, 2025 8:50:10 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
>> Date: Fri, 13 Jun 2025 07:48:54 -0700
>> From: Daniel Colascione <dancol <at> dancol.org>
>> CC: pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
>> 
>> On June 13, 2025 7:46:41 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
>> >> Date: Fri, 13 Jun 2025 04:49:21 -0700
>> >> From: Daniel Colascione <dancol <at> dancol.org>
>> >> CC: pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
>> >> 
>> >> 
>> >> 
>> >> On June 13, 2025 4:36:42 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
>> >> >> From: Daniel Colascione <dancol <at> dancol.org>
>> >> >> Cc: Pip Cet <pipcet <at> protonmail.com>,  monnier <at> iro.umontreal.ca,
>> >> >>   78737 <at> debbugs.gnu.org
>> >> >> Date: Fri, 13 Jun 2025 00:53:38 -0700
>> >> >> 
>> >> >> > If you are talking about a GUI session, then IME the 'emergency exit"
>> >> >> > procedure isn't reliably working in that case, and I'm not sure the
>> >> >> > implementation intends to support that.  I always knew that it's only
>> >> >> > reliably working on TTY frames.
>> >> >> >
>> >> >> > Or are you talking about the effect of the changes on the branch?
>> >> >> 
>> >> >> FWIW, the purpose of my N-times-in-T-milliseconds-within-one-command
>> >> >> formulation of emergency exit is to get the mechanism working reliably
>> >> >> in all cases.
>> >> >> 
>> >> >> I can definitely type 4-5 C-gs in a GUI Emacs (well, NS, but I recall
>> >> >> PGTK being similar?) and not have Emacs quit.  If I mash C-g, it
>> >> >> sometimes does, and sometimes doesn't.
>> >> >> 
>> >> >> Right now, the logic is this:
>> >> >> 
>> >> >>     {
>> >> >>       /* Request quit when it's safe.  */
>> >> >>       int count = NILP (Vquit_flag) ? 1 : force_quit_count + 1;
>> >> >>       force_quit_count = count;
>> >> >>       if (count == 3)
>> >> >> 	Vinhibit_quit = Qnil;
>> >> >>       Vquit_flag = Qt;
>> >> >>     }
>> >> >> 
>> >> >> IOW, the first quit after clearing Vquit_flag resets the count to one.
>> >> >> Maybe that's why it isn't working reliably right now.  If we reformulate
>> >> >> this mechanism not in terms of count == 3 (which is fiddly for all sorts
>> >> >> of reasons, since Vquit_flag can get reset) but in terms of the UX
>> >> >> directly --- N recent quits in T time in a single command --- we make
>> >> >> the whole thing more reliable.
>> >> >> 
>> >> >> If you set T=infinity and N=3, you get the current force quit UX (modulo
>> >> >> my upgrade-before-disabling-inhibit-quit thing), just more reliably, and
>> >> >> you can break out of arbitrary Lisp code.
>> >> >
>> >> >I suggest to leave the emergency exit feature alone for now, and focus
>> >> >on the interruptibility of Lisp programs.
>> >> 
>> >> That *is* the interruptabiltity of Lisp programs.l
>> >
>> >No, not in my book.  A Lisp program should be interruptible without
>> >killing the Emacs session.  "Emergency exit", OTOH, kills the Emacs
>> >session.
>> 
>> Maybe we're talking past each other? I'm not proposing anything that automatically kills Emacs. I'm not sure what would have given you the impression we were talking about killing Emacs.
>
>I was talking about "emergency exit", and you responded to that,
>that's what gave me the impression.  Emergency exit, as its name
>implies, exist the Emacs session.


Ah, I was reading it as exiting the *current operation* and returning to the command loop --- a synonym for emergency quit. 
I




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 16:04:02 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, dancol <at> dancol.org
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 19:03:21 +0300
> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
> Cc: Daniel Colascione <dancol <at> dancol.org>,  78737 <at> debbugs.gnu.org,  Eli
>  Zaretskii <eliz <at> gnu.org>
> Date: Fri, 13 Jun 2025 10:51:37 -0400
> 
> > Making
> >
> >     (while t (read-event))
> >
> > infloop without being able to quit is a bad idea.  We shouldn't do it.
> 
> I don't find this terribly problematic, If you think of what that loop
> means it *is* a "please shoot me in the foot" kind of thing.
> 
> I agree that not being able to escape is a problem, but it's not the
> only way to get into such trouble.  IOW I think it just gets us back to
> the fact that we need an "emergency quit" for bugs (which `kill -USR2`
> can sometimes provide, tho it's not a quit per-se).

What I asked, and still didn't get an answer to, is at what point does
a program that calls read-event becomes interruptible by a single C-g,
after the changes on the branch?  The above loop is not interruptible,
but Daniel says that his proposal allows interrupting Lisp programs,
just not silly programs such as the one above.  So if we start from
the above silly program, and add to it some meaningful processing of
the event read by read-event, at what point does such a program become
interruptible by a single C-g?

Later responses by Daniel seem to indicate that the answer is "never".
It seems like his proposal is to change the behavior of C-g such that
to interrupt a Lisp program the user will need two or more C-g presses
(with the number customizable) during some predefine time interval.
Is that understanding correct?  If it is, then what will a single C-g
produce? will it _never_ cause a quit?

If my understanding above is correct, then this is a significant
change in behavior, and it is not yet implemented on the branch.  I
would suggest to discuss this change in behavior on emacs-devel before
we decide to make the change (perhaps even before it is implemented,
to prevent waste of development efforts in case the proposal is voted
down).

Whether we need an "emergency quit" (whatever that means) is a
related, but separate question.  Currently, what we have is the
"emergency exit", which doesn't quit, but kills the session (with or
without a core dump), and IME it doesn't work reliably in GUI
sessions.  Again, this is IMO a separate feature and a separate
discussion.  The discussion about what a single C-g does and how to
interrupt Lisp programs using C-g is much more important and therefore
much more complicated.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 16:06:03 GMT) Full text and rfc822 format available.

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

From: Pip Cet <pipcet <at> protonmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 Daniel Colascione <dancol <at> dancol.org>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 16:04:41 +0000
"Stefan Monnier" <monnier <at> iro.umontreal.ca> writes:

>> -    ;; FIXME: we should not read-event here at all, because it's much too
>> -    ;; difficult to reliably "undo" a read-event by pushing it onto
>> -    ;; unread-command-events.
>> -    ;; For bug#14782, we need read-event to do the keyboard-coding-system
>> -    ;; decoding (hence non-nil as second arg under POSIX ttys).
>> -    ;; For bug#15614, we need read-event not to inherit-input-method.
>> -    ;; So we temporarily suspend input-method-function.
>> -    (let ((read (let ((input-method-function nil))
>> -                  (read-event nil t seconds))))
>> -      (or (null read)
>> -	  (progn
>> -            ;; https://lists.gnu.org/r/emacs-devel/2006-10/msg00394.html
>> -            ;; We want `read' appear in the next command's this-command-event
>> -            ;; but not in the current one.
>> -            ;; By pushing (cons t read), we indicate that `read' has not
>> -            ;; yet been recorded in this-command-keys, so it will be recorded
>> -            ;; next time it's read.
>> -            ;; And indeed the `seconds' argument to read-event correctly
>> -            ;; prevented recording this event in the current command's
>> -            ;; this-command-keys.
>> -	    (push (cons t read) unread-command-events)
>> -	    nil))))))
>> +    (not (if throw-on-input
>> +             (sleep-for seconds)
>> +           (while-no-input (sleep-for seconds)))))))
>
> I'm not sure this will wake up on the same events (i.e. whether its
> notion of what is "not a real input event" is the same).  `sit-for` has
> seen several iterations because of "corner cases", so I wouldn't be
> surprised to bump into regressions, but I agree that it would be nice to
> "align" the notion of "relevant" events used by `sit-for` with that used
> by `while-no-input`.
> [ IIRC part of the differences are the events handled by
>   `special-event-map`.  ]
>
> Note also that I'm not sure `sleep-for` will actually do what we want
> here (does it run process filters and timers?  And update the display
> accordingly?).

You're right, there are differences (such as the hourglass displaying in
one case but not the other, it seems).  No obvious way to call
wait_reading_process_output with precisely the right parameters.  Let's
drop this one for now.

Inhibit-quit and quitting before rather than after removing an event
from the queue should still both fix the original problem, if that's
what we decide to do for now.

Pip





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 16:12:06 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>, pipcet <at> protonmail.com
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 12:10:55 -0400
>>Maybe `kill -USR2` would work better? 
> Thanks for reminding me to mention SIGUSR2. We'll treat it like #quits >= M.

USR2 is used to jump into the debugger (from which we can jump back to
top-level if we want), so it's only like `quit` in the sens of
`debug-on-quit` but not in terms of exiting the current execution.

> That's what I'm proposing.

[ Yeah, I read that later.  Thanks.  ]


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 16:15:10 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Eli Zaretskii <eliz <at> gnu.org>, Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 09:14:20 -0700
On June 13, 2025 9:03:21 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
>> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
>> Cc: Daniel Colascione <dancol <at> dancol.org>,  78737 <at> debbugs.gnu.org,  Eli
>>  Zaretskii <eliz <at> gnu.org>
>> Date: Fri, 13 Jun 2025 10:51:37 -0400
>> 
>> > Making
>> >
>> >     (while t (read-event))
>> >
>> > infloop without being able to quit is a bad idea.  We shouldn't do it.
>> 
>> I don't find this terribly problematic, If you think of what that loop
>> means it *is* a "please shoot me in the foot" kind of thing.
>> 
>> I agree that not being able to escape is a problem, but it's not the
>> only way to get into such trouble.  IOW I think it just gets us back to
>> the fact that we need an "emergency quit" for bugs (which `kill -USR2`
>> can sometimes provide, tho it's not a quit per-se).
>
>What I asked, and still didn't get an answer to, is at what point does

I believe I answered your question at length in <https://lists.gnu.org/archive/html/bug-gnu-emacs/2025-06/msg00678.html> and specifically addressed the question above. I believe I'd addressed the subject several times before as well.

Could you please take a look at the proposal before declaring these questions unanswered?

>a program that calls read-event becomes interruptible by a single C-g,
>after the changes on the branch?  The above loop is not interruptible,
>but Daniel says that his proposal allows interrupting Lisp programs,
>just not silly programs such as the one above.  So if we start from
>the above silly program, and add to it some meaningful processing of
>the event read by read-event, at what point does such a program become
>interruptible by a single C-g?
>
>Later responses by Daniel seem to indicate that the answer is "never".
>It seems like his proposal is to change the behavior of C-g such that
>to interrupt a Lisp program the user will need two or more C-g presses
>(with the number customizable) during some predefine time interval.
>Is that understanding correct?

No, that is not correct, and I've said so many times. I'm not sure what I could say to increase clarity.

Outside contrived corner cases, the only difference users will notice is that quitting works more reliably.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 16:19:03 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, dancol <at> dancol.org
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 12:18:03 -0400
> What I asked, and still didn't get an answer to, is at what point does
> a program that calls read-event becomes interruptible by a single C-g,
> after the changes on the branch?

It's interrupted if the `C-g` occurs while running the code rather than
while sitting inside `read-event`.  For the tight `while t` loop, it's
virtually never.


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 16:23:04 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>, Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 09:22:21 -0700
On June 13, 2025 9:18:03 AM PDT, Stefan Monnier <monnier <at> iro.umontreal.ca> wrote:
>> What I asked, and still didn't get an answer to, is at what point does
>> a program that calls read-event becomes interruptible by a single C-g,
>> after the changes on the branch?
>
>It's interrupted if the `C-g` occurs while running the code rather than
>while sitting inside `read-event`.  For the tight `while t` loop, it's
>virtually never.

For clarity's sake, Stefan is describing what's in the branch right now and I'm describing what will be on the branch before it's ready for merging.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 17:34:04 GMT) Full text and rfc822 format available.

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

From: Pip Cet <pipcet <at> protonmail.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, dancol <at> dancol.org,
 Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 17:33:33 +0000
"Eli Zaretskii" <eliz <at> gnu.org> writes:
> Whether we need an "emergency quit" (whatever that means) is a
> related, but separate question.  Currently, what we have is the
> "emergency exit", which doesn't quit, but kills the session (with or
> without a core dump), and IME it doesn't work reliably in GUI
> sessions.

I think the behavior of C-g C-g C-g is, as you describe, very different
in GUI-only sessions and in sessions with a terminal frame: if there is
a terminal frame, we offer to auto-save and kill the session (there is
an option to continue the session, but I don't know whether it works);
if there isn't, we set inhibit-quit to nil and quit-flag to t and hope
for the best.  (This description simplifies things somewhat;
handle_interrupt has the gory details).

We don't even tell the user that if we modified inhibit-quit, there is a
significant risk they just destroyed their session and that they have to
restart Emacs.  On the other hand, many places assume inhibit-quit
doesn't change under them and don't react to such changes, so a C-g C-g
C-g may do nothing; in this case, you usually don't get a second chance
because of the force_quit_count > 3 behavior.

> Again, this is IMO a separate feature and a separate discussion.  The
> discussion about what a single C-g does and how to interrupt Lisp
> programs using C-g is much more important and therefore much more
> complicated.

I think both discussions are important, but they depend on each other in
this way:

I think improving C-g C-g C-g, a lot, is necessary *before* we put more
blank bullets into C-g than there already are.  In fact, it may be
easier to think of it as replacing it by something somewhere between the
current C-g and the current C-g C-g C-g.

My suggestion is (Someone Else) coming up with a proposal for a good
"C-g C-g" (which might involve a different key sequence entirely),
implementing it, and then, only then, can we decide whether Daniel is
right and single C-g should become a normal input event in more
(Daniel's proposal) or all (my modification; this is not what Daniel
proposed) situations.  Or maybe we want to put the genie back in the
bottle and make C-g mean "quit" again, in almost all situations, such as
in transient mode.

If C-g C-g (or the same functionality by any other name) works and works
well, should we really let our muscle memory of using a single C-g for
quit stand in the way of more consistent behavior, freeing C-g for
ordinary use (it'd still mean something quit-like, a polite warning that
you're about to hit C-g a second time)?

We could even think of it as a way in which Emacs stabilized beyond the
need for a two-keystroke quit key.

But, right now, we can't reliably use C-g to quit Lisp programs; we
can't reliably use C-g C-g C-g either; we can't *safely* use C-g C-g C-g
either; and we can't use C-g as an ordinary input event with perfect
safety (but we have code which, essentially, assumes CPUs are so fast
now that we can get away with it in practice).

(That last one may be fixable, and it needs fixing for the MPS branch.)

Pip





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 17:35:05 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, dancol <at> dancol.org
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 20:33:59 +0300
> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
> Cc: Daniel Colascione <dancol <at> dancol.org>,  78737 <at> debbugs.gnu.org,
>   pipcet <at> protonmail.com
> Date: Fri, 13 Jun 2025 11:09:33 -0400
> 
> > Specifically, what I'm interested in is how come
> >
> >  (while t
> >    (read-event))
> >
> > cannot be interrupted by C-g, but you seem to be saying that
> >
> >  (while t
> >    (let (evt (read-event))
> >      (do-something-with evt)))
> >
> > _can_ be interrupted?
> 
> Usually the `(do-something-with evt)` part will offer some way to end
> the loop.

How?  If read-event returns the character 7, then the information
about the fact that C-g was typed is lost by the time we get to the
do-something-with part, no?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 17:39:01 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, dancol <at> dancol.org
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 20:38:06 +0300
> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
> Cc: Daniel Colascione <dancol <at> dancol.org>,  78737 <at> debbugs.gnu.org,
>   pipcet <at> protonmail.com
> Date: Fri, 13 Jun 2025 11:24:29 -0400
> 
> > We should start by agreeing that the capability of interrupting a
> > running Lisp program is a real need.  Are we in agreement about that?
> > If not, let's first hear the arguments why not.
> 
> It's a real need, but there's also a real need for some ELisp functions
> to catch normal quits.  So we can't have "normal quits" as the universal
> answer to "interrupting a running Lisp program".

What is a "normal quit"?  And what other kinds of quit are there, and
what are they?

It sounds like not only do we disagree about some aspects of this, we
don't even have a common terminology.

> What we have instead is that "normal quit" should work to interrupt any
> well-behaved ELisp programs, plus it should also work to interrupt most
> other ELisp programs (IOW it shouldn't be hard to write well-behaved
> ELisp code), but there has always been and will always be cases where we
> need an "emergency quit" to interrupt some ELisp programs (and that
> feature has been missing in GUI builds for a while).

What is "emergency quit"?

And if you are describing the current situation on the master branch,
then the changes proposed on the branch still leave some programs not
interruptible, just a few more.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 17:48:01 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 20:47:43 +0300
> Date: Fri, 13 Jun 2025 09:14:20 -0700
> From: Daniel Colascione <dancol <at> dancol.org>
> CC: pipcet <at> protonmail.com, 78737 <at> debbugs.gnu.org
> 
> On June 13, 2025 9:03:21 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
> >> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
> >> Cc: Daniel Colascione <dancol <at> dancol.org>,  78737 <at> debbugs.gnu.org,  Eli
> >>  Zaretskii <eliz <at> gnu.org>
> >> Date: Fri, 13 Jun 2025 10:51:37 -0400
> >> 
> >> > Making
> >> >
> >> >     (while t (read-event))
> >> >
> >> > infloop without being able to quit is a bad idea.  We shouldn't do it.
> >> 
> >> I don't find this terribly problematic, If you think of what that loop
> >> means it *is* a "please shoot me in the foot" kind of thing.
> >> 
> >> I agree that not being able to escape is a problem, but it's not the
> >> only way to get into such trouble.  IOW I think it just gets us back to
> >> the fact that we need an "emergency quit" for bugs (which `kill -USR2`
> >> can sometimes provide, tho it's not a quit per-se).
> >
> >What I asked, and still didn't get an answer to, is at what point does
> 
> I believe I answered your question at length in <https://lists.gnu.org/archive/html/bug-gnu-emacs/2025-06/msg00678.html> and specifically addressed the question above. I believe I'd addressed the subject several times before as well.
> 
> Could you please take a look at the proposal before declaring these questions unanswered?

I did.

My current understanding is that what you propose will cause some
(most) programs to be interruptible with a single C-g, while some (in
particular those which call read-event) will need two or more C-g to
be interrupted.  Is that correct?

If this is correct, then we need to decide whether this inconsistency
(one C-g vs several) is tolerable.

> >Later responses by Daniel seem to indicate that the answer is "never".
> >It seems like his proposal is to change the behavior of C-g such that
> >to interrupt a Lisp program the user will need two or more C-g presses
> >(with the number customizable) during some predefine time interval.
> >Is that understanding correct?
> 
> No, that is not correct, and I've said so many times. I'm not sure what I could say to increase clarity.

Is the modified description above correct?  If not, what is incorrect
in it?

> Outside contrived corner cases, the only difference users will notice is that quitting works more reliably.

Thanks, but that doesn't answer my question, which is specifically
about the effect of C-g on Lisp programs, whether they call read-event
or don't call it.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 17:50:06 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 20:48:49 +0300
> Date: Fri, 13 Jun 2025 09:22:21 -0700
> From: Daniel Colascione <dancol <at> dancol.org>
> CC: pipcet <at> protonmail.com, 78737 <at> debbugs.gnu.org
> 
> On June 13, 2025 9:18:03 AM PDT, Stefan Monnier <monnier <at> iro.umontreal.ca> wrote:
> >> What I asked, and still didn't get an answer to, is at what point does
> >> a program that calls read-event becomes interruptible by a single C-g,
> >> after the changes on the branch?
> >
> >It's interrupted if the `C-g` occurs while running the code rather than
> >while sitting inside `read-event`.  For the tight `while t` loop, it's
> >virtually never.
> 
> For clarity's sake, Stefan is describing what's in the branch right now and I'm describing what will be on the branch before it's ready for merging.

And my question was bout the latter, not the former.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 18:01:04 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>, pipcet <at> protonmail.com
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 14:00:31 -0400
>>> What I asked, and still didn't get an answer to, is at what point does
>>> a program that calls read-event becomes interruptible by a single C-g,
>>> after the changes on the branch?
>>It's interrupted if the `C-g` occurs while running the code rather than
>>while sitting inside `read-event`.  For the tight `while t` loop, it's
>>virtually never.
> For clarity's sake, Stefan is describing what's in the branch right now and
> I'm describing what will be on the branch before it's ready for merging.

I thought the difference was only in terms of "emergency quit", which
I think is not what Eli referred to when he meant "interruptible".
[ I suspect these kinds of differences of intended meaning are
a significant part of the misunderstandings in this thread.  ]


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 18:08:02 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com,
 Daniel Colascione <dancol <at> dancol.org>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 14:07:20 -0400
> My current understanding is that what you propose will cause some
> (most) programs to be interruptible with a single C-g, while some (in
> particular those which call read-event) will need two or more C-g to
> be interrupted.  Is that correct?

I think so, tho only for *some* of those which call `read-event`.

> If this is correct, then we need to decide whether this inconsistency
> (one C-g vs several) is tolerable.

That inconsistency already exists in various places, such as if you use
`read-key`.  I think what we need to decide is if the resulting overall
behavior is better (e.g. easier to describe and less error prone), and
if so, whether it's worth the incompatibility.

Of course, we could also make the change more backward-compatible by
renaming `read-event` to some new name and (re)defining `read-event` on
top of that new function.


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 18:15:07 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, dancol <at> dancol.org
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 14:14:44 -0400
>> >  (while t
>> >    (let (evt (read-event))
>> >      (do-something-with evt)))
>> >
>> > _can_ be interrupted?
>> 
>> Usually the `(do-something-with evt)` part will offer some way to end
>> the loop.
>
> How?  If read-event returns the character 7, then the information
> about the fact that C-g was typed is lost by the time we get to the
> do-something-with part, no?

AFAIK that information is in `evt` and hence not lost.
Usually `do-something-with` will look at `evt` and do various things
depending on the key that was pressed and usually one of those options
lets you end what you were doing.

Some code may assume they don't need to explicitly abort when `evt` is
7 because they rely on the current behavior of `read-event`, but AFAIK
that behavior is not completely reliable (e.g. it depends on
`inhibit-quit` and sometimes timing), so if we want to encourage use of
that feature we should try and make it more reliable.


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 18:17:02 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, dancol <at> dancol.org
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 14:16:08 -0400
> What is a "normal quit"?

A single C-g.

> What is "emergency quit"?

Something like `C-g C-g C-g`, tho we don't have that implemented,
currently, AFAIK.


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 18:18:01 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, dancol <at> dancol.org
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 14:17:01 -0400
>> What is "emergency quit"?
> Something like `C-g C-g C-g`, tho we don't have that implemented,
> currently, AFAIK.

I guess `kill -USR2` could count as well.


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 18:26:02 GMT) Full text and rfc822 format available.

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

From: Pip Cet <pipcet <at> protonmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>, dancol <at> dancol.org
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 18:25:13 +0000
"Stefan Monnier" <monnier <at> iro.umontreal.ca> writes:

>> What is a "normal quit"?
>
> A single C-g.
>
>> What is "emergency quit"?
>
> Something like `C-g C-g C-g`, tho we don't have that implemented,
> currently, AFAIK.

It's implemented.  See handle_interrupt in keyboard.c:

      /* Request quit when it's safe.  */
      int count = NILP (Vquit_flag) ? 1 : force_quit_count + 1;
      force_quit_count = count;
      if (count == 3)
	Vinhibit_quit = Qnil;
      Vquit_flag = Qt;

The "emergency" part is clearing the inhibit-quit flag when
force_quit_count reaches 3.  The bug is that it should be >= 3, and the
questionable design feature is that we should reset the counter if
Vquit_flag and Vinhibit_quit are both nil, not just based on Vquit_flag.

However, there's also the rest of handle_interrupt, which applies to
terminal sessions and takes them through an interactive text adventure
which never clears Vinhibit_quit.

Pip





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 18:39:05 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 14:38:22 -0400
On June 13, 2025 1:47:43 PM EDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
>> Date: Fri, 13 Jun 2025 09:14:20 -0700
>> From: Daniel Colascione <dancol <at> dancol.org>
>> CC: pipcet <at> protonmail.com, 78737 <at> debbugs.gnu.org
>> 
>> On June 13, 2025 9:03:21 AM PDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
>> >> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
>> >> Cc: Daniel Colascione <dancol <at> dancol.org>,  78737 <at> debbugs.gnu.org,  Eli
>> >>  Zaretskii <eliz <at> gnu.org>
>> >> Date: Fri, 13 Jun 2025 10:51:37 -0400
>> >> 
>> >> > Making
>> >> >
>> >> >     (while t (read-event))
>> >> >
>> >> > infloop without being able to quit is a bad idea.  We shouldn't do it.
>> >> 
>> >> I don't find this terribly problematic, If you think of what that loop
>> >> means it *is* a "please shoot me in the foot" kind of thing.
>> >> 
>> >> I agree that not being able to escape is a problem, but it's not the
>> >> only way to get into such trouble.  IOW I think it just gets us back to
>> >> the fact that we need an "emergency quit" for bugs (which `kill -USR2`
>> >> can sometimes provide, tho it's not a quit per-se).
>> >
>> >What I asked, and still didn't get an answer to, is at what point does
>> 
>> I believe I answered your question at length in <https://lists.gnu.org/archive/html/bug-gnu-emacs/2025-06/msg00678.html> and specifically addressed the question above. I believe I'd addressed the subject several times before as well.
>> 
>> Could you please take a look at the proposal before declaring these questions unanswered?
>
>I did.
>
>My current understanding is that what you propose will cause some
>(most) programs to be interruptible with a single C-g, while some (in
>particular those which call read-event) will need two or more C-g to
>be interrupted.  Is that correct?

Yes.

However, it looks right now like the class of program that has to be quit with a repeated C-g is extremely small. I've seen only contrived examples so far.  Most programs do something with the result of calling read-event, and when they see C-g, either break out of their dispatch loop or do a C-g appropriate thing.

Things using low level input events like that, however, tend to be either old or specialized.

The most common code paths (e.g. isearch, transient, map-y-or-n-p, etc.) with dispatch loops already use higher level tools like read-key, read-char-from-minibuffer, or transient keymaps and so get C-g handled as an input event anyway.

Has anyone complained that (while t (read-key)) doesn't admit keyboard quitting?

In practice, based on experience so far, there's no practical need to press C-g any more often than one does on mainline.

>If this is correct, then we need to decide whether this inconsistency
>(one C-g vs several) is tolerable.

I think it's correct only in theory. Maybe I'm wrong and there's some undiscovered case that this breaks. It's to discover these cases that it would be nice to test the branch and merge it to mainline. We can always put it behind a feature flag.

>> >Later responses by Daniel seem to indicate that the answer is "never".
>> >It seems like his proposal is to change the behavior of C-g such that
>> >to interrupt a Lisp program the user will need two or more C-g presses
>> >(with the number customizable) during some predefine time interval.
>> >Is that understanding correct?
>> 
>> No, that is not correct, and I've said so many times. I'm not sure what I could say to increase clarity.
>
>Is the modified description above correct?  If not, what is incorrect
>in it?
>
>> Outside contrived corner cases, the only difference users will notice is that quitting works more reliably.
>
>Thanks, but that doesn't answer my question, which is specifically
>about the effect of C-g on Lisp programs, whether they call read-event
>or don't call it.

Lisp programs that don't call read-event, read-char, or read-char-exclusive don't see a change in behavior except for how, once we implement the repeated C-g work, users will be able to break out of loops like (while t (read-key)) by pressing C-g multiple times.

I have yet to see a real program that does something like this, much less one that depends on bricking quit functionality in the user's Emacs session.

Lisp programs that do call these low level functions see a contract change, as I detailed in my previous messages.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 18:46:05 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>, Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 14:43:54 -0400
On June 13, 2025 2:14:44 PM EDT, Stefan Monnier <monnier <at> iro.umontreal.ca> wrote:
>>> >  (while t
>>> >    (let (evt (read-event))
>>> >      (do-something-with evt)))
>>> >
>>> > _can_ be interrupted?
>>> 
>>> Usually the `(do-something-with evt)` part will offer some way to end
>>> the loop.
>>
>> How?  If read-event returns the character 7, then the information
>> about the fact that C-g was typed is lost by the time we get to the
>> do-something-with part, no?
>
>AFAIK that information is in `evt` and hence not lost.
>Usually `do-something-with` will look at `evt` and do various things
>depending on the key that was pressed and usually one of those options
>lets you end what you were doing.
>
>Some code may assume they don't need to explicitly abort when `evt` is
>7 because they rely on the current behavior of `read-event`, but AFAIK
>that behavior is not completely reliable (e.g. it depends on

Yes. It's not reliable today. An example I gave earlier: on master, putting C-g into unread-command-events makes the next read-event  return 7, not signal quit.

>`inhibit-quit` and sometimes timing), so if we want to encourage use of
>that feature we should try and make it more reliable.

We should steer developers away from read-char and towards higher level features like read-key anyway, right?





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 18:46:09 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Pip Cet <pipcet <at> protonmail.com>, Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 14:45:26 -0400
On June 13, 2025 2:25:13 PM EDT, Pip Cet <pipcet <at> protonmail.com> wrote:
>"Stefan Monnier" <monnier <at> iro.umontreal.ca> writes:
>
>>> What is a "normal quit"?
>>
>> A single C-g.
>>
>>> What is "emergency quit"?
>>
>> Something like `C-g C-g C-g`, tho we don't have that implemented,
>> currently, AFAIK.
>
>It's implemented.  See handle_interrupt in keyboard.c:
>
>      /* Request quit when it's safe.  */
>      int count = NILP (Vquit_flag) ? 1 : force_quit_count + 1;
>      force_quit_count = count;
>      if (count == 3)
>	Vinhibit_quit = Qnil;
>      Vquit_flag = Qt;
>
>The "emergency" part is clearing the inhibit-quit flag when
>force_quit_count reaches 3.  The bug is that it should be >= 3, and the
>questionable design feature is that we should reset the counter if
>Vquit_flag and Vinhibit_quit are both nil, not just based on Vquit_flag.
>
>However, there's also the rest of handle_interrupt, which applies to
>terminal sessions and takes them through an interactive text adventure
>which never clears Vinhibit_quit.

Yes. We need something like the force quit code you posted in spirit, but I don't think that's the right implementation because it's too easy to prematurely clear the quit flag.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 18:52:01 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>, pipcet <at> protonmail.com
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 14:51:08 -0400
On June 13, 2025 2:00:31 PM EDT, Stefan Monnier <monnier <at> iro.umontreal.ca> wrote:
>>>> What I asked, and still didn't get an answer to, is at what point does
>>>> a program that calls read-event becomes interruptible by a single C-g,
>>>> after the changes on the branch?
>>>It's interrupted if the `C-g` occurs while running the code rather than
>>>while sitting inside `read-event`.  For the tight `while t` loop, it's
>>>virtually never.
>> For clarity's sake, Stefan is describing what's in the branch right now and
>> I'm describing what will be on the branch before it's ready for merging.
>
>I thought the difference was only in terms of "emergency quit", which
>I think is not what Eli referred to when he meant "interruptible".

To be clear, when I say that a Lisp form is interruptible, I mean that it is *possible* to break out of it using enough C-g presses.  For example, this code, which is not interruptible at all in current master,

(while t (read-key))

becomes interruptible, the way I'm defining it, when you press C-g >= N times.

This code is interruptible on both master and in my proposal:

(while t (read-event))

However, on master, you need only one C-g to interrupt it. In the idea we're discussing, you need N (so 2 or 3 or whatever we set N to).

That might seem like a disadvantage of a UI change, but it isn't really because loops like the above don't occur in practice.

>[ I suspect these kinds of differences of intended meaning are
>a significant part of the misunderstandings in this thread.  ]

Yes. I think there's quite a bit of talking past each other.

>
>
>        Stefan
>





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 19:09:02 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>, Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 15:07:51 -0400
On June 13, 2025 2:16:08 PM EDT, Stefan Monnier <monnier <at> iro.umontreal.ca> wrote:
>> What is a "normal quit"?
>
>A single C-g.
>
>> What is "emergency quit"?
>
>Something like `C-g C-g C-g`, tho we don't have that implemented,
>currently, AFAIK.


How about this terminology?

C-g --- normal quit

C-g C-g C-g --- urgent quit (breaks out of read-event. should probably break out of redisplay too?)

C-g C-g C-g C-g C-g C-g --- emergency quit. ignores inhibit-quit. good chance of horking your Emacs by violating atomicity assumptions. Display "are you sure?" message before final C-g.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Fri, 13 Jun 2025 21:57:05 GMT) Full text and rfc822 format available.

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

From: Lynn Winebarger <owinebar <at> gmail.com>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 Pip Cet <pipcet <at> protonmail.com>, Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Fri, 13 Jun 2025 17:55:49 -0400
On Fri, Jun 13, 2025 at 10:02 AM Daniel Colascione <dancol <at> dancol.org> wrote:
>
>
>
> On June 13, 2025 6:42:58 AM PDT, Daniel Colascione <dancol <at> dancol.org> wrote:
> >
> >
> >On June 13, 2025 5:23:34 AM PDT, Lynn Winebarger <owinebar <at> gmail.com> wrote:
> >>On Fri, Jun 13, 2025, 2:26 AM Eli Zaretskii <eliz <at> gnu.org> wrote:
> >>
> >>> > From: Daniel Colascione <dancol <at> dancol.org>
> >>> > Cc: Eli Zaretskii <eliz <at> gnu.org>,  monnier <at> iro.umontreal.ca,
> >>> >   78737 <at> debbugs.gnu.org
> >>> > Date: Thu, 12 Jun 2025 11:48:50 -0700
> >>> >
> >>> > Pip Cet <pipcet <at> protonmail.com> writes:
> >>> >
> >>> > > I'd like read-event, when called while inhibit-quit is t, to report
> >>> > > quits by setting quit-flag in addition to returning quit_char: it'll
> >>> > > simplify the C code, and it would make
> >>> > >
> >>> > > (while t
> >>> > >   (let ((inhibit-quit t))
> >>> > >     (read-event)))
> >>> >
> >>> > I strongly disagree.  read-event should read an event.
> >>> > Setting quit-flag by side effect when it happens to read one key and not
> >>> > others makes the interface less regular and understandable.
> >>>
> >>> We should start by agreeing that the capability of interrupting a
> >>> running Lisp program is a real need.  Are we in agreement about that?
> >>> If not, let's first hear the arguments why not.
> >>>
> >>> If we _are_ in agreement about that, we should discuss how this should
> >>> be possible if read-event (and perhaps others?) return C-g instead of
> >>> raising quit-flag.  The alternatives mentioned until now are:
> >>>
> >>>  . restore the old behavior, whereby C-g interrupts read-event
> >>>  . have a variable that, if set, will restore the old behavior in
> >>>    read-event and other affected primitives, to be interruptible by a
> >>>    single C-g
> >>>  . make two C-g presses "in quick succession" set quit-flag, IOW
> >>>    "C-g C-g" will have the same effect as C-g previously
> >>>
> >>> Are there other alternatives?
> >>>
> >>
> >>What about keeping a (possibly buffer-local?) lisp variable holding a list
> >>of keystrokes mapped to thunks that are treated as generating lisp machine
> >>"interrupts"?  The key strokes would be processed by C machinery and never
> >>seen directly by lisp code and not be considered "events".
> >>Then C-g could be bound to a thunk signalling quit, and the effect of
> >>"inhibit-quit" achieved by removing C-g from the list in a given dynamic
> >>scope.  Then user code could make other key-strokes "special" without
> >>resorting to read-event.  For example, this read-event call in term.el:
> >>(message "Hit space to flush")
> >>      (let ((ch (read-event)))
> >> (if (eq ch ?\s)
> >>     (set-window-configuration conf)
> >>   (push ch unread-command-events)))
> >>
> >>Could be replaced by something like
> >>(with-interrupts ((?\s (signal term-flush)))
> >>  (condition-case nil
> >>    (while t (sit-for 100))
> >>     (term-flush (set-window-configuration conf))))
> >>
> >>Then some of these use-case concerns could be mooted altogether.
> >
> >We already have something like that. :-) read-event already runs the events it reads through special-event-map, right? We don't even need to create a separate thunk list concept: we could just bind C-g in special event map and do what we want, right?
Would that provide the behavior Pip is looking for?  I can't pretend
to understand what is going on in read_char, but it looks like that
map isn't applied to *every* key entered, to ensure they are removed
from the normal event stream.

> >The only special thing about C-g is how we treat it when Lisp is running. When it's instead reading an event, it can and be a boring event processed the same way every other event is.
It seems to me what Pip is looking for is analogous to a "Quit" button
hardwired to a pin on a CPU, which is not something that can be
reliably implemented in the C primitives as they are now.  That would
mean adding "interrupts" to the lisp machine architecture.
If I think about it seriously, I guess I would be talking about a
mechanism incorporated into signal handlers that would do surgery on
the appropriate thread's C/Lisp machine stack so that when that
machine's operation is resumed, the active frame would be for a call
to the registered interrupt handler, arranged to return to cleanly
return to wherever the C code was before the signal, unless the
interrupt handler performed a non-local exit, like (signal 'quit).
Maybe the interrupt handler shouldn't be a thunk, but take two
arguments: the data delivered with the signal (in this case the
keystroke) and a timestamp, so your "<N> quits in <M> milliseconds"
could be implemented when there are multiple keystrokes before the
lisp thread resumes.  In this scenario, the signal handler would never
deliver "hard-wired" interrupt keystrokes to the event queue processed
by read_char.  It would also mean a C-g (or other designated
interrupt) could be processed earlier than preceding keystrokes, but
that seems like what Pip would want?
Theoretically, such interrupt handlers could be required to be
byte-code functions that don't use any operations that could produce
unbounded stack usage, most notably no call instructions, or certified
by the native compiler to be "safe" for use with interrupts.  Also,
byte-code ops for "signal" and "throw" would need to be added.  The
possibility of forcing a non-local exit on the lisp thread would be
the whole point of arranging a handler to run on that thread in the
first place.  Anyway, this kind of restriction would probably
scare-off any non-serious uses of the facility.

This approach is really too low-level for the use I suggested in
term.el, though I do think there should be some way of saying "wake me
up when this key is pressed" and either block until that happens
(queueing other keystrokes) or let the command loop do whatever it
normally would if that makes sense.

> Oh yeah, one thing I forgot to mention: for the *asynchronous* case, the C code is pretty deeply coupled to quit_char, and IIRC, even hard codes 7, C-g, in some places instead of quit_char. In your proposal, we'd references to quit_char and literal 7 to calls to a new bool is_quit_char(int c) function -- and this function would return true for any raw keys bound in special-event-map. In this way, you'd be able to define as many asynchronous-input characters as you wanted.
  I guess I would consider removing that kind of hard-coded logic a plus?
>
> We wouldn't get the special SIGINT behavior this way (because in termios there can be only one interrupt key, right?), but I think that's okay, since quitting works without the SIGINT wiring and I suspect that we could remove the SIGINT wiring and simplify the codebase without losing any actual functionality.

I suppose I am thinking from the perspective of making the lisp
machine more machine-like, to facilitate the possibility of running
multiple elisp "cpus" or "cores" in the same process, but that's all
pie in the sky at this point.  I'd like to see inputs and displays
become clean sources and sinks, with the threads processing the data
freed from concerns like whether redisplay will be called.  Like
having dedicated coprocessors for I/O devices, with the lisp machine
core primitives just concerned with the data structures (like buffers)
they manage.

I'm talking awfully big for someone struggling to make
read0/readevalloop re-entrant enough to interleave progressive
evaluation of forms in a string with loading a file or evaluating a
buffer.

Lynn




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 03:44:02 GMT) Full text and rfc822 format available.

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

From: Gerd Möllmann <gerd.moellmann <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 Daniel Colascione <dancol <at> dancol.org>, Pip Cet <pipcet <at> protonmail.com>,
 Lynn Winebarger <owinebar <at> gmail.com>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 05:43:41 +0200
Stefan Monnier <monnier <at> iro.umontreal.ca> writes:

>>> We already have something like that. :-) read-event already runs the
>>> events it reads through special-event-map, right?
>> Entirely unrelated, I just came across this because I searched for
>> read-event. Let me just mention that read-event does not respect
>> input-decode-map. This is a problem on ttys, see bug#75886.
>
> Currently the only "decoding" we have to turn the TTY input bytes into
> events is limited to the keyboard-coding-system thingy.  🙁
>
> Maybe I should have implemented `input-decode-map` directly inside
> `read-event`, but I think it goes contrary to the design.
>
> It's usually better to change the users to use a higher-level function
> instead, such as `read-key`.
>
> Admittedly, if you want to recognize a quit event encoded as an escape
> sequence, that's not going to help you because we need/want those events
> to be decoded at as-low a level as we can. 🙁

I'd deprecate read-event TBH.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 06:26:02 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, dancol <at> dancol.org
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 09:25:28 +0300
> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
> Cc: Eli Zaretskii <eliz <at> gnu.org>,  pipcet <at> protonmail.com,
>   78737 <at> debbugs.gnu.org
> Date: Fri, 13 Jun 2025 14:00:31 -0400
> 
> >>> What I asked, and still didn't get an answer to, is at what point does
> >>> a program that calls read-event becomes interruptible by a single C-g,
> >>> after the changes on the branch?
> >>It's interrupted if the `C-g` occurs while running the code rather than
> >>while sitting inside `read-event`.  For the tight `while t` loop, it's
> >>virtually never.
> > For clarity's sake, Stefan is describing what's in the branch right now and
> > I'm describing what will be on the branch before it's ready for merging.
> 
> I thought the difference was only in terms of "emergency quit", which
> I think is not what Eli referred to when he meant "interruptible".

No, this is a gross misunderstanding of what I was saying, and IMO of
the whole discussion.

By "interruptible" I mean the ability of interrupt a Lisp program with
a single C-g.  Currently, some Lisp programs cannot be interrupted
that way (or in any way, except by SIGUSR2 or something similar), but
most are.  Changes proposed by Daniel make this small subset of
programs a bit larger (AFAIU), so we are discussing whether that is a
problem, how significant is that problem, and how to remedy it.

"Emergency exit" (not "emergency quit", which never existed in Emacs)
is the feature whereby typing more than 1 C-g would pop the question
whether to exit Emacs and if so, whether to dump core.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 06:29:02 GMT) Full text and rfc822 format available.

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

From: Pip Cet <pipcet <at> protonmail.com>
To: Lynn Winebarger <owinebar <at> gmail.com>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 Daniel Colascione <dancol <at> dancol.org>,
 Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 06:28:06 +0000
"Lynn Winebarger" <owinebar <at> gmail.com> writes:

> On Fri, Jun 13, 2025 at 10:02 AM Daniel Colascione <dancol <at> dancol.org> wrote:
>>
>>
>>
>> On June 13, 2025 6:42:58 AM PDT, Daniel Colascione <dancol <at> dancol.org> wrote:
>> >
>> >
>> >On June 13, 2025 5:23:34 AM PDT, Lynn Winebarger <owinebar <at> gmail.com> wrote:
>> >>On Fri, Jun 13, 2025, 2:26 AM Eli Zaretskii <eliz <at> gnu.org> wrote:
>> >>
>> >>> > From: Daniel Colascione <dancol <at> dancol.org>
>> >>> > Cc: Eli Zaretskii <eliz <at> gnu.org>,  monnier <at> iro.umontreal.ca,
>> >>> >   78737 <at> debbugs.gnu.org
>> >>> > Date: Thu, 12 Jun 2025 11:48:50 -0700
>> >>> >
>> >>> > Pip Cet <pipcet <at> protonmail.com> writes:
>> >>> >
>> >>> > > I'd like read-event, when called while inhibit-quit is t, to report
>> >>> > > quits by setting quit-flag in addition to returning quit_char: it'll
>> >>> > > simplify the C code, and it would make
>> >>> > >
>> >>> > > (while t
>> >>> > >   (let ((inhibit-quit t))
>> >>> > >     (read-event)))
>> >>> >
>> >>> > I strongly disagree.  read-event should read an event.
>> >>> > Setting quit-flag by side effect when it happens to read one key and not
>> >>> > others makes the interface less regular and understandable.
>> >>>
>> >>> We should start by agreeing that the capability of interrupting a
>> >>> running Lisp program is a real need.  Are we in agreement about that?
>> >>> If not, let's first hear the arguments why not.
>> >>>
>> >>> If we _are_ in agreement about that, we should discuss how this should
>> >>> be possible if read-event (and perhaps others?) return C-g instead of
>> >>> raising quit-flag.  The alternatives mentioned until now are:
>> >>>
>> >>>  . restore the old behavior, whereby C-g interrupts read-event
>> >>>  . have a variable that, if set, will restore the old behavior in
>> >>>    read-event and other affected primitives, to be interruptible by a
>> >>>    single C-g
>> >>>  . make two C-g presses "in quick succession" set quit-flag, IOW
>> >>>    "C-g C-g" will have the same effect as C-g previously
>> >>>
>> >>> Are there other alternatives?
>> >>>
>> >>
>> >>What about keeping a (possibly buffer-local?) lisp variable holding a list
>> >>of keystrokes mapped to thunks that are treated as generating lisp machine
>> >>"interrupts"?  The key strokes would be processed by C machinery and never
>> >>seen directly by lisp code and not be considered "events".
>> >>Then C-g could be bound to a thunk signalling quit, and the effect of
>> >>"inhibit-quit" achieved by removing C-g from the list in a given dynamic
>> >>scope.  Then user code could make other key-strokes "special" without
>> >>resorting to read-event.  For example, this read-event call in term.el:
>> >>(message "Hit space to flush")
>> >>      (let ((ch (read-event)))
>> >> (if (eq ch ?\s)
>> >>     (set-window-configuration conf)
>> >>   (push ch unread-command-events)))
>> >>
>> >>Could be replaced by something like
>> >>(with-interrupts ((?\s (signal term-flush)))
>> >>  (condition-case nil
>> >>    (while t (sit-for 100))
>> >>     (term-flush (set-window-configuration conf))))
>> >>
>> >>Then some of these use-case concerns could be mooted altogether.
>> >
>> >We already have something like that. :-) read-event already runs
>> > the events it reads through special-event-map, right? We don't
>> > even need to create a separate thunk list concept: we could just
>> > bind C-g in special event map and do what we want, right?

> Would that provide the behavior Pip is looking for?

It would not, because quits are currently processed out-of-order, and
this important feature should remain in place for "serious" quits.  See
below.

>> >The only special thing about C-g is how we treat it when Lisp is
>> > running. When it's instead reading an event, it can and be a
>> > boring event processed the same way every other event is.

> It seems to me what Pip is looking for is analogous to a "Quit" button
> hardwired to a pin on a CPU, which is not something that can be
> reliably implemented in the C primitives as they are now.

You're suggesting I'm looking for something that cannot be implemented.
I'm not.

I described specific situations in which I think quit should be expanded
to work better than it does now.  No one's expecting that quit works in
absolutely every situation, as far as I know.  That's what gdb is for.

If you're referring to the "C-g C-g" thing, I did not describe how I'd
implement it in detail, because there are many choices to be made; but
the main idea would be that we should not immediately clear inhibit-quit
for that combination, because that's a dangerous and destructive thing
to do.  If we decide to do so (after a delay, for example), we need to
print a clear warning to the user that their Emacs session needs
restarting.

So C-g C-g might do less than GUI C-g C-g C-g does currently.

There are actions even more dangerous than clearing inhibit-quit.  I
don't know whether we want a level-3 quit which does even more than the
current GUI C-g C-g C-g code.

But, again, such decisions ultimately require actually writing code, and
I haven't, so far.

> It would also mean a C-g (or other designated interrupt) could be
> processed earlier than preceding keystrokes, but that seems like what
> Pip would want?

That's the current behavior.  I'd like to keep it.

Quit has some immediate effects, including sometimes clearing
unread-command-events, discarding queued input.  It also sets the quit
flag before other input is processed.  It then causes an actual quit,
which is an error, which causes Fdiscard_input to be called.

>> Oh yeah, one thing I forgot to mention: for the *asynchronous* case,
>> the C code is pretty deeply coupled to quit_char, and IIRC, even
>> hard codes 7, C-g, in some places instead of quit_char. In your
>> proposal, we'd references to quit_char and literal 7 to calls to a
>> new bool is_quit_char(int c) function -- and this function would
>> return true for any raw keys bound in special-event-map. In this
>> way, you'd be able to define as many asynchronous-input characters
>> as you wanted.
> I guess I would consider removing that kind of hard-coded logic a
> plus?

I think whether to make quit_char configurable (in GUI sessions) or keep
the code which makes it configurable (in terminal sessions only) is a
very minor detail.

This comment in bindings.el:

;; The following wouldn't work to interrupt running code since C-g is
;; treated specially in the event loop.
;; (define-key global-map [stop]		'keyboard-quit) ; Sun

suggests someone once wanted to add an additional quit_char and gave up.

Pip





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 06:47:03 GMT) Full text and rfc822 format available.

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

From: Pip Cet <pipcet <at> protonmail.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, dancol <at> dancol.org,
 Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 06:46:03 +0000
"Eli Zaretskii" <eliz <at> gnu.org> writes:

> "Emergency exit" (not "emergency quit", which never existed in Emacs)
> is the feature whereby typing more than 1 C-g would pop the question
> whether to exit Emacs and if so, whether to dump core.

Sorry if I'm being dense, but just to recap:

"Emergency exit" works in sessions that have a terminal frame.  In such
sessions, the code manipulating force_quit_count is never reached.

In GUI sessions, this code is reached, and hitting C-g three times while
quit-flag is set will perform a special kind of quit, clearing
inhibit-quit.

IIUC, you object to calling this special kind of quit "emergency quit",
and would prefer to call it something else.

Is that right?  What's the preferred term for this special kind of quit?

I'm asking mostly because this feature isn't documented in trouble.texi.
The emergency escape (= emergency exit) feature is well-documented but I
fear that won't help most users, terminal frames being rare these days.

Pip





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 07:06:02 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, dancol <at> dancol.org
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 10:05:46 +0300
> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
> Cc: Daniel Colascione <dancol <at> dancol.org>,  pipcet <at> protonmail.com,
>   78737 <at> debbugs.gnu.org
> Date: Fri, 13 Jun 2025 14:07:20 -0400
> 
> > My current understanding is that what you propose will cause some
> > (most) programs to be interruptible with a single C-g, while some (in
> > particular those which call read-event) will need two or more C-g to
> > be interrupted.  Is that correct?
> 
> I think so, tho only for *some* of those which call `read-event`.

If read-event always returns 7, then the "*some*" part is incorrect,
as long as C-g was pressed while we are in read-event.

> > If this is correct, then we need to decide whether this inconsistency
> > (one C-g vs several) is tolerable.
> 
> That inconsistency already exists in various places, such as if you use
> `read-key`.

Yes, but it's a known inconsistency, with which we lived for many
years.  We are now introducing a new inconsistency.

This is a practical matter, not an academic one.  Some people and some
applications will be surprised, and some applications will not work as
they did before.  Telling them that we always had a similar
inconsistency will not help.

> I think what we need to decide is if the resulting overall
> behavior is better (e.g. easier to describe and less error prone), and
> if so, whether it's worth the incompatibility.

Yes, we do need to make that decision.  However:

  . we need first to agree on the design and the implementation of new
    code, and
  . we then need to describe the resulting behavior in clear enough
    terms for others to understand and reason about it

Then we need to describe these changes on emacs-devel and see if the
changes in behavior are acceptable by the community.

> Of course, we could also make the change more backward-compatible by
> renaming `read-event` to some new name and (re)defining `read-event` on
> top of that new function.

That's yet another possibility, yes.  But given the original
motivation (the problems in transient.el), I doubt if this is a viable
solution.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 07:14:02 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, dancol <at> dancol.org
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 10:12:55 +0300
> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
> Cc: dancol <at> dancol.org,  78737 <at> debbugs.gnu.org,  pipcet <at> protonmail.com
> Date: Fri, 13 Jun 2025 14:14:44 -0400
> 
> >> >  (while t
> >> >    (let (evt (read-event))
> >> >      (do-something-with evt)))
> >> >
> >> > _can_ be interrupted?
> >> 
> >> Usually the `(do-something-with evt)` part will offer some way to end
> >> the loop.
> >
> > How?  If read-event returns the character 7, then the information
> > about the fact that C-g was typed is lost by the time we get to the
> > do-something-with part, no?
> 
> AFAIK that information is in `evt` and hence not lost.

That's not what I see on the branch.  read-event returns the character
7, a scalar.  Or am I missing something?

> Usually `do-something-with` will look at `evt` and do various things
> depending on the key that was pressed and usually one of those options
> lets you end what you were doing.
> 
> Some code may assume they don't need to explicitly abort when `evt` is
> 7 because they rely on the current behavior of `read-event`, but AFAIK
> that behavior is not completely reliable (e.g. it depends on
> `inhibit-quit` and sometimes timing), so if we want to encourage use of
> that feature we should try and make it more reliable.

So you are saying that, to be interruptible by a single C-g, a Lisp
program that calls read-event will need to have code that quits under
certain circumstances when read-event returns 7, is that right?
Doesn't that mean we will now require every program that calls
read-event to have such Lisp code, where it previously didn't?
Pushing quitting to the application level is not something that will
be appreciated by Lisp programmers, I think.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 07:14:02 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, dancol <at> dancol.org
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 10:13:43 +0300
> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
> Cc: dancol <at> dancol.org,  78737 <at> debbugs.gnu.org,  pipcet <at> protonmail.com
> Date: Fri, 13 Jun 2025 14:17:01 -0400
> 
> >> What is "emergency quit"?
> > Something like `C-g C-g C-g`, tho we don't have that implemented,
> > currently, AFAIK.
> 
> I guess `kill -USR2` could count as well.

Not as a single trigger, no: it isn't portable enough.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 07:17:02 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Pip Cet <pipcet <at> protonmail.com>
Cc: 78737 <at> debbugs.gnu.org, dancol <at> dancol.org, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 10:16:15 +0300
> Date: Fri, 13 Jun 2025 18:25:13 +0000
> From: Pip Cet <pipcet <at> protonmail.com>
> Cc: Eli Zaretskii <eliz <at> gnu.org>, dancol <at> dancol.org, 78737 <at> debbugs.gnu.org
> 
> "Stefan Monnier" <monnier <at> iro.umontreal.ca> writes:
> 
> >> What is a "normal quit"?
> >
> > A single C-g.
> >
> >> What is "emergency quit"?
> >
> > Something like `C-g C-g C-g`, tho we don't have that implemented,
> > currently, AFAIK.
> 
> It's implemented.  See handle_interrupt in keyboard.c:
> 
>       /* Request quit when it's safe.  */
>       int count = NILP (Vquit_flag) ? 1 : force_quit_count + 1;
>       force_quit_count = count;
>       if (count == 3)
> 	Vinhibit_quit = Qnil;
>       Vquit_flag = Qt;

That's not "emergency quit", that's part of "emergency exit".  A
different, though related, feature.

> The "emergency" part is clearing the inhibit-quit flag when
> force_quit_count reaches 3.  The bug is that it should be >= 3, and the
> questionable design feature is that we should reset the counter if
> Vquit_flag and Vinhibit_quit are both nil, not just based on Vquit_flag.

It isn't a bug, because emergency exit happens when the count is 2.

There's a reason why I suggested to leave the emergency exit feature
alone for now.  Mixing it with this discussion just muddies the waters
and adds to confusion and misunderstandings.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 07:51:01 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 10:50:41 +0300
> Date: Fri, 13 Jun 2025 14:38:22 -0400
> From: Daniel Colascione <dancol <at> dancol.org>
> CC: monnier <at> iro.umontreal.ca, pipcet <at> protonmail.com, 78737 <at> debbugs.gnu.org
> 
> On June 13, 2025 1:47:43 PM EDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
> >My current understanding is that what you propose will cause some
> >(most) programs to be interruptible with a single C-g, while some (in
> >particular those which call read-event) will need two or more C-g to
> >be interrupted.  Is that correct?
> 
> Yes.

Good.

> However, it looks right now like the class of program that has to be quit with a repeated C-g is extremely small. I've seen only contrived examples so far.  Most programs do something with the result of calling read-event, and when they see C-g, either break out of their dispatch loop or do a C-g appropriate thing.
> 
> Things using low level input events like that, however, tend to be either old or specialized.
> 
> The most common code paths (e.g. isearch, transient, map-y-or-n-p, etc.) with dispatch loops already use higher level tools like read-key, read-char-from-minibuffer, or transient keymaps and so get C-g handled as an input event anyway.
> 
> Has anyone complained that (while t (read-key)) doesn't admit keyboard quitting?
> 
> In practice, based on experience so far, there's no practical need to press C-g any more often than one does on mainline.
> 
> >If this is correct, then we need to decide whether this inconsistency
> >(one C-g vs several) is tolerable.
> 
> I think it's correct only in theory. Maybe I'm wrong and there's some undiscovered case that this breaks. It's to discover these cases that it would be nice to test the branch and merge it to mainline. We can always put it behind a feature flag.

I don't think we can dismiss use cases just because they are rare.
When we get a bug report about some regression, we try to fix the
regression regardless of how frequent the recipe is.  We do sometimes
decide not to fix such bugs, and in those cases we might bring up
arguments about importance and frequency of the situation.  But first
we try to fix the bug without considering that.

So if we are going to have a policy of disregarding such regressions
in these cases, we need to see a broad agreement to it.

> >Thanks, but that doesn't answer my question, which is specifically
> >about the effect of C-g on Lisp programs, whether they call read-event
> >or don't call it.
> 
> Lisp programs that don't call read-event, read-char, or read-char-exclusive don't see a change in behavior except for how, once we implement the repeated C-g work, users will be able to break out of loops like (while t (read-key)) by pressing C-g multiple times.
> 
> I have yet to see a real program that does something like this, much less one that depends on bricking quit functionality in the user's Emacs session.
> 
> Lisp programs that do call these low level functions see a contract change, as I detailed in my previous messages.

I understand that Lisp programs which do call those low-level
functions will need to either accept that they cannot be interrupted
by a single C-g, or add some Lisp to quit when they receive a keyboard
input event that's equal to quit-char, is that right?  If so, we will
need to clearly identify and document the low-level functions affected
by this.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 07:57:02 GMT) Full text and rfc822 format available.

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

From: Pip Cet <pipcet <at> protonmail.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, dancol <at> dancol.org, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 07:55:54 +0000
"Eli Zaretskii" <eliz <at> gnu.org> writes:

>> Date: Fri, 13 Jun 2025 18:25:13 +0000
>> From: Pip Cet <pipcet <at> protonmail.com>
>> Cc: Eli Zaretskii <eliz <at> gnu.org>, dancol <at> dancol.org, 78737 <at> debbugs.gnu.org
>>
>> "Stefan Monnier" <monnier <at> iro.umontreal.ca> writes:
>>
>> >> What is a "normal quit"?
>> >
>> > A single C-g.
>> >
>> >> What is "emergency quit"?
>> >
>> > Something like `C-g C-g C-g`, tho we don't have that implemented,
>> > currently, AFAIK.
>>
>> It's implemented.  See handle_interrupt in keyboard.c:
>>
>>       /* Request quit when it's safe.  */
>>       int count = NILP (Vquit_flag) ? 1 : force_quit_count + 1;
>>       force_quit_count = count;
>>       if (count == 3)
>> 	Vinhibit_quit = Qnil;
>>       Vquit_flag = Qt;
>
> That's not "emergency quit", that's part of "emergency exit".  A
> different, though related, feature.

Sorry, still being dense.  This code is not reached on text terminals,
so it's not part of what trouble.texi calls the Emergency Escape
mechanism.  I thought you were using "emergency exit" to refer to the
Emergency Escape feature, but the above suggests that "emergency exit"
includes both the Emergency Escape and triple-C-g behavior on GUI
terminals.

I'd like a term for just the latter.

Triple C-g on a GUI terminal clears inhibit-quit and quits, breaking out
of loops such as:

(let ((inhibit-quit t))
  (while t))

This:

1. requires *three* C-g presses
2. does not trigger an Emergency Escape or exit Emacs
3. is unreachable on text terminals

Since this behavior does not exit Emacs, I thought it would not count as
part of the "emergency exit" feature.

>> The "emergency" part is clearing the inhibit-quit flag when
>> force_quit_count reaches 3.  The bug is that it should be >= 3, and the
>> questionable design feature is that we should reset the counter if
>> Vquit_flag and Vinhibit_quit are both nil, not just based on Vquit_flag.
>
> It isn't a bug, because emergency exit happens when the count is 2.

No, nothing special happens when the count reaches 2.

These two are mutually exclusive:

The code incrementing force_quit_count is unreachable on text terminals.

The code implementing the Emergency Escape feature is unreachable on GUI
terminals.

static void
handle_interrupt (bool in_signal_handler)
{
  char c;

  cancel_echoing ();

  /* XXX This code needs to be revised for multi-tty support.  */
  if (!NILP (Vquit_flag) && get_named_terminal (dev_tty))
    {
      <Emergency Escape feature>
    }
  else
    {
      <What do we call this?>
      /* Request quit when it's safe.  */
      int count = NILP (Vquit_flag) ? 1 : force_quit_count + 1; <-- on text terminals, Vquit_flag is nil!
      force_quit_count = count;
      if (count == 3)
	Vinhibit_quit = Qnil;
      Vquit_flag = Qt;
    }
  ...
}

So, on GUI frames, a double C-g will leave force_quit_count set to 2,
but it will not perform an Emergency Escape, and it will not clear
inhibit-quit.  Nothing special happens when force_quit_count reaches 2.

The third C-g, assuming quit-flag is still set, will clear inhibit-quit,
set the quit-flag again, and thus trigger a "special kind of quit".  I'm
looking for a name for it.

I note that this triple-C-g behavior is documented only in the code;
it's missing from trouble.texi.

diff --git a/doc/emacs/trouble.texi b/doc/emacs/trouble.texi
index 45f15c7dd0d..33c97352f7c 100644
--- a/doc/emacs/trouble.texi
+++ b/doc/emacs/trouble.texi
@@ -83,6 +83,10 @@ Quitting
 actually executed as a command if you type it while Emacs is waiting for
 input.  In that case, the command it runs is @code{keyboard-quit}.
 
+  On graphical terminals, you may be able to quit by typing @kbd{C-g}
+three times, even when an ordinary @kbd{C-g} doesn't work.
+@xref{Feature X}.
+
   On a text terminal, if you quit with @kbd{C-g} a second time before
 the first @kbd{C-g} is recognized, you activate the emergency-escape
 feature and return to the shell.  @xref{Emergency Escape}.
@@ -157,7 +161,8 @@ Lossage
 * Memory Full::           How to cope when you run out of memory.
 * Crashing::              What Emacs does when it crashes.
 * After a Crash::         Recovering editing in an Emacs session that crashed.
-* Emergency Escape::      What to do if Emacs stops responding.
+* Feature X::             What to do if Emacs stops responding.
+* Emergency Escape::      What to do if Emacs stops responding on a text terminal.
 * DEL Does Not Delete::   What to do if @key{DEL} doesn't delete.
 @end menu
 
@@ -400,6 +405,22 @@ After a Crash
 which does not already exist; if the file does exist, the script does
 not make a backup of its old contents.
 
+@node Feature X
+@subsection Feature X
+@cindex feature x
+
+@c This works only if all terminals are graphical terminals; mixed
+@c text/GUI terminal sessions use the Emergency Escape feature.
+
+  On graphical terminals, typing @kbd{C-g} three times in a row while
+Emacs is not responding will clear the @code{inhibit-quit} flag.  This
+allows Emacs to recover from being stuck in certain kinds of loops.
+
+  After using this feature, Emacs will appear to have processed an
+ordinary quit, but you should exit and restart Emacs.  This is because
+forcibly clearing the @code{inhibit-quit} flag may have left Emacs in an
+inconsistent state.
+
 @node Emergency Escape
 @subsection Emergency Escape
 @cindex emergency escape

Obviously, we should replace "feature X" by something else.

Pip





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 07:57:02 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 10:55:57 +0300
> Date: Fri, 13 Jun 2025 15:07:51 -0400
> From: Daniel Colascione <dancol <at> dancol.org>
> CC: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com
> 
> On June 13, 2025 2:16:08 PM EDT, Stefan Monnier <monnier <at> iro.umontreal.ca> wrote:
> >> What is a "normal quit"?
> >
> >A single C-g.
> >
> >> What is "emergency quit"?
> >
> >Something like `C-g C-g C-g`, tho we don't have that implemented,
> >currently, AFAIK.
> 
> 
> How about this terminology?
> 
> C-g --- normal quit
> 
> C-g C-g C-g --- urgent quit (breaks out of read-event. should probably break out of redisplay too?)

Breaking out of redisplay should remain an opt-in behavior, like it is
now on the branch.  When turned on, I'm okay with having it activated
with several C-g presses.

> C-g C-g C-g C-g C-g C-g --- emergency quit. ignores inhibit-quit. good chance of horking your Emacs by violating atomicity assumptions. Display "are you sure?" message before final C-g.

This seems to ignore the "emergency exit" feature we have today.  I
wouldn't want to lose that as well.  Or did you mean to leave that
activated by "C-g C-g"?  If the latter, wouldn't we be prone to
sometimes activating the emergency exit instead of the "urgent quit"?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 08:15:02 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Gerd Möllmann <gerd.moellmann <at> gmail.com>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, dancol <at> dancol.org,
 monnier <at> iro.umontreal.ca, owinebar <at> gmail.com
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 11:14:04 +0300
> From: Gerd Möllmann <gerd.moellmann <at> gmail.com>
> Cc: Daniel Colascione <dancol <at> dancol.org>,  78737 <at> debbugs.gnu.org,  Eli
>  Zaretskii <eliz <at> gnu.org>,  Pip Cet <pipcet <at> protonmail.com>,  Lynn
>  Winebarger <owinebar <at> gmail.com>
> Date: Sat, 14 Jun 2025 05:43:41 +0200
> 
> Stefan Monnier <monnier <at> iro.umontreal.ca> writes:
> 
> >>> We already have something like that. :-) read-event already runs the
> >>> events it reads through special-event-map, right?
> >> Entirely unrelated, I just came across this because I searched for
> >> read-event. Let me just mention that read-event does not respect
> >> input-decode-map. This is a problem on ttys, see bug#75886.
> >
> > Currently the only "decoding" we have to turn the TTY input bytes into
> > events is limited to the keyboard-coding-system thingy.  🙁
> >
> > Maybe I should have implemented `input-decode-map` directly inside
> > `read-event`, but I think it goes contrary to the design.
> >
> > It's usually better to change the users to use a higher-level function
> > instead, such as `read-key`.
> >
> > Admittedly, if you want to recognize a quit event encoded as an escape
> > sequence, that's not going to help you because we need/want those events
> > to be decoded at as-low a level as we can. 🙁
> 
> I'd deprecate read-event TBH.

If we want to do this, we should start by removing it from our own
sources.  Currently, we use it in around 80 places.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 08:31:02 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Pip Cet <pipcet <at> protonmail.com>
Cc: 78737 <at> debbugs.gnu.org, dancol <at> dancol.org, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 11:30:31 +0300
> Date: Sat, 14 Jun 2025 06:46:03 +0000
> From: Pip Cet <pipcet <at> protonmail.com>
> Cc: Stefan Monnier <monnier <at> iro.umontreal.ca>, dancol <at> dancol.org, 78737 <at> debbugs.gnu.org
> 
> "Eli Zaretskii" <eliz <at> gnu.org> writes:
> 
> > "Emergency exit" (not "emergency quit", which never existed in Emacs)
> > is the feature whereby typing more than 1 C-g would pop the question
> > whether to exit Emacs and if so, whether to dump core.
> 
> Sorry if I'm being dense, but just to recap:
> 
> "Emergency exit" works in sessions that have a terminal frame.  In such
> sessions, the code manipulating force_quit_count is never reached.
> 
> In GUI sessions, this code is reached, and hitting C-g three times while
> quit-flag is set will perform a special kind of quit, clearing
> inhibit-quit.
> 
> IIUC, you object to calling this special kind of quit "emergency quit",
> and would prefer to call it something else.
> 
> Is that right?  What's the preferred term for this special kind of quit?

I don't know.  This feature is not currently documented in the manual,
so I don't think we have a term for it.  We don't even advertise it
anywhere, AFAICT.

> I'm asking mostly because this feature isn't documented in trouble.texi.
> The emergency escape (= emergency exit) feature is well-documented but I
> fear that won't help most users, terminal frames being rare these days.

I would like to see the emergency exit feature work on GUI frames as
well, if that's feasible.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 08:50:03 GMT) Full text and rfc822 format available.

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

From: Ihor Radchenko <yantar92 <at> posteo.net>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, Pip Cet <pipcet <at> protonmail.com>, dancol <at> dancol.org,
 monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 08:47:41 +0000
Eli Zaretskii <eliz <at> gnu.org> writes:

>> I'm asking mostly because this feature isn't documented in trouble.texi.
>> The emergency escape (= emergency exit) feature is well-documented but I
>> fear that won't help most users, terminal frames being rare these days.
>
> I would like to see the emergency exit feature work on GUI frames as
> well, if that's feasible.

+1
FYI, I independently re-implemented (without knowing) a similar feature
for Org mode (see `org-element--cache-interrupt-C-g' and
`org-element--cache-interrupt-C-g-max-count' in org-element.el)
Note that it is an example when Elisp code needs some cleanup if
emergency exit is requested:

(when (and inhibit-quit org-element--cache-interrupt-C-g quit-flag)
               (when quit-flag
	         (cl-incf org-element--cache-interrupt-C-g-count)
                 (setq quit-flag nil))
               (when (>= org-element--cache-interrupt-C-g-count
                         org-element--cache-interrupt-C-g-max-count)
                 (setq quit-flag t)
                 (setq org-element--cache-interrupt-C-g-count 0)
                 (org-element-cache-reset)
                 (error "org-element: Parsing aborted by user.  Cache has been cleared.
If you observe Emacs hangs frequently, please report this to Org mode mailing list (M-x org-submit-bug-report)"))
               (message (substitute-command-keys
                         "`org-element--parse-to': Suppressed `\\[keyboard-quit]'.  Press `\\[keyboard-quit]' %d more times to force interruption.")
                        (- org-element--cache-interrupt-C-g-max-count
                           org-element--cache-interrupt-C-g-count)))

-- 
Ihor Radchenko // yantar92,
Org mode maintainer,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 08:55:02 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Pip Cet <pipcet <at> protonmail.com>
Cc: 78737 <at> debbugs.gnu.org, dancol <at> dancol.org, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 11:54:25 +0300
> Date: Sat, 14 Jun 2025 07:55:54 +0000
> From: Pip Cet <pipcet <at> protonmail.com>
> Cc: monnier <at> iro.umontreal.ca, dancol <at> dancol.org, 78737 <at> debbugs.gnu.org
> 
> "Eli Zaretskii" <eliz <at> gnu.org> writes:
> 
> >>       /* Request quit when it's safe.  */
> >>       int count = NILP (Vquit_flag) ? 1 : force_quit_count + 1;
> >>       force_quit_count = count;
> >>       if (count == 3)
> >> 	Vinhibit_quit = Qnil;
> >>       Vquit_flag = Qt;
> >
> > That's not "emergency quit", that's part of "emergency exit".  A
> > different, though related, feature.
> 
> Sorry, still being dense.  This code is not reached on text terminals,
> so it's not part of what trouble.texi calls the Emergency Escape
> mechanism.  I thought you were using "emergency exit" to refer to the
> Emergency Escape feature

I was.

> but the above suggests that "emergency exit"
> includes both the Emergency Escape and triple-C-g behavior on GUI
> terminals.

It doesn't.  The triple-C-g thing is not documented at all.

> Triple C-g on a GUI terminal clears inhibit-quit and quits, breaking out
> of loops such as:
> 
> (let ((inhibit-quit t))
>   (while t))

Btw, the triple-C-g doesn't break this on Windows in a GUI session.
handle_interrupt is not called at all on Windows when I press C-g.

> This:
> 
> 1. requires *three* C-g presses
> 2. does not trigger an Emergency Escape or exit Emacs
> 3. is unreachable on text terminals

If we want to adverse this, we need to document it in the same place
as the emergency exit.

> Since this behavior does not exit Emacs, I thought it would not count as
> part of the "emergency exit" feature.

Indeed, it doesn't.

> >> The "emergency" part is clearing the inhibit-quit flag when
> >> force_quit_count reaches 3.  The bug is that it should be >= 3, and the
> >> questionable design feature is that we should reset the counter if
> >> Vquit_flag and Vinhibit_quit are both nil, not just based on Vquit_flag.
> >
> > It isn't a bug, because emergency exit happens when the count is 2.
> 
> No, nothing special happens when the count reaches 2.

On TTY frames, it does, doesn't it?

> These two are mutually exclusive:
> 
> The code incrementing force_quit_count is unreachable on text terminals.
> 
> The code implementing the Emergency Escape feature is unreachable on GUI
> terminals.

OK, so once we've established that, what's your point?

> I note that this triple-C-g behavior is documented only in the code;
> it's missing from trouble.texi.

Yes, but the correct place to document it is in the same section where
the emergency exit is described.  And talking about inhibit-quit in
the user manual is wrong, because users aren't expected to know about
that.  And finally, if we want to advertise this, we had better made
it work on all supported platforms.

Last, but not least, this is not directly related to the main part of
this discussion, which is about being able to interrupt Lisp programs
by a single C-g.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 09:13:02 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: pipcet <at> protonmail.com
Cc: 78737 <at> debbugs.gnu.org, dancol <at> dancol.org, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 12:12:03 +0300
> Cc: 78737 <at> debbugs.gnu.org, dancol <at> dancol.org, monnier <at> iro.umontreal.ca
> Date: Sat, 14 Jun 2025 11:30:31 +0300
> From: Eli Zaretskii <eliz <at> gnu.org>
> 
> > "Emergency exit" works in sessions that have a terminal frame.  In such
> > sessions, the code manipulating force_quit_count is never reached.
> > 
> > In GUI sessions, this code is reached, and hitting C-g three times while
> > quit-flag is set will perform a special kind of quit, clearing
> > inhibit-quit.
> > 
> > IIUC, you object to calling this special kind of quit "emergency quit",
> > and would prefer to call it something else.
> > 
> > Is that right?  What's the preferred term for this special kind of quit?
> 
> I don't know.

It seems this feature was originally known as "immediate quit".  At
some point the immediate_quit variable itself was removed, but the
term seems appropriate regardless.  So I suggest that's how we call
it.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 09:14:01 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: pipcet <at> protonmail.com
Cc: 78737 <at> debbugs.gnu.org, dancol <at> dancol.org, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 12:12:57 +0300
> Cc: 78737 <at> debbugs.gnu.org, dancol <at> dancol.org, monnier <at> iro.umontreal.ca
> Date: Sat, 14 Jun 2025 11:54:25 +0300
> From: Eli Zaretskii <eliz <at> gnu.org>
> 
> > Triple C-g on a GUI terminal clears inhibit-quit and quits, breaking out
> > of loops such as:
> > 
> > (let ((inhibit-quit t))
> >   (while t))
> 
> Btw, the triple-C-g doesn't break this on Windows in a GUI session.
> handle_interrupt is not called at all on Windows when I press C-g.

I attempted to fix that now, on master.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 10:25:02 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Eli Zaretskii <eliz <at> gnu.org>, Pip Cet <pipcet <at> protonmail.com>
Cc: 78737 <at> debbugs.gnu.org, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 06:24:40 -0400
On June 14, 2025 4:54:25 AM EDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
>> Date: Sat, 14 Jun 2025 07:55:54 +0000
>> From: Pip Cet <pipcet <at> protonmail.com>
>> Cc: monnier <at> iro.umontreal.ca, dancol <at> dancol.org, 78737 <at> debbugs.gnu.org
>> 
>> "Eli Zaretskii" <eliz <at> gnu.org> writes:
>> 
>> >>       /* Request quit when it's safe.  */
>> >>       int count = NILP (Vquit_flag) ? 1 : force_quit_count + 1;
>> >>       force_quit_count = count;
>> >>       if (count == 3)
>> >> 	Vinhibit_quit = Qnil;
>> >>       Vquit_flag = Qt;
>> >
>> > That's not "emergency quit", that's part of "emergency exit".  A
>> > different, though related, feature.
>> 
>> Sorry, still being dense.  This code is not reached on text terminals,
>> so it's not part of what trouble.texi calls the Emergency Escape
>> mechanism.  I thought you were using "emergency exit" to refer to the
>> Emergency Escape feature
>
>I was.
>
>> but the above suggests that "emergency exit"
>> includes both the Emergency Escape and triple-C-g behavior on GUI
>> terminals.
>
>It doesn't.  The triple-C-g thing is not documented at all.
>
>> Triple C-g on a GUI terminal clears inhibit-quit and quits, breaking out
>> of loops such as:
>> 
>> (let ((inhibit-quit t))
>>   (while t))
>
>Btw, the triple-C-g doesn't break this on Windows in a GUI session.
>handle_interrupt is not called at all on Windows when I press C-g.
>
>> This:
>> 
>> 1. requires *three* C-g presses
>> 2. does not trigger an Emergency Escape or exit Emacs
>> 3. is unreachable on text terminals
>
>If we want to adverse this, we need to document it in the same place
>as the emergency exit.
>
>> Since this behavior does not exit Emacs, I thought it would not count as
>> part of the "emergency exit" feature.
>
>Indeed, it doesn't.
>
>> >> The "emergency" part is clearing the inhibit-quit flag when
>> >> force_quit_count reaches 3.  The bug is that it should be >= 3, and the
>> >> questionable design feature is that we should reset the counter if
>> >> Vquit_flag and Vinhibit_quit are both nil, not just based on Vquit_flag.
>> >
>> > It isn't a bug, because emergency exit happens when the count is 2.
>> 
>> No, nothing special happens when the count reaches 2.
>
>On TTY frames, it does, doesn't it?
>
>> These two are mutually exclusive:
>> 
>> The code incrementing force_quit_count is unreachable on text terminals.
>> 
>> The code implementing the Emergency Escape feature is unreachable on GUI
>> terminals.
>
>OK, so once we've established that, what's your point?
>
>> I note that this triple-C-g behavior is documented only in the code;
>> it's missing from trouble.texi.
>
>Yes, but the correct place to document it is in the same section where
>the emergency exit is described.  And talking about inhibit-quit in
>the user manual is wrong, because users aren't expected to know about
>that.  And finally, if we want to advertise this, we had better made
>it work on all supported platforms.
>
>Last, but not least, this is not directly related to the main part of
>this discussion, which is about being able to interrupt Lisp programs
>by a single C-g.


Why is it so important that a *single* C-g interrupt a Lisp program? If a Lisp program is reading input, and C-g is input, treating at least the first C-g as input is expected, and like I said, it's just not possible to interrupt with a single C-g a program expecting to read input that is also a single C-g. If you try to achieve this goal you either break the input capability or you break the single C-g quit, and you're not addressing this contradiction head on.





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 10:36:02 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 13:35:40 +0300
> Date: Sat, 14 Jun 2025 06:24:40 -0400
> From: Daniel Colascione <dancol <at> dancol.org>
> CC: monnier <at> iro.umontreal.ca, 78737 <at> debbugs.gnu.org
> 
> >Last, but not least, this is not directly related to the main part of
> >this discussion, which is about being able to interrupt Lisp programs
> >by a single C-g.
> 
> 
> Why is it so important that a *single* C-g interrupt a Lisp program?

Only because it was possible (with some exceptions) until today.
Thus, any change in this will be rightfully considered to be an
incompatible change in behavior

> If a Lisp program is reading input, and C-g is input, treating at least the first C-g as input is expected, and like I said, it's just not possible to interrupt with a single C-g a program expecting to read input that is also a single C-g. If you try to achieve this goal you either break the input capability or you break the single C-g quit, and you're not addressing this contradiction head on.

We moved past these arguments, so why go back now?  I didn't say we
_must_ preserve previous behavior of a single C-g, I just said what is
this discussion about.  Let's argue where we disagree, not where we
don't.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 10:43:01 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 06:42:20 -0400
On June 14, 2025 3:50:41 AM EDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
>> Date: Fri, 13 Jun 2025 14:38:22 -0400
>> From: Daniel Colascione <dancol <at> dancol.org>
>> CC: monnier <at> iro.umontreal.ca, pipcet <at> protonmail.com, 78737 <at> debbugs.gnu.org
>> 
>> On June 13, 2025 1:47:43 PM EDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
>> >My current understanding is that what you propose will cause some
>> >(most) programs to be interruptible with a single C-g, while some (in
>> >particular those which call read-event) will need two or more C-g to
>> >be interrupted.  Is that correct?
>> 
>> Yes.
>
>Good.
>
>> However, it looks right now like the class of program that has to be quit with a repeated C-g is extremely small. I've seen only contrived examples so far.  Most programs do something with the result of calling read-event, and when they see C-g, either break out of their dispatch loop or do a C-g appropriate thing.
>> 
>> Things using low level input events like that, however, tend to be either old or specialized.
>> 
>> The most common code paths (e.g. isearch, transient, map-y-or-n-p, etc.) with dispatch loops already use higher level tools like read-key, read-char-from-minibuffer, or transient keymaps and so get C-g handled as an input event anyway.
>> 
>> Has anyone complained that (while t (read-key)) doesn't admit keyboard quitting?
>> 
>> In practice, based on experience so far, there's no practical need to press C-g any more often than one does on mainline.
>> 
>> >If this is correct, then we need to decide whether this inconsistency
>> >(one C-g vs several) is tolerable.
>> 
>> I think it's correct only in theory. Maybe I'm wrong and there's some undiscovered case that this breaks. It's to discover these cases that it would be nice to test the branch and merge it to mainline. We can always put it behind a feature flag.
>
>I don't think we can dismiss use cases just because they are rare.

Sure: all things being equal, don't break working code. 

>When we get a bug report about some regression, we try to fix the
>regression regardless of how frequent the recipe is.  We do sometimes
>decide not to fix such bugs, and in those cases we might bring up
>arguments about importance and frequency of the situation.  But first
>we try to fix the bug without considering that.
>
>So if we are going to have a policy of disregarding such regressions
>in these cases, we need to see a broad agreement to it.
>
>> >Thanks, but that doesn't answer my question, which is specifically
>> >about the effect of C-g on Lisp programs, whether they call read-event
>> >or don't call it.
>> 
>> Lisp programs that don't call read-event, read-char, or read-char-exclusive don't see a change in behavior except for how, once we implement the repeated C-g work, users will be able to break out of loops like (while t (read-key)) by pressing C-g multiple times.
>> 
>> I have yet to see a real program that does something like this, much less one that depends on bricking quit functionality in the user's Emacs session.
>> 
>> Lisp programs that do call these low level functions see a contract change, as I detailed in my previous messages.
>
>I understand that Lisp programs which do call those low-level
>functions will need to either accept that they cannot be interrupted
>by a single C-g, or add some Lisp to quit when they receive a keyboard
>input event that's equal to quit-char, is that right?  If so, we will
>need to clearly identify and document the low-level functions affected
>by this.

The third option is that they handle the C-g they get like any other input. They don't have to necessarily treat it as a quit: for example, a terminal emulator might want to forward a C-g to a remote system.

Documenting new behavior should go without saying.

The requirement we document, IMHO should revolve around forward progress: whatever you do with the C-g shouldn't go back to reading a possible C-g in the same situation. Doing that would require the user to break out of your loop using multiple C-g, which is inconvenient.

(while (pcase (read-char) (1 (foo) t) (2 (bar) t) (_ (ding) nil)))

Fortunately, people tend not to write code like this.

This guidance applies to higher level input functions like read-key.

We should also mention in documentation that people should use these higher level functions unless they have a specific reason to use the lower level ones. 




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 10:56:01 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Eli Zaretskii <eliz <at> gnu.org>, Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 06:54:58 -0400
On June 14, 2025 3:12:55 AM EDT, Eli Zaretskii <eliz <at> gnu.org> wrote:
>> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
>> Cc: dancol <at> dancol.org,  78737 <at> debbugs.gnu.org,  pipcet <at> protonmail.com
>> Date: Fri, 13 Jun 2025 14:14:44 -0400
>> 
>> >> >  (while t
>> >> >    (let (evt (read-event))
>> >> >      (do-something-with evt)))
>> >> >
>> >> > _can_ be interrupted?
>> >> 
>> >> Usually the `(do-something-with evt)` part will offer some way to end
>> >> the loop.
>> >
>> > How?  If read-event returns the character 7, then the information
>> > about the fact that C-g was typed is lost by the time we get to the
>> > do-something-with part, no?
>> 
>> AFAIK that information is in `evt` and hence not lost.
>
>That's not what I see on the branch.  read-event returns the character
>7, a scalar.  Or am I missing something?

That's the encoding of C-g. What information is lost?

>> Usually `do-something-with` will look at `evt` and do various things
>> depending on the key that was pressed and usually one of those options
>> lets you end what you were doing.
>> 
>> Some code may assume they don't need to explicitly abort when `evt` is
>> 7 because they rely on the current behavior of `read-event`, but AFAIK
>> that behavior is not completely reliable (e.g. it depends on
>> `inhibit-quit` and sometimes timing), so if we want to encourage use of
>> that feature we should try and make it more reliable.
>
>So you are saying that, to be interruptible by a single C-g, a Lisp
>program that calls read-event will need to have code that quits under
>certain circumstances when read-event returns 7, is that right?
>Doesn't that mean we will now require every program that calls
>read-event to have such Lisp code, where it previously didn't?

I've seen that in practice are interruptable in this manner already. It looks like use of higher level functions like read-key or transient maps is already more common in higher level code and that this code already reacts properly to receiving C-g as input.

I do see a bit of variety in what programs actually do when they get C-g though. Some signal quit. Some call keyboard-quit, which is harmless because it eventually signals quit, but is less clear and does unnecessary work before signaling quit.

It'd be nice to guide high-level and low-level input readers alike to quit by signaling quit rather than trying to call keyboard-quit and such themselves.

>Pushing quitting to the application level is not something that will
>be appreciated by Lisp programmers, I think.

We've been pushing quitting to applications for decades when these applications use the higher level input reading functions. Check out how we do it in, e.g. calc. I haven't seen any objections.







Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 11:12:02 GMT) Full text and rfc822 format available.

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

From: Daniel Colascione <dancol <at> dancol.org>
To: Pip Cet <pipcet <at> protonmail.com>, Lynn Winebarger <owinebar <at> gmail.com>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 07:11:14 -0400
On June 14, 2025 2:28:06 AM EDT, Pip Cet <pipcet <at> protonmail.com> wrote:
>"Lynn Winebarger" <owinebar <at> gmail.com> writes:
>
>> On Fri, Jun 13, 2025 at 10:02 AM Daniel Colascione <dancol <at> dancol.org> wrote:
>>>
>>>
>>>
>>> On June 13, 2025 6:42:58 AM PDT, Daniel Colascione <dancol <at> dancol.org> wrote:
>>> >
>>> >
>>> >On June 13, 2025 5:23:34 AM PDT, Lynn Winebarger <owinebar <at> gmail.com> wrote:
>>> >>On Fri, Jun 13, 2025, 2:26 AM Eli Zaretskii <eliz <at> gnu.org> wrote:
>>> >>
>>> >>> > From: Daniel Colascione <dancol <at> dancol.org>
>>> >>> > Cc: Eli Zaretskii <eliz <at> gnu.org>,  monnier <at> iro.umontreal.ca,
>>> >>> >   78737 <at> debbugs.gnu.org
>>> >>> > Date: Thu, 12 Jun 2025 11:48:50 -0700
>>> >>> >
>>> >>> > Pip Cet <pipcet <at> protonmail.com> writes:
>>> >>> >
>>> >>> > > I'd like read-event, when called while inhibit-quit is t, to report
>>> >>> > > quits by setting quit-flag in addition to returning quit_char: it'll
>>> >>> > > simplify the C code, and it would make
>>> >>> > >
>>> >>> > > (while t
>>> >>> > >   (let ((inhibit-quit t))
>>> >>> > >     (read-event)))
>>> >>> >
>>> >>> > I strongly disagree.  read-event should read an event.
>>> >>> > Setting quit-flag by side effect when it happens to read one key and not
>>> >>> > others makes the interface less regular and understandable.
>>> >>>
>>> >>> We should start by agreeing that the capability of interrupting a
>>> >>> running Lisp program is a real need.  Are we in agreement about that?
>>> >>> If not, let's first hear the arguments why not.
>>> >>>
>>> >>> If we _are_ in agreement about that, we should discuss how this should
>>> >>> be possible if read-event (and perhaps others?) return C-g instead of
>>> >>> raising quit-flag.  The alternatives mentioned until now are:
>>> >>>
>>> >>>  . restore the old behavior, whereby C-g interrupts read-event
>>> >>>  . have a variable that, if set, will restore the old behavior in
>>> >>>    read-event and other affected primitives, to be interruptible by a
>>> >>>    single C-g
>>> >>>  . make two C-g presses "in quick succession" set quit-flag, IOW
>>> >>>    "C-g C-g" will have the same effect as C-g previously
>>> >>>
>>> >>> Are there other alternatives?
>>> >>>
>>> >>
>>> >>What about keeping a (possibly buffer-local?) lisp variable holding a list
>>> >>of keystrokes mapped to thunks that are treated as generating lisp machine
>>> >>"interrupts"?  The key strokes would be processed by C machinery and never
>>> >>seen directly by lisp code and not be considered "events".
>>> >>Then C-g could be bound to a thunk signalling quit, and the effect of
>>> >>"inhibit-quit" achieved by removing C-g from the list in a given dynamic
>>> >>scope.  Then user code could make other key-strokes "special" without
>>> >>resorting to read-event.  For example, this read-event call in term.el:
>>> >>(message "Hit space to flush")
>>> >>      (let ((ch (read-event)))
>>> >> (if (eq ch ?\s)
>>> >>     (set-window-configuration conf)
>>> >>   (push ch unread-command-events)))
>>> >>
>>> >>Could be replaced by something like
>>> >>(with-interrupts ((?\s (signal term-flush)))
>>> >>  (condition-case nil
>>> >>    (while t (sit-for 100))
>>> >>     (term-flush (set-window-configuration conf))))
>>> >>
>>> >>Then some of these use-case concerns could be mooted altogether.
>>> >
>>> >We already have something like that. :-) read-event already runs
>>> > the events it reads through special-event-map, right? We don't
>>> > even need to create a separate thunk list concept: we could just
>>> > bind C-g in special event map and do what we want, right?
>
>> Would that provide the behavior Pip is looking for?
>
>It would not, because quits are currently processed out-of-order, and
>this important feature should remain in place for "serious" quits.  See
>below.

Not out of the box, true. In principle, though, it would be possible to scan special-event-map for single-key bindings and treat them all like we do quit_char for purposes of Lisp interruption, input discarding, and so on.

For example, while I'm debugging something, it'd actually be nice to have a single key to instantly invoke the debugger without having to deal with the inconvenience of debug-on-quit breaking into the debugger in a lot of places I would rather it not.

Likewise, it'd be convenient to have the ability to bind a key at a low level to something that would instantly launch and attach GDB without having to deal with the friction of creating a terminal, finding the Emacs PID, starting the debugger, and attaching by hand.

Not the most important thing to do right now, but there do seem to be actual use cases for binding behaviors to keys in the manner we do for quits.






Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 11:13:04 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, monnier <at> iro.umontreal.ca
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 14:11:56 +0300
> Date: Sat, 14 Jun 2025 06:54:58 -0400
> From: Daniel Colascione <dancol <at> dancol.org>
> CC: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com
> 
> >Pushing quitting to the application level is not something that will
> >be appreciated by Lisp programmers, I think.
> 
> We've been pushing quitting to applications for decades when these applications use the higher level input reading functions. Check out how we do it in, e.g. calc. I haven't seen any objections.

I know, but these arguments don't work when applications that didn't
do that in the past are suddenly required to do it.  What Calc does is
intentional, so why would we expect any objections in those cases?
Objections will come when code which didn't need to do this will be
required to do so.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sat, 14 Jun 2025 17:38:03 GMT) Full text and rfc822 format available.

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

From: Lynn Winebarger <owinebar <at> gmail.com>
To: Pip Cet <pipcet <at> protonmail.com>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 Daniel Colascione <dancol <at> dancol.org>,
 Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sat, 14 Jun 2025 13:36:59 -0400
[Message part 1 (text/plain, inline)]
On Sat, Jun 14, 2025, 2:28 AM Pip Cet <pipcet <at> protonmail.com> wrote:

> "Lynn Winebarger" <owinebar <at> gmail.com> writes:
>
> > On Fri, Jun 13, 2025 at 10:02 AM Daniel Colascione <dancol <at> dancol.org>
> wrote:
> >>
> >>
> >>
> >> On June 13, 2025 6:42:58 AM PDT, Daniel Colascione <dancol <at> dancol.org>
> wrote:
> >> >
> >> >We already have something like that. :-) read-event already runs
> >> > the events it reads through special-event-map, right? We don't
> >> > even need to create a separate thunk list concept: we could just
> >> > bind C-g in special event map and do what we want, right?
>
> > Would that provide the behavior Pip is looking for?
>
> It would not, because quits are currently processed out-of-order, and
> this important feature should remain in place for "serious" quits.  See
> below.
>
> >> >The only special thing about C-g is how we treat it when Lisp is
> >> > running. When it's instead reading an event, it can and be a
> >> > boring event processed the same way every other event is.
>
> > It seems to me what Pip is looking for is analogous to a "Quit" button
> > hardwired to a pin on a CPU, which is not something that can be
> > reliably implemented in the C primitives as they are now.
>
> You're suggesting I'm looking for something that cannot be implemented.
> I'm not.
>

That was not my intention.  I don't think that hard-wired behavior can be
reliably implemented one read_char has started processing an input event
off its queue.  There's just too many ways a keystroke can get consumed or
discarded that may not even be in the C primitives, as far as I can tell.
At least, that's what it looks like from a cursory reading of read_char.
It seems to me the most reliable way to guarantee C-g or any other
designated special input is treated specially is to make sure they don't
enter the queue processed by read_char at all.  And the most reliable way
to do that is probably to make the signal handler indicating keystrokes are
available, split the special keystrokes off into their own queue right from
the start.  How much actual processing might be done from the handler's
activation frame is a separate matter.  For example, the signal handler
could increment a quit count if it isn't already, then do something more
aggressive if the count exceeds some threshold, like throwing directly from
the signal handler rather than waiting for the C code to reach some point
safe for throwing.

>
> I described specific situations in which I think quit should be expanded
> to work better than it does now.  No one's expecting that quit works in
> absolutely every situation, as far as I know.  That's what gdb is for.
>

Actually, I'd love C-g to reliably interrupt Emacs when it appears locked
up and I have no idea why.  It's probably annoying to other users who don't
have a copy of Emacs built for debugging to not be able to kick Emacs out
of an infinite loop (or worse) as well.



> If you're referring to the "C-g C-g" thing, I did not describe how I'd
> implement it in detail, because there are many choices to be made; but
> the main idea would be that we should not immediately clear inhibit-quit
> for that combination, because that's a dangerous and destructive thing
> to do.  If we decide to do so (after a delay, for example), we need to
> print a clear warning to the user that their Emacs session needs
> restarting.
>
> So C-g C-g might do less than GUI C-g C-g C-g does currently.
>
> There are actions even more dangerous than clearing inhibit-quit.  I
> don't know whether we want a level-3 quit which does even more than the
> current GUI C-g C-g C-g code.
>

I don't really understand the necessity or use of inhibit-quit, as opposed
to, say, pushing a new quit handler or blocking input altogether, if the
consistency of the lisp machine state is a concern (e.g. to prevent
throwing from a signal handler).

Lynn
[Message part 2 (text/html, inline)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sun, 15 Jun 2025 06:39:02 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, dancol <at> dancol.org
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sun, 15 Jun 2025 02:38:14 -0400
>> >> What is "emergency quit"?
>> > Something like `C-g C-g C-g`, tho we don't have that implemented,
>> > currently, AFAIK.
>> I guess `kill -USR2` could count as well.
> Not as a single trigger, no: it isn't portable enough.

It's still a valid example of what I mean by "emergency quit":
a mechanism by which users can get out of (hopefully rare) "hangs" that
are due to ELisp coding mistakes.
But yes, it's not "good enough", so we want to offer another mechanism
such as `C-g C-g C-g`.


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sun, 15 Jun 2025 06:48:02 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>, pipcet <at> protonmail.com
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sun, 15 Jun 2025 02:47:34 -0400
> We should steer developers away from read-char and towards higher level
> features like read-key anyway, right?

+1


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sun, 15 Jun 2025 17:53:02 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Daniel Colascione <dancol <at> dancol.org>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>, pipcet <at> protonmail.com
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sun, 15 Jun 2025 13:52:16 -0400
> C-g C-g C-g --- urgent quit (breaks out of read-event. should probably
> break out of redisplay too?)

Side note: "breaking out of redisplay" is not straightforward for
various reasons, such as the fact that most places where we run ELisp
try and catch every non-local exit (tho we fail to catch some `throw`s,
IIRC), or the fact that non-local exits may leave some redisplay
data-structures in an inconsistent state, or the fact that even if we
sucessfully interrupt a redisplay hang, we're likely to fall right back
into it at the next redisplay (hence really soon).

> C-g C-g C-g C-g C-g C-g --- emergency quit. ignores inhibit-quit. good
> chance of horking your Emacs by violating atomicity assumptions.

Sometimes a single `C-g` is sufficient, but it can still take a short
while for Emacs to reply, so the user may hit `C-g` repeatedly without
necessarily meaning to break a "hard hang", so it would be nice to have
some way to distinguish the two.

> Display "are you sure?" message before final C-g.

That's indeed one way to distinguish the two, but of course, maybe
displaying that message could get us back into the hang.

Another (similar option) is to jump into the debugger (from where the
users can "continue" or jump to toplevel, but which can also fall back
into the hang the user is trying to get out of).


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sun, 15 Jun 2025 17:58:02 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: Gerd Möllmann <gerd.moellmann <at> gmail.com>,
 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, dancol <at> dancol.org,
 owinebar <at> gmail.com
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sun, 15 Jun 2025 13:57:11 -0400
>> I'd deprecate read-event TBH.

When I introduced `read-key` the intention was for it to make
`read-event` mostly obsolete, but the replacement is a slow process
because of ... details.

> If we want to do this, we should start by removing it from our own
> sources.  Currently, we use it in around 80 places.

+1


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sun, 15 Jun 2025 18:04:01 GMT) Full text and rfc822 format available.

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

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, dancol <at> dancol.org
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sun, 15 Jun 2025 14:03:16 -0400
> It seems this feature was originally known as "immediate quit".
> At some point the immediate_quit variable itself was removed, but the
> term seems appropriate regardless.  So I suggest that's how we
> call it.

Hmm... I thought the `immediate_quit` variable was used for yet another
notion of "immediate quit".  Maybe I'm confused.


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sun, 15 Jun 2025 18:07:02 GMT) Full text and rfc822 format available.

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

From: Pip Cet <pipcet <at> protonmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78737 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 Daniel Colascione <dancol <at> dancol.org>
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sun, 15 Jun 2025 18:06:32 +0000
"Stefan Monnier" <monnier <at> iro.umontreal.ca> writes:

>> We should steer developers away from read-char and towards higher level
>> features like read-key anyway, right?
>
> +1

I agree in principle, but right now it's unpredictable whether read-key
returns "7" for a C-g or signals a quit, at least when you use X and
your timing is a bit off.  The observed behavior is this:

If I suspend Emacs while it's in (read-key), type C-g in the suspended
window, and unsuspend it, I usually get a quit.  If I don't, I seem to
always get a 7.  (This is probably because the focus-in event and the
quit event arrive simultaneously, as far as read_char is concerned).

There are so many small buglets and unexplained oddities in this code
that I think an overhaul is needed.  We should probably open a new bug
for the general topic of how C-g relates to various kinds of quitting
(normal, urgent, emergency escape), and how it can be simplified (why do
we still have getcjmp? Is it for the MSDOS port exclusively?)

However, opening that bug would ideally involve a somewhat complete
description of the current, chaotic situation (read-key isn't the only
function that makes it depend on timing, or timers, how quits are
handled).  And that takes some time.  I mean things like "sometimes
unread-command-events get looked up in special-event-map, but usually
they don't".

But I suggest we fix the original easily-fixed sit-for bug in one of the
various minimally invasive ways we've found, and start out with a fresh
bug.  The current discussion is impossible for anyone else to read.

Pip





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78737; Package emacs. (Sun, 15 Jun 2025 20:04:01 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78737 <at> debbugs.gnu.org, pipcet <at> protonmail.com, dancol <at> dancol.org
Subject: Re: bug#78737: sit-for behavior changes when byte-compiled
Date: Sun, 15 Jun 2025 23:02:53 +0300
> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
> Cc: pipcet <at> protonmail.com,  78737 <at> debbugs.gnu.org,  dancol <at> dancol.org
> Date: Sun, 15 Jun 2025 14:03:16 -0400
> 
> > It seems this feature was originally known as "immediate quit".
> > At some point the immediate_quit variable itself was removed, but the
> > term seems appropriate regardless.  So I suggest that's how we
> > call it.
> 
> Hmm... I thought the `immediate_quit` variable was used for yet another
> notion of "immediate quit".  Maybe I'm confused.

It was used for interrupting potentially long operations.  The
mechanism had some subtle problems, so it was removed, but as result
we lost some of the abilities to break out of prolonged operations.




This bug report was last modified 3 days ago.

Previous Next


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