windows: Detect pwsh (#25713)

Closes #22015


Release Notes:

- N/A
This commit is contained in:
张小白 2025-03-25 13:31:11 +08:00 committed by GitHub
parent fca7ce9a14
commit b85492bd00
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 118 additions and 2 deletions

View file

@ -434,8 +434,10 @@ impl ShellBuilder {
// `alacritty_terminal` uses this as default on Windows. See: // `alacritty_terminal` uses this as default on Windows. See:
// https://github.com/alacritty/alacritty/blob/0d4ab7bca43213d96ddfe40048fc0f922543c6f8/alacritty_terminal/src/tty/windows/mod.rs#L130 // https://github.com/alacritty/alacritty/blob/0d4ab7bca43213d96ddfe40048fc0f922543c6f8/alacritty_terminal/src/tty/windows/mod.rs#L130
// We could use `util::retrieve_system_shell()` here, but we are running tasks here, so leave it to `powershell.exe`
// should be okay.
fn system_shell() -> String { fn system_shell() -> String {
"powershell".to_owned() "powershell.exe".to_string()
} }
fn to_windows_shell_variable(&self, input: String) -> String { fn to_windows_shell_variable(&self, input: String) -> String {

View file

@ -376,7 +376,19 @@ impl TerminalBuilder {
let pty_options = { let pty_options = {
let alac_shell = match shell.clone() { let alac_shell = match shell.clone() {
Shell::System => None, Shell::System => {
#[cfg(target_os = "windows")]
{
Some(alacritty_terminal::tty::Shell::new(
util::retrieve_system_shell(),
Vec::new(),
))
}
#[cfg(not(target_os = "windows"))]
{
None
}
}
Shell::Program(program) => { Shell::Program(program) => {
Some(alacritty_terminal::tty::Shell::new(program, Vec::new())) Some(alacritty_terminal::tty::Shell::new(program, Vec::new()))
} }

View file

@ -416,6 +416,108 @@ pub fn iterate_expanded_and_wrapped_usize_range(
} }
} }
#[cfg(target_os = "windows")]
pub fn retrieve_system_shell() -> String {
use std::path::PathBuf;
fn find_pwsh_in_programfiles(find_alternate: bool, find_preview: bool) -> Option<PathBuf> {
#[cfg(target_pointer_width = "64")]
let env_var = if find_alternate {
"ProgramFiles(x86)"
} else {
"ProgramFiles"
};
#[cfg(target_pointer_width = "32")]
let env_var = if find_alternate {
"ProgramW6432"
} else {
"ProgramFiles"
};
let install_base_dir = PathBuf::from(std::env::var_os(env_var)?).join("PowerShell");
install_base_dir
.read_dir()
.ok()?
.filter_map(Result::ok)
.filter(|entry| matches!(entry.file_type(), Ok(ft) if ft.is_dir()))
.filter_map(|entry| {
let dir_name = entry.file_name();
let dir_name = dir_name.to_string_lossy();
let version = if find_preview {
let dash_index = dir_name.find('-')?;
if &dir_name[dash_index + 1..] != "preview" {
return None;
};
dir_name[..dash_index].parse::<u32>().ok()?
} else {
dir_name.parse::<u32>().ok()?
};
let exe_path = entry.path().join("pwsh.exe");
if exe_path.exists() {
Some((version, exe_path))
} else {
None
}
})
.max_by_key(|(version, _)| *version)
.map(|(_, path)| path)
}
fn find_pwsh_in_msix(find_preview: bool) -> Option<PathBuf> {
let msix_app_dir =
PathBuf::from(std::env::var_os("LOCALAPPDATA")?).join("Microsoft\\WindowsApps");
if !msix_app_dir.exists() {
return None;
}
let prefix = if find_preview {
"Microsoft.PowerShellPreview_"
} else {
"Microsoft.PowerShell_"
};
msix_app_dir
.read_dir()
.ok()?
.filter_map(|entry| {
let entry = entry.ok()?;
if !matches!(entry.file_type(), Ok(ft) if ft.is_dir()) {
return None;
}
if !entry.file_name().to_string_lossy().starts_with(prefix) {
return None;
}
let exe_path = entry.path().join("pwsh.exe");
exe_path.exists().then_some(exe_path)
})
.next()
}
fn find_pwsh_in_scoop() -> Option<PathBuf> {
let pwsh_exe =
PathBuf::from(std::env::var_os("USERPROFILE")?).join("scoop\\shims\\pwsh.exe");
pwsh_exe.exists().then_some(pwsh_exe)
}
static SYSTEM_SHELL: LazyLock<String> = LazyLock::new(|| {
find_pwsh_in_programfiles(false, false)
.or_else(|| find_pwsh_in_programfiles(true, false))
.or_else(|| find_pwsh_in_msix(false))
.or_else(|| find_pwsh_in_programfiles(false, true))
.or_else(|| find_pwsh_in_msix(true))
.or_else(|| find_pwsh_in_programfiles(true, true))
.or_else(find_pwsh_in_scoop)
.map(|p| p.to_string_lossy().to_string())
.unwrap_or("powershell.exe".to_string())
});
(*SYSTEM_SHELL).clone()
}
pub trait ResultExt<E> { pub trait ResultExt<E> {
type Ok; type Ok;