From e55a7547f303c05c0097934f41e52e5da39b557c Mon Sep 17 00:00:00 2001 From: Manos Mertzianis Date: Tue, 11 Oct 2022 03:18:14 +0300 Subject: [PATCH 01/13] implementing picker preview scrolling --- helix-term/src/ui/picker.rs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index a56455d7d569..1e1c1ebd298b 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -204,6 +204,8 @@ impl Component for FilePicker { let inner = inner.inner(&margin); block.render(preview_area, surface); + let mut preview_scroll_offset = self.picker.preview_scroll_offset; + if let Some((path, range)) = self.current_file(cx.editor) { let preview = self.get_preview(&path, cx.editor); let doc = match preview.document() { @@ -226,7 +228,8 @@ impl Component for FilePicker { }) .unwrap_or(0); - let offset = Position::new(first_line, 0); + preview_scroll_offset = preview_scroll_offset.min(doc.text().len_lines()); + let offset = Position::new(first_line + preview_scroll_offset, 0); let highlights = EditorView::doc_syntax_highlights(doc, offset, area.height, &cx.editor.theme); @@ -258,6 +261,9 @@ impl Component for FilePicker { ); } } + + // Limits the preview scroll between 0 and doc's len_lines() in case it moves past the line number + self.picker.preview_scroll_offset = preview_scroll_offset; } fn handle_event(&mut self, event: &Event, ctx: &mut Context) -> EventResult { @@ -297,6 +303,7 @@ pub struct Picker { // pattern: String, prompt: Prompt, previous_pattern: String, + preview_scroll_offset: usize, /// Whether to truncate the start (default true) pub truncate_start: bool, /// Whether to show the preview panel (default true) @@ -327,6 +334,7 @@ impl Picker { cursor: 0, prompt, previous_pattern: String::new(), + preview_scroll_offset: 0, truncate_start: true, show_preview: true, callback_fn: Box::new(callback_fn), @@ -434,6 +442,18 @@ impl Picker { } } + // Move the picker file preview by a number of lines, either down (`Forward`) or up (`Backward`) + pub fn move_preview_by(&mut self, amount: usize, direction: Direction) { + self.preview_scroll_offset = match direction { + Direction::Forward => { + self.preview_scroll_offset.saturating_add(amount) + }, + Direction::Backward => { + self.preview_scroll_offset.saturating_sub(amount) + }, + }; + } + /// Move the cursor down by exactly one page. After the last page comes the first page. pub fn page_up(&mut self) { self.move_by(self.completion_height as usize, Direction::Backward); @@ -509,6 +529,12 @@ impl Component for Picker { shift!(Tab) | key!(Up) | ctrl!('p') => { self.move_by(1, Direction::Backward); } + shift!(Up) => { + self.move_preview_by(cx.editor.config().scroll_lines.unsigned_abs(), Direction::Backward); + } + shift!(Down) => { + self.move_preview_by(cx.editor.config().scroll_lines.unsigned_abs(), Direction::Forward); + } key!(Tab) | key!(Down) | ctrl!('n') => { self.move_by(1, Direction::Forward); } From 68f87160c7712d7e0db54e501a602f3e573fcb98 Mon Sep 17 00:00:00 2001 From: Manos Mertzianis Date: Tue, 11 Oct 2022 14:04:04 +0300 Subject: [PATCH 02/13] fixed reset scroll on move_by, reorganized key_event matching --- helix-term/src/ui/picker.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 1e1c1ebd298b..e42e25c3182a 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -440,17 +440,16 @@ impl Picker { self.cursor = self.cursor.saturating_add(len).saturating_sub(amount) % len; } } + + // Reset the preview scroll on pointing to a different file + self.preview_scroll_offset = 0; } // Move the picker file preview by a number of lines, either down (`Forward`) or up (`Backward`) pub fn move_preview_by(&mut self, amount: usize, direction: Direction) { self.preview_scroll_offset = match direction { - Direction::Forward => { - self.preview_scroll_offset.saturating_add(amount) - }, - Direction::Backward => { - self.preview_scroll_offset.saturating_sub(amount) - }, + Direction::Forward => self.preview_scroll_offset.saturating_add(amount), + Direction::Backward => self.preview_scroll_offset.saturating_sub(amount), }; } @@ -529,12 +528,6 @@ impl Component for Picker { shift!(Tab) | key!(Up) | ctrl!('p') => { self.move_by(1, Direction::Backward); } - shift!(Up) => { - self.move_preview_by(cx.editor.config().scroll_lines.unsigned_abs(), Direction::Backward); - } - shift!(Down) => { - self.move_preview_by(cx.editor.config().scroll_lines.unsigned_abs(), Direction::Forward); - } key!(Tab) | key!(Down) | ctrl!('n') => { self.move_by(1, Direction::Forward); } @@ -550,6 +543,12 @@ impl Component for Picker { key!(End) => { self.to_end(); } + shift!(Up) => { + self.move_preview_by(cx.editor.config().scroll_lines.unsigned_abs(), Direction::Backward); + } + shift!(Down) => { + self.move_preview_by(cx.editor.config().scroll_lines.unsigned_abs(), Direction::Forward); + } key!(Esc) | ctrl!('c') => { return close_fn; } From 05d14b3513e4a6287a6d5e457455c8631641ca46 Mon Sep 17 00:00:00 2001 From: Manos Mertzianis Date: Wed, 12 Oct 2022 17:32:44 +0300 Subject: [PATCH 03/13] changed keybindings to alt+u alt+d --- helix-term/src/ui/picker.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index e42e25c3182a..c2f26b90e022 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -1,4 +1,5 @@ use crate::{ + alt, compositor::{Component, Compositor, Context, Event, EventResult}, ctrl, key, shift, ui::{self, EditorView}, @@ -228,6 +229,7 @@ impl Component for FilePicker { }) .unwrap_or(0); + // Limits the preview scroll between 0 and doc's len_lines() in case it moves past the line number preview_scroll_offset = preview_scroll_offset.min(doc.text().len_lines()); let offset = Position::new(first_line + preview_scroll_offset, 0); @@ -243,6 +245,9 @@ impl Component for FilePicker { &cx.editor.config(), ); + // update after use of `doc` because of lifetime issues with get_preview() + self.picker.preview_scroll_offset = preview_scroll_offset; + // highlight the line if let Some((start, end)) = range { let offset = start.saturating_sub(first_line) as u16; @@ -261,9 +266,6 @@ impl Component for FilePicker { ); } } - - // Limits the preview scroll between 0 and doc's len_lines() in case it moves past the line number - self.picker.preview_scroll_offset = preview_scroll_offset; } fn handle_event(&mut self, event: &Event, ctx: &mut Context) -> EventResult { @@ -445,7 +447,7 @@ impl Picker { self.preview_scroll_offset = 0; } - // Move the picker file preview by a number of lines, either down (`Forward`) or up (`Backward`) + /// Moves the picker file preview by a number of lines, either down (`Forward`) or up (`Backward`) pub fn move_preview_by(&mut self, amount: usize, direction: Direction) { self.preview_scroll_offset = match direction { Direction::Forward => self.preview_scroll_offset.saturating_add(amount), @@ -543,11 +545,17 @@ impl Component for Picker { key!(End) => { self.to_end(); } - shift!(Up) => { - self.move_preview_by(cx.editor.config().scroll_lines.unsigned_abs(), Direction::Backward); + alt!('u') | shift!(Up) => { + self.move_preview_by( + cx.editor.config().scroll_lines.unsigned_abs(), + Direction::Backward, + ); } - shift!(Down) => { - self.move_preview_by(cx.editor.config().scroll_lines.unsigned_abs(), Direction::Forward); + alt!('d') | shift!(Down) => { + self.move_preview_by( + cx.editor.config().scroll_lines.unsigned_abs(), + Direction::Forward, + ); } key!(Esc) | ctrl!('c') => { return close_fn; From 6f750579baf9b552989465ab98182748ba965f7b Mon Sep 17 00:00:00 2001 From: Manos Mertzianis Date: Thu, 13 Oct 2022 14:46:49 +0300 Subject: [PATCH 04/13] better code design for preview management, fixed scrolling up on nonzero first line, fixed highlights move on scroll --- helix-term/src/ui/picker.rs | 194 +++++++++++++++++++++++++----------- 1 file changed, 138 insertions(+), 56 deletions(-) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index c2f26b90e022..4d22f7ba8ad2 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -46,6 +46,11 @@ pub struct FilePicker { read_buffer: Vec, /// Given an item in the picker, return the file path and line number to display. file_fn: Box Option>, + + /// Line offset from preview's starting point(first_line) to enable preview scrolling + preview_scroll_offset: (Direction, usize), + /// Whether to show the preview panel (default true) + show_preview: bool, } pub enum CachedPreview { @@ -102,6 +107,8 @@ impl FilePicker { preview_cache: HashMap::new(), read_buffer: Vec::with_capacity(1024), file_fn: Box::new(preview_fn), + preview_scroll_offset: (Direction::Forward, 0), + show_preview: true, } } @@ -159,9 +166,61 @@ impl FilePicker { }, ) .unwrap_or(CachedPreview::NotFound); + self.preview_cache.insert(path.to_owned(), preview); Preview::Cached(&self.preview_cache[path]) } + + /// Moves the picker file preview by a number of lines, either down (`Forward`) or up (`Backward`) + fn move_preview_by(&mut self, amount: usize, move_direction: Direction) { + let (current_scroll_direction, current_scroll_offset) = self.preview_scroll_offset; + + match move_direction { + Direction::Backward => match current_scroll_direction { + Direction::Backward => { + self.preview_scroll_offset.1 = current_scroll_offset.saturating_add(amount); + } + Direction::Forward => { + if let Some(change) = current_scroll_offset.checked_sub(amount) { + self.preview_scroll_offset.1 = change; + } else { + self.preview_scroll_offset = ( + Direction::Backward, + amount.saturating_sub(current_scroll_offset), + ); + } + } + }, + Direction::Forward => match current_scroll_direction { + Direction::Backward => { + if let Some(change) = current_scroll_offset.checked_sub(amount) { + self.preview_scroll_offset.1 = change; + } else { + self.preview_scroll_offset = ( + Direction::Forward, + amount.saturating_sub(current_scroll_offset), + ); + } + } + Direction::Forward => { + self.preview_scroll_offset.1 = current_scroll_offset.saturating_add(amount); + } + }, + }; + } + + /// Updates FilePicker state if picker::cursor_moved is `true`. + /// Used for resetting the preview scroll offset on Picker::move_by() + fn on_cursor_move_update(&mut self) { + if self.picker.cursor_moved { + self.preview_scroll_offset.1 = 0; + self.picker.cursor_moved = false; + } + } + + fn toggle_preview(&mut self) { + self.show_preview = !self.show_preview; + } } impl Component for FilePicker { @@ -173,7 +232,7 @@ impl Component for FilePicker { // | | | | // +---------+ +---------+ - let render_preview = self.picker.show_preview && area.width > MIN_AREA_WIDTH_FOR_PREVIEW; + let render_preview = self.show_preview && area.width > MIN_AREA_WIDTH_FOR_PREVIEW; // -- Render the frame: // clear area let background = cx.editor.theme.get("ui.background"); @@ -205,7 +264,10 @@ impl Component for FilePicker { let inner = inner.inner(&margin); block.render(preview_area, surface); - let mut preview_scroll_offset = self.picker.preview_scroll_offset; + self.on_cursor_move_update(); + // we get the scroll offset here because the lifetimes of + // FilePicker::get_preview() prohibit the use of self until the final use of doc: `&Document` + let mut preview_scroll_offset = self.preview_scroll_offset; if let Some((path, range)) = self.current_file(cx.editor) { let preview = self.get_preview(&path, cx.editor); @@ -229,9 +291,27 @@ impl Component for FilePicker { }) .unwrap_or(0); - // Limits the preview scroll between 0 and doc's len_lines() in case it moves past the line number - preview_scroll_offset = preview_scroll_offset.min(doc.text().len_lines()); - let offset = Position::new(first_line + preview_scroll_offset, 0); + // limit scroll offset between [-first_line, doc.text().len_lines() - first_line - preview height + 1] + // +1 is so to assert that preview scrolls up to one line after the end of the file + preview_scroll_offset.1 = match preview_scroll_offset.0 { + Direction::Backward => preview_scroll_offset.1.min(first_line), + Direction::Forward => preview_scroll_offset.1.min( + doc.text() + .len_lines() + .saturating_sub(first_line) + .saturating_sub(inner.height as usize) + + 1, + ), + }; + + // subtract or add scroll offset with respect to first_line + let offset = Position::new( + match preview_scroll_offset.0 { + Direction::Backward => first_line.saturating_sub(preview_scroll_offset.1), + Direction::Forward => first_line.saturating_add(preview_scroll_offset.1), + }, + 0, + ); let highlights = EditorView::doc_syntax_highlights(doc, offset, area.height, &cx.editor.theme); @@ -245,31 +325,63 @@ impl Component for FilePicker { &cx.editor.config(), ); - // update after use of `doc` because of lifetime issues with get_preview() - self.picker.preview_scroll_offset = preview_scroll_offset; + self.preview_scroll_offset = preview_scroll_offset; // highlight the line if let Some((start, end)) = range { - let offset = start.saturating_sub(first_line) as u16; - surface.set_style( - Rect::new( - inner.x, - inner.y + offset, - inner.width, - (end.saturating_sub(start) as u16 + 1) - .min(inner.height.saturating_sub(offset)), - ), - cx.editor - .theme - .try_get("ui.highlight") - .unwrap_or_else(|| cx.editor.theme.get("ui.selection")), - ); + let offset_h = start.saturating_sub(offset.row) as u16; + + // highlight only if selection is inside preview + if offset_h <= inner.height && end >= offset.row { + surface.set_style( + Rect::new( + inner.x, + inner.y + offset_h, + inner.width, + (end.saturating_sub(start) as u16 + 1) + .min(inner.height.saturating_sub(offset_h)) + .min(end.saturating_sub(offset.row) as u16 + 1), + ), + cx.editor + .theme + .try_get("ui.highlight") + .unwrap_or_else(|| cx.editor.theme.get("ui.selection")), + ); + } } } } fn handle_event(&mut self, event: &Event, ctx: &mut Context) -> EventResult { - // TODO: keybinds for scrolling preview + if let Event::Key(key_event) = event { + match key_event { + alt!('u') | shift!(Up) => { + self.move_preview_by( + ctx.editor.config().scroll_lines.unsigned_abs(), + Direction::Backward, + ); + + return EventResult::Consumed(None); + } + alt!('d') | shift!(Down) => { + self.move_preview_by( + ctx.editor.config().scroll_lines.unsigned_abs(), + Direction::Forward, + ); + + return EventResult::Consumed(None); + } + ctrl!('t') => { + self.toggle_preview(); + + return EventResult::Consumed(None); + } + _ => { + return self.picker.handle_event(event, ctx); + } + } + } + self.picker.handle_event(event, ctx) } @@ -302,14 +414,13 @@ pub struct Picker { completion_height: u16, cursor: usize, + /// Used to inform the picker owner on a cursor move + cursor_moved: bool, // pattern: String, prompt: Prompt, previous_pattern: String, - preview_scroll_offset: usize, /// Whether to truncate the start (default true) pub truncate_start: bool, - /// Whether to show the preview panel (default true) - show_preview: bool, callback_fn: Box, } @@ -334,11 +445,10 @@ impl Picker { matches: Vec::new(), filters: Vec::new(), cursor: 0, + cursor_moved: false, prompt, previous_pattern: String::new(), - preview_scroll_offset: 0, truncate_start: true, - show_preview: true, callback_fn: Box::new(callback_fn), completion_height: 0, }; @@ -443,16 +553,7 @@ impl Picker { } } - // Reset the preview scroll on pointing to a different file - self.preview_scroll_offset = 0; - } - - /// Moves the picker file preview by a number of lines, either down (`Forward`) or up (`Backward`) - pub fn move_preview_by(&mut self, amount: usize, direction: Direction) { - self.preview_scroll_offset = match direction { - Direction::Forward => self.preview_scroll_offset.saturating_add(amount), - Direction::Backward => self.preview_scroll_offset.saturating_sub(amount), - }; + self.cursor_moved = true; } /// Move the cursor down by exactly one page. After the last page comes the first page. @@ -489,10 +590,6 @@ impl Picker { self.prompt.clear(cx.editor); } - pub fn toggle_preview(&mut self) { - self.show_preview = !self.show_preview; - } - fn prompt_handle_event(&mut self, event: &Event, cx: &mut Context) -> EventResult { if let EventResult::Consumed(_) = self.prompt.handle_event(event, cx) { // TODO: recalculate only if pattern changed @@ -545,18 +642,6 @@ impl Component for Picker { key!(End) => { self.to_end(); } - alt!('u') | shift!(Up) => { - self.move_preview_by( - cx.editor.config().scroll_lines.unsigned_abs(), - Direction::Backward, - ); - } - alt!('d') | shift!(Down) => { - self.move_preview_by( - cx.editor.config().scroll_lines.unsigned_abs(), - Direction::Forward, - ); - } key!(Esc) | ctrl!('c') => { return close_fn; } @@ -581,9 +666,6 @@ impl Component for Picker { ctrl!(' ') => { self.save_filter(cx); } - ctrl!('t') => { - self.toggle_preview(); - } _ => { self.prompt_handle_event(event, cx); } From 3d08447608a3b1db8094be45c9c4751e36dcfd78 Mon Sep 17 00:00:00 2001 From: Manos Mertzianis Date: Sat, 15 Oct 2022 18:42:54 +0300 Subject: [PATCH 05/13] fixed preview scroll resets only on file change --- helix-term/src/ui/picker.rs | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 4d22f7ba8ad2..005f0f8446c5 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -47,6 +47,7 @@ pub struct FilePicker { /// Given an item in the picker, return the file path and line number to display. file_fn: Box Option>, + preview_file_path: PathBuf, /// Line offset from preview's starting point(first_line) to enable preview scrolling preview_scroll_offset: (Direction, usize), /// Whether to show the preview panel (default true) @@ -107,6 +108,7 @@ impl FilePicker { preview_cache: HashMap::new(), read_buffer: Vec::with_capacity(1024), file_fn: Box::new(preview_fn), + preview_file_path: PathBuf::default(), preview_scroll_offset: (Direction::Forward, 0), show_preview: true, } @@ -209,15 +211,6 @@ impl FilePicker { }; } - /// Updates FilePicker state if picker::cursor_moved is `true`. - /// Used for resetting the preview scroll offset on Picker::move_by() - fn on_cursor_move_update(&mut self) { - if self.picker.cursor_moved { - self.preview_scroll_offset.1 = 0; - self.picker.cursor_moved = false; - } - } - fn toggle_preview(&mut self) { self.show_preview = !self.show_preview; } @@ -264,12 +257,15 @@ impl Component for FilePicker { let inner = inner.inner(&margin); block.render(preview_area, surface); - self.on_cursor_move_update(); // we get the scroll offset here because the lifetimes of // FilePicker::get_preview() prohibit the use of self until the final use of doc: `&Document` let mut preview_scroll_offset = self.preview_scroll_offset; if let Some((path, range)) = self.current_file(cx.editor) { + if path != self.preview_file_path { + preview_scroll_offset = (preview_scroll_offset.0, 0); + self.preview_file_path = path.clone(); + } let preview = self.get_preview(&path, cx.editor); let doc = match preview.document() { Some(doc) => doc, @@ -414,8 +410,6 @@ pub struct Picker { completion_height: u16, cursor: usize, - /// Used to inform the picker owner on a cursor move - cursor_moved: bool, // pattern: String, prompt: Prompt, previous_pattern: String, @@ -445,7 +439,6 @@ impl Picker { matches: Vec::new(), filters: Vec::new(), cursor: 0, - cursor_moved: false, prompt, previous_pattern: String::new(), truncate_start: true, @@ -552,8 +545,6 @@ impl Picker { self.cursor = self.cursor.saturating_add(len).saturating_sub(amount) % len; } } - - self.cursor_moved = true; } /// Move the cursor down by exactly one page. After the last page comes the first page. From a0101d6581181ce7a1643780e445d3a6f2bba28a Mon Sep 17 00:00:00 2001 From: Manos Mertzianis Date: Sun, 16 Oct 2022 12:20:47 +0300 Subject: [PATCH 06/13] preview scrolls only if show_preview = true --- helix-term/src/ui/picker.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 005f0f8446c5..815bdf772eae 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -351,7 +351,7 @@ impl Component for FilePicker { fn handle_event(&mut self, event: &Event, ctx: &mut Context) -> EventResult { if let Event::Key(key_event) = event { match key_event { - alt!('u') | shift!(Up) => { + alt!('u') | shift!(Up) if self.show_preview => { self.move_preview_by( ctx.editor.config().scroll_lines.unsigned_abs(), Direction::Backward, @@ -359,7 +359,7 @@ impl Component for FilePicker { return EventResult::Consumed(None); } - alt!('d') | shift!(Down) => { + alt!('d') | shift!(Down) if self.show_preview => { self.move_preview_by( ctx.editor.config().scroll_lines.unsigned_abs(), Direction::Forward, From 12d4539a19e739fc7ea6b15ab16f0520279b928f Mon Sep 17 00:00:00 2001 From: Manos Mertzianis Date: Sun, 16 Oct 2022 18:56:51 +0300 Subject: [PATCH 07/13] updated keybindings --- helix-term/src/ui/picker.rs | 41 +++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 815bdf772eae..36a9762503f9 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -47,6 +47,8 @@ pub struct FilePicker { /// Given an item in the picker, return the file path and line number to display. file_fn: Box Option>, + /// preview window height + preview_height: u16, preview_file_path: PathBuf, /// Line offset from preview's starting point(first_line) to enable preview scrolling preview_scroll_offset: (Direction, usize), @@ -108,6 +110,7 @@ impl FilePicker { preview_cache: HashMap::new(), read_buffer: Vec::with_capacity(1024), file_fn: Box::new(preview_fn), + preview_height: 0, preview_file_path: PathBuf::default(), preview_scroll_offset: (Direction::Forward, 0), show_preview: true, @@ -351,7 +354,7 @@ impl Component for FilePicker { fn handle_event(&mut self, event: &Event, ctx: &mut Context) -> EventResult { if let Event::Key(key_event) = event { match key_event { - alt!('u') | shift!(Up) if self.show_preview => { + alt!('k') | shift!(Up) if self.show_preview => { self.move_preview_by( ctx.editor.config().scroll_lines.unsigned_abs(), Direction::Backward, @@ -359,7 +362,7 @@ impl Component for FilePicker { return EventResult::Consumed(None); } - alt!('d') | shift!(Down) if self.show_preview => { + alt!('j') | shift!(Down) if self.show_preview => { self.move_preview_by( ctx.editor.config().scroll_lines.unsigned_abs(), Direction::Forward, @@ -367,6 +370,38 @@ impl Component for FilePicker { return EventResult::Consumed(None); } + alt!('u') if self.show_preview => { + self.move_preview_by( + self.preview_height.saturating_div(2) as usize, + Direction::Backward, + ); + + return EventResult::Consumed(None); + } + alt!('d') if self.show_preview => { + self.move_preview_by( + self.preview_height.saturating_div(2) as usize, + Direction::Forward, + ); + + return EventResult::Consumed(None); + } + alt!('b') if self.show_preview => { + self.move_preview_by( + self.preview_height as usize, + Direction::Backward, + ); + + return EventResult::Consumed(None); + } + alt!('f') if self.show_preview => { + self.move_preview_by( + self.preview_height as usize, + Direction::Forward, + ); + + return EventResult::Consumed(None); + } ctrl!('t') => { self.toggle_preview(); @@ -386,6 +421,8 @@ impl Component for FilePicker { } fn required_size(&mut self, (width, height): (u16, u16)) -> Option<(u16, u16)> { + self.preview_height = height.saturating_sub(2); + let picker_width = if width > MIN_AREA_WIDTH_FOR_PREVIEW { width / 2 } else { From 77d7f376ee4df6d747a2b6d84200ce01bf197cdd Mon Sep 17 00:00:00 2001 From: Manos Mertzianis Date: Mon, 17 Oct 2022 16:07:59 +0300 Subject: [PATCH 08/13] rearrange the order of imports --- helix-term/src/ui/picker.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 36a9762503f9..75bd2b1fed40 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -1,7 +1,6 @@ use crate::{ - alt, compositor::{Component, Compositor, Context, Event, EventResult}, - ctrl, key, shift, + alt, ctrl, key, shift, ui::{self, EditorView}, }; use tui::{ From b28ac5fa23786b90cb1163645f89ed36701f3a25 Mon Sep 17 00:00:00 2001 From: Manos Mertzianis Date: Mon, 17 Oct 2022 17:03:06 +0300 Subject: [PATCH 09/13] fix lint test with "cargo fmt --all" --- helix-term/src/ui/picker.rs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 95e0b612c94b..8aff1231662b 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -1,6 +1,7 @@ use crate::{ + alt, compositor::{Component, Compositor, Context, Event, EventResult}, - alt, ctrl, key, shift, + ctrl, key, shift, ui::{self, fuzzy_match::FuzzyQuery, EditorView}, }; use tui::{ @@ -410,18 +411,12 @@ impl Component for FilePicker { return EventResult::Consumed(None); } alt!('b') if self.show_preview => { - self.move_preview_by( - self.preview_height as usize, - Direction::Backward, - ); + self.move_preview_by(self.preview_height as usize, Direction::Backward); return EventResult::Consumed(None); } alt!('f') if self.show_preview => { - self.move_preview_by( - self.preview_height as usize, - Direction::Forward, - ); + self.move_preview_by(self.preview_height as usize, Direction::Forward); return EventResult::Consumed(None); } @@ -445,7 +440,7 @@ impl Component for FilePicker { fn required_size(&mut self, (width, height): (u16, u16)) -> Option<(u16, u16)> { self.preview_height = height.saturating_sub(2); - + let picker_width = if width > MIN_AREA_WIDTH_FOR_PREVIEW { width / 2 } else { From dc054ecfbd4159c1d1668f142d46ab597756051d Mon Sep 17 00:00:00 2001 From: Manos Mertzianis Date: Sun, 30 Oct 2022 21:17:51 +0200 Subject: [PATCH 10/13] added scrollbar for preview scrolling --- helix-term/src/ui/picker.rs | 39 ++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 30ea085f083a..c02a84c34515 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -300,6 +300,7 @@ impl Component for FilePicker { return; } }; + let doc_height = doc.text().len_lines(); // align to middle let first_line = range @@ -310,16 +311,13 @@ impl Component for FilePicker { }) .unwrap_or(0); - // limit scroll offset between [-first_line, doc.text().len_lines() - first_line - preview height + 1] - // +1 is so to assert that preview scrolls up to one line after the end of the file + // limit scroll offset between [-first_line, doc.text().len_lines() - first_line - preview height] preview_scroll_offset.1 = match preview_scroll_offset.0 { Direction::Backward => preview_scroll_offset.1.min(first_line), Direction::Forward => preview_scroll_offset.1.min( - doc.text() - .len_lines() + doc_height .saturating_sub(first_line) .saturating_sub(inner.height as usize) - + 1, ), }; @@ -352,6 +350,37 @@ impl Component for FilePicker { self.preview_scroll_offset = preview_scroll_offset; + let win_height = inner.height as usize; + let len = doc_height; + let fits = len <= win_height; + let scroll = offset.row; + let scroll_style = cx.editor.theme.get("ui.menu.scroll"); + + const fn div_ceil(a: usize, b: usize) -> usize { + (a + b - 1) / b + } + + if !fits { + let scroll_height = div_ceil(win_height.pow(2), len).min(win_height); + let scroll_line = (win_height - scroll_height) * scroll + / std::cmp::max(1, len.saturating_sub(win_height)); + + let mut cell; + for i in 0..win_height { + cell = &mut surface[(inner.right() - 1, inner.top() + i as u16)]; + + cell.set_symbol("▐"); // right half block + + if scroll_line <= i && i < scroll_line + scroll_height { + // Draw scroll thumb + cell.set_fg(scroll_style.fg.unwrap_or(helix_view::theme::Color::Reset)); + } else { + // Draw scroll track + cell.set_fg(scroll_style.bg.unwrap_or(helix_view::theme::Color::Reset)); + } + } + } + // highlight the line if let Some((start, end)) = range { let offset_h = start.saturating_sub(offset.row) as u16; From 25011662ca51cae3e4eacc275f47d044463e413e Mon Sep 17 00:00:00 2001 From: Manos Mertzianis Date: Sun, 30 Oct 2022 21:19:15 +0200 Subject: [PATCH 11/13] cargo fmt --- helix-term/src/ui/picker.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index c02a84c34515..6b674a59022a 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -317,7 +317,7 @@ impl Component for FilePicker { Direction::Forward => preview_scroll_offset.1.min( doc_height .saturating_sub(first_line) - .saturating_sub(inner.height as usize) + .saturating_sub(inner.height as usize), ), }; From 03e297008dbf1c815968eae4ec00acd06ccf0bc6 Mon Sep 17 00:00:00 2001 From: Manos Mertzianis Date: Thu, 3 Nov 2022 14:09:41 +0200 Subject: [PATCH 12/13] fix: scroll reset on diagnostic picker --- helix-term/src/ui/picker.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 6b674a59022a..d6c28e4729f1 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -48,7 +48,7 @@ pub struct FilePicker { /// preview window height preview_height: u16, - preview_file_path: PathBuf, + cursor_position: usize, /// Line offset from preview's starting point(first_line) to enable preview scrolling preview_scroll_offset: (Direction, usize), /// Whether to show the preview panel (default true) @@ -110,7 +110,7 @@ impl FilePicker { read_buffer: Vec::with_capacity(1024), file_fn: Box::new(preview_fn), preview_height: 0, - preview_file_path: PathBuf::default(), + cursor_position: 0, preview_scroll_offset: (Direction::Forward, 0), show_preview: true, } @@ -284,11 +284,15 @@ impl Component for FilePicker { // FilePicker::get_preview() prohibit the use of self until the final use of doc: `&Document` let mut preview_scroll_offset = self.preview_scroll_offset; + // reset if cursor moved + let cursor_position = self.picker.cursor; + if self.cursor_position != cursor_position { + preview_scroll_offset = (Direction::Forward, 0); + self.cursor_position = cursor_position; + } + log::info!("Cursor Position {:?}", self.cursor_position); + if let Some((path, range)) = self.current_file(cx.editor) { - if path != self.preview_file_path { - preview_scroll_offset = (preview_scroll_offset.0, 0); - self.preview_file_path = path.clone(); - } let preview = self.get_preview(&path, cx.editor); let doc = match preview.document() { Some(doc) => doc, From 23189b9b71fd4140a79f75fceaae1579a7c8e5cd Mon Sep 17 00:00:00 2001 From: Manos Mertzianis Date: Thu, 3 Nov 2022 14:16:13 +0200 Subject: [PATCH 13/13] removed unnecessary log::info --- helix-term/src/ui/picker.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index d6c28e4729f1..a5f53ecf9aca 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -290,7 +290,6 @@ impl Component for FilePicker { preview_scroll_offset = (Direction::Forward, 0); self.cursor_position = cursor_position; } - log::info!("Cursor Position {:?}", self.cursor_position); if let Some((path, range)) = self.current_file(cx.editor) { let preview = self.get_preview(&path, cx.editor);