Last update: 15 February 2020
I recently switched to Doom Emacs from Spacemacs. The Doom documentation is currently quite sparse, so I've posted here my personal notes on using Doom along with a description of my workflow (something I find vital but missing from most documentation). Doom might be for you if
helm
; andI'm not going into detail on how Emacs works or basic Vim keybindings here---the focus is on the things I found different and useful.
You definitely want to use the develop
branch, not master
! This means:
git clone https://github.com/hlissner/doom-emacs ~/.emacs.d
cd ~/.emacs.d
git checkout develop
Then run bin/doom quickstart
to get everything setup. Run bin/doom help
to see what other commands are available.
I find it useful to manage my work with projects and workspaces. I get two benefits from this: it's faster to find the things I'm looking for as I only look within the current project, and it's faster to get to work as I can save and restore window and buffer configuration. In Doom this means using projectile and persp-mode.
The basic workflow is:
Decide what I'm working on. Is this a distinct project, or is it something that spans multiple projects (such as managing my todo lists) or doesn't need to live in a project (such as doing a quick calculation in a scratch buffer)? If it's a distinct project it gets it's own workspace. If not I'll do it in the default workspace (main
).
Switch to the appropriate workspace with SPC TAB .
If the appropriate workspace is not loaded load it with SPC TAB l
. Otherwise create a new workspace with SPC TAB n
. If I'm creating a new workspace I will often give it a more informative name, using SPC TAB r
and then save with SPC TAB s
.
If I'm switching to an existing workspace Emacs will be returned to the state it was in when I last worked on the project and I can get straight to work. If not I'll select a project for this workspace using SPC p p
and then get to work.
Three very useful commands are:
SPC SPC
to switch to a file within the current project, with fuzzy completion; andSPC ,
to switch to a buffer within the current project, again with fuzzy completion.SPC fr
to load a recently viewed file.Things I do all the time:
SPC :
for M-x
.
SPC gg
for Magit, which is the only sane way to use Git.
Things I occasionally do:
SPC .
to find a file. Using SPC SPC
is faster, so try to use SPC .
only when you want to switch to something outside the current project.
SPC b B
to switch to a buffer outside the current project.
If you know there is text somewhere, but you don't know where, there are two basic ways to find it:
SPC sp
to search all files in the current project. (Press SPC s
and wait for a popup for other options.) When you have a buffer of matches you can jump to the one your want by pressing return or press C-c C-e
to edit all the files at once. You can then do whatever edits you want and press C-c C-c
to commit, or C-c C-k
to abandon your changes. This is super useful for both simple and complex edits across multiple files.
/
to search within the current buffer. Use n
and N
to go to next and
previous matches. (?
to search backwards.)
If you can see text on the screen and want to move to it there are a number of ways to quickly get there.
s
and type two characters to jump forward to the nearest match, and S
to jump backwards. Type ,
to cycle to matches earlier in the buffer and ;
to cycle through matches later in the buffer. By default these functions only jump to a match on the current line, but if you cycle with ,
and ;
they'll jump around the whole buffer. This is evil-snipe, which has an amazing cover graphic / logo.
gs SPC
, start typing the word you're looking at. You'll either jump directly there or be given a quick key to press to disambiguate the phrase you've typed. If you add (setq avy-all-windows t)
to your config.el
this will work across all visible windows. I love this method for quickly jumping around the screen. This uses Avy.
gs
and wait for the popup for a million other search methods. I don't really use them as the two options above do everything I need, but maybe I'm missing out.
If the things I want to jump to is fairly close to where the cursor is I'll use evil-snipe (s
and S
). If it's far away or in another window I'll use Avy (gs SPC
). Both can be used to create text objects. Imagine we have the text
Just some example text
with the cursor at the J
and we want to select Just some example
. We could use v3e
but we have to count the number of words (and remember the difference between e
and w
). Instead we could type vsle
. The s
uses evil-snipe, and le
is the two characters we're sniping. We could also use vgsSPCle
to use Avy (and we'd then have to move the cursor one character right).
There is a bit of complexity using evil-snipe. It's bound to s
for visual selection, but other commands (e.g. yank or y
) bind s
to evil-surround. In these cases evil-snipe is bound to z
(or Z
to snipe backwards). If we don't want include the letters we're sniping in the text object we can use x
(or X
for backwards sniping).
It can be useful to restrict a buffer to a selection of text, called narrowing in Emacs. This is particularly useful with multiple cursors (see below). To narrow to the current selection use SPC rn
and use SPC rw
to perform the reverse, called widening. Narrowing to the current function, with SPC rf
, is also useful.
Multiple cursors allow you to edit multiple things at a time. Doom provides two implementations of multiple cursors, evil-multiedit and evil-mc. I find evil-multiedit easier to use, but it is less powerful.
There are two ways to start editing with evil-multiedit:
select one example of the things you want to edit and press R
to select all the rest in the current buffer (perhaps narrowing first); or
move the cursor over one example of the word you want to edit and then repeatedly press M-d
and M-D
to select next or previous examples respectively.
Having selected some regions you can move between them using C-n
(next) and C-p
(previous). Pressing RET
on a region will remove it from the selection, so by using these commands you can choose arbitrary regions to include.
Once you have selected the regions, edits made to one region will be reflected in all the others. The majority of evil commands work with evil-multiedit.
Finally use the usual cancel key (ESC
or C-[
) to exit out of evil-multiedit.
The other multiple cursor implementation, evil-mc, is a bit more flexible but harder to use. There are more options for creating multiple cursors with evil-mc:
gzm
to create cursors at all matches for the word at point (possibly
narrowing the buffer first);gzd
to create a cursor at point and move to the next match (and gzD
to create and move to the previous match);gzj
to create a cursor at point and move to the next line (and gzk
to
create and move to the previous line); orgzz
to create a cursor at point.Cursors will mirror the commands you enter at the "real" cursor. You can temporarily turn off multiple cursors with gzt
. This is automatically done if you create a cursor at point with gzz
. Start the cursors again with the same key combo, gzt
.
Most commands work with evil-mc but a few commands I commonly use do not:
DEL
(backspace) in insert mode will not be repeated across all cursors in
some modes; andysiw
doesn't work across all cursors in all the modes I tried (though ciw
, for example, does).If the cursors get out of sync undoing a few commands usually sorts things out.
When you've finished with multiple cursors press gzu
to remove them all.
TODO
u
is undo, but this uses the undo-tree
system which is a bit more
complicated that you might be used to.
C-r
and M-_
is redo
C-x u
shows the undo tree.
TODO
gd
or SPC cd
to go to the definition of the symbol at point.
gD
or SPC cD
to list references to the symbol at point.
K
to lookup documentation for the symbol at point. Uses Dash docsets if you
have them installed and the major mode is correctly configured.
TODO
SPC p c
or M-b
to compile (build)
]e
and [e
for next and previous flycheck error, respectively
SPC c x
to list current errors (from flycheck)
gcc
to comment or uncomment the current line or selection;SPC oA
for the Org agenda;SPC x
for a temporary buffer for random notes;M-=
to increase, M--
to
decrease, and M-+
to reset it.I learned most of what I know about Doom by reading through the default keybindings and looking up commands I didn't recognise. It's easy to experiment in a scratch buffer to figure out what a command does.
Learning Doom has been a gradual process for me. I didn't adopt all the above at once! In fact many things I only figured out when I came to write this document.