mirror of
https://github.com/zellij-org/zellij.git
synced 2026-10-11 22:50:07 +00:00
fix(windows): prefer PATHEXT variants over bare filename in resolver (#5364)
`find_executable` used to short-circuit on the first exists()-and-is_file match and only consult PATHEXT if no bare file was present. That returned the wrong file for tools whose Windows installer ships both a Unix-style launcher and a `.bat` alongside it. The reported case is Composer, whose setup places bare `composer` (a Unix launcher, invalid PE on Windows) next to `composer.bat`. The bare file was resolved and handed to CreateProcessW, which rejected it with ERROR_BAD_EXE_FORMAT. On Windows, when the candidate has no user-supplied extension, walk PATHEXT first and only fall back to the bare match if nothing matches. This mirrors cmd.exe's and powershell's resolution.
This commit is contained in:
@@ -21,6 +21,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||
* fix: occasional high resource utilization and sluggishness on machines with tens of thousands of concurent processes (https://github.com/zellij-org/zellij/pull/5324)
|
||||
* feat: allow opening panes/tabs from the CLI without changing focus (https://github.com/zellij-org/zellij/pull/5346)
|
||||
* feat: allow binding `SetDarkTheme`, `SetLightTheme` and `ToggleTheme` as direct keybinding actions (https://github.com/zellij-org/zellij/pull/5302)
|
||||
* fix(windows): prefer PATHEXT variants over bare filename when resolving commands (fixes launching `composer` and similar) (https://github.com/zellij-org/zellij/pull/5364)
|
||||
* feat: allow disabling ctrl-mouse-scroll to resize panes (https://github.com/zellij-org/zellij/pull/5283)
|
||||
* fix: scrolling region line wrap behavior at bottom edge (https://github.com/zellij-org/zellij/pull/5357)
|
||||
* fix: properly pad lines before CUF (https://github.com/zellij-org/zellij/pull/5377)
|
||||
|
||||
@@ -37,28 +37,36 @@ pub use async_trait::async_trait;
|
||||
|
||||
/// Check whether a candidate path refers to an executable file, considering
|
||||
/// PATHEXT extensions on Windows (e.g. `.exe`, `.cmd`).
|
||||
///
|
||||
/// On Windows, when the candidate has no extension we try each PATHEXT
|
||||
/// variant BEFORE the bare match, mirroring cmd.exe's resolution. Tools like
|
||||
/// Composer install both `composer` (a Unix launcher) and `composer.bat`
|
||||
/// (the Windows launcher) side by side; returning the bare file would send
|
||||
/// a non-PE binary to CreateProcessW and fail with ERROR_BAD_EXE_FORMAT.
|
||||
fn find_executable(candidate: &std::path::Path) -> Option<PathBuf> {
|
||||
if candidate.exists() && candidate.is_file() {
|
||||
return Some(candidate.to_path_buf());
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
if let Some(pathext) = env::var_os("PATHEXT") {
|
||||
let pathext = pathext.to_string_lossy();
|
||||
for ext in pathext.split(';') {
|
||||
let ext = ext.trim();
|
||||
if ext.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let mut with_ext = candidate.as_os_str().to_os_string();
|
||||
with_ext.push(ext);
|
||||
let with_ext_path = PathBuf::from(with_ext);
|
||||
if with_ext_path.exists() && with_ext_path.is_file() {
|
||||
return Some(with_ext_path);
|
||||
if candidate.extension().is_none() {
|
||||
if let Some(pathext) = env::var_os("PATHEXT") {
|
||||
let pathext = pathext.to_string_lossy();
|
||||
for ext in pathext.split(';') {
|
||||
let ext = ext.trim();
|
||||
if ext.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let mut with_ext = candidate.as_os_str().to_os_string();
|
||||
with_ext.push(ext);
|
||||
let with_ext_path = PathBuf::from(with_ext);
|
||||
if with_ext_path.exists() && with_ext_path.is_file() {
|
||||
return Some(with_ext_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if candidate.exists() && candidate.is_file() {
|
||||
return Some(candidate.to_path_buf());
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user