Skip to content

Commit 12fd2b4

Browse files
authored
[TUI] Remove bottom padding (#4854)
We don't need the bottom padding. It currently just makes the footer look off-centered. Before: <img width="1905" height="478" alt="image" src="https://github.com/user-attachments/assets/c2a18b38-b8fd-4317-bbbb-2843bca02ba1" /> After: <img width="617" height="479" alt="image" src="https://github.com/user-attachments/assets/f42470c5-4b24-4a02-b15c-e2aad03e3b42" />
1 parent f255542 commit 12fd2b4

10 files changed

+66
-64
lines changed

codex-rs/tui/src/bottom_pane/mod.rs

Lines changed: 34 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ pub(crate) struct BottomPaneParams {
8181
}
8282

8383
impl BottomPane {
84-
const BOTTOM_PAD_LINES: u16 = 1;
84+
const BOTTOM_PAD_LINES: u16 = 0;
8585
pub fn new(params: BottomPaneParams) -> Self {
8686
let enhanced_keys_supported = params.enhanced_keys_supported;
8787
Self {
@@ -522,10 +522,29 @@ impl WidgetRef for &BottomPane {
522522
mod tests {
523523
use super::*;
524524
use crate::app_event::AppEvent;
525+
use insta::assert_snapshot;
525526
use ratatui::buffer::Buffer;
526527
use ratatui::layout::Rect;
527528
use tokio::sync::mpsc::unbounded_channel;
528529

530+
fn snapshot_buffer(buf: &Buffer) -> String {
531+
let mut lines = Vec::new();
532+
for y in 0..buf.area().height {
533+
let mut row = String::new();
534+
for x in 0..buf.area().width {
535+
row.push(buf[(x, y)].symbol().chars().next().unwrap_or(' '));
536+
}
537+
lines.push(row);
538+
}
539+
lines.join("\n")
540+
}
541+
542+
fn render_snapshot(pane: &BottomPane, area: Rect) -> String {
543+
let mut buf = Buffer::empty(area);
544+
(&pane).render_ref(area, &mut buf);
545+
snapshot_buffer(&buf)
546+
}
547+
529548
fn exec_request() -> ApprovalRequest {
530549
ApprovalRequest::Exec {
531550
id: "1".to_string(),
@@ -685,7 +704,7 @@ mod tests {
685704
}
686705

687706
#[test]
688-
fn bottom_padding_present_with_status_above_composer() {
707+
fn status_and_composer_fill_height_without_bottom_padding() {
689708
let (tx_raw, _rx) = unbounded_channel::<AppEvent>();
690709
let tx = AppEventSender::new(tx_raw);
691710
let mut pane = BottomPane::new(BottomPaneParams {
@@ -700,43 +719,21 @@ mod tests {
700719
// Activate spinner (status view replaces composer) with no live ring.
701720
pane.set_task_running(true);
702721

703-
// Use height == desired_height; expect 1 status row at top and 2 bottom padding rows.
722+
// Use height == desired_height; expect spacer + status + composer rows without trailing padding.
704723
let height = pane.desired_height(30);
705724
assert!(
706725
height >= 3,
707-
"expected at least 3 rows with bottom padding; got {height}"
726+
"expected at least 3 rows to render spacer, status, and composer; got {height}"
708727
);
709728
let area = Rect::new(0, 0, 30, height);
710-
let mut buf = Buffer::empty(area);
711-
(&pane).render_ref(area, &mut buf);
712-
713-
// Row 1 contains the status header (row 0 is the spacer)
714-
let mut top = String::new();
715-
for x in 0..area.width {
716-
top.push(buf[(x, 1)].symbol().chars().next().unwrap_or(' '));
717-
}
718-
assert!(
719-
top.trim_start().starts_with("• Working"),
720-
"expected top row to start with '• Working': {top:?}"
721-
);
722-
assert!(
723-
top.contains("Working"),
724-
"expected Working header on top row: {top:?}"
725-
);
726-
727-
// Last row should be blank padding; the row above should generally contain composer content.
728-
let mut r_last = String::new();
729-
for x in 0..area.width {
730-
r_last.push(buf[(x, height - 1)].symbol().chars().next().unwrap_or(' '));
731-
}
732-
assert!(
733-
r_last.trim().is_empty(),
734-
"expected last row blank: {r_last:?}"
729+
assert_snapshot!(
730+
"status_and_composer_fill_height_without_bottom_padding",
731+
render_snapshot(&pane, area)
735732
);
736733
}
737734

738735
#[test]
739-
fn bottom_padding_shrinks_when_tiny() {
736+
fn status_hidden_when_height_too_small() {
740737
let (tx_raw, _rx) = unbounded_channel::<AppEvent>();
741738
let tx = AppEventSender::new(tx_raw);
742739
let mut pane = BottomPane::new(BottomPaneParams {
@@ -750,37 +747,18 @@ mod tests {
750747

751748
pane.set_task_running(true);
752749

753-
// Height=2 → status on one row, composer on the other.
750+
// Height=2 → composer takes the full space; status collapses when there is no room.
754751
let area2 = Rect::new(0, 0, 20, 2);
755-
let mut buf2 = Buffer::empty(area2);
756-
(&pane).render_ref(area2, &mut buf2);
757-
let mut row0 = String::new();
758-
let mut row1 = String::new();
759-
for x in 0..area2.width {
760-
row0.push(buf2[(x, 0)].symbol().chars().next().unwrap_or(' '));
761-
row1.push(buf2[(x, 1)].symbol().chars().next().unwrap_or(' '));
762-
}
763-
let has_composer = row0.contains("Ask Codex") || row1.contains("Ask Codex");
764-
assert!(
765-
has_composer,
766-
"expected composer to be visible on one of the rows: row0={row0:?}, row1={row1:?}"
767-
);
768-
assert!(
769-
row0.contains("Working") || row1.contains("Working"),
770-
"expected status header to be visible at height=2: row0={row0:?}, row1={row1:?}"
752+
assert_snapshot!(
753+
"status_hidden_when_height_too_small_height_2",
754+
render_snapshot(&pane, area2)
771755
);
772756

773757
// Height=1 → no padding; single row is the composer (status hidden).
774758
let area1 = Rect::new(0, 0, 20, 1);
775-
let mut buf1 = Buffer::empty(area1);
776-
(&pane).render_ref(area1, &mut buf1);
777-
let mut only = String::new();
778-
for x in 0..area1.width {
779-
only.push(buf1[(x, 0)].symbol().chars().next().unwrap_or(' '));
780-
}
781-
assert!(
782-
only.contains("Ask Codex"),
783-
"expected composer with no padding: {only:?}"
759+
assert_snapshot!(
760+
"status_hidden_when_height_too_small_height_1",
761+
render_snapshot(&pane, area1)
784762
);
785763
}
786764
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
source: tui/src/bottom_pane/mod.rs
3+
expression: "render_snapshot(&pane, area)"
4+
---
5+
6+
Working (0sesc to interru
7+
8+
9+
Ask Codex to do anything
10+
11+
? for shortcuts
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
source: tui/src/bottom_pane/mod.rs
3+
expression: "render_snapshot(&pane, area1)"
4+
---
5+
Ask Codex to do an
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
source: tui/src/bottom_pane/mod.rs
3+
expression: "render_snapshot(&pane, area2)"
4+
---
5+
6+
Ask Codex to do an
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
---
22
source: tui/src/chatwidget/tests.rs
3+
assertion_line: 1470
34
expression: terminal.backend()
45
---
56
" "
6-
"› Ask Codex to do anything "
77
" "
8+
"› Ask Codex to do anything "
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
source: tui/src/chatwidget/tests.rs
3+
assertion_line: 1500
34
expression: terminal.backend()
45
---
5-
"• Thinking (0s • esc to interrupt) "
6+
" "
67
"› Ask Codex to do anything "

codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__chat_small_running_h3.snap

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
---
22
source: tui/src/chatwidget/tests.rs
3+
assertion_line: 1500
34
expression: terminal.backend()
45
---
56
" "
7+
"• Thinking (0s • esc to interrupt) "
68
"› Ask Codex to do anything "
7-
" "

codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__exec_approval_modal_exec.snap

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
---
22
source: tui/src/chatwidget/tests.rs
3+
assertion_line: 409
34
expression: "format!(\"{buf:?}\")"
45
---
56
Buffer {
6-
area: Rect { x: 0, y: 0, width: 80, height: 15 },
7+
area: Rect { x: 0, y: 0, width: 80, height: 14 },
78
content: [
89
" ",
910
" ",
@@ -19,7 +20,6 @@ Buffer {
1920
" 3. No, and tell Codex what to do differently esc ",
2021
" ",
2122
" Press enter to confirm or esc to cancel ",
22-
" ",
2323
],
2424
styles: [
2525
x: 0, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
@@ -34,6 +34,5 @@ Buffer {
3434
x: 47, y: 11, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
3535
x: 50, y: 11, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
3636
x: 2, y: 13, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
37-
x: 0, y: 14, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
3837
]
3938
}

codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_widget_active.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
source: tui/src/chatwidget/tests.rs
3+
assertion_line: 1577
34
expression: terminal.backend()
45
---
56
" "
@@ -9,4 +10,3 @@ expression: terminal.backend()
910
"› Ask Codex to do anything "
1011
" "
1112
" ? for shortcuts "
12-
" "

codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_widget_and_approval_modal.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
source: tui/src/chatwidget/tests.rs
3+
assertion_line: 1548
34
expression: terminal.backend()
45
---
56
" "
@@ -16,4 +17,3 @@ expression: terminal.backend()
1617
" 3. No, and tell Codex what to do differently esc "
1718
" "
1819
" Press enter to confirm or esc to cancel "
19-
" "

0 commit comments

Comments
 (0)