Fix TAB to wrap with completion-auto-select t

* lisp/minibuffer.el (completions--clear-selection): New
function.
(minibuffer-hide-completions): Call it.
* lisp/simple.el (next-column-completion): Call it (bug#81635).
* test/lisp/minibuffer-tests.el
(completion-auto-select-test-bug81635): New test.
This commit is contained in:
Spencer Baugh 2026-08-20 13:49:28 -04:00 committed by Sean Whitton
parent 526912e158
commit 61700f9dd6
3 changed files with 46 additions and 4 deletions

View file

@ -2742,6 +2742,13 @@ The candidate will still be chosen by `choose-completion' unless
(goto-char (or (next-single-property-change (point) 'completion--string)
(point-max)))))
(defun completions--clear-selection ()
"Clear the selected candidate in the completions buffer.
Unlike `completions--deselect' this fully clears all selected-completion
state from the buffer."
(goto-char (point-min)))
(defun completions--should-show-p (metadata &optional force-eager-update)
"Return non-nil if *Completions* should be automatically updated or displayed.
@ -3020,7 +3027,7 @@ has been requested by the completion table."
(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.
(goto-char (point-min))
(completions--clear-selection)
(bury-buffer))))
(defun exit-minibuffer ()

View file

@ -10269,7 +10269,9 @@ Also see the `completion-auto-wrap' variable."
(not (eq completions-format 'vertical))))
(if (and (eq completion-auto-select t) tabcommand
(minibufferp completion-reference-buffer))
(throw 'bound nil)
(progn
(completions--clear-selection)
(throw 'bound nil))
(first-completion))))
(when (and (eq completions-format 'vertical)
(or last
@ -10321,8 +10323,8 @@ Also see the `completion-auto-wrap' variable."
(completion--move-to-candidate-start))
((and (eq completion-auto-select t) tabcommand
(minibufferp completion-reference-buffer))
(progn
(throw 'bound nil)))
(completions--clear-selection)
(throw 'bound nil))
(t
(last-completion)))))
(setq n (1+ n))))

View file

@ -639,6 +639,39 @@
(execute-kbd-macro (kbd "TAB TAB"))
(should (eq (current-buffer) (get-buffer "*Completions*"))))))
(ert-deftest completion-auto-select-test-bug81635 ()
(let ((completion-auto-select t)
(completion-auto-wrap t))
(completing-read-with-minibuffer-setup
'("aa" "ab" "ac")
(cl-flet ((selected ()
(and (eq (current-buffer) (get-buffer "*Completions*"))
(get-text-property (point) 'completion--string))))
;; TAB cycles forward through all candidates, then to the
;; minibuffer, then back to the first candidate.
(execute-kbd-macro (kbd "a TAB"))
(should (equal (selected) "aa"))
(execute-kbd-macro (kbd "TAB"))
(should (equal (selected) "ab"))
(execute-kbd-macro (kbd "TAB"))
(should (equal (selected) "ac"))
(execute-kbd-macro (kbd "TAB"))
(should (minibufferp))
(execute-kbd-macro (kbd "TAB"))
(should (equal (selected) "aa"))
(execute-kbd-macro (kbd "TAB"))
(should (equal (selected) "ab"))
;; S-TAB cycles backward, then to the minibuffer, then to the
;; last candidate.
(execute-kbd-macro (kbd "<backtab>"))
(should (equal (selected) "aa"))
(execute-kbd-macro (kbd "<backtab>"))
(should (minibufferp))
(execute-kbd-macro (kbd "<backtab>"))
(should (equal (selected) "ac"))
(execute-kbd-macro (kbd "<backtab>"))
(should (equal (selected) "ab"))))))
(ert-deftest completion-auto-wrap-test ()
(let ((completion-auto-wrap nil))
(completing-read-with-minibuffer-setup