From 9c1bf837fb4f5d42dd56ea0d14bb5558f6671a73 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sat, 14 Mar 2026 06:56:07 -0600 Subject: [PATCH] Fix TUI crash/corruption on code blocks with lines exceeding terminal width (#343) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Initial plan * Fix content renderer crash on long lines in code blocks exceeding terminal width Co-authored-by: glittercowboy <186001655+glittercowboy@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: glittercowboy <186001655+glittercowboy@users.noreply.github.com> Co-authored-by: TÂCHES --- packages/pi-tui/src/components/markdown.ts | 13 +++++++++++-- packages/pi-tui/src/tui.ts | 6 +++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/pi-tui/src/components/markdown.ts b/packages/pi-tui/src/components/markdown.ts index 7ab926896..b24999767 100644 --- a/packages/pi-tui/src/components/markdown.ts +++ b/packages/pi-tui/src/components/markdown.ts @@ -1,7 +1,7 @@ import { marked, type Token } from "marked"; import { isImageLine } from "../terminal-image.js"; import type { Component } from "../tui.js"; -import { applyBackgroundToLine, visibleWidth, wrapTextWithAnsi } from "../utils.js"; +import { applyBackgroundToLine, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "../utils.js"; /** * Default text styling for markdown content. @@ -130,7 +130,16 @@ export class Markdown implements Component { if (isImageLine(line)) { wrappedLines.push(line); } else { - wrappedLines.push(...wrapTextWithAnsi(line, contentWidth)); + const wrapped = wrapTextWithAnsi(line, contentWidth); + for (const wl of wrapped) { + // Safety net: silently truncate lines that still exceed contentWidth. + // This handles edge cases like code blocks with very long whitespace + // sequences or tokens that wrapTextWithAnsi cannot split further. + // No ellipsis is used (empty string) to avoid visual noise in code output; + // the truncation is intentional and matches the terminal-width safety + // behavior expected from all TUI components. + wrappedLines.push(visibleWidth(wl) > contentWidth ? truncateToWidth(wl, contentWidth, "") : wl); + } } } diff --git a/packages/pi-tui/src/tui.ts b/packages/pi-tui/src/tui.ts index 8e2c65a3f..89537f1b3 100644 --- a/packages/pi-tui/src/tui.ts +++ b/packages/pi-tui/src/tui.ts @@ -903,7 +903,11 @@ export class TUI extends Container { if (clear) buffer += "\x1b[3J\x1b[2J\x1b[H"; // Clear scrollback, screen, and home for (let i = 0; i < newLines.length; i++) { if (i > 0) buffer += "\r\n"; - buffer += newLines[i]; + let line = newLines[i]; + if (!isImageLine(line) && visibleWidth(line) > width) { + line = truncateToWidth(line, width); + } + buffer += line; } buffer += "\x1b[?2026l"; // End synchronized output this.terminal.write(buffer);