Package: emacs;
Reported by: Spencer Baugh <sbaugh <at> janestreet.com>
Date: Tue, 25 Mar 2025 15:12:02 UTC
Severity: normal
Found in version 30.1.50
Message #29 received at 77253 <at> debbugs.gnu.org (full text, mbox):
From: Spencer Baugh <sbaugh <at> janestreet.com> To: Juri Linkov <juri <at> linkov.net> Cc: 77253 <at> debbugs.gnu.org Subject: Re: bug#77253: 30.1.50; Support RET choosing the selected completion without rebinding arrow keys Date: Thu, 03 Apr 2025 13:52:44 -0400
Juri Linkov <juri <at> linkov.net> writes: >> - It's not necessarily obvious that closing the completions window will >> make the arrow keys operate in the minibuffer. Actually, maybe we >> should update the completion help text to say that? That might help a >> lot. > > Maybe it's possible to squeeze this help text just into one additional line? > Something like: > > Type 'C-g' to close this window and restore arrows to move point. Maybe we don't even need an additional line? How about: Click or type RET on a completion to select it, or C-g to close this window. Type <right>, <left>, <down>, <up> to move point between completions. >> - The new completion-eager-display makes *Completions* pop up >> immediately; when this happens, it can be surprising that the arrow >> keys don't work in the minibuffer from the very start of the >> minibuffer session. > > Then another possible value for 'minibuffer-visible-completions' > would be to not rebind left/right arrows when the completions window > contains only one column (like on the browser's address bar). True. Though I guess that could maybe be the default behavior when completions-format=one-column. >>> Not sure if it's possible for RET to accept the selected candidate >>> by default since users might prefer to accept text in the minibuffer. >> >> If there's a selected candidate, though, then users have already decided >> to use M-<up>/M-<down> to interact with completions. (Or they've >> switched to the completions buffer and selected one) >> >> If they decide they don't want the candidate they selected, and want to >> continue with text in the minibuffer, completion-auto-deselect will >> automatically deselect the candidate if they type anything. >> >> I think these two facts combined make it possible for RET to accept the >> selected candidate by default. > > Makes sense. So we need to try how well it performs. How about this? (BTW, after writing minibuffer--completions-visible, I'm wondering if most of the code which calls (get-buffer-window "*Completions*" 0) is actually buggy, because it's not checking completion-reference-buffer. Should we replace ~all the calls to (get-buffer-window "*Completions*" 0) with (minibuffer--completions-visible) which does check that?) diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index 404fa143194..c026e41a818 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -3209,6 +3209,12 @@ completion-help-at-point (define-key map "\n" 'exit-minibuffer) (define-key map "\r" 'exit-minibuffer)) +(defun minibuffer-choose-completion-just-exit (&optional no-exit) + "Choose the selected completion from the minibuffer or call `exit-minibuffer'." + (interactive "P") + (or (minibuffer-choose-completion-if-selected no-exit) + (minibuffer-exit))) + (defvar-keymap minibuffer-local-completion-map :doc "Local keymap for minibuffer input with completion." :parent minibuffer-local-map @@ -3218,6 +3224,7 @@ minibuffer-local-completion-map ;; another binding for it. ;; "M-TAB" #'minibuffer-force-complete "SPC" #'minibuffer-complete-word + "RET" #'minibuffer-choose-completion-just-exit "?" #'minibuffer-completion-help "<prior>" #'switch-to-completions "M-v" #'switch-to-completions @@ -3229,7 +3236,7 @@ minibuffer-local-completion-map (defvar-keymap minibuffer-local-must-match-map :doc "Local keymap for minibuffer input with completion, for exact match." :parent minibuffer-local-completion-map - "RET" #'minibuffer-complete-and-exit + "RET" #'minibuffer-choose-completion-or-exit "C-j" #'minibuffer-complete-and-exit) (defvar-keymap minibuffer-local-filename-completion-map @@ -3326,18 +3333,34 @@ minibuffer-visible-completions (defvar minibuffer-visible-completions--always-bind nil "If non-nil, force the `minibuffer-visible-completions' bindings on.") +(defun minibuffer--completions-visible () + "Return the window where the *Completions* buffer for this minibuffer is visible." + (when-let ((window (get-buffer-window "*Completions*" 0))) + (when (eq (buffer-local-value 'completion-reference-buffer + (window-buffer window)) + (window-buffer (active-minibuffer-window))) + window))) + +(defun minibuffer-choose-completion-if-selected (&optional no-exit no-quit) + "Like `minibuffer-choose-completion', but do nothing if no candidate is selected. + +Return non-nil if a completion was chosen." + (when-let* ((window (minibuffer--completions-visible))) + (with-selected-window window + ;; Detect selection as if `choose-completion-deselect-if-after' is nil. + (when (get-text-property (point) 'completion--string) + (choose-completion nil no-exit no-quit) + t)))) + (defun minibuffer-visible-completions--filter (cmd) "Return CMD if `minibuffer-visible-completions' bindings should be active." (if minibuffer-visible-completions--always-bind cmd - (when-let ((window (get-buffer-window "*Completions*" 0))) - (when (and (eq (buffer-local-value 'completion-reference-buffer - (window-buffer window)) - (window-buffer (active-minibuffer-window))) - (if (eq cmd #'minibuffer-choose-completion-or-exit) - (with-current-buffer (window-buffer window) - (get-text-property (point) 'completion--string)) - t)) + (when-let ((window (minibuffer--completions-visible))) + (when (if (eq cmd #'minibuffer-choose-completion-or-exit) + (with-current-buffer (window-buffer window) + (get-text-property (point) 'completion--string)) + t) cmd)))) (defun minibuffer-visible-completions--bind (binding) @@ -5109,10 +5132,8 @@ minibuffer-choose-completion-or-exit in the completions window, then exit the minibuffer using its present contents." (interactive "P") - (condition-case nil - (let ((choose-completion-deselect-if-after t)) - (minibuffer-choose-completion no-exit no-quit)) - (error (minibuffer-complete-and-exit)))) + (or (minibuffer-choose-completion-if-selected no-exit no-quit) + (minibuffer-complete-and-exit))) (defun minibuffer-complete-history () "Complete as far as possible using the minibuffer history.
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.