Skip to content

Commit

Permalink
provide way to override east-asian rune width calc (addr. #220) (#223)
Browse files Browse the repository at this point in the history
  • Loading branch information
jedib0t committed Aug 22, 2022
1 parent b3bddf1 commit 782119a
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 1 deletion.
24 changes: 23 additions & 1 deletion text/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ const (
EscapeStopRune = 'm'
)

// RuneWidth stuff
var (
rwCondition = runewidth.NewCondition()
)

// InsertEveryN inserts the rune every N characters in the string. For ex.:
// InsertEveryN("Ghost", '-', 1) == "G-h-o-s-t"
// InsertEveryN("Ghost", '-', 2) == "Gh-os-t"
Expand Down Expand Up @@ -79,6 +84,23 @@ func LongestLineLen(str string) int {
return maxLength
}

// OverrideRuneWidthEastAsianWidth can *probably* help with alignment, and
// length calculation issues when dealing with Unicode character-set and a
// non-English language set in the LANG variable.
//
// Set this to 'false' to force the "runewidth" library to pretend to deal with
// English character-set. Be warned that if the text/content you are dealing
// with contains East Asian character-set, this may result in unexpected
// behavior.
//
// References:
// * https://github.com/mattn/go-runewidth/issues/64#issuecomment-1221642154
// * https://github.com/jedib0t/go-pretty/issues/220
// * https://github.com/jedib0t/go-pretty/issues/204
func OverrideRuneWidthEastAsianWidth(val bool) {
rwCondition.EastAsianWidth = val
}

// Pad pads the given string with as many characters as needed to make it as
// long as specified (maxLen). This function does not count escape sequences
// while calculating length of the string. Ex.:
Expand Down Expand Up @@ -132,7 +154,7 @@ func RuneCount(str string) int {
// RuneWidth('︿') == 2
// RuneWidth(0x27) == 0
func RuneWidth(r rune) int {
return runewidth.RuneWidth(r)
return rwCondition.RuneWidth(r)
}

// RuneWidthWithoutEscSequences is similar to RuneWidth, except for the fact
Expand Down
21 changes: 21 additions & 0 deletions text/string_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,27 @@ func TestLongestLineLen(t *testing.T) {
assert.Equal(t, 7, LongestLineLen("\x1b[33mMother\x1b[0m\nOf\nDragons"))
}

func TestOverrideRuneWidthEastAsianWidth(t *testing.T) {
originalValue := rwCondition.EastAsianWidth
defer func() {
rwCondition.EastAsianWidth = originalValue
}()

OverrideRuneWidthEastAsianWidth(true)
assert.Equal(t, 2, RuneWidthWithoutEscSequences("╋"))
OverrideRuneWidthEastAsianWidth(false)
assert.Equal(t, 1, RuneWidthWithoutEscSequences("╋"))

// Note for posterity. We want the length of the box drawing character to
// be reported as 1. However, with an environment where LANG is set to
// something like 'zh_CN.UTF-8', the value being returned is 2, which breaks
// text alignment/padding logic in this library.
//
// If a future version of runewidth is able to address this internally and
// return 1 for the above, the function being tested can be marked for
// deprecation.
}

func ExamplePad() {
fmt.Printf("%#v\n", Pad("Ghost", 0, ' '))
fmt.Printf("%#v\n", Pad("Ghost", 3, ' '))
Expand Down

0 comments on commit 782119a

Please sign in to comment.