Skip to content

Additional Configuration

Daniel Mendler edited this page Jul 28, 2021 · 80 revisions

This page lists example of additional configuration that might be useful to use with embark.

Use which key like a key menu prompt

The built-in embark-verbose-indicator displays actions in a buffer along with their keybindings and the first line of their docstrings. Users desiring a more compact display can use which-key instead with the following configuration:

(defun embark-which-key-indicator (keymap targets)
  "An embark indicator that displays KEYMAP with which-key.
The which-key help message will show the type and value of the
current target followed by an ellipsis if there are further
TARGETS."
  (which-key--show-keymap
   (if (eq (caar targets) 'embark-become)
       "Become"
     (format "Act on %s '%s'%s"
             (caar targets)
             (embark--truncate-target (cdar targets))
             (if (cdr targets) "" "")))
   keymap
   nil nil t)
  (lambda (prefix)
    (if prefix
        (embark-which-key-indicator (lookup-key keymap prefix) targets)
      (kill-buffer which-key--buffer))))

(setq embark-indicator #'embark-which-key-indicator)

Refresh candidate list after action

Some actions, such as delete-file, rename-file or kill-buffer can change the candidate list. To get the completion UI to refresh automatically use the following:

Icomplete

(add-hook 'embark-pre-action-hook #'completion--flush-all-sorted-completions)

Selectrum

(defun refresh-selectrum ()
  (setq selectrum--previous-input-string nil))

(add-hook 'embark-pre-action-hook #'refresh-selectrum)

Embark Collect

(add-hook 'embark-post-action-hook #'embark-collect--update-linked)

Automatically resizing auto-updating Embark Collect buffers to fit their contents

This produces an effect similar to (setq resize-mini-windows t) for the minibuffer.

(add-hook 'embark-collect-post-revert-hook
          (defun resize-embark-collect-window (&rest _)
            (when (memq embark-collect--kind '(:live :completions))
              (fit-window-to-buffer (get-buffer-window)
                                    (floor (frame-height) 2) 1))))))

Showing Embark actions keys in keycast-mode

Because of the way embark-act works, @tarsius's excellent keycast package never finds out that Embark actions are commands nor what keys you pressed to run them. The following configuration fixes that:

(defun store-action-key+cmd (cmd)
  (setq keycast--this-command-keys (this-single-command-keys)
        keycast--this-command cmd))

(advice-add 'embark-keymap-prompter :filter-return #'store-action-key+cmd)

(defun force-keycast-update (&rest _)
  (force-mode-line-update t))

(dolist (cmd '(embark-act embark-act-noexit embark-become))
  (advice-add cmd :before #'force-keycast-update))

Shrink Selectrum to a single line while using embark-collect-live

When live collect is active you may want to shrink the Selectrum minibuffer in order to save some screen space. The shrink-selectrum hook ensures that Selectrum switches to horizontal mode, showing only a single candidate.

(defun shrink-selectrum ()
  (when (eq embark-collect--kind :live)
    (with-selected-window (active-minibuffer-window)
      (setq-local selectrum-num-candidates-displayed 1)
      (setq-local selectrum-display-style
                  '(horizontal :before-candidates "[" :after-candidates "]"
                               :more-candidates "" :candidates-separator "")))))

(add-hook 'embark-collect-mode-hook #'shrink-selectrum)

Associate commands with actions

Ivy allows to associate commands with specific actions. The classification hooks embark provides allow you to easily define actions which are useful for a wider range of contexts. But you can also define adhoc actions and actions which are specific to their command by setting embark-overriding-keymap. You can also use this variable to setup your own mappings for commands with custom actions by using something like this:

(defvar my-actions
  (let ((map (make-sparse-keymap)))
    (define-key map "d"
      (defun example-action ()
        (interactive)
        (message "Do something with %s" (embark-target))))
    map))

(defvar my-action-map-alist
  '((example-command . my-actions)))

(add-hook 'minibuffer-setup-hook
          (defun my-setup-actions ()
            (when-let ((map (cdr (assoc this-command my-action-map-alist))))
              (setq-local embark-overriding-keymap (symbol-value map)))))

(defun example-command ()
  (interactive)
  (completing-read "Check: " '("this" "out")))

Switch between candidates and actions like in Helm

Use the tab key (change according to preference) to switch back and forth between the list of minibuffer candidates and the list of embark actions on the selected candidate, like in Helm. Works best with a completion system that shows candidates in a vertical list, like vertico, selectrum, icomplete-vertical etc.

(defun with-minibuffer-keymap (keymap)
  (lambda (fn &rest args)
    (minibuffer-with-setup-hook
        (lambda ()
          (use-local-map
           (make-composed-keymap keymap (current-local-map))))
      (apply fn args))))

(defvar embark-completing-read-prompter-map
  (let ((map (make-sparse-keymap)))
    (define-key map (kbd "<tab>") 'abort-recursive-edit)
    map))

(advice-add 'embark-completing-read-prompter :around
            (with-minibuffer-keymap embark-completing-read-prompter-map))
(define-key vertico-map (kbd "<tab>") 'embark-act-with-completing-read)

  (defun embark-act-with-completing-read (&optional arg)
    (interactive "P")
    (let* ((embark-prompter 'embark-completing-read-prompter)
           (act (propertize "Act" 'face 'highlight))
           (embark-indicator (lambda (_keymap targets) nil)))
      (embark-act arg)))

Replace vertico-map above with your completion system of choice's active minibuffer keymap. The default is minibuffer-local-completion-map.

Show the current Embark target types in the modeline

Similar to which-function-mode.

(defvar embark--target-mode-timer nil)
(defvar embark--target-mode-string "")

(defun embark--target-mode-update ()
  (setq embark--target-mode-string
        (if-let (targets (embark--targets))
            (format "[%s%s] "
                    (propertize (symbol-name (caaar targets)) 'face 'bold)
                    (mapconcat (lambda (x) (format ", %s" (caar x)))
                               (cdr targets)
                               ""))
          "")))

(define-minor-mode embark-target-mode
  "Shows the current targets in the modeline."
  :global t
  (setq mode-line-misc-info (assq-delete-all 'embark-target-mode mode-line-misc-info))
  (when embark--target-mode-timer
    (cancel-timer embark--target-mode-timer)
    (setq embark--target-mode-timer nil))
  (when embark-target-mode
    (push '(embark-target-mode (:eval embark--target-mode-string)) mode-line-misc-info)
    (setq embark--target-mode-timer
          (run-with-idle-timer 0.1 t #'embark--target-mode-update))))
Clone this wiki locally