diff --git a/src/main.rs b/src/main.rs index d43b637..6085b11 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,26 +1,73 @@ -use std::{io::{stdin, stdout, Write}, process::Command}; +use std::{env, io::{stdin, stdout, Write}, path::Path, process::{Child, Command, Stdio}}; fn main(){ loop { - // use the `>` character as the prompt - // need to explicitly flush this to ensure it prints before read_line print!("> "); stdout().flush(); let mut input = String::new(); stdin().read_line(&mut input).unwrap(); - let mut parts = input.trim().split_whitespace(); - let command = parts.next().unwrap(); - let args = parts; + // must be peekable so we know when we are on the last command + let mut commands = input.trim().split(" | ").peekable(); + let mut previous_command = None; - let mut child = Command::new(command) - .args(args) - .spawn() - .unwrap(); + while let Some(command) = commands.next() { + + let mut parts = command.trim().split_whitespace(); + let command = parts.next().unwrap(); + let args = parts; + + match command { + "cd" => { + let new_dir = args.peekable().peek() + .map_or("/", |x| *x); + let root = Path::new(new_dir); + if let Err(e) = env::set_current_dir(&root) { + eprintln!("{}", e); + } + + previous_command = None; + }, + "exit" => return, + command => { + let stdin = previous_command + .map_or( + Stdio::inherit(), + |output: Child| Stdio::from(output.stdout.unwrap()) + ); + + let stdout = if commands.peek().is_some() { + // there is another command piped behind this one + // prepare to send output to the next command + Stdio::piped() + } else { + // there are no more commands piped behind this one + // send output to shell stdout + Stdio::inherit() + }; + + let output = Command::new(command) + .args(args) + .stdin(stdin) + .stdout(stdout) + .spawn(); + + match output { + Ok(output) => { previous_command = Some(output); }, + Err(e) => { + previous_command = None; + eprintln!("{}", e); + }, + }; + } + } + } + + if let Some(mut final_command) = previous_command { + // block until the final command has finished + final_command.wait(); + } - // don't accept another command until this one completes - child.wait(); } } -