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