go-runewidth

Computes the terminal cell width of runes and strings, handling CJK, emoji, and combining characters correctly.

Library
Go
vv0.0.30
723 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
72 /100 Good
Development Activity 92
Maintenance 52
Community 64
Maturity 60
Momentum 20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
76 /100 Good
Architecture 85
Code Quality 85
Innovation 80
Learning Curve 55

go-runewidth is a small, dependency-light Go library that answers a deceptively hard question: how many terminal columns does this string actually occupy? A plain rune count is wrong the moment a string contains East Asian wide characters, emoji, zero-width combining marks, or grapheme clusters made of several runes that render as one glyph. go-runewidth implements the Unicode East Asian Width property (UTR #11) plus practical heuristics for ambiguous-width and emoji runes, and exposes both single-rune (RuneWidth) and full-string (StringWidth) width calculations.

Beyond raw measurement, it ships the string-manipulation primitives that terminal UIs actually need: Truncate, TruncateLeft, and TruncatePrefix cut a string to fit a target cell width without splitting a grapheme cluster in half, Wrap line-wraps text by visual width rather than byte or rune count, and FillLeft/FillRight pad strings for column alignment. A Condition struct lets callers override the East-Asian-width and strict-emoji-neutral flags per call site (instead of relying on the auto-detected locale), and an optional CreateLUT() precomputes a full lookup table for hot paths that call width functions at high frequency.

What You Get

  • StringWidth/RuneWidth functions that return true terminal cell width per Unicode TR#11, not a naive rune or byte count
  • Grapheme-cluster-aware Truncate, TruncateLeft, and TruncatePrefix that never split a combined character in half
  • Wrap, FillLeft, and FillRight helpers for building aligned, column-based terminal output
  • A Condition type for per-call-site control of East-Asian-width and emoji-neutral behavior, independent of the detected locale
  • Automatic locale detection (IsEastAsian) via POSIX locale env vars or the Windows console output codepage
  • An optional CreateLUT() precomputed lookup table for width-sensitive hot paths, plus a lazily-built internal LUT so importing the package costs no memory unless width functions are actually called

Common Use Cases

  • Terminal UI / TUI toolkits computing box-border and column widths so layouts stay aligned when text contains CJK or emoji
  • CLI tools rendering formatted tables or progress bars over mixed-width Unicode content
  • Truncating long strings (filenames, commit messages, chat text) to fit a fixed terminal width without corrupting a multi-rune glyph
  • Wrapping paragraph text in a terminal app by actual visual width instead of rune count

Under The Hood

Architecture The package is a flat, single-package library: runewidth.go holds the primary API and orchestration logic, runewidth_table.go holds generated static Unicode interval tables (private, nonprint, combining, doublewidth, ambiguous, emoji, narrow, neutral) produced by script/generate.go’s go:generate directive pulling data from unicode.org, and runewidth_posix.go/runewidth_windows.go/runewidth_appengine.go/runewidth_js.go provide build-tag-gated platform implementations of IsEastAsian() (POSIX locale-env parsing vs. a Windows GetConsoleOutputCP syscall vs. no-op stubs). The core data flow merges the static interval tables into zerowidth/widewidth/eastAsianWidth tables lazily via sync.Once, consulted through binary search (inTable/inWidthTable) or a fully materialized two-plane byte lookup table (strictWidthLUT) that fills its low region eagerly at init and its high region lazily behind an atomic, acquire-semantics limit check — a documented concurrency invariant (see the comments around issue #104) that keeps plain package import cheap. Condition is the central strategy object encapsulating the EastAsianWidth/StrictEmojiNeutral flags and an optional precomputed combinedLut, with every package-level convenience function delegating to a shared DefaultCondition. Grapheme-aware operations delegate cluster segmentation to the external uax29/v2 dependency rather than iterating runes directly, so that dependency’s segmentation boundaries flow straight through to every width computation.

Tech Stack Pure Go, module targets Go 1.23, with a single external dependency (github.com/clipperhouse/uax29/v2) providing UAX #29 grapheme-cluster segmentation. Table generation is handled by a go generate-invoked script that fetches interval data from unicode.org and regenerates runewidth_table.go; there is no other build tooling. CI (GitHub Actions) runs go generate ./... followed by git diff --cached --exit-code to guarantee committed tables are never stale, then go test -cover and go test -bench, across a 3x3 matrix of Go 1.24/1.25/1.26 on Windows, macOS, and Linux runners, with coverage uploaded to Codecov.

Code Quality Testing is substantial for a library this size: table-driven tests verify SHA-256 checksums of every generated Unicode interval table to catch silent drift, cross-check the fast lookup-table path against the slow binary-search path for correctness, and exercise StringWidth/Truncate/Wrap across ASCII, CJK, and emoji inputs, plus locale-parsing edge cases on POSIX. Only the standard testing package is used — no external assertion library. Naming is idiomatic Go throughout, and comments are unusually precise about concurrency invariants (documenting exactly which regions of shared state may be read concurrently with a lazy build). There is no linter configuration beyond the generated-file diff check in CI, and error handling is minimal by design since width computation never fails.

API Design The public surface favors progressive disclosure: top-level functions (RuneWidth, StringWidth, Truncate, Wrap, FillLeft, FillRight) work with zero configuration for the common case — a single import and one function call — while advanced use cases construct a Condition to override locale detection per call site, or call CreateLUT() to trade memory for speed on hot paths, without any API redesign. Naming follows a consistent Verb+Modifier pattern (TruncateLeft, TruncatePrefix, FillLeft, FillRight), every exported symbol carries a doc comment, and deprecated fields (ZeroWidthJoiner) are marked with a clear migration note. The README itself is minimal (a single usage line), so onboarding relies on godoc rather than prose documentation.

Used by 5 apps in this directory

Go
80%
Apache 2.0

Dolt

Data Engineering · Databases · Developer Tools

24,532

The SQL database you can branch, merge, diff, and clone — Git for your data, MySQL-compatible and ready for multi-agent AI workflows.

View details
90
Repo Health
9
Technical
65
Dependency
Built with
Go 80%
Shell 19%
Updated 1 weeks ago
Go
86%
MIT

Hatchet

AI Development · Automation · Developer Tools

8,014

A Postgres-backed orchestration engine for background tasks, AI agents, and durable workflows that replaces Redis queues and multi-datastore durable execution platforms with a single self-hostable service.

View details
88
Repo Health
83
Technical
67
Dependency
Built with
Go 86%
Updated 5 days ago
Go
69%
MIT

Ollama

AI Development · Developer Tools

181,830

Run Llama, Gemma, DeepSeek, and other open LLMs on your own machine with one command and an OpenAI-compatible API.

View details
90
Repo Health
85
Technical
67
Dependency
Built with
Go 69%
C 22%
Updated 5 days ago
Go
90%
BSD 3

tau

Devops

5,174

Open-source, Git-native platform-as-a-service for building, deploying, and scaling fullstack apps on your own infrastructure with no DevOps required.

View details
80
Repo Health
82
Technical
64
Dependency
Built with
Go 90%
Updated 1 months ago
Go
99%
Apache 2.0

Tusk

AI Code Assistants · Developer Tools · Devops

143

Record live API traffic and replay it as deterministic, sandboxed tests, plus AI code review and unit test generation, all from one Go CLI built by YC W2024's Use-Tusk.

View details
43
Repo Health
77
Technical
76
Dependency
Built with
Go 99%
Updated 4 months ago

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers