aboutsummaryrefslogtreecommitdiffstats
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs193
1 files changed, 37 insertions, 156 deletions
diff --git a/src/main.rs b/src/main.rs
index 885e03d..08c4528 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -10,12 +10,12 @@ pub mod linebuf;
pub mod panic;
pub mod parse;
pub mod raw;
+pub mod run;
use linebuf::LineBuf;
use raw::*;
use crate::cursor::{Direction, move_cursor};
-use crate::parse::Ast;
macro_rules! print {
($($x:tt)*) => {{
@@ -37,134 +37,6 @@ macro_rules! println {
const PROMPT: &str = "> ";
-fn run_command(raw: &ScopedRawMode, line: Vec<u8>) {
- let parsed = parse::do_parse(&line);
-
- let parsed = match parsed {
- Ok(p) => p,
- Err(err) => {
- println!("{line:?}");
- print!("{err:?}\r\n{PROMPT}");
- return;
- }
- };
-
- let Ast::Pipes(pipes) = parsed else {
- todo!("can only handle pipes");
- };
-
- // 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;
- }
- b"clear" => clear_screen(),
- #[cfg(debug_assertions)]
- b"re" => {
- // restart shell
- raw.disable();
- let _ = Command::new("cargo").arg("run").status();
- raw.disable();
- std::process::exit(0);
- }
- b"from" => todo!("read from file"),
- b"to" | b"into" => todo!("write into file"),
- b"append" => todo!("append to file"),
- _ => (),
- }
- }
-
- let mut children: Vec<Child> = Vec::new();
- let mut prev_stdout = None;
- let mut spawn_error = false;
-
- raw.disable();
-
- 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));
- }
-
- 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 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.enable();
-
- print!("\r{status_string}{PROMPT}");
-}
-
-fn env_path() {
- let path = std::env::var("PATH").unwrap();
- for p in path.split(":") {
- println!("{p}");
- }
-}
-
fn completely_clear_screen() {
print!("\x1B[2J\x1B[1;1H");
}
@@ -174,9 +46,17 @@ fn clear_screen() {
print!("{PROMPT}")
}
-fn event_loop() {
- env_path();
+type BString = Vec<u8>;
+#[allow(non_camel_case_types)]
+type bstr = [u8];
+pub struct Session {
+ raw: ScopedRawMode,
+ line: LineBuf,
+ history: Vec<BString>,
+}
+
+fn event_loop() {
let stdin = io::stdin();
let stdout = io::stdout();
@@ -184,21 +64,22 @@ fn event_loop() {
let raw = ScopedRawMode::on_fd(fd);
raw.enable();
- let mut stdin = stdin.lock();
- let mut stdout = stdout.lock();
-
- let mut buffer = [0u8; 1];
- let mut line = LineBuf::new();
- let mut history = Vec::new();
+ let mut se = Session {
+ raw,
+ line: LineBuf::new(),
+ history: Vec::new(),
+ };
print!("{PROMPT}");
loop {
- let Ok(_) = stdin.read_exact(&mut buffer) else {
+ let mut buf = [0u8; 1];
+
+ let Ok(_) = stdin.lock().read_exact(&mut buf) else {
break;
};
- match buffer[0] {
+ match buf[0] {
// EOF
4 => {
break;
@@ -212,23 +93,23 @@ fn event_loop() {
// Enter
b'\r' => {
- let line = line.dump();
+ let line = se.line.dump();
if !line.is_empty() {
print!("\r\n");
- history.push(line.clone());
- run_command(&raw, line);
+ se.history.push(line.clone());
+ run::run(&se, line);
}
}
// Backspace (127 on most systems)
127 => {
- if line.is_empty() && !line.is_dirty() && !history.is_empty() {
+ if se.line.is_empty() && !se.line.is_dirty() && !se.history.is_empty() {
// take previous command for editing
- let cmd = history[history.len() - 1].clone();
+ let cmd = se.history[se.history.len() - 1].clone();
io::stdout().write_all(&cmd).unwrap();
io::stdout().flush().unwrap();
- line.set_content(cmd);
- } else if line.del_left().is_some() {
+ se.line.set_content(cmd);
+ } else if se.line.del_left().is_some() {
print!("\x08 \x08");
}
}
@@ -240,7 +121,7 @@ fn event_loop() {
// Escape sequence
27 => {
let mut seq = [0u8; 2];
- stdin.read_exact(&mut seq).unwrap();
+ stdin.lock().read_exact(&mut seq).unwrap();
if seq[0] == b'[' {
match seq[1] {
@@ -252,35 +133,35 @@ fn event_loop() {
}
b'C' => {
move_cursor(Direction::Right, 1);
- line.right();
+ se.line.right();
}
b'D' => {
move_cursor(Direction::Left, 1);
- line.left();
+ se.line.left();
}
x => todo!("escape character {x}"),
}
}
}
- b'|' if line.is_empty() && !history.is_empty() => {
- let mut cmd = history[history.len() - 1].clone();
+ b'|' if se.line.is_empty() && !se.history.is_empty() => {
+ let mut cmd = se.history[se.history.len() - 1].clone();
cmd.extend_from_slice(b" | ");
io::stdout().write_all(&cmd).unwrap();
io::stdout().flush().unwrap();
- line.set_content(cmd);
+ se.line.set_content(cmd);
}
// Normal character
x => {
- line.add(x);
- stdout.write_all(&[x]).unwrap();
- line.display_post();
+ se.line.add(x);
+ stdout.lock().write_all(&[x]).unwrap();
+ se.line.display_post();
}
}
}
- raw.disable();
+ se.raw.disable();
}
fn main() {