ainame/swift-displaywidth
wcwidth implementation with the latest Unicode spec
Why use this?
Instead of this library, there's wcwidth imported with import Darwin, import Musl, or import Glibc.
- https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/wcwidth.3.html
- https://www.gnu.org/software/gnulib/manual/html_node/wcwidth.html
- https://git.musl-libc.org/cgit/musl/tree/src/ctype/wcwidth.c
If that meets your requirements, you should just use it. However, this project has following superior points.
- Portable/Cross-platform implementation that doesn't require a C library nor even Foundation
- Up-to-date Unicode spec
- Better support of Unicode grapheme clusters
- Swift-friendly API
Usage
Add to your Package.swift:
dependencies: [
.package(url: "https://github.com/ainame/swift-displaywidth", from: "0.1.0")
]Then:
import DisplayWidth
// call as function
let baseDisplayWidth = DisplayWidth()
baseDisplayWidth("A") // 1
baseDisplayWidth("あ") // 2
baseDisplayWidth("👩💻") // 2
baseDisplayWidth("e\u{0301}") // 1 (e + combining acute)
// If your environment treat ambiguous chars as full-width,
// you can set this option.
let ambiguousWidth = DisplayWidth(treatAmbiguousAsFullWidth: true)import DisplayWidth
// ANSI escape sequences can be ignored during string measurement.
let ansiAwareDisplayWidth = DisplayWidth(stripsANSI: true)
ansiAwareDisplayWidth("\u{001B}[31mhello\u{001B}[0m") // 5
// Tabs can advance to the next tab stop every 4 columns.
let tabStopsDisplayWidth = DisplayWidth(tab: .tabStops(4))
tabStopsDisplayWidth("a\tb") // 5
// Or each tab can count as a fixed number of spaces.
let fixedTabsDisplayWidth = DisplayWidth(tab: .fixedSpaces(3))
fixedTabsDisplayWidth("a\tb") // 5stripsANSI and tab affect string measurement only. Character and scalar measurement keep their existing behavior. DisplayWidth.Tab.tabStops(n) uses terminal-style tab stops, while .fixedSpaces(n) counts each tab as exactly n columns. For example, with 3, "a\tb" is width 4 with .tabStops(3) and width 5 with .fixedSpaces(3).
Diagram with 4:
.tabStops(4)
tab stops: 4, 8, 12, ...
"a\tb" = 1 + 3 + 1 = 5
"ab\tb" = 2 + 2 + 1 = 5
"abcd\tb" = 4 + 4 + 1 = 9
.fixedSpaces(4)
every tab = 4
"a\tb" = 1 + 4 + 1 = 6
"ab\tb" = 2 + 4 + 1 = 7
"abcd\tb" = 4 + 4 + 1 = 9Reference: Tab stop
Links
- https://man7.org/linux/man-pages/man3/wcwidth.3.html
- Other langs
Python https://github.com/jquast/wcwidth Go https://github.com/mattn/go-runewidth/ * JS https://github.com/komagata/eastasianwidth/
- https://emonkak.pages.dev/articles/wcwidth/
* This project (to avoid using wcwidth(3)) is against to this blog post but I took ideas around full-width symbols
Package Metadata
Repository: ainame/swift-displaywidth
Stars: 4
Forks: 0
Open issues: 0
Default branch: main
Primary language: swift
License: MIT
Topics: swift, tui, unicode
README: README.md