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

From: Pip Cet <[email-masked]>
Date: Sat, 14 Jun 2025 06:28:06 +0000

"Lynn Winebarger" <[email-masked]> writes:

> On Fri, Jun 13, 2025 at 10:02 AM Daniel Colascione <[email-masked]> wrote:
>>
>>
>>
>> On June 13, 2025 6:42:58 AM PDT, Daniel Colascione <[email-masked]> wrote:
>> >
>> >
>> >On June 13, 2025 5:23:34 AM PDT, Lynn Winebarger <[email-masked]> wrote:
>> >>On Fri, Jun 13, 2025, 2:26 AM Eli Zaretskii <[email-masked]> wrote:
>> >>
>> >>> > From: Daniel Colascione <[email-masked]>
>> >>> > Cc: Eli Zaretskii <[email-masked]>,  [email-masked],
>> >>> >   [email-masked]
>> >>> > Date: Thu, 12 Jun 2025 11:48:50 -0700
>> >>> >
>> >>> > Pip Cet <[email-masked]> 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