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) {