Skip to content

Additional Configuration

Rudolf Adamkovič edited this page Jan 15, 2022 · 76 revisions

This page lists examples of additional configuration that might be useful with selectrum.

Examples which show how to integrate selectrum with other packages only present the basic configuration needed to make use of them. You will need to look at the respective projects READMEs to checkout their other configuration options.

Configuration for built-ins

Minibuffer default add function

Completion commands can bind minibuffer-default-add-function to control which candidates a user gets offered when pressing M-n. A good default is to offer the symbol or file name that where a point before entering the minibuffer:

(autoload 'ffap-guesser "ffap")
(setq minibuffer-default-add-function
      (defun minibuffer-default-add-function+ ()
        (with-selected-window (minibuffer-selected-window)
          (delete-dups
           (delq nil
                 (list (thing-at-point 'symbol)
                       (thing-at-point 'list)
                       (ffap-guesser)
                       (thing-at-point-url-at-point)))))))

Complete file names at point

When completing file names in shell/comint selectrum gives you the same interface as you get for find-file. This means the completion does not exit after one path level like with other frameworks and you can conveniently navigate to the path you are interested in. If you want to be able to get this file completion mechanism globally you can use the following:

(autoload 'ffap-file-at-point "ffap")

(add-hook 'completion-at-point-functions
          (defun complete-path-at-point+ ()
            (let ((fn (ffap-file-at-point))
                  (fap (thing-at-point 'filename)))
              (when (and (or fn
                             (equal "/" fap))
                         (save-excursion
                           (search-backward fap (line-beginning-position) t)))
                (list (match-beginning 0)
                      (match-end 0)
                      #'completion-file-name-table)))) 'append)

With the above you can call the command completion-at-point to get file completion with the point after a path name. See also the option tab-always-indent.

Shadowed pathes with file-name-shadow-mode

The built-in file-name-shadow-mode works with selectrum out of the box. For example if you want to use it to hide shadowed pathes you can use the following:

(setq file-name-shadow-properties
      '(invisible t))

Configuration for external packages

Sorting for M-x with amx

NOTE: It is recommend to use Prescient instead.

(setq amx-backend 'selectrum)

Filtering with orderless

Selectrum does support completion-styles so when you configured them for orderless filtering and highlighting is done by it already:

(setq completion-styles '(orderless))

However completion-styles do filter and highlight in a single step, the approach of Selectrum to only highlight the actually displayed candidates is more efficient so it is recommended to also configure:

(setq orderless-skip-highlighting (lambda () selectrum-is-active))
(setq selectrum-highlight-candidates-function #'orderless-highlight-matches)

Use prescient only for sorting

If you only want to sort with prescient you can omit calling selectrum-prescient-mode and use:

(setq selectrum-prescient-enable-filtering nil)

Minibuffer-actions with embark

Embark now works out of the box with Selectrum. All you need to do is bind embark commands like embark-act in minibuffer-local-map, since Embark commands are not Selectrum-specific. Note that you might want to bind embark-act even globally since it provides general context sensitive actions. For available commands and other embark configurations see the embark documentation and its wiki.

Correcting spelling errors with flyspell-correct

The default interface (flyspell-correct-completing-read), already works with Selectrum. To ensure that you are using the default interface, you can do

(setq flyspell-correct-interface #'flyspell-correct-completing-read)

When flyspell-correct provides candidates to completing-read, it appends alternative actions ([SAVE], [ACCEPT (session)], [ACCEPT (buffer)], and [SKIP]) to the list of possible spelling corrections. As of 2020 August 28, flyspell-correct-dummy no longer allows these candidates to be sorted (meaning that the actions are now always at the end of the candidate list). If you are using an older version, you can achieve the same effect by advising flyspell-correct-dummy like below.

;; Not needed for newer versions of `flyspell-correct'.
(advice-add 'flyspell-correct-dummy :around
              (defun my--fsc-wrapper (func &rest args)
                (let ((selectrum-should-sort nil))
                  (apply func args))))

Working with projects in projectile

NOTE: Since 2020-11-21 projectile auto-detects the active completion system. Therefore no additional configuration is necessary for Selectrum.

Display minibuffer in a child frame with mini-frame

Make sure you have

(mini-frame-mode +1)

;; Make sure you don't override the display action:
; (setq selectrum-display-action nil)

to enable mini-frame support. With more recent Emacs versions (27.2 and above), selectrum will use a mini-frame automatically when you don't have a custom selectrum-display-action defined.

For older versions, you may also need the following fix, see #169:

;; workaround bug#44080, should be fixed in version 27.2 and above, see #169
(define-advice fit-frame-to-buffer (:around (f &rest args) dont-skip-ws-for-mini-frame)
  (cl-letf* ((orig (symbol-function #'window-text-pixel-size))
             ((symbol-function #'window-text-pixel-size)
              (lambda (win from to &rest args)
                (apply orig
                       (append (list win from 
                                     (if (and (window-minibuffer-p win)
                                              (frame-root-window-p win)
                                              (eq t to))
                                         nil
                                       to))
                               args)))))
    (apply f args)))

;; If you are using Gnome there are issues with dynamic resize set by `mini-frame-resize`:
;; https://github.com/muffinmad/emacs-mini-frame/commit/bac8ab2a1be8e1b2959f3d40ffa714cdf3c49a01
;; The following setting will fix that:
(setq x-gtk-resize-child-frames 'resize-mode) ; only for Gnome users

To use mini-frame for display at point you can make use of posframe handlers position calculation:

(setq mini-frame-show-parameters                                        
      (lambda ()                                                                
        (let* ((info (posframe-poshandler-argbuilder))
               (posn (posframe-poshandler-point-bottom-left-corner info))
               (left (car posn))
               (top (cdr posn)))
          `((left . ,left)
            (top . ,top)))))

Display candidates in a posframe

A simple example to show the use of posframes with selectrum-display-action:

(setq selectrum-display-action '(display-buffer-show-in-posframe))

(defun display-buffer-show-in-posframe (buffer _alist)
  (frame-root-window
   (posframe-show buffer
                  :min-height 10
                  :min-width (frame-width)
                  :internal-border-width 1
                  :left-fringe 8
                  :right-fringe 8
                  :poshandler 'posframe-poshandler-frame-bottom-left-corner)))

(add-hook 'minibuffer-exit-hook 'posframe-delete-all)

Completion with magit

Without explicitly setting this the candidates won't be sorted with prescient if you have it enabled.

(setq magit-completing-read-function #'selectrum-completing-read)

See below for alternative approach.

Handle completion order for refs in magit with prescient

(define-advice magit-list-refs (:around (orig &optional namespaces format sortby)
                                        prescient-sort)
  "Apply prescient sorting when listing refs."
  (let ((res (funcall orig namespaces format sortby)))
    (if (or sortby
            magit-list-refs-sortby
            (not selectrum-should-sort))
            res
      (prescient-sort res))))

Handle complete-symbol with SLIME

SLIME is old enough that it doesn't obey the completion-in-region-function API, this doesn't matter with company (see slime-company) but normally it won't use selectrum for completions. To fix this, use the following advice:

(advice-add 'slime-display-or-scroll-completions :around
             (defun my--slime-completion-in-region (_ completions start end)
               (completion-in-region start end completions)))

Improve the completion of multi-occur.

NOTE: This command is provided by Consult, see consult-multi-occur.

multi-occur reads a list of buffers to search in. Unfortunately the default Emacs implementation does not interact well with selectrum, since it does not use completing-read-multiple. Instead it reads each buffer separately.

By overwriting the default multi-occur, this issue can be fixed:

(defun multi-occur (bufs regexp &optional nlines)
  (interactive (cons
                (mapcar #'get-buffer
                        (completing-read-multiple "Buffer: "
                                                  #'internal-complete-buffer))
                (occur-read-primary-args)))
  (occur-1 regexp nlines bufs))

See also https://github.com/raxod502/selectrum/issues/226