aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/completion.rs34
-rw-r--r--src/main.rs5
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 {