starship/modules/
nix_shell.rs1use super::{Context, Module, ModuleConfig};
2
3use crate::configs::nix_shell::NixShellConfig;
4use crate::formatter::StringFormatter;
5
6enum NixShellType {
7 Pure,
8 Impure,
9 Unknown,
12}
13
14impl NixShellType {
15 fn detect_shell_type(use_heuristic: bool, context: &Context) -> Option<Self> {
16 use NixShellType::{Impure, Pure, Unknown};
17
18 let shell_type = context.get_env("IN_NIX_SHELL");
19 match shell_type.as_deref() {
20 Some("pure") => return Some(Pure),
21 Some("impure") => return Some(Impure),
22 _ => {}
23 }
24
25 if use_heuristic {
26 Self::in_new_nix_shell(context).map(|()| Unknown)
27 } else {
28 None
29 }
30 }
31
32 fn in_new_nix_shell(context: &Context) -> Option<()> {
35 let path = context.get_env("PATH")?;
36
37 std::env::split_paths(&path)
38 .any(|path| path.starts_with("/nix/store"))
39 .then_some(())
40 }
41}
42
43pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
61 let mut module = context.new_module("nix_shell");
62 let config: NixShellConfig = NixShellConfig::try_load(module.config);
63
64 let shell_name = context.get_env("name");
65 let shell_type = NixShellType::detect_shell_type(config.heuristic, context)?;
66 let shell_type_format = match shell_type {
67 NixShellType::Pure => config.pure_msg,
68 NixShellType::Impure => config.impure_msg,
69 NixShellType::Unknown => config.unknown_msg,
70 };
71
72 let parsed = StringFormatter::new(config.format).and_then(|formatter| {
73 formatter
74 .map_meta(|variable, _| match variable {
75 "symbol" => Some(config.symbol),
76 "state" => Some(shell_type_format),
77 _ => None,
78 })
79 .map_style(|variable| match variable {
80 "style" => Some(Ok(config.style)),
81 _ => None,
82 })
83 .map(|variable| match variable {
84 "name" => shell_name.as_ref().map(Ok),
85 _ => None,
86 })
87 .parse(None, Some(context))
88 });
89
90 module.set_segments(match parsed {
91 Ok(segments) => segments,
92 Err(error) => {
93 log::warn!("Error in module `nix_shell`:\n{error}");
94 return None;
95 }
96 });
97
98 Some(module)
99}
100
101#[cfg(test)]
102mod tests {
103 use crate::test::ModuleRenderer;
104 use nu_ansi_term::Color;
105
106 #[test]
107 fn no_env_variables() {
108 let actual = ModuleRenderer::new("nix_shell").collect();
109 let expected = None;
110
111 assert_eq!(expected, actual);
112 }
113
114 #[test]
115 fn invalid_env_variables() {
116 let actual = ModuleRenderer::new("nix_shell")
117 .env("IN_NIX_SHELL", "something_wrong")
118 .collect();
119 let expected = None;
120
121 assert_eq!(expected, actual);
122 }
123
124 #[test]
125 fn pure_shell() {
126 let actual = ModuleRenderer::new("nix_shell")
127 .env("IN_NIX_SHELL", "pure")
128 .collect();
129 let expected = Some(format!("via {} ", Color::Blue.bold().paint("❄️ pure")));
130
131 assert_eq!(expected, actual);
132 }
133
134 #[test]
135 fn impure_shell() {
136 let actual = ModuleRenderer::new("nix_shell")
137 .env("IN_NIX_SHELL", "impure")
138 .collect();
139 let expected = Some(format!("via {} ", Color::Blue.bold().paint("❄️ impure")));
140
141 assert_eq!(expected, actual);
142 }
143
144 #[test]
145 fn pure_shell_name() {
146 let actual = ModuleRenderer::new("nix_shell")
147 .env("IN_NIX_SHELL", "pure")
148 .env("name", "starship")
149 .collect();
150 let expected = Some(format!(
151 "via {} ",
152 Color::Blue.bold().paint("❄️ pure (starship)")
153 ));
154
155 assert_eq!(expected, actual);
156 }
157
158 #[test]
159 fn impure_shell_name() {
160 let actual = ModuleRenderer::new("nix_shell")
161 .env("IN_NIX_SHELL", "impure")
162 .env("name", "starship")
163 .collect();
164 let expected = Some(format!(
165 "via {} ",
166 Color::Blue.bold().paint("❄️ impure (starship)")
167 ));
168
169 assert_eq!(expected, actual);
170 }
171
172 #[test]
173 fn new_nix_shell() {
174 let actual = ModuleRenderer::new("nix_shell")
175 .env(
176 "PATH",
177 "/nix/store/v7qvqv81jp0cajvrxr9x072jgqc01yhi-nix-info/bin:/Users/user/.cargo/bin",
178 )
179 .config(toml::toml! {
180 [nix_shell]
181 heuristic = true
182 })
183 .collect();
184 let expected = Some(format!("via {} ", Color::Blue.bold().paint("❄️ ")));
185
186 assert_eq!(expected, actual);
187 }
188
189 #[test]
190 fn no_new_nix_shell() {
191 let actual = ModuleRenderer::new("nix_shell")
192 .env("PATH", "/Users/user/.cargo/bin")
193 .config(toml::toml! {
194 [nix_shell]
195 heuristic = true
196 })
197 .collect();
198 let expected = None;
199
200 assert_eq!(expected, actual);
201 }
202
203 #[test]
204 fn no_new_nix_shell_with_nix_store_subdirectory() {
205 let actual = ModuleRenderer::new("nix_shell")
206 .env("PATH", "/Users/user/some/nix/store/subdirectory")
207 .config(toml::toml! {
208 [nix_shell]
209 heuristic = true
210 })
211 .collect();
212 let expected = None;
213
214 assert_eq!(expected, actual);
215 }
216
217 #[test]
218 fn no_new_nix_shell_when_heuristic_is_disabled() {
219 let actual = ModuleRenderer::new("nix_shell")
220 .env(
221 "PATH",
222 "/nix/store/v7qvqv81jp0cajvrxr9x072jgqc01yhi-nix-info/bin:/Users/user/.cargo/bin",
223 )
224 .collect();
225 let expected = None;
226
227 assert_eq!(expected, actual);
228 }
229}