prescient.el: simple but effective sorting and filtering for Emacs.
prescient.el is a library which sorts and filters lists of
candidates, such as appear when you use a package like Ivy or
Company. Extension packages such as ivy-prescient.el and
company-prescient.el adapt the library for usage with various
frameworks.
prescient.el also provides a completion style (prescient) for
filtering candidates via Emacs's generic completion, such as in
Icomplete, Vertico, and Corfu. These last two have extension
packages to correctly set up filtering and sorting.
As compared to other packages which accomplish similar tasks,
including IDO, Ivy, Helm, Smex, Flx, Historian, and
Company-Statistics, prescient.el aims to be simpler, more
predictable, and faster.
prescient.el is available on MELPA as six separate packages (one
for the library, and the rest for integrating with other frameworks):
The easiest way to install these packages is using
straight.el:
(straight-use-package 'prescient)
(straight-use-package 'corfu-prescient)
(straight-use-package 'company-prescient)
(straight-use-package 'ivy-prescient)
(straight-use-package 'selectrum-prescient)
(straight-use-package 'vertico-prescient)
However, you may install using any other package manager if you prefer.
prescient.el and the extension packages provide modes that configure
filtering and/or sorting in their respective framework. These modes
can have their own settings, such as ways to set up filtering but
not sorting, which are described in a following section.
-
To cause Emacs to use the
prescientcompletion style for filtering, addprescientto the user optioncompletion-styles. -
To cause Corfu to use
prescient.elsorting and filtering, enablecorfu-prescient-mode. -
To cause Company to use
prescient.elsorting, enablecompany-prescient-mode. -
To cause Ivy to use
prescient.elsorting and filtering, enableivy-prescient-mode. -
To cause Selectrum to use
prescient.elsorting and filtering, enableselectrum-prescient-mode. -
To cause Vertico to use
prescient.elsorting and filtering, enablevertico-prescient-mode. -
To cause your usage statistics to be saved between Emacs sessions, enable
prescient-persist-mode.
Please note that you must load Counsel before ivy-prescient.el.
This is because loading Counsel results in a number of changes being
made to the user options of Ivy, which ivy-prescient.el must then
undo.
prescient.el takes as input a list of candidates, and a query that
you type.
When filtering, the query is first split on spaces into subqueries
(two consecutive spaces match a literal space). Each subquery filters
the candidates according to the filter methods listed in
prescient-filter-method. By default, a subquery must match as either
a substring of the candidate, a regexp, or an initialism (e.g. ffap
matches find-file-at-point, and so does fa). A candidate must
match all subqueries to pass the filter and subqueries can be matched
in any order.
When sorting, the last few candidates you selected are displayed first, followed by the most frequently selected ones, and then the remaining candidates are sorted by length.
If you would like prescient.el to forget about a candidate, use the
command prescient-forget.
-
prescient-history-length: The number of recently selected candidates that are remembered and displayed at the top of the list. -
prescient-frequency-decay:prescient.elkeeps a "frequency" for each selected candidate, which is incremented by one each time you select the candidate. To keep things tidy, frequencies are multiplied by this variable's value each time you select a new candidate, so they decrease over time. -
prescient-frequency-threshold: Once the frequency for an infrequently used command falls below the value of this variable,prescient.elforgets about it. -
prescient-save-file: Where to save statistics that are persisted between Emacs sessions whenprescient-persist-modeis active. The default value follows the conventions ofno-littering. -
prescient-filter-method: A list of algorithms to use for filtering candidates. The default isliteral,regexp, andinitialismas described above, but you can also use substring matching, initialism matching, regexp matching, fuzzy matching, prefix matching, anchored matching, literal-prefix matching, or any combination of those. See the docstring for full details. -
prescient-filter-alist: An alist of symbol-function pairs that associate a symbol inprescient-filter-methodwith a function that creates a regexp for matching a candidate. You can add to this alist to define your own custom filter methods, and use them by adding the appropriate symbol toprescient-filter-method. -
prescient-sort-full-matches-first: Whetherprescient.elsorts candidates that are fully matched before candidates that are partially matched. This user option affects:corfu-prescient.elcompany-prescient.elfor Company backends that used theprescientcompletion style for filteringselectrum-prescient.elvertico-prescient.el
-
prescient-sort-length-enable: Whether to sort the candidates by length in addition to recency and frequency. -
prescient-tiebreaker: Function to use for breaking ties in recency instead of length. -
prescient-use-char-folding: Whether theliteralandliteral-prefixfilter methods use character folding. -
prescient-use-case-folding: Whether filtering methods use case folding (in non-Emacs terms, whether they are case insensitive). This can be one ofnil,t, orsmart(the default). Ifsmart, then case folding is disabled when upper-case characters are used. -
Quickly adjusting filtering: Commands are available to temporarily toggle filter methods on or off while you're completing candidates. These commands are similar in usage to Isearch's own toggling commands, except that multiple filtering methods can be active at the same time.
For example, to toggle regexp filtering on or off (perhaps you're searching for a long/complex candidate), you can press
M-s r. If you wish to use only regexp filtering, you can useC-u M-s rto unconditionally turn on regexp filtering and turn off all other methods. This toggling is a buffer-local effect, and does not change the default filtering behavior. For that, customizeprescient-filter-method.selectrum-prescient.elandvertico-prescient.elwill both bind commands to toggle filter methods in the current completion buffer.corfu-prescient.elwill bind the commands while the Corfu pop-up is active. While the integration mode is enabled,M-sis bound toprescient-toggle-mapin the completion buffer or Corfu pop-up, and is used as a prefix key to access the commands.Key Command M-s aprescient-toggle-anchoredM-s fprescient-toggle-fuzzyM-s iprescient-toggle-initialismM-s lprescient-toggle-literalM-s pprescient-toggle-prefixM-s Pprescient-toggle-literal-prefixM-s rprescient-toggle-regexpM-s 'prescient-toggle-char-foldM-s cprescient-toggle-case-foldWhen defining custom filter methods, you can create new bindings using
prescient-create-and-bind-toggle-command, which takes an unquoted filter symbol and a string that can be used bykbd. For example,(prescient-create-and-bind-toggle-command my-foo "M-f")will bind a command for toggling the
my-foofilter toM-s M-f.
prescient.el defines two faces: prescient-primary-highlight and
prescient-secondary-highlight. The primary highlight is used to
highlight matches in candidates. The secondary highlight is used for
important sections within each matched region. For example, the
initialism filter method highlights the entire match with
prescient-primary-highlight and each initial in the initialism with
prescient-secondary-highlight.
These faces are used by the prescient completion style (and so
completion frameworks using that style, such as Corfu and Vertico) and
Selectrum. ivy-prescient.el uses Ivy's faces.
The following example shows customizing these faces. I use the Zerodark color theme, which includes colors for Ivy, but not for Selectrum. I inspected the theme source code to see what colors were being used for Ivy, and copied them to be used for Selectrum as well:
(require 'zerodark-theme)
(let ((class '((class color) (min-colors 89))))
(custom-theme-set-faces
'zerodark
`(selectrum-current-candidate
((,class (:background "#48384c"
:weight bold
:foreground "#c678dd"))))
`(prescient-primary-highlight
((,class (:foreground "#da8548"))))
`(prescient-secondary-highlight
((,class (:foreground "#98be65"))))))
(enable-theme 'zerodark)The following user options are specific to using the prescient
completion style:
prescient-completion-highlight-matches: Whether the completion style should highlight matches in the filtered candidates using the facesprescient-primary-highlightandprescient-secondary-highlight.
corfu-prescient.el configures filtering locally in buffers in
which corfu-mode is active. To do this, it modifies the values of
completion-styles, completion-category-overrides, and
completion-category-defaults. Sorting is configured globally.
The following user options are specific to using prescient.el with
Corfu:
-
corfu-prescient-completion-styles: What the value ofcompletion-stylesis changed to. -
corfu-prescient-completion-category-overrides: Overrides that should be included incompletion-category-overrides. -
corfu-prescient-enable-filtering: If non-nil whencorfu-prescient-modeis enabled, thenM-sis bound toprescient-toggle-mapwhile the Corfu pop-up is activecompletion-stylesis changed to the value ofcorfu-prescient-completion-stylescompletion-category-overridesis changed to include overrides incorfu-prescient-completion-category-overridescompletion-category-defaultsis set tonil
-
corfu-prescient-enable-sorting: If non-nil whencorfu-prescient-modeis enabled, thencorfu-sort-functionis set to the functionprescient-completion-sort. -
corfu-prescient-override-sorting: If non-nil whencorfu-prescient-modeis enabled, thencorfu-sort-override-functionis set to the functionprescient-completion-sortandcorfu-prescient-enable-sortingis made non-nil.
The following user options are specific to using prescient.el
sorting with Company:
company-prescient-sort-length-enable: By default, the standardprescient.elsorting algorithm is used for all Company completions whencompany-prescient-modeis enabled. However, this algorithm is inappropriate in some situations. In particular, some Company backends return fuzzy-matched candidates with an intelligent sorting pre-applied. In this case, the fallback sorting by length thatprescient.eldoes will just make a giant mess of things. By customizing this user option to nil for such Company backends (see Radian for an example), you can avoid the problem. Thenprescient.elwill helpfully move recently and frequently used candidates to the top of the completions list, but otherwise leave candidate ordering alone.
The following user options are specific to using prescient.el with
Ivy:
-
ivy-prescient-sort-commands: By default, all commands have their candidates sorted. You can override this behavior by customizingivy-prescient-sort-commands. See the docstring. -
ivy-prescient-retain-classic-highlighting: By default, the highlighting behavior ofivy-prescient.elis slightly different from Ivy's highlighting forivy--regex-ignore-order. You can recover the original behavior by customizing this user option; see the docstring for more details. -
ivy-prescient-enable-filtering: If set to nil, thenivy-prescient.eldoes not applyprescient.elfiltering to Ivy. See the Ivy documentation for information on how Ivy filters by default, and how to customize it manually. -
ivy-prescient-enable-sorting: If set to nil, thenivy-prescient.eldoes not applyprescient.elsorting to Ivy. See the Ivy documentation for information on how Ivy sorts by default, and how to customize it manually.
The following user options are specific to using prescient.el with
Selectrum:
-
selectrum-prescient-enable-filtering: If set to nil, thenselectrum-prescient.eldoes not change filtering of Selectrum. See the Selectrum documentation for information on how Selectrum configures filtering by default, and how to customize it manually.Additionally, when set, the matched part of each candidate is highlighted using the faces described above.
-
selectrum-prescient-enable-sorting: If set to nil, thenselectrum-prescient.eldoes not change sorting of Selectrum. See the Selectrum documentation for information on how Selectrum configures sorting by default, and how to customize it manually.
vertico-prescient.el configures filtering locally in the Vertico
buffer. To do this, it modifies the values of completion-styles,
completion-category-overrides, and completion-category-defaults.
Sorting is configured globally.
The following user options are specific to using prescient.el with
Vertico:
-
vertico-prescient-completion-styles: What the value ofcompletion-stylesis changed to. -
vertico-prescient-completion-category-overrides: Overrides that should be included incompletion-category-overrides. -
vertico-prescient-enable-filtering: If non-nil whenvertico-prescient-modeis enabled, thenM-sis bound toprescient-toggle-mapcompletion-stylesis changed to the value ofvertico-prescient-completion-stylescompletion-category-overridesis changed to include overrides invertico-prescient-completion-category-overridescompletion-category-defaultsis set tonil
-
vertico-prescient-enable-sorting: If non-nil whenvertico-prescient-modeis enabled, thenvertico-sort-functionis set to the functionprescient-completion-sort. -
vertico-prescient-override-sorting: If non-nil whenvertico-prescient-modeis enabled, thenvertico-sort-override-functionis set to the functionprescient-completion-sortandvertico-prescient-enable-sortingis made non-nil.
For use with completion-preview-mode in Emacs 30:
(setq completion-preview-sort-function #'prescient-completion-sort)Please see the contributor guide for my projects.