Subject: bug#78916: 31.0.50; C-g fails to exit loop

From: Stefan Monnier <[email-masked]>
Date: Mon, 30 Jun 2025 16:15:17 -0400

Eli Zaretskii [2025-06-30 22:00:02] wrote:

>> From: Stefan Monnier <[email-masked]>
>> Cc: Mike Kupfer <[email-masked]>,  [email-masked]
>> Date: Mon, 30 Jun 2025 12:01:02 -0400
>> 
>> >> > - Both keys behave like the "old C-g".
>> >> > ?
>> >> I'm fine with that.
>> > Same, but does it mean 'C-g' will do the same as 'q'?  If not, what is
>> > the difference between them?
>> 
>> Hmm... so `q` is bound to `exit` which consumes the key and exits the
>> Q&R loop.  In contrast `C-g` and `C-]` were bound to `quit` which is
>> not handled exlicitly by the Q&R loop, instead it just pushes the event
>> back on the `unread-commend-events` before exiting the loop, so in
>> Mike's test case, `q` exits the inner Q&R and passes to the next,
>> whereas `C-]` aborts all the subsequent Q&R calls after which it runs
>> the global binding of `C-[`.
>
> I think I understand what you are saying about the difference between
> 'q' and 'C-g', but I don't see any nested query-replace in Mike's test
> case, or what did I miss?  Or maybe I misunderstood what you mean by
> "the next"?

His Q&R call is inside a loop:

         (while (re-search-forward "bug#[[:digit:]]+:" nil t)
           (search-backward "(\"bug")
           (let (end (start (point)))
             (forward-sexp)
             (setq end (point))
             (query-replace-regexp "\\(\"bug#[[:digit:]]+:\\).*\"" "\\1\""
             		    nil start end))))

so when we exit one we enter the next (as long as there's another match
for the main regexp, that is).

> In practice, typing 'q' stops query-replace and leaves point at the
> last match where Emacs asked me whether to replace.  And 'C-g' does
> the same, AFAICT.
> If I'm right, then what would be an example where 'q' and 'C-g' would
> behave differently?

`C-g` (and `C-]`) behave just like "`q` followed by C-g/C-]".
Usually hitting C-g or C-] right after `q` has no effect, which is why
they are often perceived as doing the same, but in the above loop the
difference becomes more significant.

> In any case, this difference between 'q' and 'C-g' is not explained in
> the user manual.  The manual uses different wording to describe them,
> but my interpretation of the text is that they have the same effect.

So in effect we've had 3 "identical" yet subtly different behaviors for
years:

- The behavior of `q`: exit the Q&R and continue with whatever may follow.
- The behavior of `C-]`: exit the Q&R and also continue with whatever
  may follow, but without consuming the `C-]` so next time we read a key
  we'll get this `C-]`.
- The old behavior of `C-g` (which we definitely want to recover): abort
  the current command.

        Stefan