feat(kebab-tui): p9-fb-24 task 3 — Ask PgUp/PgDn page scroll

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-04 16:44:47 +00:00
parent 94541523e7
commit 5242328588
2 changed files with 72 additions and 0 deletions

View File

@@ -439,6 +439,24 @@ pub fn handle_key_ask(state: &mut App, key: KeyEvent) -> KeyOutcome {
s.input.delete_after(); s.input.delete_after();
KeyOutcome::Continue KeyOutcome::Continue
} }
// p9-fb-24: PgUp / PgDn page-scroll the transcript by
// `pager::PAGE_STEP` rows. Mode-agnostic (physical keys, no
// typing ambiguity). Both flip `follow_tail` to false so the
// user pinning the view via paging doesn't get yanked back to
// the bottom on the next streamed token (same contract as
// `j` / `k` from p9-fb-22).
(KeyCode::PageDown, _) => {
let s = state.ask.as_mut().unwrap();
s.follow_tail = false;
s.scroll = s.scroll.saturating_add(crate::pager::PAGE_STEP);
KeyOutcome::Continue
}
(KeyCode::PageUp, _) => {
let s = state.ask.as_mut().unwrap();
s.follow_tail = false;
s.scroll = s.scroll.saturating_sub(crate::pager::PAGE_STEP);
KeyOutcome::Continue
}
// Insert mode: every non-chord Char (incl. e/j/k) types into // Insert mode: every non-chord Char (incl. e/j/k) types into
// input. CTRL/ALT chords stay reserved. // input. CTRL/ALT chords stay reserved.
(KeyCode::Char(c), m) (KeyCode::Char(c), m)

View File

@@ -784,6 +784,60 @@ fn ctrl_l_resets_follow_tail_in_ask() {
assert!(app.ask.as_ref().unwrap().follow_tail); assert!(app.ask.as_ref().unwrap().follow_tail);
} }
/// p9-fb-24: PgDn advances Ask scroll by `PAGE_STEP` (= 10) and
/// disengages follow-tail (matches `j` semantics — manual scroll =
/// freeze).
#[test]
fn page_down_advances_scroll_and_freezes_follow_tail_in_ask() {
let mut app = fresh_app();
app.mode = kebab_tui::Mode::Normal;
let outcome = handle_key_ask(
&mut app,
KeyEvent::new(KeyCode::PageDown, KeyModifiers::NONE),
);
assert_eq!(outcome, KeyOutcome::Continue);
let s = app.ask.as_ref().unwrap();
assert_eq!(s.scroll, 10, "PgDn shifts scroll by PAGE_STEP");
assert!(!s.follow_tail, "PgDn freezes follow_tail like j/k");
}
/// p9-fb-24: PgUp rewinds Ask scroll by `PAGE_STEP` (saturating at 0)
/// and disengages follow-tail.
#[test]
fn page_up_rewinds_scroll_saturating_and_freezes_follow_tail_in_ask() {
let mut app = fresh_app();
app.mode = kebab_tui::Mode::Normal;
app.ask.as_mut().unwrap().scroll = 25;
app.ask.as_mut().unwrap().follow_tail = true;
handle_key_ask(
&mut app,
KeyEvent::new(KeyCode::PageUp, KeyModifiers::NONE),
);
let s = app.ask.as_ref().unwrap();
assert_eq!(s.scroll, 15);
assert!(!s.follow_tail);
app.ask.as_mut().unwrap().scroll = 3;
handle_key_ask(
&mut app,
KeyEvent::new(KeyCode::PageUp, KeyModifiers::NONE),
);
assert_eq!(app.ask.as_ref().unwrap().scroll, 0);
}
/// p9-fb-24: PgUp / PgDn fire from BOTH Insert and Normal modes
/// (physical keys, no typing ambiguity — same as Left/Right/Home/End
/// from p9-fb-22).
#[test]
fn page_keys_fire_from_insert_mode_in_ask() {
let mut app = fresh_app();
app.mode = kebab_tui::Mode::Insert;
handle_key_ask(
&mut app,
KeyEvent::new(KeyCode::PageDown, KeyModifiers::NONE),
);
assert_eq!(app.ask.as_ref().unwrap().scroll, 10);
}
/// p9-fb-22 (issue #95): when follow_tail is on and the transcript /// p9-fb-22 (issue #95): when follow_tail is on and the transcript
/// has many lines, the rendered buffer's last visible line includes /// has many lines, the rendered buffer's last visible line includes
/// content from the tail of the answer (not the head). /// content from the tail of the answer (not the head).