mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-28 13:53:10 +00:00
Work around $PATH issues under WSL (#10506)
A common complaint has been the massive amount of directories Windows appends to $PATH slowing down fish when it attempts to find a non-existent binary (which it does a lot more often than someone not in the know might think). The typical workaround suggested is to trim unneeded entries from $PATH, but this a) has considerable friction, b) breaks resolution of Windows binaries (you can no longer use `clip.exe`, `cmd.exe`, etc). This patch introduces a two-PATH workaround. If the cmd we are executing does not contain a period (i.e. has no extension) it by definition cannot be a Windows executable. In this case, we skip searching for it in any of the auto-mounted, auto-PATH-appended directories like `/mnt/c/Windows/` or `/mnt/c/Program Files`, but we *do* include those directories if what we're searching for could be a Windows executable. (For now, instead of hard-coding a list of known Windows executable extensions like .bat, .cmd, .exe, etc, we just depend on the presence of an extension at all). e.g. this is what starting up fish prints with logging enabled (that has been removed): bypassing 100 dirs for lookup of kill bypassing 100 dirs for lookup of zoxide bypassing 100 dirs for lookup of zoxide bypassing 100 dirs for lookup of fd not bypassing dirs for lookup of open.exe not bypassing dirs for lookup of git.exe This has resulted in a massive speedup of common fish functions, especially anywhere we internally use or perform the equivalent of `if command -q foo`. Note that the `is_windows_subsystem_for_linux()` check will need to be patched to extend this workaround to WSLv2, but I'll do that separately. Under WSL: * Benchmark `external_cmds` improves by 10% * Benchmark `load_completions` improves by an incredible 77%
This commit is contained in:
parent
bd4e5fe69a
commit
3374692b91
1 changed files with 25 additions and 1 deletions
26
src/path.rs
26
src/path.rs
|
@ -2,7 +2,7 @@
|
|||
//! for testing if a command with a given name can be found in the PATH, and various other
|
||||
//! path-related issues.
|
||||
|
||||
use crate::common::wcs2zstring;
|
||||
use crate::common::{is_windows_subsystem_for_linux as is_wsl, wcs2zstring};
|
||||
use crate::env::{EnvMode, EnvStack, Environment};
|
||||
use crate::expand::{expand_tilde, HOME_DIRECTORY};
|
||||
use crate::flog::{FLOG, FLOGF};
|
||||
|
@ -308,6 +308,30 @@ fn path_get_path_core<S: AsRef<wstr>>(cmd: &wstr, pathsv: &[S]) -> GetPathResult
|
|||
return GetPathResult::new(test_path(cmd).err(), cmd.to_owned());
|
||||
}
|
||||
|
||||
// WSLv1/WSLv2 tack on the entire Windows PATH to the end of the PATH environment variable, and
|
||||
// accessing these paths from WSL binaries is pathalogically slow. We also don't expect to find
|
||||
// any "normal" nix binaries under these paths, so we can skip them unless we are executing bins
|
||||
// with Windows-ish names. We try to keep paths manually added to $fish_user_paths by only
|
||||
// chopping off entries after the last "normal" PATH entry.
|
||||
let pathsv = if is_wsl() && !cmd.contains('.') {
|
||||
let win_path_count = pathsv
|
||||
.iter()
|
||||
.rev()
|
||||
.take_while(|p| {
|
||||
let p = p.as_ref();
|
||||
p.starts_with("/mnt/")
|
||||
&& p.chars()
|
||||
.skip("/mnt/x".len())
|
||||
.next()
|
||||
.map(|c| c == '/')
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.count();
|
||||
&pathsv[..pathsv.len() - win_path_count]
|
||||
} else {
|
||||
&pathsv
|
||||
};
|
||||
|
||||
let mut best = noent_res;
|
||||
for next_path in pathsv {
|
||||
let next_path: &wstr = next_path.as_ref();
|
||||
|
|
Loading…
Reference in a new issue