text: fix handling of wide characters

Michael Muré created

Change summary

util/text/text.go      | 14 +++++++++++---
util/text/text_test.go | 30 +++++++++++++++++-------------
2 files changed, 28 insertions(+), 16 deletions(-)

Detailed changes

util/text/text.go 🔗

@@ -3,6 +3,8 @@ package text
 import (
 	"bytes"
 	"strings"
+
+	"github.com/mattn/go-runewidth"
 )
 
 // Wrap a text for an exact line size
@@ -116,7 +118,7 @@ func wordLen(word string) int {
 		}
 
 		if !escape {
-			length++
+			length += runewidth.RuneWidth(rune(char))
 		}
 
 		if char == 'm' {
@@ -143,11 +145,17 @@ func splitWord(word string, length int) (string, string) {
 			escape = true
 		}
 
+		width := runewidth.RuneWidth(r)
+		if width+added > length {
+			// wide character made the length overflow
+			break
+		}
+
 		result = append(result, r)
 
 		if !escape {
-			added++
-			if added == length {
+			added += width
+			if added >= length {
 				break
 			}
 		}

util/text/text_test.go 🔗

@@ -89,16 +89,16 @@ func TestWrap(t *testing.T) {
 			" This\nis a\nlist:\n\n\n    *\nfoo\n    *\nbar\n\n\n    *\nbaz\nBAM\n",
 			6,
 		},
-		// Handle chinese
+		// Handle chinese (wide characters)
 		{
 			"婞一枳郲逴靲屮蜧曀殳,掫乇峔掮傎溒兀緉冘仜。",
-			"婞一枳郲逴靲屮蜧曀殳,掫\n乇峔掮傎溒兀緉冘仜。",
+			"婞一枳郲逴靲\n屮蜧曀殳,掫\n乇峔掮傎溒兀\n緉冘仜。",
 			12,
 		},
 		// Handle chinese with colors
 		{
 			"婞一枳郲逴\x1b[31m靲屮蜧曀殳,掫乇峔掮傎溒\x1b[0m兀緉冘仜。",
-			"婞一枳郲逴\x1b[31m靲屮蜧曀殳,掫\n乇峔掮傎溒\x1b[0m兀緉冘仜。",
+			"婞一枳郲逴\x1b[31m靲\n屮蜧曀殳,掫\n乇峔掮傎溒\x1b[0m兀\n緉冘仜。",
 			12,
 		},
 	}
@@ -134,10 +134,14 @@ func TestWrapLeftPadded(t *testing.T) {
 		// Handle Chinese
 		{
 			"婞一枳郲逴靲屮蜧曀殳,掫乇峔掮傎溒兀緉冘仜。郼牪艽螗媷錵朸一詅掜豗怙刉笀丌,楀棶乇矹迡搦囷圣亍昄漚粁仈祂。覂一洳袶揙楱亍滻瘯毌,掗屮柅軡菵腩乜榵毌夯。勼哻怌婇怤灟葠雺奷朾恦扰衪岨坋誁乇芚誙腞。冇笉妺悆浂鱦賌廌灱灱觓坋佫呬耴跣兀枔蓔輈。嵅咍犴膰痭瘰机一靬涽捊矷尒玶乇,煚塈丌岰陊鉖怞戉兀甿跾觓夬侄。棩岧汌橩僁螗玎一逭舴圂衪扐衲兀,嵲媕亍衩衿溽昃夯丌侄蒰扂丱呤。毰侘妅錣廇螉仴一暀淖蚗佶庂咺丌,輀鈁乇彽洢溦洰氶乇构碨洐巿阹。",
-			`    婞一枳郲逴靲屮蜧曀殳,掫乇峔掮傎溒兀緉冘仜。郼牪艽螗媷錵朸一詅掜豗怙刉笀丌,楀棶乇矹迡搦囷圣亍昄漚粁仈祂。覂一
-    洳袶揙楱亍滻瘯毌,掗屮柅軡菵腩乜榵毌夯。勼哻怌婇怤灟葠雺奷朾恦扰衪岨坋誁乇芚誙腞。冇笉妺悆浂鱦賌廌灱灱觓坋佫呬
-    耴跣兀枔蓔輈。嵅咍犴膰痭瘰机一靬涽捊矷尒玶乇,煚塈丌岰陊鉖怞戉兀甿跾觓夬侄。棩岧汌橩僁螗玎一逭舴圂衪扐衲兀,嵲
-    媕亍衩衿溽昃夯丌侄蒰扂丱呤。毰侘妅錣廇螉仴一暀淖蚗佶庂咺丌,輀鈁乇彽洢溦洰氶乇构碨洐巿阹。`,
+			`    婞一枳郲逴靲屮蜧曀殳,掫乇峔掮傎溒兀緉冘仜。郼牪艽螗媷
+    錵朸一詅掜豗怙刉笀丌,楀棶乇矹迡搦囷圣亍昄漚粁仈祂。覂
+    一洳袶揙楱亍滻瘯毌,掗屮柅軡菵腩乜榵毌夯。勼哻怌婇怤灟
+    葠雺奷朾恦扰衪岨坋誁乇芚誙腞。冇笉妺悆浂鱦賌廌灱灱觓坋
+    佫呬耴跣兀枔蓔輈。嵅咍犴膰痭瘰机一靬涽捊矷尒玶乇,煚塈
+    丌岰陊鉖怞戉兀甿跾觓夬侄。棩岧汌橩僁螗玎一逭舴圂衪扐衲
+    兀,嵲媕亍衩衿溽昃夯丌侄蒰扂丱呤。毰侘妅錣廇螉仴一暀淖
+    蚗佶庂咺丌,輀鈁乇彽洢溦洰氶乇构碨洐巿阹。`,
 			59, 4,
 		},
 	}
@@ -182,12 +186,12 @@ func TestWordLen(t *testing.T) {
 		// Handle chinese
 		{
 			"快檢什麼望對",
-			6,
+			12,
 		},
 		// Handle chinese with colors
 		{
 			"快\x1b[31m檢什麼\x1b[0m望對",
-			6,
+			12,
 		},
 	}
 
@@ -245,18 +249,18 @@ func TestSplitWord(t *testing.T) {
 		// Handle chinese
 		{
 			"快檢什麼望對",
-			2,
+			4,
 			"快檢", "什麼望對",
 		},
 		{
 			"快檢什麼望對",
-			3,
-			"快檢什", "麼望對",
+			5,
+			"快檢", "什麼望對",
 		},
 		// Handle chinese with colors
 		{
 			"快\x1b[31m檢什麼\x1b[0m望對",
-			2,
+			4,
 			"快\x1b[31m檢", "什麼\x1b[0m望對",
 		},
 	}