Convert SectionTree and all remaining callers to ScrollPane

SectionTree.scroll is now a ScrollPaneState. All callers of
render_scrollable replaced with ScrollPane::render_stateful_widget.

Deleted render_scrollable and its imports — no hand-rolled scroll
rendering remains outside of scroll_pane.rs.

Co-Authored-By: Kent Overstreet <kent.overstreet@gmail.com>
This commit is contained in:
ProofOfConcept 2026-04-11 01:42:49 -04:00
parent 4a1f5acb85
commit e17118e4c9
3 changed files with 19 additions and 47 deletions

View file

@ -1,11 +1,9 @@
// widgets.rs — Shared TUI helpers and reusable components
use ratatui::{
layout::{Margin, Rect},
style::{Color, Modifier, Style},
text::Line,
widgets::{Block, Borders, Paragraph, Scrollbar, ScrollbarOrientation, ScrollbarState, Wrap},
Frame,
widgets::{Block, Borders},
crossterm::event::KeyCode,
};
use crate::agent::context::{AstNode, Ast};
@ -102,35 +100,6 @@ pub fn tree_legend() -> Line<'static> {
)
}
/// Render a scrollable paragraph with a vertical scrollbar.
///
/// Legacy wrapper — callers that manage their own `u16` scroll offset
/// use this. For new code, prefer ScrollPane + ScrollPaneState.
pub fn render_scrollable(
frame: &mut Frame,
area: Rect,
lines: Vec<Line<'_>>,
block: Block<'_>,
scroll: u16,
) {
let content_len = lines.len();
let para = Paragraph::new(lines)
.block(block)
.wrap(Wrap { trim: false })
.scroll((scroll, 0));
frame.render_widget(para, area);
let visible = area.height.saturating_sub(2) as usize;
if content_len > visible {
let mut sb_state = ScrollbarState::new(content_len)
.position(scroll as usize);
frame.render_stateful_widget(
Scrollbar::new(ScrollbarOrientation::VerticalRight),
area.inner(Margin { vertical: 1, horizontal: 0 }),
&mut sb_state,
);
}
}
// ---------------------------------------------------------------------------
// SectionTree — expand/collapse tree renderer for ContextSection
@ -139,12 +108,12 @@ pub fn render_scrollable(
pub struct SectionTree {
pub selected: Option<usize>,
pub expanded: std::collections::HashSet<usize>,
pub scroll: u16,
pub scroll: super::scroll_pane::ScrollPaneState,
}
impl SectionTree {
pub fn new() -> Self {
Self { selected: None, expanded: std::collections::HashSet::new(), scroll: 0 }
Self { selected: None, expanded: std::collections::HashSet::new(), scroll: super::scroll_pane::ScrollPaneState::new() }
}
fn total_nodes(&self, sections: &[SectionView]) -> usize {
@ -184,14 +153,14 @@ impl SectionTree {
KeyCode::PageUp => {
let sel = self.selected.unwrap_or(0);
self.selected = Some(sel.saturating_sub(page));
self.scroll = self.scroll.saturating_sub(page as u16);
self.scroll.scroll_up(page as u16);
return;
}
KeyCode::PageDown => {
let max = item_count.saturating_sub(1);
let sel = self.selected.map_or(0, |s| (s + page).min(max));
self.selected = Some(sel);
self.scroll += page as u16;
self.scroll.scroll_down(page as u16);
return;
}
KeyCode::Home => {
@ -228,10 +197,10 @@ impl SectionTree {
if let Some(sel) = self.selected {
let sel_line = sel as u16;
let visible = height.saturating_sub(2);
if sel_line < self.scroll {
self.scroll = sel_line;
} else if sel_line >= self.scroll + visible {
self.scroll = sel_line.saturating_sub(visible.saturating_sub(1));
if sel_line < self.scroll.offset {
self.scroll.offset = sel_line;
} else if sel_line >= self.scroll.offset + visible {
self.scroll.offset = sel_line.saturating_sub(visible.saturating_sub(1));
}
}
}