Repository: Evertras/bubble-table
Pull request #45 (2022-03-08 13:38:41)

Fix string length limiting for double-width characters
https://github.com/Evertras/bubble-table/issues/40
Implemented the go-runewidth library to manage runes truncation
Added tests for japanese characters

Evertras: You can run `make lint` to check linting locally.  It looks like it's whining about a function length and I think this is a false positive, because this is just adding straightforward test cases.  To get around this, you'll want to add comments like in https://github.com/Evertras/bubble-table/blob/main/table/dimensions_test.go#L10-L11

```golang
// This function is only long because of repetitive test definitions, this is fine
// nolint: funlen
```

Put that immediately in front of the test function and the linting should then pass.
RobertKwiatkowski: Sorry, wait a second let me change commit author because accidentally used my company one.
Evertras: > Unfortunately I can't due to usage of windows. I guess it's high time to use the WSL 😛

Ahh, yeah, this is built on both a Mac and a Linux machine, no Windows.  Definitely recommend WSL in general for the general dev ecosystem.

And no worries, I also just noticed the commit author was slightly different than your user.  LGTM though, will merge once you give the clear.
Evertras: LGTM, thanks for the contribution!
RobertKwiatkowski: Well, it's easy to forget about the global git config...

Commit&author looks goods now, feel free to merge it.

Btw. It was really nice to cooperate with you, thank for all the insights :).

Patch:
diff --git a/examples/flex/main.go b/examples/flex/main.go
index abc5c9d..63bdc54 100644
--- a/examples/flex/main.go
+++ b/examples/flex/main.go
@@ -36,11 +36,9 @@ func NewModel() Model {
 				columnKeyDescription: "Super zappy mouse, handle with care",
 			}),
 			table.NewRow(table.RowData{
-				columnKeyName:    "Charmander",
-				columnKeyElement: "Fire",
-				// TODO: Fix double width string length limiting!
-				//columnKeyDescription: "直立した恐竜のような身体と、尻尾の先端に常に燃えている炎が特徴。",
-				columnKeyDescription: "Lots of fire",
+				columnKeyName:        "Charmander",
+				columnKeyElement:     "Fire",
+				columnKeyDescription: "直立した恐竜のような身体と、尻尾の先端に常に燃えている炎が特徴。",
 			}),
 		}),
 	}
diff --git a/table/strlimit.go b/table/strlimit.go
index 274216f..8cd4be3 100644
--- a/table/strlimit.go
+++ b/table/strlimit.go
@@ -1,12 +1,13 @@
 package table
 
+import "github.com/mattn/go-runewidth"
+
 func limitStr(str string, maxLen int) string {
 	if maxLen == 0 {
 		return ""
 	}
-
-	if len([]rune(str)) > maxLen {
-		return string([]rune(str)[:maxLen-1]) + "…"
+	if runewidth.StringWidth(str) > maxLen {
+		return runewidth.Truncate(str, maxLen-1, "") + "…"
 	}
 
 	return str


Test patch:
diff --git a/table/strlimit_test.go b/table/strlimit_test.go
index df440fd..0ed5730 100644
--- a/table/strlimit_test.go
+++ b/table/strlimit_test.go
@@ -7,6 +7,8 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
+// This function is only long because of repetitive test definitions, this is fine
+// nolint: funlen
 func TestLimitStr(t *testing.T) {
 	tests := []struct {
 		name     string
@@ -56,6 +58,18 @@ func TestLimitStr(t *testing.T) {
 			max:      2,
 			expected: "✓…",
 		},
+		{
+			name:     "Unicode japenese equal",
+			input:    "直立",
+			max:      5,
+			expected: "直立",
+		},
+		{
+			name:     "Unicode japenese truncated",
+			input:    "直立した恐",
+			max:      5,
+			expected: "直立…",
+		},
 	}
 
 	for _, test := range tests {