use ctrlc; use std::fs; use std::io; use std::io::Write; use std::process::Command; fn eval(paths: &[&str], prompt: &str) { let mut bins: Vec = Vec::new(); for path in paths { let files = fs::read_dir(path).expect("Unable to read files in your path"); for file in files { bins.push(file.unwrap().path().display().to_string()); } } loop { // Output the prompt io::stdout().flush().unwrap(); print!("{}", prompt); io::stdout().flush().unwrap(); // Wait for user input let mut input = String::new(); let bytes = io::stdin() .read_line(&mut input) .expect("Unable to evaluate the input string"); // Check if we've reached EOF (i.e. ) if bytes == 0 { break; } // Trim the input let input = input.trim(); // Check if user wants to exit the shell if input == "exit" || input == "quit" { break; } // Parse command and arguments let mut split = input.split(' '); let cmd = match split.next() { Some(str) if str.trim().is_empty() => continue, Some(str) => str.trim(), None => continue, }; // Parse arguments let mut args = vec![]; loop { let next = split.next(); match next { Some(str) => args.push(str), None => break, } } // Check if the command exists let cmd = match bins.iter().find(|b| b.split("/").last().unwrap() == cmd) { Some(cmd) => cmd, None => { println!("Command not found"); continue; } }; // Run the command (and wait for it to finish) let mut child = match Command::new(cmd).args(args).spawn() { Ok(ch) => ch, Err(_) => { println!("Unable to fork"); continue; } }; child.wait().unwrap(); } } 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", ]; // Set the prompt let prompt = "|> "; // Handle signals ctrlc::set_handler(move || { print!("\n{}", prompt); io::stdout().flush().unwrap(); }) .expect("Unable to set handler"); // Begin evaluating commands eval(&paths, prompt); }