11//! Shared shell detection and profile helpers.
22
3+ use std:: str:: FromStr ;
4+
35use directories:: BaseDirs ;
46use vite_path:: { AbsolutePath , AbsolutePathBuf } ;
57use vite_str:: Str ;
@@ -19,21 +21,37 @@ pub enum Shell {
1921 Cmd ,
2022}
2123
22- /// Detect the current shell from environment variables.
24+ impl FromStr for Shell {
25+ type Err = ( ) ;
26+
27+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
28+ match s. to_lowercase ( ) . as_str ( ) {
29+ "sh" | "bash" | "zsh" => Ok ( Shell :: Posix ) ,
30+ "fish" => Ok ( Shell :: Fish ) ,
31+ "nu" | "nushell" => Ok ( Shell :: NuShell ) ,
32+ "pwsh" | "powershell" => Ok ( Shell :: PowerShell ) ,
33+ "cmd" => Ok ( Shell :: Cmd ) ,
34+ _ => Err ( ( ) ) ,
35+ }
36+ }
37+ }
38+
39+ /// Detect the current shell:
40+ /// 1. `VP_SHELL` environment variable
41+ /// 2. Platform default
2342#[ must_use]
2443pub fn detect_shell ( ) -> Shell {
2544 let config = vite_shared:: EnvConfig :: get ( ) ;
26- if config. fish_version . is_some ( ) {
27- Shell :: Fish
28- } else if config. vp_shell_nu {
29- Shell :: NuShell
30- } else if config. vp_shell_pwsh {
31- Shell :: PowerShell
32- } else if cfg ! ( windows) {
33- Shell :: Cmd
34- } else {
35- Shell :: Posix
45+
46+ // 1. Check VP_SHELL environment variable
47+ if let Some ( vp_shell) = & config. vp_shell {
48+ if let Ok ( shell) = Shell :: from_str ( vp_shell) {
49+ return shell;
50+ }
3651 }
52+
53+ // 2. Platform default
54+ if cfg ! ( windows) { Shell :: Cmd } else { Shell :: Posix }
3755}
3856
3957/// All shell profile files that interactive terminal sessions may source.
@@ -235,53 +253,98 @@ mod tests {
235253 use super :: * ;
236254
237255 #[ test]
238- fn test_detect_shell_pwsh ( ) {
256+ fn test_shell_from_str ( ) {
257+ // POSIX shells
258+ assert_eq ! ( Shell :: from_str( "sh" ) , Ok ( Shell :: Posix ) ) ;
259+ assert_eq ! ( Shell :: from_str( "bash" ) , Ok ( Shell :: Posix ) ) ;
260+ assert_eq ! ( Shell :: from_str( "zsh" ) , Ok ( Shell :: Posix ) ) ;
261+
262+ // Other shells
263+ assert_eq ! ( Shell :: from_str( "fish" ) , Ok ( Shell :: Fish ) ) ;
264+ assert_eq ! ( Shell :: from_str( "nu" ) , Ok ( Shell :: NuShell ) ) ;
265+ assert_eq ! ( Shell :: from_str( "nushell" ) , Ok ( Shell :: NuShell ) ) ;
266+ assert_eq ! ( Shell :: from_str( "powershell" ) , Ok ( Shell :: PowerShell ) ) ;
267+ assert_eq ! ( Shell :: from_str( "pwsh" ) , Ok ( Shell :: PowerShell ) ) ;
268+ assert_eq ! ( Shell :: from_str( "cmd" ) , Ok ( Shell :: Cmd ) ) ;
269+
270+ // Case insensitive
271+ assert_eq ! ( Shell :: from_str( "SH" ) , Ok ( Shell :: Posix ) ) ;
272+ assert_eq ! ( Shell :: from_str( "BASH" ) , Ok ( Shell :: Posix ) ) ;
273+ assert_eq ! ( Shell :: from_str( "Fish" ) , Ok ( Shell :: Fish ) ) ;
274+ assert_eq ! ( Shell :: from_str( "POWERSHELL" ) , Ok ( Shell :: PowerShell ) ) ;
275+ assert_eq ! ( Shell :: from_str( "Nu" ) , Ok ( Shell :: NuShell ) ) ;
276+
277+ // Invalid
278+ assert ! ( Shell :: from_str( "posix" ) . is_err( ) ) ;
279+ assert ! ( Shell :: from_str( "invalid" ) . is_err( ) ) ;
280+ assert ! ( Shell :: from_str( "" ) . is_err( ) ) ;
281+ }
282+
283+ #[ test]
284+ fn test_detect_shell_vp_shell_explicit ( ) {
239285 let _guard = vite_shared:: EnvConfig :: test_guard ( vite_shared:: EnvConfig {
240- vp_shell_pwsh : true ,
286+ vp_shell : Some ( "nu" . into ( ) ) ,
241287 ..vite_shared:: EnvConfig :: for_test ( )
242288 } ) ;
243289 let shell = detect_shell ( ) ;
244- assert ! ( matches! ( shell, Shell :: PowerShell ) ) ;
290+ assert_eq ! ( shell, Shell :: NuShell ) ;
245291 }
246292
247293 #[ test]
248- fn test_detect_shell_fish ( ) {
294+ fn test_detect_shell_vp_shell_case_insensitive ( ) {
249295 let _guard = vite_shared:: EnvConfig :: test_guard ( vite_shared:: EnvConfig {
250- fish_version : Some ( "3.7.0 " . into ( ) ) ,
296+ vp_shell : Some ( "POWERSHELL " . into ( ) ) ,
251297 ..vite_shared:: EnvConfig :: for_test ( )
252298 } ) ;
253299 let shell = detect_shell ( ) ;
254- assert ! ( matches! ( shell, Shell :: Fish ) ) ;
300+ assert_eq ! ( shell, Shell :: PowerShell ) ;
255301 }
256302
257303 #[ test]
258- fn test_detect_shell_nushell ( ) {
304+ fn test_detect_shell_vp_shell_pwsh_alias ( ) {
259305 let _guard = vite_shared:: EnvConfig :: test_guard ( vite_shared:: EnvConfig {
260- vp_shell_nu : true ,
306+ vp_shell : Some ( "pwsh" . into ( ) ) ,
261307 ..vite_shared:: EnvConfig :: for_test ( )
262308 } ) ;
263309 let shell = detect_shell ( ) ;
264- assert ! ( matches! ( shell, Shell :: NuShell ) ) ;
310+ assert_eq ! ( shell, Shell :: PowerShell ) ;
265311 }
266312
267313 #[ test]
268- fn test_detect_shell_nushell_wins_over_powershell ( ) {
314+ fn test_detect_shell_vp_shell_fish ( ) {
269315 let _guard = vite_shared:: EnvConfig :: test_guard ( vite_shared:: EnvConfig {
270- vp_shell_nu : true ,
271- ps_module_path : Some ( "/some/path" . into ( ) ) ,
316+ vp_shell : Some ( "fish" . into ( ) ) ,
272317 ..vite_shared:: EnvConfig :: for_test ( )
273318 } ) ;
274319 let shell = detect_shell ( ) ;
275- assert ! ( matches! ( shell, Shell :: NuShell ) ) ;
320+ assert_eq ! ( shell, Shell :: Fish ) ;
276321 }
277322
278323 #[ test]
279- fn test_detect_shell_posix_default ( ) {
280- let _guard = vite_shared:: EnvConfig :: test_guard ( vite_shared:: EnvConfig :: for_test ( ) ) ;
324+ fn test_detect_shell_defaults_without_vp_shell ( ) {
325+ let _guard = vite_shared:: EnvConfig :: test_guard ( vite_shared:: EnvConfig {
326+ vp_shell : None ,
327+ ..vite_shared:: EnvConfig :: for_test ( )
328+ } ) ;
329+ let shell = detect_shell ( ) ;
330+ if cfg ! ( windows) {
331+ assert_eq ! ( shell, Shell :: Cmd ) ;
332+ } else {
333+ assert_eq ! ( shell, Shell :: Posix ) ;
334+ }
335+ }
336+
337+ #[ test]
338+ fn test_detect_shell_invalid_vp_shell_falls_back_to_default ( ) {
339+ let _guard = vite_shared:: EnvConfig :: test_guard ( vite_shared:: EnvConfig {
340+ vp_shell : Some ( "invalid" . into ( ) ) ,
341+ ..vite_shared:: EnvConfig :: for_test ( )
342+ } ) ;
281343 let shell = detect_shell ( ) ;
282- #[ cfg( not( windows) ) ]
283- assert ! ( matches!( shell, Shell :: Posix ) ) ;
284- #[ cfg( windows) ]
285- assert ! ( matches!( shell, Shell :: Cmd ) ) ;
344+ if cfg ! ( windows) {
345+ assert_eq ! ( shell, Shell :: Cmd ) ;
346+ } else {
347+ assert_eq ! ( shell, Shell :: Posix ) ;
348+ }
286349 }
287350}
0 commit comments