From f778ddb6c50bb0ec32cfe7bef59c2f98fd9f12e5 Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Tue, 29 Oct 2024 09:55:34 +0100 Subject: [PATCH] support surrogate pairs --- packages/playwright/src/reporters/base.ts | 24 ++++++++++++---------- tests/playwright-test/fit-to-width.spec.ts | 7 +++++++ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/packages/playwright/src/reporters/base.ts b/packages/playwright/src/reporters/base.ts index 45c4c5a938..1e93740403 100644 --- a/packages/playwright/src/reporters/base.ts +++ b/packages/playwright/src/reporters/base.ts @@ -495,21 +495,22 @@ function characterWidth(c: string) { function stringWidth(v: string) { let width = 0; - for (let i = 0; i < v.length; ++i) - width += characterWidth(v[i]); + for (const { segment } of new Intl.Segmenter(undefined, { granularity: 'grapheme' }).segment(v)) + width += characterWidth(segment); return width; } function suffixOfWidth(v: string, width: number) { - let i = v.length - 1; - for (; i > 0; --i) { - const c = v[i]; - const cWidth = characterWidth(c); - if (cWidth >= width) + const segments = [...new Intl.Segmenter(undefined, { granularity: 'grapheme' }).segment(v)]; + let suffixBegin = v.length; + for (const { segment, index } of segments.reverse()) { + const segmentWidth = stringWidth(segment); + if (segmentWidth > width) break; - width -= cWidth; + width -= segmentWidth; + suffixBegin = index; } - return v.substring(i); + return v.substring(suffixBegin); } // Leaves enough space for the "prefix" to also fit. @@ -528,9 +529,10 @@ export function fitToWidth(line: string, width: number, prefix?: string): string taken.push(parts[i]); } else { let part = suffixOfWidth(parts[i], width); - if (part.length < parts[i].length && part.length > 0) { + const wasTruncated = part.length < parts[i].length; + if (wasTruncated && part.length > 0) { // Add ellipsis if we are truncating. - part = '\u2026' + part.substring(1); + part = '\u2026' + suffixOfWidth(parts[i], width - 1); } taken.push(part); width -= stringWidth(part); diff --git a/tests/playwright-test/fit-to-width.spec.ts b/tests/playwright-test/fit-to-width.spec.ts index c118e6687f..6a45d8c64f 100644 --- a/tests/playwright-test/fit-to-width.spec.ts +++ b/tests/playwright-test/fit-to-width.spec.ts @@ -21,3 +21,10 @@ test('chinese characters', () => { expect(fitToWidth('你你好', 3)).toBe('…好'); expect(fitToWidth('你好你好', 4)).toBe('…好'); }); + +test('surrogate pairs', () => { + expect(fitToWidth('🫣🤗', 2)).toBe('🫣🤗'); + expect(fitToWidth('🚄🚄', 1)).toBe('…'); + expect(fitToWidth('🚄🚄🚄', 2)).toBe('…🚄'); + expect(fitToWidth('🚄🚄', 2)).toBe('🚄🚄'); +});