Even if you've never heard of our lord and savior™ Nix, I'll try to make this as understandable as possible for non-Nix users.

A bit of context

Emacs is a very good OS, but lacks a text editor. One of its most interesting features if that it's a Lisp interpreter where you can evaluate code at runtime to (for instance) change its configuration. This makes it highly customizable and adaptable.

I don't use vanilla Emacs but instead, a distribution called Doom emacs that provides some nice defaults which I like. Plus it offered defaults to things I didn't how to configure when I began using Emacs and that I've grown to be quite familiar with.

Whenever you want to modify your configuration, you usually do it the following way :

  1. Editing files in ~/.doom.d/
  2. reloading the configuration (SPC h r r) which calls the doom/reload function.

How you install / manage doom emacs

To install / update doom :

  1. You clone the upstream git repository in ~/.emacs.d
  2. You install it

Whenever you want to update it, you git pull and then install again. This is nice but it means that we may (and will) have different versions across different machines.

What about Nix ?

Nix is akin to an all-consuming creature of agar.io striving to engulf everything in on order to achieve repeatability (and sometimes reproducible) environments.

Another noteworthy project is the Nix-doom-emacs project which makes easy to integrate an existing Doom Emacs configuration to a Nix system. configuration to your Nix repository easier. But you lose the ability to reload your configuration on-the-fly which is very disheartening. This makes an almost instantaneous configuration into a (currently) 31s time to get my configuration installed. Not so great.

How can we fix this ?

First, we want to pin the configuration so that we have a repeatable setup.

To do this we use Home-manager's ability to symlinks derivations (Nix packages) which can be created out of git repositories. Since they are pinned on a commit, we get free repeatable setup! … Right ?

home.file.".emacs.d".source = pkgs.fetchFromGitHub {
  owner = "doomemacs";
  repo = "doomemacs";
  rev = "99c6949e5464746a232cbe619b359d1fa05ed8fe";
  hash = "sha256-gPhsBTNaCXgfHylbmi3g4oqxUYZ1XEuGo6CD6RapUms=";
};

Not so quickly, ~/.emacs.d by default is expected to writable, but since this symlinks on the Nix store which is read-only, this will fail with cryptic errors.

Additionally, if you're using a recent version of Emacs that utilizes bytecode compilation, you'll encounter this issue because Emacs requires a directory to write the bytecode files.

To address that we can instruct Doom to use other directories to write things in.

The following code achieves this :

systemd.user.sessionVariables = {
  DOOMLOCALDIR = "$HOME/.local/share/doomemacs";
  DOOMPROFILELOADFILE = "$HOME/.local/share/doomemacs/profiles/load.el";
}

This sets session variables to direct Emacs to use the different (writable) directories.

Note that you may need to relog-in to have those variables set correctly. Alternatively, you can declare those in your .bashrc or similar but I find this approach to be somewhat inelegant.

That's all for today!

Nota bene

The variable for vanilla emacs seems to be user-emacs-directory but I haven't investigated it further.