Repository navigation
fix(core): preserve line terminators in truncateString - #29673
diegogodinezr wants to merge 3 commits into
Conversation
Add the dotAll (s) flag to graphemeRegex in truncateString so that '.' matches line terminators (\n, \r, \u2028, \u2029), preserving multi-line formatting and counting line terminators toward the maxLength budget. Fixes google-gemini#29562
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses an issue where line terminators were being stripped and ignored during string truncation. By enabling the dotAll flag in the regex used for grapheme parsing, the function now correctly treats line breaks as characters, ensuring they are preserved in the output and accounted for within the specified length budget. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
|
📊 PR Size: size/S
|
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request updates the truncateString utility in textUtils.ts by adding the s (dotAll) flag to the grapheme regular expression, ensuring that line terminators are preserved and counted toward the maximum length budget. It also adds corresponding unit tests in textUtils.test.ts. The review feedback recommends treating \r\n (CRLF) as a single, indivisible grapheme cluster to prevent splitting that could corrupt terminal rendering in CLI environments, and suggests updating the test assertions to reflect this behavior.
| expect(truncateString('x\r\ny', 2, '')).toBe('x\r'); | ||
| expect(truncateString('x\r\ny', 3, '')).toBe('x\r\n'); |
There was a problem hiding this comment.
Update the test assertions to reflect that \r\n (CRLF) is treated as a single indivisible grapheme cluster, preventing a dangling \r from being returned when truncating.
| expect(truncateString('x\r\ny', 2, '')).toBe('x\r'); | |
| expect(truncateString('x\r\ny', 3, '')).toBe('x\r\n'); | |
| expect(truncateString('x\r\ny', 2, '')).toBe('x'); | |
| expect(truncateString('x\r\ny', 3, '')).toBe('x\r\n'); |
References
- When truncating strings that may contain multi-byte Unicode characters, use methods that operate on grapheme clusters instead of UTF-16 code units to prevent character splitting.
There was a problem hiding this comment.
Code Review
This pull request updates the truncateString utility by adding the s (dotAll) flag to its grapheme regular expression, ensuring line terminators are preserved and counted toward the length budget, and adds corresponding unit tests. However, the review feedback highlights that this custom regex approach still fails to handle complex Unicode grapheme clusters correctly, such as splitting CRLF (\r\n) into separate characters (which is also codified in the new tests). Since the project targets Node.js >= 20, it is recommended to replace the custom regex with the built-in Intl.Segmenter API for robust Unicode support.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request refactors the truncateString utility in packages/core/src/utils/textUtils.ts to use the native Intl.Segmenter API with grapheme granularity instead of a custom regular expression. This improves the handling of complex grapheme clusters, such as zero-width joiner (ZWJ) emojis and line terminators. Additionally, corresponding unit tests have been added to packages/core/src/utils/textUtils.test.ts to verify these behaviors. There are no review comments, and I have no feedback to provide.
Summary
Fixes
truncateStringin@google/gemini-cli-coreso that line terminators (\n,\r,\r\n,\u2028,\u2029) and complex Unicode grapheme clusters are preserved in the truncated output and counted toward themaxLengthbudget.Details
Previously,
graphemeRegexintruncateString(/(?:[\uD800-\uDBFF][\uDC00-\uDFFF]|.)\p{M}*/gu) omitted thes(dotAll) flag and used a manual regular expression that skipped line terminators and could split multi-code-point grapheme clusters such as\r\n(CRLF) or ZWJ emoji sequences.This change replaces the manual regex with
Intl.Segmenter(granularity: 'grapheme') so that line terminators, CRLF sequences, and complex Unicode grapheme clusters are treated as atomic segments and counted towardmaxLength, and adds unit test coverage for multi-line strings and ZWJ emoji clusters.Related Issues
Fixes #29562
How to Validate
textUtilsunit tests in@google/gemini-cli-core:npm test -w @google/gemini-cli-core -- src/utils/textUtils.test.tstruncateStringpreserves line terminators and counts grapheme clusters towardmaxLength:truncateString('aa\nbb\ncc', 4, '')returns'aa\nb'truncateString('a\nb\nc', 3, '')returns'a\nb'truncateString('x\r\ny', 2, '')returns'x'truncateString('x\r\ny', 3, '')returns'x\r\n'Pre-Merge Checklist