Skip to content

Commit

Permalink
text: bug-fixes (#61)
Browse files Browse the repository at this point in the history
* text: fix RepeatAndTrim() for strings with Unicode chars; fixes #58
* text: fix WrapText() to work with escape sequences; fixes #59
  • Loading branch information
jedib0t committed Aug 21, 2018
1 parent 2d30ee9 commit c83e531
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 13 deletions.
30 changes: 30 additions & 0 deletions table/table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,23 @@ func TestTable_SetAllowedColumnLengths(t *testing.T) {
\-----v--------v-----------v------v---------/`
assert.Equal(t, []int{100, 100, 100, 100, 7}, table.allowedColumnLengths)
assert.Equal(t, expectedOut, table.Render())

table.AppendRow(
Row{20, "Jon", "Snow", 2000, text.FgHiRed.Sprint("You know nothing, Jon Snow!")},
)
expectedOut = "(-----^--------^-----------^------^---------)\n" +
"[< 1>|<Arya >|<Stark >|<3000>|< >]\n" +
"[< 20>|<Jon >|<Snow >|<2000>|<You kno>]\n" +
"[< >|< >|< >|< >|<w nothi>]\n" +
"[< >|< >|< >|< >|<ng, Jon>]\n" +
"[< >|< >|< >|< >|< Snow! >]\n" +
"[<300>|<Tyrion>|<Lannister>|<5000>|< >]\n" +
"[< 20>|<Jon >|<Snow >|<2000>|<\x1b[91mYou kno\x1b[0m>]\n" +
"[< >|< >|< >|< >|<\x1b[91mw nothi\x1b[0m>]\n" +
"[< >|< >|< >|< >|<\x1b[91mng, Jon\x1b[0m>]\n" +
"[< >|< >|< >|< >|<\x1b[91m Snow!\x1b[0m >]\n" +
"\\-----v--------v-----------v------v---------/"
assert.Equal(t, expectedOut, table.Render())
}

func TestTable_SetAllowedRowLength(t *testing.T) {
Expand Down Expand Up @@ -289,6 +306,19 @@ func TestTable_SetAutoIndex(t *testing.T) {
[< >|< >|< >|< >|< >|<This is known. >]
\---v-----v------------v-----------v--------v-----------------------------/`
assert.Equal(t, expectedOut, table.Render())

table.SetStyle(StyleLight)
expectedOut = `┌───┬─────┬────────────┬───────────┬────────┬─────────────────────────────┐
│ │ # │ FIRST NAME │ LAST NAME │ SALARY │ │
├───┼─────┼────────────┼───────────┼────────┼─────────────────────────────┤
│ 1 │ 1 │ Arya │ Stark │ 3000 │ │
│ 2 │ 20 │ Jon │ Snow │ 2000 │ You know nothing, Jon Snow! │
│ 3 │ 300 │ Tyrion │ Lannister │ 5000 │ │
│ 4 │ 0 │ Winter │ Is │ 0 │ Coming. │
│ │ │ │ │ │ The North Remembers! │
│ │ │ │ │ │ This is known. │
└───┴─────┴────────────┴───────────┴────────┴─────────────────────────────┘`
assert.Equal(t, expectedOut, table.Render())
}

func TestTable_SetCaption(t *testing.T) {
Expand Down
49 changes: 36 additions & 13 deletions text/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,11 @@ func InsertRuneEveryN(s string, r rune, n int) string {
func RepeatAndTrim(s string, maxRunes int) string {
if maxRunes == 0 {
return ""
} else if maxRunes == len(s) {
} else if maxRunes == utf8.RuneCountInString(s) {
return s
}
return TrimTextWithoutEscapeSeq(strings.Repeat(s, int(maxRunes/utf8.RuneCountInString(s))+1), maxRunes)
repeatedS := strings.Repeat(s, int(maxRunes/utf8.RuneCountInString(s))+1)
return TrimTextWithoutEscapeSeq(repeatedS, maxRunes)
}

// RuneCountWithoutEscapeSeq is similar to utf8.RuneCountInString, except for
Expand Down Expand Up @@ -187,26 +188,48 @@ func WrapText(s string, n int) string {
var out strings.Builder
sLen := utf8.RuneCountInString(s)
out.Grow(sLen + (sLen / n))
lineIdx, isEscSeq := 0, false
lineIdx, isEscSeq, lastEscSeq := 0, false, ""
for idx, c := range s {
if c == EscapeStartRune {
isEscSeq = true
lastEscSeq = ""
}

if !isEscSeq && lineIdx == n && c != '\n' {
out.WriteRune('\n')
lineIdx = 0
}
out.WriteRune(c)
if c == '\n' {
lineIdx = 0
} else if !isEscSeq && idx < sLen {
lineIdx++
if isEscSeq {
lastEscSeq += string(c)
}

wrapRune(sLen, n, idx, c, &lineIdx, isEscSeq, lastEscSeq, &out)

if isEscSeq && c == EscapeStopRune {
isEscSeq = false
}
if lastEscSeq == EscapeReset {
lastEscSeq = ""
}
}
if lastEscSeq != "" && lastEscSeq != EscapeReset {
out.WriteString(EscapeReset)
}
return out.String()
}

func wrapRune(sLen int, wrapLen int, idx int, c int32, lineIdx *int, isEscSeq bool, lastEscSeq string, out *strings.Builder) {
if !isEscSeq && *lineIdx == wrapLen && c != '\n' {
if lastEscSeq != "" {
out.WriteString(EscapeReset)
}
out.WriteRune('\n')
out.WriteString(lastEscSeq)
*lineIdx = 0
}
if c == '\n' && lastEscSeq != "" {
out.WriteString(EscapeReset)
}
out.WriteRune(c)
if c == '\n' {
out.WriteString(lastEscSeq)
*lineIdx = 0
} else if !isEscSeq && idx < sLen {
*lineIdx++
}
}
4 changes: 4 additions & 0 deletions text/string_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ func TestRepeatAndTrim(t *testing.T) {
assert.Equal(t, "Ghost", RepeatAndTrim("Ghost", 5))
assert.Equal(t, "GhostGh", RepeatAndTrim("Ghost", 7))
assert.Equal(t, "GhostGhost", RepeatAndTrim("Ghost", 10))
assert.Equal(t, "───", RepeatAndTrim("─", 3))
}

func TestRuneCountWithoutEscapeSeq(t *testing.T) {
Expand Down Expand Up @@ -72,6 +73,9 @@ func TestWrapText(t *testing.T) {
assert.Equal(t, "Jon\nSno\nw\n", WrapText("Jon\nSnow\n", 3))
assert.Equal(t, "\x1b[33mJon\x1b[0m\nSno\nw", WrapText("\x1b[33mJon\x1b[0m\nSnow", 3))
assert.Equal(t, "\x1b[33mJon\x1b[0m\nSno\nw\n", WrapText("\x1b[33mJon\x1b[0m\nSnow\n", 3))
assert.Equal(t, "\x1b[33mJon\x1b[0m\n\x1b[33m Sn\x1b[0m\n\x1b[33mow\x1b[0m", WrapText("\x1b[33mJon Snow\x1b[0m", 3))
assert.Equal(t, "\x1b[33mJon\x1b[0m\n\x1b[33m Sn\x1b[0m\n\x1b[33mow\x1b[0m\n\x1b[33m\x1b[0m", WrapText("\x1b[33mJon Snow\n", 3))
assert.Equal(t, "\x1b[33mJon\x1b[0m\n\x1b[33m Sn\x1b[0m\n\x1b[33mow\x1b[0m\n\x1b[33m\x1b[0m", WrapText("\x1b[33mJon Snow\n\x1b[0m", 3))

complexIn := "+---+------+-------+------+\n| 1 | Arya | Stark | 3000 |\n+---+------+-------+------+"
assert.Equal(t, complexIn, WrapText(complexIn, 27))
Expand Down

0 comments on commit c83e531

Please sign in to comment.