mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-10 07:36:27 -04:00
Add a truncation function that puts the ellipsis in the middle
TruncateWithEllipsis cuts off the end of a string, which is the wrong end for a path: what distinguishes two paths is often the last segment, and it is the one thing the reader wants to see. Keep both ends and put the ellipsis between them. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3c4d3920a3
commit
2135e928db
|
|
@ -199,6 +199,49 @@ func TruncateWithEllipsis(str string, limit int) string {
|
|||
return truncatedStr + "…"
|
||||
}
|
||||
|
||||
// TruncateWithEllipsisInMiddle returns a string, truncated to a certain width,
|
||||
// with an ellipsis in the middle. Use it where the end of the string is as
|
||||
// informative as its beginning, e.g. for paths.
|
||||
func TruncateWithEllipsisInMiddle(str string, limit int) string {
|
||||
if StringWidth(str) <= limit {
|
||||
return str
|
||||
}
|
||||
if limit <= 2 {
|
||||
return strings.Repeat(".", limit)
|
||||
}
|
||||
|
||||
clusters := []string{}
|
||||
widths := []int{}
|
||||
graphemes := uniseg.NewGraphemes(str)
|
||||
for graphemes.Next() {
|
||||
clusters = append(clusters, graphemes.Str())
|
||||
widths = append(widths, graphemes.Width())
|
||||
}
|
||||
|
||||
// One column goes to the ellipsis; the rest is split between the two ends,
|
||||
// with the odd one going to the front.
|
||||
remaining := limit - 1
|
||||
frontLimit := (remaining + 1) / 2
|
||||
|
||||
front := 0
|
||||
frontWidth := 0
|
||||
for front < len(clusters) && frontWidth+widths[front] <= frontLimit {
|
||||
frontWidth += widths[front]
|
||||
front++
|
||||
}
|
||||
|
||||
// Whatever the front didn't use, e.g. because a wide grapheme didn't fit
|
||||
// into it, is available to the back.
|
||||
back := len(clusters)
|
||||
backWidth := 0
|
||||
for back > front && backWidth+widths[back-1] <= remaining-frontWidth {
|
||||
backWidth += widths[back-1]
|
||||
back--
|
||||
}
|
||||
|
||||
return strings.Join(clusters[:front], "") + "…" + strings.Join(clusters[back:], "")
|
||||
}
|
||||
|
||||
func SafeTruncate(str string, limit int) string {
|
||||
if len(str) > limit {
|
||||
return str[0:limit]
|
||||
|
|
|
|||
|
|
@ -162,6 +162,38 @@ func TestTruncateWithEllipsis(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestTruncateWithEllipsisInMiddle(t *testing.T) {
|
||||
type scenario struct {
|
||||
str string
|
||||
limit int
|
||||
expected string
|
||||
}
|
||||
|
||||
scenarios := []scenario{
|
||||
{"hello world !", 0, ""},
|
||||
{"hello world !", 1, "."},
|
||||
{"hello world !", 2, ".."},
|
||||
{"hello world !", 3, "h…!"},
|
||||
{"hello world !", 4, "he…!"},
|
||||
{"hello world !", 5, "he… !"},
|
||||
{"hello world !", 12, "hello …rld !"},
|
||||
{"hello world !", 13, "hello world !"},
|
||||
{"hello world !", 14, "hello world !"},
|
||||
// A wide grapheme that doesn't fit into the front leaves its column to
|
||||
// the back
|
||||
{"大大大大", 5, "大…大"},
|
||||
{"大大大大", 7, "大…大大"},
|
||||
{"大大大大", 8, "大大大大"},
|
||||
{"大大大大", 2, ".."},
|
||||
{"大大大大", 1, "."},
|
||||
{"大大大大", 0, ""},
|
||||
}
|
||||
|
||||
for _, s := range scenarios {
|
||||
assert.EqualValues(t, s.expected, TruncateWithEllipsisInMiddle(s.str, s.limit))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenderDisplayStrings(t *testing.T) {
|
||||
type scenario struct {
|
||||
input [][]string
|
||||
|
|
|
|||
Loading…
Reference in a new issue