🏆 I provide private lessons on Emacs, Linux, and Life in general: https://protesilaos.com/coach/. Lessons continue throughout the year.

Change Log of the Minibuffer and Completions in Tandem (MCT)

This document contains the release notes that are included in each tagged commit on the project's main git repository: https://gitlab.com/protesilaos/mct.

The newest release is at the top. For further details, please consult the manual: https://protesilaos.com/emacs/mct.

Version 0.5.0 on 2022-02-08

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
        ;; Some completion categories

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 a file 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 with mct-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 option mct-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 the file 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 and corfu 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 where mct-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 to C-g by default) now works properly with the mct-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 the highlight face. This makes things easier for themes (if you use the modus-themes package (by me), mct is now affected by the option modus-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.

Version 0.4.0 on 2022-01-19

This entry outlines the changes to the "Minibuffer and Completions in Tandem" (mct package) since the release of version 0.3.0 on 2021-11-19. There have been more than 120 commits in the meantime.

For further details, please consult the manual online: https://protesilaos.com/emacs/mct. Or evaluate the following expression if you already have mct installed:

(info "(mct) Top")

As most changes pertain to optimisations in the code base, we limit this log to what is of interest to the end-user.

Minibuffer Confines Transcended (aka mct-region-mode)

Emacs distinguishes between two types of completion: one that involves the minibuffer and another for text expansion inside regular buffers. MCT has supported the former case since its inception, as hinted by its original name ("Minibuffer and Completions in Tandem"), but would not work as intended for in-buffer completion.

This changes with the introduction of a new global minor mode: mct-region-mode. What once was mct-mode is now defined as mct-minibuffer-mode to better denote the scope of the given functionality.

With mct-region-mode enabled, users get a simplified subset of the familiar MCT functionality when typing TAB or C-M-i to complete the text-at-point in any major-mode that supports completion-at-point-functions (e.g. programming modes or Org).

mct-region-mode is considered experimental and unstable. Users are encouraged to report any bugs as well as recommend ways to improve its functionality or interaction model. The manual has been updated to cover all the relevant details.

Daniel Mendler, who is the developer of the vertico and corfu packages (alternatives to mct-minibuffer-mode and mct-region-mode, respectively), was intstrumental in making mct-region-mode happen. Daniel's patches helped with everything from (i) the proper functioning of mct-region-mode, (ii) the separation between mct-minibuffer-mode and mct-region-mode, (iii) the overall setup of the minor modes, and (iv) lots of other crucial details of the overall design of MCT. In short: there would be no mct-region-mode without Daniel's contributions. Any remaining errors or omissions are my own.

Given this new functionality, we can now joke that "MCT" stands for "Minibuffer Confines Transcended".

Version 0.3.0 on 2021-11-19

This entry describes the changes to Minibuffer and Completions in Tandem (mct) since the release of version 0.2.0 on 2021-11-12. There have been more than 40 commits since then. For further details, please consult the manual online: https://protesilaos.com/emacs/mct. Or evaluate the following expression if you have the mct package installed:

(info "(mct) Top")

As this release is a continuation of version 0.2.0, the changelog for that version is also provided below (I released version 0.2.0 earlier than anticipated so that users could get a stable package on GNU ELPA). Here is a brief description of what has been achieved in 0.3.0.

MCT on Emacs 27

  • MCT now works on Emacs 27. This was not possible in the past because mct-mode was originally designed to operate with the one-column style of the completions-format, which was added in Emacs 28. To make everything behave intuitively, several parts had to be abstracted and refactored (the changelog of version 0.2.0 (further below) covers everything not mentioned here).
  • The scenaria where the functionality was thoroughly tested involve all the available formats and cover commands that fulfil the following criteria:
    • Plain completion candidates, as in switch-to-buffer.
    • Dynamic completion like that of find-file.
    • Annotated candidates, as seen in describe-symbol for versions of Emacs 28 or higher.
    • Commands where candidates are grouped by heading, as done by various extensions of the consult package, such as consult-imenu.
    • Commands where no completion category is associated with them.
  • The only change which is visible to the user is the implementation of a bespoke overlay to highlight the current candidate. In previous versions, this was provided by the built-in hl-line-mode, though that does not work as intended with either the vertical or horizontal layouts of the completions-format as it covers the whole line instead of the candidate at point.
  • The highlight extends to the edge of the window when the one-column format is used for the completions-format (Emacs 28 or higher). In the other views it stretches from the beginning to the end of the completion candidate.
  • Thanks to Case Duckworth for the initial request and subsequent testing in issue 1: https://gitlab.com/protesilaos/mct/-/issues/1.

Miscellaneous changes

  • There is a new command that is active in the minibuffer which allows to complete and exit immediately: C-RET (mct-complete-and-exit). This economises on key presses when all the user wants is to select the top-most candidate (or last highlighted one) without first switching to the Completions' buffer and then confirming it from there (RET in the *Completions* buffer completes and exits directly).
  • The mct-mode does not get activated in contexts where (i) the minibuffer is involved but (ii) no completion takes place. For example, the eval-expression command (bound to M-: by default).
  • mct-mode no longer remaps the faces of the display-line-numbers-mode. This was a useful experiment from the early days of the code base, although it is bad practice for a user-facing package.
  • Various tweaks and refinements to the manual.
  • Retroactive introduction of a CHANGELOG.org file and coverage of all noteworthy changes hitherto.

Version 0.2.0 on 2021-11-12

This entry describes the changes to Minibuffer and Completions in Tandem (mct) since the release of version 0.1.0 on 2021-10-22. There have been 70 commits since then. For further details, please consult the manual online: https://protesilaos.com/emacs/mct. Or evaluate the following expression if you have the mct package installed:

(info "(mct) Top")

Packaged version of MCT

mct is now available on the official GNU ELPA archive for users of Emacs version 28 or higher. One can install the package without any further configuration. The following commands shall suffice:

M-x package-refresh-contents
M-x package-install RET mct

Changes to the format and placement of the Completions

  • The user option mct-live-completion controls how and when the Completions' buffer should be placed in a window and be updated live in response to user feedback. Copying from the doc string:

    mct-live-completion is a variable defined in ‘mct.el’.

    Its value is t

    Control auto-display and live-update of Completions' buffer.

    When nil, the user has to manually request completions, using the regular activating commands. The Completions' buffer is never updated live to match user input. Updating has to be handled manually. This is like the out-of-the-box minibuffer completion experience.

    When set to the value visible, the Completions' buffer is live updated only if it is visible. The actual display of the completions is still handled manually. For this reason, the visible style does not read the mct-minimum-input, meaning that it will always try to live update the visible completions, regardless of input length.

    When non-nil (the default), the Completions' buffer is automatically displayed once the mct-minimum-input is met and is hidden if the input drops below that threshold. While visible, the buffer is updated live to match the user input.

    Note that every function in the mct-completion-passlist ignores this option altogether. This means that every such command will always show the Completions' buffer automatically and will always update its contents live. Same principle for every function declared in the mct-completion-blocklist, which will always disable both the automatic display and live updating of the Completions' buffer.

  • As with all buffers, the placement of the *Completions* can be controlled with the display-buffer machinery. The default is to show the completions at the bottom of the frame, though users can easily move it to, say, the left side window. The doc string of the user option mct-display-buffer-action explains how to do so.
    • Thanks to Philip Kaludercic for the initial implementation in commit 436b24e (was sent via email as a patch).
    • Thanks to Kostadin Ninev for reporting a bug where the Completions' buffer would proliferate during completion: https://gitlab.com/protesilaos/mct/-/issues/3. It was fixed by Philip Kaludercic in commit 51c1e17.
  • MCT now supports all the available styles of the completions-format, whereas the original design was only meant to work with the value one-column, which was introduced in Emacs 28. The user option is mct-completions-format. If that variable is set with setq, the mct-mode has to be restarted manually for changes to take effect (setting the variable through customize-set-variable (and related) handles the mode reloading automatically).
    • Thanks to Philip Kaludercic for the patch in commit b392b0b.
    • Several changes were then made to ensure that the cyclic motions that move between the *Completions* and the minibuffer work intuitively in a grid view. In short: C-n, C-p or the down/up arrow keys, perform a vertical motion, while the left/right arrow keys move laterally. Prior to those changes, C-n or down arrow as well as C-p or up arrow, would perform a lateral motion as that is internally the meaning of the next/previous completion candidate.
    • The command mct-choose-completion-number was updated to throw a user error when a grid view is active. That is because it is designed to jump to a given line number, which only works as intended when there is only one candidate per line. (Perhaps a future release should overlay characters over candidates in the grid view to select them directly.)
  • The mct-mode no longer sets the completions-detailed variable. That is a matter of user preference. It is not integral to the functionality of MCT.

Group motions

  • Emacs 28 provides infrastructure for commands to group candidates based on their contents. These groups can have their own heading in the Completions' buffer, as well as a separator. Overall, it makes things look more organised. The commands mct-next-completion-group and mct-previous-completion-group move between those headings. While in the *Completions* buffer, they are bound to M-n and M-p, respectively. Thanks to James Norman Vladimir Cash for the contribution in merge request 2: https://gitlab.com/protesilaos/mct/-/merge_requests/2.

Miscellaneous changes

  • The TAB key in the Completions' buffer never exits the minibuffer (the command is mct-choose-completion-no-exit). Instead, it expands the current candidate in the minibuffer and switches focus to it. Before, this behaviour would only happen in find-file and related prompts, but consistency/predictability is better.

    [ By contrast, RET (mct-choose-completion-exit) in the Completions buffer always exits with the candidate at point. ]

    Note that in this context "exit" means to close the session and accept the current input.

  • There is a new heuristic to deal with commands that let bind the crm-separator (e.g. org-set-tags-command sets the separator to :). This is used to make M-RET (mct-choose-completion-dwim) in the Completions buffer work in all completing-read-multiple contexts. Thanks to James Norman Vladimir Cash for contributing the heuristic in merge request 1: https://gitlab.com/protesilaos/mct/-/merge_requests/1.
  • The aforementioned M-RET command used to have the same effect as RET when not in a completing-read-multiple prompt ("CRM prompt"). This has now been revised to behave like TAB instead (as described further above), which is consistent with the ordinary behaviour of M-RET in CRM prompts where it appends the candidate at point to the minibuffer without exiting.
  • The check for display-line-numbers-mode tests whether it is bound, thus avoiding possible errors. Thanks to Philip Kaludercic for the patch in commit 6bd2457.
  • Made several improvements to doc strings and various snippets of code.

Updates to the manual

  • All of the aforementioned were documented, where appropriate.
  • A Makefile is now on offer, which is used to generate the mct.info and mct.texi files. Thanks to Philip Kaludercic for the patch in commit 295bac0.
  • A sample setup is available for mct as well as several built-in options pertaining to the minibuffer.
  • There are sections about third-party extensions as well as one that describes alternatives to MCT. Thanks to Manuel Uberti for the feedback in issue 5: https://gitlab.com/protesilaos/mct/-/issues/5.
  • The "Acknowledgements" section includes the names of people who have contributed to the project in one way or another (code, ideas, user feedback, …).

Version 0.1.0 on 2021-10-22

Initial release. The mct.el file derived from the now-deprecated prot-minibuffer.el (part of my dotfiles), which I had been using for more than six months full time.