util: Fix env load issues on Windows due to quoting (#50782)

Closes #47823 

Before you mark this PR as ready for review, make sure that you have:
- [x] Added a solid test coverage and/or screenshots from doing manual
testing
- [x] Done a self-review taking into account security and performance
aspects
- [x] No UI changes
 
Release Notes:

- Solves the issue where env variables failed to load when a project
with dir path had `'`(single quote) in them, for example:
`C:\Temp\O'Brien\project_1`.
- added a zed pre-quote for directory paths and zed executable 
- handled pwsh, nushell, cmd, fish, posix, csh, tcsh, rc, xonsh, elvish
based terminals
-  uses `try_quote` for quoting shell paths
This commit is contained in:
Amaan authored and GitHub committed 2026-03-05 08:33:44 +00:00
1 parent df0b3de25f
commit c091c90faf
2 files changed
+88 -42

No files matched your search

+36
View File
@@ -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(&quoted),
Some(vec![path_with_quote.to_string()])
);
if shell_kind == ShellKind::Nushell {
let prefixed = shell_kind.prepend_command_prefix(&quoted);
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"));
}
}
}
+52 -42
View File
@@ -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(&quoted_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",
]),
}