From c4cd1e2c165c4f34ebf67fa9350f8732b2aeca13 Mon Sep 17 00:00:00 2001 From: Rory Dudley Date: Tue, 4 Jun 2024 16:25:32 -0600 Subject: 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. --- src/poem/anthology/source.rs | 98 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 81 insertions(+), 17 deletions(-) (limited to 'src/poem/anthology/source.rs') diff --git a/src/poem/anthology/source.rs b/src/poem/anthology/source.rs index 3c81110..0ed759c 100644 --- a/src/poem/anthology/source.rs +++ b/src/poem/anthology/source.rs @@ -1,7 +1,8 @@ use crate::compose::Environment; -use crate::poem::Verse; use crate::poem::{read::Readable, recite::Reciteable, Poem}; use std::fs; +use std::os::unix::process::ExitStatusExt; +use std::process::{ExitStatus, Output}; /// source /// @@ -12,12 +13,29 @@ use std::fs; /// ```sh /// source ~/.dwvshrc /// ``` -pub fn incant(verse: &Verse, out: &mut Vec, env: &mut Environment) -> i32 { - let files = match verse.clause() { +pub fn incant( + clause: &Option>, + uout: bool, + uerr: bool, + env: &mut Environment, +) -> Output { + let mut status = 0; + let mut out: Vec = Vec::new(); + let mut err: Vec = Vec::new(); + let files = match clause { Some(clause) => clause, None => { - eprintln!("source: not enough arguments"); - return 1; + status = 1; + if uerr { + err.append(&mut "source: not enough arguments\n".as_bytes().to_vec()); + } else { + eprintln!("source: not enough arguments"); + } + return Output { + status: ExitStatus::from_raw(status), + stdout: out, + stderr: err, + }; } }; @@ -25,31 +43,77 @@ pub fn incant(verse: &Verse, out: &mut Vec, env: &mut Environment) -> i32 { let poetry = match fs::read_to_string(&file) { Ok(poetry) => poetry, Err(e) => { - eprintln!( - "source: could not load {}: {}", - file, - e.to_string().to_lowercase() - ); - return 127; + status = 127; + if uerr { + err.append( + &mut format!( + "source: could not load {}: {}\n", + file, + e.to_string().to_lowercase() + ) + .as_bytes() + .to_vec(), + ); + } else { + eprintln!( + "source: could not load {}: {}", + file, + e.to_string().to_lowercase() + ); + } + return Output { + status: ExitStatus::from_raw(status), + stdout: out, + stderr: err, + }; } }; let poem = match Poem::read(poetry, env) { Ok(poem) => poem, Err(e) => { - eprintln!("dwvsh: {}", e.to_string().to_lowercase()); + if uerr { + err.append( + &mut format!("dwvsh: {}", e.to_string().to_lowercase()) + .as_bytes() + .to_vec(), + ); + } else { + eprintln!("dwvsh: {}", e.to_string().to_lowercase()); + } continue; } }; - *out = match poem.recite(env) { - Ok(out) => out, + status = match poem.recite(env) { + Ok(mut sout) => { + if uout { + out.append(&mut sout); + } else { + if !sout.is_empty() { + println!("{}", String::from_utf8_lossy(&sout)); + } + } + 0 + } Err(e) => { - eprintln!("dwvsh: {}", e.to_string().to_lowercase()); - continue; + if uerr { + err.append( + &mut format!("dwvsh: {}", e.to_string().to_lowercase()) + .as_bytes() + .to_vec(), + ); + } else { + eprintln!("dwvsh: {}", e.to_string().to_lowercase()); + } + 1 } }; } - 0 + Output { + status: ExitStatus::from_raw(status), + stdout: out, + stderr: err, + } } -- cgit v1.2.3