marienz / nix-doom-emacs-unstraightened

Builds Doom Emacs using Nix
Apache License 2.0
27 stars 1 forks source link

nix-doom-emacs-unstraightened

nix-doom-emacs-unstraightened (referred to as "Unstraightened" below) builds Doom Emacs using Nix bundling a user configuration directory and the dependencies specified by it. It is very similar to nix-doom-emacs, but is implemented differently.

Status

CI

Tested and working on Linux, with emacs-overlay and Doom inputs updated automatically. If you're reading this on Github, there should be a CI status badge above: if CI is passing, Unstraightened installs an up-to-date version of Doom Emacs and (almost) all module dependencies.

Not yet tested on macOS. Likely works as long as you do not need an "app" (you launch Emacs from the commandline or through other means). I intend to fix this.

You may encounter "Cannot find Git revision" errors on Nix versions newer than 2.18.x (see #14). Try enabling experimentalFetchTree to work around this (see below).

Please report any issues.

How to use

Test run

  1. Check out this repository
  2. Optional: run nix flake update nixpkgs (Nix 2.19 or up) or nix flake lock --update-input nixpkgs (earlier versions). If nixpkgs is in the system registry (which it is by default on NixOS 24.05 and up) this will make Unstraightened reuse more dependencies already on your system.

[!NOTE] Updating other inputs (with nix flake update) is not recommended. These inputs are automatically updated daily as long as tests pass. Updating manually may update to an incompatible version of Doom or Emacs packages.

  1. Copy your Doom configuration into doomdir (overwriting what's there)
  2. Make sure all files are added (git add doomdir)
  3. Run nix run .#doom-emacs.

If this does not work, the "with flakes" setup below is unlikely to work either. Please file an issue.

With flakes

Add this flake as an input in flake.nix:

inputs = {
  nix-doom-emacs-unstraightened.url = "github:marienz/nix-doom-emacs-unstraightened";
  # Optional, to download less. Neither the module nor the overlay uses this input.
  nix-doom-emacs-unstraightened.inputs.nixpkgs.follows = "";
};

If your Doom configuration lives in a different repository, add that as input too:

inputs = {
  doom-config.url = "...";
  doom-config.flake = false;
};

Home Manager

If you use Home Manager, add Unstraightened's home-manager module in flake.nix:

outputs = inputs @ { nixpkgs, home-manager, ... }: {
  homeConfigurations."username" = home-manager.lib.homeManagerConfiguration {
    modules = [
      inputs.nix-doom-emacs-unstraightened.hmModule
      ./home.nix
    ];
    extraSpecialArgs = { inherit inputs; };
  };
};

Configure it in home.nix:

  programs.doom-emacs = {
    enable = true;
    doomDir = inputs.doom-config;  # or e.g. `./doom.d` for a local configuration
  };

There are a few other configurable options, see below.

If you set services.emacs.enable = true, that will run Unstraightened as well (Unstraightened sets itself as services.emacs.package). Set programs.doom-emacs.provideEmacs = false or override services.emacs.package if you want a vanilla Emacs daemon instead.

[!WARNING] Using the overlay described below with programs.emacs.package will not work correctly (see [HACKING.md] for details).

Overlay

If you don't use Home Manager or prefer not to use Unstraightened's Home Manager module, add Unstraightened's overlay. Typically that means adding:

nixpkgs.overlays = [ inputs.nix-doom-emacs-unstraightened.overlays.default ];

to a home-manager or NixOS module.

The overlay adds two packages:

Without flakes

This is currently not explicitly supported, but should be possible (use pkgs.callPackages ./nix-doom-emacs-unstraightened). PRs extending this part of the documentation are welcome, as are (within reason) changes necessary to support use without flakes.

Options

doomEmacs and emacsWithDoom support the following options:

[!NOTE] This supports ~ expansion but does not support shell variable expansion. Using $XDG_DATA_HOME will not work.

[!NOTE] Because Unstraightened uses Doom's profile system, using the same value you used with vanilla Doom will not result in Unstraightened finding your files. See below.

There are a few other settings but they are not typically useful. See the source.

The home-manager module supports the same options, as well as:

Comparison to "normal" Doom Emacs

Comparison to nix-doom-emacs

Bugs

Do not report bugs upstream. If you think it's a bug in Doom, reproduce it without Unstraightened first, or report it here first.

There are a few known current bugs and likely future bugs in Unstraightened:

Pins can break

The way Unstraightened applies Doom's pins to Nix instead of straight.el build recipes is a hack. Although it seems to work fairly well (better than I expected), it will break at times.

If it breaks, it should break at build time, but I do not know all failure modes to expect yet.

One likely failure mode is an error about Git commits not being present in the upstream repository. To fix this, try building against a revision of the emacs-overlay flake that is closer to the age of doomemacs. This is a fundamental limitation: Doom assumes its pins are applied to straight.el build recipes, while we use nixpkgs / emacs-overlay. If these diverge, our build breaks.

Another possible problem is a package failing to build or run because one of its dependencies is missing. Unstraightened currently uses dependencies from the original (emacs-overlay) package. This is largely a performance optimization, that can be revisited if it breaks too frequently.

Saving Custom changes fails

Saving changes through Custom will not work, because custom-file is read-only. I am open to suggestions for how this should work:

Flag-controlled packages may be broken

Doom supports listing all packages (including ones pulled in by modules that are not currently enabled). Unstraightened uses this to build-test them. However, this does not include packages enabled through currently-disabled flags.

This is tricky because Doom seems to not support accessing supported flags programmatically, and because some flags are mutually exclusive.

I may end up approximating this by checking in a hardcoded init.el with all (or at least most) currently-available flags enabled.

doom doctor fails with / complains about...

"Checking for stale elc files... File is missing"

> Checking for stale elc files...
x There was an unexpected runtime error
  Message: File is missing
  Details: ("Opening directory" "No such file or directory" "/home/marienz/.local/share/nix-doom-unstraightened/straight/build-29.3")

For now, just create the directory.

I would like to fix this but have not thought of the least messy way yet.

"Doom is installed in a non-standard location"

Ignore it.

Unstraightened uses --init-directory, as the doctor recommends.

"Found another Emacs config:"

Safe to ignore, for the same reason as the previous warning.

tree-sitter error on initialization with file-error "Opening output file" "Read-only file system"

The ABI loaded for some grammars from nixpkgs is too new (14) compared to what vanilla Doom Emacs receives (13). This results in tree-sitter and some particular grammars to be incompatible. This issue is currently confirmed to affect golang.

See issue #7 for a more detailed explanation.

Considering that Doom Emacs will likely use the Emacs 29+ built-in tree-sitter at some point at least as an opt-in (see related Doom Emacs issue) this particular issue for Unstraightened is unlikely to get solved.

As a workaround the following is possible:

As a result tree-sitter (built-in to Emacs) will be compatible with the current ABI for grammars included in nixpkgs.

Frequently Anticipated Questions

How do I add more packages?

Add (package! foo) to packages.el.

Do not wrap emacsWithDoom in emacsWithPackages. See HACKING.md for why this will not work.

The home-manager option extraPackages is available to add extra Emacs packages from nixpkgs to Doom Emacs. If this is not sufficient, please file an issue.

How do I add packages not in Emacs overlay?

Add (package! foo :recipe ...) to packages.el.

If this is not sufficient, file an issue explaining what you're trying to do.

What's wrong with straight.el?

straight.el is great, but its features are somewhat at odds with Nix:

Doom heavily uses straight.el during doom sync, but it does not use it at all at startup and barely uses it after that. Since we're replacing doom sync in its entirety, bypassing straight.el seems simpler than trying to use it just for package builds.

Unstraightened seems to use package.el. Isn't that bad?

Doom's FAQ offers several arguments against package.el. They boil down to two problems, neither of which applies to Unstraightened:

It's so slow to build!

Parallel builds should help (set Nix's max-jobs to something greater than 1), but it is a bit slow.

There are a few issues:

Required disclaimer

This is not an officially supported Google product. It is a personal side project.