From cfb59b908256881868e15ced8f8b9d7cb8de3f7b Mon Sep 17 00:00:00 2001 From: kwy404 Date: Thu, 1 Oct 2026 13:25:45 -0300 Subject: [PATCH] fix: avoid splitting surrogate pairs in trimEnd --- src/common/stringUtils.test.ts | 7 ++++++- src/common/stringUtils.ts | 5 ++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/common/stringUtils.test.ts b/src/common/stringUtils.test.ts index d16bb8a98..f96cecc60 100644 --- a/src/common/stringUtils.test.ts +++ b/src/common/stringUtils.test.ts @@ -4,9 +4,14 @@ import { expect } from 'chai'; import { Base0Position } from './positions'; -import { PositionToOffset } from './stringUtils'; +import { PositionToOffset, trimEnd } from './stringUtils'; describe('stringUtils', () => { + it('trimEnd does not split surrogate pairs', () => { + expect(trimEnd('ab\u{1F600}cd', 4)).to.equal('ab…'); + expect(trimEnd('ab\u{1F600}cd', 5)).to.equal('ab\u{1F600}…'); + }); + it('positionToOffset', () => { const simple = new PositionToOffset('hello\nworld'); expect(simple.convert(new Base0Position(0, 2))).to.equal(2); diff --git a/src/common/stringUtils.ts b/src/common/stringUtils.ts index 6153c03d0..490434a5d 100644 --- a/src/common/stringUtils.ts +++ b/src/common/stringUtils.ts @@ -6,7 +6,10 @@ import { IPosition } from './positions'; export function trimEnd(text: string, maxLength: number) { if (text.length <= maxLength) return text; - return text.substr(0, maxLength - 1) + '…'; + let end = maxLength - 1; + const lastPoint = text.codePointAt(end - 1); + if (lastPoint && lastPoint >= 0x10000) --end; + return text.substr(0, end) + '…'; } export function trimMiddle(text: string, maxLength: number) {