Skip to content

Commit d1b1d50

Browse files
committed
fix: wrap long project/branch names instead of truncating
1 parent 1fa2d65 commit d1b1d50

File tree

2 files changed

+69
-27
lines changed

2 files changed

+69
-27
lines changed

format.go

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,22 @@ func shortProject(slug string) string {
9999
if s == "" {
100100
s = slug
101101
}
102-
if len(s) > 40 {
103-
s = "..." + s[len(s)-37:]
104-
}
105102
return s
106103
}
107104

105+
func wrapName(name string, chunkSize int) []string {
106+
if name == "" {
107+
return nil
108+
}
109+
var chunks []string
110+
for len(name) > chunkSize {
111+
chunks = append(chunks, name[:chunkSize])
112+
name = name[chunkSize:]
113+
}
114+
chunks = append(chunks, name)
115+
return chunks
116+
}
117+
108118
type OutputOptions struct {
109119
ShowDaily bool
110120
ShowMonthly bool
@@ -547,23 +557,26 @@ func printProjectBreakdown(data *ParseResult, opts OutputOptions) {
547557
}
548558
sort.Slice(sorted, func(i, j int) bool { return sorted[i].bucket.Cost > sorted[j].bucket.Cost })
549559

550-
first := true
551-
for _, m := range sorted {
552-
b := m.bucket
560+
names := wrapName(name, 30)
561+
for i, m := range sorted {
553562
n := ""
554-
if first {
555-
n = name
556-
if len(n) > 35 {
557-
n = n[:32] + "..."
558-
}
563+
if i < len(names) {
564+
n = names[i]
559565
}
566+
b := m.bucket
560567
fmt.Printf(" %-35s %s %7d %s\n",
561568
n, cyan.Sprintf("%-16s", shortModel(m.name)),
562569
b.Requests, colorCost(b.Cost, 10))
563-
first = false
570+
}
571+
for i := len(sorted); i < len(names)-1; i++ {
572+
fmt.Printf(" %s\n", names[i])
573+
}
574+
subtotalName := ""
575+
if len(names) > len(sorted) {
576+
subtotalName = names[len(names)-1]
564577
}
565578
fmt.Printf(" %-35s %-16s %7s %s\n",
566-
"", "SUBTOTAL", "", colorCost(proj.total, 10))
579+
subtotalName, "SUBTOTAL", "", colorCost(proj.total, 10))
567580
fmt.Println()
568581
}
569582
}
@@ -604,23 +617,26 @@ func printBranchBreakdown(data *ParseResult, opts OutputOptions) {
604617
}
605618
sort.Slice(sorted, func(i, j int) bool { return sorted[i].bucket.Cost > sorted[j].bucket.Cost })
606619

607-
firstBranch := true
608-
for _, m := range sorted {
609-
b := m.bucket
610-
bn := ""
611-
if firstBranch {
612-
bn = br.branch
613-
if len(bn) > 30 {
614-
bn = bn[:27] + "..."
615-
}
620+
names := wrapName(br.branch, 25)
621+
for i, m := range sorted {
622+
n := ""
623+
if i < len(names) {
624+
n = names[i]
616625
}
626+
b := m.bucket
617627
fmt.Printf(" %-30s %s %7d %s\n",
618-
bn, cyan.Sprintf("%-16s", shortModel(m.name)),
628+
n, cyan.Sprintf("%-16s", shortModel(m.name)),
619629
b.Requests, colorCost(b.Cost, 10))
620-
firstBranch = false
630+
}
631+
for i := len(sorted); i < len(names)-1; i++ {
632+
fmt.Printf(" %s\n", names[i])
633+
}
634+
subtotalName := ""
635+
if len(names) > len(sorted) {
636+
subtotalName = names[len(names)-1]
621637
}
622638
fmt.Printf(" %-30s %-16s %7s %s\n",
623-
"", "SUBTOTAL", "", colorCost(br.total, 10))
639+
subtotalName, "SUBTOTAL", "", colorCost(br.total, 10))
624640
fmt.Println()
625641
}
626642
}

format_test.go

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ func TestShortProject(t *testing.T) {
5656
{"simple-project", "simple/project"},
5757
// Double hyphens collapsed
5858
{"a--b", "a/b"},
59-
// Truncation at 40 chars
60-
{"a-very-long-project-name-that-exceeds-the-forty-character-limit", "...hat-exceeds-the-forty-character-limit"},
59+
// Long names preserved
60+
{"a-very-long-project-name-that-exceeds-the-forty-character-limit", "a/very-long-project-name-that-exceeds-the-forty-character-limit"},
6161
// Empty slug returns original
6262
{"", ""},
6363
}
@@ -69,6 +69,32 @@ func TestShortProject(t *testing.T) {
6969
}
7070
}
7171

72+
func TestWrapName(t *testing.T) {
73+
tests := []struct {
74+
name string
75+
chunk int
76+
expected []string
77+
}{
78+
{"short", 10, []string{"short"}},
79+
{"abcdefghij", 10, []string{"abcdefghij"}},
80+
{"abcdefghijklmnopqrst", 10, []string{"abcdefghij", "klmnopqrst"}},
81+
{"abcdefghijklmnopqrstuvwxyz12345", 10, []string{"abcdefghij", "klmnopqrst", "uvwxyz1234", "5"}},
82+
{"", 10, nil},
83+
}
84+
for _, tt := range tests {
85+
got := wrapName(tt.name, tt.chunk)
86+
if len(got) != len(tt.expected) {
87+
t.Errorf("wrapName(%q, %d) len = %d, want %d", tt.name, tt.chunk, len(got), len(tt.expected))
88+
continue
89+
}
90+
for i := range got {
91+
if got[i] != tt.expected[i] {
92+
t.Errorf("wrapName(%q, %d)[%d] = %q, want %q", tt.name, tt.chunk, i, got[i], tt.expected[i])
93+
}
94+
}
95+
}
96+
}
97+
7298
func TestFmtDuration(t *testing.T) {
7399
tests := []struct {
74100
input time.Duration

0 commit comments

Comments
 (0)