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 Babel

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
    #+END_SRC emacs-lisp
    More description for more code here
    #+BEGIN_SRC emacs-lisp

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 file. Then, I simply set (org-babel-load-file "~/emacs/") 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.

Literate Config

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 package.el to 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.