diff --git a/hm-modules/theme/default.nix b/hm-modules/theme/default.nix index d83ea7a..31448db 100644 --- a/hm-modules/theme/default.nix +++ b/hm-modules/theme/default.nix @@ -30,15 +30,21 @@ let availableVariants = concatStringsSep " " (attrNames themeVariants); + # variant:doomtheme pairs consumed by the theme-switch script's + # best-effort Doom Emacs hook (see ./theme-switch.sh). + doomThemeMap = concatStringsSep " " + (mapAttrsToList (variant: theme: "${variant}:${theme}") cfg.doomThemes); + # Userspace theme switcher: activates a pre-built Home Manager # specialisation generation. No sudo, no OS rebuild — just runs the # specialisation's activation script in the base HM generation. # # The script logic lives in ./theme-switch.sh (plain shell, no Nix - # escaping); we only inject the two config-derived values it needs. + # escaping); we only inject the config-derived values it needs. theme-switch = pkgs.writeShellScriptBin "theme-switch" '' baseVariant="${baseVariant}" availableVariants="${availableVariants}" + doomThemes="${doomThemeMap}" ${builtins.readFile ./theme-switch.sh} ''; @@ -67,6 +73,28 @@ in { default = builtinThemes; description = "Available themes with dark and light variants"; }; + + doomThemes = mkOption { + type = types.attrsOf types.str; + default = { + gruvbox-dark = "doom-gruvbox"; + gruvbox-light = "doom-one-light"; + catppuccin-dark = "doom-one"; + catppuccin-light = "doom-one-light"; + }; + description = '' + Mapping from theme variant name (e.g. "gruvbox-dark") to the Doom + Emacs theme symbol (e.g. "doom-gruvbox") that theme-switch will + live-load via emacsclient when switching to that variant. Variants + absent from this map are left unchanged in Emacs. + + Only themes actually installed in Doom will load; the defaults use + themes bundled with doom-themes (so they work out of the box, though + catppuccin variants fall back to generic dark/light). For accurate + catppuccin colours, install the `catppuccin-theme` Emacs package and + map the variants to `catppuccin-mocha` / `catppuccin-latte`. + ''; + }; }; config = mkIf cfg.enable ( diff --git a/hm-modules/theme/theme-switch.sh b/hm-modules/theme/theme-switch.sh index eb155a1..78c6f6a 100644 --- a/hm-modules/theme/theme-switch.sh +++ b/hm-modules/theme/theme-switch.sh @@ -1,18 +1,22 @@ # shellcheck shell=bash # theme-switch — activate a pre-built Home Manager specialisation. # -# Expects two variables to be injected by the Nix wrapper: +# Expects these variables to be injected by the Nix wrapper: # baseVariant the variant that is the generation itself (not a # specialisation), activated via `$gen/activate`. # availableVariants space-separated list of all variant names (help text). +# doomThemes optional space-separated `variant:doomtheme` pairs for +# the best-effort Doom Emacs live-switch (may be empty). # # Standalone usage for testing: # baseVariant=gruvbox-dark \ # availableVariants="gruvbox-dark gruvbox-light catppuccin-dark catppuccin-light" \ +# doomThemes="gruvbox-dark:doom-gruvbox" \ # bash theme-switch.sh : "${baseVariant:?theme-switch: baseVariant not set}" : "${availableVariants:?theme-switch: availableVariants not set}" +: "${doomThemes:=}" set -euo pipefail variant="${1:-}" @@ -74,4 +78,26 @@ if [ ! -x "$activate" ]; then fi echo "Switching theme to $variant..." + +# Best-effort: live-switch the running Doom Emacs daemon too. No config +# files are touched; if the daemon isn't running or emacsclient isn't +# installed (e.g. on a server), this is silently skipped. A theme symbol +# that isn't installed in Doom makes emacsclient return non-zero, which we +# also treat as skip. +doom_theme="" +if [ -n "$doomThemes" ]; then + for pair in $doomThemes; do + case "$pair" in + "${variant}":*) doom_theme="${pair#*:}"; break ;; + esac + done +fi +if [ -n "$doom_theme" ] && command -v emacsclient >/dev/null 2>&1; then + if emacsclient --eval "(progn (mapc (function disable-theme) custom-enabled-themes) (load-theme (quote ${doom_theme}) t))" >/dev/null 2>&1; then + echo "Doom: ${doom_theme}" + else + echo "note: Doom theme switch skipped (daemon not running or '${doom_theme}' not installed)" >&2 + fi +fi + exec "$activate"