[StringUtilities] Fix unicode trimming using Intl.Segmenter [devtools/devtools-frontend : main]

0 views
Skip to first unread message

Connor Clark (Gerrit)

unread,
Dec 18, 2025, 6:58:37 PM (3 days ago) Dec 18
to Paul Irish, Devtools-frontend LUCI CQ, devtools-rev...@chromium.org
Attention needed from Paul Irish

Connor Clark voted Auto-Submit+1

Auto-Submit+1
Open in Gerrit

Related details

Attention is currently required from:
  • Paul Irish
Submit Requirements:
  • requirement satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: devtools/devtools-frontend
Gerrit-Branch: main
Gerrit-Change-Id: I1f1f1bf3b73b5efbdf7249585cb3877125723c5b
Gerrit-Change-Number: 7278421
Gerrit-PatchSet: 2
Gerrit-Owner: Connor Clark <cja...@chromium.org>
Gerrit-Reviewer: Connor Clark <cja...@chromium.org>
Gerrit-Reviewer: Paul Irish <paul...@chromium.org>
Gerrit-CC: Devtools-frontend LUCI CQ <devtools-fro...@luci-project-accounts.iam.gserviceaccount.com>
Gerrit-Attention: Paul Irish <paul...@chromium.org>
Gerrit-Comment-Date: Thu, 18 Dec 2025 23:58:35 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: Yes
satisfied_requirement
unsatisfied_requirement
open
diffy

Paul Irish (Gerrit)

unread,
Dec 19, 2025, 8:25:07 PM (2 days ago) Dec 19
to Connor Clark, Devtools-frontend LUCI CQ, devtools-rev...@chromium.org
Attention needed from Connor Clark

Paul Irish voted and added 4 comments

Votes added by Paul Irish

Code-Review+1

4 comments

Patchset-level comments
File-level comment, Patchset 2 (Latest):
Paul Irish . resolved

played around with this. tried some variants. but in the end what you got here is solid. Nice work

File front_end/core/platform/StringUtilities.test.ts
Line 350, Patchset 2 (Latest): it('trimEndWithMaxLength', () => {
const {trimEndWithMaxLength} = Platform.StringUtilities;

assert.strictEqual(trimEndWithMaxLength('aaa', 30), 'aaa');
assert.strictEqual(trimEndWithMaxLength('aaa', 3), 'aaa');
assert.strictEqual(trimEndWithMaxLength('aaa', 2), 'a…');
assert.strictEqual(trimEndWithMaxLength('aaa🥳', 4), 'aaa🥳');
assert.strictEqual(trimEndWithMaxLength('aaa🥳', 3), 'aa…');
assert.strictEqual(trimEndWithMaxLength('aaa👨‍👨‍👦‍👦', 4), 'aaa👨‍👨‍👦‍👦');
assert.strictEqual(trimEndWithMaxLength('aaa👨‍👨‍👦‍👦', 3), 'aa…');
assert.strictEqual(trimEndWithMaxLength('देवनागरी', 5), 'देवनागरी');
assert.strictEqual(trimEndWithMaxLength('देवनागरी', 4), 'देवना…');

assert.strictEqual(trimEndWithMaxLength('aaa', 3, ''), 'aaa');
assert.strictEqual(trimEndWithMaxLength('aaa', 2, ''), 'aa');
assert.strictEqual(trimEndWithMaxLength('aaa', 1), '…');
assert.strictEqual(trimEndWithMaxLength('aaa', 0), '…');

assert.strictEqual(trimEndWithMaxLength('aaaaa', 5, '...'), 'aaaaa');
assert.strictEqual(trimEndWithMaxLength('aaaaa', 4, '...'), 'a...');
assert.strictEqual(trimEndWithMaxLength('aaaaa', 3, '...'), '...');
assert.strictEqual(trimEndWithMaxLength('aaaaa', 1, '...'), '...');

// NFD.
assert.strictEqual(trimEndWithMaxLength('caf\u0065\u0301', 4), 'café');
assert.strictEqual(trimEndWithMaxLength('caf\u0065\u0301', 3), 'ca…');
});
Paul Irish . unresolved

i was fucking around and got explored some edge cases.. it resulted in this more comprehensive test suite.

and your fn passes all. :)


