From 596f8c5c3c855b78eae3222c5ee0aad3a91f4b43 Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Sun, 27 Sep 2026 19:36:39 +0000 Subject: [PATCH] Match pinned transcript headers to the original prompt style (#48775) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What changed Add the `› ` prefix to pinned prompt headers, using bold red for spoken prompts and bold dim styling for other prompts. Reserve one column when truncating the header. ## Testing Add a rendering test comparing pinned headers with the original prompt rows for both regular and spoken prompts. Update snapshots for the prefix and display-width truncation. GitOrigin-RevId: 89c2d9267374ef8f6504058c12c078025f302fef --- .../tui/src/transcript_view/prompt_header.rs | 12 +++++-- .../transcript_view/prompt_header_tests.rs | 31 +++++++++++++++++++ ...ntrols_and_truncates_by_display_width.snap | 3 +- ..._to_visible_prompts_and_short_screens.snap | 6 ++-- 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/codex-rs/tui/src/transcript_view/prompt_header.rs b/codex-rs/tui/src/transcript_view/prompt_header.rs index 9e60b8e158..b2d6953b97 100644 --- a/codex-rs/tui/src/transcript_view/prompt_header.rs +++ b/codex-rs/tui/src/transcript_view/prompt_header.rs @@ -46,8 +46,16 @@ pub(super) fn line( message }; Some(truncate_line_with_ellipsis_if_overflow( - Line::from(message).style(crate::style::history_prompt_style()), - usize::from(width), + Line::from(vec![ + if prompt.spoken { + "› ".red().bold() + } else { + "› ".bold().dim() + }, + message.into(), + ]) + .style(crate::style::history_prompt_style()), + usize::from(width.saturating_sub(1)), )) } diff --git a/codex-rs/tui/src/transcript_view/prompt_header_tests.rs b/codex-rs/tui/src/transcript_view/prompt_header_tests.rs index 68eaa3f906..3915436844 100644 --- a/codex-rs/tui/src/transcript_view/prompt_header_tests.rs +++ b/codex-rs/tui/src/transcript_view/prompt_header_tests.rs @@ -1,6 +1,7 @@ //! Sticky context follows the visible turn while leaving source text and hit rows intact. use super::*; +use crate::history_cell::new_spoken_user_prompt; use crate::history_cell::new_user_prompt; use crate::transcript_view::tests::cell; use crate::transcript_view::tests::render; @@ -84,6 +85,36 @@ fn header_sanitizes_controls_and_truncates_by_display_width() { insta::assert_snapshot!(line.to_string()); } +#[test] +fn pinned_prompt_matches_the_original_prompt_style() { + for prompt in [ + new_user_prompt("keep going".into(), Vec::new(), Vec::new(), Vec::new()), + new_spoken_user_prompt("keep going".into()), + ] { + let width = 30; + let mut expected = Buffer::empty(Rect::new( + /*x*/ 0, /*y*/ 0, width, /*height*/ 3, + )); + TextLayout::new(prompt.transcript_hyperlink_lines(width), width).render( + expected.area, + &mut expected, + /*start_row*/ 0, + ); + let cells: Vec> = vec![ + Arc::new(prompt), + cell("one\ntwo\nthree\nfour\nfive\nsix\nseven\neight"), + ]; + let mut view = TranscriptView::default(); + let actual = render(&mut view, &cells, width, /*height*/ 7); + + assert_eq!( + &actual.content[..usize::from(width)], + &expected.content[usize::from(width)..usize::from(width * 2)] + ); + assert_eq!(view.area.y, 1); + } +} + #[test] fn mouse_selection_preserves_header_reservation_at_turn_boundaries() { let cells = vec![ diff --git a/codex-rs/tui/src/transcript_view/snapshots/codex_tui__transcript_view__prompt_header__tests__header_sanitizes_controls_and_truncates_by_display_width.snap b/codex-rs/tui/src/transcript_view/snapshots/codex_tui__transcript_view__prompt_header__tests__header_sanitizes_controls_and_truncates_by_display_width.snap index a0a5c35f7d..f4246a03cd 100644 --- a/codex-rs/tui/src/transcript_view/snapshots/codex_tui__transcript_view__prompt_header__tests__header_sanitizes_controls_and_truncates_by_display_width.snap +++ b/codex-rs/tui/src/transcript_view/snapshots/codex_tui__transcript_view__prompt_header__tests__header_sanitizes_controls_and_truncates_by_display_width.snap @@ -1,6 +1,5 @@ --- source: tui/src/transcript_view/prompt_header_tests.rs -assertion_line: 76 expression: line.to_string() --- -界 café next ques… +› 界 café next q… diff --git a/codex-rs/tui/src/transcript_view/snapshots/codex_tui__transcript_view__prompt_header__tests__prompt_header_tracks_reading_and_yields_to_visible_prompts_and_short_screens.snap b/codex-rs/tui/src/transcript_view/snapshots/codex_tui__transcript_view__prompt_header__tests__prompt_header_tracks_reading_and_yields_to_visible_prompts_and_short_screens.snap index d96fd4221a..12a29bfec8 100644 --- a/codex-rs/tui/src/transcript_view/snapshots/codex_tui__transcript_view__prompt_header__tests__prompt_header_tracks_reading_and_yields_to_visible_prompts_and_short_screens.snap +++ b/codex-rs/tui/src/transcript_view/snapshots/codex_tui__transcript_view__prompt_header__tests__prompt_header_tracks_reading_and_yields_to_visible_prompts_and_short_screens.snap @@ -4,21 +4,21 @@ assertion_line: 68 expression: "snapshots.join(\"\\n\\n\")" --- Latest -Second café question +› Second café question seven eight nine ten Earlier answer -First question +› First question one two three four After prepend -First question +› First question one two three