mod alias; mod cd; mod exit; mod export; mod source; mod which; use crate::compose::Environment; use std::io; use std::process::{Output, Stdio}; /// A static list of all the built-in commands static INDEX: [&str; 8] = [ "alias", "cd", "exit", "export", "source", "unalias", "unset", "which", ]; /// Lookup the index of a built-in command /// /// Looks up the index of a built-in command in [INDEX], accounting for aliases. /// /// # Aliases /// * quit -> exit /// * set -> export pub fn lookup(verb: &str) -> Option { let verb = match verb { "quit" => "exit", // Alias 'quit' to 'exit' "set" => "export", // Alias 'set' to 'export' _ => verb, }; INDEX.iter().position(|v| v.to_string() == verb) } #[derive(Debug, PartialEq, Eq, Clone)] pub struct AnthologyStdin { data: Vec, } impl AnthologyStdin { pub fn new() -> Self { AnthologyStdin { data: Vec::new() } } pub fn as_mut(&mut self) -> Option<&mut Self> { Some(self) } pub fn write_all(&mut self, data: &[u8]) -> Result<(), io::Error> { self.data.append(&mut data.to_vec()); Ok(()) } } #[derive(Debug, Clone)] pub struct Anthology { verb: String, clause: Option>, uin: bool, uout: bool, uerr: bool, pub stdin: AnthologyStdin, output: Option, } impl Anthology { /// Create a new instance of a built-in command /// /// Sets up a built-in command with default values. /// /// # Examples /// ``` /// let mut command = Anthology::new("alias"); /// ``` pub fn new(i: usize) -> Self { Anthology { verb: INDEX[i].to_string(), clause: None, uin: false, uout: false, uerr: false, stdin: AnthologyStdin::new(), output: None, } } /// Setup arguments to the built-in command /// /// Sets the 'clause' field of the [Anthology] struct, which are arguments /// to be passed to the built-in command. pub fn args(&mut self, clause: Vec) { self.clause = match clause.is_empty() { true => None, false => Some(clause.clone()), }; } /// Read to STDIN /// /// None of the built-in commands will currently read from STDIN for any /// reason, so this is just a dummy function. pub fn stdin(&mut self, _stdin: Stdio) { self.uin = true; } /// Capture STDOUT pub fn stdout(&mut self, _stdout: Stdio) { self.uout = true; } /// Capture STDERR pub fn stderr(&mut self, _stderr: Stdio) { self.uerr = true; } pub fn process_group(&mut self, _id: usize) {} pub fn id(&mut self) -> i32 { 0 } pub fn spawn(&mut self, env: &mut Environment) -> Result { // Incant the built-in and set the output self.output = Some(match self.verb.as_str() { "alias" => alias::incant(&self.clause, self.uout, &mut env.aliases), "cd" => cd::incant(&self.clause, self.uerr), "exit" => exit::incant(), "export" => export::incant(&self.clause, self.uout), "source" => source::incant(&self.clause, self.uout, self.uerr, env), "unalias" => alias::unincant(&self.clause, self.uerr, &mut env.aliases), "unset" => export::unincant(&self.clause, self.uerr), "which" => which::incant(&self.clause, self.uout, self.uerr, env), _ => unreachable!(), }); Ok(self.clone()) } pub fn wait_with_output(&self) -> Result { match &self.output { Some(output) => Ok(output.clone()), None => Err(io::Error::new(io::ErrorKind::Other, "not spawned")), } } }