diff --git a/modules/misc/news/2026/05/2026-05-18_12-00-00.nix b/modules/misc/news/2026/05/2026-05-18_12-00-00.nix new file mode 100644 index 000000000..b0e6c5647 --- /dev/null +++ b/modules/misc/news/2026/05/2026-05-18_12-00-00.nix @@ -0,0 +1,18 @@ +{ config, ... }: +{ + time = "2026-05-18T17:00:00+00:00"; + condition = config.programs.zsh.enable; + message = '' + The `programs.zsh` module now sources Home Manager session variables from + `.zprofile` for login shells. Non-login shells continue to source them from + `.zshenv`. + + As a result, Home Manager now always writes `.zprofile` when + `programs.zsh.enable` is set, instead of only writing it when + `programs.zsh.profileExtra` is configured. + + This keeps `home.sessionPath` entries from being overwritten or reordered + by system login startup files such as NixOS' `/etc/zprofile` or macOS' + `path_helper`. + ''; +} diff --git a/modules/programs/zsh/default.nix b/modules/programs/zsh/default.nix index 6fba1580a..b148367e0 100644 --- a/modules/programs/zsh/default.nix +++ b/modules/programs/zsh/default.nix @@ -373,6 +373,21 @@ in let envVarsStr = config.lib.zsh.exportAll cfg.sessionVariables { indent = " "; }; localVarsStr = config.lib.zsh.defineAll cfg.localVariables; + sessionVarsStr = lib.removeSuffix "\n" '' + # Environment variables + . "${config.home.sessionVariablesPackage}/etc/profile.d/hm-session-vars.sh" + + # Only source this once + if [[ -z "''${__HM_ZSH_SESS_VARS_SOURCED-}" ]]; then + export __HM_ZSH_SESS_VARS_SOURCED=1 + ${envVarsStr} + fi + ''; + indentNonEmptyLines = + str: + concatStringsSep "\n" ( + map (line: if line == "" then "" else " ${line}") (lib.splitString "\n" str) + ); aliasesStr = concatStringsSep "\n" ( lib.mapAttrsToList ( @@ -441,10 +456,6 @@ in home.file."${dotDirRel}/.zshenv".text = cfg.envExtra; }) - (mkIf (cfg.profileExtra != "") { - home.file."${dotDirRel}/.zprofile".text = cfg.profileExtra; - }) - (mkIf (cfg.loginExtra != "") { home.file."${dotDirRel}/.zlogin".text = cfg.loginExtra; }) @@ -478,15 +489,18 @@ in { home.file."${dotDirRel}/.zshenv".text = '' - # Environment variables - . "${config.home.sessionVariablesPackage}/etc/profile.d/hm-session-vars.sh" - - # Only source this once - if [[ -z "''${__HM_ZSH_SESS_VARS_SOURCED-}" ]]; then - export __HM_ZSH_SESS_VARS_SOURCED=1 - ${envVarsStr} + if [[ ! -o login ]]; then + ${indentNonEmptyLines sessionVarsStr} fi ''; + + home.file."${dotDirRel}/.zprofile".text = '' + ${sessionVarsStr} + '' + + optionalString (cfg.profileExtra != "") '' + + ${cfg.profileExtra} + ''; } { diff --git a/tests/modules/programs/zsh/session-variables.nix b/tests/modules/programs/zsh/session-variables.nix index 5e49dd106..368489c8b 100644 --- a/tests/modules/programs/zsh/session-variables.nix +++ b/tests/modules/programs/zsh/session-variables.nix @@ -18,5 +18,7 @@ nmt.script = '' assertFileExists home-files/.zshenv assertFileContent $(normalizeStorePaths home-files/.zshenv) ${./session-variables.zshenv} + assertFileExists home-files/.zprofile + assertFileContent $(normalizeStorePaths home-files/.zprofile) ${./session-variables.zprofile} ''; } diff --git a/tests/modules/programs/zsh/session-variables.zprofile b/tests/modules/programs/zsh/session-variables.zprofile new file mode 100644 index 000000000..cf99c7748 --- /dev/null +++ b/tests/modules/programs/zsh/session-variables.zprofile @@ -0,0 +1,13 @@ +# Environment variables +. "/nix/store/00000000000000000000000000000000-hm-session-vars.sh/etc/profile.d/hm-session-vars.sh" + +# Only source this once +if [[ -z "${__HM_ZSH_SESS_VARS_SOURCED-}" ]]; then + export __HM_ZSH_SESS_VARS_SOURCED=1 + export IS_EMPTY="" + export IS_FALSE=false + export IS_TRUE=true + export PATH="$HOME/bin:$PATH" + export V1="v1" + export V2="v2-v1" +fi diff --git a/tests/modules/programs/zsh/session-variables.zshenv b/tests/modules/programs/zsh/session-variables.zshenv index cf99c7748..d879b8921 100644 --- a/tests/modules/programs/zsh/session-variables.zshenv +++ b/tests/modules/programs/zsh/session-variables.zshenv @@ -1,13 +1,15 @@ -# Environment variables -. "/nix/store/00000000000000000000000000000000-hm-session-vars.sh/etc/profile.d/hm-session-vars.sh" +if [[ ! -o login ]]; then + # Environment variables + . "/nix/store/00000000000000000000000000000000-hm-session-vars.sh/etc/profile.d/hm-session-vars.sh" -# Only source this once -if [[ -z "${__HM_ZSH_SESS_VARS_SOURCED-}" ]]; then - export __HM_ZSH_SESS_VARS_SOURCED=1 - export IS_EMPTY="" - export IS_FALSE=false - export IS_TRUE=true - export PATH="$HOME/bin:$PATH" - export V1="v1" - export V2="v2-v1" + # Only source this once + if [[ -z "${__HM_ZSH_SESS_VARS_SOURCED-}" ]]; then + export __HM_ZSH_SESS_VARS_SOURCED=1 + export IS_EMPTY="" + export IS_FALSE=false + export IS_TRUE=true + export PATH="$HOME/bin:$PATH" + export V1="v1" + export V2="v2-v1" + fi fi