diff --git a/atuin/src/command/client/search/interactive.rs b/atuin/src/command/client/search/interactive.rs index db927d26..5076d528 100644 --- a/atuin/src/command/client/search/interactive.rs +++ b/atuin/src/command/client/search/interactive.rs @@ -42,6 +42,7 @@ struct State { results_state: ListState, switched_search_mode: bool, search_mode: SearchMode, + results_len: usize, search: SearchState, engine: Box, @@ -58,27 +59,26 @@ impl State { async fn query_results(&mut self, db: &mut dyn Database) -> Result> { let results = self.engine.query(&self.search, db).await?; self.results_state.select(0); + self.results_len = results.len(); Ok(results) } - fn handle_input(&mut self, settings: &Settings, input: &Event, len: usize) -> Option { + fn handle_input(&mut self, settings: &Settings, input: &Event) -> Option { match input { - Event::Key(k) => self.handle_key_input(settings, k, len), - Event::Mouse(m) => self.handle_mouse_input(*m, len), + Event::Key(k) => self.handle_key_input(settings, k), + Event::Mouse(m) => self.handle_mouse_input(*m), Event::Paste(d) => self.handle_paste_input(d), _ => None, } } - fn handle_mouse_input(&mut self, input: MouseEvent, len: usize) -> Option { + fn handle_mouse_input(&mut self, input: MouseEvent) -> Option { match input.kind { event::MouseEventKind::ScrollDown => { - let i = self.results_state.selected().saturating_sub(1); - self.results_state.select(i); + self.scroll_down(1); } event::MouseEventKind::ScrollUp => { - let i = self.results_state.selected() + 1; - self.results_state.select(i.min(len - 1)); + self.scroll_up(1); } _ => {} } @@ -94,12 +94,7 @@ impl State { #[allow(clippy::too_many_lines)] #[allow(clippy::cognitive_complexity)] - fn handle_key_input( - &mut self, - settings: &Settings, - input: &KeyEvent, - len: usize, - ) -> Option { + fn handle_key_input(&mut self, settings: &Settings, input: &KeyEvent) -> Option { if input.kind == event::KeyEventKind::Release { return None; } @@ -211,39 +206,45 @@ impl State { }) } KeyCode::Down if !settings.invert => { - let i = self.results_state.selected().saturating_sub(1); - self.results_state.select(i); + self.scroll_down(1); } KeyCode::Up if settings.invert => { - let i = self.results_state.selected().saturating_sub(1); - self.results_state.select(i); + self.scroll_down(1); } - KeyCode::Char('n' | 'j') if ctrl => { - let i = self.results_state.selected().saturating_sub(1); - self.results_state.select(i); + KeyCode::Char('n' | 'j') if ctrl && !settings.invert => { + self.scroll_down(1); + } + KeyCode::Char('n' | 'j') if ctrl && settings.invert => { + self.scroll_up(1); } KeyCode::Up if !settings.invert => { - let i = self.results_state.selected() + 1; - self.results_state.select(i.min(len - 1)); + self.scroll_up(1); } KeyCode::Down if settings.invert => { - let i = self.results_state.selected() + 1; - self.results_state.select(i.min(len - 1)); + self.scroll_up(1); } - KeyCode::Char('p' | 'k') if ctrl => { - let i = self.results_state.selected() + 1; - self.results_state.select(i.min(len - 1)); + KeyCode::Char('p' | 'k') if ctrl && !settings.invert => { + self.scroll_up(1); + } + KeyCode::Char('p' | 'k') if ctrl && settings.invert => { + self.scroll_down(1); } KeyCode::Char(c) => self.search.input.insert(c), - KeyCode::PageDown => { + KeyCode::PageDown if !settings.invert => { let scroll_len = self.results_state.max_entries() - settings.scroll_context_lines; - let i = self.results_state.selected().saturating_sub(scroll_len); - self.results_state.select(i); + self.scroll_down(scroll_len); } - KeyCode::PageUp => { + KeyCode::PageDown if settings.invert => { let scroll_len = self.results_state.max_entries() - settings.scroll_context_lines; - let i = self.results_state.selected() + scroll_len; - self.results_state.select(i.min(len - 1)); + self.scroll_up(scroll_len); + } + KeyCode::PageUp if !settings.invert => { + let scroll_len = self.results_state.max_entries() - settings.scroll_context_lines; + self.scroll_up(scroll_len); + } + KeyCode::PageUp if settings.invert => { + let scroll_len = self.results_state.max_entries() - settings.scroll_context_lines; + self.scroll_down(scroll_len); } _ => {} }; @@ -251,6 +252,16 @@ impl State { None } + fn scroll_down(&mut self, scroll_len: usize) { + let i = self.results_state.selected().saturating_sub(scroll_len); + self.results_state.select(i); + } + + fn scroll_up(&mut self, scroll_len: usize) { + let i = self.results_state.selected() + scroll_len; + self.results_state.select(i.min(self.results_len - 1)); + } + #[allow(clippy::cast_possible_truncation)] #[allow(clippy::bool_to_int_with_if)] fn draw(&mut self, f: &mut Frame<'_, T>, results: &[History], settings: &Settings) { @@ -579,6 +590,7 @@ pub async fn history( }, }, engine: engines::engine(settings.search_mode), + results_len: 0, }; let mut results = app.query_results(&mut db).await?; @@ -596,7 +608,7 @@ pub async fn history( event_ready = event_ready => { if event_ready?? { loop { - if let Some(i) = app.handle_input(settings, &event::read()?, results.len()) { + if let Some(i) = app.handle_input(settings, &event::read()?) { break 'render i; } if !event::poll(Duration::ZERO)? {