diff --git a/modules/config/home-cursor.nix b/modules/config/home-cursor.nix index c696908d..89f5409d 100644 --- a/modules/config/home-cursor.nix +++ b/modules/config/home-cursor.nix @@ -136,16 +136,17 @@ in { home.packages = [ cfg.package defaultIndexThemePackage ]; + home.sessionVariables = { + XCURSOR_SIZE = mkDefault cfg.size; + XCURSOR_THEME = mkDefault cfg.name; + }; + # Set directory to look for cursors in, needed for some applications # that are unable to find cursors otherwise. See: # https://github.com/nix-community/home-manager/issues/2812 # https://wiki.archlinux.org/title/Cursor_themes#Environment_variable - home.sessionVariables = { - XCURSOR_PATH = mkDefault ("$XCURSOR_PATH\${XCURSOR_PATH:+:}" - + "${config.home.profileDirectory}/share/icons"); - XCURSOR_SIZE = mkDefault cfg.size; - XCURSOR_THEME = mkDefault cfg.name; - }; + home.sessionSearchVariables.XCURSOR_PATH = + [ "${config.home.profileDirectory}/share/icons" ]; # Add symlink of cursor icon directory to $HOME/.icons, needed for # backwards compatibility with some applications. See: diff --git a/modules/home-environment.nix b/modules/home-environment.nix index 59497ec4..6f5f521c 100644 --- a/modules/home-environment.nix +++ b/modules/home-environment.nix @@ -309,7 +309,7 @@ in ".git/safe/../../bin" ]; description = '' - Extra directories to add to {env}`PATH`. + Extra directories to be prepend to {env}`PATH`. These directories are added to the {env}`PATH` variable in a double-quoted context, so expressions like `$HOME` are @@ -319,6 +319,28 @@ in ''; }; + home.sessionSearchVariables = mkOption { + default = { }; + type = with types; attrsOf (listOf str); + example = { + MANPATH = [ + "$HOME/.npm-packages/man" + "\${xdg.configHome}/.local/share/man" + ]; + }; + description = '' + Extra directories to be prepend to arbitrary PATH-like + environment variables (e.g.: {env}`MANPATH`). The values + will be concatenated by `:`. + + These directories are added to the environment variable in a + double-quoted context, so expressions like `$HOME` are + expanded by the shell. However, since expressions like `~` or + `*` are escaped, they will end up in the environment + verbatim. + ''; + }; + home.sessionVariablesExtra = mkOption { type = types.lines; default = ""; @@ -575,11 +597,18 @@ in export __HM_SESS_VARS_SOURCED=1 ${config.lib.shell.exportAll cfg.sessionVariables} - '' + lib.optionalString (cfg.sessionPath != [ ]) '' - export PATH="$PATH''${PATH:+:}${concatStringsSep ":" cfg.sessionPath}" - '' + cfg.sessionVariablesExtra; + '' + concatStringsSep "\n" + (mapAttrsToList + (env: values: config.lib.shell.export + env + (config.lib.shell.prependToVar ":" env values)) + cfg.sessionSearchVariables) + + cfg.sessionVariablesExtra; }; + home.sessionSearchVariables.PATH = + mkIf (cfg.sessionPath != [ ]) cfg.sessionPath; + home.packages = [ config.home.sessionVariablesPackage ]; # A dummy entry acting as a boundary between the activation diff --git a/modules/i18n/input-method/fcitx5.nix b/modules/i18n/input-method/fcitx5.nix index 3c2d1c19..5117e680 100644 --- a/modules/i18n/input-method/fcitx5.nix +++ b/modules/i18n/input-method/fcitx5.nix @@ -24,13 +24,15 @@ in { config = mkIf (im.enabled == "fcitx5") { i18n.inputMethod.package = fcitx5Package; - home.sessionVariables = { - GLFW_IM_MODULE = "ibus"; # IME support in kitty - GTK_IM_MODULE = "fcitx"; - QT_IM_MODULE = "fcitx"; - XMODIFIERS = "@im=fcitx"; - QT_PLUGIN_PATH = - "$QT_PLUGIN_PATH\${QT_PLUGIN_PATH:+:}${fcitx5Package}/${pkgs.qt6.qtbase.qtPluginPrefix}"; + home = { + sessionVariables = { + GLFW_IM_MODULE = "ibus"; # IME support in kitty + GTK_IM_MODULE = "fcitx"; + QT_IM_MODULE = "fcitx"; + XMODIFIERS = "@im=fcitx"; + }; + sessionSearchVariables.QT_PLUGIN_PATH = + [ "${fcitx5Package}/${pkgs.qt6.qtbase.qtPluginPrefix}" ]; }; systemd.user.services.fcitx5-daemon = { diff --git a/modules/lib/shell.nix b/modules/lib/shell.nix index 5e5743f5..c6113d0f 100644 --- a/modules/lib/shell.nix +++ b/modules/lib/shell.nix @@ -1,6 +1,14 @@ { lib }: rec { + # Produces a Bourne shell like statement that prepend new values to + # an possibly existing variable, using sep(ator). + # Example: + # prependToVar ":" "PATH" [ "$HOME/bin" "$HOME/.local/bin" ] + # => "$HOME/bin:$HOME/.local/bin:${PATH:+:}\$PATH" + prependToVar = sep: n: v: + "${lib.concatStringsSep sep v}\${${n}:+${sep}}\$${n}"; + # Produces a Bourne shell like variable export statement. export = n: v: ''export ${n}="${toString v}"''; diff --git a/modules/misc/debug.nix b/modules/misc/debug.nix index fc0d8946..908b9114 100644 --- a/modules/misc/debug.nix +++ b/modules/misc/debug.nix @@ -18,9 +18,8 @@ with lib; config = mkIf config.home.enableDebugInfo { home.extraOutputsToInstall = [ "debug" ]; - home.sessionVariables = { - NIX_DEBUG_INFO_DIRS = - "$NIX_DEBUG_INFO_DIRS\${NIX_DEBUG_INFO_DIRS:+:}${config.home.profileDirectory}/lib/debug"; + home.sessionSearchVariables = { + NIX_DEBUG_INFO_DIRS = [ "${config.home.profileDirectory}/lib/debug" ]; }; }; } diff --git a/modules/misc/qt.nix b/modules/misc/qt.nix index a36bd567..1f9ccd14 100644 --- a/modules/misc/qt.nix +++ b/modules/misc/qt.nix @@ -214,13 +214,10 @@ in { inherit (config.home) profileDirectory; qtVersions = with pkgs; [ qt5 qt6 ]; makeQtPath = prefix: - lib.concatStringsSep ":" (map (qt: "${profileDirectory}/${qt.qtbase.${prefix}}") qtVersions); in { - QT_PLUGIN_PATH = "$QT_PLUGIN_PATH\${QT_PLUGIN_PATH:+:}" - + (makeQtPath "qtPluginPrefix"); - QML2_IMPORT_PATH = "$QML2_IMPORT_PATH\${QML2_IMPORT_PATH:+:}" - + (makeQtPath "qtQmlPrefix"); + QT_PLUGIN_PATH = makeQtPath "qtPluginPrefix"; + QML2_IMPORT_PATH = makeQtPath "qtQmlPrefix"; }; in lib.mkIf cfg.enable { @@ -244,19 +241,14 @@ in { home = { sessionVariables = envVars; - # home.sessionVariables does not support setting the same environment - # variable to different values. - # Since some other modules may set the QT_PLUGIN_PATH or QML2_IMPORT_PATH - # to their own value, e.g.: fcitx5, we avoid conflicts by setting - # the values in home.sessionVariablesExtra instead. - sessionVariablesExtra = '' - export QT_PLUGIN_PATH=${envVarsExtra.QT_PLUGIN_PATH} - export QML2_IMPORT_PATH=${envVarsExtra.QML2_IMPORT_PATH} - ''; + sessionSearchVariables = envVarsExtra; }; # Apply theming also to apps started by systemd. - systemd.user.sessionVariables = envVars // envVarsExtra; + systemd.user.sessionVariables = envVars // { + QT_PLUGIN_PATH = lib.concatStringsSep ":" envVarsExtra.QT_PLUGIN_PATH; + QML2_IMPORT_PATH = lib.concatStringsSep ":" envVarsExtra.QML2_IMPORT_PATH; + }; home.packages = (lib.findFirst (x: x != [ ]) [ ] [ (lib.optionals (platformTheme.package != null) diff --git a/modules/targets/generic-linux.nix b/modules/targets/generic-linux.nix index 9dce9f5c..a5ea98b9 100644 --- a/modules/targets/generic-linux.nix +++ b/modules/targets/generic-linux.nix @@ -48,12 +48,8 @@ in { # We need to append system-wide FHS directories due to the default prefix # resolving to the Nix store. # https://github.com/nix-community/home-manager/pull/2891#issuecomment-1101064521 - home.sessionVariables = { - XCURSOR_PATH = "$XCURSOR_PATH\${XCURSOR_PATH:+:}" + concatStringsSep ":" [ - "${config.home.profileDirectory}/share/icons" - "/usr/share/icons" - "/usr/share/pixmaps" - ]; + home.sessionSearchVariables = { + XCURSOR_PATH = [ "/usr/share/icons" "/usr/share/pixmaps" ]; }; home.sessionVariablesExtra = '' diff --git a/tests/modules/home-environment/default.nix b/tests/modules/home-environment/default.nix index e76e248a..c38ad5ce 100644 --- a/tests/modules/home-environment/default.nix +++ b/tests/modules/home-environment/default.nix @@ -1,4 +1,5 @@ { - home-session-variables = ./session-variables.nix; home-session-path = ./session-path.nix; + home-session-search-variables = ./session-search-variables.nix; + home-session-variables = ./session-variables.nix; } diff --git a/tests/modules/home-environment/session-path.nix b/tests/modules/home-environment/session-path.nix index 57cfeced..55c4084a 100644 --- a/tests/modules/home-environment/session-path.nix +++ b/tests/modules/home-environment/session-path.nix @@ -10,6 +10,6 @@ hmSessVars=home-path/etc/profile.d/hm-session-vars.sh assertFileExists $hmSessVars assertFileContains $hmSessVars \ - 'export PATH="$PATH''${PATH:+:}bar:baz:foo"' + 'export PATH="bar:baz:foo''${PATH:+:}$PATH"' ''; } diff --git a/tests/modules/home-environment/session-search-variables.nix b/tests/modules/home-environment/session-search-variables.nix new file mode 100644 index 00000000..66dcb034 --- /dev/null +++ b/tests/modules/home-environment/session-search-variables.nix @@ -0,0 +1,15 @@ +{ config, lib, pkgs, ... }: + +{ + imports = [ + ({ ... }: { config.home.sessionSearchVariables.TEST = [ "foo" ]; }) + ({ ... }: { config.home.sessionSearchVariables.TEST = [ "bar" "baz" ]; }) + ]; + + nmt.script = '' + hmSessVars=home-path/etc/profile.d/hm-session-vars.sh + assertFileExists $hmSessVars + assertFileContains $hmSessVars \ + 'export TEST="bar:baz:foo''${TEST:+:}$TEST"' + ''; +} diff --git a/tests/modules/misc/qt/qt-platform-theme-gtk.nix b/tests/modules/misc/qt/qt-platform-theme-gtk.nix index 76a6512f..84acc402 100644 --- a/tests/modules/misc/qt/qt-platform-theme-gtk.nix +++ b/tests/modules/misc/qt/qt-platform-theme-gtk.nix @@ -4,7 +4,6 @@ enable = true; platformTheme.name = "gtk"; }; - i18n.inputMethod.enabled = "fcitx5"; nmt.script = '' assertFileRegex home-path/etc/profile.d/hm-session-vars.sh \