Make runewidth treat ambiguous rune as short and fix ui display

Yang Zhang created

Change summary

util/text/left_padded.go      | 9 ++++++++-
util/text/left_padded_test.go | 6 +++---
util/text/text.go             | 7 +++++++
3 files changed, 18 insertions(+), 4 deletions(-)

Detailed changes

util/text/left_padded.go 🔗

@@ -7,6 +7,13 @@ import (
 	"strings"
 )
 
+// Force runewidth not to treat ambiguous runes as wide chars, so that things
+// like unicode ellipsis/up/down/left/right glyphs can have correct runewidth
+// and can be displayed correctly in terminals.
+func init() {
+	runewidth.DefaultCondition.EastAsianWidth = false
+}
+
 // LeftPadMaxLine pads a string on the left by a specified amount and pads the
 // string on the right to fill the maxLength
 func LeftPadMaxLine(text string, length, leftPad int) string {
@@ -15,7 +22,7 @@ func LeftPadMaxLine(text string, length, leftPad int) string {
 	scrWidth := runewidth.StringWidth(text)
 	// truncate and ellipse if needed
 	if scrWidth+leftPad > length {
-		rightPart = runewidth.Truncate(text, length-leftPad, "...")
+		rightPart = runewidth.Truncate(text, length-leftPad, "…")
 	} else if scrWidth+leftPad < length {
 		rightPart = runewidth.FillRight(text, length-leftPad)
 	}

util/text/left_padded_test.go 🔗

@@ -16,7 +16,7 @@ func TestLeftPadMaxLine(t *testing.T) {
 		},
 		{
 			"foofoofoo",
-			"f...",
+			"foo…",
 			4,
 			0,
 		},
@@ -28,13 +28,13 @@ func TestLeftPadMaxLine(t *testing.T) {
 		},
 		{
 			"foo",
-			"  ...",
+			"  f…",
 			4,
 			2,
 		},
 		{
 			"foofoofoo",
-			"  f...",
+			"  foo…",
 			6,
 			2,
 		},

util/text/text.go 🔗

@@ -6,6 +6,13 @@ import (
 	"unicode/utf8"
 )
 
+// Force runewidth not to treat ambiguous runes as wide chars, so that things
+// like unicode ellipsis/up/down/left/right glyphs can have correct runewidth
+// and can be displayed correctly in terminals.
+func init() {
+	runewidth.DefaultCondition.EastAsianWidth = false
+}
+
 // Wrap a text for an exact line size
 // Handle properly terminal color escape code
 func Wrap(text string, lineWidth int) (string, int) {