diff options
| author | Jonas Maier <> | 2026-03-05 09:42:23 +0100 |
|---|---|---|
| committer | Jonas Maier <> | 2026-03-05 09:42:23 +0100 |
| commit | a3432a7a2ffbceea783fdf20231a22ce0ad2302c (patch) | |
| tree | 7cda43507c19ad774dc212a8fcdada3a0ea0a9ce | |
| parent | 70dd1e194c10904993069c14dbf4642e7a265889 (diff) | |
| download | pish-a3432a7a2ffbceea783fdf20231a22ce0ad2302c.tar.gz | |
pipes :)
| -rw-r--r-- | src/main.rs | 131 | ||||
| -rw-r--r-- | src/parse.rs | 4 |
2 files changed, 96 insertions, 39 deletions
diff --git a/src/main.rs b/src/main.rs index b0db2e4..a9f64e9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,18 +3,19 @@ use std::io::{self, IsTerminal, Read, Write}; use std::os::unix::ffi::OsStrExt; use std::os::unix::io::AsRawFd; use std::path::Path; -use std::process::Command; +use std::process::{Child, Command, Stdio}; pub mod cursor; pub mod linebuf; +pub mod panic; pub mod parse; pub mod raw; -pub mod panic; use linebuf::LineBuf; use raw::*; use crate::cursor::{Direction, move_cursor}; +use crate::parse::Ast; macro_rules! print { ($($x:tt)*) => {{ @@ -37,55 +38,111 @@ macro_rules! println { const PROMPT: &str = "> "; fn run_command(raw: &ScopedRawMode, line: Vec<u8>) { - let parsed = parse::do_parse(&line); - println!("{parsed:?}"); - let mut words: Vec<&[u8]> = line.split(|x| *x == b' ').collect(); - words.retain(|w| !w.is_empty()); + let parsed = match parsed { + Ok(p) => p, + Err(err) => { + print!("{err:?}\r\n{PROMPT}"); + return; + } + }; + + let Ast::Pipes(pipes) = parsed else { + todo!("can only handle pipes"); + }; - if words.is_empty() { - print!("{PROMPT}"); - return; + // simple command that can probably be builtin + // TODO: handle builtins uniformly instead of big if case + if pipes.cmds.len() == 1 { + let c = &pipes.cmds[0]; + match &c.cmd[..] { + b"cd" => { + let target: &Path = match c.args.get(0).map(|v| &v[..]) { + Some(b"-") => todo!("prev"), + Some(path) => OsStr::from_bytes(path).as_ref(), + None => todo!("homedir"), + }; + + if let Err(_) = std::env::set_current_dir(target) { + print!("ERR {PROMPT}"); + } else { + print!("{PROMPT}"); + } + + return; + } + _ => (), + } } - let cmd = words[0]; + let mut children: Vec<Child> = Vec::new(); + let mut prev_stdout = None; + let mut spawn_error = false; - match cmd { - b"cd" => { - let target: &Path = match words.get(1) { - Some(&b"-") => todo!("prev"), - Some(path) => OsStr::from_bytes(path).as_ref(), - None => todo!("homedir"), - }; + raw.disable(); - if let Err(_) = std::env::set_current_dir(target) { - print!("ERR {PROMPT}"); - } else { - print!("{PROMPT}"); - } + for (i, cmd) in pipes.cmds.iter().enumerate() { + let mut command = Command::new(OsStr::from_bytes(&cmd.cmd)); + for arg in cmd.args.iter() { + command.arg(OsStr::from_bytes(arg)); + } - return; + if let Some(stdout) = prev_stdout.take() { + command.stdin(Stdio::from(stdout)); + } + + if i < pipes.cmds.len() - 1 { + command.stdout(Stdio::piped()); } - _ => (), + + let mut child = match command.spawn() { + Ok(c) => c, + Err(e) => { + println!("failed to spawn {:?} - {e:?}", OsStr::from_bytes(&cmd.cmd)); + spawn_error = true; + break; + } + }; + + prev_stdout = child.stdout.take(); + + children.push(child); } - let mut cmd = Command::new(OsStr::from_bytes(cmd)); - for arg in words[1..].iter() { - cmd.arg(OsStr::from_bytes(arg)); + let status_string; + + if spawn_error { + for child in children.iter_mut() { + if let Err(e) = child.kill() { + println!("failed to kill child - {e:?}"); + } + } + status_string = "ERR".into(); + } else { + let mut code = 0; + for mut child in children { + match child.wait() { + Ok(ec) => { + if let Some(c) = ec.code() { + code = c; + } + } + Err(e) => { + println!("failed to wait for child - {e:?}") + } + } + } + if code == 0 { + status_string = String::new(); + } else { + status_string = format!("{code}"); + } } - raw.disable(); - let status = cmd.status(); raw.enable(); - let status_string = match status { - Ok(ec) if ec.success() => String::new(), - Ok(ec) => format!("{ec} "), - Err(_) => String::from("IO ERROR "), - }; - - print!("{status_string}{PROMPT}"); + print!("\r{status_string}{PROMPT}"); } fn main() { @@ -167,7 +224,7 @@ fn main() { } b'|' if line.is_empty() && !history.is_empty() => { - let mut cmd = history[history.len()-1].clone(); + let mut cmd = history[history.len() - 1].clone(); cmd.extend_from_slice(b" | "); io::stdout().write_all(&cmd).unwrap(); io::stdout().flush().unwrap(); diff --git a/src/parse.rs b/src/parse.rs index efe3b33..39ede4b 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -17,7 +17,7 @@ pub struct Pipes { #[derive(Debug)] pub struct Command { - pub path: Vec<u8>, + pub cmd: Vec<u8>, pub args: Vec<Vec<u8>>, } @@ -119,7 +119,7 @@ impl Parse for Command { Err(e) => Err(e)?, } } - Ok(Self { path, args }) + Ok(Self { cmd: path, args }) } } |
