diff --git a/modules/programs/zsh.nix b/modules/programs/zsh.nix index 9f9a98841..c78401ea2 100644 --- a/modules/programs/zsh.nix +++ b/modules/programs/zsh.nix @@ -3,29 +3,33 @@ with lib; let + homeDir = config.home.homeDirectory; cfg = config.programs.zsh; - relToDotDir = file: (optionalString (cfg.dotDir != null) (cfg.dotDir + "/")) + file; + dotDirParsed = + escapeShellArg ( + removeSuffix "/" ( + (optionalString (!hasPrefix "/" cfg.dotDir) homeDir) + "/${cfg.dotDir}" + ) + ); - pluginsDir = if cfg.dotDir != null then - relToDotDir "plugins" else ".zsh/plugins"; + dotDirRelToHome = removePrefix "${homeDir}/" dotDirParsed; + + pluginsDir = dotDirParsed + + (optionalString homeDir == dotDirParsed "/.zsh") + + "/plugins"; envVarsStr = config.lib.zsh.exportAll cfg.sessionVariables; localVarsStr = config.lib.zsh.defineAll cfg.localVariables; aliasesStr = concatStringsSep "\n" ( - mapAttrsToList (k: v: "alias -- ${lib.escapeShellArg k}=${lib.escapeShellArg v}") cfg.shellAliases + mapAttrsToList (k: v: "alias -- ${escapeShellArg k}=${escapeShellArg v}") cfg.shellAliases ); dirHashesStr = concatStringsSep "\n" ( mapAttrsToList (k: v: ''hash -d ${k}="${v}"'') cfg.dirHashes ); - # Absolute paths are assigned unmutated, relative paths - # are prepended with the user's home directory. - zdotdir = (strings.optionalString (!strings.hasPrefix "/" cfg.dotDir) - config.home.homeDirectory) + escapeShellArg cfg.dotDir; - bindkeyCommands = { emacs = "bindkey -e"; viins = "bindkey -v"; @@ -66,14 +70,9 @@ let path = mkOption { type = types.str; - default = if versionAtLeast stateVersion "20.03" - then "$HOME/.zsh_history" - else relToDotDir ".zsh_history"; - defaultText = literalExpression '' - "$HOME/.zsh_history" if state version ≥ 20.03, - "$ZDOTDIR/.zsh_history" otherwise - ''; - example = literalExpression ''"''${config.xdg.dataHome}/zsh/zsh_history"''; + default = "${dotDirParsed}/.zsh_history"; + defaultText = "`\${config.programs.zsh.dotDir}/.zsh_history`"; + example = "`\${config.xdg.dataHome}/zsh/zsh_history`"; description = "History file location"; }; @@ -183,7 +182,7 @@ let custom = mkOption { default = ""; type = types.str; - example = "$HOME/my_customizations"; + example = "\${config.home.homeDirectory}/my_customizations"; description = '' Path to a custom oh-my-zsh package to override config of oh-my-zsh. See @@ -307,12 +306,14 @@ in }; dotDir = mkOption { - default = null; - example = ".config/zsh"; + default = homeDir; + defaultText = "`config.home.homeDirectory`"; + example = "`\${config.xdg.configHome}/zsh`"; description = '' - Directory where the zsh configuration should be located. The default - is the home directory. This option accepts absolute paths, or paths - relative to `config.home.homeDirectory`. + Custom directory for zsh configuration and data. If unset, .zshrc, + .zshenv and similar are stored in the user's home directory, while + plugins and other data are stored in `.zsh/`. This option accepts + absolute paths, or paths relative to the user's home directory. ''; type = types.nullOr types.str; }; @@ -351,9 +352,9 @@ in default = {}; example = literalExpression '' { - docs = "$HOME/Documents"; - vids = "$HOME/Videos"; - dl = "$HOME/Downloads"; + docs = "''${config.home.homeDirectory}/Documents"; + vids = "''${config.home.homeDirectory}/Videos"; + dl = "''${config.home.homeDirectory)/Downloads"; } ''; description = '' @@ -544,31 +545,31 @@ in config = mkIf cfg.enable (mkMerge [ (mkIf (cfg.envExtra != "") { - home.file."${relToDotDir ".zshenv"}".text = cfg.envExtra; + home.file."${dotDirRelToHome}/.zshenv".text = cfg.envExtra; }) (mkIf (cfg.profileExtra != "") { - home.file."${relToDotDir ".zprofile"}".text = cfg.profileExtra; + home.file."${dotDirRelToHome}/.zprofile".text = cfg.profileExtra; }) (mkIf (cfg.loginExtra != "") { - home.file."${relToDotDir ".zlogin"}".text = cfg.loginExtra; + home.file."${dotDirRelToHome}/.zlogin".text = cfg.loginExtra; }) (mkIf (cfg.logoutExtra != "") { - home.file."${relToDotDir ".zlogout"}".text = cfg.logoutExtra; + home.file."${dotDirRelToHome}/.zlogout".text = cfg.logoutExtra; }) (mkIf cfg.oh-my-zsh.enable { - home.file."${relToDotDir ".zshenv"}".text = '' + home.file."${dotDirRelToHome}/.zshenv".text = '' ZSH="${cfg.oh-my-zsh.package}/share/oh-my-zsh"; ZSH_CACHE_DIR="${config.xdg.cacheHome}/oh-my-zsh"; ''; }) - (mkIf (cfg.dotDir != null) { - home.file."${relToDotDir ".zshenv"}".text = '' - export ZDOTDIR=${zdotdir} + (mkIf (dotDirParsed != homeDir) { + home.file."${dotDirRelToHome}/.zshenv".text = '' + export ZDOTDIR=${dotDirParsed} ''; # When dotDir is set, only use ~/.zshenv to source ZDOTDIR/.zshenv, @@ -576,12 +577,12 @@ in # already set correctly (by e.g. spawning a zsh inside a zsh), all env # vars still get exported home.file.".zshenv".text = '' - source ${zdotdir}/.zshenv + source ${dotDirParsed}/.zshenv ''; }) { - home.file."${relToDotDir ".zshenv"}".text = '' + home.file."${dotDirRelToHome}/.zshenv".text = '' # Environment variables . "${config.home.profileDirectory}/etc/profile.d/hm-session-vars.sh" @@ -598,7 +599,7 @@ in ++ optional cfg.enableCompletion pkgs.nix-zsh-completions ++ optional cfg.oh-my-zsh.enable cfg.oh-my-zsh.package; - home.file."${relToDotDir ".zshrc"}".text = concatStringsSep "\n" ([ + home.file."${dotDirRelToHome}/.zshrc".text = concatStringsSep "\n" ([ # zprof must be loaded before everything else, since it # benchmarks the shell initialization. (optionalString cfg.zprof.enable '' @@ -679,7 +680,7 @@ in # See https://github.com/nix-community/home-manager/issues/177. HISTSIZE="${toString cfg.history.size}" SAVEHIST="${toString cfg.history.save}" - ${optionalString (cfg.history.ignorePatterns != []) "HISTORY_IGNORE=${lib.escapeShellArg "(${lib.concatStringsSep "|" cfg.history.ignorePatterns})"}"} + ${optionalString (cfg.history.ignorePatterns != []) "HISTORY_IGNORE=${escapeShellArg "(${concatStringsSep "|" cfg.history.ignorePatterns})"}"} ${if versionAtLeast config.home.stateVersion "20.03" then ''HISTFILE="${cfg.history.path}"'' else ''HISTFILE="$HOME/${cfg.history.path}"''} @@ -701,7 +702,7 @@ in ${aliasesStr} '' ] - ++ (mapAttrsToList (k: v: "alias -g -- ${lib.escapeShellArg k}=${lib.escapeShellArg v}") cfg.shellGlobalAliases) + ++ (mapAttrsToList (k: v: "alias -g -- ${escapeShellArg k}=${escapeShellArg v}") cfg.shellGlobalAliases) ++ [ ('' # Named Directory Hashes ${dirHashesStr} @@ -730,13 +731,13 @@ in # https://github.com/zsh-users/zsh-history-substring-search#usage '' source ${pkgs.zsh-history-substring-search}/share/zsh-history-substring-search/zsh-history-substring-search.zsh - ${lib.concatMapStringsSep "\n" + ${concatMapStringsSep "\n" (upKey: "bindkey \"${upKey}\" history-substring-search-up") - (lib.toList cfg.historySubstringSearch.searchUpKey) + (toList cfg.historySubstringSearch.searchUpKey) } - ${lib.concatMapStringsSep "\n" + ${concatMapStringsSep "\n" (downKey: "bindkey \"${downKey}\" history-substring-search-down") - (lib.toList cfg.historySubstringSearch.searchDownKey) + (toList cfg.historySubstringSearch.searchDownKey) } '')