diff --git a/codex-rs/tui/src/exec_cell/render.rs b/codex-rs/tui/src/exec_cell/render.rs index 3375f1dca..a38cf5a84 100644 --- a/codex-rs/tui/src/exec_cell/render.rs +++ b/codex-rs/tui/src/exec_cell/render.rs @@ -219,7 +219,12 @@ impl HistoryCell for ExecCell { if let Some(output) = call.output.as_ref() { if !call.is_unified_exec_interaction() { - lines.extend(output.formatted_output.lines().map(ansi_escape_line)); + let wrap_width = width.max(1) as usize; + let wrap_opts = RtOptions::new(wrap_width); + for unwrapped in output.formatted_output.lines().map(ansi_escape_line) { + let wrapped = word_wrap_line(&unwrapped, wrap_opts.clone()); + push_owned_lines(&wrapped, &mut lines); + } } let duration = call .duration diff --git a/codex-rs/tui/src/pager_overlay.rs b/codex-rs/tui/src/pager_overlay.rs index 3b47e9a70..b5f7b963c 100644 --- a/codex-rs/tui/src/pager_overlay.rs +++ b/codex-rs/tui/src/pager_overlay.rs @@ -748,6 +748,49 @@ mod tests { assert_snapshot!("transcript_overlay_apply_patch_scroll_vt100", snapshot); } + #[test] + fn transcript_overlay_wraps_long_exec_output_lines() { + let marker = "Z"; + let long_line = marker.repeat(200); + + let mut exec_cell = crate::exec_cell::new_active_exec_command( + "exec-long".into(), + vec!["bash".into(), "-lc".into(), "echo long".into()], + vec![ParsedCommand::Unknown { + cmd: "echo long".into(), + }], + ExecCommandSource::Agent, + None, + false, + ); + exec_cell.complete_call( + "exec-long", + CommandOutput { + exit_code: 0, + aggregated_output: format!("{long_line}\n"), + formatted_output: long_line, + }, + Duration::from_millis(10), + ); + let exec_cell: Arc = Arc::new(exec_cell); + + let mut overlay = TranscriptOverlay::new(vec![exec_cell]); + let area = Rect::new(0, 0, 20, 10); + let mut buf = Buffer::empty(area); + + overlay.render(area, &mut buf); + let rendered = buffer_to_text(&buf, area); + + let wrapped_lines = rendered + .lines() + .filter(|line| line.contains(marker)) + .count(); + assert!( + wrapped_lines >= 2, + "expected long exec output to wrap into multiple lines in transcript overlay, got:\n{rendered}" + ); + } + #[test] fn transcript_overlay_keeps_scroll_pinned_at_bottom() { let mut overlay = TranscriptOverlay::new(