From a5b63e593645e00f2d127d71706873ddf0df558e Mon Sep 17 00:00:00 2001 From: Stephan Dilly Date: Mon, 24 May 2021 11:07:32 +0200 Subject: [PATCH] support common nav for syntax view (closes #725) --- filetree/src/filetree.rs | 5 +++ src/components/revision_files.rs | 18 +++------- src/components/syntax_text.rs | 60 +++++++++++++++++++++----------- src/ui/mod.rs | 29 +++++++++++++++ 4 files changed, 77 insertions(+), 35 deletions(-) diff --git a/filetree/src/filetree.rs b/filetree/src/filetree.rs index e373c642..26c7a5af 100644 --- a/filetree/src/filetree.rs +++ b/filetree/src/filetree.rs @@ -13,6 +13,8 @@ pub enum MoveSelection { Right, Top, End, + PageDown, + PageUp, } #[derive(Debug, Clone, Copy)] @@ -121,6 +123,9 @@ impl FileTree { Self::selection_start(selection) } MoveSelection::End => self.selection_end(selection), + MoveSelection::PageDown | MoveSelection::PageUp => { + None + } }; let changed_index = diff --git a/src/components/revision_files.rs b/src/components/revision_files.rs index 6b1acac3..a5328e8a 100644 --- a/src/components/revision_files.rs +++ b/src/components/revision_files.rs @@ -6,7 +6,7 @@ use crate::{ keys::SharedKeyConfig, queue::{InternalEvent, Queue}, strings::{self, order}, - ui::{self, style::SharedTheme}, + ui::{self, common_nav, style::SharedTheme}, }; use anyhow::Result; use asyncgit::{ @@ -15,7 +15,7 @@ use asyncgit::{ }; use crossbeam_channel::Sender; use crossterm::event::Event; -use filetree::{FileTree, MoveSelection}; +use filetree::FileTree; use std::{ cell::Cell, collections::BTreeSet, convert::From, path::Path, }; @@ -376,18 +376,8 @@ fn tree_nav( key_config: &SharedKeyConfig, key: crossterm::event::KeyEvent, ) -> bool { - if key == key_config.move_down { - tree.move_selection(MoveSelection::Down) - } else if key == key_config.move_up { - tree.move_selection(MoveSelection::Up) - } else if key == key_config.move_right { - tree.move_selection(MoveSelection::Right) - } else if key == key_config.move_left { - tree.move_selection(MoveSelection::Left) - } else if key == key_config.home || key == key_config.shift_up { - tree.move_selection(MoveSelection::Top) - } else if key == key_config.end || key == key_config.shift_down { - tree.move_selection(MoveSelection::End) + if let Some(common_nav) = common_nav(key, key_config) { + tree.move_selection(common_nav) } else if key == key_config.tree_collapse_recursive { tree.collapse_recursive(); true diff --git a/src/components/syntax_text.rs b/src/components/syntax_text.rs index 9968d55c..c13ff5e2 100644 --- a/src/components/syntax_text.rs +++ b/src/components/syntax_text.rs @@ -6,8 +6,8 @@ use crate::{ keys::SharedKeyConfig, strings, ui::{ - self, style::SharedTheme, AsyncSyntaxJob, ParagraphState, - ScrollPos, StatefulParagraph, + self, common_nav, style::SharedTheme, AsyncSyntaxJob, + ParagraphState, ScrollPos, StatefulParagraph, }, }; use anyhow::Result; @@ -18,6 +18,7 @@ use asyncgit::{ }; use crossbeam_channel::Sender; use crossterm::event::Event; +use filetree::MoveSelection; use itertools::Either; use std::{cell::Cell, convert::From, path::Path}; use tui::{ @@ -120,27 +121,41 @@ impl SyntaxTextComponent { } } - fn scroll(&self, down: Option) { - let mut state = self.paragraph_state.get(); - let new_scroll_pos = down.map_or_else( - || state.scroll().y, - |down| { - if down { - state.scroll().y.saturating_add(1) - } else { - state.scroll().y.saturating_sub(1) - } - }, - ); + fn scroll(&self, nav: MoveSelection) -> bool { + let state = self.paragraph_state.get(); - let new_scroll_pos = new_scroll_pos.min( + let new_scroll_pos = match nav { + MoveSelection::Down => state.scroll().y.saturating_add(1), + MoveSelection::Up => state.scroll().y.saturating_sub(1), + MoveSelection::Top => 0, + MoveSelection::End => state + .lines() + .saturating_sub(state.height().saturating_sub(2)), + MoveSelection::PageUp => state + .scroll() + .y + .saturating_sub(state.height().saturating_sub(2)), + MoveSelection::PageDown => state + .scroll() + .y + .saturating_add(state.height().saturating_sub(2)), + _ => state.scroll().y, + }; + + self.set_scroll(new_scroll_pos) + } + + fn set_scroll(&self, pos: u16) -> bool { + let mut state = self.paragraph_state.get(); + + let new_scroll_pos = pos.min( state .lines() .saturating_sub(state.height().saturating_sub(2)), ); if new_scroll_pos == state.scroll().y { - return; + return false; } state.set_scroll(ScrollPos { @@ -148,6 +163,8 @@ impl SyntaxTextComponent { y: new_scroll_pos, }); self.paragraph_state.set(state); + + true } } @@ -185,7 +202,7 @@ impl DrawableComponent for SyntaxTextComponent { self.paragraph_state.set(state); - self.scroll(None); + self.set_scroll(state.scroll().y); if self.focused() { ui::draw_scrollbar( @@ -227,10 +244,11 @@ impl Component for SyntaxTextComponent { event: crossterm::event::Event, ) -> Result { if let Event::Key(key) = event { - if key == self.key_config.move_down { - self.scroll(Some(true)); - } else if key == self.key_config.move_up { - self.scroll(Some(false)); + if let Some(nav) = common_nav(key, &self.key_config) { + return Ok(self + .scroll(nav) + .then(|| EventState::Consumed) + .unwrap_or(EventState::NotConsumed)); } } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 2b4646cd..7734b08d 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -5,6 +5,7 @@ mod stateful_paragraph; pub mod style; mod syntax_text; +use filetree::MoveSelection; pub use scrollbar::draw_scrollbar; pub use scrolllist::{draw_list, draw_list_block}; pub use stateful_paragraph::{ @@ -13,6 +14,8 @@ pub use stateful_paragraph::{ pub use syntax_text::{AsyncSyntaxJob, SyntaxText}; use tui::layout::{Constraint, Direction, Layout, Rect}; +use crate::keys::SharedKeyConfig; + /// return the scroll position (line) necessary to have the `selection` in view if it is not already pub const fn calc_scroll_top( current_top: usize, @@ -109,3 +112,29 @@ pub fn centered_rect_absolute( height.min(r.height), ) } + +/// +pub fn common_nav( + key: crossterm::event::KeyEvent, + key_config: &SharedKeyConfig, +) -> Option { + if key == key_config.move_down { + Some(MoveSelection::Down) + } else if key == key_config.move_up { + Some(MoveSelection::Up) + } else if key == key_config.page_up { + Some(MoveSelection::PageUp) + } else if key == key_config.page_down { + Some(MoveSelection::PageDown) + } else if key == key_config.move_right { + Some(MoveSelection::Right) + } else if key == key_config.move_left { + Some(MoveSelection::Left) + } else if key == key_config.home || key == key_config.shift_up { + Some(MoveSelection::Top) + } else if key == key_config.end || key == key_config.shift_down { + Some(MoveSelection::End) + } else { + None + } +}