diff --git a/packages/terminal-core/src/table.test.ts b/packages/terminal-core/src/table.test.ts index 2f44ecc55318..488208b72240 100644 --- a/packages/terminal-core/src/table.test.ts +++ b/packages/terminal-core/src/table.test.ts @@ -70,6 +70,21 @@ describe("renderTable", () => { vi.restoreAllMocks(); }); + it("renders fitting ASCII cells without grapheme segmentation", () => { + const segment = vi.spyOn(Intl.Segmenter.prototype, "segment"); + + const out = renderTable({ + border: "ascii", + columns: [{ key: "Name", header: "Name" }], + rows: [{ Name: "alpha" }, { Name: "beta" }], + }); + + expect(out).toBe( + ["+-------+", "| Name |", "+-------+", "| alpha |", "| beta |", "+-------+", ""].join("\n"), + ); + expect(segment).not.toHaveBeenCalled(); + }); + it.each(["$&", "$`", "$'", "$$"])( "displays a literal %s home path in terminal tables", (pattern) => { diff --git a/packages/terminal-core/src/table.ts b/packages/terminal-core/src/table.ts index 7ac971acccb7..1f0bd1112365 100644 --- a/packages/terminal-core/src/table.ts +++ b/packages/terminal-core/src/table.ts @@ -55,8 +55,9 @@ function padCell(text: string, width: number, align: Align): string { // A single grapheme wider than the cell (e.g. a width-2 CJK/emoji glyph in a // width-1 column) survives wrapLine intact, so clamp here to keep every cell // exactly `width` columns and preserve the border-alignment invariant. - const content = visibleWidth(text) > width ? truncateToVisibleWidth(text, width) : text; - const w = visibleWidth(content); + const textWidth = visibleWidth(text); + const content = textWidth > width ? truncateToVisibleWidth(text, width) : text; + const w = content === text ? textWidth : visibleWidth(content); if (w >= width) { return content; } @@ -366,6 +367,11 @@ function wrapLine(text: string, width: number): string[] { if (width <= 0) { return [text]; } + // Fitting edge-trimmed ASCII is one column per code unit and needs no ANSI/grapheme scan. + // Keep edge whitespace on the full path, where wrapping preserves its trimming semantics. + if (text.length <= width && /^[!-~](?:[ -~]*[!-~])?$/u.test(text)) { + return [text]; + } // ANSI-aware wrapping: never split inside ANSI SGR/OSC-8 sequences. // Table cells are padded and bordered per physical line, so wrapped lines