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:

The newest release is at the top. For further details, please consult the manual:

Version 1.0.0 on 2023-09-24

Resumption of MCT development

In April 2022, I announced that I was discontinuing the development of my mct package. At the time, Emacs 29 was gaining new MCT-like capabilities and I thought we would quickly reach a point where my package would be superseded by built-in functionality. The article I published at the time:

About a year later and after receiving questions about MCT, I decided to restart its development. This was done in light of the realisation that the built-in Emacs functionality was still not as opinionated as MCT. There are good reasons for this state of affairs, due to the legacy of this important User Interface element and Emacs' policy to not break stuff willy nilly. Still, the fact remains that MCT can fit in a very narrow niche for those who (i) like the built-in completions and (ii) appreciate a few extra niceties. What I wrote in March, 2023:

What does MCT offer that the built-in Emacs UI does not? In short:

  • MCT provides a facility for "live completions", to automatically update the *Completions* buffer given certain conditions. A number of user options control the specifics.
  • There are user options for a passlist and blocklist, which determine what should automatically display the *Completions* buffer and be live updated. The passlist and the blocklist can target individual commands, such as find-file, as well as completion categories like buffer. The manual includes a section with several known completion categories.

To be clear: MCT builds on top of the built-in functionality and should not compete with it. Depending on my availability, I will try to prepare patches for emacs.git to see whether at least some features can be added directly to mnibuffer.el or related.

MCT supports Emacs 29 or higher

MCT is highly opinionated about how the completions should work. This applies to the presentation of the completion candidates as well as the behaviour of commands that cycle between the minibuffer and the *Completions*, treating the two as a contiguous space. In previous versions of Emacs, MCT could not work exactly as intended due to limitations in the underlying framework. For example, the variable completions-format gained the one-column value only in Emacs 28: Emacs 27 supported grid views which are not intuitive as a vertical list for up-down cycling between the candidates.

To make things easier to maintain, MCT only works with Emacs 29 or higher. The ~1 year hiatus has hopefully given users enough time to assess their options.

Deprecation of mct-region-mode

For a while, MCT supported in-buffer completion via a minor mode that would add all the needed functionality. This was always problematic due to underlying constrains and is thus no longer supported. MCT is designed to work exclusively with the minibuffer, where the behaviour is more reliable.

Nevertheless, users can still get an MCT-like experience with these settings, which affect the default UI (modify as you see fit):

;; Define the small wrapper functions
(defun my-mct-next-line-or-completion (n)
  "Select next completion or move to next line N times.
Select the next completion if `completion-in-region-mode' is
active and the Completions window is on display."
  (interactive "p")
  (if (and completion-in-region-mode (mct--get-completion-window))
      (minibuffer-next-completion n)
    (next-line n)))

(defun my-mct-previous-line-or-completion (n)
  "Select previous completion or move to previous line N times.
Select the previous completion if `completion-in-region-mode' is
active and the Completions window is on display."
  (interactive "p")
  (if (and completion-in-region-mode (mct--get-completion-window))
      (minibuffer-previous-completion n)
    (previous-line n)))

(defun my-mct-return-or-choose-completion (n)
  "Choose current completion or create N newlines.
Choose the current completion if `completion-in-region-mode' is
active and the Completions window is on display."
  (interactive "p")
  (if (and completion-in-region-mode (mct--get-completion-window))
    (newline n :interactive)))

;; Get the key bindings
(let ((map completion-in-region-mode-map))
  (define-key map (kbd "C-n") #'my-mct-next-line-or-completion)
  (define-key map (kbd "C-p") #'my-mct-previous-line-or-completion)
  (define-key map (kbd "RET") #'my-mct-return-or-choose-completion))

;; Tweak the appearance
(setq completions-format 'one-column)
(setq completion-show-help nil)
(setq completion-auto-help t)

;; Optionally, tweak the appearance further
(setq completions-detailed t)
(setq completion-show-inline-help nil)
(setq completions-max-height 6)
(setq completions-highlight-face 'completions-highlight)

The mct-minibuffer-mode is renamed to mct-mode

The mct-mode was the original name, which was later given the "minibuffer" specifier to disambiguate it from the aforementioned mct-region-mode. With the latter gone, this qualification is no longer pertinent and the original name can be restored.

The completing-read-multiple indicator has been removed

Previous versions of MCT would prepend a [CRM] tag to the minibuffer prompt of commands powered by completing-read-multiple. While this is a nice usability enhancement, it is not specific to MCT and thus should not be part of mct.el. Use this in your init file instead:

;; Add prompt indicator to `completing-read-multiple'.  We display
;; [`completing-read-multiple': <separator>], e.g.,
;; [`completing-read-multiple': ,] if the separator is a comma.  This
;; is adapted from the README of the `vertico' package by Daniel
;; Mendler.  I made some small tweaks to propertize the segments of
;; the prompt.
(defun crm-indicator (args)
  (cons (format "[`crm-separator': %s]  %s"
                  "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
                 'face 'error)
                (car args))
        (cdr args)))

(advice-add #'completing-read-multiple :filter-args #'crm-indicator)

No more IDO-like file navigation

Older versions of MCT had a command for file navigation that would delete the whole directory component before point, effectively going back up one directory. While the functionality can be useful, it is not integral to the MCT experience and thus should not belong in mct.el. Add this to your own configuration file instead:

;; Adaptation of `icomplete-fido-backward-updir'.
(defun my-backward-updir ()
  "Delete char before point or go up a directory."
  (interactive nil mct-mode)
   ((and (eq (char-before) ?/)
         (eq (mct--completion-category) 'file))
    (when (string-equal (minibuffer-contents) "~/")
      (insert (expand-file-name "~/"))
      (goto-char (line-end-position)))
      (goto-char (1- (point)))
      (when (search-backward "/" (minibuffer-prompt-end) t)
        (delete-region (1+ (point)) (point-max)))))
   (t (call-interactively 'backward-delete-char))))

(define-key minibuffer-local-filename-completion-map (kbd "DEL") #'my-backward-updir)

Lots of changes under the hood

I do not intend to refashion MCT. It works the way it was originally intended to. What I did is to streamline the code for compatibility with Emacs 29 and tweak the custom commands to preserve the desired cyclic behaviour between the minibuffer and the *Completions*.

Experiments such as integration with the avy package or the ability to type-to-complete in the *Completions* buffer are abandoned.

Do not expect radical changes henceforth. I shall monitor and/or contribute to developments in core Emacs and am happy to forever archive MCT if/when the default completion UI gains the capabilities that, I think, make the user experience a little bit easier.

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: 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:

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:

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):

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:
  • 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:
  • 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:

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:
  • 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:
  • 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:
  • 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:

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: 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: 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:

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 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: 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: 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:

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:
  • 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 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:
  • 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.