From 1ad8ae2579fd9e1db4b549150f5ec9c3905b9900 Mon Sep 17 00:00:00 2001 From: Jeremy Rose <172423086+nornagon-openai@users.noreply.github.com> Date: Fri, 15 Aug 2025 16:25:48 -0400 Subject: [PATCH] color the status letter in apply patch summary (#2337) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Screenshot 2025-08-14 at 8 30 30 PM --- AGENTS.md | 9 +++++++++ codex-rs/tui/src/history_cell.rs | 28 ++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 264b1e04..b2f21c7c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -12,6 +12,15 @@ Before finalizing a change to `codex-rs`, run `just fmt` (in `codex-rs` director 1. Run the test for the specific project that was changed. For example, if changes were made in `codex-rs/tui`, run `cargo test -p codex-tui`. 2. Once those pass, if any changes were made in common, core, or protocol, run the complete test suite with `cargo test --all-features`. +## TUI code conventions + +- Use concise styling helpers from ratatui’s Stylize trait. + - Basic spans: use "text".into() + - Styled spans: use "text".red(), "text".green(), "text".magenta(), "text".dim(), etc. + - Prefer these over constructing styles with `Span::styled` and `Style` directly. + - Example: patch summary file lines + - Desired: vec![" └ ".into(), "M".red(), " ".dim(), "tui/src/app.rs".dim()] + ## Snapshot tests This repo uses snapshot tests (via `insta`), especially in `codex-rs/tui`, to validate rendered output. When UI or text output changes intentionally, update the snapshots as follows: diff --git a/codex-rs/tui/src/history_cell.rs b/codex-rs/tui/src/history_cell.rs index 37a9d66f..bc90ad34 100644 --- a/codex-rs/tui/src/history_cell.rs +++ b/codex-rs/tui/src/history_cell.rs @@ -818,8 +818,32 @@ pub(crate) fn new_patch_apply_success(stdout: String) -> PlainHistoryCell { let mut iter = stdout.lines(); for (i, raw) in iter.by_ref().take(TOOL_CALL_MAX_LINES).enumerate() { let prefix = if i == 0 { " └ " } else { " " }; - let s = format!("{prefix}{raw}"); - lines.push(ansi_escape_line(&s).dim()); + + // First line is the header; dim it entirely. + if i == 0 { + let s = format!("{prefix}{raw}"); + lines.push(ansi_escape_line(&s).dim()); + continue; + } + + // Subsequent lines should look like: "M path/to/file". + // Colorize the status letter like `git status` (e.g., M red). + let status = raw.chars().next(); + let rest = raw.get(1..).unwrap_or(""); + + let status_span = match status { + Some('M') => "M".red(), + Some('A') => "A".green(), + Some('D') => "D".red(), + Some(other) => other.to_string().into(), + None => "".into(), + }; + + lines.push(Line::from(vec![ + prefix.into(), + status_span, + ansi_escape_line(rest).to_string().into(), + ])); } let remaining = iter.count(); if remaining > 0 {