Codex Handbook
tui/src/chatwidget/rendering.rs 149 lines
//! Render composition for the main chat widget surface.use super::*;impl ChatWidget {    pub(super) fn as_renderable(&self) -> RenderableItem<'_> {        let active_cell_right_reserve = self.ambient_pet_wrap_reserved_cols();        let active_cell_renderable = match &self.transcript.active_cell {            Some(cell) => RenderableItem::Owned(Box::new(TranscriptAreaRenderable {                child: cell.as_ref(),                top: 1,                right: active_cell_right_reserve,            })),            None => RenderableItem::Owned(Box::new(())),        };        let active_hook_cell_renderable = match &self.active_hook_cell {            Some(cell) if cell.should_render() => {                RenderableItem::Owned(Box::new(TranscriptAreaRenderable {                    child: cell,                    top: 1,                    right: active_cell_right_reserve,                }))            }            _ => RenderableItem::Owned(Box::new(())),        };        let mut flex = FlexRenderable::new();        flex.push(/*flex*/ 1, active_cell_renderable);        flex.push(/*flex*/ 0, active_hook_cell_renderable);        if let Some(cell) = self.pending_token_activity_output() {            flex.push(                /*flex*/ 1,                RenderableItem::Owned(Box::new(TranscriptAreaRenderable {                    child: cell,                    top: 1,                    right: active_cell_right_reserve,                })),            );        }        if let Some(cell) = self.pending_rate_limit_reset_hint() {            flex.push(                /*flex*/ 1,                RenderableItem::Owned(Box::new(TranscriptAreaRenderable {                    child: cell,                    top: 1,                    right: active_cell_right_reserve,                })),            );        }        flex.push(            /*flex*/ 0,            RenderableItem::Owned(Box::new(BottomPaneComposerReserveRenderable {                bottom_pane: &self.bottom_pane,                right_reserve: active_cell_right_reserve,            }))            .inset(Insets::tlbr(                /*top*/ 1, /*left*/ 0, /*bottom*/ 0, /*right*/ 0,            )),        );        RenderableItem::Owned(Box::new(flex))    }}struct BottomPaneComposerReserveRenderable<'a> {    bottom_pane: &'a BottomPane,    right_reserve: u16,}impl Renderable for BottomPaneComposerReserveRenderable<'_> {    fn render(&self, area: Rect, buf: &mut Buffer) {        self.bottom_pane            .render_with_composer_right_reserve(area, buf, self.right_reserve);    }    fn desired_height(&self, width: u16) -> u16 {        self.bottom_pane            .desired_height_with_composer_right_reserve(width, self.right_reserve)    }    fn cursor_pos(&self, area: Rect) -> Option<(u16, u16)> {        self.bottom_pane            .cursor_pos_with_composer_right_reserve(area, self.right_reserve)    }    fn cursor_style(&self, area: Rect) -> crossterm::cursor::SetCursorStyle {        self.bottom_pane            .cursor_style_with_composer_right_reserve(area, self.right_reserve)    }}struct TranscriptAreaRenderable<'a> {    child: &'a dyn HistoryCell,    top: u16,    right: u16,}impl Renderable for TranscriptAreaRenderable<'_> {    fn render(&self, area: Rect, buf: &mut Buffer) {        let area = self.child_area(area);        let lines = self.child.display_lines(area.width);        let paragraph = Paragraph::new(Text::from(lines)).wrap(Wrap { trim: false });        let y = if area.height == 0 {            0        } else {            let overflow = paragraph                .line_count(area.width)                .saturating_sub(usize::from(area.height));            u16::try_from(overflow).unwrap_or(u16::MAX)        };        Clear.render(area, buf);        paragraph.scroll((y, 0)).render(area, buf);    }    fn desired_height(&self, width: u16) -> u16 {        let child_width = width.saturating_sub(self.right).max(1);        HistoryCell::desired_height(self.child, child_width) + self.top    }}impl TranscriptAreaRenderable<'_> {    fn child_area(&self, area: Rect) -> Rect {        let y = area.y.saturating_add(self.top);        let height = area.height.saturating_sub(self.top);        Rect::new(            area.x,            y,            area.width.saturating_sub(self.right).max(1),            height,        )    }}impl Renderable for ChatWidget {    fn render(&self, area: Rect, buf: &mut Buffer) {        self.as_renderable().render(area, buf);        self.last_rendered_width.set(Some(area.width as usize));    }    fn desired_height(&self, width: u16) -> u16 {        self.as_renderable().desired_height(width)    }    fn cursor_pos(&self, area: Rect) -> Option<(u16, u16)> {        self.as_renderable().cursor_pos(area)    }    fn cursor_style(&self, area: Rect) -> crossterm::cursor::SetCursorStyle {        self.as_renderable().cursor_style(area)    }}