Skip to content

refactor!: measure display width via breakword instead of wcwidth - #27

Merged
tecfu merged 6 commits into
masterfrom
breakword-width
Sep 20, 2026
Merged

tecfu merged 6 commits into
masterfrom
breakword-width

Conversation

@tecfu

@tecfu tecfu commented Sep 20, 2026

Copy link
Copy Markdown
Owner

Why

wcwidth@1.x ships a stale, hand-maintained East Asian Width table. breakword (post tcfu/breakword#22) removed its own wcwidth dependency in favor of a generated Unicode-18.0.0 W/F table plus UAX #51 Emoji_Presentation, with explicit zero-width rules. Depending on breakword for width instead of duplicating that table keeps both packages consistent — one width policy, one generated table, one place to regenerate.

Requires the public width export: tecfu/breakword#24. That PR must merge and publish as 2.1.0 before this can be merged/released.

What

  • package.json: wcwidth → breakword@^2.1.0
  • src/main.ts: wcwidth(string) replaced by breakword.width(char) summed per code point; per-character chunking calls breakword.width directly
  • types/wcwidth.d.ts → types/breakword.d.ts (same shim pattern)

Behavior changes

Width policy differences that surface in output:

  • U+26A1 ⚡ (and friends that breakword scores 2 where wcwidth 1.x said 1) now wrap as 2 cells. Test 18 (LordPablo⚡️ @ width 10) expectation updated: 11 cells → the emoji moves to its own line. This matches how modern terminals actually render it.
  • Known per-code-point approximation carried over from breakword: ZWJ emoji sequences (👨‍👩‍👧) count as their members (see breakword eslint-ignore masks undeclared result variable #21). Fine for wrapping; revisit if it bites.

Tests

npm test — 25 passing. Breakword was installed via npm install ../breakword --no-save for local verification; CI/merge needs 2.1.0 published.

Note

npm run lint is broken independently of this change (.eslintrc.js lacks root: true, so ESLint 8 cascades past the repo to a stray ~/Documents/.eslintrc.json requiring @nx/eslint-plugin). Not touched here.

Drops the wcwidth dependency; width comes from breakword.width()
(public export, PR tecfu/breakword#24), which ships its own generated
East Asian Width + Emoji_Presentation table with no deps.

Behavior change: code points wcwidth 1.x scored 1 but breakword scores
2 (e.g. U+26A1 high voltage) now wrap as 2 cells. Test 18 expectation
updated accordingly.

- package.json: wcwidth -> breakword ^2.1.0
- types/wcwidth.d.ts -> types/breakword.d.ts
- main.ts: string width summed per code point via breakword.width
breakword@2.1.0 declares engines >=22; declare the same floor instead
of claiming support we do not control. CI matrix trimmed to 22/24/26.
@tecfu

tecfu commented Sep 20, 2026

Copy link
Copy Markdown
Owner Author

Unblocked — merge-ready.

The gating dependency has shipped: breakword 2.1.0 is merged and published (dist-tags.latest = 2.1.0, verified against the npm tarball: module.exports.width present).

Re-verified against the published package (fresh registry install, no local symlinks):

  • npm ls breakword → breakword@2.1.0
  • npm test — build + 25 passing
  • Input contract holds: width() accepts a string of zero or one code point; this PR only ever passes single code points from [...input] spreads.

Also pushed 43cf017 — chore: require Node.js >=22: breakword@2.1.0 declares engines: >=22, so smartwrap now declares the same floor instead of claiming >=14 support it can't honor under engine-strict. README and the CI matrix (14–20 dropped) updated to match.

Under Breaking changes in 3.0.0: width now comes from breakword.width()
(Unicode 18 generated table + Emoji_Presentation); code points wcwidth
1.x scored 1 but measure 2 (e.g. U+26A1) now wrap wider.
@tecfu
tecfu merged commit 711ad9d into master Sep 20, 2026
4 checks passed
tecfu added a commit that referenced this pull request Sep 20, 2026
Version bump for the breakword switch (PR #27): display width now
measured by breakword.width() instead of wcwidth, plus the engines
floor (Node >=22). Published as v4.0.0.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant