diff --git a/src/components/commit_details/details.rs b/src/components/commit_details/details.rs index 986a1af29d..aa8fc86b85 100644 --- a/src/components/commit_details/details.rs +++ b/src/components/commit_details/details.rs @@ -244,7 +244,10 @@ impl DetailsComponent { }) } - fn move_scroll_top(&mut self, move_type: ScrollType) -> bool { + pub(in crate::components) fn move_scroll_top( + &mut self, + move_type: ScrollType, + ) -> bool { if self.data.is_some() { self.scroll.move_top(move_type) } else { diff --git a/src/components/commit_details/mod.rs b/src/components/commit_details/mod.rs index 229c2a9ae9..54ebab99aa 100644 --- a/src/components/commit_details/mod.rs +++ b/src/components/commit_details/mod.rs @@ -11,6 +11,7 @@ use crate::{ app::Environment, keys::{key_match, SharedKeyConfig}, strings, + ui::seek_scroll, }; use anyhow::Result; use asyncgit::{ @@ -221,6 +222,16 @@ impl Component for CommitDetailsComponent { self.file_tree.focus(false); self.set_details_focus(true); Ok(EventState::Consumed) + } else if let Some(scroll) = + seek_scroll(e, &self.key_config) + { + let state = if self.file_tree.focused() { + self.single_details.move_scroll_top(scroll); + EventState::Consumed + } else { + EventState::NotConsumed + }; + Ok(state) } else { Ok(EventState::NotConsumed) }; diff --git a/src/components/mod.rs b/src/components/mod.rs index 4f1f3f4006..b24a7deb83 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -132,7 +132,7 @@ pub fn command_pump( } } -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub enum ScrollType { Up, Down, diff --git a/src/components/revision_files.rs b/src/components/revision_files.rs index d2f5bb8fdf..eaa83ea06d 100644 --- a/src/components/revision_files.rs +++ b/src/components/revision_files.rs @@ -10,7 +10,7 @@ use crate::{ queue::{InternalEvent, Queue, StackablePopupOpen}, strings::{self, order, symbol}, try_or_popup, - ui::{self, common_nav, style::SharedTheme}, + ui::{self, common_nav, seek_move, style::SharedTheme}, AsyncNotification, }; use anyhow::Result; @@ -444,6 +444,11 @@ impl Component for RevisionFilesComponent { ) .order(order::RARE_ACTION), ); + out.push(CommandInfo::new( + strings::commands::seek(&self.key_config), + self.tree.selected_file().is_some(), + true, + )); tree_nav_cmds(&self.tree, &self.key_config, out); } else { self.current_file.commands(out, force_all); @@ -480,6 +485,22 @@ impl Component for RevisionFilesComponent { self.hide(); return Ok(EventState::Consumed); } + } else if key_match(key, self.key_config.keys.seek_up) + || key_match(key, self.key_config.keys.seek_down) + { + if is_tree_focused { + if let Some(nav) = + seek_move(key, &self.key_config) + { + return Ok( + if self.current_file.scroll(nav) { + EventState::Consumed + } else { + EventState::NotConsumed + }, + ); + } + } } else if key_match(key, self.key_config.keys.move_right) { if is_tree_focused { diff --git a/src/components/syntax_text.rs b/src/components/syntax_text.rs index aaf348ddaf..cee158c69a 100644 --- a/src/components/syntax_text.rs +++ b/src/components/syntax_text.rs @@ -135,7 +135,10 @@ impl SyntaxTextComponent { } } - fn scroll(&self, nav: MoveSelection) -> bool { + pub(in crate::components) fn scroll( + &self, + nav: MoveSelection, + ) -> bool { let state = self.paragraph_state.get(); let new_scroll_pos = match nav { diff --git a/src/keys/key_list.rs b/src/keys/key_list.rs index a542ef938a..965ee87085 100644 --- a/src/keys/key_list.rs +++ b/src/keys/key_list.rs @@ -56,6 +56,8 @@ pub struct KeysList { pub move_right: GituiKeyEvent, pub move_up: GituiKeyEvent, pub move_down: GituiKeyEvent, + pub seek_up: GituiKeyEvent, + pub seek_down: GituiKeyEvent, pub tree_collapse_recursive: GituiKeyEvent, pub tree_expand_recursive: GituiKeyEvent, pub home: GituiKeyEvent, @@ -152,6 +154,8 @@ impl Default for KeysList { end: GituiKeyEvent::new(KeyCode::End, KeyModifiers::empty()), move_up: GituiKeyEvent::new(KeyCode::Up, KeyModifiers::empty()), move_down: GituiKeyEvent::new(KeyCode::Down, KeyModifiers::empty()), + seek_up: GituiKeyEvent::new(KeyCode::Up, KeyModifiers::ALT), + seek_down: GituiKeyEvent::new(KeyCode::Down, KeyModifiers::ALT), popup_up: GituiKeyEvent::new(KeyCode::Up, KeyModifiers::empty()), popup_down: GituiKeyEvent::new(KeyCode::Down, KeyModifiers::empty()), page_down: GituiKeyEvent::new(KeyCode::PageDown, KeyModifiers::empty()), diff --git a/src/strings.rs b/src/strings.rs index 70ca9e3e8f..fbaccbfb69 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -546,6 +546,17 @@ pub mod commands { CMD_GROUP_GENERAL, ) } + pub fn seek(key_config: &SharedKeyConfig) -> CommandText { + CommandText::new( + format!( + "Seek [{}{}]", + key_config.get_hint(key_config.keys.seek_up), + key_config.get_hint(key_config.keys.seek_down) + ), + "Seek up or down in selected file", + CMD_GROUP_GENERAL, + ) + } pub fn commit_list_mark( key_config: &SharedKeyConfig, marked: bool, diff --git a/src/ui/mod.rs b/src/ui/mod.rs index f0ee1539f9..26b7d11dd0 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -14,7 +14,10 @@ pub use stateful_paragraph::{ }; pub use syntax_text::{AsyncSyntaxJob, SyntaxText}; -use crate::keys::{key_match, SharedKeyConfig}; +use crate::{ + components::ScrollType, + keys::{key_match, SharedKeyConfig}, +}; /// return the scroll position (line) necessary to have the `selection` in view if it is not already pub const fn calc_scroll_top( @@ -153,6 +156,32 @@ pub fn common_nav( } } +pub fn seek_move( + key: &crossterm::event::KeyEvent, + key_config: &SharedKeyConfig, +) -> Option { + if key_match(key, key_config.keys.seek_up) { + Some(MoveSelection::Up) + } else if key_match(key, key_config.keys.seek_down) { + Some(MoveSelection::Down) + } else { + None + } +} + +pub fn seek_scroll( + key: &crossterm::event::KeyEvent, + key_config: &SharedKeyConfig, +) -> Option { + if key_match(key, key_config.keys.seek_up) { + Some(ScrollType::Up) + } else if key_match(key, key_config.keys.seek_down) { + Some(ScrollType::Down) + } else { + None + } +} + #[cfg(test)] mod test { use super::{rect_inside, Size};