From a5483c6407705760297e0f0d54e251dd69a81912 Mon Sep 17 00:00:00 2001 From: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com> Date: Fri, 10 Jul 2026 04:46:55 +0000 Subject: [PATCH 1/2] fix: contain termimad panic on ragged tables in PR comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit termimad 0.34.1 panics with an out-of-bounds index (src/tbl.rs:176) when a ragged markdown table — a row with more cells than the header — is rendered at a width too narrow to fit the widest row. Its column fitter takes an error path that skips padding the short rows, then indexes past them. PR-comment markdown is untrusted and can contain such a table. The `wt switch` picker renders comment bodies through `render_table_with_termimad` on a rayon worker, so the escaped panic aborted the whole process ("Rayon: detected unexpected panic; aborting"). Contain the panic with catch_unwind and fall back to the plain preprocessed lines so the pane still shows the table's text instead of crashing. Closes #3407 Co-Authored-By: Claude --- src/md_help.rs | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/md_help.rs b/src/md_help.rs index 7986db8ef2..56aa757a60 100644 --- a/src/md_help.rs +++ b/src/md_help.rs @@ -302,7 +302,19 @@ fn render_table_with_termimad(lines: &[&str], indent: &str, max_width: Option Date: Fri, 10 Jul 2026 05:04:44 +0000 Subject: [PATCH 2/2] test: assert ragged-table test hits the fallback, not a real render MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The regression test asserted only that the output contains the cell text ("alpha"/"zeta"), which a successful termimad render of the same table also contains — so it passed on either path. If a future termimad release fixes the ragged-table panic (or the width-20 reproducer stops tripping the fitter), the test would stay green while silently no longer covering `catch_unwind`. Add an assertion on the literal `|` delimiters, which only the plain-text fallback preserves (a real render replaces them with box-drawing `│`), so the test keeps exercising the containment path. Co-Authored-By: Claude Opus 4.8 --- src/md_help.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/md_help.rs b/src/md_help.rs index 56aa757a60..d3846e46ab 100644 --- a/src/md_help.rs +++ b/src/md_help.rs @@ -885,6 +885,17 @@ mod tests { ]; let result = render_table(&lines, Some(20)); let plain = ansi_str::AnsiStr::ansi_strip(&result); + // Assert on something only the fallback produces, so the test keeps + // covering `catch_unwind` even if a future termimad release stops + // panicking on this input. The fallback returns the preprocessed lines + // verbatim, keeping the literal `|` delimiters; a successful termimad + // render replaces them with box-drawing borders (`│`) and contains no + // literal `|`. Cell-text presence alone can't tell the two apart. + assert!( + plain.contains('|'), + "expected the plain-text fallback (literal `|` delimiters), \ + not a termimad render: {plain}" + ); assert!( plain.contains("alpha") && plain.contains("zeta"), "fallback should still surface the table's cell text: {plain}"