Personal Emacs config. Targets Emacs 30+, leans on built-ins, adds a small set of third-party packages where the built-in story is still thin.
This README is the cheat sheet I want when I come back to Emacs after a few months away. It documents what's wired up, the key bindings I actually use, and how to relearn the fancy bits (completion, LSP, etc.).
Required:
- Emacs 30 or newer.
gpgon PATH.init.elerrors out early without it because GNU ELPA signatures cannot be verified otherwise.brew install gnupgon macOS.
Recommended:
- JetBrainsMono Nerd Font.
Default frame font is
JetBrainsMono Nerd Font-16:weight=thin. ripgrepforconsult-ripgrep(C-c r).brew install ripgrep.goplsif you edit Go.brew install goplsorgo install golang.org/x/tools/gopls@latest.multimarkdownformarkdown-modepreview.brew install multimarkdown.
init.el single-file config, organized by ;;;; section headings
custom.el auto-managed by Customize; kept separate from init.el
savefile/ persistent state: desktop, save-place, savehist
elpa/ installed packages (gitignored)
eln-cache/ native-compilation cache (gitignored)
To navigate init.el, use M-g i (consult-imenu): the ;;;;
headings show up as a "Sections" group.
The modern minibuffer trio plus consult:
| Package | Role |
|---|---|
vertico |
Vertical list UI for any completing-read call. |
orderless |
Match by space-separated fragments, any order, any position. |
marginalia |
Right-aligned annotations (docstrings, file size, modes ...). |
consult |
Power commands that feed into completing-read. |
How it feels in practice. C-x b (consult-buffer) opens a vertical list
of buffers, recent files, and bookmarks. Type init el and orderless
matches both fragments anywhere in the candidate. marginalia shows the
buffer's major mode and file path next to each entry. RET selects;
C-n / C-p move; M-. previews. No need to type a prefix.
Bindings I use:
| Keys | Command | What it does |
|---|---|---|
C-x b |
consult-buffer |
Buffer/file/bookmark switcher. |
C-c l |
consult-line |
Fuzzy in-buffer line search. |
M-y |
consult-yank-pop |
Browse kill ring. |
M-g g |
consult-goto-line |
Jump to line N. |
M-g i |
consult-imenu |
Jump to function/section in buffer. |
C-c r |
consult-ripgrep |
Project-wide regex search via rg. |
C-x C-f |
find-file |
File picker, now vertico-powered. |
M-x |
execute-extended-command |
Command picker, vertico-powered. |
Tip: inside any vertico prompt, M-. previews the candidate without
selecting it. C-c C-c (or M-RET, depending on context) accepts the
literal input instead of the highlighted candidate.
paredit-modeinemacs-lisp-modeand duringeval-expression. Keeps parens balanced.C-)slurps the next sexp,C-(slurps the previous,M-ssplices,M-(wraps.rainbow-delimiters-modein allprog-modebuffers. Colours nested parens by depth.company-modeglobally for in-buffer completion popups.M-/forhippie-expand(dabbrev plus filename plus lisp symbol completion).completion-preview-modeinprog-mode. Shows a greyed-out inline suggestion.TABaccepts.delete-selection-mode: type over a region to replace it.
eglot for Go, via gopls. Diagnostics flow into flymake, hover
docs into eldoc, completion into completion-at-point (which
company-capf picks up).
M-. jumps to definition, M-, jumps back, M-? finds references,
M-x eglot-rename renames across the project, C-h . shows eldoc at point.
To add another language: install its language server, then add a hook like
(add-hook 'python-mode-hook #'eglot-ensure).
Three layers, all writing into savefile/:
desktop-save-mode: which files are open, point/window/mode metadata, reopened on next launch. Dired buffers and large/log/archive files are excluded. TRAMP paths excluded.save-place-mode: point position remembered per file.savehist-mode: minibuffer history (commands, search rings, etc.) persisted across sessions.
auto-save-visited-mode is also on: real saves every 30 seconds for
visited files. If that is too eager, tune auto-save-visited-interval.
which-key-mode: after a prefix likeC-x, a popup shows the next-key options.repeat-mode: chord-free repeat of common sequences. AfterC-x o, hitoto keep cycling windows.marginaliaannotations makeM-xself-documenting: hover any command withC-nand see its docstring summary.
- Theme:
tango-dark.solarized-themeis installed but not loaded;M-x load-theme RET solarized-darkto try it. - Font: JetBrainsMono Nerd Font, thin weight, 16pt. Adjust in
default-frame-alistnear the bottom ofinit.el. - Ligatures via
ligature.elinprog-mode. The font advertises which sequences to compose; the configured list is a superset covering Fira Code / JetBrainsMono / Cascadia. pixel-scroll-precision-modefor smooth GUI scrolling.show-paren-modewithshow-paren-context-when-offscreen: if the matching paren is off-screen, it shows in the echo area.
magitonC-x g.ibufferreplacesbuffer-menuonC-x C-b.M-RETtoggles fullscreen on macOS GUI frames.s-=/s--/s-0for text scale up / down / reset.exec-path-from-shellon macOS so GUI Emacs inherits shell PATH.global-auto-revert-mode: buffers reload when the file changes on disk.use-short-answers:y/ninstead ofyes/no.
If it has been a while:
- Open Emacs. Wait for
package-refresh-contentsand any installs. - Read this file.
C-x C-f ~/.emacs.d/README.md RET. - Tour
init.elby section:C-x C-f ~/.emacs.d/init.el RETthenM-g iand pick a section. - Run
M-x consult-buffer. Type a few characters. Notice the vertical list, the annotations, the fuzzy matching. That is the new normal. C-h k(describe-key) then any keystroke shows what it is bound to.C-h f(describe-function) for any command name.C-h vfor any variable. These three are the entire Emacs help system.M-xand start typing. With orderless, you do not need prefixes:buf listfindslist-buffers.
Modern Emacs rewards a few targeted reads:
- Built-in tutorial:
C-h t. Still the best 30 minutes you can spend. - Vertico/Orderless/Marginalia/Consult: see each package's README on GitHub. The Consult README in particular is a tour of useful commands worth skimming end to end.
- Eglot:
M-x eglotto start it in a buffer, thenC-h v eglot-mode-mapto see the keymap. - Magit:
C-x g, then?shows transient menus for every operation. - Paredit:
M-x paredit-cheatsheetand theparedit.elcommentary at the top of the source.
- Add a package: another
use-packageblock under a;;;;section. - Change a setting:
setoptfor customizable variables (so the type is checked),setqfor plain ones. Seefeedback_prefer_builtinsin my Claude memory for the modernization rules. - After editing
init.el:M-x eval-buffer, or restart Emacs. custom.elis auto-managed. Do not hand-edit. Things you set viaM-x customizeland there.
- "gpg not found" on startup: install GnuPG, restart.
- Packages fail to install with signature errors: delete
elpa/gnupg/and restart. The bootstrap ininit.elre-imports the bundled keyring. - Native compilation warnings pile up: silenced by default. Look in
*Native-compile-Log*if curious. - Desktop refuses to load:
rm savefile/.emacs.desktop.lockif a stale lock survived a crash.