1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7
8let
9 cfg = config.programs.starship;
10
11 settingsFormat = pkgs.formats.toml { };
12
13 userSettingsFile = settingsFormat.generate "starship.toml" cfg.settings;
14
15 settingsFile =
16 if cfg.presets == [ ] then
17 userSettingsFile
18 else
19 pkgs.runCommand "starship.toml"
20 {
21 nativeBuildInputs = [ pkgs.yq ];
22 }
23 ''
24 tomlq -s -t 'reduce .[] as $item ({}; . * $item)' \
25 ${
26 lib.concatStringsSep " " (map (f: "${cfg.package}/share/starship/presets/${f}.toml") cfg.presets)
27 } \
28 ${userSettingsFile} \
29 > $out
30 '';
31
32 initOption = if cfg.interactiveOnly then "promptInit" else "shellInit";
33
34in
35{
36 options.programs.starship = {
37 enable = lib.mkEnableOption "the Starship shell prompt";
38
39 package = lib.mkPackageOption pkgs "starship" { };
40
41 interactiveOnly =
42 lib.mkEnableOption ''
43 starship only when the shell is interactive.
44 Some plugins require this to be set to false to function correctly
45 ''
46 // {
47 default = true;
48 };
49
50 presets = lib.mkOption {
51 default = [ ];
52 example = [ "nerd-font-symbols" ];
53 type = with lib.types; listOf str;
54 description = ''
55 Presets files to be merged with settings in order.
56 '';
57 };
58
59 settings = lib.mkOption {
60 inherit (settingsFormat) type;
61 default = { };
62 description = ''
63 Configuration included in `starship.toml`.
64
65 See https://starship.rs/config/#prompt for documentation.
66 '';
67 };
68
69 transientPrompt =
70 let
71 mkTransientPromptOption =
72 side:
73 lib.mkOption {
74 type =
75 with lib.types;
76 nullOr (str // { description = "Fish shell code concatenated with \"\\n\""; });
77 description =
78 let
79 function = "`starship_transient_${lib.optionalString (side == "right") "r"}prompt_func` function";
80 in
81 ''
82 Fish code composing the body of the ${function}. The output of
83 this code will become the ${side} side of the transient prompt.
84
85 Not setting this option (or setting it to `null`) will prevent
86 the ${function} from being generated. By default, the ${side}
87 prompt is ${if (side == "right") then "empty" else "a bold-green '❯' character"}.
88 '';
89 example = "starship module ${if (side == "right") then "time" else "character"}";
90 default = null;
91 };
92 in
93 {
94 enable = lib.mkEnableOption ''
95 Starship's [transient prompt](https://starship.rs/advanced-config/#transientprompt-and-transientrightprompt-in-fish)
96 feature in `fish` shells. After a command has been entered, Starship
97 replaces the usual prompt with the terminal output of the commands
98 defined in the `programs.starship.transientPrompt.left`
99 and `programs.starship.transientPrompt.right` options.
100
101 This option only works with `fish`, as `bash` requires a
102 [custom configuration](https://starship.rs/advanced-config/#transientprompt-and-transientrightprompt-in-bash)
103 involving [Ble.sh](https://github.com/akinomyoga/ble.sh), which can be
104 enabled with `programs.bash.blesh.enable`, but not configured using NixOS
105 '';
106 left = mkTransientPromptOption "left";
107 right = mkTransientPromptOption "right";
108 };
109 };
110
111 config = lib.mkIf cfg.enable {
112 programs.bash.${initOption} = ''
113 if [[ $TERM != "dumb" ]]; then
114 # don't set STARSHIP_CONFIG automatically if there's a user-specified
115 # config file. starship appears to use a hardcoded config location
116 # rather than one inside an XDG folder:
117 # https://github.com/starship/starship/blob/686bda1706e5b409129e6694639477a0f8a3f01b/src/configure.rs#L651
118 if [[ ! -f "$HOME/.config/starship.toml" ]]; then
119 export STARSHIP_CONFIG=${settingsFile}
120 fi
121 eval "$(${cfg.package}/bin/starship init bash)"
122 fi
123 '';
124
125 programs.fish.${initOption} = ''
126 if test "$TERM" != "dumb"
127 # don't set STARSHIP_CONFIG automatically if there's a user-specified
128 # config file. starship appears to use a hardcoded config location
129 # rather than one inside an XDG folder:
130 # https://github.com/starship/starship/blob/686bda1706e5b409129e6694639477a0f8a3f01b/src/configure.rs#L651
131 if not test -f "$HOME/.config/starship.toml";
132 set -x STARSHIP_CONFIG ${settingsFile}
133 end
134 ${lib.optionalString (!isNull cfg.transientPrompt.left) ''
135 function starship_transient_prompt_func
136 ${cfg.transientPrompt.left}
137 end
138 ''}
139 ${lib.optionalString (!isNull cfg.transientPrompt.right) ''
140 function starship_transient_rprompt_func
141 ${cfg.transientPrompt.right}
142 end
143 ''}
144 eval (${cfg.package}/bin/starship init fish)
145 ${lib.optionalString cfg.transientPrompt.enable "enable_transience"}
146 end
147 '';
148
149 programs.zsh.${initOption} = ''
150 if [[ $TERM != "dumb" ]]; then
151 # don't set STARSHIP_CONFIG automatically if there's a user-specified
152 # config file. starship appears to use a hardcoded config location
153 # rather than one inside an XDG folder:
154 # https://github.com/starship/starship/blob/686bda1706e5b409129e6694639477a0f8a3f01b/src/configure.rs#L651
155 if [[ ! -f "$HOME/.config/starship.toml" ]]; then
156 export STARSHIP_CONFIG=${settingsFile}
157 fi
158 eval "$(${cfg.package}/bin/starship init zsh)"
159 fi
160 '';
161 };
162
163 meta.maintainers = pkgs.starship.meta.maintainers;
164}