JDs Work

A blog about technology, careers, and personal growth.

Literate Org Configs

December 28, 2020
Category: 
Development

Org mode is one of the greatest things Emacs has to offer. With a vibrant ecosystem of packages and a large number of resources available it's easy to do just about anything with org mode.

Org-babel-tangle

A great feature of org-mode comes in a package called org-babel. This is a language parser allowing you to write source code blocks and even executing them inline.

#+begin_src ruby  <-- Org Source Block begin & lang declaration
def hello
  return 'Hello, World'
end

hello
#+end_src

#+RESULTS:  <-- Resulting Execution with `C-c C-c`
: Hello, World

This is essentially a repl. You can import whatever you need to and execute/output everything that's necessary. Things don't stop there.

Org, being a powerful markup language, allows you to write source blocks and document them, similar to how markdown looks. The payoff comes when you use org-babel-tangle. This package gets an org file, cuts out all the markup, except source code blocks, and outputs the blocks into a file of your choosing. This means you can neatly markup any files and tangle them out into another file that only consists of your source code.

Example

In my .doom.d directory, I have a Kitty.org file to manage my Kitty Terminal configuration. This is what it looks like:

#+TITLE: Kitty Config
#+PROPERTY: header-args :tangle ~/.config/kitty/kitty.conf

* Colorscheme
Based on: [[https://gist.github.com/marcusramberg/64010234c95a93d953e8c79fdaf94192][This gist]] & [[https://github.com/arcticicestudio/nord-hyper][Nord Color Scheme]]

#+begin_src shell
foreground            #D8DEE9
background            #2E3440
selection_foreground  #000000
selection_background  #FFFACD
url_color             #0087BD
cursor                #81A1C1

color0   #3B4252
color8   #4C566A

color1   #BF616A
color9   #BF616A

color2   #A3BE8C
color10  #A3BE8C

color3   #EBCB8B
color11  #EBCB8B

color4  #81A1C1
color12 #81A1C1

color5   #B48EAD
color13  #B48EAD

color6   #88C0D0
color14  #8FBCBB

color7   #E5E9F0
color15  #ECEFF4
#+end_src

* The worst
#+begin_src shell
enable_audio_bell no
#+end_src

* Fonts
Use JetBrainsMono like everything else.

#+begin_src shell
font_family      JetBrainsMono-Regular
bold_font        JetBrainsMono-Bold
italic_font      JetBrainsMono-MediumItalic
bold_italic_font JetBrainsMono-BoldItalic

font_size 13.0
#+end_src

* Visual
A few small visual changes to satisfy my OCD.

#+begin_src shell
hide_window_decorations yes
window_padding_width 1.0
#+end_src

* Tabs
Basic tab commands to be more like Chrome/Doom-Emacs
#+begin_src shell
tab_bar_style powerline
map cmd+1 goto_tab 1
map cmd+2 goto_tab 2
map cmd+3 goto_tab 3
map cmd+4 goto_tab 4
map cmd+5 goto_tab 5
map cmd+6 goto_tab 6
map cmd+7 goto_tab 7
map cmd+8 goto_tab 8
map cmd+9 goto_tab 9

active_tab_foreground   #D8DEE9
active_tab_background   #5E81AC
active_tab_font_style   bold
inactive_tab_foreground #ECEFF4
inactive_tab_background #3B4252
inactive_tab_font_style normal
#+end_src

With that as my .org file I just need to run org-babel-tangle with M-x or C-c C-v t and it will strip out my comments and headings and just output a normal conf file like so:

foreground            #D8DEE9
background            #2E3440
selection_foreground  #000000
selection_background  #FFFACD
url_color             #0087BD
cursor                #81A1C1

color0   #3B4252
color8   #4C566A

color1   #BF616A
color9   #BF616A

color2   #A3BE8C
color10  #A3BE8C

color3   #EBCB8B
color11  #EBCB8B

color4  #81A1C1
color12 #81A1C1

color5   #B48EAD
color13  #B48EAD

color6   #88C0D0
color14  #8FBCBB

color7   #E5E9F0
color15  #ECEFF4

enable_audio_bell no

font_family      JetBrainsMono-Regular
bold_font        JetBrainsMono-Bold
italic_font      JetBrainsMono-MediumItalic
bold_italic_font JetBrainsMono-BoldItalic

font_size 13.0

hide_window_decorations yes
window_padding_width 1.0

tab_bar_style powerline
map cmd+1 goto_tab 1
map cmd+2 goto_tab 2
map cmd+3 goto_tab 3
map cmd+4 goto_tab 4
map cmd+5 goto_tab 5
map cmd+6 goto_tab 6
map cmd+7 goto_tab 7
map cmd+8 goto_tab 8
map cmd+9 goto_tab 9

active_tab_foreground   #D8DEE9
active_tab_background   #5E81AC
active_tab_font_style   bold
inactive_tab_foreground #ECEFF4
inactive_tab_background #3B4252
inactive_tab_font_style normal

As you can see all my comments in the org configuration are gone and now just the "code" is here.

This has a few key implications for dotfiles in general:

  • All dotfiles could be tangled this way making manging your dotfiles a breeze. Not having to deal with symlinks, tools, or worse, manual imports and loading
  • You can document you code fairly consistently, and with GH support for Org markup it's even easier to document your configs so you always remember what the one function does in your .zshrc file.
  • Your dotfiles will be dependent on Emacs but the code is always there. If for whatever reason you can't use Emacs to put your dotfiles in place you can always just copy the source blocks manually :)

The Emacs community has popularized this technique and has aptly called it "literate configuration" which is a suitable name. I'm currently in the process of converting all my dotfiles into a simple repo of org files this way and I couldn't be more excited to actually have organized dotfiles.