diff options
Diffstat (limited to 'src/completion.rs')
| -rw-r--r-- | src/completion.rs | 34 |
1 files changed, 33 insertions, 1 deletions
diff --git a/src/completion.rs b/src/completion.rs index 2137b6f..d10aabd 100644 --- a/src/completion.rs +++ b/src/completion.rs @@ -1,4 +1,5 @@ use crate::*; +use std::path::{Path, PathBuf}; use std::{env, fs}; pub struct Suggestion { @@ -80,10 +81,41 @@ pub fn variable_completion(session: Arc<Mutex<Session>>, prefix: BString) -> Vec out } +#[derive(Default)] +pub struct PathCache { + binaries: HashMap<BString, PathBuf>, +} + +fn is_executable(path: &Path) -> bool { + use std::os::unix::fs::PermissionsExt; + fs::metadata(path) + .map(|m| m.permissions().mode() & 0o111 != 0) + .unwrap_or(false) +} + +pub fn populate_path_cache(session: Arc<Mutex<Session>>) { + let path_var = env::var_os("PATH").unwrap(); + + let mut binaries = HashMap::new(); + + for dir in env::split_paths(&path_var) { + if let Ok(entries) = fs::read_dir(&dir) { + for entry in entries.flatten() { + let path = entry.path(); + if path.is_file() && is_executable(&path) { + binaries.insert(path.file_name().unwrap().as_bytes().to_vec(), path); + } + } + } + } + + session.lock().unwrap().path_cache = PathCache { binaries }; +} + pub fn command_completion(session: Arc<Mutex<Session>>, prefix: BString) -> Vec<Suggestion> { let se = session.lock().unwrap(); let mut out = Vec::new(); - for fun in se.funs.keys().chain(se.builtins.keys()) { + for fun in se.funs.keys().chain(se.builtins.keys()).chain(se.path_cache.binaries.keys()) { if fun.starts_with(&prefix) { out.push(Suggestion { display: fun.to_vec(), |
