From 64678f895ac2ca0e625f11259078a16a21091ad7 Mon Sep 17 00:00:00 2001 From: charley-oai Date: Tue, 20 Jan 2026 14:54:49 -0800 Subject: [PATCH] Improve UI spacing for queued messages (#9162) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Despite good spacing between queued messages and assistant message text: Screenshot 2026-01-12 at 4 54 50 PM Codex has confusing spacing between queued messages and shimmering status text (making the queued message seem like a sub-item of the shimmering status text) Screenshot 2026-01-12 at 4 54 18 PM This PR changes the spacing between the queued message(s) and shimmering status text to make it less confusing: Screenshot 2026-01-13 at 11 20 36 AM While working on the status/queued spacing change, we noticed two paste‑burst tests were timing‑sensitive and could fail on slower CI. We added a small test‑only helper to keep the paste‑burst state active and refreshed during these tests. This removes dependence on tight timing and makes the tests deterministic without affecting runtime behavior. --- codex-rs/tui/src/bottom_pane/mod.rs | 65 +++++++++++++++++-- ...s_visible_when_status_hidden_snapshot.snap | 1 - ...__status_and_queued_messages_snapshot.snap | 2 +- ...tom_pane__tests__status_only_snapshot.snap | 10 +++ ..._details_and_queued_messages_snapshot.snap | 14 ++++ ...i__chatwidget__tests__chatwidget_tall.snap | 3 +- ..._review_queues_user_messages_snapshot.snap | 3 +- codex-rs/tui2/src/bottom_pane/mod.rs | 61 ++++++++++++++++- ...s_visible_when_status_hidden_snapshot.snap | 1 - ...__status_and_queued_messages_snapshot.snap | 2 +- ...tom_pane__tests__status_only_snapshot.snap | 10 +++ ..._details_and_queued_messages_snapshot.snap | 14 ++++ ...2__chatwidget__tests__chatwidget_tall.snap | 3 +- 13 files changed, 176 insertions(+), 13 deletions(-) create mode 100644 codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__tests__status_only_snapshot.snap create mode 100644 codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__tests__status_with_details_and_queued_messages_snapshot.snap create mode 100644 codex-rs/tui2/src/bottom_pane/snapshots/codex_tui2__bottom_pane__tests__status_only_snapshot.snap create mode 100644 codex-rs/tui2/src/bottom_pane/snapshots/codex_tui2__bottom_pane__tests__status_with_details_and_queued_messages_snapshot.snap diff --git a/codex-rs/tui/src/bottom_pane/mod.rs b/codex-rs/tui/src/bottom_pane/mod.rs index ee23cad33..305754419 100644 --- a/codex-rs/tui/src/bottom_pane/mod.rs +++ b/codex-rs/tui/src/bottom_pane/mod.rs @@ -701,11 +701,14 @@ impl BottomPane { if !self.unified_exec_footer.is_empty() { flex.push(0, RenderableItem::Borrowed(&self.unified_exec_footer)); } + let has_queued_messages = !self.queued_user_messages.messages.is_empty(); + let has_status_or_footer = + self.status.is_some() || !self.unified_exec_footer.is_empty(); + if has_queued_messages && has_status_or_footer { + flex.push(0, RenderableItem::Owned("".into())); + } flex.push(1, RenderableItem::Borrowed(&self.queued_user_messages)); - if self.status.is_some() - || !self.unified_exec_footer.is_empty() - || !self.queued_user_messages.messages.is_empty() - { + if !has_queued_messages && has_status_or_footer { flex.push(0, RenderableItem::Owned("".into())); } let mut flex2 = FlexRenderable::new(); @@ -951,6 +954,60 @@ mod tests { ); } + #[test] + fn status_only_snapshot() { + let (tx_raw, _rx) = unbounded_channel::(); + let tx = AppEventSender::new(tx_raw); + let mut pane = BottomPane::new(BottomPaneParams { + app_event_tx: tx, + frame_requester: FrameRequester::test_dummy(), + has_input_focus: true, + enhanced_keys_supported: false, + placeholder_text: "Ask Codex to do anything".to_string(), + disable_paste_burst: false, + animations_enabled: true, + skills: Some(Vec::new()), + }); + + pane.set_task_running(true); + + let width = 48; + let height = pane.desired_height(width); + let area = Rect::new(0, 0, width, height); + assert_snapshot!("status_only_snapshot", render_snapshot(&pane, area)); + } + + #[test] + fn status_with_details_and_queued_messages_snapshot() { + let (tx_raw, _rx) = unbounded_channel::(); + let tx = AppEventSender::new(tx_raw); + let mut pane = BottomPane::new(BottomPaneParams { + app_event_tx: tx, + frame_requester: FrameRequester::test_dummy(), + has_input_focus: true, + enhanced_keys_supported: false, + placeholder_text: "Ask Codex to do anything".to_string(), + disable_paste_burst: false, + animations_enabled: true, + skills: Some(Vec::new()), + }); + + pane.set_task_running(true); + pane.update_status( + "Working".to_string(), + Some("First detail line\nSecond detail line".to_string()), + ); + pane.set_queued_user_messages(vec!["Queued follow-up question".to_string()]); + + let width = 48; + let height = pane.desired_height(width); + let area = Rect::new(0, 0, width, height); + assert_snapshot!( + "status_with_details_and_queued_messages_snapshot", + render_snapshot(&pane, area) + ); + } + #[test] fn queued_messages_visible_when_status_hidden_snapshot() { let (tx_raw, _rx) = unbounded_channel::(); diff --git a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__tests__queued_messages_visible_when_status_hidden_snapshot.snap b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__tests__queued_messages_visible_when_status_hidden_snapshot.snap index 123a5eb3a..5aea41519 100644 --- a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__tests__queued_messages_visible_when_status_hidden_snapshot.snap +++ b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__tests__queued_messages_visible_when_status_hidden_snapshot.snap @@ -5,7 +5,6 @@ expression: "render_snapshot(&pane, area)" ↳ Queued follow-up question ⌥ + ↑ edit - › Ask Codex to do anything 100% context left · ? for shortcuts diff --git a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__tests__status_and_queued_messages_snapshot.snap b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__tests__status_and_queued_messages_snapshot.snap index 27df671e4..e651ec927 100644 --- a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__tests__status_and_queued_messages_snapshot.snap +++ b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__tests__status_and_queued_messages_snapshot.snap @@ -3,10 +3,10 @@ source: tui/src/bottom_pane/mod.rs expression: "render_snapshot(&pane, area)" --- • Working (0s • esc to interrupt) + ↳ Queued follow-up question ⌥ + ↑ edit - › Ask Codex to do anything 100% context left · ? for shortcuts diff --git a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__tests__status_only_snapshot.snap b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__tests__status_only_snapshot.snap new file mode 100644 index 000000000..79e1e126e --- /dev/null +++ b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__tests__status_only_snapshot.snap @@ -0,0 +1,10 @@ +--- +source: tui/src/bottom_pane/mod.rs +expression: "render_snapshot(&pane, area)" +--- +• Working (0s • esc to interrupt) + + +› Ask Codex to do anything + + 100% context left · ? for shortcuts diff --git a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__tests__status_with_details_and_queued_messages_snapshot.snap b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__tests__status_with_details_and_queued_messages_snapshot.snap new file mode 100644 index 000000000..12090d09e --- /dev/null +++ b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__tests__status_with_details_and_queued_messages_snapshot.snap @@ -0,0 +1,14 @@ +--- +source: tui/src/bottom_pane/mod.rs +expression: "render_snapshot(&pane, area)" +--- +• Working (0s • esc to interrupt) + └ First detail line + Second detail line + + ↳ Queued follow-up question + ⌥ + ↑ edit + +› Ask Codex to do anything + + 100% context left · ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__chatwidget_tall.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__chatwidget_tall.snap index 6d9aa515b..64361e90f 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__chatwidget_tall.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__chatwidget_tall.snap @@ -2,7 +2,9 @@ source: tui/src/chatwidget/tests.rs expression: term.backend().vt100().screen().contents() --- + • Working (0s • esc to interrupt) + ↳ Hello, world! 0 ↳ Hello, world! 1 ↳ Hello, world! 2 @@ -21,7 +23,6 @@ expression: term.backend().vt100().screen().contents() ↳ Hello, world! 15 ↳ Hello, world! 16 - › Ask Codex to do anything 100% context left · ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__review_queues_user_messages_snapshot.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__review_queues_user_messages_snapshot.snap index 2a7717df7..1c02350a6 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__review_queues_user_messages_snapshot.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__review_queues_user_messages_snapshot.snap @@ -1,6 +1,5 @@ --- source: tui/src/chatwidget/tests.rs -assertion_line: 3840 expression: term.backend().vt100().screen().contents() --- @@ -14,10 +13,10 @@ expression: term.backend().vt100().screen().contents() • Working (0s • esc to interrupt) + ↳ Queued while /review is running. ⌥ + ↑ edit - › Ask Codex to do anything 100% context left · ? for shortcuts diff --git a/codex-rs/tui2/src/bottom_pane/mod.rs b/codex-rs/tui2/src/bottom_pane/mod.rs index 83764d55b..4fa0ae5fe 100644 --- a/codex-rs/tui2/src/bottom_pane/mod.rs +++ b/codex-rs/tui2/src/bottom_pane/mod.rs @@ -688,8 +688,13 @@ impl BottomPane { if let Some(status) = &self.status { flex.push(0, RenderableItem::Borrowed(status)); } + let has_queued_messages = !self.queued_user_messages.messages.is_empty(); + let has_status = self.status.is_some(); + if has_queued_messages && has_status { + flex.push(0, RenderableItem::Owned("".into())); + } flex.push(1, RenderableItem::Borrowed(&self.queued_user_messages)); - if self.status.is_some() || !self.queued_user_messages.messages.is_empty() { + if !has_queued_messages && has_status { flex.push(0, RenderableItem::Owned("".into())); } let mut flex2 = FlexRenderable::new(); @@ -931,6 +936,60 @@ mod tests { ); } + #[test] + fn status_only_snapshot() { + let (tx_raw, _rx) = unbounded_channel::(); + let tx = AppEventSender::new(tx_raw); + let mut pane = BottomPane::new(BottomPaneParams { + app_event_tx: tx, + frame_requester: FrameRequester::test_dummy(), + has_input_focus: true, + enhanced_keys_supported: false, + placeholder_text: "Ask Codex to do anything".to_string(), + disable_paste_burst: false, + animations_enabled: true, + skills: Some(Vec::new()), + }); + + pane.set_task_running(true); + + let width = 48; + let height = pane.desired_height(width); + let area = Rect::new(0, 0, width, height); + assert_snapshot!("status_only_snapshot", render_snapshot(&pane, area)); + } + + #[test] + fn status_with_details_and_queued_messages_snapshot() { + let (tx_raw, _rx) = unbounded_channel::(); + let tx = AppEventSender::new(tx_raw); + let mut pane = BottomPane::new(BottomPaneParams { + app_event_tx: tx, + frame_requester: FrameRequester::test_dummy(), + has_input_focus: true, + enhanced_keys_supported: false, + placeholder_text: "Ask Codex to do anything".to_string(), + disable_paste_burst: false, + animations_enabled: true, + skills: Some(Vec::new()), + }); + + pane.set_task_running(true); + pane.update_status( + "Working".to_string(), + Some("First detail line\nSecond detail line".to_string()), + ); + pane.set_queued_user_messages(vec!["Queued follow-up question".to_string()]); + + let width = 48; + let height = pane.desired_height(width); + let area = Rect::new(0, 0, width, height); + assert_snapshot!( + "status_with_details_and_queued_messages_snapshot", + render_snapshot(&pane, area) + ); + } + #[test] fn queued_messages_visible_when_status_hidden_snapshot() { let (tx_raw, _rx) = unbounded_channel::(); diff --git a/codex-rs/tui2/src/bottom_pane/snapshots/codex_tui2__bottom_pane__tests__queued_messages_visible_when_status_hidden_snapshot.snap b/codex-rs/tui2/src/bottom_pane/snapshots/codex_tui2__bottom_pane__tests__queued_messages_visible_when_status_hidden_snapshot.snap index 71504561d..efc74d42b 100644 --- a/codex-rs/tui2/src/bottom_pane/snapshots/codex_tui2__bottom_pane__tests__queued_messages_visible_when_status_hidden_snapshot.snap +++ b/codex-rs/tui2/src/bottom_pane/snapshots/codex_tui2__bottom_pane__tests__queued_messages_visible_when_status_hidden_snapshot.snap @@ -5,7 +5,6 @@ expression: "render_snapshot(&pane, area)" ↳ Queued follow-up question ⌥ + ↑ edit - › Ask Codex to do anything 100% context left · ? for shortcuts diff --git a/codex-rs/tui2/src/bottom_pane/snapshots/codex_tui2__bottom_pane__tests__status_and_queued_messages_snapshot.snap b/codex-rs/tui2/src/bottom_pane/snapshots/codex_tui2__bottom_pane__tests__status_and_queued_messages_snapshot.snap index 6ac429683..cdea8a17d 100644 --- a/codex-rs/tui2/src/bottom_pane/snapshots/codex_tui2__bottom_pane__tests__status_and_queued_messages_snapshot.snap +++ b/codex-rs/tui2/src/bottom_pane/snapshots/codex_tui2__bottom_pane__tests__status_and_queued_messages_snapshot.snap @@ -3,10 +3,10 @@ source: tui2/src/bottom_pane/mod.rs expression: "render_snapshot(&pane, area)" --- • Working (0s • esc to interrupt) + ↳ Queued follow-up question ⌥ + ↑ edit - › Ask Codex to do anything 100% context left · ? for shortcuts diff --git a/codex-rs/tui2/src/bottom_pane/snapshots/codex_tui2__bottom_pane__tests__status_only_snapshot.snap b/codex-rs/tui2/src/bottom_pane/snapshots/codex_tui2__bottom_pane__tests__status_only_snapshot.snap new file mode 100644 index 000000000..3b53b4d86 --- /dev/null +++ b/codex-rs/tui2/src/bottom_pane/snapshots/codex_tui2__bottom_pane__tests__status_only_snapshot.snap @@ -0,0 +1,10 @@ +--- +source: tui2/src/bottom_pane/mod.rs +expression: "render_snapshot(&pane, area)" +--- +• Working (0s • esc to interrupt) + + +› Ask Codex to do anything + + 100% context left · ? for shortcuts diff --git a/codex-rs/tui2/src/bottom_pane/snapshots/codex_tui2__bottom_pane__tests__status_with_details_and_queued_messages_snapshot.snap b/codex-rs/tui2/src/bottom_pane/snapshots/codex_tui2__bottom_pane__tests__status_with_details_and_queued_messages_snapshot.snap new file mode 100644 index 000000000..51236bb69 --- /dev/null +++ b/codex-rs/tui2/src/bottom_pane/snapshots/codex_tui2__bottom_pane__tests__status_with_details_and_queued_messages_snapshot.snap @@ -0,0 +1,14 @@ +--- +source: tui2/src/bottom_pane/mod.rs +expression: "render_snapshot(&pane, area)" +--- +• Working (0s • esc to interrupt) + └ First detail line + Second detail line + + ↳ Queued follow-up question + ⌥ + ↑ edit + +› Ask Codex to do anything + + 100% context left · ? for shortcuts diff --git a/codex-rs/tui2/src/chatwidget/snapshots/codex_tui2__chatwidget__tests__chatwidget_tall.snap b/codex-rs/tui2/src/chatwidget/snapshots/codex_tui2__chatwidget__tests__chatwidget_tall.snap index 3cc0b593d..57a590c46 100644 --- a/codex-rs/tui2/src/chatwidget/snapshots/codex_tui2__chatwidget__tests__chatwidget_tall.snap +++ b/codex-rs/tui2/src/chatwidget/snapshots/codex_tui2__chatwidget__tests__chatwidget_tall.snap @@ -2,7 +2,9 @@ source: tui2/src/chatwidget/tests.rs expression: term.backend().vt100().screen().contents() --- + • Working (0s • esc to interrupt) + ↳ Hello, world! 0 ↳ Hello, world! 1 ↳ Hello, world! 2 @@ -21,7 +23,6 @@ expression: term.backend().vt100().screen().contents() ↳ Hello, world! 15 ↳ Hello, world! 16 - › Ask Codex to do anything 100% context left · ? for shortcuts