Emacs: mct version 0.5.0
Below are the release notes. If you have no idea what mct
is, it is a
thin layer of interactivity on top of the default completion interface,
which works best on Emacs 28 or higher (Emacs 27 is supported but lacks
the ability to show completions in a single column). Watch the video
demo of the initial release.
This entry covers the changes made to the “Minibuffer and Completions in
Tandem” (mct
package) since the release of version 0.4.0 on 2022-01-19.
There have been about 60 commits in the meantime.
For further details on the user-facing options covered herein, please
read the manual: https://protesilaos.com/emacs/mct. Or evaluate the
following expression if you already have mct
installed:
(info "(mct) Top")
Customisation options
Size of the Completions buffer
The user option mct-completion-window-size
controls the maximum and
minimum height of the window where the *Completions*
buffer is shown.
It accepts a cons cell in the form of (MAX-HEIGHT . MIN-HEIGHT)
. Valid
values are natural numbers (positive integers) or functions which return
such numbers. The default is a combination of the two for the sake of
illustration:
(setq mct-completion-window-size (cons #'mct--frame-height-fraction 1))
With this in place, mct will let the *Completions*
grow up to 1/3 of the
frame’s height (per the mct--frame-height-fraction
). When live
completion is performed (see the user option mct-live-completion
), the
window will shrink to fit the candidates.
To make the *Completions*
have a fixed height instead, simply set the
same number/function twice.
If set to nil, mct will simply not try to fit the Completions’ buffer to its window.
Thanks to Daniel Mendler for the feedback in issue 14: https://gitlab.com/protesilaos/mct/-/issues/14.
Passlist and blocklist accept completion categories
The user options mct-completion-passlist
and mct-completion-blocklist
used to only match symbols of commands like find-file
, whereas now they
can affect any completion category such as file
, kill-ring
, et cetera.
Sample code:
;; This is for commands or completion categories that should always pop
;; up the completions' buffer. It circumvents the default method of
;; waiting for some user input (see `mct-minimum-input') before
;; displaying and updating the completions' buffer.
(setq mct-completion-passlist
'(;; Some commands
Info-goto-node
Info-index
Info-menu
vc-retrieve-tag
;; Some completion categories
imenu
file
buffer
kill-ring
consult-location))
The manual provides a comprehensive list of known completion categories: https://protesilaos.com/emacs/mct#h:1f42c4e6-53c1-4e8a-81ef-deab70822fa4.
Or evaluate:
(info "(mct) Known completion categories")
Persist live completion for dynamic completion tables
Quoting from the documentation of the mct-persist-dynamic-completion
user option:
When non-nil, keep dynamic completion live.
Without any intervention from MCT, the default Emacs behavior for commands such as
find-file
or for afile
completion category is to hide the*Completions*
buffer after updating the list of candidates in a non-exiting fashion (e.g. select a directory and expect to continue typing the path). This, however, runs contrary to the interaction model of MCT when it performs live completions, because the user expects the Completions’ buffer to remain visible while typing out the path to the file.When this user option is non-nil (the default) it makes all non-exiting commands keep the
*Completions*
visible when updating the list of candidates.This applies to prompts in the
file
completion category whenever the user selects a candidate withmct-choose-completion-no-exit
,mct-edit-completion
,minibuffer-complete
,minibuffer-force-complete
(i.e. any command that does not exit the minibuffer).The two exceptions are (i) when the current completion session runs a command or category that is blocked by the
mct-completion-blocklist
or (ii) the user optionmct-live-completion
is nil.The underlying rationale:
Most completion commands present a flat list of candidates to choose from. Picking a candidate concludes the session. Some prompts, however, can recalculate the list of completions based on the selected candidate. A case in point is
find-file
(or any command with thefile
completion category) which dynamically adjusts the completions to show only the elements which extend the given file system path. We call such cases “dynamic completion”. Due to their particular nature, these need to be handled explicitly. The present user option is provided primarily to raise awareness about this state of affairs.
Deprecation of mct-region-completions-format
The mct-region-completions-format
used to be the only user option that
affected the mct-region-mode
. It was removed in the interest of
simplicity and to avoid potential complications or bugs. Having
separate user options for mct-minibuffer-mode
and mct-region-mode
would
inevitably lead to duplication and a considerable expansion of the code
base with all sorts of exceptions and checks.
In-buffer completion now uses the same mct-completions-format
as its
minibuffer-based counterpart.
Deprecation of regexp for name of Completions
There used to be a user option mct-completion-windows-regexp
which
targeted the name of the *Completions*
buffer. This was legacy code
from the early days of the code base: there is no reason to provide a
customisation of this sort. The defcustom
has been converted into a
defvar
so anyone who still needs the feature can access it:
mct--completions-window-name
.
Sorting the completions on Emacs 29
Starting with commit a46421446f
to emacs.git (by me) users have the
option to control how the completions are sorted: the variable is
completions-sort
. Its default value is the same as before, namely, a
lexicographic order, though it accepts an arbitrary function.
The mct manual provides samples of such functions (improvements are always welcome): https://protesilaos.com/emacs/mct#h:493922c7-efdc-4b63-aa96-b31c684eb4fa.
Or evaluate:
(info "(mct) Sort completion candidates on Emacs 29")
For your convenience:
;; Some sorting functions...
(defun my-sort-by-alpha-length (elems)
"Sort ELEMS first alphabetically, then by length."
(sort elems (lambda (c1 c2)
(or (string-version-lessp c1 c2)
(< (length c1) (length c2)))))))
(defun my-sort-by-history (elems)
"Sort ELEMS by minibuffer history.
Use `mct-sort-sort-by-alpha-length' if no history is available."
(if-let ((hist (and (not (eq minibuffer-history-variable t))
(symbol-value minibuffer-history-variable))))
(minibuffer--sort-by-position hist elems)
(my-sort-by-alpha-length elems)))
(defun my-sort-multi-category (elems)
"Sort ELEMS per completion category."
(pcase (mct--completion-category)
('nil elems) ; no sorting
('kill-ring elems)
('project-file (my-sort-by-alpha-length elems))
(_ (my-sort-by-history elems))))
;; Specify the sorting function.
(setq completions-sort #'my-sort-multi-category)
Remember to check the manual for all known completion categories.
Changes to the manual
-
The documentation has been overhauled to better present its contents. User options now have a parent section while each of them occupies its own node, making it easier to find exactly what one needs.
-
There is a workaround on how to circumvent the known issue where
global-hl-line-mode
overrides the mct highlight. Thanks to Tomasz Hołubowicz for the feedback in issue 1 over at the GitHub mirror: https://github.com/protesilaos/mct/issues/1. -
A node is included which explains that mct uses the remap mechanism for specifying key bindings when it is appropriate. As this can lead to unexpected issues in certain user configurations, the manual explains how to resolve any conflict. Thanks to Daniel Mendler for the feedback on the matter (done in various threads).
-
Users of both
mct
andcorfu
packages may experience a conflict. Daniel Mendler (Corfu’s developer) provided a snippet which is covered in the Corfu’s README as well as the mct manual on how to address the potential issue: https://gitlab.com/protesilaos/mct/-/issues/16. -
The
emacs-mct
package for Guix is now covered in the section about installing mct. Thanks to Andrew Tropin and Nicolas Goaziou for making it happen: https://issues.guix.gnu.org/53812.
Bug fixes and other refinements
-
The timer which controls when the Completions’ buffer is displayed or updated now cancels any outdated constructs instead of creating new ones. In other words, it is optimised. Thanks to Daniel Mendler for the patch which was sent via email and is recorded as commit
4ce1004
. -
Version
0.4.1
fixed a regression with an out-of-bounds motion when performing certain motions in the*Completions*
with a numeric argument. -
Version
0.4.2
addressed a regression wheremct-region-mode
would fail to perform live updates. Thanks to Z.Du for reporting the bug in issue 17: https://gitlab.com/protesilaos/mct/-/issues/17. -
Motions in the Completions buffer are now always based on the candidate rather than the line. The old design would fail to identify the first (topmost) candidate if its text was prefixed by entries that were not part of the completion table, such as icons provided by the
all-the-icons-completion
package. -
The command
mct-keyboard-quit-dwim
(bound toC-g
by default) now works properly with themct-region-mode
. Thanks to James Norman Vladimir Cash for the contribution in merge request 5: https://gitlab.com/protesilaos/mct/-/merge_requests/5. -
The
mct-highlight-candidate
no longer hardcodes colour values and instead inherits from thehighlight
face. This makes things easier for themes (if you use themodus-themes
package (by me), mct is now affected by the optionmodus-themes-completions
). Thanks to Tomasz Hołubowicz for the side note about this face in issue 1 over at the GitHub mirror: https://github.com/protesilaos/mct/issues/1. -
Cycling the completion candidates no longer fails when the one at point consists of empty spaces and/or newlines. Thanks to Tomasz Hołubowicz for reporting the bug in issue 2 over at the GitHub mirror: https://github.com/protesilaos/mct/issues/2.