3 Tips and tricks

We now look at some useful tips that will make your life easier when writing literate config files.

Converting your existing config files

You probably already have a number of long and complex config files. The beauty of literate config is that you don’t have to do a lot of work to start using it. As a first step, you can simply include your whole file into a single source block. For example, if you already have a /.profile file, you can create /.profile.org with the following:

* My Bash config

#+begin_src bash :tangle ~/.profile
<contents of your existing .profile file>
#+end_src

You can then start breaking it up in logical blocks, adding commentary and other structure as you see fit. For this, you may find useful the org-babel-demarcate-block command, bound by default to C-c C-v C-d. When invoked within a source block, this command splits the block at that point, creating two source blocks with the same language and any other header arguments as the original one.

Using noweb references to structure your code

Exporting source blocks in the sequence in which they appear in the Org file is useful, but ultimately little more than extensively documenting your file with comments. The real power of literate programming comes from being able to express the logic of your code in a way that makes sense to a human reading it. This does not necessarily match the order or structure in which the code needs to be read by the computer.

This is possible in Org by using noweb references, so called because they follow the same convention introduced by the early noweb literate programming tool. In this convention, a code block can have an arbitrary name, and be referenced (included) in other blocks by specifying its name inside double angle brackets: <<code block name>>.

Processing of noweb references is enabled by the :noweb header argument in source blocks. This argument can have multiple values, but I have found the following to be the most useful:

  • :noweb yes enables Noweb processing in the block, both for tangling and for exporting (i.e. when you export the code block to HTML, LaTeX or some other format, the noweb references will be expanded as well);
  • :noweb no-export enables Noweb processing in the block when tangling, but not when exporting. This is useful for leaving the noweb indicators in the human-readable exports of your file, which can make it easier to understand.

The name of an individual code block can be specified with the :noweb-ref header argument. If multiple blocks have the same :noweb-ref value, they will be concatenated when referenced. You can also specify the name of a block using a #+name: property line before the source block, but in this case there can be only one block with the given name.

Consider the following org code:

Literate config with noweb references
Prepend some paths to the previous value.

#+begin_src bash :tangle ~/.profile :noweb no-export
export PATH=<<Personal paths>>:<<Homebrew paths>>:$PATH
#+end_src

These are the paths in which I store my personal scripts and binaries:

#+begin_src bash :noweb-ref Personal paths
~/bin
#+end_src

These are the directories in which Homebrew binaries are installed:

#+begin_src bash :noweb-ref Homebrew paths
/usr/local/bin:/usr/local/sbin:/usr/local/opt/coreutils/libexec/gnubin
#+end_src

Here we can see that the first block references the two other by their names, and they get combined to produce the final tangled output. This is of course a very simple example, but in complex config files, this technique can make it much easier to see the overall structure of the code before delving in the details. For a more realistic example, see the Org mode section of my Emacs config. Here you can see a top-level block as follows:

(use-package org
  :pin manual
  :load-path ("lisp/org-mode/lisp" "lisp/org-mode/lisp/contrib/lisp")
  :bind
    <<org-mode-keybindings>>
  :custom
    <<org-mode-custom-vars>>
  :custom-face
    <<org-mode-faces>>
  :hook
    <<org-mode-hooks>>
  :config
    <<org-mode-config>>)

The different noweb references get “filled in” throughout the rest of the configuration by assigning them to the corresponding :noweb-ref values. This makes it possible to specify keybindings, variables, faces, hooks and custom config code in the sections where it makes logical sense, rather than where they need to be included in the code.

Multiple config files per org file

Most Literate Config Org-mode files will probably generate a single config file. However, as illustrated in How it works, you can easily produce multiple config files from a single org file. For this, you can use one of the following techniques:

  • Manually specify the file to which each source block should be tangled, using the :tangle header argument to specify it;
  • Specify a main tangle target globally, as described in Structure of a literate config file, and specify the :tangle argument for the blocks that should be written to a different file;
  • If the different files are produced from within different sections of the Org document, you can specify the :tangle argument per section, by specifying it within a :PROPERTIES drawer of the corresponding headline. For example, in the following source, each section gets tangled to a different output file:
  * Bash .profile
    :PROPERTIES:
    :header-args:bash: :tangle ~/.profile
    :END:

  #+begin_src bash
    this code goes to ~/.profile
  #+end_src

  * Bash .bashrc
    :PROPERTIES:
    :header-args:bash: :tangle ~/.bashrc
    :END:

  #+begin_src bash
    this code goes to ~/.bashrc
  #+end_src