From 165faf398ab2e00ebf18ad730f18b9277f612213 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Sat, 11 Dec 2021 21:00:49 -0500 Subject: significantly refactor the event loop --- src/state.rs | 269 ++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 148 insertions(+), 121 deletions(-) (limited to 'src/state.rs') diff --git a/src/state.rs b/src/state.rs index f086334..dd32c5c 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,10 +1,23 @@ use textmode::Textmode as _; +#[derive(Copy, Clone, Debug)] +enum Focus { + Readline, + History(usize), + Scrolling(Option), +} + +#[derive(Copy, Clone, Debug)] +enum Scene { + Readline, + Fullscreen, +} + pub struct State { readline: crate::readline::Readline, history: crate::history::History, - focus: crate::action::Focus, - scene: crate::action::Scene, + focus: Focus, + scene: Scene, escape: bool, hide_readline: bool, offset: time::UtcOffset, @@ -15,8 +28,8 @@ impl State { Self { readline: crate::readline::Readline::new(), history: crate::history::History::new(), - focus: crate::action::Focus::Readline, - scene: crate::action::Scene::Readline, + focus: Focus::Readline, + scene: Scene::Readline, escape: false, hide_readline: false, offset, @@ -30,8 +43,8 @@ impl State { ) -> anyhow::Result<()> { out.clear(); match self.scene { - crate::action::Scene::Readline => match self.focus { - crate::action::Focus::Readline => { + Scene::Readline => match self.focus { + Focus::Readline => { self.history .render( out, @@ -50,7 +63,7 @@ impl State { ) .await?; } - crate::action::Focus::History(idx) => { + Focus::History(idx) => { if self.hide_readline { self.history .render(out, 0, Some(idx), false, self.offset) @@ -77,7 +90,7 @@ impl State { out.move_to(pos.0, pos.1); } } - crate::action::Focus::Scrolling(idx) => { + Focus::Scrolling(idx) => { self.history .render( out, @@ -98,8 +111,8 @@ impl State { out.hide_cursor(true); } }, - crate::action::Scene::Fullscreen => { - if let crate::action::Focus::History(idx) = self.focus { + Scene::Fullscreen => { + if let Focus::History(idx) = self.focus { self.history.render_fullscreen(out, idx).await; } else { unreachable!(); @@ -114,61 +127,68 @@ impl State { Ok(()) } - pub async fn handle_action( + pub async fn handle_event( &mut self, - action: crate::action::Action, + event: crate::event::Event, out: &mut textmode::Output, - action_w: &async_std::channel::Sender, + event_w: &async_std::channel::Sender, ) { let mut hard_refresh = false; - match action { - crate::action::Action::Key(key) => { - if let Some(action) = self.handle_key(key).await { - action_w.send(action).await.unwrap(); + match event { + crate::event::Event::Key(key) => { + let (quit, hard) = if self.escape { + self.escape = false; + self.handle_key_escape(key).await + } else if key == textmode::Key::Ctrl(b'e') { + self.escape = true; + (false, false) + } else { + match self.focus { + Focus::Readline => { + self.handle_key_readline(key, event_w.clone()) + .await + } + Focus::History(idx) => { + self.handle_key_history(key, idx).await; + (false, false) + } + Focus::Scrolling(_) => { + self.handle_key_escape(key).await + } + } + }; + if quit { + event_w.send(crate::event::Event::Quit).await.unwrap(); + } + if hard { + hard_refresh = true; } } - crate::action::Action::Render => { - // for instance, if we are rerendering because of command - // output, that output could increase the number of lines of - // output of a command, pushing the currently focused entry - // off the top of the screen + crate::event::Event::Resize(new_size) => { + self.readline.resize(new_size).await; + self.history.resize(new_size).await; + out.set_size(new_size.0, new_size.1); + hard_refresh = true; + } + crate::event::Event::ProcessOutput => { + // the number of visible lines may have changed, so make sure + // the focus is still visible self.history .make_focus_visible( self.readline.lines(), self.focus_idx(), - matches!( - self.focus, - crate::action::Focus::Scrolling(_) - ), + matches!(self.focus, Focus::Scrolling(_)), ) .await; } - crate::action::Action::ForceRedraw => { - hard_refresh = true; - } - crate::action::Action::Run(ref cmd) => { - let idx = - self.history.run(cmd, action_w.clone()).await.unwrap(); - self.set_focus(crate::action::Focus::History(idx), None) - .await; - self.hide_readline = true; - } - crate::action::Action::UpdateFocus(new_focus) => { - self.set_focus(new_focus, None).await; - } - crate::action::Action::UpdateScene(new_scene) => { - self.scene = new_scene; - } - crate::action::Action::CheckUpdateScene => { + crate::event::Event::ProcessAlternateScreen => { self.scene = self.default_scene(self.focus, None).await; } - crate::action::Action::Resize(new_size) => { - self.readline.resize(new_size).await; - self.history.resize(new_size).await; - out.set_size(new_size.0, new_size.1); - out.hard_refresh().await.unwrap(); + crate::event::Event::ProcessExit => { + self.set_focus(Focus::Readline, None).await; } - crate::action::Action::Quit => { + crate::event::Event::ClockTimer => {} + crate::event::Event::Quit => { // the debouncer should return None in this case unreachable!(); } @@ -176,51 +196,20 @@ impl State { self.render(out, hard_refresh).await.unwrap(); } - async fn handle_key( - &mut self, - key: textmode::Key, - ) -> Option { - if self.escape { - self.escape = false; - self.handle_key_escape(key).await - } else if key == textmode::Key::Ctrl(b'e') { - self.escape = true; - None - } else { - match self.focus { - crate::action::Focus::Readline => { - self.readline - .handle_key(key, self.history.entry_count()) - .await - } - crate::action::Focus::History(idx) => { - self.history.handle_key(key, idx).await; - None - } - crate::action::Focus::Scrolling(_) => { - self.handle_key_escape(key).await - } - } - } - } - async fn handle_key_escape( &mut self, key: textmode::Key, - ) -> Option { + ) -> (bool, bool) { match key { textmode::Key::Ctrl(b'd') => { - return Some(crate::action::Action::Quit); + return (true, false); } textmode::Key::Ctrl(b'e') => { - self.set_focus( - crate::action::Focus::Scrolling(self.focus_idx()), - None, - ) - .await; + self.set_focus(Focus::Scrolling(self.focus_idx()), None) + .await; } textmode::Key::Ctrl(b'l') => { - return Some(crate::action::Action::ForceRedraw); + return (false, true); } textmode::Key::Ctrl(b'm') => { let idx = self.focus_idx(); @@ -232,8 +221,8 @@ impl State { }; if focus { self.set_focus( - idx.map_or(crate::action::Focus::Readline, |idx| { - crate::action::Focus::History(idx) + idx.map_or(Focus::Readline, |idx| { + Focus::History(idx) }), entry, ) @@ -244,31 +233,25 @@ impl State { if let Some(idx) = self.focus_idx() { let entry = self.history.entry(idx).await; self.readline.set_input(&entry.cmd()); - self.set_focus( - crate::action::Focus::Readline, - Some(entry), - ) - .await; + self.set_focus(Focus::Readline, Some(entry)).await; } } textmode::Key::Char('e') => { - if let crate::action::Focus::History(idx) = self.focus { - self.history - .handle_key(textmode::Key::Ctrl(b'e'), idx) + if let Focus::History(idx) = self.focus { + self.handle_key_history(textmode::Key::Ctrl(b'e'), idx) .await; } } textmode::Key::Char('f') => { if let Some(idx) = self.focus_idx() { let mut entry = self.history.entry(idx).await; - let mut focus = crate::action::Focus::History(idx); - if let crate::action::Focus::Scrolling(_) = self.focus { + let mut focus = Focus::History(idx); + if let Focus::Scrolling(_) = self.focus { entry.set_fullscreen(true); } else { entry.toggle_fullscreen(); if !entry.should_fullscreen() && !entry.running() { - focus = - crate::action::Focus::Scrolling(Some(idx)); + focus = Focus::Scrolling(Some(idx)); } } self.set_focus(focus, Some(entry)).await; @@ -276,50 +259,94 @@ impl State { } textmode::Key::Char('j') | textmode::Key::Down => { self.set_focus( - crate::action::Focus::Scrolling( - self.scroll_down(self.focus_idx()), - ), + Focus::Scrolling(self.scroll_down(self.focus_idx())), None, ) .await; } textmode::Key::Char('k') | textmode::Key::Up => { self.set_focus( - crate::action::Focus::Scrolling( - self.scroll_up(self.focus_idx()), - ), + Focus::Scrolling(self.scroll_up(self.focus_idx())), None, ) .await; } textmode::Key::Char('r') => { - self.set_focus(crate::action::Focus::Readline, None).await; + self.set_focus(Focus::Readline, None).await; + } + _ => {} + } + (false, false) + } + + async fn handle_key_readline( + &mut self, + key: textmode::Key, + event_w: async_std::channel::Sender, + ) -> (bool, bool) { + match key { + textmode::Key::Char(c) => { + self.readline.add_input(&c.to_string()); + } + textmode::Key::Ctrl(b'c') => self.readline.clear_input(), + textmode::Key::Ctrl(b'd') => { + return (true, false); + } + textmode::Key::Ctrl(b'l') => { + return (false, true); + } + textmode::Key::Ctrl(b'm') => { + let cmd = self.readline.input(); + self.readline.clear_input(); + let idx = + self.history.run(&cmd, event_w.clone()).await.unwrap(); + self.set_focus(Focus::History(idx), None).await; + self.hide_readline = true; + } + textmode::Key::Ctrl(b'u') => self.readline.clear_backwards(), + textmode::Key::Backspace => self.readline.backspace(), + textmode::Key::Left => self.readline.cursor_left(), + textmode::Key::Right => self.readline.cursor_right(), + textmode::Key::Up => { + let entry_count = self.history.entry_count(); + if entry_count > 0 { + self.set_focus( + Focus::Scrolling(Some(entry_count - 1)), + None, + ) + .await; + } } _ => {} } - Some(crate::action::Action::Render) + (false, false) + } + + async fn handle_key_history(&mut self, key: textmode::Key, idx: usize) { + self.history + .entry(idx) + .await + .send_input(key.into_bytes()) + .await; } async fn default_scene( &self, - focus: crate::action::Focus, + focus: Focus, entry: Option>, - ) -> crate::action::Scene { + ) -> Scene { match focus { - crate::action::Focus::Readline - | crate::action::Focus::Scrolling(_) => { - crate::action::Scene::Readline - } - crate::action::Focus::History(idx) => { + Focus::Readline | Focus::Scrolling(_) => Scene::Readline, + Focus::History(idx) => { let fullscreen = if let Some(entry) = entry { entry.should_fullscreen() } else { self.history.entry(idx).await.should_fullscreen() }; if fullscreen { - crate::action::Scene::Fullscreen + Scene::Fullscreen } else { - crate::action::Scene::Readline + Scene::Readline } } } @@ -327,7 +354,7 @@ impl State { async fn set_focus( &mut self, - new_focus: crate::action::Focus, + new_focus: Focus, entry: Option>, ) { self.focus = new_focus; @@ -341,16 +368,16 @@ impl State { .make_focus_visible( self.readline.lines(), self.focus_idx(), - matches!(self.focus, crate::action::Focus::Scrolling(_)), + matches!(self.focus, Focus::Scrolling(_)), ) .await; } fn focus_idx(&self) -> Option { match self.focus { - crate::action::Focus::History(idx) => Some(idx), - crate::action::Focus::Readline => None, - crate::action::Focus::Scrolling(idx) => idx, + Focus::History(idx) => Some(idx), + Focus::Readline => None, + Focus::Scrolling(idx) => idx, } } -- cgit v1.2.3-54-g00ecf