Add minibuffer--completions-visible and use it

At various places, instead of just checking that there's any
window displaying a buffer named *Completions*, we should
additionally check that that *Completions* buffer is actually
for the current completion session.
minibuffer--completions-visible does that.

* lisp/comint.el (comint-complete-input-ring)
(comint-dynamic-list-completions): Call
minibuffer--completions-visible.
* lisp/minibuffer.el (minibuffer--completions-visible):
Add. (bug#77253)
(completion--do-completion, completions--post-command-update)
(completions--after-change, minibuffer-hide-completions)
(minibuffer-visible-completions)
(minibuffer-visible-completions--always-bind)
(minibuffer-visible-completions--filter)
(with-minibuffer-completions-window, minibuffer-complete-history)
(minibuffer-complete-defaults): Call
minibuffer--completions-visible.
* lisp/pcomplete.el (pcomplete-show-completions): Call
minibuffer--completions-visible.
* lisp/simple.el (switch-to-completions): Call
minibuffer--completions-visible.
* test/lisp/minibuffer-tests.el (completion-auto-help-test)
(completion-auto-select-test): Call
minibuffer--completions-visible.
This commit is contained in:
Spencer Baugh 2025-08-20 14:27:59 -04:00 committed by Juri Linkov
parent f0b987c32c
commit 3f7c16d858
5 changed files with 36 additions and 28 deletions

View file

@ -1197,7 +1197,7 @@ This function makes `comint-dynamic-list-input-ring' obsolete."
(ring-elements comint-input-ring)
(user-error "No history available")))
(completion-in-region-mode-predicate
(lambda () (get-buffer-window "*Completions*" 0))))
(lambda () (minibuffer--completions-visible))))
(completion-in-region
(comint-line-beginning-position) (point-max)
(completion-table-with-metadata
@ -3521,7 +3521,7 @@ The optional argument COMMON-SUBSTRING, if non-nil, should be a string
specifying a common substring for adding the faces
`completions-first-difference' and `completions-common-part' to
the completions."
(let ((window (get-buffer-window "*Completions*" 0)))
(let ((window (minibuffer--completions-visible)))
(setq completions (sort completions #'string-lessp))
(if (and (eq last-command this-command)
window (window-live-p window) (window-buffer window)

View file

@ -1616,7 +1616,7 @@ when the buffer's text is already an exact match."
(completed
(cond
((pcase completion-auto-help
('visible (get-buffer-window "*Completions*" 0))
('visible (minibuffer--completions-visible))
('always t))
(minibuffer-completion-help beg end))
(t (minibuffer-hide-completions)
@ -2677,13 +2677,13 @@ so that the update is less likely to interfere with user typing."
(defun completions--post-command-update ()
"Update displayed *Completions* buffer after command, once."
(remove-hook 'post-command-hook #'completions--post-command-update)
(when (and completion-eager-update (get-buffer-window "*Completions*" 0))
(when (and completion-eager-update (minibuffer--completions-visible))
(completions--background-update)))
(defun completions--after-change (_start _end _old-len)
"Update displayed *Completions* buffer after change in buffer contents."
(when (or completion-auto-deselect completion-eager-update)
(when-let* ((window (get-buffer-window "*Completions*" 0)))
(when-let* ((window (minibuffer--completions-visible)))
(when completion-auto-deselect
(with-selected-window window
(completions--deselect)))
@ -2885,7 +2885,7 @@ so that the update is less likely to interfere with user typing."
;; FIXME: We could/should use minibuffer-scroll-window here, but it
;; can also point to the minibuffer-parent-window, so it's a bit tricky.
(interactive)
(when-let* ((win (get-buffer-window "*Completions*" 0)))
(when-let* ((win (minibuffer--completions-visible)))
(with-selected-window win
;; Move point off any completions, so we don't move point there
;; again the next time `minibuffer-completion-help' is called.
@ -3332,18 +3332,26 @@ and `RET' accepts the input typed into the minibuffer."
(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 current *Completions* buffer is visible, if any."
(when-let* ((window (get-buffer-window "*Completions*" 0)))
(when (eq (buffer-local-value 'completion-reference-buffer
(window-buffer window))
;; If there's no active minibuffer, we call
;; `window-buffer' on nil, assuming that completion is
;; happening in the selected window.
(window-buffer (active-minibuffer-window)))
window)))
(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)
@ -5107,10 +5115,10 @@ the minibuffer was activated, and execute the forms."
When used in a minibuffer window, select the window with completions,
and execute the forms."
(declare (indent 0) (debug t))
`(let ((window (or (get-buffer-window "*Completions*" 0)
`(let ((window (or (minibuffer--completions-visible)
;; Make sure we have a completions window.
(progn (minibuffer-completion-help)
(get-buffer-window "*Completions*" 0)))))
(minibuffer--completions-visible)))))
(when window
(with-selected-window window
(completion--lazy-insert-strings)
@ -5205,7 +5213,7 @@ inputs for the prompting command, instead of the default completion table."
(user-error "No history available"))))
;; FIXME: Can we make it work for CRM?
(let ((completion-in-region-mode-predicate
(lambda () (get-buffer-window "*Completions*" 0))))
(lambda () (minibuffer--completions-visible))))
(completion-in-region
(minibuffer--completion-prompt-end) (point-max)
(completion-table-with-metadata
@ -5223,7 +5231,7 @@ provided by the prompting command, instead of the completion table."
minibuffer-default (funcall minibuffer-default-add-function)))
(let ((completions (ensure-list minibuffer-default))
(completion-in-region-mode-predicate
(lambda () (get-buffer-window "*Completions*" 0))))
(lambda () (minibuffer--completions-visible))))
(completion-in-region
(minibuffer--completion-prompt-end) (point-max)
(completion-table-with-metadata

View file

@ -1150,7 +1150,7 @@ Typing SPC flushes the help buffer."
((or (eq event 'tab)
;; Needed on a terminal
(eq event 9))
(let ((win (or (get-buffer-window "*Completions*" 0)
(let ((win (or (minibuffer--completions-visible)
(display-buffer "*Completions*"
'not-this-window))))
(with-selected-window win

View file

@ -10598,10 +10598,10 @@ to move point between completions.\n\n")))))))
(defun switch-to-completions ()
"Select the completion list window."
(interactive)
(when-let* ((window (or (get-buffer-window "*Completions*" 0)
(when-let* ((window (or (minibuffer--completions-visible)
;; Make sure we have a completions window.
(progn (minibuffer-completion-help)
(get-buffer-window "*Completions*" 0)))))
(minibuffer--completions-visible)))))
(select-window window)
(completion--lazy-insert-strings)
(when (bobp)

View file

@ -454,21 +454,21 @@
'("a" "ab" "ac")
(execute-kbd-macro (kbd "a TAB TAB"))
(should (equal (car messages) "Complete, but not unique"))
(should-not (get-buffer-window "*Completions*" 0))
(should-not (minibuffer--completions-visible))
(execute-kbd-macro (kbd "b TAB"))
(should (equal (car messages) "Sole completion"))))
(let ((completion-auto-help t))
(completing-read-with-minibuffer-setup
'("a" "ab" "ac")
(execute-kbd-macro (kbd "a TAB TAB"))
(should (get-buffer-window "*Completions*" 0))
(should (minibuffer--completions-visible))
(execute-kbd-macro (kbd "b TAB"))
(should (equal (car messages) "Sole completion"))))
(let ((completion-auto-help 'visible))
(completing-read-with-minibuffer-setup
'("a" "ab" "ac" "achoo")
(execute-kbd-macro (kbd "a TAB TAB"))
(should (get-buffer-window "*Completions*" 0))
(should (minibuffer--completions-visible))
(execute-kbd-macro (kbd "ch TAB"))
(should (equal (car messages) "Sole completion")))))))
@ -477,19 +477,19 @@
(completing-read-with-minibuffer-setup
'("aa" "ab" "ac")
(execute-kbd-macro (kbd "a TAB"))
(should (and (get-buffer-window "*Completions*" 0)
(should (and (minibuffer--completions-visible)
(eq (current-buffer) (get-buffer "*Completions*"))))
(execute-kbd-macro (kbd "TAB TAB TAB"))
(should (and (get-buffer-window "*Completions*" 0)
(should (and (minibuffer--completions-visible)
(eq (current-buffer) (get-buffer " *Minibuf-1*"))))
(execute-kbd-macro (kbd "S-TAB"))
(should (and (get-buffer-window "*Completions*" 0)
(should (and (minibuffer--completions-visible)
(eq (current-buffer) (get-buffer "*Completions*"))))))
(let ((completion-auto-select 'second-tab))
(completing-read-with-minibuffer-setup
'("aa" "ab" "ac")
(execute-kbd-macro (kbd "a TAB"))
(should (and (get-buffer-window "*Completions*" 0)
(should (and (minibuffer--completions-visible)
(not (eq (current-buffer) (get-buffer "*Completions*")))))
(execute-kbd-macro (kbd "TAB TAB"))
(should (eq (current-buffer) (get-buffer "*Completions*"))))))