feat: introduce CellWidget trait (#1148)

The motivation behind this PR is to make it so a `HistoryCell` is more
like a `WidgetRef` that knows how to render itself into a `Rect` so that
it can be backed by something other than a `Vec<Line>`. Because a
`HistoryCell` is intended to appear in a scrollable list, we want to
ensure the stack of cells can be scrolled one `Line` at a time even if
the `HistoryCell` is not backed by a `Vec<Line>` itself.

To this end, we introduce the `CellWidget` trait whose key method is:

```
fn render_window(&self, first_visible_line: usize, area: Rect, buf: &mut Buffer);
```

The `first_visible_line` param is what differs from
`WidgetRef::render_ref()`, as a `CellWidget` needs to know the offset
into its "full view" at which it should start rendering.

The bookkeeping in `ConversationHistoryWidget` has been updated
accordingly to ensure each `CellWidget` in the history is rendered
appropriately.
This commit is contained in:
Michael Bolin
2025-05-28 14:03:19 -07:00
committed by GitHub
parent d60f350cf8
commit ae1a83f095
5 changed files with 205 additions and 127 deletions

View File

@@ -0,0 +1,20 @@
use ratatui::prelude::*;
/// Trait implemented by every type that can live inside the conversation
/// history list. It provides two primitives that the parent scroll-view
/// needs: how *tall* the widget is at a given width and how to render an
/// arbitrary contiguous *window* of that widget.
///
/// The `first_visible_line` argument to [`render_window`] allows partial
/// rendering when the top of the widget is scrolled off-screen. The caller
/// guarantees that `first_visible_line + area.height as usize` never exceeds
/// the total height previously returned by [`height`].
pub(crate) trait CellWidget {
/// Total height measured in wrapped terminal lines when drawn with the
/// given *content* width (no scrollbar column included).
fn height(&self, width: u16) -> usize;
/// Render a *window* that starts `first_visible_line` lines below the top
/// of the widget. The windows size is given by `area`.
fn render_window(&self, first_visible_line: usize, area: Rect, buf: &mut Buffer);
}