| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 | 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<R, W> {
    pub reader: R,
    pub writer: W,
    pub should_exit: bool,
    pub name: String,
}
impl<'a> Shell<R<'a>, 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<String, &str> {
        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<usize, io::Error> {
        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<usize, io::Error> {
        self.0.write(buf)
    }
    fn flush(&mut self) -> Result<(), io::Error> {
        self.0.flush()
    }
}
 |