aboutsummaryrefslogtreecommitdiffstats
path: root/src/run/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/run/mod.rs')
-rw-r--r--src/run/mod.rs61
1 files changed, 44 insertions, 17 deletions
diff --git a/src/run/mod.rs b/src/run/mod.rs
index 40f4927..b45fac8 100644
--- a/src/run/mod.rs
+++ b/src/run/mod.rs
@@ -47,26 +47,25 @@ impl<'a> Executor<'a> {
fn execute(
&mut self,
ast: Ast<parse::PostExpansion>,
- stdin: Box<dyn io::Read + Send>,
- stdout: Box<dyn io::Write + Send>,
+ capture: Option<&mut Vec<u8>>,
) -> Result<(), ExecError> {
let Ast::Pipes(pipes) = ast else {
todo!("can only handle pipes");
};
- let mut stdin = Some(stdin);
- let mut stdout = Some(stdout);
+ //print!("exec {}", format!("{pipes:?}\n").replace("\n", "\r\n"));
let mut children = Vec::new();
let mut threads = Vec::new();
let mut prev_reader = None;
let mut spawn_error = false;
+ let mut last_output = ArcWriter::new();
+ let mut last_is_command = false;
+
let pipelen = pipes.cmds.len();
for (i, cmd) in pipes.cmds.into_iter().enumerate() {
- let last = i == pipelen - 1;
-
- let (reader, writer) = if !last {
+ let (reader, writer) = if i < pipelen - 1 {
let (r, w) = io::pipe().unwrap();
(Some(r), Some(w))
} else {
@@ -77,6 +76,8 @@ impl<'a> Executor<'a> {
match dc {
CommandKind::Path(path) => {
+ last_is_command = true;
+
let mut command = Command::new(&path);
for arg in cmd.args.iter() {
command.arg(OsStr::from_bytes(arg));
@@ -84,10 +85,14 @@ impl<'a> Executor<'a> {
if let Some(r) = prev_reader.take() {
command.stdin(Stdio::from(r));
+ } else if capture.is_some() {
+ command.stdin(Stdio::null());
}
if let Some(w) = writer {
command.stdout(Stdio::from(w));
+ } else if capture.is_some() {
+ command.stdout(Stdio::piped());
}
let child = match command.spawn() {
@@ -124,16 +129,20 @@ impl<'a> Executor<'a> {
}
CommandKind::Builtin(builtin) => {
+ last_is_command = false;
+
builtin.mod_session(&mut self.se, &cmd.args);
let mut input: Box<dyn io::Read + Send> = match prev_reader.take() {
Some(r) => Box::new(r),
- None => stdin.take().unwrap(),
+ None if capture.is_some() => Box::new(io::empty()),
+ None => Box::new(io::stdin()),
};
let mut output: Box<dyn io::Write + Send> = match writer {
Some(w) => Box::new(w),
- None => stdout.take().unwrap(),
+ None if capture.is_some() => Box::new(last_output.clone()),
+ None => Box::new(io::stdout()),
};
let handle =
@@ -159,7 +168,7 @@ impl<'a> Executor<'a> {
// TODO do not ignore panics
let _ = jh.join();
}
- for mut child in children {
+ for child in children.iter_mut() {
match child.wait() {
Ok(ec) => {
if let Some(c) = ec.code() {
@@ -171,6 +180,22 @@ impl<'a> Executor<'a> {
}
}
}
+
+ if let Some(cap) = capture {
+ if last_is_command {
+ let child = children
+ .into_iter()
+ .last()
+ .unwrap();
+ let out = child
+ .wait_with_output()
+ .unwrap();
+ *cap = out.stdout;
+ } else {
+ *cap = last_output.into_inner();
+ }
+ }
+
if code == 0 {
Ok(())
} else {
@@ -191,17 +216,16 @@ impl<'a> parse::Expander for Executor<'a> {
}
fn expand_cmd(&mut self, ast: Ast<parse::PostExpansion>) -> Result<BString, Self::Error> {
- let stdout = Box::new(ArcWriter::new());
- let stdin = Box::new(std::io::empty());
- self.execute(ast, stdin, stdout.clone())?;
- Ok(stdout.into_inner())
+ let mut out = Vec::new();
+ self.execute(ast, Some(&mut out))?;
+ Ok(out)
}
}
fn exec(se: &mut Session, ast: Ast<PreExpansion>) -> Result<(), ExecError> {
let mut exec = Executor { se };
let ast = ast.expand(&mut exec)?;
- exec.execute(ast, Box::new(io::stdin()), Box::new(io::stdout()))
+ exec.execute(ast, None)
}
pub fn run(se: &mut Session, cmd: Vec<u8>) {
@@ -209,8 +233,11 @@ pub fn run(se: &mut Session, cmd: Vec<u8>) {
let parsed = match parsed {
Ok(p) => p,
Err(err) => {
- println!("{cmd:?}");
- print!("{err:?}\r\n{}", se.prompt());
+ se.raw.disable();
+ println!("{:?}: {}", err.0, String::from_utf8_lossy(&err.1));
+ print!("{}", se.prompt());
+ std::io::stdout().lock().flush().unwrap();
+ se.raw.enable();
return;
}
};