-
-
Notifications
You must be signed in to change notification settings - Fork 61
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 “» “.
(advice-add #'vertico--format-candidate :around
(lambda (orig cand prefix suffix index _start)
(setq cand (funcall orig cand prefix suffix index _start))
(concat
(if (= vertico--index index)
(propertize "» " 'face 'vertico-current)
" ")
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)))
You can customise the highlighting of completion candidates based on completion
category. For example those coming from ivy/counsel maybe missing the ability to
visually distinguish directories from files in counsel-find-file
. You can set up
something similar with vertico.
We advise the candidate formatting function in order to transform the candidates
before they are displayed. The transform functions can then be configured via
the general vertico-multiform
mechanism.
(defvar +vertico-transform-functions nil)
(defun +vertico-transform (args)
(dolist (fun (ensure-list +vertico-transform-functions) args)
(setcar args (funcall fun (car args)))))
(advice-add #'vertico--format-candidate :filter-args #'+vertico-transform)
(defun +vertico-highlight-directory (file)
"Highlight FILE if it ends with a slash."
(if (string-suffix-p "/" file)
(propertize file 'face 'marginalia-file-priv-dir)
file))
(setq vertico-multiform-commands
'(("find-file" flat
(vertico-sort-function . sort-directories-first)
(+vertico-transform-functions . +vertico-highlight-directory))))
Here we don’t use the vertico-multiform
mechanism. Instead we introduce an alist
with the completion category as key.
(defun +vertico-highlight-directory (file)
"Highlight FILE if it ends with a slash."
(if (string-suffix-p "/" file)
(propertize file 'face 'marginalia-file-priv-dir)
file))
(defvar +completion-category-hl-func-overrides
`((file . ,#'+vertico-highlight-directory))
"Alist mapping category to highlight functions.")
(defun +completion-category-hl-candidate (args)
(when-let (fun (alist-get (vertico--metadata-get 'category)
+completion-category-hl-func-overrides))
(setcar args (funcall fun (car args))))
args)
(advice-add #'vertico--format-candidate :filter-args #'+completion-category-hl-candidate)
And the following could be added to the previous code to highlight enabled modes
in the command palette (M-x
).
(defun +completion-category-highlight-commands (cand)
(let ((len (length cand)))
(when (and (> len 0)
(with-current-buffer (nth 1 (buffer-list)) ; get buffer before minibuffer
(or (eq major-mode (intern cand)) ; check major mode
(ignore-errors (auto-minor-mode-enabled-p (intern cand)))))) ; check minor modes
(add-face-text-property 0 len '(:foreground "red") 'append cand))) ; choose any color or face you like
cand)
(add-to-list '+completion-category-hl-func-overrides `(command . ,#'+completion-category-highlight-commands))
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)
Altered from vertico-directory-up
to alternatively remove the entire entry after
the last “/”.
(defun vertico-directory-delete-entry ()
"Delete directory or entire entry before point."
(interactive)
(when (and (> (point) (minibuffer-prompt-end))
;; Check vertico--base for stepwise file path completion
(not (equal vertico--base ""))
(eq 'file (vertico--metadata-get 'category)))
(save-excursion
(goto-char (1- (point)))
(when (search-backward "/" (minibuffer-prompt-end) t)
(delete-region (1+ (point)) (point-max))
t))))
You can use vertico-directory-enter
to enter a directory or open a file
depending on what is selected.
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. An example configuration is provided at the end of this section.
Recently, prescient.el
added a completion style that can be used in the user
option completion-styles
. It is similar in function to Orderless.
When using the prescient
style, as with orderless
, it is recommended to keep
the basic
style after to better support certain dynamic completion tables.
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
.
To use prescient.el’s sorting in Veritco set the user
option vertico-sort-function
to the function prescient-completion-sort
.
This function uses frecency sorting for all candidates and, when the prescient
completion style is filtering, allows for sorting fully matched candidates before
partially matched candidates. Note that the sorting of fully matched candidates
won’t work for candidates filtered by other completion styles.
In order to make prescient.el
remember a string, it must be passed to the
function prescient-remember
. It is sufficient to advise the command
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.
;; Enable the completion style.
(setq completion-styles '(prescient basic))
;; Use `prescient-completion-sort' after filtering.
(setq vertico-sort-function #'prescient-completion-sort)
(defun vertico-prescient-remember ()
"Remember the chosen candidate with Prescient."
(when (>= vertico--index 0)
(prescient-remember
(substring-no-properties
(nth vertico--index vertico--candidates)))))
(advice-add #'vertico-insert :after #'vertico-prescient-remember)
;; 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)
See also the Consult Wiki, the Embark Wiki and the Corfu Wiki!