Skip to content

Commit 782119a

Browse files
authored
provide way to override east-asian rune width calc (addr. #220) (#223)
1 parent b3bddf1 commit 782119a

File tree

2 files changed

+44
-1
lines changed

2 files changed

+44
-1
lines changed

text/string.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ const (
1616
EscapeStopRune = 'm'
1717
)
1818

19+
// RuneWidth stuff
20+
var (
21+
rwCondition = runewidth.NewCondition()
22+
)
23+
1924
// InsertEveryN inserts the rune every N characters in the string. For ex.:
2025
// InsertEveryN("Ghost", '-', 1) == "G-h-o-s-t"
2126
// InsertEveryN("Ghost", '-', 2) == "Gh-os-t"
@@ -79,6 +84,23 @@ func LongestLineLen(str string) int {
7984
return maxLength
8085
}
8186

87+
// OverrideRuneWidthEastAsianWidth can *probably* help with alignment, and
88+
// length calculation issues when dealing with Unicode character-set and a
89+
// non-English language set in the LANG variable.
90+
//
91+
// Set this to 'false' to force the "runewidth" library to pretend to deal with
92+
// English character-set. Be warned that if the text/content you are dealing
93+
// with contains East Asian character-set, this may result in unexpected
94+
// behavior.
95+
//
96+
// References:
97+
// * https://github.com/mattn/go-runewidth/issues/64#issuecomment-1221642154
98+
// * https://github.com/jedib0t/go-pretty/issues/220
99+
// * https://github.com/jedib0t/go-pretty/issues/204
100+
func OverrideRuneWidthEastAsianWidth(val bool) {
101+
rwCondition.EastAsianWidth = val
102+
}
103+
82104
// Pad pads the given string with as many characters as needed to make it as
83105
// long as specified (maxLen). This function does not count escape sequences
84106
// while calculating length of the string. Ex.:
@@ -132,7 +154,7 @@ func RuneCount(str string) int {
132154
// RuneWidth('︿') == 2
133155
// RuneWidth(0x27) == 0
134156
func RuneWidth(r rune) int {
135-
return runewidth.RuneWidth(r)
157+
return rwCondition.RuneWidth(r)
136158
}
137159

138160
// RuneWidthWithoutEscSequences is similar to RuneWidth, except for the fact

text/string_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,27 @@ func TestLongestLineLen(t *testing.T) {
8080
assert.Equal(t, 7, LongestLineLen("\x1b[33mMother\x1b[0m\nOf\nDragons"))
8181
}
8282

83+
func TestOverrideRuneWidthEastAsianWidth(t *testing.T) {
84+
originalValue := rwCondition.EastAsianWidth
85+
defer func() {
86+
rwCondition.EastAsianWidth = originalValue
87+
}()
88+
89+
OverrideRuneWidthEastAsianWidth(true)
90+
assert.Equal(t, 2, RuneWidthWithoutEscSequences("╋"))
91+
OverrideRuneWidthEastAsianWidth(false)
92+
assert.Equal(t, 1, RuneWidthWithoutEscSequences("╋"))
93+
94+
// Note for posterity. We want the length of the box drawing character to
95+
// be reported as 1. However, with an environment where LANG is set to
96+
// something like 'zh_CN.UTF-8', the value being returned is 2, which breaks
97+
// text alignment/padding logic in this library.
98+
//
99+
// If a future version of runewidth is able to address this internally and
100+
// return 1 for the above, the function being tested can be marked for
101+
// deprecation.
102+
}
103+
83104
func ExamplePad() {
84105
fmt.Printf("%#v\n", Pad("Ghost", 0, ' '))
85106
fmt.Printf("%#v\n", Pad("Ghost", 3, ' '))

0 commit comments

Comments
 (0)