From 4682a1b75bafc06e7747f93da6cd5d084bd0bd11 Mon Sep 17 00:00:00 2001 From: Ammar Abou Zor <35040531+AmmarAbouZor@users.noreply.github.com> Date: Sat, 8 Jul 2023 12:29:47 +0200 Subject: [PATCH] Make fuzzy find popup scrollable (#1734) * Added: Make fuzzy find popup scrollable * Fuzzy_find: Add scrollbar to matches list * Update CHANGELOG --- CHANGELOG.md | 1 + src/components/fuzzy_find_popup.rs | 134 ++++++++++++++++++----------- 2 files changed, 86 insertions(+), 49 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc488145..bceb3118 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * allow `copy` file path on revision files and status tree [[@yanganto]](https://github.com/yanganto) ([#1516](https://github.com/extrawurst/gitui/pull/1516)) * print message of where log will be written if `-l` is set ([#1472](https://github.com/extrawurst/gitui/pull/1472)) * show remote branches in log [[@cruessler](https://github.com/cruessler)] ([#1501](https://github.com/extrawurst/gitui/issues/1501)) +* scrolling functionality to fuzzy-find [[@AmmarAbouZor](https://github.com/AmmarAbouZor)] ([#1732](https://github.com/extrawurst/gitui/issues/1732)) ### Fixes * fixed side effect of crossterm 0.26 on windows that caused double input of all keys [[@pm100]](https://github/pm100) ([#1686](https://github.com/extrawurst/gitui/pull/1686)) diff --git a/src/components/fuzzy_find_popup.rs b/src/components/fuzzy_find_popup.rs index 1235b7c3..cb9bfd8a 100644 --- a/src/components/fuzzy_find_popup.rs +++ b/src/components/fuzzy_find_popup.rs @@ -172,6 +172,90 @@ impl FuzzyFindPopup { false } + + #[inline] + fn draw_matches_list( + &self, + f: &mut Frame, + mut area: Rect, + ) { + { + // Block has two lines up and down which need to be considered + const HEIGHT_BLOCK_MARGIN: usize = 2; + + let title = format!("Hits: {}", self.filtered.len()); + + let height = usize::from(area.height); + let width = usize::from(area.width); + + let list_height = + height.saturating_sub(HEIGHT_BLOCK_MARGIN); + + let scroll_skip = + self.selection.saturating_sub(list_height); + + let items = self + .filtered + .iter() + .skip(scroll_skip) + .take(height) + .map(|(idx, indicies)| { + let selected = self + .selected_index + .map_or(false, |index| index == *idx); + let full_text = + trim_length_left(&self.contents[*idx], width); + let trim_length = + self.contents[*idx].graphemes(true).count() + - full_text.graphemes(true).count(); + Line::from( + full_text + .graphemes(true) + .enumerate() + .map(|(c_idx, c)| { + Span::styled( + Cow::from(c.to_string()), + self.theme.text( + selected, + indicies.contains( + &(c_idx + trim_length), + ), + ), + ) + }) + .collect::>(), + ) + }); + + ui::draw_list_block( + f, + area, + Block::default() + .title(Span::styled( + title, + self.theme.title(true), + )) + .borders(Borders::TOP), + items, + ); + + // Draw scrollbar when needed + if self.filtered.len() > list_height { + // Reset list area margin + area.width += 1; + area.height += 1; + + ui::draw_scrollbar( + f, + area, + &self.theme, + self.filtered.len().saturating_sub(1), + self.selection, + ui::Orientation::Vertical, + ); + } + } + } } impl DrawableComponent for FuzzyFindPopup { @@ -233,55 +317,7 @@ impl DrawableComponent for FuzzyFindPopup { self.find_text.draw(f, chunks[0])?; if any_hits { - let title = format!("Hits: {}", self.filtered.len()); - - let height = usize::from(chunks[1].height); - let width = usize::from(chunks[1].width); - - let items = - self.filtered.iter().take(height).map( - |(idx, indicies)| { - let selected = self - .selected_index - .map_or(false, |index| index == *idx); - let full_text = trim_length_left( - &self.contents[*idx], - width, - ); - let trim_length = self.contents[*idx] - .graphemes(true) - .count() - full_text - .graphemes(true) - .count(); - Line::from( - full_text - .graphemes(true) - .enumerate() - .map(|(c_idx, c)| { - Span::styled( - Cow::from(c.to_string()), - self.theme.text( - selected, - indicies.contains(&(c_idx + trim_length)), - ), - ) - }) - .collect::>(), - ) - }, - ); - - ui::draw_list_block( - f, - chunks[1], - Block::default() - .title(Span::styled( - title, - self.theme.title(true), - )) - .borders(Borders::TOP), - items, - ); + self.draw_matches_list(f, chunks[1]); } } Ok(())