Skip to content

Additional Configuration

Bruno Bigras edited this page Oct 16, 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 ()
  "An embark indicator that displays keymaps using 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."
  (lambda (&optional keymap targets prefix)
    (if (null keymap)
        (which-key--hide-popup-ignore-command)
      (which-key--show-keymap
       (if (eq (caar targets) 'embark-become)
           "Become"
         (format "Act on %s '%s'%s"
                 (plist-get (car targets) :type)
                 (embark--truncate-target (plist-get (car targets) :target))
                 (if (cdr targets) "" "")))
       (if prefix
           (pcase (lookup-key keymap prefix 'accept-default)
             ((and (pred keymapp) km) km)
             (_ (key-binding prefix 'accept-default)))
         keymap)
       nil nil t))))

(setq embark-indicators
  '(embark-which-key-indicator
    embark-highlight-indicator
    embark-isearch-highlight-indicator))

Colorize the current Vertico candidate differently when acting

(defun embark-vertico-indicator ()
  (let ((fr face-remapping-alist))
    (lambda (&optional keymap _targets prefix)
      (when (bound-and-true-p vertico--input)
        (setq-local face-remapping-alist
                    (if keymap
                        (cons '(vertico-current . embark-target) fr)
                      fr))))))

(add-to-list 'embark-indicators #'embark-vertico-indicator)

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-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 ad hoc actions and actions which are specific to their command by temporarily setting embark-keymap-alist. You can also use this variable to setup your own mappings for commands with custom actions by using something like this:

(defvar my-action-map-alist nil)

(add-hook 'minibuffer-setup-hook
          (defun my-setup-actions ()
            (when-let ((map (cdr (assoc this-command my-action-map-alist))))
              (setq-local embark-keymap-alist `((t . ,map))))))

Now you can associate specific commands to specific keymaps in my-action-map-alist. For example:

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

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

(add-to-list 'my-action-map-alist '(example-command . my-actions))

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 (plist-get (car targets) :type)) 'face 'bold)
                    (mapconcat (lambda (x) (format ", %s" (plist-get x :type)))
                               (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