```suggestion
describe('trimEndWithMaxLength', () => {
const {trimEndWithMaxLength} = Platform.StringUtilities;
    it('returns the original string if it fits within maxLength', () => {
assert.strictEqual(trimEndWithMaxLength('abc', 3), 'abc');
assert.strictEqual(trimEndWithMaxLength('abc', 10), 'abc');
assert.strictEqual(trimEndWithMaxLength('', 5), '');
});
    it('trims the string and adds an ellipsis if it exceeds maxLength', () => {
assert.strictEqual(trimEndWithMaxLength('abc', 2), 'a…');
assert.strictEqual(trimEndWithMaxLength('abcdef', 5), 'abcd…');
});
    it('returns just the ellipsis if maxLength is small', () => {
assert.strictEqual(trimEndWithMaxLength('abc', 1), '…');
assert.strictEqual(trimEndWithMaxLength('abc', 0), '…');
});
    it('returns the empty string if the input is empty and maxLength is 0', () => {
// Logic check:
// str.length (0) <= maxLength (0) -> returns str ("")
assert.strictEqual(trimEndWithMaxLength('', 0), '');
});
    it('handles unicode surrogate pairs and emojis correctly', () => {
assert.strictEqual(trimEndWithMaxLength('aaa🥳', 4), 'aaa🥳');
assert.strictEqual(trimEndWithMaxLength('aaa🥳', 3), 'aa…');
assert.strictEqual(trimEndWithMaxLength('aaa👨‍👨‍👦‍👦', 4), 'aaa👨‍👨‍👦‍👦');
assert.strictEqual(trimEndWithMaxLength('aaa👨‍👨‍👦‍👦', 3), 'aa…');
assert.strictEqual(trimEndWithMaxLength('🇺🇸🇨🇦', 2), '🇺🇸🇨🇦');
assert.strictEqual(trimEndWithMaxLength('🇺🇸🇨🇦', 1), '…');
});
    it('handles NFD forms correctly', () => {
assert.strictEqual(trimEndWithMaxLength('caf\u0065\u0301', 4), 'café');
assert.strictEqual(trimEndWithMaxLength('caf\u0065\u0301', 3), 'ca…');
});
    it('handles complex ZWJ sequences', () => {
const family = '👨‍👩‍👧‍👦'; // 1 grapheme
// "Start" (5) + Family (1) + "End" (3) = 9 graphemes.
assert.strictEqual(trimEndWithMaxLength(`Start${family}End`, 9), `Start${family}End`);
assert.strictEqual(trimEndWithMaxLength(`Start${family}End`, 8), `Start${family}E…`);
// Max 7. Keep 6 (7-1). "Start" (5) + Family (1).
assert.strictEqual(trimEndWithMaxLength(`Start${family}End`, 7), `Start${family}…`);
// "Start" (5) + Family (1) = 6.
// If limit is 6. "Start" + Family.
assert.strictEqual(trimEndWithMaxLength(`Start${family}`, 6), `Start${family}`);
// If limit is 5. "Star…".
assert.strictEqual(trimEndWithMaxLength(`Start${family}`, 5), 'Star…');
});
    it('handles devanagari characters', () => {
assert.strictEqual(trimEndWithMaxLength('देवनागरी', 5), 'देवनागरी');
assert.strictEqual(trimEndWithMaxLength('देवनागरी', 4), 'देवना…');
});
});
```
File front_end/core/platform/StringUtilities.ts
Line 361, Patchset 2 (Latest):export const trimMiddle = (str: string, maxLength: number, ellipsis = '…'): string => {
Paul Irish . unresolved

lets remove this as a param. it's unused in the codebase.

(and moreso.. because if you want to use a flag emoji as an ellipsis character.. you have a few bugs now. )

Line 417, Patchset 2 (Latest):export const trimEndWithMaxLength = (str: string, maxLength: number, ellipsis = '…'): string => {
Paul Irish . unresolved

same remove

Open in Gerrit

Related details

Attention is currently required from:
  • Connor Clark
Submit Requirements:
  • requirement satisfiedCode-Owners
  • requirement satisfiedCode-Review
  • requirement is not satisfiedNo-Unresolved-Comments
  • requirement satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: devtools/devtools-frontend
Gerrit-Branch: main
Gerrit-Change-Id: I1f1f1bf3b73b5efbdf7249585cb3877125723c5b
Gerrit-Change-Number: 7278421
Gerrit-PatchSet: 2
Gerrit-Owner: Connor Clark <cja...@chromium.org>
Gerrit-Reviewer: Connor Clark <cja...@chromium.org>
Gerrit-Reviewer: Paul Irish <paul...@chromium.org>
Gerrit-CC: Devtools-frontend LUCI CQ <devtools-fro...@luci-project-accounts.iam.gserviceaccount.com>
Gerrit-Attention: Connor Clark <cja...@chromium.org>
Gerrit-Comment-Date: Sat, 20 Dec 2025 01:25:05 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: Yes
satisfied_requirement
unsatisfied_requirement
open
diffy
Reply all
Reply to author
Forward
0 new messages