vendor: github.com/mattn/go-runewidth v0.0.24

- Optimize EastAsian RuneWidth with precomputed width table

full diff: https://github.com/mattn/go-runewidth/compare/v0.0.23...v0.0.24

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn
2026-06-09 16:58:46 +02:00
parent e8f837ba7f
commit a9c82c0a9f
5 changed files with 147 additions and 39 deletions
+1 -1
View File
@@ -28,7 +28,7 @@ require (
github.com/google/go-cmp v0.7.0
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/google/uuid v1.6.0
github.com/mattn/go-runewidth v0.0.23
github.com/mattn/go-runewidth v0.0.24
github.com/moby/go-archive v0.2.0
github.com/moby/moby/api v1.54.2
github.com/moby/moby/client v0.4.1
+2 -2
View File
@@ -106,8 +106,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/mattn/go-runewidth v0.0.23 h1:7ykA0T0jkPpzSvMS5i9uoNn2Xy3R383f9HDx3RybWcw=
github.com/mattn/go-runewidth v0.0.23/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
github.com/mattn/go-runewidth v0.0.24 h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/ay2DU=
github.com/mattn/go-runewidth v0.0.24/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
+25
View File
@@ -0,0 +1,25 @@
# Security Policy
## Supported Versions
The following versions of go-runewidth are currently supported with
security updates.
| Version | Supported |
| -------- | ------------------ |
| 0.0.23 | :white_check_mark: |
| < 0.0.23 | :x: |
## Reporting a Vulnerability
If you discover a security vulnerability in go-runewidth, please report it
privately via GitHub's "Report a vulnerability" feature on the Security tab
of the repository (https://github.com/mattn/go-runewidth/security), or by
emailing the maintainer at mattn.jp@gmail.com.
Please include a description of the issue, reproduction steps, and the
affected version. You can expect an initial response within one week. If
the vulnerability is accepted, a fix will be prepared and a new release
will be published; you will be credited in the release notes unless you
request otherwise. If the report is declined, you will receive an
explanation of the reasoning.
+118 -35
View File
@@ -2,6 +2,7 @@ package runewidth
import (
"os"
"sort"
"strings"
"unicode/utf8"
@@ -25,13 +26,19 @@ var (
)
var (
zerowidth table // combining + nonprint merged for faster zero-width lookup
widewidth table // ambiguous + doublewidth merged for EA path
zerowidth table // combining + nonprint merged for faster zero-width lookup
widewidth table // ambiguous + doublewidth merged for EA path
eastAsianWidth widthTable
eastAsianWidth0 [0x300]byte
)
func init() {
zerowidth = mergeIntervals(combining, nonprint)
widewidth = mergeIntervals(ambiguous, doublewidth)
eastAsianWidth = makeWidthTable(zerowidth, widewidth)
for r := range eastAsianWidth0 {
eastAsianWidth0[r] = byte(runeWidthEastAsian(rune(r)))
}
handleEnv()
}
@@ -90,6 +97,14 @@ type interval struct {
type table []interval
type widthInterval struct {
first rune
last rune
width byte
}
type widthTable []widthInterval
func inTable(r rune, t table) bool {
if r < t[0].first {
return false
@@ -116,6 +131,71 @@ func inTable(r rune, t table) bool {
return false
}
func makeWidthTable(zero, two table) widthTable {
wt := make(widthTable, 0, len(zero)+len(two))
zi := 0
for _, iv := range two {
start := iv.first
for zi < len(zero) && zero[zi].last < start {
zi++
}
for i := zi; i < len(zero) && zero[i].first <= iv.last; i++ {
if start < zero[i].first {
wt = append(wt, widthInterval{start, zero[i].first - 1, 2})
}
if start <= zero[i].last {
start = zero[i].last + 1
}
if start > iv.last {
break
}
}
if start <= iv.last {
wt = append(wt, widthInterval{start, iv.last, 2})
}
}
for _, iv := range zero {
wt = append(wt, widthInterval{iv.first, iv.last, 0})
}
sort.Slice(wt, func(i, j int) bool {
return wt[i].first < wt[j].first
})
return wt
}
func inWidthTable(r rune, t widthTable) (int, bool) {
if r < t[0].first {
return 0, false
}
if r > t[len(t)-1].last {
return 0, false
}
bot := 0
top := len(t) - 1
for top >= bot {
mid := (bot + top) >> 1
switch {
case t[mid].last < r:
bot = mid + 1
case t[mid].first > r:
top = mid - 1
default:
return int(t[mid].width), true
}
}
return 0, false
}
func runeWidthEastAsian(r rune) int {
if w, ok := inWidthTable(r, eastAsianWidth); ok {
return w
}
return 1
}
var private = table{
{0x00E000, 0x00F8FF}, {0x0F0000, 0x0FFFFD}, {0x100000, 0x10FFFD},
}
@@ -153,13 +233,16 @@ func (c *Condition) RuneWidth(r rune) int {
}
// optimized version, verified by TestRuneWidthChecksums()
if !c.EastAsianWidth {
switch {
case r < 0x20:
if r < 0x20 {
return 0
case (r >= 0x7F && r <= 0x9F) || r == 0xAD: // nonprint
}
if (r >= 0x7F && r <= 0x9F) || r == 0xAD { // nonprint
return 0
case r < 0x300:
}
if r < 0x300 {
return 1
}
switch {
case inTable(r, zerowidth):
return 0
case inTable(r, doublewidth):
@@ -167,20 +250,18 @@ func (c *Condition) RuneWidth(r rune) int {
default:
return 1
}
} else {
switch {
case inTable(r, zerowidth):
return 0
case inTable(r, narrow):
return 1
case inTable(r, widewidth):
return 2
case !c.StrictEmojiNeutral && inTable(r, emoji):
return 2
default:
return 1
}
}
if r < 0x300 {
return int(eastAsianWidth0[r])
}
if w, ok := inWidthTable(r, eastAsianWidth); ok {
return w
}
if !c.StrictEmojiNeutral && inTable(r, emoji) {
return 2
}
return 1
}
// CreateLUT will create an in-memory lookup table of 557056 bytes for faster operation.
@@ -206,6 +287,13 @@ func (c *Condition) CreateLUT() {
// StringWidth return width as you can see
func (c *Condition) StringWidth(s string) (width int) {
if len(s) == 1 {
b := s[0]
if b < 0x20 || b == 0x7F {
return 0
}
return 1
}
if len(s) > 0 && len(s) <= utf8.UTFMax {
r, size := utf8.DecodeRuneInString(s)
if size == len(s) {
@@ -213,15 +301,19 @@ func (c *Condition) StringWidth(s string) (width int) {
}
}
// ASCII fast path: no grapheme clustering needed for pure ASCII
if isAllASCII(s) {
for i := 0; i < len(s); i++ {
b := s[i]
if b >= 0x20 && b != 0x7F {
width++
}
for i := 0; i < len(s); i++ {
b := s[i]
if b >= 0x80 {
goto graphemes
}
if b >= 0x20 && b != 0x7F {
width++
}
return
}
return
graphemes:
width = 0
g := graphemes.FromString(s)
for g.Next() {
var chWidth int
@@ -236,15 +328,6 @@ func (c *Condition) StringWidth(s string) (width int) {
return
}
func isAllASCII(s string) bool {
for i := 0; i < len(s); i++ {
if s[i] >= 0x80 {
return false
}
}
return true
}
// Truncate return string truncated with w cells
func (c *Condition) Truncate(s string, w int, tail string) string {
if c.StringWidth(s) <= w {
+1 -1
View File
@@ -156,7 +156,7 @@ github.com/klauspost/compress/internal/le
github.com/klauspost/compress/internal/snapref
github.com/klauspost/compress/zstd
github.com/klauspost/compress/zstd/internal/xxhash
# github.com/mattn/go-runewidth v0.0.23
# github.com/mattn/go-runewidth v0.0.24
## explicit; go 1.20
github.com/mattn/go-runewidth
# github.com/moby/docker-image-spec v1.3.1