feat(tui2): improve transcript copy fidelity #8469
Draft
+1,990
−995
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.

Title:
feat(tui2): improve transcript copy fidelityThis PR improves transcript selection → clipboard output in TUI2 so copied text matches user intent rather than the current viewport layout.
Note
streaming output still bakes in newlines during the stream — see
streaming_wrapping_design.mdfor more details on fixing this.What changes for users
Design notes (what’s different vs tui)
codex-tuilargely deals with terminal-native selection/copy and only needsHistoryCell::transcript_lines(...).codex-tui2implements app-driven selection/copy that can span off-screen content and soft-wrap boundaries, so we need extra metadata to preserve intent across reflow/scroll.Implementation overview
Joiner plumbing (soft-wrap fidelity)
codex-rs/tui2/src/history_cell.rsTranscriptLinesWithJoiners { lines, joiner_before }+HistoryCell::transcript_lines_with_joiners(...).joiner_before[i]isSome(joiner)when lineiis a soft-wrap continuation and copy should insertjoinerinstead of;Noneindicates a hard break.codex-rs/tui2/src/wrapping.rsword_wrap_line_with_joiners/word_wrap_lines_with_joiners.word_wrap_linedelegates toword_wrap_line_with_joiners(single source of truth).Transcript rendering split
codex-rs/tui2/src/transcript_render.rsTranscriptLineMeta, spacer rows, and joiners.render_lines_to_ansi) out ofapp.rs.Clipboard reconstruction
codex-rs/tui2/src/transcript_copy.rsCopy UX separation
codex-rs/tui2/src/transcript_copy_ui.rsANSI emission consistency
codex-rs/tui2/src/insert_history.rsratatui::Color(includingRgb/Indexed) so ANSI output is deterministic acrossimpl Writebackends (used byrender_lines_to_ansiand tests).Markdown rendering style fix (code-in-blockquote)
codex-rs/tui2/src/markdown_render.rsReviewer notes / maintenance hazards
transcript_copy’sis_code_block_line/span_is_inline_codetranscript_render’s preformatted “don’t wrap” predicatelinesandjoiner_beforemust stay aligned;transcript_renderis the source of truth for both.Tests
cargo test -p codex-tui2