diff --git a/src/main.rs b/src/main.rs index 7277b43..2ca1d0b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,6 +14,7 @@ use std::io::Write; use anyhow::Result; use crate::log::*; +use shell::Shell; fn main() -> Result<()> { match Log::file("C:\\Users\\JordanOrelli\\wash.log") { @@ -30,6 +31,7 @@ fn main() -> Result<()> { let prompt = Prompt::new(); let mut input = input::Reader::new()?; let mut output = output::Writer::new()?; + let shell = Shell::new(); prompt.print(&mut output)?; info!("» enter"); @@ -58,7 +60,7 @@ fn main() -> Result<()> { vec![] }; debug!("◇ {} {}", cmd.clone(), args.join(" ")); - match shell::eval(&mut output, cmd.clone(), args.clone()) { + match shell.eval(&mut output, cmd.clone(), args.clone()) { Ok(true) => info!("▷ {} {}", cmd, args.join(" ")), Ok(false) => warn!("▷ {} {}", cmd, args.join(" ")), Err(e) => { @@ -78,8 +80,7 @@ fn main() -> Result<()> { if event.code == key::BACKSPACE { if line.backspace() { // move cursor back two spaces - output.write(b"\x1b[2D")?; - // output.back(2)?; + output.back(2)?; let tail = format!("{} ", line.tail()); let n = tail.chars().count(); output.write(tail.as_bytes())?; @@ -87,8 +88,9 @@ fn main() -> Result<()> { // after writing out the tail, rewind by the number of characters in // the tail if n > 1 { - let text = format!("\x1b[{}D", n - 1); - output.write(text.as_bytes())?; + // let text = format!("\x1b[{}D", n - 1); + output.back(n-1)?; + // output.write(text.as_bytes())?; } else { // honestly I can't remember how I figured this out output.write(b" \x1b[1D")?; @@ -115,7 +117,7 @@ fn main() -> Result<()> { // CTRL-L to clear the screen if event.ctrl && event.code == key::L { info!("» clear"); - output.write(b"\x1b[2J\x1b[0;0H")?; + output.clear()?; prompt.print(&mut output)?; output.write(line.show().as_bytes())?; continue; @@ -127,15 +129,13 @@ fn main() -> Result<()> { let n = line.clear_left(); if n > 0 { // move left by the number of elements removed - let text = format!("\x1b[{}D", n); - output.write(text.as_bytes())?; + output.back(n)?; // draw the elements remaining, followed by a space for each removed // element let kept = line.show(); let text = format!("{}{:width$}", kept, "", width = n); output.write(text.as_bytes())?; - let text = format!("\x1b[{}D", n + kept.chars().count()); - output.write(text.as_bytes())?; + output.back(n + kept.chars().count())?; } continue; } @@ -146,8 +146,7 @@ fn main() -> Result<()> { let n = line.seek_left(); if n > 0 { // move left by the distance seeked - let text = format!("\x1b[{}D", n); - output.write(text.as_bytes())?; + output.back(n)?; } continue; } @@ -158,8 +157,7 @@ fn main() -> Result<()> { let n = line.seek_right(); if n > 0 { // move right by the distance seeked - let text = format!("\x1b[{}C", n); - output.write(text.as_bytes())?; + output.forward(n)?; } continue; } @@ -177,8 +175,7 @@ fn main() -> Result<()> { if n > 1 { // if we wrote more than one character, because we weren't at the end, we // need to rewind the terminal cursor to where it was. - let text = format!("\x1b[{}D", n - 1); - output.write(text.as_bytes())?; + output.back(n-1)?; } continue; } @@ -188,13 +185,13 @@ fn main() -> Result<()> { input::Event::Left => { debug!("⛬ ←"); if line.back() { - output.write(b"\x1b[D")?; // lol this sucks + output.back(1)?; } } input::Event::Right => { debug!("⛬ →"); if line.forward() { - output.write(b"\x1b[C")?; // lol this sucks + output.forward(1)?; } } input::Event::Up => { diff --git a/src/output.rs b/src/output.rs index bde1cd2..546bb24 100644 --- a/src/output.rs +++ b/src/output.rs @@ -143,6 +143,23 @@ impl Writer { self.write(b"\r\n")?; Ok(()) } + + pub fn back(&mut self, n: usize) -> Result<()> { + let text = format!("\x1b[{}D", n); + self.write(text.as_bytes())?; + Ok(()) + } + + pub fn forward(&mut self, n: usize) -> Result<()> { + let text = format!("\x1b[{}C", n); + self.write(text.as_bytes())?; + Ok(()) + } + + pub fn clear(&mut self) -> Result<()> { + self.write(b"\x1b[2J\x1b[0;0H")?; + Ok(()) + } } impl Write for Writer { diff --git a/src/shell.rs b/src/shell.rs index 27a0c55..b2c1ad7 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -4,114 +4,122 @@ use crate::output; use anyhow::Result; -pub fn eval(output: &mut output::Writer, cmd: String, args: Vec<&str>) -> Result { - match cmd.as_str() { - "pwd" => { - let pb = std::env::current_dir()?; - println!("{}", pb.as_path().as_os_str().to_str().unwrap()); - return Ok(true); - } - "cd" => { - let cwd = std::env::current_dir()?; - if args.len() > 0 { - let target = cwd.join(args[0]); - std::env::set_current_dir(target)?; +pub struct Shell { +} + +impl Shell { + pub fn new() -> Self { + Self {} + } + + pub fn eval(&self, output: &mut output::Writer, cmd: String, args: Vec<&str>) -> Result { + match cmd.as_str() { + "pwd" => { + let pb = std::env::current_dir()?; + println!("{}", pb.as_path().as_os_str().to_str().unwrap()); + return Ok(true); } - return Ok(true); - } - "printenv" => { - if args.len() > 0 { - let name = args[0]; - match std::env::var(name) { - Ok(val) => { - println!("{}", val); - return Ok(true); - } - Err(e) => { - println!("ERROR {}", e); - return Ok(false); + "cd" => { + let cwd = std::env::current_dir()?; + if args.len() > 0 { + let target = cwd.join(args[0]); + std::env::set_current_dir(target)?; + } + return Ok(true); + } + "printenv" => { + if args.len() > 0 { + let name = args[0]; + match std::env::var(name) { + Ok(val) => { + println!("{}", val); + return Ok(true); + } + Err(e) => { + println!("ERROR {}", e); + return Ok(false); + } } + } else { + println!("which variable you fucking dork"); + return Ok(false); } - } else { - println!("which variable you fucking dork"); - return Ok(false); } - } - "which" => { - if args.len() > 0 { - let path = std::env::var("path").unwrap(); - let dirs: Vec<&str> = path.split(";").collect(); - for d in dirs { - let dir = std::path::Path::new(d); - let fname = dir.join(args[0]).with_extension("exe"); - if fname.exists() && fname.is_file() { - println!("{}", fname.to_str().unwrap()); - return Ok(true); + "which" => { + if args.len() > 0 { + let path = std::env::var("path").unwrap(); + let dirs: Vec<&str> = path.split(";").collect(); + for d in dirs { + let dir = std::path::Path::new(d); + let fname = dir.join(args[0]).with_extension("exe"); + if fname.exists() && fname.is_file() { + println!("{}", fname.to_str().unwrap()); + return Ok(true); + } } + println!("not found: {}", args[0]); + return Ok(false); + } else { + println!("what do you want to look for?"); + return Ok(false); } - println!("not found: {}", args[0]); - return Ok(false); - } else { - println!("what do you want to look for?"); - return Ok(false); } - } - "tail" => { - if args.len() > 0 { - let fname = args[0]; - match File::options().read(true).open(fname) { - Ok(mut f) => { - _ = f.seek(SeekFrom::End(0)); - let mut one_byte: [u8; 1] = [0; 1]; - let mut buf: Vec = vec![]; - loop { - match f.read(&mut one_byte) { - Ok(n) => { - if n == 1 { - buf.push(one_byte[0]); - if let Ok(s) = std::str::from_utf8(&buf) { - output.write(s.as_bytes())?; - buf.clear(); + "tail" => { + if args.len() > 0 { + let fname = args[0]; + match File::options().read(true).open(fname) { + Ok(mut f) => { + _ = f.seek(SeekFrom::End(0)); + let mut one_byte: [u8; 1] = [0; 1]; + let mut buf: Vec = vec![]; + loop { + match f.read(&mut one_byte) { + Ok(n) => { + if n == 1 { + buf.push(one_byte[0]); + if let Ok(s) = std::str::from_utf8(&buf) { + output.write(s.as_bytes())?; + buf.clear(); + } } } + Err(_) => {} } - Err(_) => {} } } + Err(e) => { + println!("failed to open file: {}", e); + return Err(e.into()); + } } - Err(e) => { - println!("failed to open file: {}", e); - return Err(e.into()); - } + } else { + println!("need a file name"); + return Ok(false); } - } else { - println!("need a file name"); - return Ok(false); } - } - "echo" => { - println!("{}", args.join(" ")); - return Ok(true); - } - _ => { - let mut proc = std::process::Command::new(cmd); - if args.len() > 0 { - proc.args(args); + "echo" => { + println!("{}", args.join(" ")); + return Ok(true); } - match proc.spawn() { - Ok(mut child) => { - if let Err(e) = child.wait() { + _ => { + let mut proc = std::process::Command::new(cmd); + if args.len() > 0 { + proc.args(args); + } + match proc.spawn() { + Ok(mut child) => { + if let Err(e) = child.wait() { + println!("error: {}", e); + return Err(e.into()); + } + } + Err(e) => { println!("error: {}", e); - return Err(e.into()); + return Ok(false); } } - Err(e) => { - println!("error: {}", e); - return Ok(false); - } + return Ok(true); } - return Ok(true); } } } -