Allow for next-completion to wrap around the completion buffer

* lisp/simple.el (completion-wrap-movement): Add new option.
(previous-completion): Update docstring.
(next-completion): Respect completion-wrap-movement.
(switch-to-completions): Handle backwards completion by jumping to the
end of the buffer.
* lisp/minibuffer.el: (minibuffer-local-completion-map): Bind
minibuffer-complete to backtab
(completion--in-region-1): Handle backtab to scroll backwards
This commit is contained in:
Philip Kaludercic 2021-12-09 17:26:14 +01:00
parent f6967d2f66
commit 15693c8116
2 changed files with 74 additions and 33 deletions

View file

@ -1379,14 +1379,18 @@ scroll the window of possible completions."
;; and this command is repeated, scroll that window.
((and (window-live-p minibuffer-scroll-window)
(eq t (frame-visible-p (window-frame minibuffer-scroll-window))))
(let ((window minibuffer-scroll-window))
(let ((window minibuffer-scroll-window)
(reverse (equal (this-command-keys) [backtab])))
(with-current-buffer (window-buffer window)
(if (pos-visible-in-window-p (point-max) window)
;; If end is in view, scroll up to the beginning.
(set-window-start window (point-min) nil)
(if (pos-visible-in-window-p (if reverse (point-min) (point-max)) window)
;; If end or beginning is in view, scroll up to the
;; beginning or end respectively.
(if reverse
(set-window-point window (point-max))
(set-window-start window (point-min) nil))
;; Else scroll down one screen.
(with-selected-window window
(scroll-up)))
(if reverse (scroll-down) (scroll-up))))
nil)))
;; If we're cycling, keep on cycling.
((and completion-cycling completion-all-sorted-completions)
@ -2651,6 +2655,7 @@ The completion method is determined by `completion-at-point-functions'."
(let ((map (make-sparse-keymap)))
(set-keymap-parent map minibuffer-local-map)
(define-key map "\t" 'minibuffer-complete)
(define-key map [backtab] 'minibuffer-complete)
;; M-TAB is already abused for many other purposes, so we should find
;; another binding for it.
;; (define-key map "\e\t" 'minibuffer-force-complete)

View file

@ -9029,38 +9029,68 @@ Go to the window from which completion was requested."
(if (get-buffer-window buf)
(select-window (get-buffer-window buf))))))
(defcustom completion-wrap-movement t
"Non-nil means to wrap around when selecting completion options.
This affects the commands `next-completion' and
`previous-completion'."
:type 'boolean
:version "29.1"
:group 'completion)
(defun previous-completion (n)
"Move to the previous item in the completion list."
"Move to the previous item in the completion list.
With prefix argument N, move back N items (negative N means move
forward)."
(interactive "p")
(next-completion (- n)))
(defun next-completion (n)
"Move to the next item in the completion list.
With prefix argument N, move N items (negative N means move backward)."
With prefix argument N, move N items (negative N means move
backward)."
(interactive "p")
(let ((beg (point-min)) (end (point-max)))
(while (and (> n 0) (not (eobp)))
;; If in a completion, move to the end of it.
(when (get-text-property (point) 'mouse-face)
(goto-char (next-single-property-change (point) 'mouse-face nil end)))
;; Move to start of next one.
(unless (get-text-property (point) 'mouse-face)
(goto-char (next-single-property-change (point) 'mouse-face nil end)))
(setq n (1- n)))
(while (and (< n 0) (not (bobp)))
(let ((prop (get-text-property (1- (point)) 'mouse-face)))
;; If in a completion, move to the start of it.
(when (and prop (eq prop (get-text-property (point) 'mouse-face)))
(goto-char (previous-single-property-change
(point) 'mouse-face nil beg)))
;; Move to end of the previous completion.
(unless (or (bobp) (get-text-property (1- (point)) 'mouse-face))
(goto-char (previous-single-property-change
(point) 'mouse-face nil beg)))
;; Move to the start of that one.
(goto-char (previous-single-property-change
(point) 'mouse-face nil beg))
(setq n (1+ n))))))
(catch 'bound
(while (> n 0)
;; If in a completion, move to the end of it.
(when (get-text-property (point) 'mouse-face)
(goto-char (next-single-property-change (point) 'mouse-face nil end)))
;; If at the last completion option, wrap or skip to the
;; minibuffer, if requested.
(when (and completion-wrap-movement (eobp))
(if (and (member (this-command-keys) '("\t" [backtab]))
completion-auto-select)
(throw 'bound nil)
(goto-char (point-min))))
;; Move to start of next one.
(unless (get-text-property (point) 'mouse-face)
(goto-char (next-single-property-change (point) 'mouse-face nil end)))
(setq n (1- n)))
(while (< n 0)
(let ((prop (get-text-property (1- (point)) 'mouse-face)))
;; If in a completion, move to the start of it.
(when (and prop (eq prop (get-text-property (point) 'mouse-face)))
(goto-char (previous-single-property-change
(point) 'mouse-face nil beg)))
;; Move to end of the previous completion.
(unless (or (bobp) (get-text-property (1- (point)) 'mouse-face))
(goto-char (previous-single-property-change
(point) 'mouse-face nil beg)))
;; If at the first completion option, wrap or skip to the
;; minibuffer, if requested.
(when (and completion-wrap-movement (bobp))
(if (and (member (this-command-keys) '("\t" [backtab]))
completion-auto-select)
(progn
(goto-char (next-single-property-change (point) 'mouse-face nil end))
(throw 'bound nil))
(goto-char (point-max))))
;; Move to the start of that one.
(goto-char (previous-single-property-change
(point) 'mouse-face nil beg))
(setq n (1+ n)))))
(when (/= 0 n)
(switch-to-minibuffer))))
(defun choose-completion (&optional event)
"Choose the completion at point.
@ -9285,10 +9315,16 @@ select the completion near point.\n\n")))))
(get-buffer-window "*Completions*" 0)))))
(when window
(select-window window)
;; In the new buffer, go to the first completion.
;; FIXME: Perhaps this should be done in `minibuffer-completion-help'.
(when (bobp)
(next-completion 1)))))
(cond
((and (memq this-command '(completion-at-point minibuffer-complete))
(equal (this-command-keys) [backtab])
(bobp))
(goto-char (point-max))
(previous-completion 1))
;; In the new buffer, go to the first completion.
;; FIXME: Perhaps this should be done in `minibuffer-completion-help'.
((bobp)
(next-completion 1))))))
(defun read-expression-switch-to-completions ()
"Select the completion list window while reading an expression."