diff --git a/crates/uv/src/commands/venv.rs b/crates/uv/src/commands/venv.rs index ca3b5e361549..5594111325af 100644 --- a/crates/uv/src/commands/venv.rs +++ b/crates/uv/src/commands/venv.rs @@ -230,7 +230,14 @@ async fn venv_impl( "source {}", shlex_posix(path.join("bin").join("activate.csh")) )), - Some(Shell::Powershell) => Some(shlex_windows(path.join("Scripts").join("activate"))), + Some(Shell::Powershell) => Some(shlex_windows( + path.join("Scripts").join("activate"), + Shell::Powershell, + )), + Some(Shell::Cmd) => Some(shlex_windows( + path.join("Scripts").join("activate"), + Shell::Cmd, + )), }; if let Some(act) = activation { writeln!(printer, "Activate with: {}", act.green()).into_diagnostic()?; @@ -254,15 +261,20 @@ fn shlex_posix(executable: impl AsRef) -> String { } } -/// Quote a path, if necessary, for safe use in `PowerShell`. -fn shlex_windows(executable: impl AsRef) -> String { +/// Quote a path, if necessary, for safe use in `PowerShell` and `cmd`. +fn shlex_windows(executable: impl AsRef, shell: Shell) -> String { // Convert to a display path. let executable = executable.as_ref().simplified_display().to_string(); - // Wrap the executable in quotes (and a `&` invocation) if it contains spaces. - // TODO(charlie): This won't work in `cmd.exe`. + // Wrap the executable in quotes (and a `&` invocation on PowerShell), if it contains spaces. if executable.contains(' ') { - format!("& \"{executable}\"") + if shell == Shell::Powershell { + // For PowerShell, wrap in a `&` invocation. + format!("& \"{executable}\"") + } else { + // Otherwise, assume `cmd`, which doesn't need the `&`. + format!("\"{executable}\"") + } } else { executable } diff --git a/crates/uv/src/shell.rs b/crates/uv/src/shell.rs index cc1cdbdb5da5..d1ec39307991 100644 --- a/crates/uv/src/shell.rs +++ b/crates/uv/src/shell.rs @@ -9,6 +9,8 @@ pub(crate) enum Shell { Fish, /// PowerShell Powershell, + /// Cmd (Command Prompt) + Cmd, /// Z SHell (zsh) Zsh, /// Nushell @@ -34,7 +36,14 @@ impl Shell { } else if let Some(env_shell) = std::env::var_os("SHELL") { Shell::from_shell_path(env_shell) } else if cfg!(windows) { - Some(Shell::Powershell) + // Command Prompt relies on PROMPT for its appearance whereas PowerShell does not. + // See: https://stackoverflow.com/a/66415037. + if std::env::var_os("PROMPT").is_some() { + Some(Shell::Cmd) + } else { + // Fallback to PowerShell if the PROMPT environment variable is not set. + Some(Shell::Powershell) + } } else { None }