diff options
| author | Frank Hamand <frank.hamand@coinbase.com> | 2022-06-13 09:33:05 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-06-13 09:33:05 +0100 |
| commit | ab994e3c827c65966ebc9cd2ac1d3a6048f042bc (patch) | |
| tree | 5b0cd9d58b5f41caca9e6d758abb99fb372c5a28 /src/command | |
| parent | Add configurable history length (#447) (diff) | |
| download | atuin-ab994e3c827c65966ebc9cd2ac1d3a6048f042bc.zip | |
Batch key handling (#448)
* Batch input events and only query once they are finished
This simplifies the code a lot (no more bounded channel) and yields
the same performance improvement with scroll wheel spam while fixing copy/paste
* Clippy
* fmt
* Use blocking wait before emptying events channel
This was causing a busy loop
* Update query on filter mode change
Diffstat (limited to 'src/command')
| -rw-r--r-- | src/command/client/event.rs | 20 | ||||
| -rw-r--r-- | src/command/client/search.rs | 33 |
2 files changed, 27 insertions, 26 deletions
diff --git a/src/command/client/event.rs b/src/command/client/event.rs index f818d728..8044e278 100644 --- a/src/command/client/event.rs +++ b/src/command/client/event.rs @@ -1,6 +1,6 @@ use std::{thread, time::Duration}; -use crossbeam_channel::{bounded, TrySendError}; +use crossbeam_channel::unbounded; use termion::{event::Event as TermEvent, event::Key, input::TermRead}; pub enum Event<I> { @@ -35,22 +35,16 @@ impl Events { } pub fn with_config(config: Config) -> Events { - // Keep channel small so scroll events don't stack for ages. - let (tx, rx) = bounded(1); + let (tx, rx) = unbounded(); { let tx = tx.clone(); thread::spawn(move || { let tty = termion::get_tty().expect("Could not find tty"); for event in tty.events().flatten() { - if let Err(err) = tx.try_send(Event::Input(event)) { - if let TrySendError::Full(_) = err { - // Silently ignore send fails when buffer is full. - // This will most likely be scroll wheel spam and we can drop some events. - } else { - eprintln!("{}", err); - return; - } + if let Err(err) = tx.send(Event::Input(event)) { + eprintln!("{}", err); + return; } } }) @@ -69,4 +63,8 @@ impl Events { pub fn next(&self) -> Result<Event<TermEvent>, crossbeam_channel::RecvError> { self.rx.recv() } + + pub fn try_next(&self) -> Result<Event<TermEvent>, crossbeam_channel::TryRecvError> { + self.rx.try_recv() + } } diff --git a/src/command/client/search.rs b/src/command/client/search.rs index 4e0de683..c50c492c 100644 --- a/src/command/client/search.rs +++ b/src/command/client/search.rs @@ -307,12 +307,7 @@ fn remove_char_from_input(app: &mut State, i: usize) -> char { } #[allow(clippy::too_many_lines)] -async fn key_handler( - input: TermEvent, - search_mode: SearchMode, - db: &mut impl Database, - app: &mut State, -) -> Option<String> { +fn key_handler(input: &TermEvent, app: &mut State) -> Option<String> { match input { TermEvent::Key(Key::Esc | Key::Ctrl('c' | 'd' | 'g')) => return Some(String::from("")), TermEvent::Key(Key::Char('\n')) => { @@ -324,7 +319,7 @@ async fn key_handler( .map_or(app.input.clone(), |h| h.command.clone()), ); } - TermEvent::Key(Key::Alt(c)) if ('1'..='9').contains(&c) => { + TermEvent::Key(Key::Alt(c)) if ('1'..='9').contains(c) => { let c = c.to_digit(10)? as usize; let i = app.results_state.selected()? + c; @@ -351,9 +346,8 @@ async fn key_handler( app.cursor_index = app.input.chars().count(); } TermEvent::Key(Key::Char(c)) => { - insert_char_into_input(app, app.cursor_index, c); + insert_char_into_input(app, app.cursor_index, *c); app.cursor_index += 1; - query_results(app, search_mode, db).await.unwrap(); } TermEvent::Key(Key::Backspace) => { if app.cursor_index == 0 { @@ -361,7 +355,6 @@ async fn key_handler( } remove_char_from_input(app, app.cursor_index); app.cursor_index -= 1; - query_results(app, search_mode, db).await.unwrap(); } TermEvent::Key(Key::Ctrl('w')) => { let mut stop_on_next_whitespace = false; @@ -379,12 +372,10 @@ async fn key_handler( } app.cursor_index -= 1; } - query_results(app, search_mode, db).await.unwrap(); } TermEvent::Key(Key::Ctrl('u')) => { app.input = String::from(""); app.cursor_index = 0; - query_results(app, search_mode, db).await.unwrap(); } TermEvent::Key(Key::Ctrl('r')) => { app.filter_mode = match app.filter_mode { @@ -393,8 +384,6 @@ async fn key_handler( FilterMode::Session => FilterMode::Directory, FilterMode::Directory => FilterMode::Global, }; - - query_results(app, search_mode, db).await.unwrap(); } TermEvent::Key(Key::Down | Key::Ctrl('n' | 'j')) | TermEvent::Mouse(MouseEvent::Press(MouseButton::WheelDown, _, _)) => { @@ -632,13 +621,27 @@ async fn select_history( loop { let history_count = db.history_count().await?; + let initial_input = app.input.clone(); + let initial_filter_mode = app.filter_mode; + // Handle input if let Event::Input(input) = events.next()? { - if let Some(output) = key_handler(input, search_mode, db, &mut app).await { + if let Some(output) = key_handler(&input, &mut app) { return Ok(output); } } + // After we receive input process the whole event channel before query/render. + while let Ok(Event::Input(input)) = events.try_next() { + if let Some(output) = key_handler(&input, &mut app) { + return Ok(output); + } + } + + if initial_input != app.input || initial_filter_mode != app.filter_mode { + query_results(&mut app, search_mode, db).await?; + } + let compact = match style { atuin_client::settings::Style::Auto => { terminal.size().map(|size| size.height < 14).unwrap_or(true) |
