diff --git a/codex-rs/tui/src/history_cell/exec.rs b/codex-rs/tui/src/history_cell/exec.rs index c1a46d2f19..57c2f166c0 100644 --- a/codex-rs/tui/src/history_cell/exec.rs +++ b/codex-rs/tui/src/history_cell/exec.rs @@ -159,17 +159,17 @@ impl HistoryCell for UnifiedExecProcessesCell { } let command = &process.command_display; let (snippet, snippet_truncated) = { - let (first_line, has_more_lines) = match command.split_once('\n') { - Some((first, _)) => (first, true), - None => (command.as_str(), false), - }; let max_graphemes = 80; - let mut graphemes = first_line.grapheme_indices(true); - if let Some((byte_index, _)) = graphemes.nth(max_graphemes) { - (first_line[..byte_index].to_string(), true) - } else { - (first_line.to_string(), has_more_lines) - } + let mut graphemes = command.graphemes(true); + let snippet: String = graphemes + .by_ref() + .take(max_graphemes) + .map(|grapheme| match grapheme { + "\n" | "\r\n" => "↵", + _ => grapheme, + }) + .collect(); + (snippet, graphemes.next().is_some()) }; if wrap_width <= prefix_width { out.push(Line::from(prefix.dim())); diff --git a/codex-rs/tui/src/history_cell/snapshots/codex_tui__history_cell__tests__ps_output_multiline_long_command_snapshot.snap b/codex-rs/tui/src/history_cell/snapshots/codex_tui__history_cell__tests__ps_output_multiline_long_command_snapshot.snap new file mode 100644 index 0000000000..ce48f3512c --- /dev/null +++ b/codex-rs/tui/src/history_cell/snapshots/codex_tui__history_cell__tests__ps_output_multiline_long_command_snapshot.snap @@ -0,0 +1,9 @@ +--- +source: tui/src/history_cell/tests.rs +expression: rendered +--- +/ps + +Background terminals + + • (↵ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx [...] diff --git a/codex-rs/tui/src/history_cell/snapshots/codex_tui__history_cell__tests__ps_output_multiline_snapshot.snap b/codex-rs/tui/src/history_cell/snapshots/codex_tui__history_cell__tests__ps_output_multiline_snapshot.snap index 0e31eddfa0..609bafd3be 100644 --- a/codex-rs/tui/src/history_cell/snapshots/codex_tui__history_cell__tests__ps_output_multiline_snapshot.snap +++ b/codex-rs/tui/src/history_cell/snapshots/codex_tui__history_cell__tests__ps_output_multiline_snapshot.snap @@ -1,13 +1,15 @@ --- -source: tui/src/history_cell.rs +source: tui/src/history_cell/tests.rs expression: rendered --- /ps Background terminals - • echo hello [...] + • echo hello↵and then some extra text ↳ hello done + • (↵ sleep 120↵) + • sleep 1↵sleep 120 • rg "foo" src ↳ src/main.rs:12:foo diff --git a/codex-rs/tui/src/history_cell/tests.rs b/codex-rs/tui/src/history_cell/tests.rs index 4d22db3310..0be28aec0d 100644 --- a/codex-rs/tui/src/history_cell/tests.rs +++ b/codex-rs/tui/src/history_cell/tests.rs @@ -878,6 +878,14 @@ fn ps_output_multiline_snapshot() { command_display: "echo hello\nand then some extra text".to_string(), recent_chunks: vec!["hello".to_string(), "done".to_string()], }, + UnifiedExecProcessDetails { + command_display: "(\n sleep 120\n)".to_string(), + recent_chunks: Vec::new(), + }, + UnifiedExecProcessDetails { + command_display: "sleep 1\r\nsleep 120".to_string(), + recent_chunks: Vec::new(), + }, UnifiedExecProcessDetails { command_display: "rg \"foo\" src".to_string(), recent_chunks: vec!["src/main.rs:12:foo".to_string()], @@ -887,6 +895,16 @@ fn ps_output_multiline_snapshot() { insta::assert_snapshot!(rendered); } +#[test] +fn ps_output_multiline_long_command_snapshot() { + let cell = new_unified_exec_processes_output(vec![UnifiedExecProcessDetails { + command_display: format!("(\n {}\n)", "x".repeat(100)), + recent_chunks: Vec::new(), + }]); + let rendered = render_lines(&cell.display_lines(/*width*/ 100)).join("\n"); + insta::assert_snapshot!(rendered); +} + #[test] fn cyber_policy_error_event_snapshot() { let cell = new_cyber_policy_error_event(crate::daybreak::Notice::Apply);