From 4a450a216b4a91394ef4843e6b0fa904e95dbe38 Mon Sep 17 00:00:00 2001 From: John Ogle Date: Sat, 10 Jan 2026 10:44:03 -0800 Subject: [PATCH] feat(emacs): Add prebuilt Doom option using nix-doom-emacs-unstraightened Implement pre-built Doom Emacs packages for the live USB image, eliminating the need to run `doom sync` after first boot. Changes: - Add nix-doom-emacs-unstraightened flake input - Add homeModule to all three module sets (nixos, unstable, darwin) - Add `prebuiltDoom` option to emacs role (default: false) - Enable prebuiltDoom for live-usb configuration - Pin custom packages in packages.el for deterministic builds: - claude-code-ide, gptel-tool-library, beads When prebuiltDoom=true, all Doom packages are compiled at nix build time using emacs-overlay. The doom configuration is stored in the nix store (read-only), and no `doom sync` is required at runtime. This is ideal for: - Live USB images - Immutable/reproducible systems - Offline deployments Closes: nixos-configs-1wd --- flake.lock | 76 ++++++++++++++++++++ flake.nix | 11 +++ home/home-live-usb.nix | 7 +- home/roles/emacs/default.nix | 113 +++++++++++++++++++----------- home/roles/emacs/doom/packages.el | 14 +++- 5 files changed, 179 insertions(+), 42 deletions(-) diff --git a/flake.lock b/flake.lock index 3ac3a34..6f83b19 100644 --- a/flake.lock +++ b/flake.lock @@ -21,6 +21,45 @@ "type": "github" } }, + "doomemacs": { + "flake": false, + "locked": { + "lastModified": 1767773143, + "narHash": "sha256-QL/t9v2kFNxBDyNJb/s411o3mxujan+QX5IZglTdpTk=", + "owner": "doomemacs", + "repo": "doomemacs", + "rev": "3e15fb36d7f94f0a218bda977be4d3f5da983a71", + "type": "github" + }, + "original": { + "owner": "doomemacs", + "repo": "doomemacs", + "type": "github" + } + }, + "emacs-overlay": { + "inputs": { + "nixpkgs": [ + "nix-doom-emacs-unstraightened" + ], + "nixpkgs-stable": [ + "nix-doom-emacs-unstraightened" + ] + }, + "locked": { + "lastModified": 1768011937, + "narHash": "sha256-SnU2XTo34vwVaijs+4VwcXTNwMWO4nwzzs08N39UagA=", + "owner": "nix-community", + "repo": "emacs-overlay", + "rev": "79abf71d9897cf3b5189f7175cda1b1102abc65c", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "emacs-overlay", + "type": "github" + } + }, "flake-compat": { "flake": false, "locked": { @@ -159,6 +198,27 @@ "type": "github" } }, + "nix-doom-emacs-unstraightened": { + "inputs": { + "doomemacs": "doomemacs", + "emacs-overlay": "emacs-overlay", + "nixpkgs": [], + "systems": "systems_2" + }, + "locked": { + "lastModified": 1768034604, + "narHash": "sha256-62pIZMvGHhYJmMiiBsxHqZt/dFyENPcFHlJq5NJF3Sw=", + "owner": "marienz", + "repo": "nix-doom-emacs-unstraightened", + "rev": "9b3b8044fe4ccdcbb2d6f733d7dbe4d5feea18bc", + "type": "github" + }, + "original": { + "owner": "marienz", + "repo": "nix-doom-emacs-unstraightened", + "type": "github" + } + }, "nix-github-actions": { "inputs": { "nixpkgs": [ @@ -303,6 +363,7 @@ "home-manager-unstable": "home-manager-unstable", "jovian": "jovian", "nix-darwin": "nix-darwin", + "nix-doom-emacs-unstraightened": "nix-doom-emacs-unstraightened", "nixos-wsl": "nixos-wsl", "nixpkgs": "nixpkgs_2", "nixpkgs-unstable": "nixpkgs-unstable", @@ -324,6 +385,21 @@ "repo": "default", "type": "github" } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index e295586..5ce3f42 100644 --- a/flake.nix +++ b/flake.nix @@ -47,6 +47,12 @@ url = "github:steveyegge/beads"; inputs.nixpkgs.follows = "nixpkgs-unstable"; }; + + nix-doom-emacs-unstraightened = { + url = "github:marienz/nix-doom-emacs-unstraightened"; + # Don't follow nixpkgs to avoid rebuild issues with emacs-overlay + inputs.nixpkgs.follows = ""; + }; }; outputs = { self, nixpkgs, nixpkgs-unstable, nixos-wsl, ... } @ inputs: let @@ -70,6 +76,7 @@ home-manager.useUserPackages = true; home-manager.sharedModules = [ inputs.plasma-manager.homeModules.plasma-manager + inputs.nix-doom-emacs-unstraightened.homeModule ]; home-manager.extraSpecialArgs = { globalInputs = inputs; @@ -98,6 +105,7 @@ home-manager.useUserPackages = true; home-manager.sharedModules = [ inputs.plasma-manager-unstable.homeModules.plasma-manager + inputs.nix-doom-emacs-unstraightened.homeModule ]; home-manager.extraSpecialArgs = { globalInputs = inputs; @@ -129,6 +137,9 @@ ]; home-manager.useGlobalPkgs = true; home-manager.useUserPackages = true; + home-manager.sharedModules = [ + inputs.nix-doom-emacs-unstraightened.homeModule + ]; home-manager.extraSpecialArgs = { globalInputs = inputs; }; diff --git a/home/home-live-usb.nix b/home/home-live-usb.nix index 8c659ba..ba4e86e 100644 --- a/home/home-live-usb.nix +++ b/home/home-live-usb.nix @@ -14,7 +14,12 @@ desktop.enable = true; tmux.enable = true; plasma-manager.enable = true; - emacs.enable = true; + emacs = { + enable = true; + # Use pre-built Doom Emacs - all packages built at nix build time + # This means no doom sync is needed after booting the live USB + prebuiltDoom = true; + }; i3_sway.enable = true; # development.enable = false; # Not needed for live USB # communication.enable = false; # Not needed for live USB diff --git a/home/roles/emacs/default.nix b/home/roles/emacs/default.nix index daeb07e..5cea812 100644 --- a/home/roles/emacs/default.nix +++ b/home/roles/emacs/default.nix @@ -23,55 +23,90 @@ let if pkgs.stdenv.isDarwin then pkgs.emacs-macport.pkgs.withPackages emacsPackages else pkgs.emacs.pkgs.withPackages emacsPackages; + + # Path to doom config directory (relative to this file) + doomConfigDir = ./doom; in { options.home.roles.emacs = { enable = mkEnableOption "Doom Emacs with vterm and tree-sitter support"; + + prebuiltDoom = mkOption { + type = types.bool; + default = false; + description = '' + Use nix-doom-emacs-unstraightened to pre-build all Doom packages at + nix build time. This eliminates the need to run `doom sync` after + first boot, making it ideal for live USB images or immutable systems. + + When enabled, the doom configuration is read-only (stored in nix store). + ''; + }; }; - config = mkIf cfg.enable { - home.packages = [ - pkgs.emacs-all-the-icons-fonts - pkgs.fira-code - pkgs.fontconfig - pkgs.graphviz - pkgs.isort - pkgs.nerd-fonts.fira-code - pkgs.nerd-fonts.droid-sans-mono - pkgs.nil # nix lsp language server - pkgs.nixfmt-rfc-style - (pkgs.ripgrep.override {withPCRE2 = true;}) - pkgs.pipenv - pkgs.poetry - pkgs.python3 - ]; + config = mkIf cfg.enable (mkMerge [ + # Common configuration for both modes + { + home.packages = [ + pkgs.emacs-all-the-icons-fonts + pkgs.fira-code + pkgs.fontconfig + pkgs.graphviz + pkgs.isort + pkgs.nerd-fonts.fira-code + pkgs.nerd-fonts.droid-sans-mono + pkgs.nil # nix lsp language server + pkgs.nixfmt-rfc-style + (pkgs.ripgrep.override {withPCRE2 = true;}) + pkgs.pipenv + pkgs.poetry + pkgs.python3 + ]; - programs.emacs = { - enable = true; - package = defaultEmacsPackage; - }; + fonts.fontconfig.enable = true; + } - fonts.fontconfig.enable = true; + # Standard Doom Emacs mode (requires doom sync at runtime) + (mkIf (!cfg.prebuiltDoom) { + programs.emacs = { + enable = true; + package = defaultEmacsPackage; + }; - # Mount emacs and tree-sitter grammars from nix store - home.file = { - "${config.xdg.configHome}/emacs".source = doomEmacs; - }; + # Mount emacs and tree-sitter grammars from nix store + home.file = { + "${config.xdg.configHome}/emacs".source = doomEmacs; + }; - home.sessionPath = [ - "${config.xdg.configHome}/emacs/bin" - ]; + home.sessionPath = [ + "${config.xdg.configHome}/emacs/bin" + ]; - home.sessionVariables = { - DOOMDIR = "${config.xdg.configHome}/doom"; - DOOMLOCALDIR = "${config.xdg.dataHome}/doom"; - }; + home.sessionVariables = { + DOOMDIR = "${config.xdg.configHome}/doom"; + DOOMLOCALDIR = "${config.xdg.dataHome}/doom"; + }; - # TODO: Use mkOutOfStoreSymlink instead? - home.activation.doomConfig = lib.hm.dag.entryAfter ["writeBoundary"] '' - # Always remove and recreate the symlink to ensure it points to the source directory - rm -rf "${config.xdg.configHome}/doom" - ln -sf "${config.home.homeDirectory}/nixos-configs/home/roles/emacs/doom" "${config.xdg.configHome}/doom" - ''; - }; + # TODO: Use mkOutOfStoreSymlink instead? + home.activation.doomConfig = lib.hm.dag.entryAfter ["writeBoundary"] '' + # Always remove and recreate the symlink to ensure it points to the source directory + rm -rf "${config.xdg.configHome}/doom" + ln -sf "${config.home.homeDirectory}/nixos-configs/home/roles/emacs/doom" "${config.xdg.configHome}/doom" + ''; + }) + + # Pre-built Doom Emacs mode (no doom sync needed - ideal for live USB) + (mkIf cfg.prebuiltDoom { + programs.doom-emacs = { + enable = true; + doomDir = doomConfigDir; + doomLocalDir = "${config.xdg.dataHome}/doom"; + # Add extra packages that aren't part of Doom but needed for our config + extraPackages = epkgs: [ + epkgs.vterm + epkgs.treesit-grammars.with-all-grammars + ]; + }; + }) + ]); } diff --git a/home/roles/emacs/doom/packages.el b/home/roles/emacs/doom/packages.el index 44813a8..b1630c5 100644 --- a/home/roles/emacs/doom/packages.el +++ b/home/roles/emacs/doom/packages.el @@ -51,11 +51,21 @@ ;; (package! org-caldav) +;; Note: Packages with custom recipes must be pinned for nix-doom-emacs-unstraightened +;; to build deterministically. Update pins when upgrading packages. + (package! gptel :recipe (:nonrecursive t)) (package! claude-code-ide - :recipe (:host github :repo "manzaltu/claude-code-ide.el")) + :recipe (:host github :repo "manzaltu/claude-code-ide.el") + :pin "760240d7f03ff16f90ede9d4f4243cd94f3fed73") (package! gptel-tool-library :recipe (:host github :repo "aard-fi/gptel-tool-library" - :files ("*.el"))) + :files ("*.el")) + :pin "baffc3b0d74a2b7cbda0d5cd6dd7726d6ccaca83") + +(package! beads + :recipe (:type git :repo "https://codeberg.org/ctietze/beads.el.git" + :files ("lisp/*.el")) + :pin "f40a6461d3c0fa0969311bbb6a1e30d1bba86c88")