From 7b7f233e366a681cbe4d9a9caf298451a5965a20 Mon Sep 17 00:00:00 2001 From: Felipe Coury Date: Mon, 16 Feb 2026 22:45:16 -0300 Subject: [PATCH] fix(tui): escape pipes in table fallback rows --- codex-rs/tui/src/markdown_render.rs | 2 +- codex-rs/tui/src/markdown_render_tests.rs | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/codex-rs/tui/src/markdown_render.rs b/codex-rs/tui/src/markdown_render.rs index b73bb670a5..5f6bb515a7 100644 --- a/codex-rs/tui/src/markdown_render.rs +++ b/codex-rs/tui/src/markdown_render.rs @@ -1240,7 +1240,7 @@ where out.push('|'); for cell in row { out.push(' '); - out.push_str(&cell.plain_text()); + out.push_str(&cell.plain_text().replace('|', "\\|")); out.push(' '); out.push('|'); } diff --git a/codex-rs/tui/src/markdown_render_tests.rs b/codex-rs/tui/src/markdown_render_tests.rs index ef7eb505a0..b6425405f4 100644 --- a/codex-rs/tui/src/markdown_render_tests.rs +++ b/codex-rs/tui/src/markdown_render_tests.rs @@ -1461,6 +1461,20 @@ fn table_falls_back_to_pipe_rendering_if_it_cannot_fit() { assert!(!lines.iter().any(|line| line.contains('┌'))); } +#[test] +fn table_pipe_fallback_escapes_literal_pipes_in_cell_content() { + let md = "| c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 |\n|---|---|---|---|---|---|---|---|---|---|\n| keep | keep | keep | keep | keep | keep | keep | keep | a \\| b | keep |\n"; + let text = crate::markdown_render::render_markdown_text_with_width(md, Some(20)); + let lines: Vec = text + .lines + .iter() + .map(|line| line.spans.iter().map(|span| span.content.clone()).collect()) + .collect(); + + assert!(lines.first().is_some_and(|line| line.starts_with('|'))); + assert!(lines.iter().any(|line| line.contains("a \\| b"))); +} + #[test] fn table_keeps_sparse_rows_with_empty_trailing_cells() { let md = "| A | B | C |\n|---|---|---|\n| a | | |\n";