A handbook for the Doom Emacs initiate
AKA: how to use Doom Emacs as my main text editor for note-taking and software development.
But what is Doom Emacs ?
An Emacs framework for the stubborn martian hacker
The TL;DR is that Doom Emacs offers sane defaults for most stuff, and uses SPACE
as your leader key.
The killer feature for me is using the beautifully lisp-y Emacs ecosystem of packages together with the insanely practical vim keybindings (if you like being evil ).
NOTE: Everything I write is tested against my own config, which you can find in my dotfiles repo: https://github.com/vvzen/dotfiles
For more info on Doom Emacs itself, have a look at https://github.com/doomemacs/doomemacs
Buffer and File Navigation
SPACE + .
-> Find a file to open in a new buffer
This^ uses dired, so you will be able to fuzzy match, etc.
-
SPACE + SPACE
-> Find a file in the current project (also uses fuzzy find, but leverages projectile) -
CTRL + x + d
-> Edit thedired
directory for the current buffer (and more) -
SPACE + b + i
-> Open a buffer listing all buffers (via ibuffer)
SPACE + b + p
-> Go to the previous bufferSPACE + b + n
-> Go to the next bufferSPACE + b + k
-> Kill the current buffer
Git
SPACE + g + g
-> Open the Magit buffer
I haven't moved to use magit fully, I still do some stuff just using git
in a terminal, since that feels more natural.
What I have been using so far is:
SPACE + g + g + c + c
-> Create a commitSPACE + g + g + c + w
-> Reword a commitSPACE + g + g + c + a
-> Amend a commit
Then, for navigation purposes:
[ + d
-> Go to previous diff hunk] + d
-> Go to next diff hunk
Search
/
-> Search in the current buffer (evil)SPACE + /
-> Search in current project (via projectile mode)SPACE + s + s
-> Conduct a text search in the current buffer (uses fuzzy match)
Windows
SPACE + w + v
-> Create a vertical split of the current bufferSPACE + w + s
-> Create a horizontal split of the current bufferSPACE + w + h
-> Focus on the window on the leftSPACE + w + l
-> Focus on the window on the rightSPACE + w + k
-> Focus on the window on the topSPACE + w + j
-> Focus on the window on the bottomSPACE + w + q
-> Close the current window split
Note: this^ will not close the buffer itself.
Text manipulation
Search and replace
Thanks to evil mode, when in normal mode, you can do similar things to what you'd do in vim, for example
s/search/replace
-> Search and replace current line:%s/search/replace
-> Global search/replace inside current buffer
Another way is also:
SPACE + replace-string
-> To replace a string within your visual selection.
To perform search and replace across multiple files, you can do the following:
SPACE + find-name-dired
to fuzzy match the files you want to work ont
to select everything from the fuzzy matchQ
to enter regex query replace modeSPACE
to confirm each replace- Finally,
SPACE + save-some-buffers
to save the modified buffers
Characters pairs
The perform a transformation like thing
-> 'thing'
, you can:
- Go in visual mode
- Press
S
(evil-surround-region) - Press
'
The same workflow can be applied for a few other 'pair' characters like ()
, {}
, []
, <>
, etc.
Multiple cursors
It feels a bit clunky compared to what helix offers natively, but you can use evil
for some simple multiple cursor operations.
For example, go to visual mode, select some lines, then type g + z + I
to enter insert mode over those lines.
Indentation
SHIFT + .
-> IndentSHIFT + ,
-> Dedent
LSP
SPACE + c + j
-> Consult symbolsg + d
-> Go to definitiong + D
-> List all referencesSPACE + s + S
-> Search buffer for symbol at point[ + g + f
-> Go to previous function declaration] + g + f
-> Go to next function declaration[ + g + F
-> Go to previous function call] + g + F
-> Go to next function call
I also have SPACE + r
mapped to lsp-rename
, which lets me quickly rename the symbol under the cursor:
(map! :leader
"r" #'lsp-rename)
Workspaces
A workspace is just series of buffers shown together at one point in time. They way I use workspaces is to logically group together buffers and vterm buffers that are related to the same project.
SPACE + TAB + n
-> Create a new workspaceSPACE + TAB + r
-> Rename workspaceSPACE + TAB + 1
-> Switch to workspace 1 (and so on)SPACE + q + s
-> Save all workspacesSPACE + q + l
-> Load last saved workspace
Terminal
I just use vterm (see https://docs.doomemacs.org/v21.12/modules/term/vterm).
SPACE + vterm
-> Create a new terminal emulator bufferSPACE + o + T
-> Open Terminal in current buffer, using current dired location
The integration with evil is a bit funky sometimes, which is why I have a d + n + e
(Do No Evil) shortcut to temporarily disable evil mode. That's particularly useful if you somehow enter vim from vterm and wonder why you can't exit..
(map! :leader
"d n e" #'turn-off-evil-mode)
Despite its rough edges, being able to use vim-like movements in my terminal (and to use visual mode too!) is a life changing experience. Selecting and copying text is faster, and I can still use escape sequences generated by CTRL+a and CTRL+e (and so on) once my shell prompt is configured for it, which basically means I get the best of both worlds!
Org mode
I was already a note-taking freak before learning about ORG mode in Emacs. I take daily notes of everything that I do at work, and I started just with plain text notes written in the TextEdit app in macOS, then I moved to just write markdown notes with my editor (helix, at the time) . Now I am a ORG-mode freak.
There's several tiny things that I like about ORG mode, so far:
- Literate programming (executable code blocks within my notes using
#+begin_src
and#+end_src
). For example:
#+begin_src
(defun something ()
(interactive)
(message "Hello world"))
(something)
#+end_src
#+RESULTS:
: Hello world
- Ability to maximize/minimize a bullet point via Tab
- This is incredibly useful if, like me, you tend to add a lot of tiny snippets into a single item
- Check-boxes with syntax highlighting (so that list entries that start with
[X]
get grayed out) - TODOs with syntax highlighting
- Tables that auto-align by pressing tab
Evil mode
Evil mode is an emulation of the vim keybindings. Here's a few things that I use daily..
Moving around
- k,j -> Move up, down a line
- h,l -> Left, Right a character
- w -> Move forward to next word
- b -> Move backward to next word
- gg -> Move cursor at the beginning of the file
- G -> Move cursor at the end of the file
- H -> Move cursor to the top of the screen
- M -> Move cursor to the middle of the screen
- L -> Move cursor to the bottom of the screen
- f +
char
-> Move to next occurrence ofchar
(from there, type;
to keep moving across occurrences)
Custom ones:
- gh -> Move to beginning of visual line
- gl -> Move to end of visual line
;;; Evil start of line
(map! :n
"g h" #'evil-beginning-of-visual-line)
;;; Evil end of line
;;; NOTE: 'g l' is already mapped natively to something else, so this overrides it
(map! :after evil
:nv
"g l" #'evil-end-of-visual-line)
Editing (in normal mode)
- x -> Delete character under the cursor
- yy -> Yank current line to clipboard
- dd -> Delete whole line and yank it
- dw -> Delete across Word boundary
- d$ -> Delete from cursor until end of line