63 lines
1 KiB
Go
63 lines
1 KiB
Go
package text
|
|
|
|
import (
|
|
"golang.org/x/text/width"
|
|
)
|
|
|
|
// DisplayWidth calculates what the rendered width of a string may be
|
|
func DisplayWidth(s string) int {
|
|
w := 0
|
|
for _, r := range s {
|
|
w += runeDisplayWidth(r)
|
|
}
|
|
return w
|
|
}
|
|
|
|
const (
|
|
ellipsisWidth = 3
|
|
minWidthForEllipsis = 5
|
|
)
|
|
|
|
// Truncate shortens a string to fit the maximum display width
|
|
func Truncate(max int, s string) string {
|
|
w := DisplayWidth(s)
|
|
if w <= max {
|
|
return s
|
|
}
|
|
|
|
useEllipsis := false
|
|
if max >= minWidthForEllipsis {
|
|
useEllipsis = true
|
|
max -= ellipsisWidth
|
|
}
|
|
|
|
cw := 0
|
|
ri := 0
|
|
for _, r := range s {
|
|
rw := runeDisplayWidth(r)
|
|
if cw+rw > max {
|
|
break
|
|
}
|
|
cw += rw
|
|
ri++
|
|
}
|
|
|
|
res := string([]rune(s)[:ri])
|
|
if useEllipsis {
|
|
res += "..."
|
|
}
|
|
if cw < max {
|
|
// compensate if truncating a wide character left an odd space
|
|
res += " "
|
|
}
|
|
return res
|
|
}
|
|
|
|
func runeDisplayWidth(r rune) int {
|
|
switch width.LookupRune(r).Kind() {
|
|
case width.EastAsianWide, width.EastAsianAmbiguous, width.EastAsianFullwidth:
|
|
return 2
|
|
default:
|
|
return 1
|
|
}
|
|
}
|