1# This module defines global configuration for the zshell.
2
3{
4 config,
5 lib,
6 options,
7 pkgs,
8 ...
9}:
10
11let
12
13 cfge = config.environment;
14
15 cfg = config.programs.zsh;
16 opt = options.programs.zsh;
17
18 zshAliases = builtins.concatStringsSep "\n" (
19 lib.mapAttrsToList (k: v: "alias -- ${k}=${lib.escapeShellArg v}") (
20 lib.filterAttrs (k: v: v != null) cfg.shellAliases
21 )
22 );
23
24 zshStartupNotes = ''
25 # Note that generated /etc/zprofile and /etc/zshrc files do a lot of
26 # non-standard setup to make zsh usable with no configuration by default.
27 #
28 # Which means that unless you explicitly meticulously override everything
29 # generated, interactions between your ~/.zshrc and these files are likely
30 # to be rather surprising.
31 #
32 # Note however, that you can disable loading of the generated /etc/zprofile
33 # and /etc/zshrc (you can't disable loading of /etc/zshenv, but it is
34 # designed to not set anything surprising) by setting `no_global_rcs` option
35 # in ~/.zshenv:
36 #
37 # echo setopt no_global_rcs >> ~/.zshenv
38 #
39 # See "STARTUP/SHUTDOWN FILES" section of zsh(1) for more info.
40 '';
41
42in
43
44{
45
46 options = {
47
48 programs.zsh = {
49
50 enable = lib.mkOption {
51 default = false;
52 description = ''
53 Whether to configure zsh as an interactive shell. To enable zsh for
54 a particular user, use the {option}`users.users.<name?>.shell`
55 option for that user. To enable zsh system-wide use the
56 {option}`users.defaultUserShell` option.
57 '';
58 type = lib.types.bool;
59 };
60
61 shellAliases = lib.mkOption {
62 default = { };
63 description = ''
64 Set of aliases for zsh shell, which overrides {option}`environment.shellAliases`.
65 See {option}`environment.shellAliases` for an option format description.
66 '';
67 type = with lib.types; attrsOf (nullOr (either str path));
68 };
69
70 shellInit = lib.mkOption {
71 default = "";
72 description = ''
73 Shell script code called during zsh shell initialisation.
74 '';
75 type = lib.types.lines;
76 };
77
78 loginShellInit = lib.mkOption {
79 default = "";
80 description = ''
81 Shell script code called during zsh login shell initialisation.
82 '';
83 type = lib.types.lines;
84 };
85
86 interactiveShellInit = lib.mkOption {
87 default = "";
88 description = ''
89 Shell script code called during interactive zsh shell initialisation.
90 '';
91 type = lib.types.lines;
92 };
93
94 promptInit = lib.mkOption {
95 default = ''
96 # Note that to manually override this in ~/.zshrc you should run `prompt off`
97 # before setting your PS1 and etc. Otherwise this will likely to interact with
98 # your ~/.zshrc configuration in unexpected ways as the default prompt sets
99 # a lot of different prompt variables.
100 autoload -U promptinit && promptinit && prompt suse && setopt prompt_sp
101 '';
102 description = ''
103 Shell script code used to initialise the zsh prompt.
104 '';
105 type = lib.types.lines;
106 };
107
108 histSize = lib.mkOption {
109 default = 2000;
110 description = ''
111 Change history size.
112 '';
113 type = lib.types.int;
114 };
115
116 histFile = lib.mkOption {
117 default = "$HOME/.zsh_history";
118 description = ''
119 Change history file.
120 '';
121 type = lib.types.str;
122 };
123
124 setOptions = lib.mkOption {
125 type = lib.types.listOf lib.types.str;
126 default = [
127 "HIST_IGNORE_DUPS"
128 "SHARE_HISTORY"
129 "HIST_FCNTL_LOCK"
130 ];
131 example = [
132 "EXTENDED_HISTORY"
133 "RM_STAR_WAIT"
134 ];
135 description = ''
136 Configure zsh options. See
137 {manpage}`zshoptions(1)`.
138 '';
139 };
140
141 enableCompletion = lib.mkOption {
142 default = true;
143 description = ''
144 Enable zsh completion for all interactive zsh shells.
145 '';
146 type = lib.types.bool;
147 };
148
149 enableBashCompletion = lib.mkOption {
150 default = false;
151 description = ''
152 Enable compatibility with bash's programmable completion system.
153 '';
154 type = lib.types.bool;
155 };
156
157 enableGlobalCompInit = lib.mkOption {
158 default = cfg.enableCompletion;
159 defaultText = lib.literalExpression "config.${opt.enableCompletion}";
160 description = ''
161 Enable execution of compinit call for all interactive zsh shells.
162
163 This option can be disabled if the user wants to extend its
164 `fpath` and a custom `compinit`
165 call in the local config is required.
166 '';
167 type = lib.types.bool;
168 };
169
170 enableLsColors = lib.mkOption {
171 default = true;
172 description = ''
173 Enable extra colors in directory listings (used by `ls` and `tree`).
174 '';
175 type = lib.types.bool;
176 };
177
178 };
179
180 };
181
182 config = lib.mkIf cfg.enable {
183
184 programs.zsh.shellAliases = builtins.mapAttrs (name: lib.mkDefault) cfge.shellAliases;
185
186 environment.etc.zshenv.text = ''
187 # /etc/zshenv: DO NOT EDIT -- this file has been generated automatically.
188 # This file is read for all shells.
189
190 # Only execute this file once per shell.
191 if [ -n "''${__ETC_ZSHENV_SOURCED-}" ]; then return; fi
192 __ETC_ZSHENV_SOURCED=1
193
194 if [ -z "''${__NIXOS_SET_ENVIRONMENT_DONE-}" ]; then
195 . ${config.system.build.setEnvironment}
196 fi
197
198 HELPDIR="${pkgs.zsh}/share/zsh/$ZSH_VERSION/help"
199
200 # Tell zsh how to find installed completions.
201 for p in ''${(z)NIX_PROFILES}; do
202 fpath=($p/share/zsh/site-functions $p/share/zsh/$ZSH_VERSION/functions $p/share/zsh/vendor-completions $fpath)
203 done
204
205 # Setup custom shell init stuff.
206 ${cfge.shellInit}
207
208 ${cfg.shellInit}
209
210 # Read system-wide modifications.
211 if test -f /etc/zshenv.local; then
212 . /etc/zshenv.local
213 fi
214 '';
215
216 environment.etc.zprofile.text = ''
217 # /etc/zprofile: DO NOT EDIT -- this file has been generated automatically.
218 # This file is read for login shells.
219 #
220 ${zshStartupNotes}
221
222 # Only execute this file once per shell.
223 if [ -n "''${__ETC_ZPROFILE_SOURCED-}" ]; then return; fi
224 __ETC_ZPROFILE_SOURCED=1
225
226 # Setup custom login shell init stuff.
227 ${cfge.loginShellInit}
228
229 ${cfg.loginShellInit}
230
231 # Read system-wide modifications.
232 if test -f /etc/zprofile.local; then
233 . /etc/zprofile.local
234 fi
235 '';
236
237 environment.etc.zshrc.text = ''
238 # /etc/zshrc: DO NOT EDIT -- this file has been generated automatically.
239 # This file is read for interactive shells.
240 #
241 ${zshStartupNotes}
242
243 # Only execute this file once per shell.
244 if [ -n "$__ETC_ZSHRC_SOURCED" -o -n "$NOSYSZSHRC" ]; then return; fi
245 __ETC_ZSHRC_SOURCED=1
246
247 ${lib.optionalString (cfg.setOptions != [ ]) ''
248 # Set zsh options.
249 setopt ${builtins.concatStringsSep " " cfg.setOptions}
250 ''}
251
252 # Alternative method of determining short and full hostname.
253 HOST=${config.networking.fqdnOrHostName}
254
255 # Setup command line history.
256 # Don't export these, otherwise other shells (bash) will try to use same HISTFILE.
257 SAVEHIST=${builtins.toString cfg.histSize}
258 HISTSIZE=${builtins.toString cfg.histSize}
259 HISTFILE=${cfg.histFile}
260
261 # Configure sane keyboard defaults.
262 . /etc/zinputrc
263
264 ${lib.optionalString cfg.enableGlobalCompInit ''
265 # Enable autocompletion.
266 autoload -U compinit && compinit
267 ''}
268
269 ${lib.optionalString cfg.enableBashCompletion ''
270 # Enable compatibility with bash's completion system.
271 autoload -U bashcompinit && bashcompinit
272 ''}
273
274 # Setup custom interactive shell init stuff.
275 ${cfge.interactiveShellInit}
276
277 ${cfg.interactiveShellInit}
278
279 ${lib.optionalString cfg.enableLsColors ''
280 # Extra colors for directory listings.
281 eval "$(${pkgs.coreutils}/bin/dircolors -b)"
282 ''}
283
284 # Setup aliases.
285 ${zshAliases}
286
287 # Setup prompt.
288 ${cfg.promptInit}
289
290 # Disable some features to support TRAMP.
291 if [ "$TERM" = dumb ]; then
292 unsetopt zle prompt_cr prompt_subst
293 unset RPS1 RPROMPT
294 PS1='$ '
295 PROMPT='$ '
296 fi
297
298 # Read system-wide modifications.
299 if test -f /etc/zshrc.local; then
300 . /etc/zshrc.local
301 fi
302 '';
303
304 # Bug in nix flakes:
305 # If we use `.source` here the path is garbage collected also we point to it with a symlink
306 # see https://github.com/NixOS/nixpkgs/issues/132732
307 environment.etc.zinputrc.text = builtins.readFile ./zinputrc;
308
309 environment.systemPackages = [
310 pkgs.zsh
311 ] ++ lib.optional cfg.enableCompletion pkgs.nix-zsh-completions;
312
313 environment.pathsToLink = lib.optional cfg.enableCompletion "/share/zsh";
314
315 #users.defaultUserShell = lib.mkDefault "/run/current-system/sw/bin/zsh";
316
317 environment.shells = [
318 "/run/current-system/sw/bin/zsh"
319 "${pkgs.zsh}/bin/zsh"
320 ];
321
322 };
323
324}