-
-
Notifications
You must be signed in to change notification settings - Fork 39
Description
String width calculation is a hot path in terminal rendering — it's called on every line of output in tools like Ink, cli-truncate, wrap-ansi, and log-update. With the growth of AI-powered terminal agents that stream large amounts of text, this is becoming even more performance-sensitive.
I profiled string-width and found two low-hanging optimizations: stripAnsi runs unconditionally even when no ANSI codes are present, and Intl.Segmenter runs on every call even for pure ASCII input where width = length.
ASCII + ANSI benchmarks (Apple M2 Max, Node 25.2.1)
| Input | Before | After | Speedup |
|---|---|---|---|
| ascii short (11 chars) | 3.87 µs | 63.85 ns | 61x |
| ascii long (1000 chars) | 137.52 µs | 777 ns | 177x |
| ANSI short (5 visible) | 2.08 µs | 147.91 ns | 14x |
| ANSI heavy (101 chars) | 30.56 µs | 4.81 µs | 6.4x |
Non-ASCII inputs (CJK, emoji, mixed) are unaffected — they fall through to the existing Intl.Segmenter path.
PRs
- perf: add ASCII fast path and codepoint iteration to avoid Intl.Segmenter #72 — ASCII fast path + stripAnsi guard
- perf: add fast path for strings without ANSI codes chalk/strip-ansi#54 — adds
string.includes('\x1B')fast path to strip-ansi - perf: use packed arrays with binary search for lookups get-east-asian-width#14 — packed arrays with binary search (3.5x faster, -25% bundle size)
Optimizations
-
ASCII fast path — regex
/^[\u0020-\u007E]*$/detects pure printable ASCII, returnsstring.lengthdirectly. SkipsIntl.Segmenter, regex, and EAW lookup entirely. 61x faster for short ASCII, the most common input type. -
stripAnsi guard — check
string.includes('\x1B') || string.includes('\x9B')before callingstripAnsi. Avoids the overhead of strip-ansi's regex on strings that contain no ANSI escapes. 14x faster for ANSI-free short strings.