use std::io::{BufRead, Write, Read, StdinLock, StdoutLock}; use std::io; use command::*; use std::str::FromStr; use std::env; ///Tuple-Structs which hold Std-in and -out locks. pub struct R<'a>(pub StdinLock<'a>); pub struct W<'a>(pub StdoutLock<'a>); pub struct Shell { pub reader: R, pub writer: W, pub should_exit: bool, pub name: String, } impl<'a> Shell, W<'a>> { /// Creates a new Shell with a name, input and output. pub fn new(input: R<'a>, output: W<'a>, name: String) -> Self { Shell { reader: input, writer: output, should_exit: false, name: name, } } /// Initializes the Shell Loop. /// Starts the shell. pub fn start(&mut self) -> Result<(), &str> { self.shell_loop() } /// Loops while exit hasn't been called. /// When *prompt()* returns (the user hit enter) a Command is created through the FromStr-Trait. /// If the Command-creation succeeds, run the command. fn shell_loop(&mut self) -> Result<(), &str> { while !self.should_exit { if let Ok(line) = self.prompt() { let _ = Command::from_str(&line).and_then(|cmd| self.run(cmd)); } } Ok(()) } /// Prints the shell prompt. /// Waits for user input and returns the read line. fn prompt(&mut self) -> Result { match env::current_dir() { Ok(pwd) => { let _ = self.writer.write( format!("{} {} > ", self.name, pwd.display()) .as_bytes(), ); let _ = self.writer.flush(); let mut line: String = String::new(); let read_result = self.reader.read_line(&mut line); match read_result { Ok(_) => Ok(line), Err(_) => Err("Error reading."), } } Err(_) => return Err("Path Error"), } } /// Runs a command. /// Currently only `cd` and `exit` are working. fn run(&mut self, command: Command) -> Result<(), CommandNotFoundError> { match command { Command::Empty => {} Command::Exit => self.should_exit = true, Command::Cd(_) => { command.exec_cd(); } } Ok(()) } } /// Implement Read-Trait for Tuple-Struct R /// Simply calls `read` of StdinLock impl<'a> Read for R<'a> { fn read(&mut self, buf: &mut [u8]) -> Result { self.0.read(buf) } } /// Implement BufRead-Trait for Tuple-Struct R /// Simply calls `fill_buff` and `consume` from StdinLock impl<'a> BufRead for R<'a> { fn fill_buf(&mut self) -> Result<&[u8], io::Error> { self.0.fill_buf() } fn consume(&mut self, amt: usize) { self.0.consume(amt) } } /// Implement Write-Trait for Tuple-Struct W /// Simply calls `write` and `flush` from StdoutLock impl<'a> Write for W<'a> { fn write(&mut self, buf: &[u8]) -> Result { self.0.write(buf) } fn flush(&mut self) -> Result<(), io::Error> { self.0.flush() } }