aboutsummaryrefslogtreecommitdiffstats
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs131
1 files changed, 94 insertions, 37 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();