DEV Community

Victor Dorneanu
Victor Dorneanu

Posted on • Originally published at blog.dornea.nu on

From Doom to Vanilla Emacs

Why vanilla?

Let's start with the most obvious question: What's wrong with Doom Emacs? Short answer: There is nothing wrong with Doom Emacs. I still use it and I still recommend it for beginners. Some years ago I started with Spacemacs and moved to Doom which, in my humble opinion, is far faster and more stable. So if you're a novice and just entered the "church of Emacs" I strongly recommend you do NOT start with vanilla. I recommend Doom because:

  • it comes with batteries included
  • I like how you can exclude packages from your configuration
  • you don't have to get into heavy Elisp
  • there is a whole group of being taking care of bugs and making sure each release works properly

That said, I still wanted to go "vanilla," at least give it a try. My first attempt failed, mainly because I was trying to use someone's config without really understanding how it works. I also had some "hard requirements" for my configuration:

  • evil mode

    I've used vim for more than 10 years and memorized vim like keybindings like my own pocket. Sometimes I find Emacs like keybindings to be more practical, though. That's why I wanted to have both.

  • literate config (using ORG mode)

    I still don't consider myself efficient in writing Elisp code. For this reason, I wanted my configuration to be written in ORG mode (like most of my stuff available online) whose parts can be written (or tangled) to files (e.g. .el files) using org-babel.

  • modular

    I wanted to group similar functionalities in the same ORG file. That's why I have a programming.org file which includes configuration for the programming languages I'm using. At the same time I wanted to easily disable parts of configuration by deleting the corresponding section or commenting it out (org-toggle-comment).

    Of course, Org mode would then have its own file org.org 😎

Go vanilla

If you really decide to continue this journey, I'd like to share some tipps/workflow to make your process more smoothly.

Ever since I've started my Emacs journey it seemed like the wholy grail to have your own (vanilla!) configuration without any hard dependencies on frameworks like Doom or Spacemacs. There are plenty of dotemacs configurations ouf there which can serve as a great source of inspiration.

In my case, it was specifically this one which caught my attention: https://config.phundrak.com/emacs/. It had almost everything I needed, it was using evil mode and the whole configuration is written in ORG mode. Bingo!

Literate config

As a matter of preference I don't like Elisp based Emacs configurations. I find ORG mode and literate config to be more easy to read and understand what's going on.

You can have a basic structure in your ORG mode file, define sections, and use the outline functionality to jump to each section. You can then tangle the ORG file to generate the .el files to be loaded by Emacs. Having spent countless hours (and days) tweaking my configuration, reading others and trying to understand custom Elisp functions, I think I've reached a level where I exactly know which part of my config is responsible for some misbehavior. Other than that, I've found a structure that fits my needs and the way I want my configuration to be structured.

Basic structure

Your configuration should have a basic structure. You can either use a single file for the whole configuration or multiple ones. I prefer multiple ones because you can tangle each one individually and thus make the whole process faster. This is what I have inside my Emacs folder in my dotfiles:

emacs
├── basic-config.org
├── custom-elisp.org
├── index.org
├── keybinding-managers.org
├── keybindings.org
├── Makefile
├── package-manager.org
├── packages
│   ├── applications.org
│   ├── autocompletion.org
│   ├── editing.org
│   ├── helpful.org
│   ├── org.org
│   ├── programming.org
│   └── visual-config.org
└── tangle_script.sh
Enter fullscreen mode Exit fullscreen mode

Basic structure of my Emacs configuration files

This structure is more or less copied from Phundrak's one which served as a really good starting point. Of course I stripped down each file to my needs.

The point is that each file would host a different set of customizations relevant to specific functionalities. If I want to change some keybindings I'd then go to keybindings.org and modify stuff. If I want to tweak the autocompletion for lsp-mode I'd then go to autocompletion.org.

Tangling

In Emacs and Org mode, tangling refers to the process of extracting code snippets from an ORG file and writing them to separate source code files. It usually allows you to maintain code and documentation in the same file while keeping them in sync. In my case I use it to generate Elisp code out of my ORG files.

image

👉 My ORG mode config

Automation

I like to automate most of the workflows and therefore I use a Makefile and some bash script for tangling all files:

# Phony target to tangle all org files
.PHONY: tangle
tangle:
    find . -name "*.org" -exec sh -c 'echo "[!] Tangling {}"; ./tangle_script.sh "{}"' \;
Enter fullscreen mode Exit fullscreen mode

Makefile for my Emacs configuration

And this is the script I use to tangle one individual file:

#!/bin/bash

emacs -q --batch --eval "(require 'ob-tangle)" \
  --eval "(setq org-confirm-babel-evaluate nil)" \
  --eval "(org-babel-tangle-file \"$1\")"
Enter fullscreen mode Exit fullscreen mode

The tangle script which takes an ORG file as an argument

Manually

I would like my overall configuration (at ~/.config/emacs) to be updated immediately whenever I change something in the Org mode files. Therefore I use .dir-locals.el to define this behaviour for all ORG mode files

;;; Directory Local Variables            -*- no-byte-compile: t -*-
;;; For more information see (info "(emacs) Directory Variables")

((org-mode . ((org-confirm-babel-evaluate . nil)
              (eval .
                    (progn
                      ;; Tangle whole file after being saved
                      (add-hook 'after-save-hook 'org-babel-tangle)
                      )))))

Enter fullscreen mode Exit fullscreen mode

.dir-locals.el

First I don't want to be asked every time if I want to evaluate the source code blocks (that's why org-confirm-babel-evaluate is set to nil ). Secondly I want to automatically tangle the file whenever the file gets saved (org-babel-tangle in the after-save-hook).

This way every time I save one file, the Elisp code will be automatically be tangled to the corresponding file.

Inspirations

Sometimes I don't know exactly how to configure a package or which options I should be using. Instead of searching the web for the examples last year I came up with an idea: I started collecting interesting/useful dotfiles~/~dotemacs collections in a single place. You can find the repository at github.com/dorneanu/dotemacs. So what I usually do is to search inside the folder where I've cloned all repositories for specific keywords. For this purpose I use rg.el and some custom function:

(setq dotemacs-directory "/cs/priv/repos/dotemacs")
(rg-define-search my/rg-dotemacs
  :query ask
  :format regexp
  :files "everything"
  :dir dotemacs-directory
  :confirm prefix)
Enter fullscreen mode Exit fullscreen mode

From the rg section in my dotemacs config

image

👉 Searching with rg

Conclusion

Checkout my dotfiles (which I manage using chezmoi) if you need some inspiration. If you have other tips on how to further improve my workflow or the overall structure, please drop me an email.

Top comments (0)