diff --git a/.beans/claudbg-4gtn--tui-spacepagedown-scrolls-past-end-of-transcript.md b/.beans/claudbg-4gtn--tui-spacepagedown-scrolls-past-end-of-transcript.md index 996748b..b2cac80 100644 --- a/.beans/claudbg-4gtn--tui-spacepagedown-scrolls-past-end-of-transcript.md +++ b/.beans/claudbg-4gtn--tui-spacepagedown-scrolls-past-end-of-transcript.md @@ -1,10 +1,15 @@ --- # claudbg-4gtn title: 'TUI: Space/PageDown scrolls past end of transcript' -status: todo +status: completed type: bug +priority: normal created_at: 2026-03-31T23:45:06Z -updated_at: 2026-03-31T23:45:06Z +updated_at: 2026-04-01T05:51:55Z --- Space/PageDown in the transcript view continues scrolling past the last line. It should stop at the bottom of the transcript content. + +## Summary of Changes + +In `src/tui/screens/transcript.rs`, the PageDown/Space handler now clamps scroll to the actual content length: computes `total_lines = build_chat_lines(...).len()` and `max_scroll = total_lines.saturating_sub(page_height)`, then applies `.min(max_scroll)` to prevent scrolling into empty space. Updated 3 existing tests to populate entries before testing scroll behavior. diff --git a/src/tui/screens/transcript.rs b/src/tui/screens/transcript.rs index ebe8130..1f1ee14 100644 --- a/src/tui/screens/transcript.rs +++ b/src/tui/screens/transcript.rs @@ -624,7 +624,10 @@ pub fn handle_transcript_event(event: Event, state: &mut AppState) -> bool { } KeyCode::PageDown | KeyCode::Char(' ') => { let page = (state.transcript_page_height as usize).max(1); - state.transcript_scroll = state.transcript_scroll.saturating_add(page); + let total_lines = + build_chat_lines(&state.transcript_entries, state.color_enabled).len(); + let max_scroll = total_lines.saturating_sub(state.transcript_page_height as usize); + state.transcript_scroll = state.transcript_scroll.saturating_add(page).min(max_scroll); true } // Horizontal scroll — only meaningful in ChatLog. @@ -1197,6 +1200,10 @@ mod tests { #[test] fn space_scrolls_down_by_page() { let mut state = transcript_state(); + // Populate enough entries that clamping won't prevent scrolling by the full page. + state.transcript_entries = (0..100) + .map(|i| user_text_entry(&format!("line {i}"))) + .collect(); state.transcript_page_height = 20; handle_transcript_event(press(KeyCode::Char(' ')), &mut state); assert_eq!(state.transcript_scroll, 20); @@ -1205,6 +1212,10 @@ mod tests { #[test] fn pagedown_scrolls_down_by_page() { let mut state = transcript_state(); + // Populate enough entries that clamping won't prevent scrolling by the full page. + state.transcript_entries = (0..100) + .map(|i| user_text_entry(&format!("line {i}"))) + .collect(); state.transcript_page_height = 15; handle_transcript_event(press(KeyCode::PageDown), &mut state); assert_eq!(state.transcript_scroll, 15); @@ -1392,6 +1403,8 @@ mod tests { #[test] fn page_scroll_uses_one_when_height_is_zero() { let mut state = transcript_state(); + // Need at least one line of content so clamping allows scroll=1. + state.transcript_entries = vec![user_text_entry("hello")]; state.transcript_page_height = 0; handle_transcript_event(press(KeyCode::Char(' ')), &mut state); assert_eq!(state.transcript_scroll, 1);