diff options
author | Rory Dudley | 2024-02-19 00:57:51 -0700 |
---|---|---|
committer | Rory Dudley | 2024-02-19 00:57:51 -0700 |
commit | b1a7db048e517ff262dc1dad0f0ea766af4bd021 (patch) | |
tree | bc7ebd313be07d9f5454fa4381f177984699cbe6 /src/main.rs | |
parent | 6cf0f1b12e880f3cd88f013a070406bfb303831a (diff) | |
download | dwarvish-b1a7db048e517ff262dc1dad0f0ea766af4bd021.tar.gz |
Support for inotifyinotify
This is a branch with some cursory support for using inotify to watch
for changes in the user's $PATH.
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 105 |
1 files changed, 82 insertions, 23 deletions
diff --git a/src/main.rs b/src/main.rs index 7fc8991..c11b939 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,20 +1,71 @@ use ctrlc; +use notify::RecursiveMode; +use notify::Watcher; +use signals2::*; use std::fs; use std::io; use std::io::Write; use std::path::Path; use std::process::Command; - -fn eval(paths: &[&str], prompt: &str) { - let mut bins: Vec<String> = Vec::new(); - - for path in paths { - let files = fs::read_dir(path).expect("Unable to read files in your path"); +use std::sync::Arc; +use std::sync::RwLock; + +fn prefresh(paths: &Vec<String>, bins: &mut Arc<RwLock<Vec<Vec<String>>>>, index: Option<i32>) { + let mut bins = bins.write().unwrap(); + let index = index.unwrap_or(-1); + + if index == -1 { + for (i, path) in paths.iter().enumerate() { + let files = fs::read_dir(path).expect("Unable to read files in your path"); + bins.push(Vec::new()); + for file in files { + bins[i].push(file.unwrap().path().display().to_string()); + } + } + } else { + let index = index as usize; + let files = fs::read_dir(paths[index].as_str()).expect("Unable to read files in your path"); + bins[index].clear(); for file in files { - bins.push(file.unwrap().path().display().to_string()); + bins[index].push(file.unwrap().path().display().to_string()); } } +} + +fn eval(paths: Vec<String>, prompt: &str) { + // Setup search for our paths + let mut bins = Arc::new(RwLock::new(Vec::new())); + prefresh(&paths, &mut bins, None); + + // Handle file changes on paths + let sig: Signal<(i32,)> = Signal::new(); + let arcbins = Arc::clone(&bins); + let p = paths.clone(); + sig.connect(move |i| { + let mut arcbins = arcbins.clone(); + prefresh(&paths, &mut arcbins, Some(i)); + }); + + let mut watcher = + notify::recommended_watcher(move |res: Result<notify::event::Event, notify::Error>| { + match res { + Ok(event) => { + if event.kind.is_create() || event.kind.is_remove() { + sig.emit(0); + } + } + Err(_) => {} + } + }) + .unwrap(); + + for path in p { + watcher + .watch(Path::new(path.as_str()), RecursiveMode::Recursive) + .unwrap(); + } + // Main REPL loop { // Output the prompt io::stdout().flush().unwrap(); @@ -43,7 +94,7 @@ fn eval(paths: &[&str], prompt: &str) { // Parse command and arguments let mut split = input.split(' '); - let mut cmd = match split.next() { + let cmd = match split.next() { Some(str) if str.trim().is_empty() => continue, Some(str) => str.trim(), None => continue, @@ -77,13 +128,21 @@ fn eval(paths: &[&str], prompt: &str) { // Check if the file exists, if given a pull or relative path // TODO: Check if file at the path is executable (i.e. +x) - if !Path::new(cmd).exists() { - // Check if the command exists in $PATH if a full or relative path - // was not given, or if the path does not exist - cmd = match bins.iter().find(|b| b.split("/").last().unwrap() == cmd) { - Some(cmd) => cmd, + let mut cmd = String::from(cmd); + if !Path::new(cmd.as_str()).exists() { + cmd = match bins + .read() + .unwrap() + .iter() + .flatten() + .map(|s| String::from(s)) + .collect::<Vec<String>>() + .iter() + .find(|b| b.split("/").last().unwrap() == cmd) + { + Some(cmd) => String::from(cmd), None => { - println!("Command not found"); + println!("dwvsh: error: command not found..."); continue; } }; @@ -104,19 +163,19 @@ fn eval(paths: &[&str], prompt: &str) { fn main() { // Define paths // TODO: Hardcoded path should only be the fallback - let paths = [ - "/bin", - "/sbin", - "/usr/bin", - "/usr/sbin", - "/usr/local/bin", - "/usr/local/sbin", + let paths = vec![ + "/bin".to_string(), + "/sbin".to_string(), + "/usr/bin".to_string(), + "/usr/sbin".to_string(), + "/usr/local/bin".to_string(), + "/usr/local/sbin".to_string(), ]; // Set the prompt let prompt = "|> "; - // Handle signals + // Handle SIGINT ctrlc::set_handler(move || { print!("\n{}", prompt); io::stdout().flush().unwrap(); @@ -124,5 +183,5 @@ fn main() { .expect("Unable to set <C-c> handler"); // Begin evaluating commands - eval(&paths, prompt); + eval(paths, prompt); } |