summaryrefslogtreecommitdiffstats
path: root/src/poem/anthology.rs
diff options
context:
space:
mode:
authorRory Dudley2024-06-04 16:25:32 -0600
committerRory Dudley2024-06-04 16:25:32 -0600
commitc4cd1e2c165c4f34ebf67fa9350f8732b2aeca13 (patch)
treea8dd06c7563c205eb4710f620cf89d89ae17d98b /src/poem/anthology.rs
parentdedadcfd30516c40692fe495a6ad10aea7c050de (diff)
downloaddwarvish-c4cd1e2c165c4f34ebf67fa9350f8732b2aeca13.tar.gz
Updated the way built-in commands are called/used
Previously, built-in commands were fairly primitive, merely outputting STDOUT and STDERR with the print! macros. However, we need them to behave like normal programs, that is: - Acknowledge their verse's meter (forking, piping, etc.), - Ability to capture STDOUT and STDERR (>, 2>), - and Affect the currently running environment. For these reasons, the anthology was reworked, and now contains the Anthology struct, which mimics both std::process::{Child, Command}. The AnthologyStdin helper struct was also created, for built-ins to take input on STDIN, though no built-in is currently using it. Each built-ins' incant functions were updated to return a std::process::Output. It contains output from STDOUT, output from STDERR, and the exit code of the "process". A fix was also implemented for aliases, where the STDOUT and STDERR vectors were not being copied to the newly constructed verse.
Notes
Notes: There is some cleanup that needs to happen on this patch. For one, the spellcheck function is no longer being used, so there is a generic OS error if the program cannot be found in the $PATH. Also, anthology::lookup gets called twice, which shouldn't need to happen.
Diffstat (limited to 'src/poem/anthology.rs')
-rw-r--r--src/poem/anthology.rs142
1 files changed, 129 insertions, 13 deletions
diff --git a/src/poem/anthology.rs b/src/poem/anthology.rs
index 8ff70f9..a35eafb 100644
--- a/src/poem/anthology.rs
+++ b/src/poem/anthology.rs
@@ -5,7 +5,8 @@ mod export;
mod source;
mod which;
use crate::compose::Environment;
-use crate::poem::Verse;
+use std::io;
+use std::process::{Output, Stdio};
/// A static list of all the built-in commands
static INDEX: [&str; 8] = [
@@ -44,17 +45,132 @@ pub fn lookup(verb: &str) -> Option<usize> {
/// ...
/// }
/// ```
-pub fn incant(verse: &Verse, out: &mut Vec<u8>, index: usize, env: &mut Environment) -> i32 {
- let verb = INDEX[index];
- match verb {
- "alias" => alias::incant(verse, out, &mut env.aliases),
- "cd" => cd::incant(verse),
- "exit" => exit::incant(),
- "export" => export::incant(verse),
- "source" => source::incant(verse, out, env),
- "unalias" => alias::unincant(verse, &mut env.aliases),
- "unset" => export::unincant(verse),
- "which" => which::incant(verse, out, env),
- _ => unreachable!(),
+// pub fn incant(verse: &Verse, out: &mut Vec<u8>, index: usize, env: &mut Environment) -> i32 {
+// // let verb = INDEX[index];
+// // match verb {
+// // "alias" => alias::incant(verse, out, &mut env.aliases),
+// // "cd" => cd::incant(verse),
+// // "exit" => exit::incant(),
+// // "export" => export::incant(verse),
+// // "source" => source::incant(verse, out, env),
+// // "unalias" => alias::unincant(verse, &mut env.aliases),
+// // "unset" => export::unincant(verse),
+// // "which" => which::incant(verse, out, env),
+// // _ => unreachable!(),
+// // }
+// 0
+// }
+
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub struct AnthologyStdin {
+ data: Vec<u8>,
+}
+
+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<Vec<String>>,
+ uin: bool,
+ uout: bool,
+ uerr: bool,
+ pub stdin: AnthologyStdin,
+ output: Option<Output>,
+}
+
+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(verb: String) -> Self {
+ Anthology {
+ verb,
+ 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<String>) {
+ 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<Self, io::Error> {
+ let index = lookup(self.verb.as_str()).unwrap();
+ let verb = INDEX[index];
+
+ // Incant the built-in and set the output
+ self.output = Some(match verb {
+ "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<Output, io::Error> {
+ match &self.output {
+ Some(output) => Ok(output.clone()),
+ None => Err(io::Error::new(io::ErrorKind::Other, "not spawned")),
+ }
}
}