From 757d971056220bfc6ced86b3998e0de05d927745 Mon Sep 17 00:00:00 2001 From: harehare Date: Mon, 13 Jul 2026 21:08:38 +0900 Subject: [PATCH] feat(pager): add vim-style page navigation keys Add f/b for full-page down/up and allow d/u to work as half-page scroll without requiring Ctrl, matching common pager/vim bindings. Also bind Home/End as aliases for jump to top/bottom. --- README.md | 6 +++--- src/pager.rs | 20 +++++++++----------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index aa10eb7..277547a 100644 --- a/README.md +++ b/README.md @@ -96,9 +96,9 @@ cat report.md | mq-view --pager | Key | Action | | --- | --- | | `j` / `k`, `↓` / `↑` | Scroll down / up | -| `Space` / `PageDown`, `PageUp` | Scroll a page down / up | -| `Ctrl-d` / `Ctrl-u` | Scroll half a page down / up | -| `g` / `G` | Jump to top / bottom | +| `Space` / `PageDown` / `f`, `PageUp` / `b` | Scroll a page down / up | +| `d` / `u` (with or without `Ctrl`) | Scroll half a page down / up | +| `g` / `Home`, `G` / `End` | Jump to top / bottom | | `Tab` | Toggle the heading outline; `j`/`k` to move, `Enter` to jump | | `/` | Search; `Enter` to confirm, `Esc` to cancel | | `n` / `N` | Jump to the next / previous search match | diff --git a/src/pager.rs b/src/pager.rs index 3113865..9eee25c 100644 --- a/src/pager.rs +++ b/src/pager.rs @@ -9,7 +9,7 @@ use notify::{RecommendedWatcher, RecursiveMode, Watcher}; use ratatui::Frame; use ratatui::Terminal; use ratatui::backend::CrosstermBackend; -use ratatui::crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers}; +use ratatui::crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind}; use ratatui::crossterm::execute; use ratatui::crossterm::terminal::{ self as crossterm_terminal, EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, @@ -330,18 +330,16 @@ fn handle_key(app: &mut App, key: KeyEvent, content_height: usize) -> bool { KeyCode::Char('q') | KeyCode::Esc => return true, KeyCode::Char('j') | KeyCode::Down => scroll_by(app, 1, content_height), KeyCode::Char('k') | KeyCode::Up => scroll_by(app, -1, content_height), - KeyCode::Char(' ') | KeyCode::PageDown => { + KeyCode::Char(' ') | KeyCode::PageDown | KeyCode::Char('f') => { scroll_by(app, content_height as isize, content_height) } - KeyCode::PageUp => scroll_by(app, -(content_height as isize), content_height), - KeyCode::Char('d') if key.modifiers.contains(KeyModifiers::CONTROL) => { - scroll_by(app, (content_height / 2) as isize, content_height) + KeyCode::PageUp | KeyCode::Char('b') => { + scroll_by(app, -(content_height as isize), content_height) } - KeyCode::Char('u') if key.modifiers.contains(KeyModifiers::CONTROL) => { - scroll_by(app, -((content_height as isize) / 2), content_height) - } - KeyCode::Char('g') => app.scroll = 0, - KeyCode::Char('G') => app.scroll = max_scroll(&app.doc, content_height), + KeyCode::Char('d') => scroll_by(app, (content_height / 2) as isize, content_height), + KeyCode::Char('u') => scroll_by(app, -((content_height as isize) / 2), content_height), + KeyCode::Char('g') | KeyCode::Home => app.scroll = 0, + KeyCode::Char('G') | KeyCode::End => app.scroll = max_scroll(&app.doc, content_height), KeyCode::Tab => { app.show_outline = true; app.outline_state.select(nearest_heading_index(app)); @@ -475,7 +473,7 @@ fn draw_footer(frame: &mut Frame, area: Rect, app: &App, content_height: usize) .split(area); frame.render_widget( Paragraph::new( - " q:quit j/k:scroll Tab:outline /:search n/N:next/prev match", + " q:quit j/k:scroll f/b/d/u:page g/G:top/bottom Tab:outline /:search n/N:next/prev match", ) .style(Style::default().fg(Color::DarkGray)), cols[0],