diff options
-rw-r--r-- | src/history.rs | 33 | ||||
-rw-r--r-- | src/main.rs | 41 | ||||
-rw-r--r-- | src/nbsh.rs | 149 | ||||
-rw-r--r-- | src/readline.rs (renamed from src/repl.rs) | 15 | ||||
-rw-r--r-- | src/state.rs | 83 | ||||
-rw-r--r-- | src/util.rs | 5 |
6 files changed, 151 insertions, 175 deletions
diff --git a/src/history.rs b/src/history.rs index 00ad39a..bf46693 100644 --- a/src/history.rs +++ b/src/history.rs @@ -3,13 +3,13 @@ use pty_process::Command as _; use textmode::Textmode as _; pub struct History { - entries: Vec<async_std::sync::Arc<async_std::sync::Mutex<HistoryEntry>>>, - action: async_std::channel::Sender<crate::nbsh::Action>, + entries: Vec<crate::util::Mutex<HistoryEntry>>, + action: async_std::channel::Sender<crate::state::Action>, } impl History { pub fn new( - action: async_std::channel::Sender<crate::nbsh::Action>, + action: async_std::channel::Sender<crate::state::Action>, ) -> Self { Self { entries: vec![], @@ -24,8 +24,9 @@ impl History { let child = process .spawn_pty(Some(&pty_process::Size::new(24, 80))) .unwrap(); - let entry = async_std::sync::Arc::new(async_std::sync::Mutex::new( - HistoryEntry::new(cmd, child.id().try_into().unwrap()), + let entry = crate::util::mutex(HistoryEntry::new( + cmd, + child.id().try_into().unwrap(), )); let task_entry = async_std::sync::Arc::clone(&entry); let task_action = self.action.clone(); @@ -42,29 +43,27 @@ impl History { } task_entry.lock_arc().await.running = false; task_action - .send(crate::nbsh::Action::UpdateFocus( - crate::nbsh::InputSource::Repl, + .send(crate::state::Action::UpdateFocus( + crate::state::Focus::Readline, )) .await .unwrap(); - task_action - .send(crate::nbsh::Action::Render) - .await - .unwrap(); break; } } - task_action.send(crate::nbsh::Action::Render).await.unwrap(); + task_action + .send(crate::state::Action::Render) + .await + .unwrap(); } }); self.entries.push(entry); self.action - .send(crate::nbsh::Action::UpdateFocus( - crate::nbsh::InputSource::History(self.entries.len() - 1), + .send(crate::state::Action::UpdateFocus( + crate::state::Focus::History(self.entries.len() - 1), )) .await .unwrap(); - self.action.send(crate::nbsh::Action::Render).await.unwrap(); Ok(self.entries.len() - 1) } @@ -81,8 +80,8 @@ impl History { } textmode::Key::Ctrl(b'z') => { self.action - .send(crate::nbsh::Action::UpdateFocus( - crate::nbsh::InputSource::Repl, + .send(crate::state::Action::UpdateFocus( + crate::state::Focus::Readline, )) .await .unwrap(); diff --git a/src/main.rs b/src/main.rs index 97624df..666b936 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,11 +4,46 @@ #![allow(clippy::unused_self)] mod history; -mod nbsh; -mod repl; +mod readline; +mod state; +mod util; async fn async_main() -> anyhow::Result<()> { - nbsh::run().await + let mut input = textmode::Input::new().await?; + let mut output = textmode::Output::new().await?; + + // avoid the guards getting stuck in a task that doesn't run to + // completion + let _input_guard = input.take_raw_guard(); + let _output_guard = output.take_screen_guard(); + + let (action_w, action_r) = async_std::channel::unbounded(); + + let state = util::mutex(state::State::new(action_w)); + + state.lock_arc().await.render(&mut output).await.unwrap(); + + { + let state = async_std::sync::Arc::clone(&state); + async_std::task::spawn(async move { + while let Ok(action) = action_r.recv().await { + state + .lock_arc() + .await + .handle_action(action, &mut output) + .await; + } + }); + } + + loop { + let key = input.read_key().await.unwrap(); + if state.lock_arc().await.handle_input(key).await { + break; + } + } + + Ok(()) } fn main() { diff --git a/src/nbsh.rs b/src/nbsh.rs deleted file mode 100644 index 84d35e3..0000000 --- a/src/nbsh.rs +++ /dev/null @@ -1,149 +0,0 @@ -use textmode::Textmode as _; - -pub async fn run() -> anyhow::Result<()> { - let mut input = textmode::Input::new().await?; - let mut output = textmode::Output::new().await?; - - // avoid the guards getting stuck in a task that doesn't run to - // completion - let _input_guard = input.take_raw_guard(); - let _output_guard = output.take_screen_guard(); - - let (action_w, action_r) = async_std::channel::unbounded(); - - let repl = async_std::sync::Arc::new(async_std::sync::Mutex::new( - crate::repl::Repl::new(action_w.clone()), - )); - let history = async_std::sync::Arc::new(async_std::sync::Mutex::new( - crate::history::History::new(action_w), - )); - let input_source = async_std::sync::Arc::new( - async_std::sync::Mutex::new(InputSource::Repl), - ); - - render( - &mut output, - &*repl.lock_arc().await, - &*history.lock_arc().await, - &*input_source.lock_arc().await, - ) - .await - .unwrap(); - - { - let repl = async_std::sync::Arc::clone(&repl); - let history = async_std::sync::Arc::clone(&history); - let input_source = async_std::sync::Arc::clone(&input_source); - async_std::task::spawn(async move { - while let Ok(action) = action_r.recv().await { - handle_action( - action, - &mut output, - async_std::sync::Arc::clone(&repl), - async_std::sync::Arc::clone(&history), - async_std::sync::Arc::clone(&input_source), - ) - .await; - } - }); - } - - loop { - let quit = handle_input( - &mut input, - async_std::sync::Arc::clone(&repl), - async_std::sync::Arc::clone(&history), - async_std::sync::Arc::clone(&input_source), - ) - .await; - if quit { - break; - } - } - - Ok(()) -} - -async fn handle_action( - action: Action, - output: &mut textmode::Output, - repl: async_std::sync::Arc<async_std::sync::Mutex<crate::repl::Repl>>, - history: async_std::sync::Arc< - async_std::sync::Mutex<crate::history::History>, - >, - input_source: async_std::sync::Arc<async_std::sync::Mutex<InputSource>>, -) { - match action { - Action::Render => { - render( - output, - &*repl.lock_arc().await, - &*history.lock_arc().await, - &*input_source.lock_arc().await, - ) - .await - .unwrap(); - } - Action::Run(ref cmd) => { - history.lock_arc().await.run(cmd).await.unwrap(); - } - Action::UpdateFocus(new_input_source) => { - *input_source.lock_arc().await = new_input_source; - } - } -} - -async fn handle_input( - input: &mut textmode::Input, - repl: async_std::sync::Arc<async_std::sync::Mutex<crate::repl::Repl>>, - history: async_std::sync::Arc< - async_std::sync::Mutex<crate::history::History>, - >, - input_source: async_std::sync::Arc<async_std::sync::Mutex<InputSource>>, -) -> bool { - let key = input.read_key().await.unwrap(); - if let Some(key) = key { - let input_source = *input_source.lock_arc().await; - let quit = match input_source { - InputSource::Repl => repl.lock_arc().await.handle_key(key).await, - InputSource::History(idx) => { - history.lock_arc().await.handle_key(key, idx).await - } - }; - if quit { - return true; - } - } else { - return true; - } - false -} - -async fn render( - out: &mut textmode::Output, - repl: &crate::repl::Repl, - history: &crate::history::History, - input_source: &InputSource, -) -> anyhow::Result<()> { - out.clear(); - if let InputSource::Repl = input_source { - history.render(out, repl.lines()).await?; - repl.render(out).await?; - } else { - history.render(out, 0).await?; - } - out.refresh().await?; - Ok(()) -} - -#[derive(Copy, Clone, Debug)] -pub enum InputSource { - Repl, - History(usize), -} - -pub enum Action { - Render, - Run(String), - UpdateFocus(InputSource), -} diff --git a/src/repl.rs b/src/readline.rs index 223aa80..8ff001c 100644 --- a/src/repl.rs +++ b/src/readline.rs @@ -1,14 +1,14 @@ use textmode::Textmode as _; -pub struct Repl { +pub struct Readline { prompt: String, input_line: String, - action: async_std::channel::Sender<crate::nbsh::Action>, + action: async_std::channel::Sender<crate::state::Action>, } -impl Repl { +impl Readline { pub fn new( - action: async_std::channel::Sender<crate::nbsh::Action>, + action: async_std::channel::Sender<crate::state::Action>, ) -> Self { Self { prompt: "$ ".into(), @@ -29,7 +29,7 @@ impl Repl { } textmode::Key::Ctrl(b'm') => { self.action - .send(crate::nbsh::Action::Run(self.input())) + .send(crate::state::Action::Run(self.input())) .await .unwrap(); self.clear_input(); @@ -37,7 +37,10 @@ impl Repl { textmode::Key::Backspace => self.backspace(), _ => {} } - self.action.send(crate::nbsh::Action::Render).await.unwrap(); + self.action + .send(crate::state::Action::Render) + .await + .unwrap(); false } diff --git a/src/state.rs b/src/state.rs new file mode 100644 index 0000000..b979ed7 --- /dev/null +++ b/src/state.rs @@ -0,0 +1,83 @@ +use textmode::Textmode as _; + +pub struct State { + readline: crate::readline::Readline, + history: crate::history::History, + focus: Focus, +} + +impl State { + pub fn new(actions: async_std::channel::Sender<Action>) -> Self { + let readline = crate::readline::Readline::new(actions.clone()); + let history = crate::history::History::new(actions); + let focus = Focus::Readline; + Self { + readline, + history, + focus, + } + } + + pub async fn render( + &self, + out: &mut textmode::Output, + ) -> anyhow::Result<()> { + out.clear(); + if let Focus::Readline = self.focus { + self.history.render(out, self.readline.lines()).await?; + self.readline.render(out).await?; + } else { + self.history.render(out, 0).await?; + } + out.refresh().await?; + Ok(()) + } + + pub async fn handle_action( + &mut self, + action: Action, + output: &mut textmode::Output, + ) { + match action { + Action::Render => { + self.render(output).await.unwrap(); + } + Action::Run(ref cmd) => { + self.history.run(cmd).await.unwrap(); + } + Action::UpdateFocus(new_focus) => { + self.focus = new_focus; + self.render(output).await.unwrap(); + } + } + } + + pub async fn handle_input(&mut self, key: Option<textmode::Key>) -> bool { + if let Some(key) = key { + let quit = match self.focus { + Focus::Readline => self.readline.handle_key(key).await, + Focus::History(idx) => { + self.history.handle_key(key, idx).await + } + }; + if quit { + return true; + } + } else { + return true; + } + false + } +} + +#[derive(Copy, Clone)] +pub enum Focus { + Readline, + History(usize), +} + +pub enum Action { + Render, + Run(String), + UpdateFocus(Focus), +} diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..d792b91 --- /dev/null +++ b/src/util.rs @@ -0,0 +1,5 @@ +pub type Mutex<T> = async_std::sync::Arc<async_std::sync::Mutex<T>>; + +pub fn mutex<T>(t: T) -> Mutex<T> { + async_std::sync::Arc::new(async_std::sync::Mutex::new(t)) +} |