From 2533183d8015a8b4aca8f484017179e19ee2c299 Mon Sep 17 00:00:00 2001 From: Christoph Urlacher Date: Mon, 20 Apr 2026 11:27:18 +0200 Subject: [PATCH] Modules/Fish: Add mechanism to load/unload fish environment shells with direnv --- config/flake.nix | 63 ++++++--- flake.lock | 180 ++++++++++++++++++++++---- flake.nix | 11 +- home/homemodules/default.nix | 1 + home/homemodules/fish/default.nix | 34 +++++ home/homemodules/kitty/default.nix | 4 +- home/homemodules/packages/default.nix | 10 ++ 7 files changed, 258 insertions(+), 45 deletions(-) diff --git a/config/flake.nix b/config/flake.nix index 12876430..a5ebd328 100644 --- a/config/flake.nix +++ b/config/flake.nix @@ -98,38 +98,65 @@ rec { buildDebug = mkBuildScript "Debug"; buildRelease = mkBuildScript "Release"; - # Use this to specify commands that should be ran after entering fish shell - initProjectShell = pkgs.writers.writeFish "init-shell.fish" '' - echo "Entering \"${description}\" environment..." - - # Determine the project root, used e.g. in cmake scripts - set -g -x FLAKE_PROJECT_ROOT (git rev-parse --show-toplevel) - + # Add project-local fish abbrs here + abbrs = { # Rust Bevy: - # abbr -a build-release-windows "CARGO_FEATURE_PURE=1 cargo xwin build --release --target x86_64-pc-windows-msvc" + # build-release-windows = "CARGO_FEATURE_PURE=1 cargo xwin build --release --target x86_64-pc-windows-msvc"; # C/C++: - # abbr -a cmake-debug "${cmakeDebug}" - # abbr -a cmake-release "${cmakeRelease}" - # abbr -a build-debug "${buildDebug}" - # abbr -a build-release "${buildRelease}" + # cmake-debug = "${cmakeDebug}"; + # cmake-release = "${cmakeRelease}"; + # build-debug = "${buildDebug}"; + # build-release = "${buildRelease}"; # Clojure: - # abbr -a clojure-deps "deps-lock --lein" + # clojure-deps = "deps-lock --lein"; # Python: - # abbr -a run "python ./app/main.py" - # abbr -a profile "py-spy record -o profile.svg -- python ./app/main.py && firefox profile.svg" - # abbr -a ptop "py-spy top -- python ./app/main.py" + # run = "python ./app/main.py"; + # profile = "py-spy record -o profile.svg -- python ./app/main.py && firefox profile.svg"; + # ptop = "py-spy top -- python ./app/main.py"; + }; + + eraseAbbr = name: value: ''abbr --erase ${name} 2>/dev/null''; + createAbbr = name: value: ''abbr -a ${name} "${value}"''; + + # This will be sourced by the global fish config if INIT_PROJECT_SHELL gets unset + unloadProjectShell = pkgs.writers.writeFish "unload-shell.fish" '' + echo "Unloading \"${description}\" environment..." + + ${builtins.concatStringsSep "\n" (lib.mapAttrsToList eraseAbbr abbrs)} + ''; + + # This will be sourced by the global fish config if INIT_PROJECT_SHELL gets set + initProjectShell = pkgs.writers.writeFish "init-shell.fish" '' + # Unload just in case, to not have redefinition errors + source ${unloadProjectShell} + + echo "Sourcing \"${description}\" environment..." + + ${builtins.concatStringsSep "\n" (lib.mapAttrsToList createAbbr abbrs)} ''; in builtins.concatStringsSep "\n" [ # Launch into pure fish shell '' - exec "$(type -p fish)" -C "source ${initProjectShell} && abbr -a menu '${pkgs.bat}/bin/bat "${initProjectShell}"'" + # Determine the project root, used e.g. in cmake scripts + export FLAKE_PROJECT_ROOT="$(git rev-parse --show-toplevel)" + + # Can't do the "exec" with nix-direnv + # - The "exec fish" would call direnv again => Infinite loop + # - The shellHook is Bash/POSIX, so fish syntax doesn't work + + # Use this for "nix develop" without direnv + # exec "$(type -p fish)" -C "source ${initProjectShell} && abbr -a menu '${pkgs.bat}/bin/bat "${initProjectShell}"'" + + # Use this for direnv without "nix develop" + export INIT_PROJECT_SHELL="${initProjectShell}" + export UNLOAD_PROJECT_SHELL="${unloadProjectShell}" '' - # Qt: Launch into wrapped fish shell + # Qt: Launch into wrapped fish shell (direnv incompatible) # https://nixos.org/manual/nixpkgs/stable/#sec-language-qt # '' # fishdir=$(mktemp -d) diff --git a/flake.lock b/flake.lock index fa7050ae..67455528 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,24 @@ { "nodes": { + "comfyui-nix": { + "inputs": { + "flake-parts": "flake-parts", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1775530069, + "narHash": "sha256-LuWit2RDTkiwwHwAhqfPcfo6ZUcV931XXijeQqD6FTM=", + "owner": "utensils", + "repo": "comfyui-nix", + "rev": "255224118c3a7d7514c4f0d975120feb3cb16b58", + "type": "github" + }, + "original": { + "owner": "utensils", + "repo": "comfyui-nix", + "type": "github" + } + }, "crane": { "locked": { "lastModified": 1754269165, @@ -17,7 +36,7 @@ }, "devshell": { "inputs": { - "nixpkgs": "nixpkgs" + "nixpkgs": "nixpkgs_2" }, "locked": { "lastModified": 1768818222, @@ -33,6 +52,28 @@ "type": "github" } }, + "direnv-instant": { + "inputs": { + "flake-parts": "flake-parts_2", + "nixpkgs": [ + "nixpkgs" + ], + "treefmt-nix": "treefmt-nix" + }, + "locked": { + "lastModified": 1776064408, + "narHash": "sha256-usJh+oOUfRDHvWd1rRjSJX/OyRskHqumg93laPhz88I=", + "owner": "Mic92", + "repo": "direnv-instant", + "rev": "f1a33bf99b030e3289b9eb00fdfea81437eda536", + "type": "github" + }, + "original": { + "owner": "Mic92", + "repo": "direnv-instant", + "type": "github" + } + }, "disko": { "inputs": { "nixpkgs": [ @@ -56,7 +97,7 @@ }, "elephant": { "inputs": { - "nixpkgs": "nixpkgs_2", + "nixpkgs": "nixpkgs_3", "systems": "systems" }, "locked": { @@ -165,6 +206,45 @@ } }, "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1767609335, + "narHash": "sha256-feveD98mQpptwrAEggBQKJTYbvwwglSbOv53uCfH9PY=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "250481aafeb741edfe23d29195671c19b36b6dca", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_2": { + "inputs": { + "nixpkgs-lib": [ + "direnv-instant", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1775087534, + "narHash": "sha256-91qqW8lhL7TLwgQWijoGBbiD4t7/q75KTi8NxjVmSmA=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "3107b77cd68437b9a76194f0f7f9c55f2329ca5b", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_3": { "inputs": { "nixpkgs-lib": [ "lanzaboote", @@ -185,7 +265,7 @@ "type": "github" } }, - "flake-parts_2": { + "flake-parts_4": { "inputs": { "nixpkgs-lib": [ "nixvim", @@ -206,7 +286,7 @@ "type": "github" } }, - "flake-parts_3": { + "flake-parts_5": { "inputs": { "nixpkgs-lib": [ "nur", @@ -343,7 +423,7 @@ }, "hytale-launcher": { "inputs": { - "nixpkgs": "nixpkgs_3" + "nixpkgs": "nixpkgs_4" }, "locked": { "lastModified": 1774383212, @@ -362,7 +442,7 @@ "impermanence": { "inputs": { "home-manager": "home-manager_2", - "nixpkgs": "nixpkgs_4" + "nixpkgs": "nixpkgs_5" }, "locked": { "lastModified": 1769548169, @@ -382,7 +462,7 @@ "inputs": { "crane": "crane", "flake-compat": "flake-compat", - "flake-parts": "flake-parts", + "flake-parts": "flake-parts_3", "nixpkgs": [ "nixpkgs" ], @@ -428,7 +508,7 @@ "naersk": { "inputs": { "fenix": "fenix", - "nixpkgs": "nixpkgs_7" + "nixpkgs": "nixpkgs_8" }, "locked": { "lastModified": 1763384566, @@ -506,7 +586,7 @@ "inputs": { "flake-compat": "flake-compat_2", "nix-index-database": "nix-index-database", - "nixpkgs": "nixpkgs_5" + "nixpkgs": "nixpkgs_6" }, "locked": { "lastModified": 1771150922, @@ -582,20 +662,35 @@ }, "nixpkgs": { "locked": { - "lastModified": 1762156382, - "narHash": "sha256-Yg7Ag7ov5+36jEFC1DaZh/12SEXo6OO3/8rqADRxiqs=", + "lastModified": 1766902085, + "narHash": "sha256-coBu0ONtFzlwwVBzmjacUQwj3G+lybcZ1oeNSQkgC0M=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "7241bcbb4f099a66aafca120d37c65e8dda32717", + "rev": "c0b0e0fddf73fd517c3471e546c0df87a42d53f4", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixpkgs-unstable", + "ref": "nixos-unstable", "repo": "nixpkgs", "type": "github" } }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1765674936, + "narHash": "sha256-k00uTP4JNfmejrCLJOwdObYC9jHRrr/5M/a/8L2EIdo=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "2075416fcb47225d9b68ac469a5c4801a9c4dd85", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, "nixpkgs-stable": { "locked": { "lastModified": 1774244481, @@ -629,6 +724,22 @@ } }, "nixpkgs_2": { + "locked": { + "lastModified": 1762156382, + "narHash": "sha256-Yg7Ag7ov5+36jEFC1DaZh/12SEXo6OO3/8rqADRxiqs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "7241bcbb4f099a66aafca120d37c65e8dda32717", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { "locked": { "lastModified": 1764242076, "narHash": "sha256-sKoIWfnijJ0+9e4wRvIgm/HgE27bzwQxcEmo2J/gNpI=", @@ -644,7 +755,7 @@ "type": "github" } }, - "nixpkgs_3": { + "nixpkgs_4": { "locked": { "lastModified": 1774106199, "narHash": "sha256-US5Tda2sKmjrg2lNHQL3jRQ6p96cgfWh3J1QBliQ8Ws=", @@ -660,7 +771,7 @@ "type": "github" } }, - "nixpkgs_4": { + "nixpkgs_5": { "locked": { "lastModified": 1768564909, "narHash": "sha256-Kell/SpJYVkHWMvnhqJz/8DqQg2b6PguxVWOuadbHCc=", @@ -676,7 +787,7 @@ "type": "github" } }, - "nixpkgs_5": { + "nixpkgs_6": { "locked": { "lastModified": 1771008912, "narHash": "sha256-gf2AmWVTs8lEq7z/3ZAsgnZDhWIckkb+ZnAo5RzSxJg=", @@ -692,7 +803,7 @@ "type": "github" } }, - "nixpkgs_6": { + "nixpkgs_7": { "locked": { "lastModified": 1774386573, "narHash": "sha256-4hAV26quOxdC6iyG7kYaZcM3VOskcPUrdCQd/nx8obc=", @@ -708,7 +819,7 @@ "type": "github" } }, - "nixpkgs_7": { + "nixpkgs_8": { "locked": { "lastModified": 1752077645, "narHash": "sha256-HM791ZQtXV93xtCY+ZxG1REzhQenSQO020cu6rHtAPk=", @@ -724,7 +835,7 @@ "type": "github" } }, - "nixpkgs_8": { + "nixpkgs_9": { "locked": { "lastModified": 1768564909, "narHash": "sha256-Kell/SpJYVkHWMvnhqJz/8DqQg2b6PguxVWOuadbHCc=", @@ -742,7 +853,7 @@ }, "nixvim": { "inputs": { - "flake-parts": "flake-parts_2", + "flake-parts": "flake-parts_4", "nixpkgs": [ "nixpkgs" ], @@ -787,7 +898,7 @@ }, "nur": { "inputs": { - "flake-parts": "flake-parts_3", + "flake-parts": "flake-parts_5", "nixpkgs": [ "nixpkgs" ] @@ -834,7 +945,9 @@ }, "root": { "inputs": { + "comfyui-nix": "comfyui-nix", "devshell": "devshell", + "direnv-instant": "direnv-instant", "disko": "disko", "elephant": "elephant", "hardware": "hardware", @@ -847,7 +960,7 @@ "nix-alien": "nix-alien", "nix-darwin": "nix-darwin", "nix-flatpak": "nix-flatpak", - "nixpkgs": "nixpkgs_6", + "nixpkgs": "nixpkgs_7", "nixpkgs-stable": "nixpkgs-stable_2", "nixvim": "nixvim", "nps": "nps", @@ -1011,12 +1124,33 @@ "type": "github" } }, + "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "direnv-instant", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1775636079, + "narHash": "sha256-pc20NRoMdiar8oPQceQT47UUZMBTiMdUuWrYu2obUP0=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "790751ff7fd3801feeaf96d7dc416a8d581265ba", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + }, "walker": { "inputs": { "elephant": [ "elephant" ], - "nixpkgs": "nixpkgs_8", + "nixpkgs": "nixpkgs_9", "systems": "systems_5" }, "locked": { diff --git a/flake.nix b/flake.nix index fb1264af..792850a1 100644 --- a/flake.nix +++ b/flake.nix @@ -78,10 +78,17 @@ nix-flatpak.url = "github:gmodena/nix-flatpak/?ref=latest"; # nix-flatpak.inputs.nixpkgs.follows = "nixpkgs"; # nix-flatpak doesn't have this + # Instant Direnv (load environment in background) + direnv-instant.url = "github:Mic92/direnv-instant"; + direnv-instant.inputs.nixpkgs.follows = "nixpkgs"; + # Realtime audio # musnix.url = "github:musnix/musnix"; # musnix.inputs.nixpkgs.follows = "nixpkgs"; + # ComfyUI + comfyui-nix.url = "github:utensils/comfyui-nix"; + # HyTale hytale-launcher.url = "github:JPyke3/hytale-launcher-nix"; @@ -138,7 +145,7 @@ inputs.nur.overlays.default inputs.niri.overlays.niri # inputs.emacs-overlay.overlay - # inputs.comfyui-nix.overlays.default + inputs.comfyui-nix.overlays.default # All my own overlays (derivations + modifications) (import ./overlays {inherit inputs nixpkgs pkgs-stable;}) @@ -250,7 +257,7 @@ [ inputs.disko.nixosModules.disko # inputs.nixified-ai.nixosModules.comfyui - # inputs.comfyui-nix.nixosModules.default + inputs.comfyui-nix.nixosModules.default ] ++ commonModules; }; diff --git a/home/homemodules/default.nix b/home/homemodules/default.nix index b2fefc6d..7a5f2228 100644 --- a/home/homemodules/default.nix +++ b/home/homemodules/default.nix @@ -39,6 +39,7 @@ inputs.nixvim.homeModules.nixvim inputs.textfox.homeManagerModules.default inputs.walker.homeManagerModules.default + inputs.direnv-instant.homeModules.direnv-instant # inputs.niri.homeModules.niri # Imported by system module # inputs.noctalia.homeModules.default # inputs.caelestia.homeManagerModules.default diff --git a/home/homemodules/fish/default.nix b/home/homemodules/fish/default.nix index 9fd9005c..d61ecaca 100644 --- a/home/homemodules/fish/default.nix +++ b/home/homemodules/fish/default.nix @@ -87,6 +87,40 @@ in { shellInit = '' set fish_greeting yes | fish_config theme save "system-theme" + + # Because we can't source that in a project flake's shellHook (is POSIX), source it here + function __project_shell_reload --on-variable INIT_PROJECT_SHELL + # Leaving the environment + if not set -q INIT_PROJECT_SHELL; or test -z "$INIT_PROJECT_SHELL" + if test -n "$__last_unload_project_shell"; and test -f "$__last_unload_project_shell" + source "$__last_unload_project_shell" + end + set -e __last_init_project_shell + set -e __last_unload_project_shell + return + end + + # Entering or switching environments + if test "$INIT_PROJECT_SHELL" != "$__last_init_project_shell" + # Cleanup the previous environment + if test -n "$__last_unload_project_shell"; and test -f "$__last_unload_project_shell" + source "$__last_unload_project_shell" + end + + # Store into variables to persist until next environment switch in the same shell + set -g __last_init_project_shell "$INIT_PROJECT_SHELL" + if set -q UNLOAD_PROJECT_SHELL; and test -f "$UNLOAD_PROJECT_SHELL" + set -g __last_unload_project_shell "$UNLOAD_PROJECT_SHELL" + else + set -e __last_unload_project_shell + end + + # Source the new environment + if test -f "$INIT_PROJECT_SHELL" + source "$INIT_PROJECT_SHELL" + end + end + end ''; functions = lib.mergeAttrsList [ diff --git a/home/homemodules/kitty/default.nix b/home/homemodules/kitty/default.nix index 5364fdb4..90156f77 100644 --- a/home/homemodules/kitty/default.nix +++ b/home/homemodules/kitty/default.nix @@ -31,8 +31,8 @@ in { settings = lib.mkMerge [ # Linux config (lib.mkIf pkgs.stdenv.isLinux { - allow_remote_control = "yes"; # For nnn file preview or nvim scrollback - listen_on = "unix:@mykitty"; + allow_remote_control = true; # For nnn file preview or nvim scrollback + listen_on = lib.mkDefault "unix:@mykitty"; # This conflicts with direnv-instant }) # Common config diff --git a/home/homemodules/packages/default.nix b/home/homemodules/packages/default.nix index b0e361a2..69df9afc 100644 --- a/home/homemodules/packages/default.nix +++ b/home/homemodules/packages/default.nix @@ -204,9 +204,19 @@ in { direnv = { enable = true; + enableFishIntegration = !config.programs.direnv-instant.enable; + silent = true; nix-direnv.enable = true; }; + # This replaces the normal direnv.enableFishIntegration. + # direnv-instant = { + # enable = true; + # enableFishIntegration = true; + # enableKittyIntegration = true; + # settings.use_cache = true; + # }; + eza = { enable = true; enableFishIntegration = config.homemodules.fish.enable;