Repository navigation
util: add getStringWidth() - #66642
Open
marcopiraccini wants to merge 4 commits into
Open
marcopiraccini wants to merge 4 commits into
marcopiraccini wants to merge 4 commits into
Conversation
Expose the string width helper that readline, the REPL and the test runner already use. It returns the number of terminal columns a string occupies: full-width characters count as two, zero-width characters as zero, and ANSI escape sequences are ignored. The API is experimental. Refs: nodejs#40214 Signed-off-by: marcopiraccini <marco.piraccini@gmail.com>
The internal helper counts code points and, since nodejs#31112, counts each emoji of a ZWJ sequence separately, because terminals of the time did not render such sequences as one glyph. That is still right for the cursor movement in readline, where overcounting is the safer error, but for a public API it disagrees with what terminals render today and with the string-width package that most CLI tools use. Add a grapheme cluster based width to the ICU binding and use it for util.getStringWidth(): an emoji sequence, flag, keycap or skin tone sequence takes two columns, Hangul jamo are grouped into syllable blocks, and spacing marks and halfwidth forms add their own columns. The build without ICU approximates this on top of its code point tables. readline and the REPL keep the code point based function. Refs: nodejs#31112 Signed-off-by: marcopiraccini <marco.piraccini@gmail.com>
marcopiraccini
marked this pull request as ready for review
October 11, 2026 08:42
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #66642 +/- ##
==========================================
+ Coverage 90.43% 90.49% +0.06%
==========================================
Files 791 791
Lines 276609 277284 +675
Branches 53118 53359 +241
==========================================
+ Hits 250154 250940 +786
+ Misses 16867 16754 -113
- Partials 9588 9590 +2
🚀 New features to boost your workflow:
|
ShogunPanda
approved these changes
Oct 11, 2026
Move the width fallback used without ICU, and the table it shares with the code point based helper, out of the hasIntl branch so that a test can call it on builds with ICU. Cover the remaining branches of the grapheme cluster width in the ICU binding: unqualified ZWJ sequences, keycap bases, a jamo cluster with a spacing mark and an invalid flag. Signed-off-by: marcopiraccini <marco.piraccini@gmail.com>
Assign the fallback when it is defined and let the build with ICU replace it, instead of assigning it in the branch that only runs without ICU. Also cover the last keycap base branch. Signed-off-by: marcopiraccini <marco.piraccini@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Expose
getStringWidth()as the experimentalutil.getStringWidth(str)API.The function estimates terminal width by grapheme cluster. Full-width characters and emoji sequences count as two columns; invisible clusters count as zero. ANSI escape sequences are ignored. Its results matched the
string-widthpackage on 200,000 random strings.The existing width helper is also used by
readline. It counts each emoji in a ZWJ sequence separately, a behavior introduced in #31112 for cursor movement. This PR leaves that helper unchanged and uses a new grapheme-aware ICU function for the public API. Builds without ICU use an approximation and leave the shared width table unchanged.Bun provides
Bun.stringWidth(), and Deno's@std/cliprovidesunicodeWidth(). PR #40214 is a precedent for exposing an existing utility as a public API.Refs: #31112
Refs: #40214