diff options
-rw-r--r-- | Cargo.lock | 6 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | src/browser/browser_state.rs | 10 | ||||
-rw-r--r-- | src/command/panel_input.rs | 17 | ||||
-rw-r--r-- | src/display/displayable_tree.rs | 11 | ||||
-rw-r--r-- | src/filesystems/filesystems_state.rs | 2 | ||||
-rw-r--r-- | src/help/help_content.rs | 1 | ||||
-rw-r--r-- | src/help/help_state.rs | 18 | ||||
-rw-r--r-- | src/hex/hex_view.rs | 7 | ||||
-rw-r--r-- | src/stage/stage_state.rs | 5 | ||||
-rw-r--r-- | src/syntactic/syntactic_view.rs | 2 | ||||
-rw-r--r-- | src/tree/tree.rs | 104 |
12 files changed, 102 insertions, 83 deletions
@@ -181,7 +181,7 @@ dependencies = [ "strict", "syntect", "tempfile", - "termimad 0.15.0", + "termimad 0.16.0", "terminal-clipboard", "toml", "umask", @@ -1612,9 +1612,9 @@ dependencies = [ [[package]] name = "termimad" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "513d1d28d91be635bdca58c59270dd54ae2280a7bf8a66c49a9963d2b6f112cd" +checksum = "e3a60170e04bc337ab4a1a3182c4a1e012ce946d109031024c2a64d47b995ae3" dependencies = [ "crossbeam", "crossterm 0.21.0", @@ -54,7 +54,7 @@ splitty = "0.1" strict = "0.1.4" syntect = "4.5" tempfile = "3.2" -termimad = "0.15.0" +termimad = "0.16.0" terminal-clipboard = { version = "0.2.1", optional = true } toml = "0.5" umask = "1.0" diff --git a/src/browser/browser_state.rs b/src/browser/browser_state.rs index dccb3b5..34a19c5 100644 --- a/src/browser/browser_state.rs +++ b/src/browser/browser_state.rs @@ -86,8 +86,8 @@ impl BrowserState { self.tree.root() } - pub fn page_height(screen: Screen) -> i32 { - i32::from(screen.height) - 2 + pub fn page_height(screen: Screen) -> usize { + screen.height as usize - 2 // br shouldn't be displayed when the screen is smaller } /// return a reference to the currently displayed tree, which @@ -243,7 +243,7 @@ impl PanelState for BrowserState { _screen: Screen, _con: &AppContext, ) -> Result<CmdResult, ProgramError> { - self.displayed_tree_mut().try_select_y(y as i32); + self.displayed_tree_mut().try_select_y(y as usize); Ok(CmdResult::Keep) } @@ -373,14 +373,14 @@ impl PanelState for BrowserState { } Internal::page_down => { let tree = self.displayed_tree_mut(); - if !tree.try_scroll(page_height, page_height) { + if !tree.try_scroll(page_height as i32, page_height) { tree.try_select_last(page_height); } CmdResult::Keep } Internal::page_up => { let tree = self.displayed_tree_mut(); - if !tree.try_scroll(-page_height, page_height) { + if !tree.try_scroll(page_height as i32 * -1, page_height) { tree.try_select_first(); } CmdResult::Keep diff --git a/src/command/panel_input.rs b/src/command/panel_input.rs index ff0c9cd..ff98b32 100644 --- a/src/command/panel_input.rs +++ b/src/command/panel_input.rs @@ -16,8 +16,7 @@ use { termimad::{Area, Event, InputField}, }; -/// wrap the input of a panel, -/// receive events and make commands +/// Wrap the input of a panel, receive events and make commands pub struct PanelInput { pub input_field: InputField, tab_cycle_count: usize, @@ -35,7 +34,7 @@ impl PanelInput { } pub fn set_content(&mut self, content: &str) { - self.input_field.set_content(content); + self.input_field.set_str(content); } pub fn get_content(&self) -> String { @@ -51,14 +50,14 @@ impl PanelInput { panel_skin: &PanelSkin, ) -> Result<(), ProgramError> { self.input_field.set_normal_style(panel_skin.styles.input.clone()); - self.input_field.focused = active && mode == Mode::Input; + self.input_field.set_focus(active && mode == Mode::Input); if mode == Mode::Command && active { queue!(w, cursor::MoveTo(area.left, area.top))?; panel_skin.styles.mode_command_mark.queue_str(w, "C")?; area.width -= 1; area.left += 1; } - self.input_field.area = area; + self.input_field.set_area(area); self.input_field.display_on(w)?; Ok(()) } @@ -95,7 +94,7 @@ impl PanelInput { if self.input_field.get_content().is_empty() { false } else { - self.input_field.set_content(""); + self.input_field.clear(); true } } @@ -189,7 +188,7 @@ impl PanelInput { self.tab_cycle_count = 0; if let Some(raw) = self.input_before_cycle.take() { // we cancel the tab cycling - self.input_field.set_content(&raw); + self.input_field.set_str(&raw); self.input_before_cycle = None; return Command::from_raw(raw, false); } else if con.modal && mode == Mode::Input { @@ -200,7 +199,7 @@ impl PanelInput { }; } else { // general back command - self.input_field.set_content(""); + self.input_field.clear(); let internal = Internal::back; return Command::Internal { internal, @@ -247,7 +246,7 @@ impl PanelInput { .as_ref() .map_or(raw, |s| s.to_string()); raw.push_str(&added); - self.input_field.set_content(&raw); + self.input_field.set_str(&raw); return Command::from_raw(raw, false); } else { return Command::None; diff --git a/src/display/displayable_tree.rs b/src/display/displayable_tree.rs index 7e5fd35..6bd5b72 100644 --- a/src/display/displayable_tree.rs +++ b/src/display/displayable_tree.rs @@ -25,7 +25,7 @@ use { file_size, git2::Status, std::io::Write, - termimad::{CompoundStyle, ProgressBar}, + termimad::{Area, CompoundStyle, ProgressBar}, }; /// A tree wrapper which can be used either @@ -451,7 +451,12 @@ impl<'a, 's, 't> DisplayableTree<'a, 's, 't> { let tree = self.tree; let total_size = tree.total_sum(); let scrollbar = if self.in_app { - self.area.scrollbar(tree.scroll, tree.lines.len() as i32 - 1) + termimad::compute_scrollbar( + tree.scroll, + tree.lines.len() - 1, // the root line isn't scrolled + self.area.height - 1, // the scrollbar doesn't cover the first line + self.area.top + 1, + ) } else { None }; @@ -602,7 +607,7 @@ impl<'a, 's, 't> DisplayableTree<'a, 's, 't> { } self.extend_line_bg(cw, selected)?; self.skin.queue_reset(f)?; - if self.in_app && y > 0 { + if self.in_app { if let Some((sctop, scbottom)) = scrollbar { f.queue(cursor::MoveTo(self.area.left + self.area.width - 1, y))?; let style = if sctop <= y && y <= scbottom { diff --git a/src/filesystems/filesystems_state.rs b/src/filesystems/filesystems_state.rs index 328b87f..3082b18 100644 --- a/src/filesystems/filesystems_state.rs +++ b/src/filesystems/filesystems_state.rs @@ -237,7 +237,7 @@ impl PanelState for FilesystemState { } else { (self.mounts.as_slice(), self.selection_idx) }; - let scrollbar = area.scrollbar(self.scroll as i32, mounts.len() as i32); + let scrollbar = area.scrollbar(self.scroll, mounts.len()); //- style preparation let styles = &disc.panel_skin.styles; let selection_bg = styles.selected_line.get_bg() diff --git a/src/help/help_content.rs b/src/help/help_content.rs index 25419de..672aeb5 100644 --- a/src/help/help_content.rs +++ b/src/help/help_content.rs @@ -68,6 +68,7 @@ ${features-text} ${features * **${feature-name}:** ${feature-description} } + "#; /// build a markdown expander which will need to be diff --git a/src/help/help_state.rs b/src/help/help_state.rs index d96cc2f..1f5800e 100644 --- a/src/help/help_state.rs +++ b/src/help/help_state.rs @@ -17,7 +17,7 @@ use { /// an application state dedicated to help pub struct HelpState { - pub scroll: i32, // scroll position + pub scroll: usize, pub text_area: Area, dirty: bool, // background must be cleared pattern: Pattern, @@ -205,7 +205,12 @@ impl PanelState for HelpState { CmdResult::Keep } line_up | line_up_no_cycle => { - self.scroll -= get_arg(input_invocation, internal_exec, 1); + let dy = get_arg(input_invocation, internal_exec, 1); + self.scroll = if self.scroll > dy { + self.scroll - dy + } else { + 0 + }; CmdResult::Keep } open_stay => match open::that(&Conf::default_location()) { @@ -222,11 +227,16 @@ impl PanelState for HelpState { )) } page_down => { - self.scroll += self.text_area.height as i32; + self.scroll += self.text_area.height as usize; CmdResult::Keep } page_up => { - self.scroll -= self.text_area.height as i32; + let height = self.text_area.height as usize; + self.scroll = if self.scroll > height { + self.scroll - self.text_area.height as usize + } else { + 0 + }; CmdResult::Keep } _ => self.on_internal_generic( diff --git a/src/hex/hex_view.rs b/src/hex/hex_view.rs index 8a7141a..40c072d 100644 --- a/src/hex/hex_view.rs +++ b/src/hex/hex_view.rs @@ -145,7 +145,7 @@ impl HexView { margin_around_adresses = true; //rem -= 2; } - let scrollbar = area.scrollbar(self.scroll as i32, self.line_count() as i32); + let scrollbar = area.scrollbar(self.scroll, self.line_count()); let scrollbar_fg = styles.scrollbar_thumb.get_fg() .or_else(|| styles.preview.get_fg()) .unwrap_or(Color::White); @@ -201,7 +201,7 @@ impl HexView { } } cw.fill(&styles.default, &SPACE_FILLING)?; - if is_thumb(y, scrollbar) { + if is_thumb(y as u16 + area.top, scrollbar) { w.queue(SetForegroundColor(scrollbar_fg))?; w.queue(Print('▐'))?; } else { @@ -237,9 +237,8 @@ impl HexView { } } -fn is_thumb(y: usize, scrollbar: Option<(u16, u16)>) -> bool { +fn is_thumb(y: u16, scrollbar: Option<(u16, u16)>) -> bool { if let Some((sctop, scbottom)) = scrollbar { - let y = y as u16; if sctop <= y && y <= scbottom { return true; } diff --git a/src/stage/stage_state.rs b/src/stage/stage_state.rs index b734f85..90551ce 100644 --- a/src/stage/stage_state.rs +++ b/src/stage/stage_state.rs @@ -304,10 +304,7 @@ impl PanelState for StageState { self.page_height = list_area.height as usize; let pattern = &self.filtered_stage.pattern().pattern; let pattern_object = pattern.object(); - let scrollbar = list_area.scrollbar( - self.scroll as i32, - self.filtered_stage.len() as i32, - ); + let scrollbar = list_area.scrollbar(self.scroll, self.filtered_stage.len()); for idx in 0..self.page_height { let y = list_area.top + idx as u16; let stage_idx = idx + self.scroll; diff --git a/src/syntactic/syntactic_view.rs b/src/syntactic/syntactic_view.rs index 2a38466..ba0063e 100644 --- a/src/syntactic/syntactic_view.rs +++ b/src/syntactic/syntactic_view.rs @@ -314,7 +314,7 @@ impl SyntacticView { .unwrap_or(Color::AnsiValue(240)); let match_bg = styles.preview_match.get_bg().unwrap_or(Color::AnsiValue(28)); let code_width = area.width as usize - 1; // 1 char left for scrollbar - let scrollbar = area.scrollbar(self.scroll as i32, self.lines.len() as i32); + let scrollbar = area.scrollbar(self.scroll, self.lines.len()); let scrollbar_fg = styles.scrollbar_thumb.get_fg() .or_else(|| styles.preview.get_fg()) .unwrap_or(Color::White); diff --git a/src/tree/tree.rs b/src/tree/tree.rs index 253eeb1..346573c 100644 --- a/src/tree/tree.rs +++ b/src/tree/tree.rs @@ -25,7 +25,7 @@ pub struct Tree { pub lines: Box<[TreeLine]>, pub selection: usize, // there's always a selection (starts with root, which is 0) pub options: TreeOptions, - pub scroll: i32, // the number of lines at the top hidden because of scrolling + pub scroll: usize, // the number of lines at the top hidden because of scrolling pub nb_gitignored: u32, // number of times a gitignore pattern excluded a file pub total_search: bool, // whether the search was made on all children pub git_status: ComputationResult<TreeGitStatus>, @@ -60,7 +60,7 @@ impl Tree { self.selection = 0; } } - self.make_selection_visible(page_height as i32); + self.make_selection_visible(page_height); Ok(()) } @@ -144,70 +144,74 @@ impl Tree { /// select another line /// /// For example the following one if dy is 1. - pub fn move_selection(&mut self, dy: i32, page_height: i32, cycle: bool) { - // FIXME may not work well if dy is too big - let l = self.lines.len() as i32; + pub fn move_selection(&mut self, dy: i32, page_height: usize, cycle: bool) { + let l = self.lines.len(); + // we find the new line to select loop { - if !cycle { - let s = dy + (self.selection as i32); - if s < 0 || s >= l { + if dy < 0 { + let ady = (-dy) as usize; + if !cycle && self.selection < ady { + break; + } + self.selection = (self.selection + l - ady) % l; + } else { + let dy = dy as usize; + if !cycle && self.selection + dy > l { break; } + self.selection = (self.selection + dy) % l; } - self.selection = (self.selection + (l + dy) as usize) % self.lines.len(); if self.lines[self.selection].is_selectable() { break; } } // we adjust the scroll - let sel = self.selection as i32; if l > page_height { - if dy < 0 { - if sel == l - 1 { - // cycling - self.scroll = l - page_height; - } else if sel < self.scroll + 5 { - self.scroll = (self.scroll + 2 * dy).max(0); - } - } else { - if sel == 0 { - // cycling brought us back to top - self.scroll = 0; - } else if sel > self.scroll + page_height - 5 { - self.scroll = (self.scroll + 2 * dy).min(l - page_height); - } + if self.selection < 3 { + self.scroll = 0; + } else if self.selection < self.scroll + 3 { + self.scroll = self.selection - 3; + } else if self.selection + 3 > l { + self.scroll = l - page_height; + } else if self.selection + 3 > self.scroll + page_height { + self.scroll = self.selection + 3 - page_height; } } } - /// scroll the desired amount and return true, or return false if it's + /// Scroll the desired amount and return true, or return false if it's /// already at end or the tree fits the page - pub fn try_scroll(&mut self, dy: i32, page_height: i32) -> bool { - let lines_len = self.lines.len() as i32; - if lines_len <= page_height { + pub fn try_scroll(&mut self, dy: i32, page_height: usize) -> bool { + if self.lines.len() <= page_height { return false; } if dy < 0 { // scroll up if self.scroll == 0 { return false; + } else { + let ady = -dy as usize; + if ady < self.scroll { + self.scroll -= ady; + } else { + self.scroll = 0; + } } - self.scroll = (self.scroll + dy).max(0); } else { // scroll down - let max = lines_len - page_height; + let max = self.lines.len() - page_height; if self.scroll >= max { return false; } - self.scroll = (self.scroll + dy).min(max); + self.scroll = (self.scroll + dy as usize).min(max); } self.select_visible_line(page_height); true } - /// try to select a line (works if y+scroll falls on a selectable line) - pub fn try_select_y(&mut self, y: i32) -> bool { + /// try to select a line by index of visible line + /// (works if y+scroll falls on a selectable line) + pub fn try_select_y(&mut self, y: usize) -> bool { let y = y + self.scroll; - if y >= 0 && y < self.lines.len() as i32 { - let y = y as usize; + if y < self.lines.len() { if self.lines[y].is_selectable() { self.selection = y; return true; @@ -216,13 +220,12 @@ impl Tree { false } /// fix the selection so that it's a selectable visible line - fn select_visible_line(&mut self, page_height: i32) { - let sel = self.selection as i32; - if sel < self.scroll || sel >= self.scroll + page_height { - self.selection = self.scroll as usize; + fn select_visible_line(&mut self, page_height: usize) { + if self.selection < self.scroll || self.selection >= self.scroll + page_height { + self.selection = self.scroll; let l = self.lines.len(); loop { - self.selection = (self.selection + ((l as i32) + 1) as usize) % l; + self.selection = (self.selection + l + 1) % l; if self.lines[self.selection].is_selectable() { break; } @@ -230,14 +233,19 @@ impl Tree { } } - pub fn make_selection_visible(&mut self, page_height: i32) { - let sel = self.selection as i32; - let l = self.lines.len() as i32; - if sel < self.scroll { - self.scroll = (self.selection as i32 - 2).max(0); - } else if l > page_height && sel >= self.scroll + page_height { - self.scroll = (self.selection as i32 - page_height + 2) as i32; + pub fn make_selection_visible(&mut self, page_height: usize) { + debug!("make_selection_visible len={} page_height={} scroll={} sel={}", + self.lines.len(), page_height, self.scroll, self.selection); + if page_height >= self.lines.len() || self.selection < 3 { + self.scroll = 0; + } else if self.selection < self.scroll { + self.scroll = self.selection - 2; + } else if self.selection > self.lines.len() - 2 { + self.scroll = self.lines.len() - page_height; + } else if self.selection >= self.scroll + page_height { + self.scroll = self.selection + 2 - page_height; } + debug!(" -> scroll={}", self.scroll); } pub fn selected_line(&self) -> &TreeLine { &self.lines[self.selection] @@ -289,7 +297,7 @@ impl Tree { } false } - pub fn try_select_last(&mut self, page_height: i32) -> bool { + pub fn try_select_last(&mut self, page_height: usize) -> bool { for idx in (0..self.lines.len()).rev() { let line = &self.lines[idx]; if line.is_selectable() { |