-
-
Notifications
You must be signed in to change notification settings - Fork 59
Additional Configuration
This page lists example of additional configuration that might be useful to use with embark
.
(Or more generally: remap commands to make the same action bindings useful in more contexts.)
Embark has h
bound to display-local-help
in the action map for identifiers. So you can remap display-local-help
to a command that's appropriate to each major mode. The command you remap to should be of one of two types: it can provide help for the identifier at point, or it can prompt for an identifier and show help for it.
For example in shell-related modes (either for editing scripts or for running a shell), you can remap display-local-help
to man
:
(with-eval-after-load 'shell
(define-key shell-mode-map [remap display-local-help] #'man))
(with-eval-after-load 'sh-script
(define-key sh-mode-map [remap display-local-help] #'man))
(with-eval-after-load 'esh-mode
(define-key eshell-mode-map [remap display-local-help] #'man))
For eshell, the h
action will still use describe-symbol
on Emacs Lisp symbols.
Other examples:
- In cperl-mode remapping to
cperl-perldoc
. - In Slime or SLY remapping to
slime-describe-symbol
orsly-describe-symbol
. In these modes you probably also will want further remappings:
(with-eval-after-load 'sly
(let ((map sly-editing-mode-map))
(define-key map [remap display-local-help] #'sly-describe-symbol)
(define-key map [remap embark-pp-eval-defun] #'sly-compile-defun)
(define-key map [remap pp-macroexpand-expression] #'sly-expand-1)
(define-key map [remap pp-eval-expression] #'sly-interactive-eval)
(define-key map [remap xref-find-definitions] #'sly-edit-definition))
This makes those Embark Emacs Lisp bindings work on Common Lisp code too.
(The slime version should be totally analogous, but I haven't tested it.)
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 (plist-get (car targets) :type) '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 (lambda (binding)
(not (string-suffix-p "-argument" (cdr binding))))))))
(setq embark-indicators
'(embark-which-key-indicator
embark-highlight-indicator
embark-isearch-highlight-indicator))
(defun embark-hide-which-key-indicator (fn &rest args)
"Hide the which-key indicator immediately when using the completing-read prompter."
(which-key--hide-popup-ignore-command)
(let ((embark-indicators
(remq #'embark-which-key-indicator embark-indicators)))
(apply fn args)))
(advice-add #'embark-completing-read-prompter
:around #'embark-hide-which-key-indicator)
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))))
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))
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)
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))
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
.
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))))
See also the Consult Wiki and the Vertico Wiki!