-
-
Notifications
You must be signed in to change notification settings - Fork 60
Home
Vertico offers a set of small extension packages, which are included in the Vertico package. They can also be installed individually, e.g., only vertico.el and vertico-directory.el. Here we document a few additional tweaks and helpful commands, which can be added to user configurations.
If you use Orderless you can restrict the set of candidates to the currently visible candidates. This functionality is present in Ivy and bound to the key S-SPC. In Vertico we can use this small command:
(defun +vertico-restrict-to-matches ()
(interactive)
(let ((inhibit-read-only t))
(goto-char (point-max))
(insert " ")
(add-text-properties (minibuffer-prompt-end) (point-max)
'(invisible t read-only t cursor-intangible t rear-nonsticky t))))
(define-key vertico-map (kbd "S-SPC") #'+vertico-restrict-to-matches)
(defun +embark-live-vertico ()
"Shrink Vertico minibuffer when `embark-live' is active."
(when-let (win (and (string-prefix-p "*Embark Live" (buffer-name))
(active-minibuffer-window)))
(with-selected-window win
(when (and (bound-and-true-p vertico--input)
(fboundp 'vertico-multiform-unobtrusive))
(vertico-multiform-unobtrusive)))))
(add-hook 'embark-collect-mode-hook #'+embark-live-vertico)
When resizing the minibuffer (e.g., via the mouse), adjust the number of visible candidates in Vertico automatically.
(defun vertico-resize--minibuffer ()
(add-hook 'window-size-change-functions
(lambda (win)
(let ((height (window-height win)))
(when (/= (1- height) vertico-count)
(setq-local vertico-count (1- height))
(vertico--exhibit))))
t t))
(advice-add #'vertico--setup :before #'vertico-resize--minibuffer)
Prefix the current candidate with “» “.
(defvar +vertico-current-arrow t)
(cl-defmethod vertico--format-candidate :around
(cand prefix suffix index start &context ((and +vertico-current-arrow
(not (bound-and-true-p vertico-flat-mode)))
(eql t)))
(setq cand (cl-call-next-method cand prefix suffix index start))
(if (bound-and-true-p vertico-grid-mode)
(if (= vertico--index index)
(concat #("▶" 0 1 (face vertico-current)) cand)
(concat #("_" 0 1 (display " ")) cand))
(if (= vertico--index index)
(concat
#(" " 0 1 (display (left-fringe right-triangle vertico-current)))
cand)
cand)))
The default sorting function vertico-sort-function
can be adjusted based on the
completion category if you use vertico-multiform-mode
. See the README for more
details regarding vertico-multiform-mode
.
Note that the default sorting function vertico-sort-function
is only used if the
completion command (completion table) doesn’t specify its own
display-sort-function
. If you still want to override this setting you can use
set the vertico-sort-override-function
.
;; Configure the default sorting function for symbols and files
;; See `vertico-sort-function'.
(setq vertico-multiform-categories
'((symbol (vertico-sort-function . vertico-sort-alpha))
(file (vertico-sort-function . sort-directories-first))))
;; Forcibly override the sorting function for `consult-line'.
;; See `vertico-sort-override-function'.
(setq vertico-multiform-commands
'((consult-line (vertico-sort-override-function . vertico-sort-alpha))))
(defun sort-directories-first (files)
;; Still sort by history position, length and alphabetically
(setq files (vertico-sort-history-length-alpha files))
;; But then move directories first
(nconc (seq-filter (lambda (x) (string-suffix-p "/" x)) files)
(seq-remove (lambda (x) (string-suffix-p "/" x)) files)))
Those coming from ivy/counsel maybe missing the ability to visually distinguish directories from files in counsel-find-file. With Vertico you can setup the highlighting of completion candidates for all commands using the completion category file. We add a transform function to the candidate formatting function and configure a directory highlighter via the general vertico-multiform mechanism.
(defvar +vertico-transform-functions nil)
(cl-defmethod vertico--format-candidate :around
(cand prefix suffix index start &context ((not +vertico-transform-functions) null))
(dolist (fun (ensure-list +vertico-transform-functions))
(setq cand (funcall fun cand)))
(cl-call-next-method cand prefix suffix index start))
(defun +vertico-highlight-directory (file)
"If FILE ends with a slash, highlight it as a directory."
(if (string-suffix-p "/" file)
(propertize file 'face 'marginalia-file-priv-dir) ; or face 'dired-directory
file))
;; function to highlight enabled modes similar to counsel-M-x
(defun +vertico-highlight-enabled-mode (cmd)
"If MODE is enabled, highlight it as font-lock-constant-face."
(let ((sym (intern cmd)))
(if (or (eq sym major-mode)
(and
(memq sym minor-mode-list)
(boundp sym)))
(propertize cmd 'face 'font-lock-constant-face)
cmd)))
;; add-to-list works if 'file isn't already in the alist
;; setq can be used but will overwrite all existing values
(add-to-list 'vertico-multiform-categories
'(file
;; this is also defined in the wiki, uncomment if used
;; (vertico-sort-function . sort-directories-first)
(+vertico-transform-functions . +vertico-highlight-directory)))
(add-to-list 'vertico-multiform-commands
'(execute-extended-command
reverse
(+vertico-transform-functions . +vertico-highlight-enabled-mode)))
Vertico doesn’t by default annotate candidates when the flat, grid or
unobtrusive display mode is active. However we may still want to see keybindings
for M-x even if we use the unobtrusive display. Annotations can be enabled via
the variables vertico-grid-annotate
and vertico-flat-annotate
. Furthermore we
configure the short annotator marginalia-annotate-binding
which only adds the
key binding as annotation.
(setq vertico-multiform-commands
'(("\\`execute-extended-command" unobtrusive
(vertico-flat-annotate . t)
(marginalia-annotator-registry (command marginalia-annotate-binding)))))
The obsolete older approach uses the +vertico-transform-functions
. You can use
this if you don’t have Marginalia installed.
;; Taken from marginalia-annotate-binding
(defun +vertico-annotate-binding (command)
"Annotate COMMAND with key binding in flat/unobtrusive mode."
(if-let* (((or (bound-and-true-p vertico-flat-mode)
(bound-and-true-p vertico-unobtrusive-mode)))
(sym (intern-soft command))
(key (and (commandp sym) (where-is-internal sym nil 'first-only))))
(format #("%s (%s)" 3 7 (face shadow)) command (key-description key))
command))
(setq vertico-multiform-commands
'(("\\`execute-extended-command" unobtrusive
(+vertico-transform-functions . +vertico-annotate-binding))))
These are useful if you start doing something in the minibuffer and go to
another window before the minibuffer command is finished; eg if you’re using
consult-line
to move around to different search matches, but also edit the
buffer being searched. These commands probably work with other styles of
minibuffer in addition to vertico.
(defun down-from-outside ()
"Move to next candidate in minibuffer, even when minibuffer isn't selected."
(interactive)
(with-selected-window (active-minibuffer-window)
(execute-kbd-macro [down])))
(defun up-from-outside ()
"Move to previous candidate in minibuffer, even when minibuffer isn't selected."
(interactive)
(with-selected-window (active-minibuffer-window)
(execute-kbd-macro [up])))
(defun to-and-fro-minibuffer ()
"Go back and forth between minibuffer and other window."
(interactive)
(if (window-minibuffer-p (selected-window))
(select-window (minibuffer-selected-window))
(select-window (active-minibuffer-window))))
(defun vertico--swap-annotations (result)
;; Move annotations only for files
(if minibuffer-completing-file-name
(mapcar (lambda (x)
;; Swap prefix/suffix annotations
(list (car x) (concat (string-trim-left (caddr x)) " ") (cadr x)))
result)
result))
(advice-add #'vertico--affixate :filter-return #'vertico--swap-annotations)
In this section a command vertico-directory-delete-entry
was provided, which was
an enhanced version of vertico-directory-up
. It removes the entire string after
the last slash. These improvements have now been added to vertico-directory-up
itself. Altered from vertico-directory-up
to alternatively remove the entire
entry after the last “/”.
This advice to vertico-insert
can be used to keep track of which directories you
have visited in find-file. Normally candidates are only added to the history on
vertico-exit
(viewing them in a buffer). With this and sorting by history, the
most recently visited folders will show up on top.
(defadvice vertico-insert
(after vertico-insert-add-history activate)
"Make vertico-insert add to the minibuffer history."
(unless (eq minibuffer-history-variable t)
(add-to-history minibuffer-history-variable (minibuffer-contents))))
Advise vertico-directory-up
to save the directory being exited.
(defvar previous-directory nil
"The directory that was just left. It is set when leaving a directory and
set back to nil once it is used in the parent directory.")
(defun set-previous-directory ()
"Set the directory that was just exited from within find-file."
(when (< (minibuffer-prompt-end) (point))
(save-excursion
(goto-char (1- (point)))
(when (search-backward "/" (minibuffer-prompt-end) t)
;; set parent directory
(setq previous-directory (buffer-substring (1+ (point)) (point-max)))
;; set back to nil if not sorting by directories or what was deleted is not a directory
(when (not (string-suffix-p "/" previous-directory))
(setq previous-directory nil))
t))))
(advice-add #'vertico-directory-up :before #'set-previous-directory)
Advise vertico--update
to select the previous directory.
(define-advice vertico--update (:after (&rest _) choose-candidate)
"Pick the previous directory rather than the prompt after updating candidates."
(cond
(previous-directory ; select previous directory
(setq vertico--index (or (seq-position vertico--candidates previous-directory)
vertico--index))
(setq previous-directory nil))))
Marginalia does a nice job left-truncating filenames associated with buffers.
But recentf
files can also be quite long, crowding out the marginalia info. To
left-truncate long filenames with vertico, you can use (adjusting the amount of
room saved as needed):
(defun my/vertico-truncate-candidates (args)
(if-let ((arg (car args))
(type (get-text-property 0 'multi-category arg))
((eq (car-safe type) 'file))
(w (max 30 (- (window-width) 38)))
(l (length arg))
((> l w)))
(setcar args (concat "…" (truncate-string-to-width arg l (- l w)))))
args)
(advice-add #'vertico--format-candidate :filter-args #'my/vertico-truncate-candidates)
;; Adapted from vertico-reverse
(defun vertico-bottom--display-candidates (lines)
"Display LINES in bottom."
(move-overlay vertico--candidates-ov (point-min) (point-min))
(unless (eq vertico-resize t)
(setq lines (nconc (make-list (max 0 (- vertico-count (length lines))) "\n") lines)))
(let ((string (apply #'concat lines)))
(add-face-text-property 0 (length string) 'default 'append string)
(overlay-put vertico--candidates-ov 'before-string string)
(overlay-put vertico--candidates-ov 'after-string nil))
(vertico--resize-window (length lines)))
(advice-add #'vertico--display-candidates :override #'vertico-bottom--display-candidates)
https://old.reddit.com/r/emacs/comments/rbmfwk/weekly_tips_tricks_c_thread/hof7rz7/
(advice-add #'vertico-next
:around
#'(lambda (origin &rest args)
(let ((beg-index vertico--index))
(apply origin args)
(if (not (eq 1 (abs (- beg-index vertico--index))))
(ding)))))
Binding this function to TAB
in vertico-map
temporarily disables vertico while
completing remote paths to restore the shell-like TAB-completes-common-prefix
behavior. This is a usability trade-off to work around a peculiarity in TRAMP’s
hostname completion.
https://github.com/minad/vertico/issues/240
(defun my-vertico-insert-unless-tramp ()
"Insert current candidate in minibuffer, except for tramp."
(interactive)
(if (vertico--remote-p (vertico--candidate))
(minibuffer-complete)
(vertico-insert)))
prescient.el is a sorting and filtering package. For certain interfaces, such as
Vertico and Corfu, there are integration packages that will set up sorting and
filtering. For Vertico, this package is called vertico-prescient
and is
available on MELPA.
Sorting in prescient.el
is based on frecency, a combination of frequency and
recency. Unlike Vertico’s default sorting method, which uses a command’s
minibuffer history, with prescient.el
, all commands (except for those
specifying their own sort order) are sorted in the same way, using the same
frecency rankings. For example, a candidate chosen in command foo1
using
history variable foo1-hist
will be sorted near the top when running command
foo2
using history variable foo2-hist
.
When candidates are filtered using the prescient
completion style and
sorted via prescient-completion-sort
(as would happen with the default
setup of the package) one can optionally sort fully matched candidates
before other candidates while maintaining the frecency-based sorting.
In order to make prescient.el
remember a string, the package advises
vertico-insert
(which is used by vertico-exit
) with a little bit of glue code.
This will not record the submission of arbitrary input using M-RET
, but
arbitrary input usually does not occur in candidate lists anyway.
Below is an example configuration. Some of the below is the default behavior and is only included as an example.
;; After installing the package
(vertico-prescient-mode 1)
;; Configure `prescient.el' filtering to your liking.
(setq prescient-filter-method '(literal initialism prefix regexp)
prescient-use-char-folding t
prescient-use-case-folding 'smart
prescient-sort-full-matches-first t ; Works well with `initialism'.
prescient-sort-length-enable t)
;; Save recency and frequency rankings to disk, which let them become better
;; over time.
(prescient-persist-mode 1)
The following configuration will provide a more familiar default directory
navigation experience on find-file
for ivy and ido converts. It does depend
on a version of vertico that has the vertico-preselect
option available.
The result of this configuration tweak is that /
will be bound to
my/vertico-insert
in vertico-map
with vertico-preselect
set to
directory
.
my/vertico-insert
will insert the first candidate if it is currently a
directory on pressing /
which allows for rapid filesystem navigation in the
style that is familiar to ido and ivy users. It does not insert the first
candidate if the previous character is one of /
~
or :
. This makes the
behavior consistent with ido and ivy when resetting the search prompt to the
file system root, a home directory, or when operating on a TRAMP prefix,
respectively.
This configuration also requires vertico-directory
and binding
vertico-directory-enter
to RET
in vertico-map
. Combined with the above
binding you can then have rapid single-RET dired invocations on /
completed
insertions of directory paths, as is familiar to ivy and ido users.
(use-package vertico
:ensure t
:demand
:config
(setq vertico-cycle t)
;; currently requires melpa version of vertico
(setq vertico-preselect 'directory)
:init
(vertico-mode)
(defun my/vertico-insert ()
(interactive)
(let* ((mb (minibuffer-contents-no-properties))
(lc (if (string= mb "") mb (substring mb -1))))
(cond ((string-match-p "^[/~:]" lc) (self-insert-command 1 ?/))
((file-directory-p (vertico--candidate)) (vertico-insert))
(t (self-insert-command 1 ?/)))))
:bind (:map vertico-map
("/" . #'my/vertico-insert)))
;; Configure directory extension.
(use-package vertico-directory
:after vertico
:ensure t
:demand
;; More convenient directory navigation commands
:bind (:map vertico-map
("RET" . vertico-directory-enter)
("DEL" . vertico-directory-delete-char)
("M-DEL" . vertico-directory-delete-word))
;; Tidy shadowed file names
:hook (rfn-eshadow-update-overlay . vertico-directory-tidy))
When using vertico with the buffer display type (via vertico-multiform), if you cancel the command, the hidden *Minibuf-[1-9]*
buffer window remains on the winner-undo-list
, and gets popped back on going back to a prior window config. The buffer is somehow marked as non-closable, so you have to delete the entire frame. The solution is to set winner-boring-buffer-regexp
to ” \*Minibuf-[0-9]+”, which will cause winner to avoid restoring these windows.
With vertico-multiform, it is possible to combine buffer and grid display, as show in the documentation, e.g. (setq vertico-multiform-categories '((file buffer grid)))
. However, it is also possible to toggle this on and off, by defining the following function, and binding it in vertico-multiform-map
(e.g. (bind-key "M-H" 'vertico-multiform-buffer-grid 'vertico-multiform-map)
or use :bind (:map vertico-multiform-map ("M-H" . vertico-multiform-buffer-grid))
with use-package).
(defun vertico-multiform-buffer-grid ()
"Toggle displaying Vertico as a grid in a large window (like a regular buffer)."
(interactive)
(if (equal '(vertico-buffer-mode vertico-grid-mode) (car vertico-multiform--stack))
(vertico-multiform-vertical)
(setcar vertico-multiform--stack '(vertico-buffer-mode vertico-grid-mode))
(vertico-multiform--toggle 1)))
It is possible to change candidate sorting during a Vertico session. For example, the following function (when bound in vertico-map
) toggles files between the default sorting (vertico-sort-history-length-alpha
) and sorting by directories first (using the sort-directories-first
function shown earlier on this wiki page). The change only lasts for the current Vertico session. The function can be modified to make the toggling permanent, by using 'vertico-sort-function
directly, without make-local-variable
.
(defun toggle-sort-directories-first ()
(interactive)
(if (eq vertico-sort-function 'sort-directories-first)
(set (make-local-variable 'vertico-sort-function) 'vertico-sort-history-length-alpha)
(set (make-local-variable 'vertico-sort-function) 'sort-directories-first))
(setq vertico--input t)
(vertico--update))
See also the Consult Wiki, the Embark Wiki and the Corfu Wiki!