From 04068bf2ad233748af1ac98edb12a27bf8ffca75 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Thu, 18 Nov 2021 00:40:01 -0500 Subject: implement cd --- src/builtins.rs | 44 +++++++++++++ src/history.rs | 191 ++++++++++++++++++++++++++++++-------------------------- src/main.rs | 1 + 3 files changed, 147 insertions(+), 89 deletions(-) create mode 100644 src/builtins.rs diff --git a/src/builtins.rs b/src/builtins.rs new file mode 100644 index 0000000..225ef5b --- /dev/null +++ b/src/builtins.rs @@ -0,0 +1,44 @@ +pub fn is(exe: &str) -> bool { + matches!(exe, "cd") +} + +pub fn run(exe: &str, args: &[String]) -> u8 { + match exe { + "cd" => { + impls::cd(args.iter().map(|s| s.as_ref()).next().unwrap_or("")) + } + _ => unreachable!(), + } +} + +mod impls { + pub fn cd(dir: &str) -> u8 { + let dir = if dir.is_empty() { + home() + } else if dir.starts_with('~') { + let path: std::path::PathBuf = dir.into(); + if let std::path::Component::Normal(prefix) = + path.components().next().unwrap() + { + if prefix.to_str() == Some("~") { + home().join(path.strip_prefix(prefix).unwrap()) + } else { + // TODO + return 1; + } + } else { + unreachable!() + } + } else { + dir.into() + }; + match std::env::set_current_dir(dir) { + Ok(()) => 0, + Err(_) => 1, + } + } + + fn home() -> std::path::PathBuf { + std::env::var_os("HOME").unwrap().into() + } +} diff --git a/src/history.rs b/src/history.rs index e740e41..d6f198a 100644 --- a/src/history.rs +++ b/src/history.rs @@ -82,100 +82,39 @@ impl History { action_w: async_std::channel::Sender, ) -> anyhow::Result { let (exe, args) = crate::parse::cmd(cmd); - let mut process = async_std::process::Command::new(&exe); - process.args(&args); - let mut child = process - .spawn_pty(Some(&pty_process::Size::new( - self.size.0, - self.size.1, - ))) - .unwrap(); let (input_w, input_r) = async_std::channel::unbounded(); let (resize_w, resize_r) = async_std::channel::unbounded(); let entry = crate::util::mutex(HistoryEntry::new( cmd, self.size, input_w, resize_w, )); - let task_entry = async_std::sync::Arc::clone(&entry); - async_std::task::spawn(async move { - loop { - enum Res { - Read(Result), - Write(Result, async_std::channel::RecvError>), - Resize(Result<(u16, u16), async_std::channel::RecvError>), - } - let mut buf = [0_u8; 4096]; - let mut pty = child.pty(); - let read = async { Res::Read(pty.read(&mut buf).await) }; - let write = async { Res::Write(input_r.recv().await) }; - let resize = async { Res::Resize(resize_r.recv().await) }; - match read.race(write).race(resize).await { - Res::Read(res) => { - match res { - Ok(bytes) => { - task_entry - .lock_arc() - .await - .vt - .process(&buf[..bytes]); - } - Err(e) => { - if e.raw_os_error() != Some(libc::EIO) { - eprintln!("pty read failed: {:?}", e); - } - // XXX not sure if this is safe - are we sure - // the child exited? - task_entry.lock_arc().await.exit_info = - Some(ExitInfo::new( - child.status().await.unwrap(), - )); - action_w - .send(crate::action::Action::UpdateFocus( - crate::state::Focus::Readline, - )) - .await - .unwrap(); - break; - } - } - action_w - .send(crate::action::Action::Render) - .await - .unwrap(); - } - Res::Write(res) => match res { - Ok(bytes) => { - pty.write(&bytes).await.unwrap(); - } - Err(e) => { - panic!( - "failed to read from input channel: {}", - e - ); - } - }, - Res::Resize(res) => match res { - Ok(size) => { - child - .resize_pty(&pty_process::Size::new( - size.0, size.1, - )) - .unwrap(); - task_entry - .lock_arc() - .await - .vt - .set_size(size.0, size.1); - } - Err(e) => { - panic!( - "failed to read from resize channel: {}", - e - ); - } - }, - } - } - }); + if crate::builtins::is(&exe) { + let code: i32 = crate::builtins::run(&exe, &args).into(); + entry.lock_arc().await.exit_info = Some(ExitInfo::new( + async_std::process::ExitStatus::from_raw(code << 8), + )); + action_w + .send(crate::action::Action::UpdateFocus( + crate::state::Focus::Readline, + )) + .await + .unwrap(); + } else { + let mut process = async_std::process::Command::new(&exe); + process.args(&args); + let child = process + .spawn_pty(Some(&pty_process::Size::new( + self.size.0, + self.size.1, + ))) + .unwrap(); + run_process( + child, + async_std::sync::Arc::clone(&entry), + input_r, + resize_r, + action_w, + ); + } self.entries.push(entry); Ok(self.entries.len() - 1) } @@ -392,3 +331,77 @@ impl ExitInfo { } } } + +fn run_process( + mut child: pty_process::async_std::Child, + entry: crate::util::Mutex, + input_r: async_std::channel::Receiver>, + resize_r: async_std::channel::Receiver<(u16, u16)>, + action_w: async_std::channel::Sender, +) { + async_std::task::spawn(async move { + loop { + enum Res { + Read(Result), + Write(Result, async_std::channel::RecvError>), + Resize(Result<(u16, u16), async_std::channel::RecvError>), + } + let mut buf = [0_u8; 4096]; + let mut pty = child.pty(); + let read = async { Res::Read(pty.read(&mut buf).await) }; + let write = async { Res::Write(input_r.recv().await) }; + let resize = async { Res::Resize(resize_r.recv().await) }; + match read.race(write).race(resize).await { + Res::Read(res) => { + match res { + Ok(bytes) => { + entry.lock_arc().await.vt.process(&buf[..bytes]); + } + Err(e) => { + if e.raw_os_error() != Some(libc::EIO) { + eprintln!("pty read failed: {:?}", e); + } + // XXX not sure if this is safe - are we sure + // the child exited? + entry.lock_arc().await.exit_info = Some( + ExitInfo::new(child.status().await.unwrap()), + ); + action_w + .send(crate::action::Action::UpdateFocus( + crate::state::Focus::Readline, + )) + .await + .unwrap(); + break; + } + } + action_w + .send(crate::action::Action::Render) + .await + .unwrap(); + } + Res::Write(res) => match res { + Ok(bytes) => { + pty.write(&bytes).await.unwrap(); + } + Err(e) => { + panic!("failed to read from input channel: {}", e); + } + }, + Res::Resize(res) => match res { + Ok(size) => { + child + .resize_pty(&pty_process::Size::new( + size.0, size.1, + )) + .unwrap(); + entry.lock_arc().await.vt.set_size(size.0, size.1); + } + Err(e) => { + panic!("failed to read from resize channel: {}", e); + } + }, + } + } + }); +} diff --git a/src/main.rs b/src/main.rs index b3852cd..94d6f90 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ #![allow(clippy::unused_self)] mod action; +mod builtins; mod format; mod history; mod parse; -- cgit v1.2.3