Skip to content

Performance: 22% smaller, 6–142x faster #71

@privatenumber

Description

@privatenumber

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

Optimizations

  1. ASCII fast path — regex /^[\u0020-\u007E]*$/ detects pure printable ASCII, returns string.length directly. Skips Intl.Segmenter, regex, and EAW lookup entirely. 61x faster for short ASCII, the most common input type.

  2. stripAnsi guard — check string.includes('\x1B') || string.includes('\x9B') before calling stripAnsi. Avoids the overhead of strip-ansi's regex on strings that contain no ANSI escapes. 14x faster for ANSI-free short strings.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions