diff options
| author | Jonas Maier <> | 2026-03-10 17:03:16 +0100 |
|---|---|---|
| committer | Jonas Maier <> | 2026-03-10 17:03:16 +0100 |
| commit | fb443270b14ad4d404f6b401f83b323a9769e667 (patch) | |
| tree | 142eb56303c5e6b17ccb9f93af992bc082a11778 | |
| parent | 27ee3f07c39f3f584fac4a8712dd4fe97e46e462 (diff) | |
| download | pish-fb443270b14ad4d404f6b401f83b323a9769e667.tar.gz | |
command-name completion based on PATH
| -rw-r--r-- | src/completion.rs | 34 | ||||
| -rw-r--r-- | src/main.rs | 5 |
2 files changed, 38 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(), diff --git a/src/main.rs b/src/main.rs index 5e7d40a..7a8d864 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,6 +30,7 @@ pub mod serialization; use linebuf::LineBuf; use raw::*; +use crate::completion::PathCache; use crate::cursor::{Direction, move_cursor}; use crate::history::HistoryEntry; use crate::parse::{Ast, PreExpansion}; @@ -74,6 +75,7 @@ pub struct Session { vars: HashMap<BString, BString>, funs: HashMap<BString, Ast<PreExpansion>>, socket_running: Option<export_fun::SocketRunning>, + path_cache: PathCache, /// n before end of history.len() /// 0 == not checking history @@ -270,11 +272,14 @@ fn event_loop() { socket_running: None, vars: HashMap::new(), funs: HashMap::new(), + path_cache: Default::default(), }; print!("{}", se.prompt()); let session = Arc::new(Mutex::new(se)); + completion::populate_path_cache(session.clone()); + let _sock_dropper = export_fun::listen(session.clone()); loop { |
