diff --git a/crates/util/src/shell.rs b/crates/util/src/shell.rs index 27ab18b58ce14cc59d57e563103fc9135f93d060..87872856d916ae39809debaeb6c151705367246b 100644 --- a/crates/util/src/shell.rs +++ b/crates/util/src/shell.rs @@ -1012,4 +1012,40 @@ mod tests { "uname".to_string() ); } + + #[test] + fn test_try_quote_single_quote_paths() { + let path_with_quote = r"C:\Temp\O'Brien\repo"; + let shlex_shells = [ + ShellKind::Posix, + ShellKind::Fish, + ShellKind::Csh, + ShellKind::Tcsh, + ShellKind::Rc, + ShellKind::Xonsh, + ShellKind::Elvish, + ShellKind::Nushell, + ]; + + for shell_kind in shlex_shells { + let quoted = shell_kind.try_quote(path_with_quote).unwrap().into_owned(); + assert_ne!(quoted, path_with_quote); + assert_eq!( + shlex::split("ed), + Some(vec![path_with_quote.to_string()]) + ); + + if shell_kind == ShellKind::Nushell { + let prefixed = shell_kind.prepend_command_prefix("ed); + assert!(prefixed.starts_with('^')); + } + } + + for shell_kind in [ShellKind::PowerShell, ShellKind::Pwsh] { + let quoted = shell_kind.try_quote(path_with_quote).unwrap().into_owned(); + assert!(quoted.starts_with('\'')); + assert!(quoted.ends_with('\'')); + assert!(quoted.contains("O''Brien")); + } + } } diff --git a/crates/util/src/shell_env.rs b/crates/util/src/shell_env.rs index 4fc9fd2d69b608c1215495d84c340f11e5be8179..ba9e77cb81086e810af8d17c7f17f2b77f5392d9 100644 --- a/crates/util/src/shell_env.rs +++ b/crates/util/src/shell_env.rs @@ -141,6 +141,14 @@ async fn capture_windows( std::env::current_exe().context("Failed to determine current zed executable path.")?; let shell_kind = ShellKind::new(shell_path, true); + let directory_string = directory.display().to_string(); + let zed_path_string = zed_path.display().to_string(); + let quote_for_shell = |value: &str| { + shell_kind + .try_quote(value) + .map(|quoted| quoted.into_owned()) + .unwrap_or_else(|| value.to_owned()) + }; let mut cmd = crate::command::new_command(shell_path); cmd.args(args); let cmd = match shell_kind { @@ -149,52 +157,54 @@ async fn capture_windows( | ShellKind::Rc | ShellKind::Fish | ShellKind::Xonsh - | ShellKind::Posix => cmd.args([ - "-l", - "-i", - "-c", - &format!( - "cd '{}'; '{}' --printenv", - directory.display(), - zed_path.display() - ), - ]), - ShellKind::PowerShell | ShellKind::Pwsh => cmd.args([ - "-NonInteractive", - "-NoProfile", - "-Command", - &format!( - "Set-Location '{}'; & '{}' --printenv", - directory.display(), - zed_path.display() - ), - ]), - ShellKind::Elvish => cmd.args([ - "-c", - &format!( - "cd '{}'; '{}' --printenv", - directory.display(), - zed_path.display() - ), - ]), - ShellKind::Nushell => cmd.args([ - "-c", - &format!( - "cd '{}'; {}'{}' --printenv", - directory.display(), - shell_kind - .command_prefix() - .map(|prefix| prefix.to_string()) - .unwrap_or_default(), - zed_path.display() - ), - ]), + | ShellKind::Posix => { + let quoted_directory = quote_for_shell(&directory_string); + let quoted_zed_path = quote_for_shell(&zed_path_string); + cmd.args([ + "-l", + "-i", + "-c", + &format!("cd {}; {} --printenv", quoted_directory, quoted_zed_path), + ]) + } + ShellKind::PowerShell | ShellKind::Pwsh => { + let quoted_directory = ShellKind::quote_pwsh(&directory_string); + let quoted_zed_path = ShellKind::quote_pwsh(&zed_path_string); + cmd.args([ + "-NonInteractive", + "-NoProfile", + "-Command", + &format!( + "Set-Location {}; & {} --printenv", + quoted_directory, quoted_zed_path + ), + ]) + } + ShellKind::Elvish => { + let quoted_directory = quote_for_shell(&directory_string); + let quoted_zed_path = quote_for_shell(&zed_path_string); + cmd.args([ + "-c", + &format!("cd {}; {} --printenv", quoted_directory, quoted_zed_path), + ]) + } + ShellKind::Nushell => { + let quoted_directory = quote_for_shell(&directory_string); + let quoted_zed_path = quote_for_shell(&zed_path_string); + let zed_command = shell_kind + .prepend_command_prefix("ed_zed_path) + .into_owned(); + cmd.args([ + "-c", + &format!("cd {}; {} --printenv", quoted_directory, zed_command), + ]) + } ShellKind::Cmd => cmd.args([ "/c", "cd", - &directory.display().to_string(), + &directory_string, "&&", - &zed_path.display().to_string(), + &zed_path_string, "--printenv", ]), }