Subject: bug#78737: sit-for behavior changes when byte-compiled

From: Daniel Colascione <[email-masked]>
Date: Tue, 10 Jun 2025 08:06:46 -0700

On June 10, 2025 4:22:38 AM PDT, Stefan Monnier <[email-masked]> 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.