Literate Emacs Init with Org Babel
Over the past few years, my emacs init files have gotten a bit out of hand. My once-cleanly-categorized files have started to blend together, and there’s a fair amount of dead code, as I’ve made many significant changes to my emacs tools (e.g. I’ve switched static analyzers and terminals basically each year).
Org-mode is a great way to mix inline code with general writing (and it’s what this website is built with), so it’s a natural fit for managing and documenting my init files as well. The basic idea is to write all init code inside an org file, where the lisp code to be executed is inlined inside code blocks like so:
* Here's a category heading Description of below code here #+BEGIN_SRC emacs-lisp (some-lisp-code) #+END_SRC emacs-lisp More description for more code here #+BEGIN_SRC emacs-lisp (some-more-lisp-code) #+END_SRC
Org-mode’s Babel can then parse these files and extract the code blocks out into a nice clean source file for emacs to read natively. This process is called “tangling”, and it has some runtime cost, but only needs to be run after file changes.
To get started with this conversion, I simply wrapped all of my lisp code inside a giant src block inside a new
config.org file. Then, I simply set
(org-babel-load-file "~/emacs/config.org") in
.emacs. With this done, it’s been fairly straightforward to break my init code into more manageable chunks, as having everything back together in a single file makes it easier to get a high-level view of how things are organized, and also discover plenty of old and unused code.
With my config now being in org-mode, it renders nicely on github, making it easy to reference, which also forces me to keep things well-documented and organized.
The other major change I’ve made is a transition from the built-in
straight.el, though I’m still using
use-package as a front-end. Straight.el already has a great list of pros/cons of why to use it, but for me the chief benefit is reproducibility, and reducing conflicts when I sync my config across machines. There’s also a nice feeling of cleanliness, where all the packaging infrastructure is now basically git, instead of the somewhat opaque MELPA installation process.