1# This module defines global configuration for the Bash shell, in
2# particular /etc/bashrc and /etc/profile.
3
4{ config, lib, pkgs, ... }:
5
6with lib;
7
8let
9
10 cfge = config.environment;
11
12 cfg = config.programs.bash;
13
14 bashCompletion = optionalString cfg.enableCompletion ''
15 # Check whether we're running a version of Bash that has support for
16 # programmable completion. If we do, enable all modules installed in
17 # the system and user profile in obsolete /etc/bash_completion.d/
18 # directories. Bash loads completions in all
19 # $XDG_DATA_DIRS/share/bash-completion/completions/
20 # on demand, so they do not need to be sourced here.
21 if shopt -q progcomp &>/dev/null; then
22 . "${pkgs.bash-completion}/etc/profile.d/bash_completion.sh"
23 nullglobStatus=$(shopt -p nullglob)
24 shopt -s nullglob
25 for p in $NIX_PROFILES; do
26 for m in "$p/etc/bash_completion.d/"*; do
27 . $m
28 done
29 done
30 eval "$nullglobStatus"
31 unset nullglobStatus p m
32 fi
33 '';
34
35 bashAliases = concatStringsSep "\n" (
36 mapAttrsFlatten (k: v: "alias ${k}='${v}'") cfg.shellAliases
37 );
38
39in
40
41{
42 options = {
43
44 programs.bash = {
45
46 /*
47 enable = mkOption {
48 default = true;
49 description = ''
50 Whenever to configure Bash as an interactive shell.
51 Note that this tries to make Bash the default
52 <option>users.defaultUserShell</option>,
53 which in turn means that you might need to explicitly
54 set this variable if you have another shell configured
55 with NixOS.
56 '';
57 type = types.bool;
58 };
59 */
60
61 shellAliases = mkOption {
62 default = config.environment.shellAliases;
63 description = ''
64 Set of aliases for bash shell. See <option>environment.shellAliases</option>
65 for an option format description.
66 '';
67 type = types.attrs; # types.attrsOf types.stringOrPath;
68 };
69
70 shellInit = mkOption {
71 default = "";
72 description = ''
73 Shell script code called during bash shell initialisation.
74 '';
75 type = types.lines;
76 };
77
78 loginShellInit = mkOption {
79 default = "";
80 description = ''
81 Shell script code called during login bash shell initialisation.
82 '';
83 type = types.lines;
84 };
85
86 interactiveShellInit = mkOption {
87 default = "";
88 description = ''
89 Shell script code called during interactive bash shell initialisation.
90 '';
91 type = types.lines;
92 };
93
94 promptInit = mkOption {
95 default = ''
96 # Provide a nice prompt if the terminal supports it.
97 if [ "$TERM" != "dumb" -o -n "$INSIDE_EMACS" ]; then
98 PROMPT_COLOR="1;31m"
99 let $UID && PROMPT_COLOR="1;32m"
100 PS1="\n\[\033[$PROMPT_COLOR\][\u@\h:\w]\\$\[\033[0m\] "
101 if test "$TERM" = "xterm"; then
102 PS1="\[\033]2;\h:\u:\w\007\]$PS1"
103 fi
104 fi
105 '';
106 description = ''
107 Shell script code used to initialise the bash prompt.
108 '';
109 type = types.lines;
110 };
111
112 enableCompletion = mkOption {
113 default = true;
114 description = ''
115 Enable Bash completion for all interactive bash shells.
116 '';
117 type = types.bool;
118 };
119
120 };
121
122 };
123
124 config = /* mkIf cfg.enable */ {
125
126 programs.bash = {
127
128 shellInit = ''
129 ${config.system.build.setEnvironment.text}
130
131 ${cfge.shellInit}
132 '';
133
134 loginShellInit = cfge.loginShellInit;
135
136 interactiveShellInit = ''
137 # Check the window size after every command.
138 shopt -s checkwinsize
139
140 # Disable hashing (i.e. caching) of command lookups.
141 set +h
142
143 ${cfg.promptInit}
144 ${bashCompletion}
145 ${bashAliases}
146
147 ${cfge.interactiveShellInit}
148 '';
149
150 };
151
152 environment.etc."profile".text =
153 ''
154 # /etc/profile: DO NOT EDIT -- this file has been generated automatically.
155 # This file is read for login shells.
156
157 # Only execute this file once per shell.
158 if [ -n "$__ETC_PROFILE_SOURCED" ]; then return; fi
159 __ETC_PROFILE_SOURCED=1
160
161 # Prevent this file from being sourced by interactive non-login child shells.
162 export __ETC_PROFILE_DONE=1
163
164 ${cfg.shellInit}
165 ${cfg.loginShellInit}
166
167 # Read system-wide modifications.
168 if test -f /etc/profile.local; then
169 . /etc/profile.local
170 fi
171
172 if [ -n "''${BASH_VERSION:-}" ]; then
173 . /etc/bashrc
174 fi
175 '';
176
177 environment.etc."bashrc".text =
178 ''
179 # /etc/bashrc: DO NOT EDIT -- this file has been generated automatically.
180
181 # Only execute this file once per shell.
182 if [ -n "$__ETC_BASHRC_SOURCED" -o -n "$NOSYSBASHRC" ]; then return; fi
183 __ETC_BASHRC_SOURCED=1
184
185 # If the profile was not loaded in a parent process, source
186 # it. But otherwise don't do it because we don't want to
187 # clobber overridden values of $PATH, etc.
188 if [ -z "$__ETC_PROFILE_DONE" ]; then
189 . /etc/profile
190 fi
191
192 # We are not always an interactive shell.
193 if [ -n "$PS1" ]; then
194 ${cfg.interactiveShellInit}
195 fi
196
197 # Read system-wide modifications.
198 if test -f /etc/bashrc.local; then
199 . /etc/bashrc.local
200 fi
201 '';
202
203 # Configuration for readline in bash. We use "option default"
204 # priority to allow user override using both .text and .source.
205 environment.etc."inputrc".source = mkOptionDefault ./inputrc;
206
207 users.defaultUserShell = mkDefault pkgs.bashInteractive;
208
209 environment.pathsToLink = optionals cfg.enableCompletion [
210 "/etc/bash_completion.d"
211 "/share/bash-completion"
212 ];
213
214 environment.systemPackages = optional cfg.enableCompletion
215 pkgs.nix-bash-completions;
216
217 environment.shells =
218 [ "/run/current-system/sw/bin/bash"
219 "/var/run/current-system/sw/bin/bash"
220 "/run/current-system/sw/bin/sh"
221 "/var/run/current-system/sw/bin/sh"
222 "${pkgs.bashInteractive}/bin/bash"
223 "${pkgs.bashInteractive}/bin/sh"
224 ];
225
226 };
227
228}