mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-02-16 17:24:23 +00:00
Navigate *Completions* buffer based on 'completions-format'
This patch makes 'next-completion' and 'previous-completion' work
in the vertical completions format analogously to how they work in
the default horizontal format (bug#78959). It also fixes wrapping
in the vertical format and confines navigation (including
wrapping) in column-wise movement in the vertical format to the
current line, analogously to how navigation (including wrapping)
in line-wise movement in the horizontal format is confined to the
current column.
* doc/emacs/mini.texi (Completion): Fix several typos and improve
wording is several places.
(Completion Commands): Document navigation of the *Completions*
buffer in the vertical format. Document the difference between
format-sensitive movement and strictly column-wise or line-wise
movement. Document 'minibuffer-complete-and-exit' and update the
documentation of 'minibuffer-completion-auto-choose' and
'minibuffer-choose-completion'. Document the use of a numeric
prefix argument with the navigation commands.
(Completion Options): Rearrange and improve documentation of
'completions-sort', 'completions-format' and
'completion-auto-wrap', updating the latter to document the new
behavior.
* lisp/minibuffer.el (minibuffer-visible-completions-map): Rebind
"<left>" to 'minibuffer-previous-column-completion' and "<right>"
to 'minibuffer-next-column-completion'.
(minibuffer-next-completion): Add check for whether completions
format is vertical to decide whether to call
'next-line-completion' and replace calling 'next-completion' by
'next-column-completion'.
(minibuffer-next-column-completion)
(minibuffer-previous-column-completion): New commands.
* lisp/simple.el (completion-list-mode-map): Rebind "<left>" to
'previous-column-completion' and "<right>" to 'next-column-completion'.
(last-completion): Add handling for vertical completions format.
(completion--move-to-candidate-end): Always move point to the
position immediately after the last character of the completion
candidate. This unifies the behavior, simplifies the
implementation and facilitates implementing the improved
navigation of the *Completions* buffer.
(previous-column-completion, next-column-completion): New
commands, replacing the previous definitions of
'previous-completion' and 'next-completion' to reflect their
column-wise operation. Confine navigation (including wrapping) in
vertical format to the current line.
(previous-line-completion, next-line-completion): Implement
line-wise navigation (including wrapping) through all completions
in vertical format, not just those in the current column as in
horiztonal format. Update doc strings.
(next-completion, previous-completion): Redefine to call
'{next,previous}-line-completion' when completions format is
vertical and '{next,previous}-column-completion' otherwise.
* test/lisp/minibuffer-tests.el
(completions-format-navigation--tests): New function providing a
template to define tests of the navigation and wrapping behavior
with specified numbers of completion candidates.
(completions-format-navigation-test-{2,3,4,5,10,15,16}): New tests.
This commit is contained in:
parent
aeadaf7748
commit
77ca60b48d
5 changed files with 670 additions and 137 deletions
|
|
@ -276,9 +276,11 @@ can fill in the rest, or some of it, based on what was typed so far.
|
|||
@key{RET}, and @key{SPC}) are rebound in the minibuffer to special
|
||||
completion commands (@pxref{Completion Commands}). These commands
|
||||
attempt to complete the text in the minibuffer, based on a set of
|
||||
@dfn{completion alternatives} provided by the command that requested
|
||||
the argument. You can usually type @kbd{?} to see a list of
|
||||
completion alternatives.
|
||||
@dfn{completion alternatives} provided by the command that requested the
|
||||
argument. You can usually type @kbd{?} to have Emacs pop up a buffer
|
||||
(named @samp{*Completions*}) displaying the relevant completion
|
||||
alternatives. As described in more detail below, you can navigate this
|
||||
buffer and choose the desired completion from it.
|
||||
|
||||
Although completion is usually done in the minibuffer, the feature
|
||||
is sometimes available in ordinary buffers too. @xref{Symbol
|
||||
|
|
@ -336,8 +338,8 @@ at the end of the minibuffer, so that the minibuffer contains
|
|||
@node Completion Commands
|
||||
@subsection Completion Commands
|
||||
|
||||
Here is a list of the completion commands defined in the minibuffer
|
||||
when completion is allowed.
|
||||
Here is a list of the completion commands defined in the minibuffer or
|
||||
the completions buffer when completion is available.
|
||||
|
||||
@table @kbd
|
||||
@item @key{TAB}
|
||||
|
|
@ -357,7 +359,7 @@ Display a list of completions and a few useful key bindings
|
|||
(@code{minibuffer-completion-help}).
|
||||
@item M-@key{DOWN}
|
||||
@itemx M-@key{UP}
|
||||
Navigate through list of completions.
|
||||
Navigate through the list of completions.
|
||||
@item M-v
|
||||
@itemx M-g M-c
|
||||
@itemx @key{PageUp}
|
||||
|
|
@ -369,13 +371,17 @@ In the completions buffer, choose the completion at point.
|
|||
@itemx mouse-2
|
||||
In the completions buffer, choose the completion at mouse click.
|
||||
@item @key{TAB}
|
||||
@itemx @key{RIGHT}
|
||||
@itemx @key{n}
|
||||
@itemx n
|
||||
In the completions buffer, move to the following completion candidate.
|
||||
@item @key{S-TAB}
|
||||
@itemx @key{LEFT}
|
||||
@itemx @key{p}
|
||||
@item S-@key{TAB}
|
||||
@itemx p
|
||||
In the completions buffer, move to the previous completion candidate.
|
||||
@item @key{RIGHT}
|
||||
@itemx @key{LEFT}
|
||||
In the completions buffer, navigate column-wise through the completion list.
|
||||
@item @key{DOWN}
|
||||
@itemx @key{UP}
|
||||
In the completions buffer, navigate line-wise through the completion list.
|
||||
@item q
|
||||
Quit the completions window and switch to the minibuffer window.
|
||||
@item z
|
||||
|
|
@ -416,19 +422,24 @@ with the completion list:
|
|||
@findex minibuffer-next-completion
|
||||
@findex minibuffer-previous-completion
|
||||
@findex minibuffer-choose-completion
|
||||
While in the minibuffer or in the completion list buffer, @kbd{M-@key{DOWN}}
|
||||
(@code{minibuffer-next-completion} and @kbd{M-@key{UP}}
|
||||
(@code{minibuffer-previous-completion}) navigate through the
|
||||
completions displayed in the completions buffer. When
|
||||
@code{minibuffer-completion-auto-choose} is non-@code{nil} (which is
|
||||
the default), using these commands also inserts the current completion
|
||||
candidate into the minibuffer. If
|
||||
@code{minibuffer-completion-auto-choose} is @code{nil}, you can use
|
||||
the @kbd{M-@key{RET}} command (@code{minibuffer-choose-completion}) to
|
||||
insert the completion candidates into the minibuffer. By default,
|
||||
that exits the minibuffer, but with a prefix argument, @kbd{C-u
|
||||
M-@key{RET}} inserts the currently active candidate without exiting
|
||||
the minibuffer.
|
||||
@findex minibuffer-complete-and-exit
|
||||
While in the minibuffer or in the completion list buffer,
|
||||
@kbd{M-@key{DOWN}} (@code{minibuffer-next-completion}) and
|
||||
@kbd{M-@key{UP}} (@code{minibuffer-previous-completion}) navigate
|
||||
through the completions displayed in the completions buffer. These
|
||||
commands are sensitive to the completion list format: they move point
|
||||
column-wise when the value of @code{completions-format} is
|
||||
@code{horizontal} and line-wise when its value is @code{vertical}
|
||||
(@pxref{Completion Options}). If you set
|
||||
@code{minibuffer-completion-auto-choose} to non-@code{nil}, using these
|
||||
commands also inserts the current completion candidate into the
|
||||
minibuffer. You can use @kbd{M-@key{RET}}
|
||||
(@code{minibuffer-choose-completion}) or @kbd{@key{RET}}
|
||||
(@code{minibuffer-complete-and-exit}) to choose the selected completion
|
||||
candidate. By default, these commands exit the minibuffer, but with a
|
||||
prefix argument (that is, @kbd{C-u M-@key{RET}} or @kbd{C-u @key{RET}})
|
||||
they insert the currently selected candidate into the minibuffer without
|
||||
exiting it.
|
||||
|
||||
@findex switch-to-completions
|
||||
Typing @kbd{M-v}, while in the minibuffer, selects the window showing
|
||||
|
|
@ -446,11 +457,27 @@ minibuffer, but doesn't exit the minibuffer---thus, you can change your
|
|||
mind and choose another candidate.
|
||||
|
||||
@findex next-completion
|
||||
While in the completion list buffer, you can use @kbd{@key{TAB}},
|
||||
@kbd{@key{RIGHT}}, or @kbd{n} to move point to the following completion
|
||||
candidate (@code{next-completion}). You can also use @kbd{@key{S-TAB}},
|
||||
@kbd{@key{LEFT}}, and @kbd{p} to move point to the previous completion
|
||||
alternative (@code{previous-completion}).
|
||||
@findex previous-completion
|
||||
While in the completion list buffer, you can use @kbd{@key{TAB}} or
|
||||
@kbd{n} to move point to the following completion candidate
|
||||
(@code{next-completion}) and @kbd{S-@key{TAB}} or @kbd{p} to move point
|
||||
to the previous completion alternative (@code{previous-completion}).
|
||||
Like @kbd{M-@key{DOWN}} and @kbd{M-@key{UP}}, these commands are also
|
||||
sensitive to the completion list format.
|
||||
|
||||
@findex next-column-completion
|
||||
@findex next-line-completion
|
||||
@findex previous-column-completion
|
||||
@findex previous-line-completion
|
||||
In contrast, @kbd{@key{RIGHT}} (@code{next-column-completion}) and
|
||||
@kbd{@key{LEFT}} (@code{previous-column-completion}) always move point
|
||||
column-wise, regardless of the completion list format. Likewise,
|
||||
@kbd{@key{DOWN}} (@code{next-line-completion}) and @kbd{@key{UP}}
|
||||
(@code{previous-line-completion}) always move point line-wise.
|
||||
|
||||
All of these movement commands (and also @kbd{M-@key{DOWN}} and
|
||||
@kbd{M-@key{UP}}) accept a numeric prefix argument @var{n}, which makes
|
||||
point move to the @var{n}th following or preceding completion candidate.
|
||||
|
||||
@findex minibuffer-complete-history
|
||||
@findex minibuffer-complete-defaults
|
||||
|
|
@ -475,10 +502,14 @@ completion buffer and delete the window showing it
|
|||
If the variable @code{minibuffer-visible-completions} is customized to
|
||||
a non-@code{nil} value, it changes the commands bound to the arrow keys:
|
||||
instead of moving in the minibuffer, they move between completion
|
||||
candidates, like meta-arrow keys do by default. Similarly,
|
||||
@kbd{@key{RET}} selects the current candidate, like @kbd{M-@key{RET}}
|
||||
does normally. @code{C-g} hides the completion window, but leaves the
|
||||
minibuffer active, so you can continue typing at the prompt.
|
||||
candidates, like meta-arrow keys do by default (but note that, just as
|
||||
when the window showing the completion list is selected, here too,
|
||||
@kbd{@key{RIGHT}} and @kbd{@key{LEFT}} only move point column-wise and
|
||||
@kbd{@key{DOWN}} and @kbd{@key{UP}} only move point line-wise,
|
||||
regardless of the completion list format). Similarly, @kbd{@key{RET}}
|
||||
selects the current candidate, like @kbd{M-@key{RET}} does normally.
|
||||
@code{C-g} hides the completion window, but leaves the minibuffer
|
||||
active, so you can continue typing at the prompt.
|
||||
|
||||
@node Completion Exit
|
||||
@subsection Completion Exit
|
||||
|
|
@ -725,18 +756,6 @@ then move to a candidate by cursor motion commands and select it with
|
|||
@code{second-tab}, then the first @kbd{@key{TAB}} will pop up the
|
||||
completions list buffer, and the second one will switch to it.
|
||||
|
||||
@findex previous-line-completion
|
||||
@findex next-line-completion
|
||||
@vindex completion-auto-wrap
|
||||
When the window showing the completions is selected, either because
|
||||
you customized @code{completion-auto-select} or because you switched to
|
||||
it by typing @kbd{C-x o}, the @kbd{@key{UP}} and @kbd{@key{DOWN}} arrow
|
||||
keys (@code{previous-line-completion} and @code{next-line-completion},
|
||||
respectively) move by lines between completion candidates; with a prefix
|
||||
numeric argument, they move that many lines. If
|
||||
@code{completion-auto-wrap} is non-@code{nil}, these commands will wrap
|
||||
at bottom and top of the candidate list.
|
||||
|
||||
@vindex completion-cycle-threshold
|
||||
If @code{completion-cycle-threshold} is non-@code{nil}, completion
|
||||
commands can cycle through completion alternatives. Normally, if
|
||||
|
|
@ -750,24 +769,57 @@ in a cyclic manner. If you give @code{completion-cycle-threshold} a
|
|||
numeric value @var{n}, completion commands switch to this cycling
|
||||
behavior only when there are @var{n} or fewer alternatives.
|
||||
|
||||
@vindex completions-format
|
||||
When displaying completions, Emacs will normally pop up a new buffer
|
||||
to display the completions. The completions will by default be sorted
|
||||
horizontally, using as many columns as will fit in the window-width,
|
||||
but this can be changed by customizing the @code{completions-format}
|
||||
user option. If its value is @code{vertical}, Emacs will sort the
|
||||
completions vertically instead, and if it's @code{one-column}, Emacs
|
||||
will use just one column.
|
||||
|
||||
@vindex completions-sort
|
||||
The @code{completions-sort} user option controls the order in which
|
||||
the completions are sorted in the @samp{*Completions*} buffer. The
|
||||
default is @code{alphabetical}, which sorts in alphabetical order.
|
||||
The value @code{nil} disables sorting; the value @code{historical}
|
||||
sorts alphabetically first, and then rearranges according to the order
|
||||
of the candidates in the minibuffer history. The value can also be a
|
||||
function, which will be called with the list of completions, and
|
||||
should return the list in the desired order.
|
||||
The user option @code{completions-sort} controls the order in which
|
||||
the completions are sorted in the @samp{*Completions*} buffer. With the
|
||||
default value @code{alphabetical}, the completions are displayed in
|
||||
alphabetical order. The value @code{nil} disables sorting; the value
|
||||
@code{historical} sorts alphabetically first, and then rearranges
|
||||
according to the order of the candidates in the minibuffer history. The
|
||||
value can also be a function, which will be called with the list of
|
||||
completions, and should return the list in the desired order.
|
||||
|
||||
@vindex completions-format
|
||||
By default, the @samp{*Completions*} buffer lists the sorted
|
||||
completions horizontally (that is, from left to right across the columns
|
||||
and continuing to the next line below), using as many columns as will
|
||||
fit in the window-width. You can change this by customizing the user
|
||||
option @code{completions-format}. If its value is @code{vertical}, the
|
||||
@samp{*Completions*} buffer lists the sorted completions vertically
|
||||
(that is, within each column and continuing with the next column to the
|
||||
left), and with the value @code{one-column}, all completions appear in a
|
||||
single column.@footnote{If a completion candidate is too long for more
|
||||
than one column to fit in the window, or it there are three or less
|
||||
candidates, all completions appear in a single column even if the value
|
||||
of @code{completions-format} is @code{horizontal} or @code{vertical}.}
|
||||
|
||||
@vindex completion-auto-wrap
|
||||
When point is on the last completion candidate, typing a key that
|
||||
moves point to the next candidate (according to the sorting order of
|
||||
current format) ``wraps around'' by default, that is, moves point to the
|
||||
first candidate in the completions buffer. Likewise, when point is on
|
||||
the first candidate, typing a key to move to the previous candidate puts
|
||||
point on the last candidate in the buffer. You can suppress this
|
||||
wrapping around by customizing the user option
|
||||
@code{completion-auto-wrap} to @code{nil}; then typing @kbd{@key{TAB}}
|
||||
or @kbd{n} on the last candidate, or typing @kbd{S-@key{TAB}} or @kbd{p}
|
||||
on the first candidate, does not move point.
|
||||
|
||||
With the arrow keys, the wrapping behavior depends on the completions
|
||||
format in use. In the horizontal format, you can use @kbd{@key{RIGHT}}
|
||||
and @kbd{@key{LEFT}}, and in the vertical format @kbd{@key{DOWN}} and
|
||||
@kbd{@key{UP}}, exactly like the format-sensitive keys for moving
|
||||
between completion candidates in the sorting order, and with the same
|
||||
wrapping behavior. In contrast, in the horizontal format
|
||||
@kbd{@key{DOWN}} and @kbd{@key{UP}} move---and wrap, if wrapping is
|
||||
enabled---only within the current column of completions, and in the
|
||||
vertical format @kbd{@key{RIGHT}} and @kbd{@key{LEFT}} move (and wrap,
|
||||
if enabled) only within the current line of completions.@footnote{If the
|
||||
completions buffer contains only single column even in the horizontal or
|
||||
vertical format, then both the format-sensitive keys and the arrow keys
|
||||
move point to the next (respectively, previous) candidate, wrapping only
|
||||
at the last (respectively, first) candidate, if the value of
|
||||
@code{completion-auto-wrap} is non-@code{nil}.}
|
||||
|
||||
@vindex completions-max-height
|
||||
When @code{completions-max-height} is non-@code{nil}, it limits the
|
||||
|
|
|
|||
30
etc/NEWS
30
etc/NEWS
|
|
@ -216,6 +216,23 @@ different values for completion-affecting variables like
|
|||
applies for the styles configuration in 'completion-category-overrides'
|
||||
and 'completion-category-defaults'.
|
||||
|
||||
+++++
|
||||
*** Navigating "*Completions*" now accommodates 'completions-format'.
|
||||
When 'completions-format' is set to 'vertical', typing 'n', '<TAB>' or
|
||||
'M-<down>' in the "*Completions*" buffer (the latter also in the
|
||||
minibuffer) now moves point to the completion candidate in the next line
|
||||
in the current column, and wraps to the next column when typed on the
|
||||
last completion candidate of the current column. Likewise, typing 'p',
|
||||
'S-<TAB>' or 'M-<up>' moves point to the completion candidate in the
|
||||
previous line or wraps to the previous column. Previously, these keys
|
||||
ignored the vertical format, i.e., moved point only to the item in the
|
||||
same line of the next or previous column, in accordance with the default
|
||||
horizontal format. In vertical format, typing '<left>' and '<right>' in
|
||||
the "*Completions*" buffer (and when 'minibuffer-visible-completions' is
|
||||
non-nil, also in the minibuffer) moves point only within the current
|
||||
line, analogously to how, in horizontal format, '<down>' and '<up>' move
|
||||
point only within the current column.
|
||||
|
||||
---
|
||||
*** Selected completion candidate is preserved across "*Completions*" updates.
|
||||
When point is on a completion candidate in the "*Completions*" buffer
|
||||
|
|
@ -2936,6 +2953,19 @@ by default and controlled by this variable; it can be set to non-nil
|
|||
to keep the old behavior. This change is to accomodate screen
|
||||
readers.
|
||||
|
||||
---
|
||||
** 'next-completion' and 'previous-completion' now use 'completions-format'.
|
||||
Previously, these commands only took horizontal format into account;
|
||||
now, they call either '{next,previous}-line-completion' or the new
|
||||
commands '{next,previous}-column-completion', depending on the value of
|
||||
'completions-format'. The latter two commands improve and extend the
|
||||
previous implementations of '{next,previous}-completion', which better
|
||||
reflect that they only take the (default) horizontal completions format
|
||||
into account. Any external code using '{next,previous}-completion' that
|
||||
assumes the previous implementation must be adjusted accordingly; see
|
||||
'minibuffer-next-completion' for an example of such an adjustment in
|
||||
Emacs core.
|
||||
|
||||
+++
|
||||
** A thread's current buffer can now be killed.
|
||||
We introduce a new attribute for threads called 'buffer-disposition'.
|
||||
|
|
|
|||
|
|
@ -3440,8 +3440,8 @@ displaying the *Completions* buffer exists."
|
|||
|
||||
(defvar-keymap minibuffer-visible-completions-map
|
||||
:doc "Local keymap for minibuffer input with visible completions."
|
||||
"<left>" (minibuffer-visible-completions--bind #'minibuffer-previous-completion)
|
||||
"<right>" (minibuffer-visible-completions--bind #'minibuffer-next-completion)
|
||||
"<left>" (minibuffer-visible-completions--bind #'minibuffer-previous-column-completion)
|
||||
"<right>" (minibuffer-visible-completions--bind #'minibuffer-next-column-completion)
|
||||
"<up>" (minibuffer-visible-completions--bind #'minibuffer-previous-line-completion)
|
||||
"<down>" (minibuffer-visible-completions--bind #'minibuffer-next-line-completion)
|
||||
"C-g" (minibuffer-visible-completions--bind #'minibuffer-hide-completions))
|
||||
|
|
@ -5224,15 +5224,15 @@ selected by these commands to the minibuffer."
|
|||
"Move to the next item in its completions window from the minibuffer.
|
||||
When the optional argument VERTICAL is non-nil, move vertically
|
||||
to the next item on the next line using `next-line-completion'.
|
||||
Otherwise, move to the next item horizontally using `next-completion'.
|
||||
Otherwise, move to the next item horizontally using `next-column-completion'.
|
||||
When `minibuffer-completion-auto-choose' is non-nil, then also
|
||||
insert the selected completion candidate to the minibuffer."
|
||||
(interactive "p")
|
||||
(let ((auto-choose minibuffer-completion-auto-choose))
|
||||
(with-minibuffer-completions-window
|
||||
(if vertical
|
||||
(if (or vertical (eq completions-format 'vertical))
|
||||
(next-line-completion (or n 1))
|
||||
(next-completion (or n 1)))
|
||||
(next-column-completion (or n 1)))
|
||||
(when auto-choose
|
||||
(let ((completion-auto-deselect nil))
|
||||
(choose-completion nil t t))))))
|
||||
|
|
@ -5262,6 +5262,26 @@ insert the selected completion candidate to the minibuffer."
|
|||
(interactive "p")
|
||||
(minibuffer-next-completion (- (or n 1)) t))
|
||||
|
||||
(defun minibuffer-next-column-completion (&optional n)
|
||||
"Move to the next completion column from the minibuffer.
|
||||
This means to move to the completion candidate in the next column
|
||||
in the *Completions* buffer while point stays in the minibuffer.
|
||||
When `minibuffer-completion-auto-choose' is non-nil, then also
|
||||
insert the selected completion candidate to the minibuffer."
|
||||
(interactive "p")
|
||||
(with-minibuffer-completions-window
|
||||
(next-column-completion (or n 1))))
|
||||
|
||||
(defun minibuffer-previous-column-completion (&optional n)
|
||||
"Move to the previous completion column from the minibuffer.
|
||||
This means to move to the completion candidate on the previous column
|
||||
in the *Completions* buffer while point stays in the minibuffer.
|
||||
When `minibuffer-completion-auto-choose' is non-nil, then also
|
||||
insert the selected completion candidate to the minibuffer."
|
||||
(interactive "p")
|
||||
(with-minibuffer-completions-window
|
||||
(next-column-completion (- (or n 1)))))
|
||||
|
||||
(defun minibuffer-choose-completion (&optional no-exit no-quit)
|
||||
"Run `choose-completion' from the minibuffer in its completions window.
|
||||
With prefix argument NO-EXIT, insert the completion candidate at point to
|
||||
|
|
|
|||
276
lisp/simple.el
276
lisp/simple.el
|
|
@ -10068,8 +10068,8 @@ makes it easier to edit it."
|
|||
(define-key map [remap keyboard-quit] #'delete-completion-window)
|
||||
(define-key map [up] 'previous-line-completion)
|
||||
(define-key map [down] 'next-line-completion)
|
||||
(define-key map [left] 'previous-completion)
|
||||
(define-key map [right] 'next-completion)
|
||||
(define-key map [left] 'previous-column-completion)
|
||||
(define-key map [right] 'next-column-completion)
|
||||
(define-key map [?\t] 'next-completion)
|
||||
(define-key map [backtab] 'previous-completion)
|
||||
(define-key map [M-up] 'minibuffer-previous-completion)
|
||||
|
|
@ -10159,21 +10159,54 @@ the completions is popped up and down."
|
|||
(defun last-completion ()
|
||||
"Move to the last item in the completions buffer."
|
||||
(interactive)
|
||||
;; Move to the last item in horizontal or one-column format.
|
||||
(goto-char (previous-single-property-change
|
||||
(point-max) 'mouse-face nil (point-min)))
|
||||
;; Move to the start of last one.
|
||||
;; Move to the start of the item.
|
||||
(unless (get-text-property (point) 'mouse-face)
|
||||
(when-let* ((pos (previous-single-property-change (point) 'mouse-face)))
|
||||
(goto-char pos))))
|
||||
(goto-char pos)))
|
||||
;; In vertical format the last item is in the last column even if its
|
||||
;; line number is less than that of the last item in earlier columns.
|
||||
(when (eq completions-format 'vertical)
|
||||
(let ((pt (point))
|
||||
(col (current-column))
|
||||
(last-col (progn
|
||||
(first-completion)
|
||||
(goto-char (pos-eol))
|
||||
(goto-char (previous-single-property-change
|
||||
(point) 'mouse-face))
|
||||
(current-column))))
|
||||
(if (zerop last-col)
|
||||
;; If there is only one column of completions, the last
|
||||
;; completion in vertical format is the same as in horizontal
|
||||
;; format, so go there now.
|
||||
(goto-char pt)
|
||||
;; Otherwise, we set `pt' to the beginning of first item in last
|
||||
;; column here because if the last column contains only one
|
||||
;; item, `pt' will not be set below.)
|
||||
(setq pt (point))
|
||||
;; If all columns contain the same number of items, `col' (which
|
||||
;; specifies the column of the last item in horizontal format)
|
||||
;; equals `last-col', so the test must be with `>=', not `>'.
|
||||
(when (>= last-col col)
|
||||
(while (= (current-column) last-col)
|
||||
(forward-line)
|
||||
(unless (eobp)
|
||||
(goto-char (pos-eol))
|
||||
(move-to-column last-col)
|
||||
(when (= (current-column) last-col)
|
||||
(setq pt (point))))))
|
||||
(goto-char pt)))))
|
||||
|
||||
(defun previous-completion (n)
|
||||
"Move to the previous item in the completions buffer.
|
||||
With prefix argument N, move back N items (negative N means move
|
||||
(defun previous-column-completion (n)
|
||||
"Move to the item in the previous column of the completions buffer.
|
||||
With prefix argument N, move back N columns (negative N means move
|
||||
forward).
|
||||
|
||||
Also see the `completion-auto-wrap' variable."
|
||||
(interactive "p")
|
||||
(next-completion (- n)))
|
||||
(next-column-completion (- n)))
|
||||
|
||||
(defun completion--move-to-candidate-start ()
|
||||
"If in a completion candidate, move point to its start."
|
||||
|
|
@ -10183,21 +10216,26 @@ Also see the `completion-auto-wrap' variable."
|
|||
(goto-char (previous-single-property-change (point) 'mouse-face))))
|
||||
|
||||
(defun completion--move-to-candidate-end ()
|
||||
"If in a completion candidate, move point to its end."
|
||||
(when (and (get-text-property (point) 'mouse-face)
|
||||
(not (eobp))
|
||||
(get-text-property (1+ (point)) 'mouse-face))
|
||||
(goto-char (or (next-single-property-change (point) 'mouse-face) (point-max)))))
|
||||
"If in a completion candidate, move point to its end.
|
||||
More precisely, point moves the the position immediately after the last
|
||||
character of the completion candidate."
|
||||
(when (get-text-property (point) 'mouse-face)
|
||||
(goto-char (or (next-single-property-change (point) 'mouse-face)
|
||||
(point-max)))))
|
||||
|
||||
(defun next-completion (n)
|
||||
"Move to the next item in the completions buffer.
|
||||
With prefix argument N, move N items (negative N means move
|
||||
(defun next-column-completion (n)
|
||||
"Move to the item in the next column of the completions buffer.
|
||||
With prefix argument N, move N columns (negative N means move
|
||||
backward).
|
||||
|
||||
Also see the `completion-auto-wrap' variable."
|
||||
(interactive "p")
|
||||
(let ((tabcommand (member (this-command-keys) '("\t" [backtab])))
|
||||
pos)
|
||||
(one-col (save-excursion
|
||||
(first-completion)
|
||||
(completion--move-to-candidate-end)
|
||||
(eolp)))
|
||||
pos line last first)
|
||||
(catch 'bound
|
||||
(when (and (bobp)
|
||||
(> n 0)
|
||||
|
|
@ -10208,32 +10246,61 @@ Also see the `completion-auto-wrap' variable."
|
|||
(setq n (1- n)))
|
||||
|
||||
(while (> n 0)
|
||||
(setq pos (point))
|
||||
(setq pos (point) line (line-number-at-pos)
|
||||
last (if one-col
|
||||
(save-excursion (and (forward-line) (eobp)))
|
||||
(save-excursion (completion--move-to-candidate-end) (eolp))))
|
||||
;; If in a completion, move to the end of it.
|
||||
(when (get-text-property pos 'mouse-face)
|
||||
(setq pos (next-single-property-change pos 'mouse-face)))
|
||||
(when pos (setq pos (next-single-property-change pos 'mouse-face)))
|
||||
(if pos
|
||||
(if (and pos
|
||||
(if last
|
||||
(not (eq completions-format 'vertical))
|
||||
t))
|
||||
;; Move to the start of next one.
|
||||
(goto-char pos)
|
||||
;; If at the last completion option, wrap or skip
|
||||
;; to the minibuffer, if requested.
|
||||
(when completion-auto-wrap
|
||||
(when (and completion-auto-wrap
|
||||
(or one-col
|
||||
(not (eq completions-format 'vertical))))
|
||||
(if (and (eq completion-auto-select t) tabcommand
|
||||
(minibufferp completion-reference-buffer))
|
||||
(throw 'bound nil)
|
||||
(first-completion))))
|
||||
(when (and (eq completions-format 'vertical)
|
||||
(or last
|
||||
(= (point) (save-excursion (first-completion) (point)))))
|
||||
(if (> (line-number-at-pos) line)
|
||||
(forward-line -1)
|
||||
(when completion-auto-wrap
|
||||
(goto-char (pos-bol))
|
||||
(completion--move-to-candidate-start))))
|
||||
(setq n (1- n)))
|
||||
|
||||
(while (< n 0)
|
||||
(setq pos (point))
|
||||
(setq pos (point) line (line-number-at-pos)
|
||||
first (if one-col
|
||||
(save-excursion
|
||||
(forward-line -1)
|
||||
(not (get-text-property (point) 'mouse-face)))
|
||||
(save-excursion (completion--move-to-candidate-start)
|
||||
(bolp))))
|
||||
;; If in a completion, move to the start of it.
|
||||
(when (and (get-text-property pos 'mouse-face)
|
||||
(not (bobp))
|
||||
(get-text-property (1- pos) 'mouse-face))
|
||||
(setq pos (previous-single-property-change pos 'mouse-face)))
|
||||
(when pos (setq pos (previous-single-property-change pos 'mouse-face)))
|
||||
(if pos
|
||||
(if (and pos
|
||||
(not (and completion-auto-wrap
|
||||
(eq completions-format 'vertical)
|
||||
(not one-col)
|
||||
(bolp)))
|
||||
(if first
|
||||
(not (eq completions-format 'vertical))
|
||||
t))
|
||||
(progn
|
||||
(goto-char pos)
|
||||
;; Move to the start of that one.
|
||||
|
|
@ -10243,11 +10310,19 @@ Also see the `completion-auto-wrap' variable."
|
|||
;; If at the first completion option, wrap or skip
|
||||
;; to the minibuffer, if requested.
|
||||
(when completion-auto-wrap
|
||||
(if (and (eq completion-auto-select t) tabcommand
|
||||
(minibufferp completion-reference-buffer))
|
||||
(progn
|
||||
(throw 'bound nil))
|
||||
(last-completion))))
|
||||
(cond ((and (eq completions-format 'vertical)
|
||||
(not one-col)
|
||||
(or first (not pos)))
|
||||
(when (> line (line-number-at-pos))
|
||||
(forward-line))
|
||||
(goto-char (1- (pos-eol)))
|
||||
(completion--move-to-candidate-start))
|
||||
((and (eq completion-auto-select t) tabcommand
|
||||
(minibufferp completion-reference-buffer))
|
||||
(progn
|
||||
(throw 'bound nil)))
|
||||
(t
|
||||
(last-completion)))))
|
||||
(setq n (1+ n))))
|
||||
|
||||
(when (/= 0 n)
|
||||
|
|
@ -10255,7 +10330,11 @@ Also see the `completion-auto-wrap' variable."
|
|||
|
||||
(defun previous-line-completion (&optional n)
|
||||
"Move to completion candidate on the previous line in the completions buffer.
|
||||
With prefix argument N, move back N lines (negative N means move forward).
|
||||
With prefix argument N, move back N lines (negative N means move
|
||||
forward). In vertical format (see user option `completions-format')
|
||||
this command moves line-wise through all columns in the completions
|
||||
buffer, in horizontal format movement is confined to the current column
|
||||
of completions.
|
||||
|
||||
Also see the `completion-auto-wrap' variable."
|
||||
(interactive "p")
|
||||
|
|
@ -10263,11 +10342,15 @@ Also see the `completion-auto-wrap' variable."
|
|||
|
||||
(defun next-line-completion (&optional n)
|
||||
"Move to completion candidate on the next line in the completions buffer.
|
||||
With prefix argument N, move N lines forward (negative N means move backward).
|
||||
With prefix argument N, move N lines forward (negative N means move
|
||||
backward). In vertical format (see user option `completions-format')
|
||||
this command moves line-wise through all columns in the completions
|
||||
buffer, in horizontal format movement is confined to the current column
|
||||
of completions.
|
||||
|
||||
Also see the `completion-auto-wrap' variable."
|
||||
(interactive "p")
|
||||
(let (line column pos found)
|
||||
(let (line column pos found last first)
|
||||
(when (and (bobp)
|
||||
(> n 0)
|
||||
(get-text-property (point) 'mouse-face)
|
||||
|
|
@ -10292,54 +10375,109 @@ Also see the `completion-auto-wrap' variable."
|
|||
((< n 0) (first-completion)))))
|
||||
|
||||
(while (> n 0)
|
||||
(setq found nil pos nil column (current-column) line (line-number-at-pos))
|
||||
(completion--move-to-candidate-end)
|
||||
(while (and (not found)
|
||||
(eq (forward-line 1) 0)
|
||||
(not (eobp))
|
||||
(move-to-column column))
|
||||
(when (get-text-property (point) 'mouse-face)
|
||||
(setq found t)))
|
||||
(when (not found)
|
||||
(if (not completion-auto-wrap)
|
||||
(last-completion)
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(when (and (eq (move-to-column column) column)
|
||||
(get-text-property (point) 'mouse-face))
|
||||
(setq pos (point)))
|
||||
(while (and (not pos) (> line (line-number-at-pos)))
|
||||
(forward-line 1)
|
||||
(setq found nil pos (point) column (current-column)
|
||||
line (line-number-at-pos)
|
||||
last (= (point) (save-excursion (last-completion) (point))))
|
||||
(if (and (eq completions-format 'vertical)
|
||||
completion-auto-wrap last)
|
||||
(first-completion) ; Wrap from last to first item.
|
||||
(completion--move-to-candidate-end)
|
||||
(while (and (not found)
|
||||
(eq (forward-line 1) 0)
|
||||
(not (eobp))
|
||||
(move-to-column column))
|
||||
(when (get-text-property (point) 'mouse-face)
|
||||
(setq found t)))
|
||||
(when (not found)
|
||||
(if (and (not completion-auto-wrap)
|
||||
(if (eq completions-format 'vertical)
|
||||
(and (or last (get-text-property (point) 'mouse-face))
|
||||
(last-completion))
|
||||
(goto-char pos)))
|
||||
t
|
||||
(save-excursion
|
||||
(setq pos nil)
|
||||
(goto-char (point-min))
|
||||
(when (and (eq (move-to-column column) column)
|
||||
(get-text-property (point) 'mouse-face))
|
||||
(setq pos (point)))))
|
||||
(if pos (goto-char pos))))
|
||||
(setq pos (point)))
|
||||
(while (and (not pos) (> line (line-number-at-pos)))
|
||||
(forward-line 1)
|
||||
(when (and (eq (move-to-column column) column)
|
||||
(get-text-property (point) 'mouse-face))
|
||||
(setq pos (point)))))
|
||||
(if pos (goto-char pos))
|
||||
(when (eq completions-format 'vertical)
|
||||
(next-column-completion 1))))) ; Move to next column.
|
||||
(setq n (1- n)))
|
||||
|
||||
(while (< n 0)
|
||||
(setq found nil pos nil column (current-column) line (line-number-at-pos))
|
||||
(completion--move-to-candidate-start)
|
||||
(while (and (not found)
|
||||
(eq (forward-line -1) 0)
|
||||
(move-to-column column))
|
||||
(when (get-text-property (point) 'mouse-face)
|
||||
(setq found t)))
|
||||
(when (not found)
|
||||
(if (not completion-auto-wrap)
|
||||
(first-completion)
|
||||
(save-excursion
|
||||
(goto-char (point-max))
|
||||
(when (and (eq (move-to-column column) column)
|
||||
(get-text-property (point) 'mouse-face))
|
||||
(setq pos (point)))
|
||||
(while (and (not pos) (< line (line-number-at-pos)))
|
||||
(forward-line -1)
|
||||
(setq found nil pos (point) column (current-column)
|
||||
line (line-number-at-pos)
|
||||
first (= (point) (save-excursion (first-completion) (point))))
|
||||
(if (and (eq completions-format 'vertical)
|
||||
completion-auto-wrap first)
|
||||
(last-completion) ; Wrap from first to last item.
|
||||
(completion--move-to-candidate-start)
|
||||
(while (and (not found)
|
||||
(eq (forward-line -1) 0)
|
||||
(move-to-column column))
|
||||
(when (get-text-property (point) 'mouse-face)
|
||||
(setq found t)))
|
||||
(when (not found)
|
||||
(if (and (not completion-auto-wrap)
|
||||
(if (eq completions-format 'vertical)
|
||||
(and (or last first
|
||||
(get-text-property (point) 'mouse-face))
|
||||
first (first-completion))
|
||||
(goto-char pos)))
|
||||
t
|
||||
(save-excursion
|
||||
(setq pos nil)
|
||||
(goto-char (point-max))
|
||||
(when (and (eq (move-to-column column) column)
|
||||
(get-text-property (point) 'mouse-face))
|
||||
(setq pos (point)))))
|
||||
(if pos (goto-char pos))))
|
||||
(setq pos (point)))
|
||||
(while (and (not pos) (< line (line-number-at-pos)))
|
||||
(forward-line -1)
|
||||
(when (and (eq (move-to-column column) column)
|
||||
(get-text-property (point) 'mouse-face))
|
||||
(setq pos (point)))))
|
||||
(if pos (goto-char pos))
|
||||
(when (eq completions-format 'vertical)
|
||||
(previous-column-completion 1) ; Move to previous column.
|
||||
(setq column (current-column))
|
||||
;; Move to last item in this column (previous column may
|
||||
;; have fewer items).
|
||||
(while (not (eobp))
|
||||
(move-to-column column)
|
||||
(setq pos (point))
|
||||
(forward-line))
|
||||
(goto-char pos)))))
|
||||
(setq n (1+ n)))))
|
||||
|
||||
(defun next-completion (&optional n)
|
||||
"Move according to `completions-format' to next completion item.
|
||||
In horizontal format movement is between columns within the same line,
|
||||
in vertical format between lines within the same column. With non-nil
|
||||
`completion-auto-wrap', movement continues to the next line or column,
|
||||
respectively."
|
||||
(interactive "p")
|
||||
(pcase completions-format
|
||||
('vertical (next-line-completion n))
|
||||
(_ (next-column-completion n))))
|
||||
|
||||
(defun previous-completion (&optional n)
|
||||
"Move according to `completions-format' to previous completion item.
|
||||
In horizontal format movement is between columns within the same line,
|
||||
in vertical format between lines within the same column. With non-nil
|
||||
`completion-auto-wrap', movement continues to the next line or column,
|
||||
respectively."
|
||||
(interactive "p")
|
||||
(pcase completions-format
|
||||
('vertical (previous-line-completion n))
|
||||
(_ (previous-column-completion n))))
|
||||
|
||||
(defvar choose-completion-deselect-if-after nil
|
||||
"If non-nil, don't choose a completion candidate if point is right after it.
|
||||
|
||||
|
|
|
|||
|
|
@ -734,10 +734,303 @@
|
|||
(let ((completion-auto-wrap nil))
|
||||
(first-completion)
|
||||
(next-line-completion 7)
|
||||
(should (equal "ac2" (get-text-property (point) 'completion--string)))
|
||||
(should (equal "ac1" (get-text-property (point) 'completion--string)))
|
||||
(previous-line-completion 7)
|
||||
(should (equal "aa1" (get-text-property (point) 'completion--string))))))
|
||||
|
||||
(defun completions-format-navigation--tests (n)
|
||||
"Make tests for navigating buffer of N completion candidate.
|
||||
The tests check expected results of navigating with and without wrapping
|
||||
for combinations of the values of `completion-auto-wrap' and
|
||||
`completions-format' (see bug#78959 for motivation and discussion of the
|
||||
expected behavior). The tests are actually run by calling this
|
||||
function, with specific values of N (> 1 to have a \"*Completions*\"
|
||||
buffer), from functions defined by `ert-deftest.'"
|
||||
(let* (
|
||||
;; Make list of N unique completions.
|
||||
(letters (mapcar 'string (number-sequence 97 122)))
|
||||
(gen-compl (lambda (x)
|
||||
(let (comps)
|
||||
(dotimes (_ x)
|
||||
(push (concat (car comps) (pop letters)) comps))
|
||||
(nreverse comps))))
|
||||
(completions (funcall gen-compl n))
|
||||
|
||||
;; Navigation tests.
|
||||
;; (i) For both horizontal and vertical formats.
|
||||
(all-completions
|
||||
(lambda (type)
|
||||
(let ((next-fn (pcase type
|
||||
('any 'next-completion)
|
||||
('column 'next-column-completion)
|
||||
('line 'next-line-completion)))
|
||||
(prev-fn (pcase type
|
||||
('any 'previous-completion)
|
||||
('column 'previous-column-completion)
|
||||
('line 'previous-line-completion))))
|
||||
(completing-read-with-minibuffer-setup completions
|
||||
(insert (car completions))
|
||||
(minibuffer-completion-help)
|
||||
(switch-to-completions)
|
||||
;; Sanity check that we're on first completion candidate.
|
||||
(should
|
||||
(equal (car completions)
|
||||
(get-text-property (point) 'completion--string)))
|
||||
;; Double check.
|
||||
(first-completion)
|
||||
(should
|
||||
(equal (car completions)
|
||||
(get-text-property (point) 'completion--string)))
|
||||
;; Test moving from first to Ith next completion
|
||||
;; candidate (0<I<N-1).
|
||||
(dolist (i (number-sequence 1 (1- n)))
|
||||
(funcall next-fn i)
|
||||
(should
|
||||
(equal (nth i completions)
|
||||
(get-text-property (point) 'completion--string)))
|
||||
(if (< i (1- n))
|
||||
(first-completion)
|
||||
(last-completion)
|
||||
(should
|
||||
(equal (nth i completions)
|
||||
(get-text-property (point) 'completion--string)))
|
||||
(funcall next-fn 1)
|
||||
(if completion-auto-wrap
|
||||
;; Wrap around to first completion candidate.
|
||||
(should
|
||||
(equal (car completions)
|
||||
(get-text-property (point) 'completion--string)))
|
||||
;; No wrapping.
|
||||
(should
|
||||
(equal (nth i completions)
|
||||
(get-text-property (point) 'completion--string))))))
|
||||
(last-completion)
|
||||
;; Test moving from last to Ith previous completion
|
||||
;; candidate (0<I<N-1).
|
||||
(dolist (i (number-sequence 1 (1- n)))
|
||||
(funcall prev-fn i)
|
||||
(should
|
||||
(equal (nth (- n i 1) completions)
|
||||
(get-text-property (point) 'completion--string)))
|
||||
(if (< i (1- n))
|
||||
(last-completion)
|
||||
(first-completion)
|
||||
(should
|
||||
(equal (car completions)
|
||||
(get-text-property (point) 'completion--string)))
|
||||
(funcall prev-fn 1)
|
||||
(if completion-auto-wrap
|
||||
;; Wrap around to last completion candidate.
|
||||
(should
|
||||
(equal (nth (1- n) completions)
|
||||
(get-text-property (point) 'completion--string)))
|
||||
;; No wrapping.
|
||||
(should
|
||||
(equal (car completions)
|
||||
(get-text-property (point)
|
||||
'completion--string))))))))))
|
||||
|
||||
;; (ii) Only for horizontal format.
|
||||
(within-column
|
||||
(lambda ()
|
||||
(completing-read-with-minibuffer-setup completions
|
||||
(insert (car completions))
|
||||
(minibuffer-completion-help)
|
||||
(switch-to-completions)
|
||||
(while (not (eolp))
|
||||
(completion--move-to-candidate-start)
|
||||
(let* ((first (get-text-property (point) 'completion--string))
|
||||
(pos (point))
|
||||
(i 0)
|
||||
last1 last2)
|
||||
;; Keep moving to next completion candidate in this
|
||||
;; column until we reach the last one, and then wrap
|
||||
;; back to the first candidate, if
|
||||
;; `completion-auto-wrap' is non-nil, otherwise stay
|
||||
;; on the last one.
|
||||
(while (or (and completion-auto-wrap
|
||||
(not (equal last1 first)))
|
||||
(not (equal last1
|
||||
(get-text-property
|
||||
(point) 'completion--string))))
|
||||
(setq last2 last1)
|
||||
(next-line-completion 1)
|
||||
(incf i)
|
||||
;; Set `last1' to either the first or last
|
||||
;; candidate, depending on the value of
|
||||
;; `completion-auto-wrap'.
|
||||
(setq last1 (get-text-property (point) 'completion--string)))
|
||||
(setq last1 last2
|
||||
last2 nil)
|
||||
(decf i)
|
||||
(when completion-auto-wrap
|
||||
(should (equal (get-text-property (point) 'completion--string)
|
||||
first))
|
||||
;; Test wrapping from last to first line in this column.
|
||||
(next-line-completion i) ; Move to last candidate.
|
||||
(should (equal (get-text-property (point) 'completion--string)
|
||||
last1)))
|
||||
;; Now keeping move from last to first completion
|
||||
;; candidate in this column.
|
||||
(while (or (not (equal last2 first))
|
||||
(not (equal last2
|
||||
(get-text-property
|
||||
(point) 'completion--string))))
|
||||
(previous-line-completion 1)
|
||||
(setq last2 (get-text-property (point) 'completion--string)))
|
||||
;; Test wrapping from first to last line in this column.
|
||||
(when completion-auto-wrap
|
||||
(should (equal (get-text-property (point) 'completion--string)
|
||||
first))
|
||||
(next-line-completion i)
|
||||
(should (equal (get-text-property (point) 'completion--string)
|
||||
last1)))
|
||||
;; Move to first candidate in next column to continue loop
|
||||
(completion--move-to-candidate-end)
|
||||
(unless (eolp)
|
||||
(goto-char pos)
|
||||
(next-column-completion 1)))))))
|
||||
|
||||
;; (iii) Only for vertical format.
|
||||
(within-line
|
||||
(lambda ()
|
||||
(completing-read-with-minibuffer-setup completions
|
||||
(insert (car completions))
|
||||
(minibuffer-completion-help)
|
||||
(switch-to-completions)
|
||||
(let ((one-col (save-excursion
|
||||
(first-completion)
|
||||
(completion--move-to-candidate-end)
|
||||
(eolp))))
|
||||
(while (not (eobp))
|
||||
(let ((first (get-text-property (point) 'completion--string))
|
||||
last pos)
|
||||
;; Test moving to next column in this line.
|
||||
(while (not (eolp))
|
||||
(next-column-completion 1)
|
||||
(let ((next (get-text-property (point) 'completion--string)))
|
||||
(should
|
||||
;; FIXME: tautology?
|
||||
(equal (nth (seq-position completions next) completions)
|
||||
next)))
|
||||
;; If this is the last completion in this line,
|
||||
;; exit the loop.
|
||||
(when (or (> (current-column) 0)
|
||||
(save-excursion (and (forward-line) (eobp)))
|
||||
(unless one-col
|
||||
(save-excursion
|
||||
(and (progn
|
||||
(completion--move-to-candidate-start)
|
||||
(bolp))
|
||||
(progn
|
||||
(completion--move-to-candidate-end)
|
||||
(eolp))))))
|
||||
(completion--move-to-candidate-end)))
|
||||
(backward-char)
|
||||
(completion--move-to-candidate-start)
|
||||
(setq last (get-text-property (point) 'completion--string)
|
||||
pos (point))
|
||||
;; We're on the last column, so next move either
|
||||
;; wraps or stays put.
|
||||
(next-column-completion 1)
|
||||
(if completion-auto-wrap
|
||||
;; We wrapped around to first candidate in this line.
|
||||
(progn
|
||||
(should (bolp))
|
||||
(should
|
||||
(equal (get-text-property (point) 'completion--string)
|
||||
first))
|
||||
;; Go back to last completion in this line for next test.
|
||||
(goto-char (if one-col pos (pos-eol)))
|
||||
(backward-char))
|
||||
(should
|
||||
(equal (get-text-property (point) 'completion--string)
|
||||
last)))
|
||||
;; Test moving to previous column in this line.
|
||||
(while (if one-col
|
||||
(save-excursion
|
||||
(forward-line -1)
|
||||
(get-text-property (point) 'completion--string))
|
||||
(not (bolp)))
|
||||
(previous-column-completion 1)
|
||||
(let ((prev (get-text-property (point) 'completion--string)))
|
||||
(should
|
||||
;; FIXME: tautology?
|
||||
(equal (nth (seq-position completions prev) completions)
|
||||
prev))))
|
||||
;; We're on the first column, so next move either
|
||||
;; wraps or stay put.
|
||||
(previous-column-completion 1)
|
||||
(if completion-auto-wrap
|
||||
;; We wrapped around to last candidate in this line.
|
||||
(progn
|
||||
(completion--move-to-candidate-end)
|
||||
(should (eolp))
|
||||
(backward-char)
|
||||
(should
|
||||
(equal (get-text-property (point) 'completion--string)
|
||||
last)))
|
||||
;; We stayed on the first candidate.
|
||||
(should
|
||||
(equal (get-text-property (point) 'completion--string)
|
||||
first)))
|
||||
(if one-col
|
||||
(goto-char (point-max))
|
||||
(forward-line)))))))))
|
||||
|
||||
;; Run tests.
|
||||
;; Test navigation with wrapping...
|
||||
(let ((completion-auto-wrap t))
|
||||
;; ...in horizontal format,
|
||||
(let ((completions-format 'horizontal))
|
||||
(funcall all-completions 'any)
|
||||
(funcall all-completions 'column)
|
||||
(funcall within-column))
|
||||
;; ...in vertical format.
|
||||
(let ((completions-format 'vertical))
|
||||
(funcall all-completions 'any)
|
||||
(funcall all-completions 'line)
|
||||
(funcall within-line)))
|
||||
;; Test navigation without wrapping...
|
||||
(let ((completion-auto-wrap nil))
|
||||
;; ...in horizontal format,
|
||||
(let ((completions-format 'horizontal))
|
||||
(funcall all-completions 'any)
|
||||
(funcall all-completions 'column)
|
||||
(funcall within-column))
|
||||
;; ...in vertical format.
|
||||
(let ((completions-format 'vertical))
|
||||
(funcall all-completions 'any)
|
||||
(funcall all-completions 'line)
|
||||
(funcall within-line)))))
|
||||
|
||||
;; (ert-deftest completions-format-navigation-test-1 ()
|
||||
;; (completions-format-navigation--tests 1))
|
||||
|
||||
(ert-deftest completions-format-navigation-test-2 ()
|
||||
(completions-format-navigation--tests 2))
|
||||
|
||||
(ert-deftest completions-format-navigation-test-3 ()
|
||||
(completions-format-navigation--tests 3))
|
||||
|
||||
(ert-deftest completions-format-navigation-test-4 ()
|
||||
(completions-format-navigation--tests 4))
|
||||
|
||||
(ert-deftest completions-format-navigation-test-5 ()
|
||||
(completions-format-navigation--tests 5))
|
||||
|
||||
(ert-deftest completions-format-navigation-test-9 ()
|
||||
(completions-format-navigation--tests 9))
|
||||
|
||||
(ert-deftest completions-format-navigation-test-10 ()
|
||||
(completions-format-navigation--tests 10))
|
||||
|
||||
(ert-deftest completions-format-navigation-test-15 ()
|
||||
(completions-format-navigation--tests 15))
|
||||
|
||||
(ert-deftest completions-format-navigation-test-16 ()
|
||||
(completions-format-navigation--tests 16))
|
||||
|
||||
(ert-deftest completion-cycle ()
|
||||
(completing-read-with-minibuffer-setup '("aaa" "bbb" "ccc")
|
||||
(let ((completion-cycle-threshold t))
|
||||
|
|
|
|||
Loading…
Reference in a new issue