From bb376132a36632193187571a1e3d7ce49cd85c0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E5=98=89=E4=BC=9F?= <202383014@uibe.edu.cn> Date: Mon, 5 Oct 2026 01:39:18 +0800 Subject: [PATCH 1/3] fix(codemode): preserve block tint across truncated rows --- extensions/codemode-display/render.ts | 25 ++++++++++++------- .../codemode-display/render.test.ts | 18 +++++++++++++ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/extensions/codemode-display/render.ts b/extensions/codemode-display/render.ts index 26d640ae7..562e5fa14 100644 --- a/extensions/codemode-display/render.ts +++ b/extensions/codemode-display/render.ts @@ -99,6 +99,15 @@ const ICON_COLOR = { type Tone = "toolPendingBg" | "toolSuccessBg" | "toolErrorBg"; +/** Reapply the block tint after nested foreground styles reset all SGR state. */ +function paintBackground(theme: Theme, color: Tone, row: string) { + return row + .split("\u001b[0m") + .filter((segment) => segment.length > 0) + .map((segment) => theme.bg(color, segment)) + .join(""); +} + /** Mirror Pi's default tool shell (padded, tinted block) with a tone derived from all evidence. */ function framed( theme: Theme, @@ -115,15 +124,13 @@ function framed( if (edges.top) rows.unshift(""); if (edges.bottom()) rows.push(""); const bg = tone(); - return rows.map((row) => { - const padded = row + " ".repeat(Math.max(0, width - visibleWidth(row))); - // Pi's truncation/wrapping resets all SGR styles. Reapply the owning - // card background after each reset, including ellipsis and padding. - return padded - .split("\x1b[0m") - .map((segment) => theme.bg(bg, segment)) - .join("\x1b[0m"); - }); + return rows.map((row) => + paintBackground( + theme, + bg, + row + " ".repeat(Math.max(0, width - visibleWidth(row))), + ), + ); }, invalidate() {}, }; diff --git a/tests/extensions/codemode-display/render.test.ts b/tests/extensions/codemode-display/render.test.ts index 26b2714c9..17ea2b73b 100644 --- a/tests/extensions/codemode-display/render.test.ts +++ b/tests/extensions/codemode-display/render.test.ts @@ -388,6 +388,24 @@ test("block tint is green only for a clean ledger, neutral for nested issues and assert.equal(tone(result("boom"), true), "toolErrorBg"); }); +test("truncated rows keep the block background after nested foreground resets", () => { + const ansi = { + fg: (_color: string, text: string) => `\u001b[31m${text}\u001b[0m`, + bg: (_color: string, text: string) => `\u001b[44m${text}\u001b[0m`, + bold: (text: string) => text, + } as Theme; + const rows = codemodeRenderers.renderCall!( + { code }, + ansi, + context(false), + ).render(40); + assert.ok(rows.length > 0); + assert.ok( + rows.some((row) => /\u001b\[0m\u001b\[44m/u.test(row)), + "each nested reset must reopen the block background", + ); +}); + test("compact call rows name their first string argument within the row budget", () => { const calls = [ { From a9eb64c4430a2f8eb34fc52b6207c0eb2a59285c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E5=98=89=E4=BC=9F?= <202383014@uibe.edu.cn> Date: Thu, 8 Oct 2026 11:55:18 +0800 Subject: [PATCH 2/3] fix(codemode): preserve reset markers while repainting tint --- extensions/codemode-display/render.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/extensions/codemode-display/render.ts b/extensions/codemode-display/render.ts index 562e5fa14..1dfbb0ea3 100644 --- a/extensions/codemode-display/render.ts +++ b/extensions/codemode-display/render.ts @@ -103,9 +103,8 @@ type Tone = "toolPendingBg" | "toolSuccessBg" | "toolErrorBg"; function paintBackground(theme: Theme, color: Tone, row: string) { return row .split("\u001b[0m") - .filter((segment) => segment.length > 0) .map((segment) => theme.bg(color, segment)) - .join(""); + .join("\u001b[0m"); } /** Mirror Pi's default tool shell (padded, tinted block) with a tone derived from all evidence. */ From 5b3ac36caae15947a1bef4364b4222d7b6a13591 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E5=98=89=E4=BC=9F?= <202383014@uibe.edu.cn> Date: Thu, 15 Oct 2026 16:16:26 +0800 Subject: [PATCH 3/3] ci: rerun Web E2E after transient response disposal