Fifteen ways to use Embark
Update (2024-10-02): Update for Emacs 29
Update (2024-09-08): Read this article in Japanese at Qiita or at Emacs-JP.
Update (2021-10-16): While this list was intended as a demonstration of the kinds of things you can do with Embark, there has been some interest by readers in reproducing these demos exactly on their machines. So I have added a “Play by play” section under each demo listing the sequence of actions in the demo.
Embark is a fantastic and thoughtfully designed package for Emacs that flips Emacs’ action → object ordering without adding a learning curve. It’s completely changed how I use Emacs, and I’m going to show you why.
By default, Emacs’ action model is to specify the action (find-file
), then the object (the file):
This mirrors how one does things in a shell:
The difference is that before you submit your shell command, you’re free to edit both the action and the object, since it’s just a line of text. In Emacs you can change the object freely, but to change the action you’d have to hit C-g
and call a different command.
Things work the other way in a GUI program like a file manager. You select some representation of the object (usually an icon), then choose the action you would like to perform on it:
Either paradigm works fine, but this is Emacs, there’s no reason to choose just one! Embark lets you go back and forth between the two patterns. So you can call find-file
(say) and pick a file, only to realize that you want to do something else with it, like open it in another window, or copy the file to a different directory:
With Embark, this is a breeze.
embark-act
: Actually…. & But first…
embark-act
is your “Actually…” command. As in, I called package-install
and picked a package but actually I’d like to read the package description instead!
embark-act
is your “Yes, but first…” command as well. As in, I called find-file
but first I’d like to copy it elsewhere to be safe, then continue to open this file!
Or perhaps you want to think of it as a keyboard driven analog of a “right-click menu” in a GUI environment. That works too, but the former maps better to the idea of “late-binding” and laziness that I think of Embark as enabling.
Emacs makes you specify and fix the action/verb first (find-file
, say), then choose the thing it acts on (the file). If you call embark-act, this is reversed. Now the object (file) is fixed, and you’re free to choose the action.
I know: It sounds like I’m describing Helm actions. The difference is that Embark works everywhere, across all types of “objects”, and with every initial and wait-I-changed-my-mind command. There is no predetermined set of alternative actions configured to work with another predetermined set of initial actions. No one (including yourself) needs to have anticipated in advance what actions go together.1 This uniform, consistent integration into Emacs makes the difference between them one of kind and not of quantity, although it takes a bit of time to see this.
This means you can start a command and select a candidate in the minibuffer, then call embark-act
and M-x some-other-command
to run that command on the candidate instead. If you are about to kill a buffer with C-x k
but want to switch to it instead, you can call embark-act
followed by C-x b
. You can even do this without losing the kill-buffer
prompt if you just want a quick peek at the buffer!
The categories of objects Embark understands covers most common cases: filenames, buffers, bookmarks, URLs, text regions, variables, commands, symbols and more.
When you call embark-act
, Embark also activates a keymap with direct access to common actions you might want to run for each category of object. This makes it unnecessary to use M-x
to run your I-changed-my-mind action all the time, although you always have that option. You can, of course, add your own commands to this keymap as I do below.
I use embark-act
literally hundreds of times every day. Here are a few of my common uses. A few of these are built in, others need some elisp to work, all are surprisingly useful. To be clear, this list barely scratches the surface of the sphere of possibilities with Embark.
A recipe for reproducing these demos
I use Embark in conjunction with various Consult commands (consult-grep
, consult-locate
, consult-dir
etc) in Emacs 27.2. If you want to reproduce these demos exactly in your Emacs, you will need the following packages:
embark
marginalia
vertico
consult
embark-consult
orderless
consult-dir
ace-window
0x0
Additionally you may need to bind the relevant commands (embark-act
, embark-export
, consult-*
) to suitable keys.
Open any buffer by splitting any window
This needs a little background. The ace-window package allows you to switch to a window based on keyboard hints. A less well known feature is that it also provides a “dispatch menu” that lets you act on windows in ways beyond simply switching to them:
Play by play
- With two or more windows open, call
ace-window
- Press
?
to bring up the dispatch menu. - Press the dispatch key to split a window horizontally (
v
in my video) - Press the ace-window key corresponding to the buffer you want to split (
e
in my video) - Repeat steps 1 and 2
- Press the dispatch key to split a window vertically (
s
in my video) - Press the ace-window key corresponding to the buffer you want to split (
w
in my video)
So you can kill windows, move them around, split them and more by using the dispatch keys. (Hit ?
to bring up the dispatch menu.)
Now: You can call ace-window via Embark to display a candidate anywhere, including in splits that you create using the above dispatch menu. This means any buffer/file/bookmark I open is always placed exactly where I want it to be on the screen.
In the below demo, I open a bookmark (with consult-bookmark
), a file (with find-file
) and a buffer (with consult-buffer
) in sequence. Each time, I run embark-act
and select the ace-window action, which activates ace-window
. You can then display the buffer in any existing window by making a selection with ace-window
. I actually go one step further in the demo: I split one of the existing windows using ace-window
’s dispatch feature from above and display the relevant buffer in that split!
Play by play
- Run a command that requires selecting a file, bookmark or buffer, perhaps
switch-to-buffer
- Select one and run
embark-act
- Run the
my/embark-ace-action
witho
(see below) - Select the window where you want the buffer to be placed, OR
- Split an existing window with
v
orb
(seeaw-dispatch-alist
) followed by a window selection, and display the buffer in the new split.
Update for Emacs 29
Emacs 29 provides a bunch of “window-prefix” actions: these are commands you can call to display the output of the next command in specified windows. For example, calling other-tab-prefix
and then find-file
will open the file you select in a new tab. Emacs provides same-window-prefix
, other-window-prefix
, other-tab-prefix
and other-frame-prefix
. We can go one step further and define an ace-window-prefix
. Calling it will activate ace-window
after the next command and show its result in the window you select, including possibly in splits you create using ace-window
actions:
(defun ace-window-prefix ()
"Use `ace-window' to display the buffer of the next command.
The next buffer is the buffer displayed by the next command invoked
immediately after this command (ignoring reading from the minibuffer).
Creates a new window before displaying the buffer.
When `switch-to-buffer-obey-display-actions' is non-nil,
`switch-to-buffer' commands are also supported."
(interactive)
(display-buffer-override-next-command
(lambda (buffer _)
(let (window type)
(setq
window (aw-select (propertize " ACE" 'face 'mode-line-highlight))
type 'reuse)
(cons window type)))
nil "[ace-window]")
(message "Use `ace-window' to display next command buffer..."))
Now the interesting bit: Instead of defining separate Embark actions for opening files, bookmarks or buffers in specified windows or splits, we can embed the window prefix actions into Embark so they can be used with any category of object.
First we define a keymap with these actions:
(defvar-keymap my/window-prefix-map
:doc "Keymap for various window-prefix maps"
:suppress 'nodigits
"o" #'ace-window-prefix
"0" #'ace-window-prefix
"1" #'same-window-prefix
"2" #'split-window-vertically
"3" #'split-window-horizontally
"4" #'other-window-prefix
"5" #'other-frame-prefix
"6" #'other-tab-prefix
"t" #'other-tab-prefix)
What we’d like: When running embark-act
, pressing any of the keys in the above keymap should run Embark’s default action – i.e. the command that you originally invoked – but with the right window-prefix applied. This will supersede the below, older method of defining individual Embark commands for each kind of object. Getting there involves hooking into Embark’s event loop, so this is a little convoluted. Strap in!
-
We define a function that looks up keys in the above keymap and calls the right
-window-prefix
command before running Embark’s default action. This is intended as a hook function for Embark’sembark-around-action-hooks
, which lets you insert specific behavior around each Embark action. This is the code we’d like Embark to actually run:;; Look up the key in `my/window-prefix-map' and call that function first. ;; Then run the default embark action. (cl-defun my/embark--call-prefix-action (&rest rest &key run type &allow-other-keys) (when-let ((cmd (keymap-lookup my/window-prefix-map (key-description (this-command-keys-vector))))) (funcall cmd)) (funcall run :action (embark--default-action type) :type type rest))
-
But this behavior is not attached to any Embark action yet. To access this behavior from Embark, we define a dummy Embark action whose behavior will be replaced by the above function:
;; Dummy function, will be overridden by running `embark-around-action-hooks' (defun my/embark-set-window () (interactive)) ;; When running the dummy function, call the prefix action from above (setf (alist-get 'my/embark-set-window embark-around-action-hooks) '(my/embark--call-prefix-action))
-
A wrinkle: to support multi-category commands like those provided by Consult (where the candidates can be a mix of bookmarks, buffers, files and others), we need to explicitly set the “default” Embark action for relevant categories:
(setf (alist-get 'buffer embark-default-action-overrides) #'pop-to-buffer-same-window (alist-get 'file embark-default-action-overrides) #'find-file (alist-get 'bookmark embark-default-action-overrides) #'bookmark-jump (alist-get 'library embark-default-action-overrides) #'find-library)
-
Finally, we map this dummy embark action to all the keys in
my/window-prefix-map
:(map-keymap (lambda (key cmd) (keymap-set embark-general-map (key-description (make-vector 1 key)) #'my/embark-set-window)) my/window-prefix-map)
The fact that all keys in
my/window-prefix-map
are mapped to the same action is not a problem – inmy/embark--call-prefix-action
we dispatch on the key that was actually pressed.
If you’re on Emacs 29 or later, you can enable behavior like the above for all commands and categories at once, without needing to define individual actions. The below is a more manual (and backward-compatible) approach.
To get this to work, you’ll need to add a few ace-window functions to the Embark file actions map:
(eval-when-compile
(defmacro my/embark-ace-action (fn)
`(defun ,(intern (concat "my/embark-ace-" (symbol-name fn))) ()
(interactive)
(with-demoted-errors "%s"
(require 'ace-window)
(let ((aw-dispatch-always t))
(aw-switch-to-window (aw-select nil))
(call-interactively (symbol-function ',fn)))))))
(define-key embark-file-map (kbd "o") (my/embark-ace-action find-file))
(define-key embark-buffer-map (kbd "o") (my/embark-ace-action switch-to-buffer))
(define-key embark-bookmark-map (kbd "o") (my/embark-ace-action bookmark-jump))
I also add actions to open the buffer in a vertical or horizontal split. But you probably don’t need this, since you can do this and a lot more with ace-window’s dispatch menu!
(eval-when-compile
(defmacro my/embark-split-action (fn split-type)
`(defun ,(intern (concat "my/embark-"
(symbol-name fn)
"-"
(car (last (split-string
(symbol-name split-type) "-"))))) ()
(interactive)
(funcall #',split-type)
(call-interactively #',fn))))
(define-key embark-file-map (kbd "2") (my/embark-split-action find-file split-window-below))
(define-key embark-buffer-map (kbd "2") (my/embark-split-action switch-to-buffer split-window-below))
(define-key embark-bookmark-map (kbd "2") (my/embark-split-action bookmark-jump split-window-below))
(define-key embark-file-map (kbd "3") (my/embark-split-action find-file split-window-right))
(define-key embark-buffer-map (kbd "3") (my/embark-split-action switch-to-buffer split-window-right))
(define-key embark-bookmark-map (kbd "3") (my/embark-split-action bookmark-jump split-window-right))
Copy a file to a remote location when finding a file
Play by play
- Run any command that requires selecting a file, perhaps
find-file-other-window
- Select one and run
embark-act
- Run the
copy-file
action withc
. Embark has a key for this but you can alsoM-x copy-file
here. - Navigate to the destination path. In the video I used the consult-dir package to instantly switch the path to one of my bookmarks, a remote location.
- Press
RET
to copy the file. You can type in a name to copy it as.
Here’s what happened. In any file prompt, you can call embark-act
and select the copy action to copy the file instead. (You could just as well call M-x copy-file
.) In this case I then use consult-dir to insert a bookmark that points to my server into the destination prompt, and the file is copied using Tramp.
You can even do this without losing the find-file
prompt! Calling embark-act
with a prefix argument keeps the prompt alive:
Play by play
- Run any command that requires selecting a file, perhaps
find-file-other-window
- Select one and run
embark-act
with a prefix argument. That is, if your binding forembark-act
isC-.
, runC-u C-.
. - Run the
copy-file
action withc
. Embark has a key for this but you can alsoM-x copy-file
here. - Navigate to the destination path. In the video I used the consult-dir package to instantly switch the path to one of my bookmarks, a remote location.
- Press
RET
to copy the file. You can type in a name to copy it as. - Continue to use your
find-file-other-window
prompt as before.
At the end I quit the find-file
prompt manually and check the remote directory to ensure that the file has been copied.
Insert a minibuffer candidate into the buffer
Simple but very convenient:
Play by play
- Run any command that requires you to make a selection using the minibuffer. The selection can be anything, it just has to display some text.
- In the video I chose a distant directory with
consult-dir
and selected a file in that directory. - Run
embark-act
- Press
i
to insert the text of the selection into the main buffer. In the video I usedI
instead to insert the selected file’s relative path.I
does different things based on the type of object you’re selecting. For example,I
with a buffer candidate inserts the contents of the buffer instead.
Run a shell command on a minibuffer candidate file without losing your session
A perfect example of But First I need to…:
Play by play
- Run any command that requires selecting a file, perhaps
find-file
- I switched to a distant directory using
consult-dir
. - Select a file and run
embark-act
with a prefix argument. That is, if your binding forembark-act
isC-.
, runC-u C-.
. - Press
&
to run theasync-shell-command
action. Embark has a key for this in its keymaps but you could runM-x async-shell-command
or call its default keybinding (M-&
) instead. - Type in the command at the prompt. The file name is already filled in for you. I used the
file
shell command for more info on a file. - Press
RET
to run the command and return to thefind-file
prompt.
I called the “file” shell command for more info on the file without ending the find-file
prompt.
Open a file as root without losing your session
Emacs’ version of forgetting to add sudo
before the command. In the shell you can go back to the start of the prompt and type it in, or engage in the sudo !!
ritual. In Emacs I use an Embark action:
Play by play
- Run any command that requires selecting a file. I used
consult-locate
to locate a root-owned file on my filesystem. - Select one and run
embark-act
with a prefix argument. That is, if your binding forembark-act
isC-.
, runC-u C-.
. - Select the
sudo-find-file
action withS
. Note: You’ll need to add this action to the keymap, see below. Alternatively you can runM-x sudo-find-file
or its global binding.
Like before, this works from any file prompt but the command I started with was consult-locate
. For the sudo program there is the sudo-edit
package, although I used a snippet from my init file that I can’t ascertain the provenance of anymore:
(defun sudo-find-file (file)
"Open FILE as root."
(interactive "FOpen file as root: ")
(when (file-writable-p file)
(user-error "File is user writeable, aborting sudo"))
(find-file (if (file-remote-p file)
(concat "/" (file-remote-p file 'method) ":"
(file-remote-p file 'user) "@" (file-remote-p file 'host)
"|sudo:root@"
(file-remote-p file 'host) ":" (file-remote-p file 'localname))
(concat "/sudo:root@localhost:" file))))
To use sudo-find-file
as an Embark action, you can run it (with M-x
or a global keybinding) after calling embark-act
, or shorten the process further by adding an entry to Embark’s file actions map:
(define-key embark-file-map (kbd "S") 'sudo-find-file)
Upload a region of text to 0x0
Play by play
- Select a region of text in a buffer.
- Run
embark-act
. - Press
U
to choose the0x0-dwim
action. Note: You’ll need to add this action to the keymap, see below. - The region text will be uploaded to 0x0 and URL added to the
kill-ring
. (See message at the end of the video.)
I’m using the 0x0 package for the 0x0-dwim
function. When called as an Embark action on a URL, this shortens it. When called on a file, it uploads the file. The echo area message at the end (from 0x0-dwim
) tells me the upload URL has been copied to the kill ring. As with the other examples, you can call 0x0-dwim
after running embark-act
or define a short key for it in one of Embark’s keymaps:
(define-key embark-region-map (kbd "U") '0x0-dwim)
Visit a package’s URL from the minibuffer
Play by play
- Run any command that requires selecting a package, perhaps
describe-package
(C-h P
by default) - Select a package and run
embark-act
- Press
u
to run theembark-browse-package-url
action.
In this case I ran the describe-package
command before going “Actually… URL please”, but in this example as all the others, there’s nothing special about describe-package
. Any command that gives you a list of packages at the minibuffer will proffer the same set of Embark actions.
Set a variable from anywhere it appears in a buffer
Super handy for quickly setting variables, especially when testing code.
Play by play
- Move point to a variable in a buffer. (Alternatively, run a command that requires selecting a variable at the minibuffer, like
describe-variable
) - Run
embark-act
. - Press
=
to run theset-variable
action. Embark has a key for this in its keymaps, but you could callM-x set-variable
instead. - Set the new value of the variable.
In this case Embark has an entry for set-variable
in its variables keymap (bound to =
), but you can just call M-x set-variable
.
Add a keybinding for a command name from anywhere it appears
Set all the keys.
Play by play
- Move point to a command name in a buffer. (Alternatively, run a command that requires selecting a command at the minibuffer, like
describe-command
) - Run
embark-act
. - Press
g
to run theglobal-set-key
action. Embark has a key for this in its keymaps, but you could callM-x global-set-key
instead. - Set the new keybinding for the command.
Embark provides an action in its keymap to run global-set-key
, but you could just call M-x global-set-key
after running embark-act
with the point on a command name. There is also local-set-key
in the embark keymap.
embark-export
: I want a gist, so give me a list
If that was everything Embark did I’d be a happy camper. But embark-act
isn’t even its best feature. That would be the gem of composability that is embark-export
(and its lesser kin embark-collect
). These commands create persistent collections from minibuffer candidate lists: It’s one part ivy-occur and one part glue that ties together Emacs libraries better than Emacs does. The examples illustrate why.
Export Emacs package candidates to a package menu
Want a package-menu-mode buffer with all packages involving shells in Emacs? embark-export
has you covered:
Play by play
- Run any command that requires selecting a package, perhaps
describe-package
(C-h P
by default) - (Optional) Type in some text to filter the completions list
- Run
embark-export
The clever idea behind embark-export
is to reuse Emacs’ built-in functionality whenever possible: the package-menu library already handles displaying packages. If you’re generating a list of packages with user-specified conditions, why reinvent the wheel?
Collect imenu candidates in an “imenu-list”
embark-collect
creates persistent collections of minibuffer completion candidates (filtered by user input) in a way that basically obsoletes every “listing” package for me. In this example I create a filtered list of imenu
items that sticks around and that I can use to navigate around the file:
Play by play
- When visiting any file, run
imenu
or a version of it (I ranconsult-imenu-all
) - (Optional) Type in some text to filter the completions list
- Run
embark-export
. (This actually runsembark-collect
under the hood. You could runembark-collect
directly instead, but it’s simpler to just use one command.) - Press
RET
in the persistent collections buffer to navigate to that symbol in the file.
I didn’t show this in the demo, but all embark-act
actions are available in the Collections buffer, and you can even call them directly (i.e. without calling embark-act
first) by turning on embark-collect-direct-action-minor-mode
.
Export file candidates to a dired-buffer
Have a list of files you arrived at in a tortuous manner that you want to keep around? dired
was created to list files, and embark-export
respects this:
Play by play
- Run any command that requires selecting a file. I used
consult-fd
to find all files matching a pattern below a directory. - (Optional) Type in some text to filter the completions list. With
consult-fd
you do this by adding a#
to end the string to search on and begin the string used to filter the results. - Run
embark-export
.
This obsoletes find-name-dired
, another “listing” based feature.
Export buffer candidates to ibuffer
You saw this coming: Any list of buffers gets exported to an ibuffer
.
Play by play
- Run any command that requires selecting a buffer. I used
consult-buffer
. - Type in some text to filter the completions list:
- I pressed
b SPC
to narrow the consult-buffer list to buffers, then - typed in
!
followed by*
to omit all buffers2 that begin with a*
, i.e. “special” buffers.
- I pressed
- Run
embark-export
.
Export variable candidates to a customize buffer
A list of variables is exported by embark-export
into a customize buffer:
Play by play
- Run a command that requires selecting a variable, like
describe-variable
- Type in some text to filter the completions list
- Run
embark-export
This is a great way to transition from looking up a variable to a full-fledged apropos on relevant items when you need to.
Export grep or line candidates to a grep buffer
Any occur
-like results (from consult-line, grep, xref etc) get exported into a grep
buffer.
Play by play
- Run a command that generates a list of grep-style matches. I used
consult-ripgrep
in the demo. Other Consult-based options areconsult-grep
,consult-git-grep
andconsult-line
. - Type in some text to find grep results.
- Not necessary: I flipped through the various files that matched with
vertico-next-group
andvertico-previous-group
. - Run
embark-export
. - Turn on
next-error-follow-minor-mode
in the grep buffer withC-c C-f
. This jumps each match as I… - …navigate the grep buffer with
M-n
andM-p
(compilation-next-error
andcompilation-previous-error
), and move to the next/previous matching file with}
and{
.
Note that this is a regular grep buffer, so you can use all your tricks, like wgrep to edit the grep buffer and save changes in all the files.
BONUS: Use Embark Actions like Helm
In the above examples, the available embark actions were displayed in some window in the frame. Embark has multiple “prompters” listing the preset actions, and with a little elbow grease you can set up something similar to Helm3:
Play by play
- Run any command involving minibuffer selection,
consult-buffer
in the video. - (Optional) type in something to filter the completions list or select a buffer.
- Press
TAB
to switch to the list of embark actions. - Press
TAB
again to switch back to the list of candidates. - Search for an action by name (in this case “kill”) to filter the list of actions
- Erase and search for a different action (“diff”) and choose the
diff-buffer-with-file
action - Press
RET
to rundiff-buffer-with-file
on the selected buffer - (Optional) Navigate the diff hunks with
diff-hunk-next
anddiff-hunk-prev
- (Optional) Fold the diff sections with
outline-cycle
- Run
consult-buffer
again and select a buffer - Switch to the actions list again with
TAB
- Press
@
to call an action by its keybinding instead of selecting it by name - Call the embark action for killing a buffer with
k
to kill the selected buffer.
Here I switch back and forth between the list of actions and the list of candidates (like in Helm) with C-<tab>
. In the actions list you can either type the action (matched with completing-read), or call the action directly by prepending its keybinding with @
.
Elbow grease:
(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)
(embark-indicators '(embark-minimal-indicator)))
(embark-act arg)))
Replace vertico-map
above with your completion system of choice’s active minibuffer keymap. The default is minibuffer-local-completion-map
.
Remember that unlike with Helm, you’re not restricted to these actions when you use Embark! You can call literally any command that it makes sense to with its keybinding or with M-x
after running embark-act
.
33%
That’s fifteen useful Embark thingamajigs, and I didn’t get to mention embark-become
. Or embark-prefix-help-map
, embark-which-key-prompter
, or Embark’s targets and target cycling, or half a dozen more thoughtful features and niceties about Embark. Maybe next time.
I’ll conclude instead by mentioning the main packages I used in the above demos:
embark
by Omar Antolin Camarena, who’s been a pleasure to interact with and pester with my requests for features. To add custom actions to the embark keymaps or otherwise customize Embark, I suggest perusing the README. It’s as readable and informative as they come.consult
for its various enhancements to Emacs’ builtins.consult-locate
andconsult-find
(actuallyconsult-fd
) to find files,consult-imenu
for a colorful imenu with grouping andconsult-ripgrep
to grep across a directory.marginalia
for the annotations in the minibuffer. Co-maintained by Omar Antolin and Daniel Mendler.vertico
as the minibuffer completion interface. Consult, Vertico and Marginalia are all authored by Daniel Mendler, who I’m convinced never sleeps. I didn’t even mention Corfu.- The
orderless
completion style, also by Omar Antolin, to match pieces of text against minibuffer candidates independently. Together these five packages form the MOVEC pentagram, a composable enhancement suite that integrates Emacs’ loosely bound libraries into a modern and cohesive whole. consult-dir
to switch directories quickly. I used this multiple times above to navigate to distant directories when in the minibuffer prompt.popper
to makeembark-collect
, help and other ephemeral buffers behave when they appear on screen.ace-window
by abo-abo, whose dispatch-keys idea in Ace-Window and Avy I promptly ripped off for Popper. If I understand correctly his Ivy-Occur was an early influence on what became Embark-Collect as well.0x0
by William Vaughn. I use this far more often than I thought I would.
Finally a quick note for Doom Emacs users: Doom ships with Embark out of the box (as of Sep 2021), you don’t need to do anything besides looking up the keys for embark-act
and embark-collect
.
Despite what these examples suggest, I estimate that I use less than a third of what Embark provides. Even so, in allowing me to change or chain actions at any time, it lets me pilot Emacs by the seat of my pants. A second, unforeseen benefit is that it makes commands and listings that I would never use available in a frictionless way: commands like transpose-regions
and apply-macro-to-region-lines
, or custom dired, ibuffer and package-menu listings that are interactively inaccessible otherwise4. The ability to quickly whip up such buffers makes knowhing how to use dired or ibuffer pay off several fold. In composing such features seamlessly with minibuffer interaction or with text-regions, Embark acts as a lever to amplify the power of Emacs’ myriad built in commands and libraries.
-
Although of course, Helm and Embark both do a good job with their presets. ↩︎
-
To match the inverse of an input string with
!
, I used a feature of the orderless package for Emacs. ↩︎ -
Yes, it’s not fully Helm-style since it still uses the minibuffer instead of a buffer to show the candidates/actions. You could use vertico-buffer if that’s a sticking point. ↩︎
-
Technically custom package-menu listings are accessible. From the full package listing (
M-x list-packages
), you can filter package names by regexp with/ n
. ↩︎