From 230bf2d1c63b818d09f6da04d23e03d20019e40a Mon Sep 17 00:00:00 2001 From: Nemo157 Date: Fri, 26 Jan 2024 11:49:04 +0100 Subject: [PATCH] feat(ui): When in vim-normal mode apply an alternative highlighting to the selected line (#1574) This makes it much more obvious whether you're in normal or insert mode. --- .../src/command/client/search/history_list.rs | 27 +++++++++++++++---- .../src/command/client/search/interactive.rs | 11 +++++--- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/atuin/src/command/client/search/history_list.rs b/atuin/src/command/client/search/history_list.rs index 39c1dc32..31c2ac53 100644 --- a/atuin/src/command/client/search/history_list.rs +++ b/atuin/src/command/client/search/history_list.rs @@ -16,6 +16,8 @@ pub struct HistoryList<'a> { history: &'a [History], block: Option>, inverted: bool, + /// Apply an alternative highlighting to the selected row + alternate_highlight: bool, } #[derive(Default)] @@ -65,6 +67,7 @@ impl<'a> StatefulWidget for HistoryList<'a> { y: 0, state, inverted: self.inverted, + alternate_highlight: self.alternate_highlight, }; for item in self.history.iter().skip(state.offset).take(end - start) { @@ -81,11 +84,12 @@ impl<'a> StatefulWidget for HistoryList<'a> { } impl<'a> HistoryList<'a> { - pub fn new(history: &'a [History], inverted: bool) -> Self { + pub fn new(history: &'a [History], inverted: bool, alternate_highlight: bool) -> Self { Self { history, block: None, inverted, + alternate_highlight, } } @@ -116,11 +120,14 @@ struct DrawState<'a> { y: u16, state: &'a ListState, inverted: bool, + alternate_highlight: bool, } // longest line prefix I could come up with #[allow(clippy::cast_possible_truncation)] // we know that this is <65536 length pub const PREFIX_LENGTH: u16 = " > 123ms 59s ago".len() as u16; +static SPACES: &str = " "; +static _ASSERT: () = assert!(SPACES.len() == PREFIX_LENGTH as usize); impl DrawState<'_> { fn index(&mut self) { @@ -157,7 +164,10 @@ impl DrawState<'_> { let time = format_duration(since.try_into().unwrap_or_default()); // pad the time a little bit before we write. this aligns things nicely - self.x = PREFIX_LENGTH - 4 - time.len() as u16; + self.draw( + &SPACES[..((PREFIX_LENGTH - self.x) as usize - 4 - time.len())], + Style::default(), + ); self.draw(&time, style); self.draw(" ago", style); @@ -165,12 +175,14 @@ impl DrawState<'_> { fn command(&mut self, h: &History) { let mut style = Style::default(); - if self.y as usize + self.state.offset == self.state.selected { + if !self.alternate_highlight && (self.y as usize + self.state.offset == self.state.selected) + { + // if not applying alternative highlighting to the whole row, color the command style = style.fg(Color::Red).add_modifier(Modifier::BOLD); } for section in h.command.escape_control().split_ascii_whitespace() { - self.x += 1; + self.draw(" ", style); if self.x > self.list_area.width { // Avoid attempting to draw a command section beyond the width // of the list @@ -180,7 +192,7 @@ impl DrawState<'_> { } } - fn draw(&mut self, s: &str, style: Style) { + fn draw(&mut self, s: &str, mut style: Style) { let cx = self.list_area.left() + self.x; let cy = if self.inverted { @@ -189,6 +201,11 @@ impl DrawState<'_> { self.list_area.bottom() - self.y - 1 }; + if self.alternate_highlight && (self.y as usize + self.state.offset == self.state.selected) + { + style = style.add_modifier(Modifier::REVERSED); + } + let w = (self.list_area.width - self.x) as usize; self.x += self.buf.set_stringn(cx, cy, s, w, style).0 - cx; } diff --git a/atuin/src/command/client/search/interactive.rs b/atuin/src/command/client/search/interactive.rs index 8647b146..1fc37b57 100644 --- a/atuin/src/command/client/search/interactive.rs +++ b/atuin/src/command/client/search/interactive.rs @@ -550,7 +550,7 @@ impl State { match self.tab_index { 0 => { - let results_list = Self::build_results_list(style, results); + let results_list = Self::build_results_list(style, results, self.keymap_mode); f.render_stateful_widget(results_list, results_list_chunk, &mut self.results_state); } @@ -652,8 +652,13 @@ impl State { stats } - fn build_results_list(style: StyleState, results: &[History]) -> HistoryList { - let results_list = HistoryList::new(results, style.invert); + fn build_results_list( + style: StyleState, + results: &[History], + keymap_mode: KeymapMode, + ) -> HistoryList<'_> { + let results_list = + HistoryList::new(results, style.invert, keymap_mode == KeymapMode::VimNormal); if style.compact { results_list