Skip to content

Commit

Permalink
Fixed StringWidth() implementation by using proper Unicode grapheme c…
Browse files Browse the repository at this point in the history
…luster segmentation. Fixes #28
  • Loading branch information
Oliver committed Aug 29, 2019
1 parent 703b5e6 commit d3f4cc2
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 36 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
module github.com/mattn/go-runewidth

go 1.9

require github.com/rivo/uniseg v0.1.0
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
49 changes: 15 additions & 34 deletions runewidth.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@ package runewidth

import (
"os"

"github.com/rivo/uniseg"
)

var (
// EastAsianWidth will be set true if the current locale is CJK
EastAsianWidth bool

// ZeroWidthJoiner is flag to set to use UTR#51 ZWJ
ZeroWidthJoiner bool

// DefaultCondition is a condition in current locale
DefaultCondition = &Condition{}
)
Expand All @@ -28,7 +27,6 @@ func handleEnv() {
}
// update DefaultCondition
DefaultCondition.EastAsianWidth = EastAsianWidth
DefaultCondition.ZeroWidthJoiner = ZeroWidthJoiner
}

type interval struct {
Expand Down Expand Up @@ -806,15 +804,13 @@ var neutral = table{

// Condition have flag EastAsianWidth whether the current locale is CJK or not.
type Condition struct {
EastAsianWidth bool
ZeroWidthJoiner bool
EastAsianWidth bool
}

// NewCondition return new instance of Condition which is current locale.
func NewCondition() *Condition {
return &Condition{
EastAsianWidth: EastAsianWidth,
ZeroWidthJoiner: ZeroWidthJoiner,
EastAsianWidth: EastAsianWidth,
}
}

Expand All @@ -833,35 +829,20 @@ func (c *Condition) RuneWidth(r rune) int {
}
}

func (c *Condition) stringWidth(s string) (width int) {
for _, r := range []rune(s) {
width += c.RuneWidth(r)
}
return width
}

func (c *Condition) stringWidthZeroJoiner(s string) (width int) {
r1, r2 := rune(0), rune(0)
for _, r := range []rune(s) {
if r == 0xFE0E || r == 0xFE0F {
continue
}
w := c.RuneWidth(r)
if r2 == 0x200D && inTables(r, emoji) && inTables(r1, emoji) {
w = 0
}
width += w
r1, r2 = r2, r
}
return width
}

// StringWidth return width as you can see
func (c *Condition) StringWidth(s string) (width int) {
if c.ZeroWidthJoiner {
return c.stringWidthZeroJoiner(s)
g := uniseg.NewGraphemes(s)
for g.Next() {
var chWidth int
for _, r := range g.Runes() {
chWidth = RuneWidth(r)
if chWidth > 0 {
break // Our best guess at this point is to use the width of the first non-zero-width rune.
}
}
width += chWidth
}
return c.stringWidth(s)
return
}

// Truncate return string truncated with w cells
Expand Down
3 changes: 1 addition & 2 deletions runewidth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ func TestStringWidth(t *testing.T) {
c.EastAsianWidth = true
for _, tt := range stringwidthtests {
if out := c.StringWidth(tt.in); out != tt.eaout {
t.Errorf("StringWidth(%q) = %d, want %d", tt.in, out, tt.eaout)
t.Errorf("StringWidth(%q) = %d, want %d (EA)", tt.in, out, tt.eaout)
}
}
}
Expand Down Expand Up @@ -378,7 +378,6 @@ func TestEnv(t *testing.T) {

func TestZeroWidthJointer(t *testing.T) {
c := NewCondition()
c.ZeroWidthJoiner = true

var tests = []struct {
in string
Expand Down

0 comments on commit d3f4cc2

Please sign in to comment.