1
0
Fork 0
mirror of https://github.com/nix-community/home-manager.git synced 2025-03-20 23:30:07 +00:00

zsh: refactor zsh configuration for better order control over .zshrc (#6479)

* zsh: add initContent option for custom .zshrc content insertion

- Users can add content anywhere by using `lib.mkOrder`, `lib.mkBefore`
and `lib.mkAfter` custom configurations.
- Add test cases to verify the insertion of content before and after
existing configurations in `.zshrc`.
consolidate zshrc content tests into a single priorities test
This commit is contained in:
Qiming Chu 2025-03-13 21:37:11 +08:00 committed by GitHub
parent 1878091234
commit 7832b5aa95
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 177 additions and 117 deletions

View file

@ -2129,6 +2129,17 @@ in {
Cohere, Groq).
'';
}
{
time = "2025-03-11T02:34:43+00:00";
condition = config.programs.zsh.enable;
message = ''
A new module is available: 'programs.zsh.initContent'.
initContent option allows you to set the content of the zshrc file,
you can use `lib.mkOrder` to specify the order of the content you want to insert.
'';
}
];
};
}

View file

@ -471,6 +471,15 @@ in
description = "Environment variables that will be set for zsh session.";
};
initContent = mkOption {
default = "";
type = types.lines;
example = lib.mkOrder 1000 ''
echo "Hello, initContent!"
'';
description = "Content to be added to {file}`.zshrc`. To specify the order, use `lib.mkOrder`.";
};
initExtraBeforeCompInit = mkOption {
default = "";
type = types.lines;
@ -616,158 +625,161 @@ 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" ([
programs.zsh.initContent = mkMerge [
# zprof must be loaded before everything else, since it
# benchmarks the shell initialization.
(optionalString cfg.zprof.enable ''
(mkOrder 400 (optionalString cfg.zprof.enable ''
zmodload zsh/zprof
'')
''))
cfg.initExtraFirst
"typeset -U path cdpath fpath manpath"
(mkOrder 550 cfg.initExtraFirst)
(mkOrder 600 "typeset -U path cdpath fpath manpath")
(optionalString (cfg.cdpath != []) ''
(mkOrder 650 (optionalString (cfg.cdpath != [ ]) ''
cdpath+=(${concatStringsSep " " cfg.cdpath})
''))
(mkOrder 700 ''
for profile in ''${(z)NIX_PROFILES}; do
fpath+=($profile/share/zsh/site-functions $profile/share/zsh/$ZSH_VERSION/functions $profile/share/zsh/vendor-completions)
done
HELPDIR="${cfg.package}/share/zsh/$ZSH_VERSION/help"
'')
''
for profile in ''${(z)NIX_PROFILES}; do
fpath+=($profile/share/zsh/site-functions $profile/share/zsh/$ZSH_VERSION/functions $profile/share/zsh/vendor-completions)
done
HELPDIR="${cfg.package}/share/zsh/$ZSH_VERSION/help"
''
(optionalString (cfg.defaultKeymap != null) ''
(mkOrder 750 (optionalString (cfg.defaultKeymap != null) ''
# Use ${cfg.defaultKeymap} keymap as the default.
${getAttr cfg.defaultKeymap bindkeyCommands}
'')
localVarsStr
''))
cfg.initExtraBeforeCompInit
(mkOrder 800 localVarsStr)
(mkOrder 850 cfg.initExtraBeforeCompInit)
(concatStrings (map (plugin: ''
(mkOrder 900 (concatStrings (map (plugin: ''
path+="$HOME/${pluginsDir}/${plugin.name}"
fpath+="$HOME/${pluginsDir}/${plugin.name}"
'') cfg.plugins))
'') cfg.plugins)))
''
# Oh-My-Zsh/Prezto calls compinit during initialization,
# calling it twice causes slight start up slowdown
# as all $fpath entries will be traversed again.
${optionalString (cfg.enableCompletion && !cfg.oh-my-zsh.enable && !cfg.prezto.enable)
cfg.completionInit
}''
(mkOrder 950 ''
# Oh-My-Zsh/Prezto calls compinit during initialization,
# calling it twice causes slight start up slowdown
# as all $fpath entries will be traversed again.
${optionalString
(cfg.enableCompletion && !cfg.oh-my-zsh.enable && !cfg.prezto.enable)
cfg.completionInit}'')
(optionalString cfg.autosuggestion.enable ''
(mkOrder 1000 (optionalString cfg.autosuggestion.enable ''
source ${pkgs.zsh-autosuggestions}/share/zsh-autosuggestions/zsh-autosuggestions.zsh
${optionalString (cfg.autosuggestion.strategy != []) ''
ZSH_AUTOSUGGEST_STRATEGY=(${concatStringsSep " " cfg.autosuggestion.strategy})
''
}
'')
(optionalString (cfg.autosuggestion.enable && cfg.autosuggestion.highlight != null) ''
ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="${cfg.autosuggestion.highlight}"
${optionalString (cfg.autosuggestion.strategy != [ ]) ''
ZSH_AUTOSUGGEST_STRATEGY=(${
concatStringsSep " " cfg.autosuggestion.strategy
})
''}
''))
(mkOrder 1050 (optionalString
(cfg.autosuggestion.enable && cfg.autosuggestion.highlight != null) ''
ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="${cfg.autosuggestion.highlight}"
''))
(mkOrder 1100 (optionalString cfg.oh-my-zsh.enable ''
# oh-my-zsh extra settings for plugins
${cfg.oh-my-zsh.extraConfig}
# oh-my-zsh configuration generated by NixOS
${optionalString (cfg.oh-my-zsh.plugins != [ ])
"plugins=(${concatStringsSep " " cfg.oh-my-zsh.plugins})"}
${optionalString (cfg.oh-my-zsh.custom != "")
''ZSH_CUSTOM="${cfg.oh-my-zsh.custom}"''}
${optionalString (cfg.oh-my-zsh.theme != "")
''ZSH_THEME="${cfg.oh-my-zsh.theme}"''}
source $ZSH/oh-my-zsh.sh
''))
(mkOrder 1150 ''
${optionalString cfg.prezto.enable (builtins.readFile
"${cfg.prezto.package}/share/zsh-prezto/runcoms/zshrc")}
${concatStrings (map (plugin: ''
if [[ -f "$HOME/${pluginsDir}/${plugin.name}/${plugin.file}" ]]; then
source "$HOME/${pluginsDir}/${plugin.name}/${plugin.file}"
fi
'') cfg.plugins)}
# History options should be set in .zshrc and after oh-my-zsh sourcing.
# 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})"
}"}
${if versionAtLeast config.home.stateVersion "20.03" then
''HISTFILE="${cfg.history.path}"''
else
''HISTFILE="$HOME/${cfg.history.path}"''}
mkdir -p "$(dirname "$HISTFILE")"
setopt HIST_FCNTL_LOCK
${if cfg.history.append then "setopt" else "unsetopt"} APPEND_HISTORY
${if cfg.history.ignoreDups then "setopt" else "unsetopt"} HIST_IGNORE_DUPS
${if cfg.history.ignoreAllDups then "setopt" else "unsetopt"} HIST_IGNORE_ALL_DUPS
${if cfg.history.saveNoDups then "setopt" else "unsetopt"} HIST_SAVE_NO_DUPS
${if cfg.history.findNoDups then "setopt" else "unsetopt"} HIST_FIND_NO_DUPS
${if cfg.history.ignoreSpace then "setopt" else "unsetopt"} HIST_IGNORE_SPACE
${if cfg.history.expireDuplicatesFirst then "setopt" else "unsetopt"} HIST_EXPIRE_DUPS_FIRST
${if cfg.history.share then "setopt" else "unsetopt"} SHARE_HISTORY
${if cfg.history.extended then "setopt" else "unsetopt"} EXTENDED_HISTORY
${if cfg.autocd != null then "${if cfg.autocd then "setopt" else "unsetopt"} autocd" else ""}
'')
(optionalString cfg.oh-my-zsh.enable ''
# oh-my-zsh extra settings for plugins
${cfg.oh-my-zsh.extraConfig}
# oh-my-zsh configuration generated by NixOS
${optionalString (cfg.oh-my-zsh.plugins != [])
"plugins=(${concatStringsSep " " cfg.oh-my-zsh.plugins})"
}
${optionalString (cfg.oh-my-zsh.custom != "")
"ZSH_CUSTOM=\"${cfg.oh-my-zsh.custom}\""
}
${optionalString (cfg.oh-my-zsh.theme != "")
"ZSH_THEME=\"${cfg.oh-my-zsh.theme}\""
}
source $ZSH/oh-my-zsh.sh
'')
''
${optionalString cfg.prezto.enable
(builtins.readFile "${cfg.prezto.package}/share/zsh-prezto/runcoms/zshrc")}
${concatStrings (map (plugin: ''
if [[ -f "$HOME/${pluginsDir}/${plugin.name}/${plugin.file}" ]]; then
source "$HOME/${pluginsDir}/${plugin.name}/${plugin.file}"
fi
'') cfg.plugins)}
# History options should be set in .zshrc and after oh-my-zsh sourcing.
# 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})"}"}
${if versionAtLeast config.home.stateVersion "20.03"
then ''HISTFILE="${cfg.history.path}"''
else ''HISTFILE="$HOME/${cfg.history.path}"''}
mkdir -p "$(dirname "$HISTFILE")"
setopt HIST_FCNTL_LOCK
${if cfg.history.append then "setopt" else "unsetopt"} APPEND_HISTORY
${if cfg.history.ignoreDups then "setopt" else "unsetopt"} HIST_IGNORE_DUPS
${if cfg.history.ignoreAllDups then "setopt" else "unsetopt"} HIST_IGNORE_ALL_DUPS
${if cfg.history.saveNoDups then "setopt" else "unsetopt"} HIST_SAVE_NO_DUPS
${if cfg.history.findNoDups then "setopt" else "unsetopt"} HIST_FIND_NO_DUPS
${if cfg.history.ignoreSpace then "setopt" else "unsetopt"} HIST_IGNORE_SPACE
${if cfg.history.expireDuplicatesFirst then "setopt" else "unsetopt"} HIST_EXPIRE_DUPS_FIRST
${if cfg.history.share then "setopt" else "unsetopt"} SHARE_HISTORY
${if cfg.history.extended then "setopt" else "unsetopt"} EXTENDED_HISTORY
${if cfg.autocd != null then "${if cfg.autocd then "setopt" else "unsetopt"} autocd" else ""}
${cfg.initExtra}
(mkOrder 1200 cfg.initExtra)
# Aliases
${aliasesStr}
''
]
++ (mapAttrsToList (k: v: "alias -g -- ${lib.escapeShellArg k}=${lib.escapeShellArg v}") cfg.shellGlobalAliases)
++ [ (''
# Named Directory Hashes
${dirHashesStr}
(mkOrder 1250 aliasesStr)
(mkOrder 1250 (concatStringsSep "\n" (mapAttrsToList
(k: v: "alias -g -- ${lib.escapeShellArg k}=${lib.escapeShellArg v}")
cfg.shellGlobalAliases)))
(mkOrder 1300 ''
# Named Directory Hashes
${dirHashesStr}
'')
(optionalString cfg.syntaxHighlighting.enable
(mkOrder 1350 (optionalString cfg.syntaxHighlighting.enable
# Load zsh-syntax-highlighting after all custom widgets have been created
# https://github.com/zsh-users/zsh-syntax-highlighting#faq
''
source ${cfg.syntaxHighlighting.package}/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
ZSH_HIGHLIGHT_HIGHLIGHTERS+=(${lib.concatStringsSep " " (map lib.escapeShellArg cfg.syntaxHighlighting.highlighters)})
${lib.concatStringsSep "\n" (
''
source ${cfg.syntaxHighlighting.package}/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
ZSH_HIGHLIGHT_HIGHLIGHTERS+=(${lib.concatStringsSep " " (map lib.escapeShellArg cfg.syntaxHighlighting.highlighters)})
${lib.concatStringsSep "\n" (
lib.mapAttrsToList
(name: value: "ZSH_HIGHLIGHT_STYLES[${lib.escapeShellArg name}]=${lib.escapeShellArg value}")
(name: value: "ZSH_HIGHLIGHT_STYLES[${lib.escapeShellArg name}]=${lib.escapeShellArg value}")
cfg.syntaxHighlighting.styles
)}
${lib.concatStringsSep "\n" (
)}
${lib.concatStringsSep "\n" (
lib.mapAttrsToList
(name: value: "ZSH_HIGHLIGHT_PATTERNS+=(${lib.escapeShellArg name} ${lib.escapeShellArg value})")
cfg.syntaxHighlighting.patterns
)}
'')
)}
''))
(optionalString (cfg.historySubstringSearch.enable or false)
(mkOrder 1400 (optionalString
(cfg.historySubstringSearch.enable or false)
# Load zsh-history-substring-search after zsh-syntax-highlighting
# 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"
(upKey: "bindkey \"${upKey}\" history-substring-search-up")
(lib.toList cfg.historySubstringSearch.searchUpKey)
}
${lib.concatMapStringsSep "\n"
(downKey: "bindkey \"${downKey}\" history-substring-search-down")
(lib.toList cfg.historySubstringSearch.searchDownKey)
}
'')
''
source ${pkgs.zsh-history-substring-search}/share/zsh-history-substring-search/zsh-history-substring-search.zsh
${lib.concatMapStringsSep "\n"
(upKey: ''bindkey "${upKey}" history-substring-search-up'')
(lib.toList cfg.historySubstringSearch.searchUpKey)}
${lib.concatMapStringsSep "\n"
(downKey: ''bindkey "${downKey}" history-substring-search-down'')
(lib.toList cfg.historySubstringSearch.searchDownKey)}
''))
(optionalString cfg.zprof.enable
''
(mkOrder 1450 (optionalString cfg.zprof.enable ''
zprof
'')
]);
''))
];
home.file."${relToDotDir ".zshrc"}".text = cfg.initContent;
}
(mkIf cfg.oh-my-zsh.enable {

View file

@ -9,4 +9,5 @@
zsh-prezto = ./prezto.nix;
zsh-syntax-highlighting = ./syntax-highlighting.nix;
zsh-abbr = ./zsh-abbr.nix;
zshrc-contents-priorities = ./zshrc-content-priorities.nix;
}

View file

@ -0,0 +1,36 @@
{ lib, ... }: {
programs.zsh = {
enable = true;
initContent = lib.mkMerge [
(lib.mkBefore ''
# High priority (mkBefore)
echo "High priority content"
'')
(lib.mkAfter ''
# Low priority (mkAfter)
echo "Low priority content"
'')
''
# Default priority
echo "Default priority content"
''
];
zprof.enable = true;
};
nmt.script = ''
assertFileExists home-files/.zshrc
assertFileContains home-files/.zshrc "zmodload zsh/zprof"
assertFileContains home-files/.zshrc "High priority content"
assertFileContains home-files/.zshrc "Default priority content"
assertFileContains home-files/.zshrc "Low priority content"
assertFileRegex home-files/.zshrc '^zmodload zsh/zprof'
assertFileRegex home-files/.zshrc 'echo "Low priority content"$'
'';
}