When I wrote about the Emacs packages I use , I mentioned that I had Embark installed but barely used it because I didn't understand much about how to really use it. One reason for that is that while there are a bunch of articles on the web about things you can do with Embark, all of the ones I've tried to read started out with complicated stuff involving other third party packages I didn't use, which caused me to tune out and stop reading. As sometimes happens, writing that entry caused me to poke at Embark some more and now I have a somewhat better understanding of it and some Embark tricks I want to remember.
(Now that I've made the effort to read it, Fifteen ways to use Embark has a bunch of useful examples that use only built in packages. Also, part of my confusion is that Embark actually does multiple things.)
With Embark, you start with a 'something' (what Embark calls a target ) and then Embark lets you to do an assortment of things to it; some Embark writeups describe this as a middle mouse button context menu. There are at least two ways to get the 'something' ( cf ). In a regular buffer, it's whatever is at point (or the region if you have one active); in the minibuffer, it's whatever you're entering or completing. To add a bit of confusion for regular buffers, you can often change what Embark is acting on. For instance, if the GNU Emacs point (cursor) is on a word, Embark can act on the 'word' (in various ways depending on what it thinks the word is), the sentence it's part of, or the paragraph. What Embark can do depends on what sort of thing it has as its current target, so it offers you a completely different set of options for the name of an ELisp function than for a file name (see Default Actions for a very large list).
(When Embark starts in a situation where there are multiple options for the target, it will talk about 'shadowed targets at point' in the Embark buffer.)
One important 'action' that I want to remember that's always available is M-x, ie run a suitable (Lisp) command, and in fact a lot of your regular keybindings will apparently work. Not all commands will work right when run by Embark, but most of the ones you probably want to run will; see How does Embark call the actions? for the gory details.
To use Embark, you need a target. One way to get a target if you don't already have one at hand is to type it into a buffer, but another, better way is to use the minibuffer, by triggering some GNU Emacs command that will prompt you for the type of thing you're interested in. This leads to some of my 'stupid' Embark tricks (which are apparently perfectly normal). For example, suppose that I want to toggle the value of a GNU Emacs setting variable. Embark provides this as an action on variables, so the quick way to do this is 'C-h v', which will start minibuffer completion for variable names, then when I've picked the variable, trigger Embark and pick 't'. Similarly, you can set the value of a variable via Embark rather than having to remember 'M-x set-variable' and then completing the variable name anyway.
A bunch of Embark documentation talks about using Embark in the minibuffer because you changed your mind about what you want to do. You start out doing C-x C-f to open a new file and then you realize you want it in a new Emacs window so you can see your current file and the new one at the same time, so you use Embark to switch the result of C-x C-f to 'open file in new window'. Some specific options you can switch to are explicitly available, but in general you can switch to anything , although it's on you to make sure that your minibuffer completion makes sense for what you're switching to.
The logical extension of this is to not bother using or maybe even remembering C-x 4 C-f for 'open file in new window' and always using C-x C-f and then Embark to get it. Much as with my 'toggle a variable' example, you (I) are using C-x C-f as a way to generate file names for Embark to act on. Anything that generates file names in the minibuffer would do, but C-x C-f is a harmless thing if you hit RET by accident instead of triggering Embark. This is an intended use of Embark, per this Fediverse post , which I'll quote a bit of:
[...] The pattern is that any command that prompts you for Xs becomes an X manager. [...]
Functions, variables, files and directories, buffers, GNU Emacs packages, and so on, you can trigger something that prompts you for one of them, use all your completion features to fill it in, and then use Embark. You could even build a collection of personal commands (and keybindings) that only prompted you for the appropriate thing and then did nothing with the result.
A related trick is that you can use minibuffer completion to complete things you're writing in regular buffers, through Embark's action to insert text from the minibuffer into the regular buffer. Do you want to insert a file name into what you're writing? Use C-x C-f to trigger filename completion in the minibuffer and then Embark's general 'i' action to insert the result in your text. If you already have a completion setup with good completion for regular buffers ( as I do ), this is most useful for types of completion that aren't offered for your current buffer. In text buffers, this will be most of them; in code buffers this is likely to be things like file names.
(For file names specifically you can get the same completion option with Cape , although using your completion at point setup instead of minibuffer completion. But the Embark trick works for absolutely anything you can trigger a minibuffer completion for, including custom things .)
Another trick is that in minibuffer completion, Embark can also act on the current completion candidates, applying some action to all of them instead of just to one of them, the way it would if you finished completion. There's a number of actions Embark provides for acting on these groups , including exporting the current set of candidates to a buffer where you can further manipulate them in various ways that depend on the types of things (and whether you do an 'export' or a 'collect'). Embark also lets you create ad-hoc collections of things for it to act on . I'm writing about this because I looked it up but I don't think I'm likely to use this particular aspect of Embark very much, because it seems pretty fiddly.
( VOMPECCC: A Modular Completion Framework for Emacs has a discussion of the advantages of these Embark collection buffers.)
Unfortunately, using Embark in text mode buffers is somewhat fiddly because Embark often has unusual ideas of what a text word actually is. If you're lucky, Embark decides that it's an identifier and offers you various useful options (and also highlight other occurrences of the word). If you're not lucky, Embark will decide that your word is some other type of thing with a restricted set of actions; for example, 'minibuffer' (as a bare word) will be taken as an Emacs Lisp library, which has only a restricted list of actions . As far as I know there's built in way to change the type of thing or add an option to act on it as another type.
Since this is GNU Emacs, we can use violence, which is to say we can define a new sort of target, call it a 'word', and add a keymap for it that has specific bindings we want. This requires following the examples of both adding a new target and defining a keymap :
(defvar-keymap embark-word-map
:doc "Keymap for Embark actions on plain words."
:parent embark-general-map
;; TODO: What should RET do?
"o" 'occur
"$" 'ispell-word
"'" 'expand-abbrev
"p" 'embark-previous-symbol
"n" 'embark-next-symbol
"c" 'capitalize-word
"l" 'downcase-word
"u" 'upcase-word
"H" 'embark-toggle-highlight)
(add-to-list 'embark-keymap-alist '(word . embark-word-map))
(defun embark-target-word-at-point ()
"Target a word at point but only in text mode buffers."
(save-excursion
(let* ((start (progn (skip-chars-backward "[:alnum:]") (point)))
(end (progn (skip-chars-forward "[:alnum:]") (point)))
(str (buffer-substring-no-properties start end)))
(when (and (not (string-empty-p str))
(eq major-mode 'text-mode))
`(word ,str ,start . ,end)))))
(add-to-list 'embark-target-finders 'embark-target-word-at-point)
(In an ideal world this might also look to see if it was in comments or strings in a prog-mode buffer, but that's too much work for this quick hack.)
My 'word' target isn't quite as deluxe an experience as you get with identifiers, because identifiers and symbols will also lazily highlight all other occurrences in the buffer. But possibly you don't want that for plain words.
(Embark does say that it's primarily for minibuffer stuff, it's right in the name: "Emacs Mini-Buffer Actions Rooted in Keymaps".)
Sidebar: Giving Embark a connection to Flycheck
Embark ships with a connection to Flymake, so you can trigger Embark with point on a Flymake diagnostic and get some useful bindings. Because I default to Flycheck , I wired up the same thing for Flycheck, and to save other people having to do the work, here it is:
(embark-define-overlay-target flycheck flycheck-overlay) (defvar-keymap embark-flycheck-map :doc "Keymap for Embark actions on Flycheck diagnostics." :parent embark-general-map "RET" 'flycheck-list-errors "e" 'flycheck-explain-error-at-point "h" 'flycheck-display-error-at-point "n" 'flycheck-next-error "p" 'flycheck-previous-error) (add-to-list 'embark-target-finders 'embark-target-flycheck-at-point) (add-to-list 'embark-keymap-alist '(flycheck . embark-flycheck-map))
Add more Flycheck bindings to taste, those seemed to be the obvious ones to me.