diff --git a/codex-rs/tui/src/app/snapshots/codex_tui__app__owned_transcript__tests__conversation_in_offset_rect.snap b/codex-rs/tui/src/app/snapshots/codex_tui__app__owned_transcript__tests__conversation_in_offset_rect.snap index 58eceddd64..d18190e127 100644 --- a/codex-rs/tui/src/app/snapshots/codex_tui__app__owned_transcript__tests__conversation_in_offset_rect.snap +++ b/codex-rs/tui/src/app/snapshots/codex_tui__app__owned_transcript__tests__conversation_in_offset_rect.snap @@ -4,14 +4,14 @@ expression: normalize_snapshot_paths(screen) --- ···································· ···································· -····· ····· ·····› Second prompt ····· ····· ····· ····· ····· ·····• For the complete ····· ····· instructions see the ····· -····· manual (https:// ····· -····· example.com/docs). ····· +····· manual ····· +····· (https://example.com/doc····· +····· s). ····· ····· ····· ····· ····· ·····› preserved draft ····· diff --git a/codex-rs/tui/src/markdown_render.rs b/codex-rs/tui/src/markdown_render.rs index 69459f7243..d06cd5c05e 100644 --- a/codex-rs/tui/src/markdown_render.rs +++ b/codex-rs/tui/src/markdown_render.rs @@ -2396,6 +2396,11 @@ impl<'a, 'policy> Writer<'a, 'policy> { if let Some(mut line) = self.current_line_content.take() { let style = self.current_line_style; let mut source = crate::terminal_hyperlinks::LogicalLineSource::from_line(&line.line); + if !self.current_line_in_code_block + && crate::wrapping::text_contains_url_like(&source.text) + { + source.wrap_policy = crate::terminal_hyperlinks::LineWrapPolicy::UrlAware; + } source.copy = Some(std::sync::Arc::new(std::mem::take(&mut self.copy_line))); // NB we don't wrap code in code blocks, in order to preserve whitespace for copy/paste. if !self.current_line_in_code_block diff --git a/codex-rs/tui/src/transcript_view/copy_on_select_tests.rs b/codex-rs/tui/src/transcript_view/copy_on_select_tests.rs index 1f8bcd30c9..ab4c7affef 100644 --- a/codex-rs/tui/src/transcript_view/copy_on_select_tests.rs +++ b/codex-rs/tui/src/transcript_view/copy_on_select_tests.rs @@ -186,7 +186,7 @@ fn copy_on_select_preserves_link_activation_and_ignores_empty_drags() { copy_on_select: true, ..Default::default() }; - render(&mut view, &cells, /*width*/ 30, /*height*/ 1); + render(&mut view, &cells, /*width*/ 30, /*height*/ 2); let down = mouse(MouseEventKind::Down(MouseButton::Left), /*column*/ 2); assert!(matches!( view.handle_mouse(down, &cells), diff --git a/codex-rs/tui/src/transcript_view/text_tests.rs b/codex-rs/tui/src/transcript_view/text_tests.rs index 464bfe610c..e017b13007 100644 --- a/codex-rs/tui/src/transcript_view/text_tests.rs +++ b/codex-rs/tui/src/transcript_view/text_tests.rs @@ -298,6 +298,29 @@ fn narrow_wrapping_keeps_joined_emoji_whole() { assert_eq!(buffer[(0, 0)].symbol(), "👩‍💻"); } +#[test] +fn fullscreen_markdown_keeps_a_fitting_url_on_one_row() { + use crate::history_cell::AgentMarkdownCell; + use crate::history_cell::HistoryCell; + let cell = AgentMarkdownCell::new( + "See the documentation at https://example.com/docs/reference.".into(), + std::path::Path::new("."), + ); + let layout = TextLayout::new( + cell.retained_hyperlink_lines(/*width*/ 44, /*detailed*/ false), + /*width*/ 44, + ); + let rows = layout + .rows + .iter() + .map(|row| row.line.line.to_string()) + .collect::>(); + insta::assert_snapshot!(rows.join("\n"), @" + • See the documentation at + https://example.com/docs/reference. + "); +} + #[test] fn source_backed_markdown_copy_preserves_code_indentation() { use crate::history_cell::AgentMarkdownCell;