mirror of
https://github.com/gitui-org/gitui
synced 2026-05-23 00:48:35 +00:00
feat: file and status tab support pageup and pagedown (#2496)
This commit is contained in:
parent
ee5c243cbf
commit
706cdf9243
5 changed files with 99 additions and 4 deletions
|
|
@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
* execute git-hooks directly if possible (on *nix) else use sh instead of bash (without reading SHELL variable) [[@Joshix](https://github.com/Joshix-1)] ([#2483](https://github.com/extrawurst/gitui/pull/2483))
|
||||
|
||||
### Added
|
||||
* Files and status tab support pageUp and pageDown [[@fatpandac](https://github.com/fatpandac)] ([#1951](https://github.com/extrawurst/gitui/issues/1951))
|
||||
* support loading custom syntax highlighting themes from a file [[@acuteenvy](https://github.com/acuteenvy)] ([#2565](https://github.com/gitui-org/gitui/pull/2565))
|
||||
* Select syntax highlighting theme out of the defaults from syntect [[@vasilismanol](https://github.com/vasilismanol)] ([#1931](https://github.com/extrawurst/gitui/issues/1931))
|
||||
* new command-line option to override the default log file path (`--logfile`) [[@acuteenvy](https://github.com/acuteenvy)] ([#2539](https://github.com/gitui-org/gitui/pull/2539))
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::{
|
|||
error::Result, filetreeitems::FileTreeItems,
|
||||
tree_iter::TreeIterator, TreeItemInfo,
|
||||
};
|
||||
use std::{collections::BTreeSet, path::Path};
|
||||
use std::{cell::Cell, collections::BTreeSet, path::Path};
|
||||
|
||||
///
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
|
@ -30,6 +30,7 @@ pub struct FileTree {
|
|||
selection: Option<usize>,
|
||||
// caches the absolute selection translated to visual index
|
||||
visual_selection: Option<VisualSelection>,
|
||||
pub window_height: Cell<Option<usize>>,
|
||||
}
|
||||
|
||||
impl FileTree {
|
||||
|
|
@ -42,6 +43,7 @@ impl FileTree {
|
|||
items: FileTreeItems::new(list, collapsed)?,
|
||||
selection: if list.is_empty() { None } else { Some(0) },
|
||||
visual_selection: None,
|
||||
window_height: None.into(),
|
||||
};
|
||||
new_self.visual_selection = new_self.calc_visual_selection();
|
||||
|
||||
|
|
@ -112,6 +114,18 @@ impl FileTree {
|
|||
}
|
||||
}
|
||||
|
||||
fn selection_page_updown(
|
||||
&self,
|
||||
range: impl Iterator<Item = usize>,
|
||||
) -> Option<usize> {
|
||||
let page_size = self.window_height.get().unwrap_or(0);
|
||||
|
||||
range
|
||||
.filter(|index| self.is_visible_index(*index))
|
||||
.take(page_size)
|
||||
.last()
|
||||
}
|
||||
|
||||
///
|
||||
pub fn move_selection(&mut self, dir: MoveSelection) -> bool {
|
||||
self.selection.is_some_and(|selection| {
|
||||
|
|
@ -130,9 +144,13 @@ impl FileTree {
|
|||
Self::selection_start(selection)
|
||||
}
|
||||
MoveSelection::End => self.selection_end(selection),
|
||||
MoveSelection::PageDown | MoveSelection::PageUp => {
|
||||
None
|
||||
MoveSelection::PageUp => {
|
||||
self.selection_page_updown((0..=selection).rev())
|
||||
}
|
||||
MoveSelection::PageDown => self
|
||||
.selection_page_updown(
|
||||
selection..(self.items.len()),
|
||||
),
|
||||
};
|
||||
|
||||
let changed_index =
|
||||
|
|
@ -514,4 +532,36 @@ mod test {
|
|||
assert_eq!(s.count, 3);
|
||||
assert_eq!(s.index, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_selection_page_updown() {
|
||||
let items = vec![
|
||||
Path::new("a/b/c"), //
|
||||
Path::new("a/b/c2"), //
|
||||
Path::new("a/d"), //
|
||||
Path::new("a/e"), //
|
||||
];
|
||||
|
||||
//0 a/
|
||||
//1 b/
|
||||
//2 c
|
||||
//3 c2
|
||||
//4 d
|
||||
//5 e
|
||||
|
||||
let mut tree =
|
||||
FileTree::new(&items, &BTreeSet::new()).unwrap();
|
||||
|
||||
tree.window_height.set(Some(3));
|
||||
|
||||
tree.selection = Some(0);
|
||||
assert!(tree.move_selection(MoveSelection::PageDown));
|
||||
assert_eq!(tree.selection, Some(2));
|
||||
assert!(tree.move_selection(MoveSelection::PageDown));
|
||||
assert_eq!(tree.selection, Some(4));
|
||||
assert!(tree.move_selection(MoveSelection::PageUp));
|
||||
assert_eq!(tree.selection, Some(2));
|
||||
assert!(tree.move_selection(MoveSelection::PageUp));
|
||||
assert_eq!(tree.selection, Some(0));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -275,6 +275,8 @@ impl RevisionFilesComponent {
|
|||
let tree_height = usize::from(area.height.saturating_sub(2));
|
||||
let tree_width = usize::from(area.width);
|
||||
|
||||
self.tree.window_height.set(Some(tree_height));
|
||||
|
||||
self.tree.visual_selection().map_or_else(
|
||||
|| {
|
||||
self.scroll.reset();
|
||||
|
|
|
|||
|
|
@ -351,6 +351,7 @@ impl DrawableComponent for StatusTreeComponent {
|
|||
.map(|idx| idx.saturating_sub(selection_offset))
|
||||
.unwrap_or_default();
|
||||
let tree_height = r.height.saturating_sub(2) as usize;
|
||||
self.tree.window_height.set(Some(tree_height));
|
||||
|
||||
self.scroll_top.set(ui::calc_scroll_top(
|
||||
self.scroll_top.get(),
|
||||
|
|
@ -504,6 +505,15 @@ impl Component for StatusTreeComponent {
|
|||
|| key_match(e, self.key_config.keys.shift_down)
|
||||
{
|
||||
Ok(self.move_selection(MoveSelection::End).into())
|
||||
} else if key_match(e, self.key_config.keys.page_up) {
|
||||
Ok(self
|
||||
.move_selection(MoveSelection::PageUp)
|
||||
.into())
|
||||
} else if key_match(e, self.key_config.keys.page_down)
|
||||
{
|
||||
Ok(self
|
||||
.move_selection(MoveSelection::PageDown)
|
||||
.into())
|
||||
} else if key_match(e, self.key_config.keys.move_left)
|
||||
{
|
||||
Ok(self
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use super::filetree::{
|
|||
};
|
||||
use anyhow::Result;
|
||||
use asyncgit::StatusItem;
|
||||
use std::{cmp, collections::BTreeSet};
|
||||
use std::{cell::Cell, cmp, collections::BTreeSet};
|
||||
|
||||
//TODO: use new `filetreelist` crate
|
||||
|
||||
|
|
@ -16,6 +16,8 @@ pub struct StatusTree {
|
|||
// some folders may be folded up, this allows jumping
|
||||
// over folders which are folded into their parent
|
||||
pub available_selections: Vec<usize>,
|
||||
|
||||
pub window_height: Cell<Option<usize>>,
|
||||
}
|
||||
|
||||
///
|
||||
|
|
@ -27,6 +29,8 @@ pub enum MoveSelection {
|
|||
Right,
|
||||
Home,
|
||||
End,
|
||||
PageDown,
|
||||
PageUp,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
|
@ -143,6 +147,15 @@ impl StatusTree {
|
|||
}
|
||||
MoveSelection::Home => SelectionChange::new(0, false),
|
||||
MoveSelection::End => self.selection_end(),
|
||||
MoveSelection::PageUp => self.selection_page_updown(
|
||||
selection,
|
||||
(0..=selection).rev(),
|
||||
),
|
||||
MoveSelection::PageDown => self
|
||||
.selection_page_updown(
|
||||
selection,
|
||||
selection..(self.tree.len()),
|
||||
),
|
||||
};
|
||||
|
||||
let changed_index =
|
||||
|
|
@ -283,6 +296,25 @@ impl StatusTree {
|
|||
SelectionChange::new(new_index, false)
|
||||
}
|
||||
|
||||
fn selection_page_updown(
|
||||
&self,
|
||||
current_index: usize,
|
||||
range: impl Iterator<Item = usize>,
|
||||
) -> SelectionChange {
|
||||
let page_size = self.window_height.get().unwrap_or(0);
|
||||
|
||||
let new_index = range
|
||||
.filter(|index| {
|
||||
self.available_selections.contains(index)
|
||||
&& self.is_visible_index(*index)
|
||||
})
|
||||
.take(page_size)
|
||||
.last()
|
||||
.unwrap_or(current_index);
|
||||
|
||||
SelectionChange::new(new_index, false)
|
||||
}
|
||||
|
||||
fn is_visible_index(&self, idx: usize) -> bool {
|
||||
self.tree[idx].info.visible
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue