GNU bug report logs -
#78916
31.0.50; C-g fails to exit loop
Previous Next
To reply to this bug, email your comments to 78916 AT debbugs.gnu.org.
Toggle the display of automated, internal messages from the tracker.
Report forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Fri, 27 Jun 2025 21:37:02 GMT)
Full text and
rfc822 format available.
Acknowledgement sent
to
Mike Kupfer <kupfer <at> rawbw.com>
:
New bug report received and forwarded. Copy sent to
bug-gnu-emacs <at> gnu.org
.
(Fri, 27 Jun 2025 21:37:03 GMT)
Full text and
rfc822 format available.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Recipe from 'emacs -Q':
1. Save the test-data attachment to a file.
[test-data (text/plain, attachment)]
[Message part 3 (text/plain, inline)]
2. Evaluate the following defun:
(defun do-test ()
(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))))
3. Visit the test data file. With point at the start of the buffer, run
the do-test function, and press space a couple times. Now press C-g.
Expected behavior:
The do-test function stops executing, and point is left at the same
position where you pressed C-g. (This is the behavior I see with
Emacs 30 and with a build derived from Emacs master 648453c04d9.)
Observed behavior:
point progresses through the remaining sexps, without giving you any
query-replace prompt. When do-test has finished, point is now after
'"bug#78900:"'.
The git hash reported below by 'report-emacs-bug' includes a few Lisp
changes that I believe are unrelated to the issue, and which are
unchanged from the Emacs master build that works as expected. The
corresponding git hash from master (for the buggy build) is a002ca79ee7.
In GNU Emacs 31.0.50 (build 11, x86_64-pc-linux-gnu, X toolkit, cairo
version 1.16.0, Xaw scroll bars) of 2025-06-26 built on bach
Repository revision: 272a10db724bf17aa4af0e958d3b41c996d22c4a
Repository branch: master-mdk
Windowing system distributor 'The X.Org Foundation', version 11.0.12101007
System Description: Debian GNU/Linux 12 (bookworm)
Configured using:
'configure --prefix=/usr/new --enable-checking'
Configured features:
CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GSETTINGS HARFBUZZ JPEG
LIBSELINUX LIBXML2 MODULES NOTIFY INOTIFY PDUMPER PNG SECCOMP SOUND
THREADS TIFF TOOLKIT_SCROLL_BARS WEBP X11 XDBE XIM XPM LUCID ZLIB
Important settings:
value of $LC_TIME: C
value of $LANG: en_US.UTF-8
value of $XMODIFIERS: @im=ibus
locale-coding-system: utf-8-unix
Major mode: Shell
Minor modes in effect:
server-mode: t
shell-dirtrack-mode: t
delete-selection-mode: t
display-time-mode: t
global-eldoc-mode: t
eldoc-mode: t
show-paren-mode: t
mouse-wheel-mode: t
file-name-shadow-mode: t
global-font-lock-mode: t
font-lock-mode: t
minibuffer-regexp-mode: t
indent-tabs-mode: t
transient-mark-mode: t
auto-composition-mode: t
auto-encryption-mode: t
auto-compression-mode: t
Load-path shadows:
None found.
Features:
(shadow mh-identity mh-tool-bar mh-letter mh-show goto-addr thingatpt
gnus-cite mh-mime mh-acros mh-xface mh-utils emacsbug lisp-mnt files-x
mdk-mail gnus-mh gnus-msg mh-comp mh-scan mh-gnus gnus-dup nnmh
gnus-score score-mode gnus-art mm-uu mml2015 mm-view mml-smime smime
gnutls dig gnus-sum shr pixel-fill kinsoku url-file svg dom gnus-group
gnus-undo gnus-start gnus-dbus dbus xml gnus-cloud nnimap nnmail
browse-url xdg url url-proxy url-privacy url-expand url-methods
url-history url-cookie generate-lisp-file url-domsuf url-util url-parse
auth-source cl-seq eieio eieio-core cl-macs json map byte-opt gv
bytecomp byte-compile url-vars mail-source utf7 nnoo parse-time iso8601
gnus-spec gnus-int gnus-range gnus-win gnus nnheader range wid-edit mh-e
mh-buffers mh-loaddefs message sendmail mailcap yank-media puny dired
dired-loaddefs rfc822 mml mml-sec password-cache epa derived epg rfc6068
epg-config gnus-util text-property-search time-date mm-decode mm-bodies
mm-encode mail-parse rfc2231 rfc2047 rfc2045 mm-util ietf-drums
mail-prsvr mailabbrev mail-utils gmm-utils mailheader server warnings
timeclock noutline outline icons cc-mode cc-fonts cc-guess cc-menus
cc-cmds cc-styles cc-align cc-engine cc-vars cc-defs advice shell
pcomplete comint subr-x ansi-osc ansi-color ring xcscope delsel time vc
cl-loaddefs cl-lib vc-dispatcher mdk-hacks rmc iso-transl tooltip cconv
eldoc paren electric uniquify ediff-hook vc-hooks lisp-float-type
elisp-mode mwheel term/x-win x-win term/common-win x-dnd touch-screen
tool-bar dnd fontset image regexp-opt fringe tabulated-list replace
newcomment text-mode lisp-mode prog-mode register page tab-bar menu-bar
rfn-eshadow isearch easymenu timer select scroll-bar mouse jit-lock
font-lock syntax font-core term/tty-colors frame minibuffer nadvice seq
simple cl-generic indonesian philippine cham georgian utf-8-lang
misc-lang vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms
cp51932 hebrew greek romanian slovak czech european ethiopic indian
cyrillic chinese composite emoji-zwj charscript charprop case-table
epa-hook jka-cmpr-hook help abbrev obarray oclosure cl-preloaded button
loaddefs theme-loaddefs faces cus-face macroexp files window
text-properties overlay sha1 md5 base64 format env code-pages mule
custom widget keymap hashtable-print-readable backquote threads dbusbind
inotify dynamic-setting system-font-setting font-render-setting cairo
x-toolkit x multi-tty move-toolbar make-network-process tty-child-frames
emacs)
Memory information:
((conses 16 179700 20237) (symbols 48 18865 0) (strings 32 55102 2372)
(string-bytes 1 1569839) (vectors 16 32210)
(vector-slots 8 312579 6626) (floats 8 225 15) (intervals 56 310 0)
(buffers 984 13))
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Sat, 28 Jun 2025 06:52:02 GMT)
Full text and
rfc822 format available.
Message #8 received at 78916 <at> debbugs.gnu.org (full text, mbox):
> From: Mike Kupfer <kupfer <at> rawbw.com>
> Date: Fri, 27 Jun 2025 14:36:06 -0700
>
> Recipe from 'emacs -Q':
>
> 1. Save the test-data attachment to a file.
>
> 2. Evaluate the following defun:
>
> (defun do-test ()
> (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))))
>
> 3. Visit the test data file. With point at the start of the buffer, run
> the do-test function, and press space a couple times. Now press C-g.
>
> Expected behavior:
>
> The do-test function stops executing, and point is left at the same
> position where you pressed C-g. (This is the behavior I see with
> Emacs 30 and with a build derived from Emacs master 648453c04d9.)
>
> Observed behavior:
>
> point progresses through the remaining sexps, without giving you any
> query-replace prompt. When do-test has finished, point is now after
> '"bug#78900:"'.
>
> The git hash reported below by 'report-emacs-bug' includes a few Lisp
> changes that I believe are unrelated to the issue, and which are
> unchanged from the Emacs master build that works as expected. The
> corresponding git hash from master (for the buggy build) is a002ca79ee7.
I think the offending commit is this:
commit 772c4f036c38efd2a81d3643ad0bd718033d3b7f
Author: Stefan Monnier <monnier <at> iro.umontreal.ca>
AuthorDate: Thu May 22 09:32:33 2025 -0400
Commit: Stefan Monnier <monnier <at> iro.umontreal.ca>
CommitDate: Thu May 22 09:33:14 2025 -0400
(perform-replace): Make it work with F-keys in TTYs (bug#78113)
* lisp/replace.el (perform-replace): Use `read-key`.
* test/lisp/replace-tests.el (replace-tests-with-undo): Adjust accordingly.
The build from commit cb1b65f3923d5dcb88767f6736603ffbc4272557, 3
commits before that, doesn't exhibit this problem.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Sat, 28 Jun 2025 19:15:03 GMT)
Full text and
rfc822 format available.
Message #11 received at 78916 <at> debbugs.gnu.org (full text, mbox):
Hi Mike,
> 2. Evaluate the following defun:
>
> (defun do-test ()
> (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))))
>
> 3. Visit the test data file. With point at the start of the buffer, run
> the do-test function, and press space a couple times. Now press C-g.
>
> Expected behavior:
>
> The do-test function stops executing, and point is left at the same
> position where you pressed C-g. (This is the behavior I see with
> Emacs 30 and with a build derived from Emacs master 648453c04d9.)
>
> Observed behavior:
>
> point progresses through the remaining sexps, without giving you any
> query-replace prompt. When do-test has finished, point is now after
> '"bug#78900:"'.
[ Thanks for your report. I think this is a great data-point for the
recent discussion around making `read-event` consistently return `C-g`
(instead of signaling `quit`). ]
In `query-replace-map` we have:
(define-key map "\C-g" 'quit)
(define-key map "\C-]" 'quit)
In Emacs<31 `C-g` gave what you describe as "Expected behavior", and
`C-]` gave what you describe as "Observed behavior".
In `master`, they now both behave in the same way. I think the fact
that the behave the same way is good/right since they have the same
binding in the keymap.
So what do we want:
- Both keys behave like the "old C-g".
- Both keys behave like the "old C-]" (i.e. what we have now).
- Reintroduce the difference of behavior between `C-g` and `C-]`,
presumably by giving them different bindings in `query-replace-map.
Stefan
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Sat, 28 Jun 2025 23:29:04 GMT)
Full text and
rfc822 format available.
Message #14 received at 78916 <at> debbugs.gnu.org (full text, mbox):
Stefan Monnier wrote:
> In `master`, they now both behave in the same way. I think the fact
> that the behave the same way is good/right since they have the same
> binding in the keymap.
That makes sense.
> So what do we want:
>
> - Both keys behave like the "old C-g".
> - Both keys behave like the "old C-]" (i.e. what we have now).
> - Reintroduce the difference of behavior between `C-g` and `C-]`,
> presumably by giving them different bindings in `query-replace-map.
Is there a use case for the current behavior? I definitely want to have
the "old C-g" behavior available. I think it makes sense for C-g to
provide that behavior. Different bindings in query-replace-map seems
like a clean way to achieve that.
thanks,
mike
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Sun, 29 Jun 2025 05:15:04 GMT)
Full text and
rfc822 format available.
Message #17 received at 78916 <at> debbugs.gnu.org (full text, mbox):
> Cc: 78916 <at> debbugs.gnu.org
> From: Mike Kupfer <kupfer <at> rawbw.com>
> Comments: In-reply-to Stefan Monnier <monnier <at> iro.umontreal.ca>
> message dated "Sat, 28 Jun 2025 15:14:34 -0400."
> Date: Sat, 28 Jun 2025 16:28:32 -0700
>
> Stefan Monnier wrote:
>
> > So what do we want:
> >
> > - Both keys behave like the "old C-g".
> > - Both keys behave like the "old C-]" (i.e. what we have now).
> > - Reintroduce the difference of behavior between `C-g` and `C-]`,
> > presumably by giving them different bindings in `query-replace-map.
>
> Is there a use case for the current behavior? I definitely want to have
> the "old C-g" behavior available. I think it makes sense for C-g to
> provide that behavior.
Agreed.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Sun, 29 Jun 2025 16:18:01 GMT)
Full text and
rfc822 format available.
Message #20 received at 78916 <at> debbugs.gnu.org (full text, mbox):
>> > So what do we want:
>> >
>> > - Both keys behave like the "old C-g".
>> > - Both keys behave like the "old C-]" (i.e. what we have now).
>> > - Reintroduce the difference of behavior between `C-g` and `C-]`,
>> > presumably by giving them different bindings in `query-replace-map.
>>
>> Is there a use case for the current behavior? I definitely want to have
>> the "old C-g" behavior available. I think it makes sense for C-g to
>> provide that behavior.
>
> Agreed.
So IIUC the consensus is:
- Both keys behave like the "old C-g".
?
Stefan
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Sun, 29 Jun 2025 17:35:09 GMT)
Full text and
rfc822 format available.
Message #23 received at 78916 <at> debbugs.gnu.org (full text, mbox):
Stefan Monnier wrote:
> So IIUC the consensus is:
>
> - Both keys behave like the "old C-g".
>
> ?
I'm fine with that.
mike
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Mon, 30 Jun 2025 12:08:02 GMT)
Full text and
rfc822 format available.
Message #26 received at 78916 <at> debbugs.gnu.org (full text, mbox):
> From: Mike Kupfer <kupfer <at> rawbw.com>
> cc: Eli Zaretskii <eliz <at> gnu.org>, 78916 <at> debbugs.gnu.org
> Comments: In-reply-to Stefan Monnier <monnier <at> iro.umontreal.ca>
> message dated "Sun, 29 Jun 2025 12:17:20 -0400."
> Date: Sun, 29 Jun 2025 10:34:20 -0700
>
> Stefan Monnier wrote:
>
> > So IIUC the consensus is:
> >
> > - 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?
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Mon, 30 Jun 2025 16:02:01 GMT)
Full text and
rfc822 format available.
Message #29 received at 78916 <at> debbugs.gnu.org (full text, mbox):
>> > - 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 get the impression that the intention of the `replace.el` code when it
pushes the event back on `unread-commend-events` is to make it run
whichever binding is currently active "outside" (i.e. global or local
keymap).
IOW, we have many different ways to skin this cat and I'm not sure which
is best. We can do something like:
@@ -2491,7 +2491,7 @@ query-replace-map
(define-key map [f1] 'help)
(define-key map [help] 'help)
(define-key map "?" 'help)
- (define-key map "\C-g" 'quit)
- (define-key map "\C-]" 'quit)
+ (define-key map "\C-g" #'keyboard-quit)
+ (define-key map "\C-]" #'keyboard-quit)
(define-key map "\C-v" 'scroll-up)
(define-key map "\M-v" 'scroll-down)
or we can do something like:
@@ -3328,6 +3328,9 @@ perform-replace
(replace-dehighlight)
(save-excursion (recursive-edit))
(setq replaced t))
+ ((eq def 'quit)
+ ;; FIXME: Should we call `keyboard-quit'?
+ (signal 'quit nil))
((commandp def t)
(call-interactively def))
;; Note: we do not need to treat `exit-prefix'
or we can do something like:
diff --git a/lisp/replace.el b/lisp/replace.el
index 9939273594f..62cabb45c09 100644
--- a/lisp/replace.el
+++ b/lisp/replace.el
@@ -2491,7 +2491,7 @@ query-replace-map
(define-key map [f1] 'help)
(define-key map [help] 'help)
(define-key map "?" 'help)
- (define-key map "\C-g" 'quit)
- (define-key map "\C-]" 'quit)
+ (define-key map "\C-g" 'normal-binding)
+ (define-key map "\C-]" 'normal-binding)
(define-key map "\C-]" 'quit)
(define-key map "\C-v" 'scroll-up)
(define-key map "\M-v" 'scroll-down)
@@ -3328,6 +3328,12 @@ perform-replace
(replace-dehighlight)
(save-excursion (recursive-edit))
(setq replaced t))
+ ((eq def 'normal-binding)
+ (let ((cmd (key-binding (vector key))))
+ (setq this-command cmd)
+ (setq keep-going nil)
+ (setq done t)
+ (execute-command cmd)))
((commandp def t)
(call-interactively def))
;; Note: we do not need to treat `exit-prefix'
I lean towards the first option.
Stefan
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Mon, 30 Jun 2025 18:16:03 GMT)
Full text and
rfc822 format available.
Message #32 received at 78916 <at> debbugs.gnu.org (full text, mbox):
"Stefan Monnier via \"Bug reports for GNU Emacs, the Swiss army knife of text editors\"" <bug-gnu-emacs <at> gnu.org> writes:
>>> > - 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 get the impression that the intention of the `replace.el` code when it
> pushes the event back on `unread-commend-events` is to make it run
> whichever binding is currently active "outside" (i.e. global or local
> keymap).
>
> IOW, we have many different ways to skin this cat and I'm not sure which
> is best.
I'd just like to speak out in favor of making read-key take an extra
argument to make it handle C-g the way read-event does; IIUC, the lack
of this argument is the real problem here. If we don't, we should be
very careful about replacing read-event by read-key, and revert most
such changes.
Switching from read-event to read-key should be possible without the
(sometimes) undesirable change in C-g behavior. That doesn't mean we
can't change the C-g/quit relationship at some future point; there's no
consensus to change behavior now (not even to make C-g and C-] the
same), so we shouldn't.
(I still think it would be easiest to give up on a single C-g signaling
a quit; if we move to requiring two C-g's, both of which are ordinary
input up to the point where the second one triggers a quit, all the
special cases go away.)
Pip
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Mon, 30 Jun 2025 19:01:02 GMT)
Full text and
rfc822 format available.
Message #35 received at 78916 <at> debbugs.gnu.org (full text, mbox):
> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
> Cc: Mike Kupfer <kupfer <at> rawbw.com>, 78916 <at> debbugs.gnu.org
> 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"?
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?
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.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Mon, 30 Jun 2025 19:15:04 GMT)
Full text and
rfc822 format available.
Message #38 received at 78916 <at> debbugs.gnu.org (full text, mbox):
> Date: Mon, 30 Jun 2025 18:15:40 +0000
> From: Pip Cet <pipcet <at> protonmail.com>
>
> (I still think it would be easiest to give up on a single C-g signaling
> a quit; if we move to requiring two C-g's, both of which are ordinary
> input up to the point where the second one triggers a quit, all the
> special cases go away.)
IMO, we will be lynched if we make such a change in Emacs.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Mon, 30 Jun 2025 19:41:03 GMT)
Full text and
rfc822 format available.
Message #41 received at 78916 <at> debbugs.gnu.org (full text, mbox):
Pip Cet <pipcet <at> protonmail.com> writes:
> "Stefan Monnier via \"Bug reports for GNU Emacs, the Swiss army knife of text editors\"" <bug-gnu-emacs <at> gnu.org> writes:
>
>>>> > - 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 get the impression that the intention of the `replace.el` code when it
>> pushes the event back on `unread-commend-events` is to make it run
>> whichever binding is currently active "outside" (i.e. global or local
>> keymap).
>>
>> IOW, we have many different ways to skin this cat and I'm not sure which
>> is best.
>
> I'd just like to speak out in favor of making read-key take an extra
> argument to make it handle C-g the way read-event does; IIUC, the lack
> of this argument is the real problem here. If we don't, we should be
> very careful about replacing read-event by read-key, and revert most
> such changes.
This patch (which doesn't include documentation changes yet) would make
(read-key prompt nil t)
DTRT, I think. I've looked at a few callers of read-key and they should
probably pass t as the can-quit argument, too, because most of them want
to quit for C-g and try to do so, with varying degrees of success.
I've yet to verify this fixes the original F-key issue which prompted
the change to read-key in the first place. It does appear to fix the
buggy behavior observed by the OP.
From dd850c5da3591e00dfd2fe1dd3e6d901a53e7176 Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet <at> protonmail.com>
Subject: [PATCH 1/3] Add optional 'can-quit' argument to 'read-key'
(bug#78916)
* lisp/subr.el (read-key): Add 'can-quit' argument and pass it on.
* src/callint.c (Fcall_interactively):
* src/keyboard.c (command_loop_1):
(read_menu_command): Adjust accordingly.
(read_key_sequence): Quit after read_char if can_quit is set.
(read_key_sequence_vs):
(Fread_key_sequence):
(Fread_key_sequence_vector): Add extra argument.
---
lisp/subr.el | 5 +++--
src/callint.c | 4 ++--
src/keyboard.c | 32 ++++++++++++++++++++------------
3 files changed, 25 insertions(+), 16 deletions(-)
diff --git a/lisp/subr.el b/lisp/subr.el
index 69f6e4dbab8..b06d45d449f 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -3425,7 +3425,7 @@ read-key-full-map
(defvar read-key-delay 0.01) ;Fast enough for 100Hz repeat rate, hopefully.
-(defun read-key (&optional prompt disable-fallbacks)
+(defun read-key (&optional prompt disable-fallbacks can-quit)
"Read a key from the keyboard, return the event thus read.
Contrary to `read-event' this will not return a raw event but instead will
obey the input decoding and translations usually done by `read-key-sequence'.
@@ -3505,7 +3505,8 @@ read-key
map))
(let* ((keys
(catch 'read-key (read-key-sequence-vector prompt nil t
- nil nil t)))
+ nil nil t
+ can-quit)))
(key (aref keys 0)))
(if (and (> (length keys) 1)
(memq key '(mode-line header-line tab-line
diff --git a/src/callint.c b/src/callint.c
index e0246e5d594..38ffa8804d3 100644
--- a/src/callint.c
+++ b/src/callint.c
@@ -538,7 +538,7 @@ DEFUN ("call-interactively", Fcall_interactively, Scall_interactively, 1, 3, 0,
Qface, Qminibuffer_prompt, callint_message);
args[i] = Fread_key_sequence (callint_message,
Qnil, Qnil, Qnil, Qnil,
- Qnil);
+ Qnil, Qnil);
unbind_to (speccount1, Qnil);
visargs[i] = Fkey_description (args[i], Qnil);
@@ -569,7 +569,7 @@ DEFUN ("call-interactively", Fcall_interactively, Scall_interactively, 1, 3, 0,
Qface, Qminibuffer_prompt, callint_message);
args[i] = Fread_key_sequence_vector (callint_message,
Qnil, Qt, Qnil, Qnil,
- Qnil);
+ Qnil, Qnil);
visargs[i] = Fkey_description (args[i], Qnil);
unbind_to (speccount1, Qnil);
diff --git a/src/keyboard.c b/src/keyboard.c
index 8b2ebd215d2..93149910fa7 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -1311,7 +1311,7 @@ some_mouse_moved (void)
enum { READ_KEY_ELTS = 30 };
static int read_key_sequence (Lisp_Object *, Lisp_Object,
- bool, bool, bool, bool, bool);
+ bool, bool, bool, bool, bool, bool);
static void adjust_point_for_property (ptrdiff_t, bool);
static Lisp_Object
@@ -1422,7 +1422,7 @@ command_loop_1 (void)
raw_keybuf_count = 0;
Lisp_Object keybuf[READ_KEY_ELTS];
int i = read_key_sequence (keybuf, Qnil, false, true, true, false,
- false);
+ false, false);
/* A filter may have run while we were reading the input. */
if (! FRAME_LIVE_P (XFRAME (selected_frame)))
@@ -1698,7 +1698,7 @@ read_menu_command (void)
Lisp_Object keybuf[READ_KEY_ELTS];
int i = read_key_sequence (keybuf, Qnil, false, true, true, true,
- false);
+ false, false);
unbind_to (count, Qnil);
@@ -10544,7 +10544,7 @@ restore_reading_key_sequence (int old_reading_key_sequence)
read_key_sequence (Lisp_Object *keybuf, Lisp_Object prompt,
bool dont_downcase_last, bool can_return_switch_frame,
bool fix_current_buffer, bool prevent_redisplay,
- bool disable_text_conversion_p)
+ bool disable_text_conversion_p, bool can_quit)
{
specpdl_ref count = SPECPDL_INDEX ();
@@ -10867,6 +10867,11 @@ read_key_sequence (Lisp_Object *keybuf, Lisp_Object prompt,
key = read_char (prevent_redisplay ? -2 : NILP (prompt),
current_binding, last_nonmenu_event,
&used_mouse_menu, NULL);
+ if (can_quit && EQ (key, make_fixnum (quit_char)))
+ {
+ Vquit_flag = Qt;
+ maybe_quit ();
+ }
used_mouse_menu_history[t] = used_mouse_menu;
if ((FIXNUMP (key) && XFIXNUM (key) == -2) /* wrong_kboard_jmpbuf */
/* When switching to a new tty (with a new keyboard),
@@ -11546,7 +11551,8 @@ read_key_sequence_vs (Lisp_Object prompt, Lisp_Object continue_echo,
Lisp_Object dont_downcase_last,
Lisp_Object can_return_switch_frame,
Lisp_Object cmd_loop, bool allow_string,
- bool disable_text_conversion)
+ bool disable_text_conversion,
+ bool can_quit)
{
specpdl_ref count = SPECPDL_INDEX ();
@@ -11574,7 +11580,7 @@ read_key_sequence_vs (Lisp_Object prompt, Lisp_Object continue_echo,
Lisp_Object keybuf[READ_KEY_ELTS];
int i = read_key_sequence (keybuf, prompt, ! NILP (dont_downcase_last),
! NILP (can_return_switch_frame), false, false,
- disable_text_conversion);
+ disable_text_conversion, can_quit);
#if 0 /* The following is fine for code reading a key sequence and
then proceeding with a lengthy computation, but it's not good
@@ -11596,7 +11602,7 @@ read_key_sequence_vs (Lisp_Object prompt, Lisp_Object continue_echo,
(i, keybuf)));
}
-DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 6, 0,
+DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 7, 0,
doc: /* Read a sequence of keystrokes and return as a string or vector.
The sequence is sufficient to specify a non-prefix command in the
current local and global maps.
@@ -11650,23 +11656,25 @@ Second (optional) arg CONTINUE-ECHO, if non-nil, means this key echos
being sent. */)
(Lisp_Object prompt, Lisp_Object continue_echo, Lisp_Object dont_downcase_last,
Lisp_Object can_return_switch_frame, Lisp_Object cmd_loop,
- Lisp_Object disable_text_conversion)
+ Lisp_Object disable_text_conversion, Lisp_Object can_quit)
{
return read_key_sequence_vs (prompt, continue_echo, dont_downcase_last,
can_return_switch_frame, cmd_loop, true,
- !NILP (disable_text_conversion));
+ !NILP (disable_text_conversion),
+ !NILP (can_quit));
}
DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector,
- Sread_key_sequence_vector, 1, 6, 0,
+ Sread_key_sequence_vector, 1, 7, 0,
doc: /* Like `read-key-sequence' but always return a vector. */)
(Lisp_Object prompt, Lisp_Object continue_echo, Lisp_Object dont_downcase_last,
Lisp_Object can_return_switch_frame, Lisp_Object cmd_loop,
- Lisp_Object disable_text_conversion)
+ Lisp_Object disable_text_conversion, Lisp_Object can_quit)
{
return read_key_sequence_vs (prompt, continue_echo, dont_downcase_last,
can_return_switch_frame, cmd_loop, false,
- !NILP (disable_text_conversion));
+ !NILP (disable_text_conversion),
+ !NILP (can_quit));
}
/* Return true if input events are pending. */
--
2.50.0
From 395ec08d4f5d31f2d6d6022fb40c4c90d44b8aeb Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet <at> protonmail.com>
Subject: [PATCH 2/3] Make C-g quit again in perform-replace (bug#78916)
* lisp/replace.el (perform-replace): Pass 't' as 'can-quit' argument
to 'read-key'.
---
lisp/replace.el | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lisp/replace.el b/lisp/replace.el
index 9939273594f..1d115949599 100644
--- a/lisp/replace.el
+++ b/lisp/replace.el
@@ -3103,7 +3103,7 @@ perform-replace
replacement-presentation))))
;; Use `read-key' so that escape sequences on TTYs
;; are properly mapped back to the intended key.
- (setq key (read-key prompt)))
+ (setq key (read-key prompt nil t)))
;; Necessary in case something happens during
;; read-event that clobbers the match data.
(set-match-data real-match-data)
--
2.50.0
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Mon, 30 Jun 2025 20:16:02 GMT)
Full text and
rfc822 format available.
Message #44 received at 78916 <at> debbugs.gnu.org (full text, mbox):
Eli Zaretskii [2025-06-30 22:00:02] wrote:
>> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
>> Cc: Mike Kupfer <kupfer <at> rawbw.com>, 78916 <at> debbugs.gnu.org
>> 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
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Tue, 01 Jul 2025 11:47:02 GMT)
Full text and
rfc822 format available.
Message #47 received at 78916 <at> debbugs.gnu.org (full text, mbox):
> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
> Cc: kupfer <at> rawbw.com, 78916 <at> debbugs.gnu.org
> Date: Mon, 30 Jun 2025 16:15:17 -0400
>
> Eli Zaretskii [2025-06-30 22:00:02] wrote:
>
> >> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
> >> Cc: Mike Kupfer <kupfer <at> rawbw.com>, 78916 <at> debbugs.gnu.org
> >> 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).
OK, but then the issue here is not about query-replace-regexp at all,
isn't it? It's about whether C-g is "re-read" after exiting
query-replace-regexp, and when it is re-read, does it quit. Or am I
missing something?
> > 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.
If C-g is not consumed, it will produce the expected effect, right?
If so, the problem seems to be that this is what's expected here, and
it happened in the past because C-g would quite right away, so there
was no need to re-read it. Right?
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Tue, 01 Jul 2025 20:48:03 GMT)
Full text and
rfc822 format available.
Message #50 received at 78916 <at> debbugs.gnu.org (full text, mbox):
>> 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).
>
> OK, but then the issue here is not about query-replace-regexp at all,
> isn't it? It's about whether C-g is "re-read" after exiting
> query-replace-regexp, and when it is re-read, does it quit. Or am I
> missing something?
I think you're right. Which is why I think the intention was not to
"unread it" but rather to give it its "normal" behavior (which the code
tries to do by "unreading" the input, but failing to take into account
that there's no guarantee exiting Q&R will get us back to a normal
command loop).
>> - 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.
> If C-g is not consumed, it will produce the expected effect, right?
Hmm... it depends what happens when we exit Q&R and what you think is
"the expected effect".
> If so, the problem seems to be that this is what's expected here,
I don't know what you're trying to say here.
> and it happened in the past because C-g would quite right away, so
> there was no need to re-read it. Right?
I agree that we want to signal `quit` right away here (and I think both
for `C-g` and for `C-]`) rather than "unread" them. The question is how
we want to do it:
- (signal 'quit nil)
- call `keyboard-quit`.
- call whatever is bound to `C-g` in the normal keymaps.
[ With a subsidiary question of whether we do it by changing the code
that handles a key bound to `quit` or whether we just change the
binding to something else like `keyboard-quit`. ]
Stefan
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Wed, 02 Jul 2025 02:12:04 GMT)
Full text and
rfc822 format available.
Message #53 received at 78916 <at> debbugs.gnu.org (full text, mbox):
[[[ To any NSA and FBI agents reading my email: please consider ]]]
[[[ whether defending the US Constitution against all enemies, ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]
C-g and C-] are intentionally different. C-g quits out of commands,
while C-] exis a recursive edit. The two commands exist because
they are different, and both useful.
We want to fix the bug that affects C-g. But what should C-] do here?
Its definition is to quit out of the innermos recursive edit.
But I don't think there is a recursive edit going on in this example.
query-replace-regexp doesn't use a recursive edit to read
the user's input.
Quitting out of the current command seems like a reaosnable think
for C-] to do when there is no recursive edit in progress.
--
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Wed, 02 Jul 2025 02:14:05 GMT)
Full text and
rfc822 format available.
Message #56 received at 78916 <at> debbugs.gnu.org (full text, mbox):
[[[ To any NSA and FBI agents reading my email: please consider ]]]
[[[ whether defending the US Constitution against all enemies, ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]
C-g and C-] are intentionally different. C-g quits out of commands,
while C-] exis a recursive edit. The two commands exist because
they are different, and both useful.
We want to fix the bug that affects C-g. But what should C-] do here?
Its definition is to quit out of the innermos recursive edit.
But I don't think there is a recursive edit going on in this example.
query-replace-regexp doesn't use a recursive edit to read
the user's input.
Quitting out of the current command seems like a reaosnable think
for C-] to do when there is no recursive edit in progress.
--
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Wed, 02 Jul 2025 11:38:02 GMT)
Full text and
rfc822 format available.
Message #59 received at 78916 <at> debbugs.gnu.org (full text, mbox):
> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
> Cc: kupfer <at> rawbw.com, 78916 <at> debbugs.gnu.org
> Date: Tue, 01 Jul 2025 16:47:40 -0400
>
> > and it happened in the past because C-g would quite right away, so
> > there was no need to re-read it. Right?
>
> I agree that we want to signal `quit` right away here (and I think both
> for `C-g` and for `C-]`) rather than "unread" them. The question is how
> we want to do it:
>
> - (signal 'quit nil)
> - call `keyboard-quit`.
> - call whatever is bound to `C-g` in the normal keymaps.
If you explain the difference between the first tow, I could try
making up my mind.
> [ With a subsidiary question of whether we do it by changing the code
> that handles a key bound to `quit` or whether we just change the
> binding to something else like `keyboard-quit`. ]
Currently 'quit' in replace.el is not handled, so it is a kind-of
dummy binding. It doesn't have any code that handles it. Or what did
I miss?
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Wed, 02 Jul 2025 11:40:02 GMT)
Full text and
rfc822 format available.
Message #62 received at 78916 <at> debbugs.gnu.org (full text, mbox):
> From: Richard Stallman <rms <at> gnu.org>
> Cc: eliz <at> gnu.org, 78916 <at> debbugs.gnu.org, kupfer <at> rawbw.com
> Date: Tue, 01 Jul 2025 22:10:44 -0400
>
> C-g and C-] are intentionally different. C-g quits out of commands,
> while C-] exis a recursive edit. The two commands exist because
> they are different, and both useful.
That is true in general, but we are talking about the effects of these
two inside query-replace, where they both are bound to the same
function.
> We want to fix the bug that affects C-g. But what should C-] do here?
>
> Its definition is to quit out of the innermos recursive edit.
> But I don't think there is a recursive edit going on in this example.
> query-replace-regexp doesn't use a recursive edit to read
> the user's input.
>
> Quitting out of the current command seems like a reaosnable think
> for C-] to do when there is no recursive edit in progress.
Exactly. So in this case C-g and C-] are supposed to have the same
effect, I think.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Wed, 02 Jul 2025 14:15:02 GMT)
Full text and
rfc822 format available.
Message #65 received at 78916 <at> debbugs.gnu.org (full text, mbox):
>> > and it happened in the past because C-g would quite right away, so
>> > there was no need to re-read it. Right?
>>
>> I agree that we want to signal `quit` right away here (and I think both
>> for `C-g` and for `C-]`) rather than "unread" them. The question is how
>> we want to do it:
>>
>> - (signal 'quit nil)
>> - call `keyboard-quit`.
>> - call whatever is bound to `C-g` in the normal keymaps.
>
> If you explain the difference between the first tow, I could try
> making up my mind.
I know as much as you do in this respect (i.e. the difference is
whatever `keyboard-quit` does before calling `(signal 'quit nil)`).
Also:
- (signal 'quit nil) is what C-g does/did when we use(d) `read-event`.
- `keyboard-quit` is what `C-g` does when it's handled via the global-map.
To me, the current situation sounds like a case where the `C-g` is
received by an "interactive loop" so I'd leaning towards handling it via
`keyboard-quit`, whereas (signal 'quit nil) is what is used when
interrupting *running* code.
>> [ With a subsidiary question of whether we do it by changing the code
>> that handles a key bound to `quit` or whether we just change the
>> binding to something else like `keyboard-quit`. ]
>
> Currently 'quit' in replace.el is not handled, so it is a kind-of
> dummy binding. It doesn't have any code that handles it. Or what did
> I miss?
Yes, "any" other symbol would be handled in the same way, i.e. it's
handled by the default code that unreads the event and exits the Q&R.
Stefan
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Thu, 03 Jul 2025 06:07:03 GMT)
Full text and
rfc822 format available.
Message #68 received at 78916 <at> debbugs.gnu.org (full text, mbox):
> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
> Cc: kupfer <at> rawbw.com, 78916 <at> debbugs.gnu.org
> Date: Wed, 02 Jul 2025 10:14:39 -0400
>
> >> > and it happened in the past because C-g would quite right away, so
> >> > there was no need to re-read it. Right?
> >>
> >> I agree that we want to signal `quit` right away here (and I think both
> >> for `C-g` and for `C-]`) rather than "unread" them. The question is how
> >> we want to do it:
> >>
> >> - (signal 'quit nil)
> >> - call `keyboard-quit`.
> >> - call whatever is bound to `C-g` in the normal keymaps.
> >
> > If you explain the difference between the first tow, I could try
> > making up my mind.
>
> I know as much as you do in this respect (i.e. the difference is
> whatever `keyboard-quit` does before calling `(signal 'quit nil)`).
>
> Also:
>
> - (signal 'quit nil) is what C-g does/did when we use(d) `read-event`.
> - `keyboard-quit` is what `C-g` does when it's handled via the global-map.
>
> To me, the current situation sounds like a case where the `C-g` is
> received by an "interactive loop" so I'd leaning towards handling it via
> `keyboard-quit`, whereas (signal 'quit nil) is what is used when
> interrupting *running* code.
I agree that calling keyboard-quit is better.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Thu, 03 Jul 2025 14:50:04 GMT)
Full text and
rfc822 format available.
Message #71 received at 78916 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
> I agree that calling keyboard-quit is better.
So, I suggest the patch below.
Stefan
[replace.patch (text/x-diff, inline)]
diff --git a/lisp/replace.el b/lisp/replace.el
index 9939273594f..f61a6445c4b 100644
--- a/lisp/replace.el
+++ b/lisp/replace.el
@@ -2491,16 +2491,17 @@ query-replace-map
(define-key map [f1] 'help)
(define-key map [help] 'help)
(define-key map "?" 'help)
- (define-key map "\C-g" 'quit)
- (define-key map "\C-]" 'quit)
- (define-key map "\C-v" 'scroll-up)
- (define-key map "\M-v" 'scroll-down)
- (define-key map [next] 'scroll-up)
- (define-key map [prior] 'scroll-down)
- (define-key map [?\C-\M-v] 'scroll-other-window)
- (define-key map [M-next] 'scroll-other-window)
- (define-key map [?\C-\M-\S-v] 'scroll-other-window-down)
- (define-key map [M-prior] 'scroll-other-window-down)
+ (define-key map "\C-g" #'keyboard-quit)
+ (define-key map "\C-]" #'keyboard-quit)
+ ;; FIXME: Should we use `scroll-(up|down)-command' here instead?
+ (define-key map "\C-v" #'scroll-up)
+ (define-key map "\M-v" #'scroll-down)
+ (define-key map [next] #'scroll-up)
+ (define-key map [prior] #'scroll-down)
+ (define-key map [?\C-\M-v] #'scroll-other-window)
+ (define-key map [M-next] #'scroll-other-window)
+ (define-key map [?\C-\M-\S-v] #'scroll-other-window-down)
+ (define-key map [M-prior] #'scroll-other-window-down)
;; Binding ESC would prohibit the M-v binding. Instead, callers
;; should check for ESC specially.
;; (define-key map "\e" 'exit-prefix)
@@ -2509,11 +2510,13 @@ query-replace-map
"Keymap of responses to questions posed by commands like `query-replace'.
The \"bindings\" in this map are not commands; they are answers.
The valid answers include `act', `skip', `act-and-show',
-`act-and-exit', `exit', `exit-prefix', `recenter', `scroll-up',
-`scroll-down', `scroll-other-window', `scroll-other-window-down',
-`edit', `edit-replacement', `edit-replacement-exact-case',
+`act-and-exit', `exit', `exit-prefix', `recenter', `edit',
+`edit-replacement', `edit-replacement-exact-case',
`delete-and-edit', `automatic', `backup', `undo', `undo-all',
-`quit', and `help'.
+and `help'.
+This said, valid answers can also be interactive functions.
+Functions that can make sense here include `scroll-up', `scroll-down',
+`scroll-other-window', `scroll-other-window-down', and `keyboard-quit'.
This keymap is used by `y-or-n-p' as well as `query-replace'.")
diff --git a/lisp/subr.el b/lisp/subr.el
index 69f6e4dbab8..0a1d676445b 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -4047,14 +4047,19 @@ y-or-n-p
((memq answer '(skip act)) nil)
((eq answer 'recenter)
(recenter) t)
+ ;; Explicitly handle the other non-commands, to avoid
+ ;; conflicts with possible commands of the same name.
+ ((memq answer '( act-and-show act-and-exit exit edit
+ edit-replacement edit-replacement-exact-case
+ delete-and-edit automatic backup
+ undo undo-all help))
+ t)
((eq answer 'scroll-up)
(ignore-errors (scroll-up-command)) t)
((eq answer 'scroll-down)
(ignore-errors (scroll-down-command)) t)
- ((eq answer 'scroll-other-window)
- (ignore-errors (scroll-other-window)) t)
- ((eq answer 'scroll-other-window-down)
- (ignore-errors (scroll-other-window-down)) t)
+ ((functionp answer)
+ (call-interactively answer) t)
((or (memq answer '(exit-prefix quit)) (eq key ?\e))
(signal 'quit nil) t)
(t t)))
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Thu, 03 Jul 2025 16:03:03 GMT)
Full text and
rfc822 format available.
Message #74 received at 78916 <at> debbugs.gnu.org (full text, mbox):
> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
> Cc: 78916 <at> debbugs.gnu.org, kupfer <at> rawbw.com
> Date: Thu, 03 Jul 2025 10:48:51 -0400
>
> > I agree that calling keyboard-quit is better.
>
> So, I suggest the patch below.
Thanks.
> diff --git a/lisp/subr.el b/lisp/subr.el
> index 69f6e4dbab8..0a1d676445b 100644
> --- a/lisp/subr.el
> +++ b/lisp/subr.el
> @@ -4047,14 +4047,19 @@ y-or-n-p
> ((memq answer '(skip act)) nil)
> ((eq answer 'recenter)
> (recenter) t)
> + ;; Explicitly handle the other non-commands, to avoid
> + ;; conflicts with possible commands of the same name.
> + ((memq answer '( act-and-show act-and-exit exit edit
> + edit-replacement edit-replacement-exact-case
> + delete-and-edit automatic backup
> + undo undo-all help))
> + t)
> ((eq answer 'scroll-up)
> (ignore-errors (scroll-up-command)) t)
> ((eq answer 'scroll-down)
> (ignore-errors (scroll-down-command)) t)
> - ((eq answer 'scroll-other-window)
> - (ignore-errors (scroll-other-window)) t)
> - ((eq answer 'scroll-other-window-down)
> - (ignore-errors (scroll-other-window-down)) t)
> + ((functionp answer)
> + (call-interactively answer) t)
Why not 'commandp'?
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Thu, 03 Jul 2025 17:44:02 GMT)
Full text and
rfc822 format available.
Message #77 received at 78916 <at> debbugs.gnu.org (full text, mbox):
"Stefan Monnier via \"Bug reports for GNU Emacs, the Swiss army knife of text editors\"" <bug-gnu-emacs <at> gnu.org> writes:
>> I agree that calling keyboard-quit is better.
>
> So, I suggest the patch below.
I'd just like to note that this breaks badly if quitchar is changed.
That doesn't mean we shouldn't apply this patch, it means we should
remove the vestigial support for changing quitchar from keyboard.c
(However, there are other good reason not to apply this patch, and
simply fix read-key to optionally allow quitting instead. There is no
reason to make Lisp users choose between having to handle quit
themselves (which currently requires mucking about with low-level input
details such as determining quitchar) and having to handle low-level
events themselves. Most users don't want to do either thing.
And we definitely need to fix
(while t (message "%S" (read-key)))
destroying your session. It's simply a bug in keyboard.c that this
isn't recognized by the triple-C-g code in GUI sessions, or the
double-C-g code in terminal sessions.
IMHO, no further replacements of read-event by read-key should be
performed until we've made the latter function less hostile to novice
Lisp hackers.)
Pip
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Thu, 03 Jul 2025 19:24:03 GMT)
Full text and
rfc822 format available.
Message #80 received at 78916 <at> debbugs.gnu.org (full text, mbox):
>> - ((eq answer 'scroll-other-window)
>> - (ignore-errors (scroll-other-window)) t)
>> - ((eq answer 'scroll-other-window-down)
>> - (ignore-errors (scroll-other-window-down)) t)
>> + ((functionp answer)
>> + (call-interactively answer) t)
>
> Why not 'commandp'?
No strong reason:
- `call-interactively` doesn't work on vectors and strings, only
on functions.
- I prefer an error about a function failing to be interactive than just
ignoring the binding.
But yeah, the second point also applies to strings and vectors, so maybe
it should be (or (functionp answer) (commandp answer)) or even
(or (functionp answer) (not (symbolp answer))) ?
Stefan
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Thu, 03 Jul 2025 19:28:02 GMT)
Full text and
rfc822 format available.
Message #83 received at 78916 <at> debbugs.gnu.org (full text, mbox):
> (However, there are other good reason not to apply this patch, and
> simply fix read-key to optionally allow quitting instead.
That wouldn't fix the `C-]` case.
Stefan
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Fri, 04 Jul 2025 06:09:02 GMT)
Full text and
rfc822 format available.
Message #86 received at 78916 <at> debbugs.gnu.org (full text, mbox):
> Cc: 78916 <at> debbugs.gnu.org, kupfer <at> rawbw.com
> Date: Thu, 03 Jul 2025 19:01:39 +0300
> From: Eli Zaretskii <eliz <at> gnu.org>
>
> > From: Stefan Monnier <monnier <at> iro.umontreal.ca>
> > Cc: 78916 <at> debbugs.gnu.org, kupfer <at> rawbw.com
> > Date: Thu, 03 Jul 2025 10:48:51 -0400
> >
> > > I agree that calling keyboard-quit is better.
> >
> > So, I suggest the patch below.
>
> Thanks.
Actually, shouldn't C-] invoke abort-recursive-edit instead? Wouldn't
'quit in the previous version do that, when abort-recursive-edit's
effect could be seen?
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Fri, 04 Jul 2025 06:44:01 GMT)
Full text and
rfc822 format available.
Message #89 received at 78916 <at> debbugs.gnu.org (full text, mbox):
> Date: Thu, 03 Jul 2025 17:43:25 +0000
> From: Pip Cet <pipcet <at> protonmail.com>
>
> "Stefan Monnier via \"Bug reports for GNU Emacs, the Swiss army knife of text editors\"" <bug-gnu-emacs <at> gnu.org> writes:
>
> >> I agree that calling keyboard-quit is better.
> >
> > So, I suggest the patch below.
>
> I'd just like to note that this breaks badly if quitchar is changed.
> That doesn't mean we shouldn't apply this patch, it means we should
> remove the vestigial support for changing quitchar from keyboard.c
I don't want to remove support for quit-char unless someone explains
that it cannot work well. But it is well known that changing
quit-char doesn't work well already. And if we decide to change all
the bindings of C-g to be bound to quit-char instead, it should be
trivial to fix this one as well, right?
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Fri, 04 Jul 2025 07:00:05 GMT)
Full text and
rfc822 format available.
Message #92 received at 78916 <at> debbugs.gnu.org (full text, mbox):
> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
> Cc: 78916 <at> debbugs.gnu.org, kupfer <at> rawbw.com
> Date: Thu, 03 Jul 2025 15:23:30 -0400
>
> >> - ((eq answer 'scroll-other-window)
> >> - (ignore-errors (scroll-other-window)) t)
> >> - ((eq answer 'scroll-other-window-down)
> >> - (ignore-errors (scroll-other-window-down)) t)
> >> + ((functionp answer)
> >> + (call-interactively answer) t)
> >
> > Why not 'commandp'?
>
> No strong reason:
>
> - `call-interactively` doesn't work on vectors and strings, only
> on functions.
> - I prefer an error about a function failing to be interactive than just
> ignoring the binding.
>
> But yeah, the second point also applies to strings and vectors, so maybe
> it should be (or (functionp answer) (commandp answer)) or even
> (or (functionp answer) (not (symbolp answer))) ?
Something like that, yes.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Fri, 04 Jul 2025 14:24:02 GMT)
Full text and
rfc822 format available.
Message #95 received at 78916 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
>> But yeah, the second point also applies to strings and vectors, so maybe
>> it should be (or (functionp answer) (commandp answer)) or even
>> (or (functionp answer) (not (symbolp answer))) ?
>
> Something like that, yes.
Together with
> Actually, shouldn't C-] invoke abort-recursive-edit instead? Wouldn't
> 'quit in the previous version do that, when abort-recursive-edit's
> effect could be seen?
Gives me the patch below.
Stefan
[replace.patch (text/x-diff, inline)]
diff --git a/lisp/replace.el b/lisp/replace.el
index 9939273594f..4010162150d 100644
--- a/lisp/replace.el
+++ b/lisp/replace.el
@@ -2491,16 +2491,17 @@ query-replace-map
(define-key map [f1] 'help)
(define-key map [help] 'help)
(define-key map "?" 'help)
- (define-key map "\C-g" 'quit)
- (define-key map "\C-]" 'quit)
- (define-key map "\C-v" 'scroll-up)
- (define-key map "\M-v" 'scroll-down)
- (define-key map [next] 'scroll-up)
- (define-key map [prior] 'scroll-down)
- (define-key map [?\C-\M-v] 'scroll-other-window)
- (define-key map [M-next] 'scroll-other-window)
- (define-key map [?\C-\M-\S-v] 'scroll-other-window-down)
- (define-key map [M-prior] 'scroll-other-window-down)
+ (define-key map "\C-g" #'keyboard-quit)
+ (define-key map "\C-]" #'abort-recursive-edit)
+ ;; FIXME: Should we use `scroll-(up|down)-command' here instead?
+ (define-key map "\C-v" #'scroll-up)
+ (define-key map "\M-v" #'scroll-down)
+ (define-key map [next] #'scroll-up)
+ (define-key map [prior] #'scroll-down)
+ (define-key map [?\C-\M-v] #'scroll-other-window)
+ (define-key map [M-next] #'scroll-other-window)
+ (define-key map [?\C-\M-\S-v] #'scroll-other-window-down)
+ (define-key map [M-prior] #'scroll-other-window-down)
;; Binding ESC would prohibit the M-v binding. Instead, callers
;; should check for ESC specially.
;; (define-key map "\e" 'exit-prefix)
@@ -2509,11 +2510,13 @@ query-replace-map
"Keymap of responses to questions posed by commands like `query-replace'.
The \"bindings\" in this map are not commands; they are answers.
The valid answers include `act', `skip', `act-and-show',
-`act-and-exit', `exit', `exit-prefix', `recenter', `scroll-up',
-`scroll-down', `scroll-other-window', `scroll-other-window-down',
-`edit', `edit-replacement', `edit-replacement-exact-case',
+`act-and-exit', `exit', `exit-prefix', `recenter', `edit',
+`edit-replacement', `edit-replacement-exact-case',
`delete-and-edit', `automatic', `backup', `undo', `undo-all',
-`quit', and `help'.
+and `help'.
+This said, valid answers can also be interactive functions.
+Functions that can make sense here include `scroll-up', `scroll-down',
+`scroll-other-window', `scroll-other-window-down', and `keyboard-quit'.
This keymap is used by `y-or-n-p' as well as `query-replace'.")
diff --git a/lisp/subr.el b/lisp/subr.el
index 69f6e4dbab8..3777ce07ac0 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -4047,17 +4047,20 @@ y-or-n-p
((memq answer '(skip act)) nil)
((eq answer 'recenter)
(recenter) t)
+ ;; Explicitly handle the other non-commands, to avoid
+ ;; conflicts with possible commands of the same name.
+ ((memq answer '( act-and-show act-and-exit exit edit
+ edit-replacement edit-replacement-exact-case
+ delete-and-edit automatic backup
+ undo undo-all help))
+ t)
((eq answer 'scroll-up)
(ignore-errors (scroll-up-command)) t)
((eq answer 'scroll-down)
(ignore-errors (scroll-down-command)) t)
- ((eq answer 'scroll-other-window)
- (ignore-errors (scroll-other-window)) t)
- ((eq answer 'scroll-other-window-down)
- (ignore-errors (scroll-other-window-down)) t)
((or (memq answer '(exit-prefix quit)) (eq key ?\e))
(signal 'quit nil) t)
- (t t)))
+ (t (call-interactively answer) t)))
(ding)
(discard-input)))
(t
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Fri, 04 Jul 2025 14:34:02 GMT)
Full text and
rfc822 format available.
Message #98 received at 78916 <at> debbugs.gnu.org (full text, mbox):
> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
> Cc: 78916 <at> debbugs.gnu.org, kupfer <at> rawbw.com
> Date: Fri, 04 Jul 2025 10:23:28 -0400
>
> >> But yeah, the second point also applies to strings and vectors, so maybe
> >> it should be (or (functionp answer) (commandp answer)) or even
> >> (or (functionp answer) (not (symbolp answer))) ?
> >
> > Something like that, yes.
>
> Together with
>
> > Actually, shouldn't C-] invoke abort-recursive-edit instead? Wouldn't
> > 'quit in the previous version do that, when abort-recursive-edit's
> > effect could be seen?
>
> Gives me the patch below.
LGTM, thanks.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Fri, 04 Jul 2025 18:07:02 GMT)
Full text and
rfc822 format available.
Message #101 received at 78916 <at> debbugs.gnu.org (full text, mbox):
> LGTM, thanks.
Hmm... I'm getting cold feet.
Having grep'd further for `query-replace-map` in *.el and *.texi files,
I'm beginning to think we should let those sleeping dogs lie: other uses
follow the pattern of `y-or-n-p` of not supporting "arbitrary" commands.
Most uses I found are in Emacs, but some are in third party packages, so
there's a non-trivial backward compatibility issue in changing the
bindings from `quit` to something like `keyboard-quit`.
So maybe the simpler patch below is preferable.
Stefan
diff --git a/lisp/replace.el b/lisp/replace.el
index 9939273594f..130c19763f2 100644
--- a/lisp/replace.el
+++ b/lisp/replace.el
@@ -3328,6 +3331,7 @@ perform-replace
(replace-dehighlight)
(save-excursion (recursive-edit))
(setq replaced t))
+ ((eq def 'quit) (keyboard-quit))
((commandp def t)
(call-interactively def))
;; Note: we do not need to treat `exit-prefix'
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Fri, 04 Jul 2025 18:17:02 GMT)
Full text and
rfc822 format available.
Message #104 received at 78916 <at> debbugs.gnu.org (full text, mbox):
"Stefan Monnier" <monnier <at> iro.umontreal.ca> writes:
>> (However, there are other good reason not to apply this patch, and
>> simply fix read-key to optionally allow quitting instead.
>
> That wouldn't fix the `C-]` case.
I'm not sure it's that important. It's not documented in
query-replace-help, and I'm not really sure whether it should behave
like C-g or ESC (or should ESC be fixed, too?) or any unbound key (like
"r").
But, sure, if we want to change the behavior of C-], that requires a
change beyond making C-g quit in our read-key call, because C-] is
ordinary input (and the binding in the map is relevant), unlike C-g.
The C-g case is documented (because C-g is documented for all of Emacs,
and exceptions are noted) and will behave inconsistently (interrupting a
timer in read-key will cause read-key to signal quit; if there's no
timer, we look up the key and perform a (keyboard-quit)) in the current
proposal. That may or may not be acceptable; adding the may-quit option
to read-key would fix the problem for most callers, including this one,
so it's a better solution.
Pip
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Fri, 04 Jul 2025 18:29:01 GMT)
Full text and
rfc822 format available.
Message #107 received at 78916 <at> debbugs.gnu.org (full text, mbox):
> (However, there are other good reason not to apply this patch, and
> simply fix read-key to optionally allow quitting instead.
The way I see it, part of this bug-report points out a bug in Q&R which
applies not just to `C-g` but also to `C-]`, i.e. to any key bound to
`quit` in `query-replace-map`, so what you suggest would just
re-circumvent that bug for the `C-g` case, leaving the other case broken.
IOW, I don't think your proposal and my patch are exclusive.
Regarding your proposal, I think it makes a lot of sense, especially to
make it easier to convert `read-event` calls to `read-key` (tho
I suspect it would be "more right" to call `keyboard-quit` rather than
`(signal 'quit nil), but that's a bikeshed color I'm not wedded to).
Stefan
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Fri, 04 Jul 2025 18:33:01 GMT)
Full text and
rfc822 format available.
Message #110 received at 78916 <at> debbugs.gnu.org (full text, mbox):
>>> (However, there are other good reason not to apply this patch, and
>>> simply fix read-key to optionally allow quitting instead.
>> That wouldn't fix the `C-]` case.
> I'm not sure it's that important. It's not documented in
> query-replace-help, and I'm not really sure whether it should behave
> like C-g or ESC (or should ESC be fixed, too?) or any unbound key (like
> "r").
The doc says:
‘quit’
Perform a quit right away. Only ‘y-or-n-p’ and related functions
use this answer.
and currently it doesn't perform a quit at all. To me, it's clear now
that the intention of the `C-]` binding in this keymap is to mimic the
global `C-]` binding, so the current behavior in Mike's test case is wrong.
Stefan
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Sat, 05 Jul 2025 06:33:03 GMT)
Full text and
rfc822 format available.
Message #113 received at 78916 <at> debbugs.gnu.org (full text, mbox):
> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
> Cc: 78916 <at> debbugs.gnu.org, kupfer <at> rawbw.com
> Date: Fri, 04 Jul 2025 14:06:13 -0400
>
> > LGTM, thanks.
>
> Hmm... I'm getting cold feet.
>
> Having grep'd further for `query-replace-map` in *.el and *.texi files,
> I'm beginning to think we should let those sleeping dogs lie: other uses
> follow the pattern of `y-or-n-p` of not supporting "arbitrary" commands.
> Most uses I found are in Emacs, but some are in third party packages, so
> there's a non-trivial backward compatibility issue in changing the
> bindings from `quit` to something like `keyboard-quit`.
>
> So maybe the simpler patch below is preferable.
>
>
> Stefan
>
>
> diff --git a/lisp/replace.el b/lisp/replace.el
> index 9939273594f..130c19763f2 100644
> --- a/lisp/replace.el
> +++ b/lisp/replace.el
> @@ -3328,6 +3331,7 @@ perform-replace
> (replace-dehighlight)
> (save-excursion (recursive-edit))
> (setq replaced t))
> + ((eq def 'quit) (keyboard-quit))
> ((commandp def t)
> (call-interactively def))
> ;; Note: we do not need to treat `exit-prefix'
>
>
But if the key that causes 'quit' can be re-read and re-executed after
exiting the replace, shouldn't we do that? Because AFAIU the above
will not make C-] behave as intended.
IOW, C-g might require special handling if it is bound to 'quit', but
other keys should be given back to the event queue. Right?
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Sat, 05 Jul 2025 06:37:02 GMT)
Full text and
rfc822 format available.
Message #116 received at 78916 <at> debbugs.gnu.org (full text, mbox):
> Date: Fri, 04 Jul 2025 18:16:29 +0000
> From: Pip Cet <pipcet <at> protonmail.com>
> Cc: Eli Zaretskii <eliz <at> gnu.org>, 78916 <at> debbugs.gnu.org, kupfer <at> rawbw.com
>
> "Stefan Monnier" <monnier <at> iro.umontreal.ca> writes:
>
> >> (However, there are other good reason not to apply this patch, and
> >> simply fix read-key to optionally allow quitting instead.
> >
> > That wouldn't fix the `C-]` case.
>
> I'm not sure it's that important. It's not documented in
> query-replace-help, and I'm not really sure whether it should behave
> like C-g or ESC (or should ESC be fixed, too?) or any unbound key (like
> "r").
C-] is documented in the manual as part of this catch-all:
Aside from this, any other character exits the ‘query-replace’, and
is then reread as part of a key sequence. Thus, if you type ‘C-k’, it
exits the ‘query-replace’ and then kills to end of line. In particular,
‘C-g’ simply exits the ‘query-replace’.
> The C-g case is documented (because C-g is documented for all of Emacs,
> and exceptions are noted)
C-g is documented specially in query-replace, see above.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Sat, 05 Jul 2025 08:18:01 GMT)
Full text and
rfc822 format available.
Message #119 received at 78916 <at> debbugs.gnu.org (full text, mbox):
"Eli Zaretskii" <eliz <at> gnu.org> writes:
>> Date: Fri, 04 Jul 2025 18:16:29 +0000
>> From: Pip Cet <pipcet <at> protonmail.com>
>> Cc: Eli Zaretskii <eliz <at> gnu.org>, 78916 <at> debbugs.gnu.org, kupfer <at> rawbw.com
>>
>> "Stefan Monnier" <monnier <at> iro.umontreal.ca> writes:
>>
>> >> (However, there are other good reason not to apply this patch, and
>> >> simply fix read-key to optionally allow quitting instead.
>> >
>> > That wouldn't fix the `C-]` case.
>>
>> I'm not sure it's that important. It's not documented in
>> query-replace-help, and I'm not really sure whether it should behave
>> like C-g or ESC (or should ESC be fixed, too?) or any unbound key (like
>> "r").
> C-] is documented in the manual as part of this catch-all:
> Aside from this, any other character exits the ‘query-replace’, and
> is then reread as part of a key sequence. Thus, if you type ‘C-k’, it
> exits the ‘query-replace’ and then kills to end of line. In particular,
> ‘C-g’ simply exits the ‘query-replace’.
That is no longer accurate if we apply Stefan's fix, which will prevent
C-] from being reread over and over again in Mike's loop. The last
sentence contradicts the rest of it, too: if C-g is reread, it doesn't
simply exit the 'query-replace'.
So the documentation in the manual is contradictory and inaccurate, and
the documentation in query-replace-help is incomplete.
Pip
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Sat, 05 Jul 2025 08:24:02 GMT)
Full text and
rfc822 format available.
Message #122 received at 78916 <at> debbugs.gnu.org (full text, mbox):
"Stefan Monnier" <monnier <at> iro.umontreal.ca> writes:
>> (However, there are other good reason not to apply this patch, and
>> simply fix read-key to optionally allow quitting instead.
>
> The way I see it, part of this bug-report points out a bug in Q&R which
> applies not just to `C-g` but also to `C-]`, i.e. to any key bound to
> `quit` in `query-replace-map`, so what you suggest would just
> re-circumvent that bug for the `C-g` case, leaving the other case broken.
Serious question: doesn't it apply to ESC, too? It's exit-prefix, not
quit, but rereading it over and over again also breaks Mike's loop, I
think.
> IOW, I don't think your proposal and my patch are exclusive.
Oh. That makes sense, and installing the one-liner (or the first patch)
would fix things for now, and if we change the read-key call later,
nothing should break in terrible ways.
> I suspect it would be "more right" to call `keyboard-quit` rather than
> `(signal 'quit nil), but that's a bikeshed color I'm not wedded to).
I think usually, it's unpredictable for the user whether a C-g
interrupts a timer or other Lisp code, which causes us to signal quit,
or gets treated as input. So making the two behave differently will
result in surprising behavior.
Pip
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Sat, 05 Jul 2025 09:49:01 GMT)
Full text and
rfc822 format available.
Message #125 received at 78916 <at> debbugs.gnu.org (full text, mbox):
> Date: Sat, 05 Jul 2025 08:17:23 +0000
> From: Pip Cet <pipcet <at> protonmail.com>
> Cc: monnier <at> iro.umontreal.ca, 78916 <at> debbugs.gnu.org, kupfer <at> rawbw.com
>
> "Eli Zaretskii" <eliz <at> gnu.org> writes:
>
> >> Date: Fri, 04 Jul 2025 18:16:29 +0000
> >> From: Pip Cet <pipcet <at> protonmail.com>
> >> Cc: Eli Zaretskii <eliz <at> gnu.org>, 78916 <at> debbugs.gnu.org, kupfer <at> rawbw.com
> >>
> >> "Stefan Monnier" <monnier <at> iro.umontreal.ca> writes:
> >>
> >> >> (However, there are other good reason not to apply this patch, and
> >> >> simply fix read-key to optionally allow quitting instead.
> >> >
> >> > That wouldn't fix the `C-]` case.
> >>
> >> I'm not sure it's that important. It's not documented in
> >> query-replace-help, and I'm not really sure whether it should behave
> >> like C-g or ESC (or should ESC be fixed, too?) or any unbound key (like
> >> "r").
>
> > C-] is documented in the manual as part of this catch-all:
>
> > Aside from this, any other character exits the ‘query-replace’, and
> > is then reread as part of a key sequence. Thus, if you type ‘C-k’, it
> > exits the ‘query-replace’ and then kills to end of line. In particular,
> > ‘C-g’ simply exits the ‘query-replace’.
>
> That is no longer accurate if we apply Stefan's fix, which will prevent
> C-] from being reread over and over again in Mike's loop.
Which is why I suggested to augment that.
> The last sentence contradicts the rest of it, too: if C-g is reread,
> it doesn't simply exit the 'query-replace'.
When we know what change we will install and how it will affect C-g,
we can make that part more accurate.
> So the documentation in the manual is contradictory and inaccurate, and
> the documentation in query-replace-help is incomplete.
Are you talking about the documentation on the release branch (and the
behavior on that branch), or are you talking about the master branch?
If the latter, then this discussion is precisely how to make the code
behave like the documentation used to say.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Sat, 05 Jul 2025 14:38:02 GMT)
Full text and
rfc822 format available.
Message #128 received at 78916 <at> debbugs.gnu.org (full text, mbox):
>> Having grep'd further for `query-replace-map` in *.el and *.texi files,
>> I'm beginning to think we should let those sleeping dogs lie: other uses
>> follow the pattern of `y-or-n-p` of not supporting "arbitrary" commands.
>> Most uses I found are in Emacs, but some are in third party packages, so
>> there's a non-trivial backward compatibility issue in changing the
>> bindings from `quit` to something like `keyboard-quit`.
>>
>> So maybe the simpler patch below is preferable.
>>
>>
>> Stefan
>>
>>
>> diff --git a/lisp/replace.el b/lisp/replace.el
>> index 9939273594f..130c19763f2 100644
>> --- a/lisp/replace.el
>> +++ b/lisp/replace.el
>> @@ -3328,6 +3331,7 @@ perform-replace
>> (replace-dehighlight)
>> (save-excursion (recursive-edit))
>> (setq replaced t))
>> + ((eq def 'quit) (keyboard-quit))
>> ((commandp def t)
>> (call-interactively def))
>> ;; Note: we do not need to treat `exit-prefix'
> But if the key that causes 'quit' can be re-read and re-executed after
> exiting the replace, shouldn't we do that?
No, the documented behavior of the `quit` binding is to "Perform a quit
right away", and as Mike's example shows, we don't know that unreading
will do the right thing for us.
> Because AFAIU the above will not make C-] behave as intended.
Depends what you mean by "as intended".
> IOW, C-g might require special handling if it is bound to 'quit', but
> other keys should be given back to the event queue. Right?
IMO, if users want to give it back to the event queue, then they should
not give it a binding at all.
My point is that these bindings are used in more places than Q&R, so we
can't just change the bindings so easily.
Stefan
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Sat, 05 Jul 2025 14:44:02 GMT)
Full text and
rfc822 format available.
Message #131 received at 78916 <at> debbugs.gnu.org (full text, mbox):
>>> (However, there are other good reason not to apply this patch, and
>>> simply fix read-key to optionally allow quitting instead.
>>
>> The way I see it, part of this bug-report points out a bug in Q&R which
>> applies not just to `C-g` but also to `C-]`, i.e. to any key bound to
>> `quit` in `query-replace-map`, so what you suggest would just
>> re-circumvent that bug for the `C-g` case, leaving the other case broken.
>
> Serious question: doesn't it apply to ESC, too? It's exit-prefix, not
> quit, but rereading it over and over again also breaks Mike's loop, I
> think.
ESC is bound to `exit-prefix` which is documented as:
‘exit-prefix’
Like ‘exit’, but add the key that was pressed to
‘unread-command-events’ (*note Event Input Misc::).
so it looks OK to me: maybe it's not the behavior Mike would prefer, but
at least it's in line with what the doc says.
Stefan
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Sat, 05 Jul 2025 22:34:01 GMT)
Full text and
rfc822 format available.
Message #134 received at 78916 <at> debbugs.gnu.org (full text, mbox):
Stefan Monnier wrote:
> ESC is bound to `exit-prefix` which is documented as:
>
> ‘exit-prefix’
> Like ‘exit’, but add the key that was pressed to
> ‘unread-command-events’ (*note Event Input Misc::).
>
> so it looks OK to me: maybe it's not the behavior Mike would prefer, but
> at least it's in line with what the doc says.
I would assume that ESC gets added to the unread events so that the user
can type ESC-mumble intead of M-mumble. (Not that I actually know
anything about all the event processing details y'all have been talking
about. :-))
mike
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78916
; Package
emacs
.
(Sun, 06 Jul 2025 11:14:02 GMT)
Full text and
rfc822 format available.
Message #137 received at 78916 <at> debbugs.gnu.org (full text, mbox):
"Stefan Monnier" <monnier <at> iro.umontreal.ca> writes:
>>>> (However, there are other good reason not to apply this patch, and
>>>> simply fix read-key to optionally allow quitting instead.
>>>
>>> The way I see it, part of this bug-report points out a bug in Q&R which
>>> applies not just to `C-g` but also to `C-]`, i.e. to any key bound to
>>> `quit` in `query-replace-map`, so what you suggest would just
>>> re-circumvent that bug for the `C-g` case, leaving the other case broken.
>>
>> Serious question: doesn't it apply to ESC, too? It's exit-prefix, not
>> quit, but rereading it over and over again also breaks Mike's loop, I
>> think.
>
> ESC is bound to `exit-prefix` which is documented as:
>
> ‘exit-prefix’
> Like ‘exit’, but add the key that was pressed to
> ‘unread-command-events’ (*note Event Input Misc::).
>
> so it looks OK to me: maybe it's not the behavior Mike would prefer, but
> at least it's in line with what the doc says.
I think I'm terminally confused now.
I'm fine with ESC and C-] behaving in whatever way seems best to the
rest of you.
They're not mentioned in query-replace-help, and they're not mentioned
in emacs.info, so the only way to get an idea (correct or incorrect) of
how they behave is to read some Lisp (inspect a variable, at least) as
well as some of the documentation, right?
So I no longer think there are good reasons not to apply this patch;
some further work seems necessary (see below), but fixing this bug
should have priority.
We might want to consider offering a customization option to disable the
entire "unhandled commands cause an exit and get reread" behavior. It
seems extremely surprising to me, and it means any addition to
query-replace-map will break someone's muscle memory.
I'm still thinking about whether it's really the right thing to give
read-key a "quit" argument; we might want to invoke keyboard-quit
instead (this would require fixing the interrupted-timer thing), or we
might want to use new functions (read-key-sequence already has five
optional arguments, making it painful to use from Lisp even with eldoc).
Pip
This bug report was last modified 24 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.