Creating a Literate Config for Spacemacs
A guide to creating and correctly loading an org-mode file as a literate configuration for Spacemacs
Why create a “literate configuration”?
In a previous post, I explained the concept and origin of literate programming. A literate configuration is simply applying the literate programming concept to configurations files. This is useful for configuration files typically require more context around the settings and why you chose to do something in a particular manner. Sometimes this could include links to where you found the configuration settings or ‘work in progress’ settings. Another reason literate configurations are useful is because configuration files are not necessarily modified every day. When jumping back into your config to fix, add, or modify a feature it might be useful to have a short explanation to quickly catch yourself up.
For this particular post the goal is to create a literate configuration for Spacemacs. It is a heavily modded distribution of Emacs. This is mainly because I use Spacemacs myself and find having a literate configuration for it very useful. Literate configuration itself is an.org
file where the weaved code is defined in code blocks. Using org-mode headings also makes it much easier to navigate your configuration file. Extracting the file code from the literate configuration, or tangling the literate configuration, will yield an elisp
file.
Spacemacs is also well suited for a literate configuration since it by default loads a single .spacemacs
file, which tends to steadily grow as it increasingly takes over your life. At the time of writing this my current 'tangled' spacemacs.el
configuration (just the code) is 1500 lines long.
Correctly loading a Spacemacs literate config
When I was attempting to create a literate Spacemacs config, there were several helpful links to figure out how to tangle and generate output files from an.org
file. I struggled to figure out the best way to load the file itself. There are two default locations for your Spacemacs configurations with the following loading priority:
~/.spacemacs
: A single dotfile in the home directory~/.spacemacs.d/init.el
: A dotfile directory in the home directory
For a literate configuration we will need to have multiple files, therefore I find it more orderly to go with the second option and create a ~/.spacemacs.d
directory.
Initially, it seemed to make sense to create a spacemacs.org
literate configuration file, and tangle directly to either .spacemacs
or init.el
file. It could be done this way, but Spacemacs adds custom content at the end of the init.el
(or ~/.spacemacs
) file in the following function:
This is where Emacs stores custom-set-variables
and custom-set-faces
generated during runtime. If we were to tangle our literate configuration file directly to the init.el
file it would overwrite this function and variables every time it was generated. Therefore, instead the literate configuration can be tangled to an intermediate file, for example spacemacs.el
, and then the init.el
file can load its contents:
spacemacs.org
: The literate configuration filespacemacs.el
: The tangled configuration fileinit.el
: The file that Spacemacs loads as a default configuration file.
An overview of how this works is shown in figure 1.
The ‘spacemacs.org’ file
This is the literate configuration file itself. When creating this you have to ensure every part of your configuration file is copied over in the code snippets. Below is the start of my configuration file. Most of these settings are not particularly important for generating the configuration file, but has served me well thus far.
#+TITLE: Spacemacs Literate User Configuration
#+STARTUP: headlines
#+STARTUP: nohideblocks
#+STARTUP: noindent
#+OPTIONS: toc:4 h:4 #+PROPERTY: header-args:emacs-lisp :comments link
An example of a code block from a part of my configuration below. The important part is the that the configuration is in the code blocks.
What defines the code block:
#+BEGIN_SRC emacs-lisp :tangle spacemacs.el
// Code here //
#+END_SRC
The emacs-lisp
option indicates what language the code block is written in. The:tangle spacemacs.el
sets the output target file to spacemacs.el
when the file is tangled. My complete spacemacs.org
, with all its warts, can be found in my dotfiles repository on github.
The ‘spacemacs.el’ file
In order to generate the tangled file, spacmacs.el
, the function org-bable-tangle()
has to be run on the literate configuration. For this function to be run every time you save the file, the following 'local variables' can be added to the bottom of spacmacs.org
. This will add a function to the after-save-hook
. A hook is a variable that holds a list of functions at a specific time.
* Local Variables :ARCHIVE:
# Local Variables:
# eval: (add-hook 'after-save-hook (lambda ()(org-babel-tangle)) nil t)
# End:
The ‘init.el’ file
This is the file Spacemacs loads as the configuration. You only have to add the following line to the file.
Spacemacs should then load your configuration and you should be up and running! As you continue to use Spacemacs, it will populate the init.el
file:
That’s it!
Now when you change your spacemacs.org
file and tangle the output to spacemacs.el
, it will not overwrite the variables generated by Spacemacs in init.el
. It is not that complicated, but I hope this helps someone fairly new to org-babel
or Spacemacs.
Resources
- Post about Literate Programming: https://olavpe.medium.com/literate-programming-reproducible-research-and-clean-code-docstrings-accf1a9f6661
- Spacemacs: https://www.spacemacs.org
- Emacs: https://www.gnu.org/software/emacs/
- Org-mode: https://orgmode.org
- Spacemacs default loading locations: https://develop.spacemacs.org/doc/QUICK_START.html
- Emacs Hooks: https://www.gnu.org/software/emacs/manual/html_node/emacs/Hooks.html
Originally published at https://www.olavpedersen.com on March 26, 2021.