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