Files
codex/codex-rs/tui2/docs/streaming_wrapping_design.md
Josh McKinney a40bb0af20 docs(tui2): document viewport/history architecture
- Add architecture/roadmap doc + running notes for the TUI2 transcript-owned
  viewport/history work (PR index, module map, gaps, roadmap).
- Add tester-facing guide for validation and triage (scroll, selection/copy,
  streaming reflow, overlays, exit printing, perf).
- Keep earlier design docs intact but add links to the new docs; align tables.

Docs in this change were automatically created by codex (gpt-5.2 xhigh).
2026-01-05 13:33:39 -08:00

4.4 KiB
Raw Blame History

Streaming Markdown Wrapping & Animation TUI2 Notes

Note: This doc is historical. For the current architecture/status/roadmap, see tui2/docs/tui2_viewport_history_architecture.md.

This document mirrors the original tui/streaming_wrapping_design.md and captures how the same concerns apply to the new tui2 crate. It exists so that future viewport and streaming work in TUI2 can rely on the same context without having to crossreference the legacy TUI implementation.

At a high level, the design constraints are the same:

  • Streaming agent responses are rendered incrementally, with an animation loop that reveals content over time.
  • Nonstreaming history cells are rendered widthagnostically and wrapped only at display time, so they reflow correctly when the terminal is resized.
  • Streaming content should eventually follow the same “wrap on display” model so the transcript reflows consistently across width changes, without regressing animation or markdown semantics.

1. Where streaming is implemented in TUI2

TUI2 keeps the streaming pipeline conceptually aligned with the legacy TUI but in a separate crate:

  • tui2/src/markdown_stream.rs implements the markdown streaming collector and animation controller for agent deltas.
  • tui2/src/chatwidget.rs integrates streamed content into the transcript via HistoryCell implementations.
  • tui2/src/history_cell.rs provides the concrete history cell types used by the inline transcript and overlays.
  • tui2/src/wrapping.rs contains the shared text wrapping utilities used by both streaming and nonstreaming render paths:
    • RtOptions describes viewportaware wrapping (width, indents, algorithm).
    • word_wrap_line, word_wrap_lines, and word_wrap_lines_borrowed provide spanaware wrapping that preserves markdown styling and emoji width.

As in the original TUI, the key tension is between:

  • Prewrapping streamed content at commit time (simpler animation, but bakedin splits that dont reflow), and
  • Deferring wrapping to render time (better reflow, but requires a more sophisticated streaming cell model or recomputation on each frame).

2. Current behavior and limitations

TUI2 is intentionally conservative for now:

  • Streaming responses use the same markdown streaming and wrapping utilities as the legacy TUI, with width decisions made near the streaming collector.
  • The transcript viewport (App::render_transcript_cells in tui2/src/app.rs) always uses word_wrap_lines_borrowed against the current Rect width, so:
    • Nonstreaming cells reflow naturally on resize.
    • Streamed cells respect whatever wrapping was applied when their lines were constructed, and may not fully “unwrap” if that work happened at a fixed width earlier in the pipeline.

This means TUI2 shares the same fundamental limitation documented in the original design note: streamed paragraphs can retain historical wrap decisions made at the time they were streamed, even if the viewport later grows wider.

3. Design directions (forwardlooking)

The options outlined in the legacy document apply here as well:

  1. Keep the current behavior but clarify tests and documentation.
    • Ensure tests in tui2/src/markdown_stream.rs, tui2/src/markdown_render.rs, tui2/src/history_cell.rs, and tui2/src/wrapping.rs encode the current expectations around streaming, wrapping, and emoji / markdown styling.
  2. Move towards widthagnostic streaming cells.
    • Introduce a dedicated streaming history cell that stores the raw markdown buffer and lets HistoryCell::display_lines(width) perform both markdown rendering and wrapping based on the current viewport width.
    • Keep the commit animation logic expressed in terms of “logical” positions (e.g., number of tokens or lines committed) rather than prewrapped visual lines at a fixed width.
  3. Hybrid “visual line count” model.
    • Track committed visual lines as a scalar and rerender the streamed prefix at the current width, revealing only the first N visual lines on each animation tick.

TUI2 does not yet implement these refactors; it intentionally stays close to the legacy behavior while the viewport work (scrolling, selection, exit transcripts) is being ported. This document exists to make that tradeoff explicit for TUI2 and to provide a natural home for any TUI2specific streaming wrapping notes as the design evolves.