Codex Handbook
tui/src/markdown_render/table_key_value.rs 283 lines
//! Vertical key/value rendering for markdown tables that no longer scan well as grids.use super::TABLE_BODY_SEPARATOR_CHAR;use super::TableCell;use super::TableColumnKind;use super::TableColumnMetrics;use crate::render::line_utils::line_to_static;use crate::render::line_utils::push_owned_lines;use crate::terminal_hyperlinks::HyperlinkLine;use crate::terminal_hyperlinks::remap_wrapped_line;use crate::wrapping::RtOptions;use crate::wrapping::word_wrap_line;use ratatui::style::Style;use ratatui::text::Line;use ratatui::text::Span;use unicode_width::UnicodeWidthStr;const FIELD_LEADING_PADDING: usize = 1;const FIELD_GAP: usize = 2;const MIN_VALUE_WIDTH: usize = 3;const MIN_ALIGNED_COMPACT_VALUE_WIDTH: usize = 12;const MIN_ALIGNED_EXPANSIVE_VALUE_WIDTH: usize = 24;const MIN_SCANNABLE_NARRATIVE_WIDTH: usize = 12;const MIN_SCANNABLE_TOKEN_HEAVY_WIDTH: usize = 12;const CRAMPED_EXPANSIVE_CELL_LINES: usize = 4;const CATASTROPHIC_NARRATIVE_CELL_LINES: usize = 7;const STACKED_VALUE_INDENT: usize = 2;/// Switch modes after enough records contain values the grid can no longer/// present in useful chunks or expansive content collapses into tall strips.pub(super) fn should_render_records(    rows: &[Vec<TableCell>],    column_widths: &[usize],    metrics: &[TableColumnMetrics],) -> bool {    if rows.is_empty() {        return false;    }    let affected_rows = rows        .iter()        .filter(|row| {            let contains_fragmented_value =                row.iter()                    .zip(column_widths)                    .zip(metrics)                    .any(|((cell, width), metrics)| {                        let has_fragmented_token = cell                            .plain_text()                            .split_whitespace()                            .any(|token| token.width() > *width);                        match metrics.kind {                            TableColumnKind::Compact => has_fragmented_token,                            TableColumnKind::TokenHeavy => {                                *width < MIN_SCANNABLE_TOKEN_HEAVY_WIDTH && has_fragmented_token                            }                            TableColumnKind::Narrative => false,                        }                    });            contains_fragmented_value || expansive_cells_are_starved(row, column_widths, metrics)        })        .count();    let threshold = if rows.len() == 1 {        1    } else {        2.max(rows.len().div_ceil(3))    };    affected_rows >= threshold}fn expansive_cells_are_starved(    row: &[TableCell],    column_widths: &[usize],    metrics: &[TableColumnMetrics],) -> bool {    let expansive_cells: Vec<(TableColumnKind, usize, usize)> = row        .iter()        .zip(column_widths)        .zip(metrics)        .filter(|&((_cell, _width), metrics)| metrics.kind != TableColumnKind::Compact)        .map(|((cell, width), metrics)| (metrics.kind, *width, wrap_cell(cell, *width).len()))        .collect();    expansive_cells        .iter()        .filter(|(_, _, height)| *height >= CRAMPED_EXPANSIVE_CELL_LINES)        .count()        >= 2        || expansive_cells.iter().any(|(kind, width, height)| {            *kind == TableColumnKind::Narrative                && *width < MIN_SCANNABLE_NARRATIVE_WIDTH                && *height >= CATASTROPHIC_NARRATIVE_CELL_LINES        })}pub(super) fn render_records(    headers: &[TableCell],    rows: &[Vec<TableCell>],    metrics: &[TableColumnMetrics],    available_width: Option<usize>,    label_style: Style,    separator_style: Style,) -> Vec<HyperlinkLine> {    let label_width = headers        .iter()        .map(|header| header.plain_text().width())        .max()        .unwrap_or(0);    let minimum_value_width = if metrics        .iter()        .any(|metrics| metrics.kind != TableColumnKind::Compact)    {        MIN_ALIGNED_EXPANSIVE_VALUE_WIDTH    } else {        MIN_ALIGNED_COMPACT_VALUE_WIDTH    };    let aligned_fields = available_width.is_none_or(|width| {        FIELD_LEADING_PADDING + label_width + FIELD_GAP + minimum_value_width <= width    });    let mut out = Vec::new();    for (row_index, row) in rows.iter().enumerate() {        for (header, value) in headers.iter().zip(row) {            if aligned_fields {                render_aligned_field(                    &mut out,                    header,                    value,                    label_width,                    available_width,                    label_style,                );            } else {                render_stacked_field(&mut out, header, value, available_width, label_style);            }        }        if row_index + 1 < rows.len() {            let width = available_width.unwrap_or_else(|| widest_line_width(&out));            out.push(HyperlinkLine::new(Line::from(Span::styled(                TABLE_BODY_SEPARATOR_CHAR.to_string().repeat(width),                separator_style,            ))));        }    }    out}fn render_aligned_field(    out: &mut Vec<HyperlinkLine>,    header: &TableCell,    value: &TableCell,    label_width: usize,    available_width: Option<usize>,    label_style: Style,) {    let value_indent = FIELD_LEADING_PADDING + label_width + FIELD_GAP;    let value_width = available_width        .map(|width| width.saturating_sub(value_indent).max(MIN_VALUE_WIDTH))        .unwrap_or_else(|| cell_width(value).max(MIN_VALUE_WIDTH));    let wrapped_value = wrap_cell(value, value_width);    for (line_index, value_line) in wrapped_value.into_iter().enumerate() {        let mut spans = Vec::new();        if line_index == 0 {            let label = header.plain_text();            spans.push(Span::raw(" ".repeat(FIELD_LEADING_PADDING)));            spans.push(Span::styled(label.clone(), label_style));            spans.push(Span::raw(                " ".repeat(label_width.saturating_sub(label.width()) + FIELD_GAP),            ));        } else {            spans.push(Span::raw(" ".repeat(value_indent)));        }        push_prefixed_value_line(out, spans, value_line);    }}fn render_stacked_field(    out: &mut Vec<HyperlinkLine>,    header: &TableCell,    value: &TableCell,    available_width: Option<usize>,    label_style: Style,) {    let label_width = available_width        .map(|width| width.saturating_sub(FIELD_LEADING_PADDING).max(1))        .unwrap_or_else(|| header.plain_text().width().max(1));    let label = Line::from(Span::styled(header.plain_text(), label_style));    let mut wrapped_labels = Vec::new();    push_owned_lines(        &word_wrap_line(&label, RtOptions::new(label_width)),        &mut wrapped_labels,    );    for label_line in wrapped_labels {        let mut spans = vec![Span::raw(" ".repeat(FIELD_LEADING_PADDING))];        spans.extend(label_line.spans);        out.push(HyperlinkLine::new(Line::from(spans)));    }    let value_width = available_width        .map(|width| width.saturating_sub(STACKED_VALUE_INDENT).max(1))        .unwrap_or_else(|| cell_width(value).max(1));    for value_line in wrap_cell(value, value_width) {        push_prefixed_value_line(            out,            vec![Span::raw(" ".repeat(STACKED_VALUE_INDENT))],            value_line,        );    }}fn push_prefixed_value_line(    out: &mut Vec<HyperlinkLine>,    mut prefix: Vec<Span<'static>>,    mut value_line: HyperlinkLine,) {    let shift = prefix        .iter()        .map(|span| span.content.width())        .sum::<usize>();    prefix.append(&mut value_line.line.spans);    let mut output_line = HyperlinkLine::new(Line::from(prefix));    output_line        .hyperlinks        .extend(value_line.hyperlinks.into_iter().map(|mut link| {            link.columns = link.columns.start + shift..link.columns.end + shift;            link        }));    out.push(output_line);}fn wrap_cell(cell: &TableCell, width: usize) -> Vec<HyperlinkLine> {    if cell.lines.is_empty() {        return vec![HyperlinkLine::new(Line::default())];    }    let mut wrapped = Vec::new();    for source_line in &cell.lines {        let rendered = word_wrap_line(&source_line.line, RtOptions::new(width.max(1)))            .into_iter()            .map(|line| line_to_static(&line))            .collect::<Vec<_>>();        if rendered.is_empty() {            wrapped.push(HyperlinkLine::new(Line::default()));        } else {            wrapped.extend(remap_wrapped_line(source_line, rendered));        }    }    if wrapped.is_empty() {        wrapped.push(HyperlinkLine::new(Line::default()));    }    wrapped}fn cell_width(cell: &TableCell) -> usize {    cell.lines        .iter()        .map(|line| {            line.line                .spans                .iter()                .map(|span| span.content.width())                .sum::<usize>()        })        .max()        .unwrap_or(0)}fn widest_line_width(lines: &[HyperlinkLine]) -> usize {    lines        .iter()        .map(|line| {            line.line                .spans                .iter()                .map(|span| span.content.width())                .sum::<usize>()        })        .max()        .unwrap_or(0)}