summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2021-12-11 17:54:10 -0500
committerJesse Luehrs <doy@tozt.net>2021-12-11 17:55:19 -0500
commit62fe2477fb8bbbfbca34779b992979f9c1a8ba53 (patch)
treea4c12df90fefa5b1f2b81905ed3f6ca2d1dcd079
parent6ca82f5be15f1c6c936c82266d1f6dc13185346c (diff)
downloadnbsh-62fe2477fb8bbbfbca34779b992979f9c1a8ba53.tar.gz
nbsh-62fe2477fb8bbbfbca34779b992979f9c1a8ba53.zip
move key handling into the main event loop
-rw-r--r--src/action.rs7
-rw-r--r--src/main.rs17
-rw-r--r--src/state.rs253
3 files changed, 139 insertions, 138 deletions
diff --git a/src/action.rs b/src/action.rs
index 2cb28c1..ff0402b 100644
--- a/src/action.rs
+++ b/src/action.rs
@@ -1,5 +1,6 @@
#[derive(Debug)]
pub enum Action {
+ Key(textmode::Key),
Render,
ForceRedraw,
Run(String),
@@ -67,6 +68,7 @@ impl Reader {
#[derive(Default)]
struct Pending {
+ key: std::collections::VecDeque<textmode::Key>,
render: Option<()>,
force_redraw: Option<()>,
run: std::collections::VecDeque<String>,
@@ -84,6 +86,7 @@ impl Pending {
fn has_action(&self) -> bool {
self.done
+ || !self.key.is_empty()
|| self.render.is_some()
|| self.force_redraw.is_some()
|| !self.run.is_empty()
@@ -97,6 +100,9 @@ impl Pending {
if self.done {
return None;
}
+ if !self.key.is_empty() {
+ return Some(Action::Key(self.key.pop_front().unwrap()));
+ }
if self.size.is_some() {
return Some(Action::Resize(self.size.take().unwrap()));
}
@@ -124,6 +130,7 @@ impl Pending {
fn new_action(&mut self, action: &Option<Action>) {
match action {
+ Some(Action::Key(key)) => self.key.push_back(key.clone()),
Some(Action::Render) => self.render = Some(()),
Some(Action::ForceRedraw) => self.force_redraw = Some(()),
Some(Action::Run(cmd)) => self.run.push_back(cmd.to_string()),
diff --git a/src/main.rs b/src/main.rs
index 6f7046b..1a15f6e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -61,11 +61,9 @@ async fn async_main() -> anyhow::Result<()> {
let (action_w, action_r) = async_std::channel::unbounded();
- let state = state::State::new(get_offset());
+ let mut state = state::State::new(get_offset());
state.render(&mut output, true).await.unwrap();
- let state = util::mutex(state);
-
{
let mut signals = signal_hook_async_std::Signals::new(&[
signal_hook::consts::signal::SIGWINCH,
@@ -81,15 +79,10 @@ async fn async_main() -> anyhow::Result<()> {
resize(&action_w).await;
{
- let state = async_std::sync::Arc::clone(&state);
let action_w = action_w.clone();
async_std::task::spawn(async move {
while let Some(key) = input.read_key().await.unwrap() {
- if let Some(action) =
- state.lock_arc().await.handle_key(key).await
- {
- action_w.send(action).await.unwrap();
- }
+ action_w.send(action::Action::Key(key)).await.unwrap();
}
});
}
@@ -117,11 +110,7 @@ async fn async_main() -> anyhow::Result<()> {
let action_reader = action::Reader::new(action_r);
while let Some(action) = action_reader.recv().await {
- state
- .lock_arc()
- .await
- .handle_action(action, &mut output, &action_w)
- .await;
+ state.handle_action(action, &mut output, &action_w).await;
}
Ok(())
diff --git a/src/state.rs b/src/state.rs
index 6ecfa07..f086334 100644
--- a/src/state.rs
+++ b/src/state.rs
@@ -23,130 +23,6 @@ impl State {
}
}
- pub async fn handle_key(
- &mut self,
- key: textmode::Key,
- ) -> Option<crate::action::Action> {
- 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<crate::action::Action> {
- match key {
- textmode::Key::Ctrl(b'd') => {
- return Some(crate::action::Action::Quit);
- }
- textmode::Key::Ctrl(b'e') => {
- self.set_focus(
- crate::action::Focus::Scrolling(self.focus_idx()),
- None,
- )
- .await;
- }
- textmode::Key::Ctrl(b'l') => {
- return Some(crate::action::Action::ForceRedraw);
- }
- textmode::Key::Ctrl(b'm') => {
- let idx = self.focus_idx();
- let (focus, entry) = if let Some(idx) = idx {
- let entry = self.history.entry(idx).await;
- (entry.running(), Some(entry))
- } else {
- (true, None)
- };
- if focus {
- self.set_focus(
- idx.map_or(crate::action::Focus::Readline, |idx| {
- crate::action::Focus::History(idx)
- }),
- entry,
- )
- .await;
- }
- }
- textmode::Key::Char(' ') => {
- 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;
- }
- }
- textmode::Key::Char('e') => {
- if let crate::action::Focus::History(idx) = self.focus {
- self.history
- .handle_key(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 {
- entry.set_fullscreen(true);
- } else {
- entry.toggle_fullscreen();
- if !entry.should_fullscreen() && !entry.running() {
- focus =
- crate::action::Focus::Scrolling(Some(idx));
- }
- }
- self.set_focus(focus, Some(entry)).await;
- }
- }
- textmode::Key::Char('j') | textmode::Key::Down => {
- self.set_focus(
- crate::action::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()),
- ),
- None,
- )
- .await;
- }
- textmode::Key::Char('r') => {
- self.set_focus(crate::action::Focus::Readline, None).await;
- }
- _ => {}
- }
- Some(crate::action::Action::Render)
- }
-
pub async fn render(
&self,
out: &mut textmode::Output,
@@ -246,6 +122,11 @@ impl State {
) {
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();
+ }
+ }
crate::action::Action::Render => {
// for instance, if we are rerendering because of command
// output, that output could increase the number of lines of
@@ -295,6 +176,130 @@ impl State {
self.render(out, hard_refresh).await.unwrap();
}
+ async fn handle_key(
+ &mut self,
+ key: textmode::Key,
+ ) -> Option<crate::action::Action> {
+ 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<crate::action::Action> {
+ match key {
+ textmode::Key::Ctrl(b'd') => {
+ return Some(crate::action::Action::Quit);
+ }
+ textmode::Key::Ctrl(b'e') => {
+ self.set_focus(
+ crate::action::Focus::Scrolling(self.focus_idx()),
+ None,
+ )
+ .await;
+ }
+ textmode::Key::Ctrl(b'l') => {
+ return Some(crate::action::Action::ForceRedraw);
+ }
+ textmode::Key::Ctrl(b'm') => {
+ let idx = self.focus_idx();
+ let (focus, entry) = if let Some(idx) = idx {
+ let entry = self.history.entry(idx).await;
+ (entry.running(), Some(entry))
+ } else {
+ (true, None)
+ };
+ if focus {
+ self.set_focus(
+ idx.map_or(crate::action::Focus::Readline, |idx| {
+ crate::action::Focus::History(idx)
+ }),
+ entry,
+ )
+ .await;
+ }
+ }
+ textmode::Key::Char(' ') => {
+ 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;
+ }
+ }
+ textmode::Key::Char('e') => {
+ if let crate::action::Focus::History(idx) = self.focus {
+ self.history
+ .handle_key(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 {
+ entry.set_fullscreen(true);
+ } else {
+ entry.toggle_fullscreen();
+ if !entry.should_fullscreen() && !entry.running() {
+ focus =
+ crate::action::Focus::Scrolling(Some(idx));
+ }
+ }
+ self.set_focus(focus, Some(entry)).await;
+ }
+ }
+ textmode::Key::Char('j') | textmode::Key::Down => {
+ self.set_focus(
+ crate::action::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()),
+ ),
+ None,
+ )
+ .await;
+ }
+ textmode::Key::Char('r') => {
+ self.set_focus(crate::action::Focus::Readline, None).await;
+ }
+ _ => {}
+ }
+ Some(crate::action::Action::Render)
+ }
+
async fn default_scene(
&self,
focus: crate::action::Focus,