To install this package, run in Emacs:
M-x package-install RET embark RET
This package provides a sort of right-click contextual menu for Emacs,
accessed through the embark-act
command (which you should bind to a
convenient key), offering you relevant actions to use on a target
determined by the context:
*Completions*
buffer the target is the completion at point.
Multiple targets can be present at the same location and you can cycle
between them by repeating the embark-act
key binding. The type of
actions offered depend on the type of the target. Here is a sample of
a few of the actions offered in the default configuration:
By default when you use embark-act
if you don't immediately select an
action, after a short delay Embark will pop up a buffer showing a list
of actions and their corresponding key bindings. If you are using
embark-act
outside the minibuffer, Embark will also highlight the
current target. These behaviors are configurable via the variable
embark-indicators
. Instead of selecting an action via its key binding,
you can select it by name with completion by typing C-h
after
embark-act
.
Everything is easily configurable: determining the current target, classifying it, and deciding which actions are offered for each type in the classification. The above introduction just mentions part of the default configuration.
Configuring which actions are offered for a type is particularly easy
and requires no programming: the variable embark-keymap-alist
associates target types with variables containing keymaps, and those
keymaps containing bindings for the actions. (To examine the available
categories and their associated keymaps, you can use C-h v
embark-keymap-alist
or customize that variable.) For example, in the
default configuration the type file
is associated with the symbol
embark-file-map
. That symbol names a keymap with single-letter key
bindings for common Emacs file commands, for instance c
is bound to
copy-file
. This means that if you are in the minibuffer after running
a command that prompts for a file, such as find-file
or rename-file
,
you can copy a file by running embark-act
and then pressing c
.
These action keymaps are very convenient but not strictly necessary
when using embark-act
: you can use any command that reads from the
minibuffer as an action and the target of the action will be inserted
at the first minibuffer prompt. After running embark-act
all of your
key bindings and even execute-extended-command
can be used to run a
command. For example, if you want to replace all occurrences of the
symbol at point, just use M-%
as the action, there is no need to bind
query-replace
in one of Embark's keymaps. Also, those action keymaps
are normal Emacs keymaps and you should feel free to bind in them
whatever commands you find useful as actions and want to be available
through convenient bindings.
The actions in embark-general-map
are available no matter what type
of completion you are in the middle of. By default this includes
bindings to save the current candidate in the kill ring and to insert
the current candidate in the previously selected buffer (the buffer
that was current when you executed a command that opened up the
minibuffer).
Emacs's minibuffer completion system includes metadata indicating the
category of what is being completed. For example, find-file
's
metadata indicates a category of file
and switch-to-buffer
's metadata
indicates a category of buffer
. Embark has the related notion of the
type of a target for actions, and by default when category metadata
is present it is taken to be the type of minibuffer completion
candidates when used as targets. Emacs commands often do not set
useful category metadata so the Marginalia package, which supplies
this missing metadata, is highly recommended for use with Embark.
Embark's default configuration has actions for the following target types: files, buffers, symbols, packages, URLs, bookmarks, and as a somewhat special case, actions for when the region is active. You can read about the default actions and their key bindings on the GitHub project wiki.
Embark has a notion of default action for a target:
kill-buffer
, then the default action will be
to kill buffers.RET
in the keymap of
actions for that type of target. For example, in Embark's default
configuration for a URL found at point the default action is
browse-url
, because RET
is bound to browse-url
in the embark-url-map
keymap.
To run the default action you can press RET
after running embark-act
.
Note that if there are several different targets at a given location,
each has its own default action, so first cycle to the target you want
and then press RET
to run the corresponding default action.
There is also embark-dwim
which runs the default action for the first
target found. It's pretty handy in non-minibuffer buffers: with
Embark's default configuration it will:
browse-url
command).Besides acting individually on targets, Embark lets you work collectively on a set of target candidates. For example, while you are in the minibuffer the candidates are simply the possible completions of your input. Embark provides three main commands to work on candidate sets:
embark-act-all
command runs the same action on each of the
current candidates. It is just like using embark-act
on each
candidate in turn. (Because you can easily act on many more
candidates than you meant to, by default Embark asks you to confirm
uses of embark-act-all
; you can turn this off by setting the user
option embark-confirm-act-all
to nil
.)embark-collect-snapshot
command produces a buffer listing all
the current candidates, for you to peruse and run actions on at your
leisure. The candidates can be viewed in a grid or as a list showing
additional annotations.
The embark-export
command tries to open a buffer in an appropriate
major mode for the set of candidates. If the candidates are files
export produces a Dired buffer; if they are buffers, you get an
Ibuffer buffer; and if they are packages you get a buffer in
package menu mode.
If you use the grepping commands from the Consult package,
consult-grep
, consult-git-grep
or consult-ripgrep
, then you'll
probably want to install and load the embark-consult
package, which
adds support for exporting a list of grep results to an honest
grep-mode buffer, on which you can even use wgrep if you wish.
When in doubt choosing between exporting and collecting, a good rule
of thumb is to always prefer embark-export
since when an exporter to a
special major mode is available for a given type of target, it will be
more featureful than an Embark collect buffer, and if no such exporter
is configured the embark-export
command falls back to the generic
embark-collect-snapshot
.
These commands are always available as "actions" (although they do not
act on just the current target but on all candidates) for embark-act
and are bound to A
, S
, and E
, respectively, in embark-general-map
.
This means that you do not have to bind your own key bindings for
these (although you can, of course!), just a key binding for
embark-act
.
There is also the embark-collect-live
variant of
embark-collect-snapshot
which produces "live" Embark Collect buffers,
meaning they auto-update as the set of candidates changes. Most users
of visual completion UIs such as Vertico, Icomplete, Selectrum or Ivy
will probably either not want to use this from the minibuffer, to
avoid seeing double (the list of candidates is displayed both by
Embark and by the completion UI), or to configure their completion UI
to hide while using embark-collect-live
. See the Embark wiki for
sample configuration for Selectrum. This command can also be used
outside the minibuffer if you have a relevant candidate collector
registered in embark-candidate-collectors
. Users of the embark-consult
package, for example, get such a candidate collector registered for
them, and can produce a live-updating table of contents for any
buffer, whose items are the lines matching outline-regexp
.
Embark also has the embark-become
command which is useful for when
you run a command, start typing at the minibuffer and realize you
meant a different command. The most common case for me is that I run
switch-to-buffer
, start typing a buffer name and realize I haven't
opened the file I had in mind yet! I'll use this situation as a
running example to illustrate embark-become
. When this happens I can,
of course, press C-g
and then run find-file
and open the file, but
this requires retyping the portion of the file name you already
typed. This process can be streamlined with embark-become
: while still
in the switch-to-buffer
you can run embark-become
and effectively
make the switch-to-buffer
command become find-file
for this run.
You can bind embark-become
to a key in minibuffer-local-map
, but it is
also available as an action under the letter B
(uppercase), so you
don't need a binding if you already have one for embark-act
. So,
assuming I have embark-act
bound to, say, C-.
, once I realize I
haven't open the file I can type C-. B C-x C-f
to have
switch-to-buffer
become find-file
without losing what I have already
typed in the minibuffer.
But for even more convenience, embark-become
offers shorter key
bindings for commands you are likely to want the current command to
become. When you use embark-become
it looks for the current command in
all keymaps named in the list embark-become-keymaps
and then activates
all keymaps that contain it. For example, the default value of
embark-become-keymaps
contains a keymap embark-become-file+buffer-map
with bindings for several commands related to files and buffers, in
particular, it binds switch-to-buffer
to b
and find-file
to f
. So when
I accidentally try to switch to a buffer for a file I haven't opened
yet, embark-become
finds that the command I ran, switch-to-buffer
, is
in the keymap embark-become-file+buffer-map
, so it activates that
keymap (and any others that also contain a binding for
switch-to-buffer
). The end result is that I can type C-. B f
to
switch to find-file
.
The easiest way to install Embark is from GNU ELPA, just run M-x
package-install RET embark RET
. (It is also available on MELPA.) It is
highly recommended to also install Marginalia (also available on GNU
ELPA), so that Embark can offer you preconfigured actions in more
contexts. For use-package
users, the following is a very reasonable
starting configuration:
(use-package marginalia :ensure t :config (marginalia-mode)) (use-package embark :ensure t :bind (("C-." . embark-act) ;; pick some comfortable binding ("C-;" . embark-dwim) ;; good alternative: M-. ("C-h B" . embark-bindings)) ;; alternative for `describe-bindings' :init ;; Optionally replace the key help with a completing-read interface (setq prefix-help-command #'embark-prefix-help-command) :config ;; Hide the mode line of the Embark live/completions buffers (add-to-list 'display-buffer-alist '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" nil (window-parameters (mode-line-format . none))))) ;; Consult users will also want the embark-consult package. (use-package embark-consult :ensure t :after (embark consult) :demand t ; only necessary if you have the hook below ;; if you want to have consult previews as you move around an ;; auto-updating embark collect buffer :hook (embark-collect-mode . consult-preview-at-point-mode))
Other Embark commands such as mbark-act-all
, embark-become
,
embark-collect-snapshot
, embark-collect-live
, embark-export
can be run
through embark-act
as actions bound to A
, B
, S
, L
, E
respectively, and
thus don't really need a dedicated key binding, but feel free to bind
them directly if you so wish. If you do choose to bind them directly,
you'll probably want to bind them in minibuffer-local-map
, since they
are most useful in the minibuffer (in fact, embark-become
only works
in the minibuffer).
The command embark-dwim
executes the default action at point. Another good
keybinding for embark-dwim
is M-.
since embark-dwim
acts like
xref-find-definitions
on the symbol at point. C-.
can be seen as a
right-click context menu at point and M-.
acts like left-click. The
keybindings are mnemonic, both act at the point (.
).
Embark needs to know what your minibuffer completion system considers
to be the list of candidates and which one is the current candidate.
Embark works out of the box if you use Emacs's default tab completion,
the built-in icomplete-mode
or fido-mode
, or the third-party packages
Vertico, Selectrum or Ivy.
If you are a Helm or Ivy user you are unlikely to want Embark since those packages include comprehensive functionality for acting on minibuffer completion candidates. (Embark does come with Ivy integration despite this.)
By default, if you run embark-act
and do not immediately select an
action, after a short delay Embark will pop up a buffer called *Embark
Actions*
containing a list of available actions with their key
bindings. You can scroll that buffer with the mouse of with the usual
commands scroll-other-window
and scroll-other-window-down
(bound by
default to C-M-v
and C-M-S-v
).
That functionality is provided by the embark-mixed-indicator
, but
Embark has other indicators that can provide information about the
target and its type, what other targets you can cycle to, and which
actions have key bindings in the action map for the current type of
target. Any number of indicators can be active at once and the user
option embark-indicators
should be set to a list of the desired
indicators.
Embark comes with the following indicators:
embark-minimal-indicator
: shows a messages in the echo area or
minibuffer prompt showing the current target and the types of all
targets starting with the current one; this one is on by default.embark-highlight-indicator
: highlights the target at point;
also on by default.embark-verbose-indicator
: displays a table of actions and their key
bindings in a buffer; this is not on by default, in favor of the
mixed indicator described next.embark-mixed-indicator
: starts out by behaving as the minimal
indicator but after a short delay acts as the verbose indicator;
this is on by default.embark-isearch-highlight-indicator
: this only does something when
the current target is the symbol at point, in which case it
lazily highlights all occurrences of that symbol in the current
buffer, like isearch; also on by default.
Users of the popular which-key package may prefer to use the
embark-which-key-indicator
from the Embark wiki. Just copy its
definition from the wiki into your configuration and customize the
embark-indicators
user option to exclude the mixed and verbose
indicators and to include embark-which-key-indicator
.
As an alternative to reading the list of actions in the verbose or
mixed indicators (see the previous section for a description of
these), you can press the embark-help-key
, which is C-h
by default
(but you may prefer ?
to free up C-h
for use as a prefix) after
running embark-act
. Pressing the help key will prompt you for the name
of an action with completion (but feel free to enter a command that is
not among the offered candidates!), and will also remind you of the
key bindings. You can press embark-keymap-prompter-key
, which is @
by
default, at the prompt and then one of the key bindings to enter the
name of the corresponding action.
You may think that with the *Embark Actions*
buffer popping up to
remind you of the key bindings you'd never want to use completion to
select an action by name, but personally I find that typing a small
portion of the action name to narrow down the list of candidates feels
significantly faster than visually scanning the entire list of actions.
If you find you prefer entering actions that way, you can configure
embark to always prompt you for actions by setting the variable
embark-prompter
to embark-completing-read-prompter
.
By default, if you call embark-act
from the minibuffer it quits the
minibuffer after performing the action. You can change this by setting
the user option embark-quit-after-action
to nil
. Having embark-act
not
quit the minibuffer can be useful to turn commands into little "thing
managers". For example, you can use find-file
as a little file manager
or describe-package
as a little package manager: you can run those
commands, perform a series of actions, and then quit the command.
If you want to control the quitting behavior in a fine-grained manner
depending on the action, you can set embark-quit-after-action
to an
alist, associating commands to either t
for quitting or nil
for not
quitting. When using an alist, you can use the special key t
to
specify the default behavior. For example, to specify that by default
actions should not quit the minibuffer but that using kill-buffer
as
an action should quit, you can use the following configuration:
(setq embark-quit-after-action '((kill-buffer . t) (t . nil)))
The variable embark-quit-after-action
only specifies a default, that
is, it only controls whether or not embark-act
quits the minibuffer
when you call it without a prefix argument, and you can select the
opposite behavior to what the variable says by calling embark-act
with
C-u
. Also note that both the variable embark-quit-after-action
and C-u
have no effect when you call embark-act
outside the minibuffer.
If you find yourself using the quitting and non-quitting variants of
embark-act
about equally often, independently of the action, you may
prefer to simply have separate commands for them instead of a single
command that you call with C-u
half the time. You could, for example,
keep the default exiting behavior of embark-act
and define a
non-quitting version as follows:
(defun embark-act-noquit () "Run action but don't quit the minibuffer afterwards." (interactive) (let ((embark-quit-after-action nil)) (embark-act)))
You can customize what happens after the target is inserted at the
minibuffer prompt of an action. There are
embark-target-injection-hooks
, that are run by default after injecting
the target into the minibuffer. The variable
embark-target-injection-hooks
is an alist associating commands to
their setup hooks. There are two special keys: if no setup hook is
specified for a given action, the hook associated to t
is run; and the
hook associated to :always
is run regardless of the action. (This
variable used to have the less explicit name of
embark-setup-action-hooks
, so please update your configuration.)
For example, consider using shell-command
as an action during file
completion. It would be useful to insert a space before the target
file name and to leave the point at the beginning, so you can
immediately type the shell command to run on that file. That's why in
Embark's default configuration there is an entry in
embark-target-injection-hooks
associating shell-command
to a hook that
includes embark--shell-prep
, a simple helper function that quotes all
the spaces in the file name, inserts an extra space at the beginning
of the line and leaves point to the left of it.
Now, the preparation that embark--shell-prep
does would be useless if
Embark did what it normally does after it inserts the target of the
action at the minibuffer prompt, which is to "press RET
" for you,
accepting the target as is; if Embark did that for shell-command
you
wouldn't get a chance to type in the command to execute! That is why
in Embark's default configuration the entry for shell-command
in
embark-target-injection-hooks
also contains the function
embark--allow-edit
.
Embark used to have a dedicated variable embark-allow-edit-actions
to
which you could add commands for which Embark should forgo pressing
RET
for you after inserting the target. Since its effect can also be
achieved via the general embark-target-injection-hooks
mechanism, that
variable has been removed to simply Embark. Be sure to update your
configuration; if you had something like:
(add-to-list 'embark-allow-edit-actions 'my-command)
you should replace it with:
(push 'embark--allow-edit (alist-get 'my-command embark-target-injection-hooks))
Also note that while you could abuse embark--allow-edit
so that you
have to confirm "dangerous" actions such as delete-file
, it is better
to implement confirmation by adding the embark--confirm
function to
the appropriate entry of a different hook alist, namely,
embark-pre-action-hooks
.
Besides embark--allow-edit
, Embark comes with another function that is
of general utility in action setup hooks: embark--ignore-target
. Use
it for commands that do prompt you in the minibuffer but for which
inserting the target would be inappropriate. This is not a common
situation but does occasionally arise. For example it is used by
default for shell-command-on-region
: that command is used as an action
for region targets, and it prompts you for a shell command; you
typically do not want the target, that is the contents of the region,
to be entered at that prompt!
Embark has two variables, embark-pre-action-hooks
and
embark-post-action-hooks
, which are alists associating commands to
hooks that should run before or after the command is used as an
action. As with, embark-target-injection-hooks
, there are two special keys
for the alists: t
designates the default hook to run when no specific
hook is specified for a command; and the hook associated to :always
runs regardless.
The default values of those variables are fairly extensive, adding
creature comforts to make running actions a smooth experience. Embark
comes with several functions intended to be added to these hooks, and
used in the default values of embark-pre-action-hooks
and
embark-post-action-hooks
.
For pre-action hooks:
embark--confirm
delete-file
and
kill-buffer
.embark--mark-target
embark-highlight-indicator
to know what portion of the buffer to
highlight); this function marks that region. It is useful as a pre
action hook for commands that expect a region to be marked, for
example, it is used by default for indent-region
so that it works on
s-expression targets, or for fill-region
so that it works on
paragraph targets.embark--unmark-target
occur
and query-replace
, for example, so that
you can use them as actions with region targets to search the whole
buffer for the text contained in the region. Without this pre-action
hook using occur
as an action for a region target would be
pointless: it would search for the the region contents in the
region, (typically, due to the details of regexps) finding only one
match!embark--beginning-of-target
backward-sexp
, so that they don't
accidentally leave you on the current target.embark--end-of-target
eval-last-sexp
. This allow you to act
on an s-expression from anywhere inside it and still use
eval-last-sexp
as an action.embark--narrow-to-target
repunctuate-sentences
.embark--xref-push-markers
xref-pop-marker-stack
. This is used by default for find-library
.For post-action hooks:
embark--restart
embark-post-action-hooks
uses it for delete-file
, kill-buffer
,
rename-file
, rename-buffer
, etc.
All internal keymaps are defined with a helper macro
embark-define-keymap
that you can use to define your own keymaps,
whether they are for new categories in embark-keymap-alist
or for any
other purpose! For example a simple version of the file action keymap
could be defined as follows:
(embark-define-keymap embark-file-map "Example keymap with a few file actions" ("d" delete-file) ("r" rename-file) ("c" copy-file))
Remember also that these action keymaps are perfectly normal Emacs
keymaps, and do not need to be created with this helper macro. You
can use the built-in define-key
, or your favorite external package
such as bind-key
or general.el
to manage them.
It is easy to configure Embark to provide actions for new types of targets, either in the minibuffer or outside it. I present below two very detailed examples of how to do this. At several points I'll explain more than one way to proceed, typically with the easiest option first. I include the alternative options since there will be similar situations where the easiest option is not available.
As an example, take the new tab bars from Emacs 27. I'll explain how to configure Embark to offer tab-specific actions when you use the tab-bar-mode commands that mention tabs by name. The configuration explained here is now built-in to Embark (and Marginalia), but it's still a good self-contained example. In order to setup up tab actions you would need to: (1) make sure Embark knows those commands deal with tabs, (2) define a keymap for tab actions and configure Embark so it knows that's the keymap you want.
For step (1), it would be great if the tab-bar-mode
commands reported
the completion category tab
when asking you for a tab with
completion. (All built-in Emacs commands that prompt for file names,
for example, do have metadata indicating that they want a file
.) They
do not, unfortunately, and I will describe a couple of ways to deal
with this.
Maybe the easiest thing is to configure Marginalia to enhance those
commands. All of the tab-bar-*-tab-by-name
commands have the words
"tab by name" in the minibuffer prompt, so you can use:
(add-to-list 'marginalia-prompt-categories '("tab by name" . tab))
That's it! But in case you are ever in a situation where you don't
already have commands that prompt for the targets you want, I'll
describe how writing your own command with appropriate category
metadata looks:
(defun my-select-tab-by-name (tab) (interactive (list (let ((tab-list (or (mapcar (lambda (tab) (cdr (assq 'name tab))) (tab-bar-tabs)) (user-error "No tabs found")))) (completing-read "Tabs: " (lambda (string predicate action) (if (eq action 'metadata) '(metadata (category . tab)) (complete-with-action action tab-list string predicate))))))) (tab-bar-select-tab-by-name tab))
As you can see, the built-in support for setting the category
meta-datum is not very easy to use or pretty to look at. To help with
this I recommend the consult--read
function from the excellent
Consult package. With that function we can rewrite the command as
follows:
(defun my-select-tab-by-name (tab) (interactive (list (let ((tab-list (or (mapcar (lambda (tab) (cdr (assq 'name tab))) (tab-bar-tabs)) (user-error "No tabs found")))) (consult--read tab-list :prompt "Tabs: " :category 'tab)))) (tab-bar-select-tab-by-name tab))
Much nicer! No matter how you define the my-select-tab-by-name
command, the first approach with Marginalia and prompt detection has
the following advantages: you get the tab
category for all the
tab-bar-*-bar-by-name
commands at once, also, you enhance built-in
commands, instead of defining new ones.
Let's say we want to offer select, rename and close actions for tabs (in addition to Embark general actions, such as saving the tab name to the kill-ring, which you get for free). Then this will do:
(embark-define-keymap embark-tab-actions "Keymap for actions for tab-bar tabs (when mentioned by name)." ("s" tab-bar-select-tab-by-name) ("r" tab-bar-rename-tab-by-name) ("k" tab-bar-close-tab-by-name)) (add-to-list 'embark-keymap-alist '(tab . embark-tab-actions))
What if after using this for a while you feel closing the tab without confirmation is dangerous? You have a couple of options:
You can keep using the tab-bar-close-tab-by-name
command, but have
Embark ask you for confirmation:
(push #'embark--confirm (alist-get 'tab-bar-close-tab-by-name embark-pre-action-hooks))
You can write your own command that prompts for confirmation and
use that instead of tab-bar-close-tab-by-name
in the above keymap:
(defun my-confirm-close-tab-by-name (tab) (interactive "sTab to close: ") (when (y-or-n-p (format "Close tab '%s'? " tab)) (tab-bar-close-tab-by-name tab)))
Notice that this is a command you can also use directly from M-x
independently of Embark. Using it from M-x
leaves something to be
desired, though, since you don't get completion for the tab names.
You can fix this if you wish as described in the previous section.
Say you want to teach Embark to treat text of the form
wikipedia:Garry_Kasparov
in any regular buffer as a link to Wikipedia,
with actions to open the Wikipedia page in eww or an external browser
or to save the URL of the page in the kill-ring. We can take advantage
of the actions that Embark has preconfigured for URLs, so all we need
to do is teach Embark that wikipedia:Garry_Kasparov
stands for the URL
https://en.wikipedia.org/wiki/Garry_Kasparov
.
You can be as fancy as you want with the recognized syntax. Here, to
keep the example simple, I'll assume the link matches the regexp
wikipedia:[[:alnum:]_]+
. We will write a function that looks for a
match surrounding point, and returns an improper list of the form
'(url actual-url-of-the-page beg . end)
where beg
and end
are the
buffer positions where the target starts and ends, and are used by
Embark to highlight the target (if you have embark-highlight-indicator
included in the list embark-indicators
).
(defun my-short-wikipedia-link () "Target a link at point of the form wikipedia:Page_Name." (save-excursion (let* ((beg (progn (skip-chars-backward "[:alnum:]_:") (point))) (end (progn (skip-chars-forward "[:alnum:]_:") (point))) (str (buffer-substring-no-properties beg end))) (save-match-data (when (string-match "wikipedia:\\([[:alnum:]_]+\\)" str) `(url (format "https://en.wikipedia.org/wiki/%s" (match-string 1 str)) ,beg . ,end)))))) (add-to-list 'embark-target-finders 'my-short-wikipedia-link)
Embark actions are normal Emacs commands, that is, functions with an
interactive specification. In order to execute an action, Embark
calls the command with call-interactively
, so the command reads user
input exactly as if run directly by the user. For example the
command may open a minibuffer and read a string
(read-from-minibuffer
) or open a completion interface
(completing-read
). If this happens, Embark takes the target string
and inserts it automatically into the minibuffer, simulating user
input this way. After inserting the string, Embark exits the
minibuffer, submitting the input. (The immediate minibuffer exit can
be disabled for specific actions in order to allow editing the
input; this is done by adding the embark--allow-edit
function to the
appropriate entry of embark-target-injection-hooks
). Embark inserts
the target string at the first minibuffer opened by the action
command, and if the command happens to prompt the user for input
more than once, the user still interacts with the second and further
prompts in the normal fashion. Note that if a command does not
prompt the user for input in the minibuffer, Embark still allows you
to use it as an action, but of course, never inserts the target
anywhere. (There are plenty of examples in the default configuration
of commands that do not prompt the user bound to keys in the action
maps, most of the region actions, for instance.)
This is how Embark manages to reuse normal commands as actions. The mechanism allows you to use as Embark actions commands that were not written with Embark in mind (and indeed almost all actions that are bound by default in Embark's action keymaps are standard Emacs commands). It also allows you to write new custom actions in such a way that they are useful even without Embark.
Staring from version 28.1, Emacs has a variable
y-or-n-p-use-read-key
, which when set to t
causes y-or-n-p
to use
read-key
instead of read-from-minibuffer
. Setting
y-or-n-p-use-read-key
to t
is recommended for Embark users because
it keeps Embark from attempting to insert the target at a y-or-n-p
prompt, which would almost never be sensible. Also consider this as
a warning to structure your own action commands so that if they use
y-or-n-p
, they do so only after the prompting for the target.
Here is a simple example illustrating the various ways of reading
input from the user mentioned above. Bind the following commands to
the embark-symbol-map
to be used as actions, then put the point on
some symbol and run them with embark-act
:
(defun example-action-command1 () (interactive) (message "The input was `%s'." (read-from-minibuffer "Input: "))) (defun example-action-command2 (arg input1 input2) (interactive "P\nsInput 1: \nsInput 2: ") (message "The first input %swas `%s', and the second was `%s'." (if arg "truly " "") input1 input2)) (defun example-action-command3 () (interactive) (message "Your selection was `%s'." (completing-read "Select: " '("E" "M" "B" "A" "R" "K")))) (defun example-action-command4 () (interactive) (message "I don't prompt you for input and thus ignore the target!")) (define-key embark-symbol-map "X1" #'example-action-command1) (define-key embark-symbol-map "X2" #'example-action-command2) (define-key embark-symbol-map "X3" #'example-action-command3) (define-key embark-symbol-map "X4" #'example-action-command4)
Also note that if you are using the key bindings to call actions,
you can pass prefix arguments to actions in the normal way. For
example, you can use C-u X2
with the above demonstration actions to
make the message printed by example-action-command2
more emphatic.
This ability to pass prefix arguments to actions is useful for some
actions in the default configuration, such as
embark-shell-command-on-buffer
.
Alternatively, Embark does support one other type of action: a non-interactive function of a single argument. The target is passed as argument to the function. For example:
(defun example-action-function (target) (message "The target was `%s'." target)) (define-key embark-symbol-map "X4" #'example-action-function)
Note that normally binding non-interactive functions in a keymap is useless, since when attempting to run them using the key binding you get an error message similar to "Wrong type argument: commandp, example-action-function". In general it is more flexible to write any new Embark actions as commands, that is, as interactive functions, because that way you can also run them directly, without Embark. But there are a couple of reasons to use non-interactive functions as actions:
Embark cooperates well with the Marginalia and Consult packages. Neither of those packages is a dependency of Embark, but Marginalia is highly recommended, for reasons explained in the rest of this section.
Embark comes with actions for symbols (commands, functions, variables
with actions such as finding the definition, looking up the
documentation, evaluating, etc.) in the embark-symbol-map
keymap, and
for packages (actions like install, delete, browse url, etc.) in the
embark-package-keymap
.
Unfortunately Embark does not automatically offers you these keymaps
when relevant, because many built-in Emacs commands don't report
accurate category metadata. For example, a command like
describe-package
, which reads a package name from the minibuffer,
does not have metadata indicating this fact.
In an earlier Embark version, there were functions to supply this
missing metadata, but they have been moved to Marginalia, which
augments many Emacs command to report accurate category metadata.
Simply activating marginalia-mode
allows Embark to offer you the
package and symbol actions when appropriate again. Candidate
annotations in the Embark collect buffer are also provided by the
Marginalia package.
marginalia-mode
, the list
view in Embark Collect buffers will use the Marginalia annotations
automatically.M-x
, or the unicode
characters in C-x 8 RET
).embark-collect-snapshot
from
consult-line
, consult-mark
or consult-outline
, you will notice the
Embark Collect buffer starts in list view by default. Similarly,
you'll notice that the consult-yank
family of commands start out in
list view with zebra stripes, so you can easily tell where
multi-line kill-ring entries start and end.embark-open-externally
has been removed following the
policy of avoiding overlap with Consult. If you used that action,
add the small function to your configuration or install Consult and
use consult-file-externally
.If you want to learn more about how others have used Embark here are some links to read:
And some videos to watch:
Contributions to Embark are very welcome. There is a wish list for actions, target finders, candidate collectors and exporters. For other ideas you have for Embark, feel free to open an issue on the issue tracker. Any neat configuration tricks you find might be a good fit for the wiki.
Code contributions are very welcome too, but since Embark is now on GNU ELPA, copyright assignment to the FSF is required before you can contribute code.
While I, Omar Antolín Camarena, have written most of the Embark code and remain very stubborn about some of the design decisions, Embark has received substantial help from a number of other people which this document has neglected to mention for far too long. In particular, Daniel Mendler has been absolutely invaluable, implementing several important features, and providing a lot of useful advice.
Code contributions:
Advice and useful discussions:
embark-0.15.tar.lz | 2022-Jan-15 | 68.8 KiB |
embark-0.14.tar.lz | 2021-Dec-29 | 67.8 KiB |
embark-0.13.tar.lz | 2021-Oct-31 | 61.4 KiB |