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

From: Stefan Monnier <[email-masked]>
Date: Thu, 03 Jul 2025 10:48:51 -0400

> I agree that calling keyboard-quit is better.

So, I suggest the patch below.

        Stefan
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)))