1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-11-25 22:32:13 +02:00

Use utils.StringWidth to optimize rendering performance

runewidth.StringWidth is an expensive call, even if the input string is pure
ASCII. Improve this by providing a wrapper that short-circuits the call to len
if the input is ASCII.

Benchmark results show that for non-ASCII strings it makes no noticable
difference, but for ASCII strings it provides a more than 200x speedup.

BenchmarkStringWidthAsciiOriginal-10            718135       1637 ns/op
BenchmarkStringWidthAsciiOptimized-10        159197538          7.545 ns/op
BenchmarkStringWidthNonAsciiOriginal-10         486290       2391 ns/op
BenchmarkStringWidthNonAsciiOptimized-10        502286       2383 ns/op
This commit is contained in:
Stefan Haller
2024-06-22 13:34:15 +02:00
parent a67eda39a5
commit 26132cf5bd
5 changed files with 50 additions and 14 deletions

View File

@@ -3,6 +3,7 @@ package utils
import (
"fmt"
"strings"
"unicode"
"github.com/mattn/go-runewidth"
"github.com/samber/lo"
@@ -21,10 +22,22 @@ type ColumnConfig struct {
Alignment Alignment
}
func StringWidth(s string) int {
// We are intentionally not using a range loop here, because that would
// convert the characters to runes, which is unnecessary work in this case.
for i := 0; i < len(s); i++ {
if s[i] > unicode.MaxASCII {
return runewidth.StringWidth(s)
}
}
return len(s)
}
// WithPadding pads a string as much as you want
func WithPadding(str string, padding int, alignment Alignment) string {
uncoloredStr := Decolorise(str)
width := runewidth.StringWidth(uncoloredStr)
width := StringWidth(uncoloredStr)
if padding < width {
return str
}
@@ -144,7 +157,7 @@ func getPadWidths(stringArrays [][]string) []int {
return MaxFn(stringArrays, func(stringArray []string) int {
uncoloredStr := Decolorise(stringArray[i])
return runewidth.StringWidth(uncoloredStr)
return StringWidth(uncoloredStr)
})
})
}
@@ -161,7 +174,7 @@ func MaxFn[T any](items []T, fn func(T) int) int {
// TruncateWithEllipsis returns a string, truncated to a certain length, with an ellipsis
func TruncateWithEllipsis(str string, limit int) string {
if runewidth.StringWidth(str) > limit && limit <= 2 {
if StringWidth(str) > limit && limit <= 2 {
return strings.Repeat(".", limit)
}
return runewidth.Truncate(str, limit, "…")