Skip to content

Commit

Permalink
Add keybindings to jump to next section of the same type
Browse files Browse the repository at this point in the history
For example, if the currently highlighted row is a section header, the page
down key will jump to the next section. If the currently highlighted row is a
line change, the page down key will jump to the next selectable line.

The new keybindings are page-up and page-down.
  • Loading branch information
emesterhazy committed Jun 2, 2024
1 parent 0564cce commit d452041
Show file tree
Hide file tree
Showing 2 changed files with 427 additions and 0 deletions.
69 changes: 69 additions & 0 deletions src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,10 @@ pub enum Event {
PageUp,
PageDown,
FocusPrev,
FocusPrevSameKind, // focus on the previous item of the same kind (i.e. file, section, line)
FocusPrevPage,
FocusNext,
FocusNextSameKind, // focus on the next item of the same kind
FocusNextPage,
FocusInner,
FocusOuter,
Expand Down Expand Up @@ -215,6 +217,19 @@ impl From<crossterm::event::Event> for Event {
state: _,
}) => Self::FocusNext,

Event::Key(KeyEvent {
code: KeyCode::PageUp,
modifiers: KeyModifiers::NONE,
kind: KeyEventKind::Press,
state: _,
}) => Self::FocusPrevSameKind,
Event::Key(KeyEvent {
code: KeyCode::PageDown,
modifiers: KeyModifiers::NONE,
kind: KeyEventKind::Press,
state: _,
}) => Self::FocusNextSameKind,

Event::Key(KeyEvent {
code: KeyCode::Left | KeyCode::Char('h'),
modifiers: KeyModifiers::NONE,
Expand Down Expand Up @@ -722,6 +737,14 @@ impl<'state, 'input> Recorder<'state, 'input> {
label: Cow::Borrowed("Next item (down, j)"),
event: Event::FocusNext,
},
MenuItem {
label: Cow::Borrowed("Previous item of the same kind (page-up)"),
event: Event::FocusPrevSameKind,
},
MenuItem {
label: Cow::Borrowed("Next item of the same kind (page-down)"),
event: Event::FocusNextSameKind,
},
MenuItem {
label: Cow::Borrowed("Outer item (left, h)"),
event: Event::FocusOuter,
Expand Down Expand Up @@ -1040,6 +1063,8 @@ impl<'state, 'input> Recorder<'state, 'input> {
| Event::PageDown
| Event::FocusPrev
| Event::FocusNext
| Event::FocusPrevSameKind
| Event::FocusNextSameKind
| Event::FocusPrevPage
| Event::FocusNextPage
| Event::ToggleAll
Expand Down Expand Up @@ -1082,6 +1107,22 @@ impl<'state, 'input> Recorder<'state, 'input> {
ensure_in_viewport: true,
}
}
(None, Event::FocusPrevSameKind) => {
let selection_key =
self.select_prev_or_next_of_same_kind(/*select_previous=*/ true);
StateUpdate::SelectItem {
selection_key,
ensure_in_viewport: true,
}
}
(None, Event::FocusNextSameKind) => {
let selection_key =
self.select_prev_or_next_of_same_kind(/*select_previous=*/ false);
StateUpdate::SelectItem {
selection_key,
ensure_in_viewport: true,
}
}
(None, Event::FocusPrevPage) => {
let selection_key = self.select_prev_page(term_height, drawn_rects);
StateUpdate::SelectItem {
Expand Down Expand Up @@ -1293,6 +1334,34 @@ impl<'state, 'input> Recorder<'state, 'input> {
}
}

// Returns the previous or next SelectionKey of the same kind as the current
// selection key. If there are no other keys of the same kind, the current
// key is returned instead. If `select_previous` is true, the previous key
// is returned. Otherwise, the next key is returned.
fn select_prev_or_next_of_same_kind(&self, select_previous: bool) -> SelectionKey {
let (keys, index) = self.find_selection();
let iterate_keys_with_wrap_around = |i| -> Box<dyn DoubleEndedIterator<Item = _>> {
let forward_iter = keys[i + 1..] // Skip the current key
.iter()
.chain(keys[..i].iter());
if select_previous {
return Box::new(forward_iter.rev());
}
Box::new(forward_iter)
};
match index {
None => self.first_selection_key(),
Some(index) => {
match iterate_keys_with_wrap_around(index)
.find(|k| std::mem::discriminant(*k) == std::mem::discriminant(&keys[index]))
{
None => keys[index],
Some(key) => *key,
}
}
}
}

fn select_prev_page(
&self,
term_height: usize,
Expand Down
Loading

0 comments on commit d452041

Please sign in to comment.