Skip to content

Commit 28e47f5

Browse files
committed
Release v2.1.0: Styled output with Lip Gloss
Full visual polish across all commands: - New styles: BranchStyle (cyan), HashStyle (yellow), AuthorStyle (magenta), DateStyle (gray), FileStyle (blue), AddStyle (green), DelStyle (red) - Styled tables with colored headers and unicode separators - context: colored labels, branch names, working tree status - graph: styled tree connectors, colored HEAD/merged/orphan indicators - drift: green ahead, red behind, colored commit list - recap: colored hashes, times, author names - who: "You" in green bold, emails dimmed, dates styled - view: colored PR status, branch names, current marker - handoff: colored stat line (green insertions, red deletions) - undo: styled "Detected:" and command display - switch: colored branch picker - shelf: styled stash list - nuke: colored merge warnings - sweep: styled branch names and summary
1 parent dc8d6c7 commit 28e47f5

16 files changed

Lines changed: 145 additions & 88 deletions

File tree

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.0.1
1+
2.1.0

cmd/context.go

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,37 +32,39 @@ func runContext(cmd *cobra.Command, args []string) error {
3232
branch, err := git.CurrentBranch()
3333
if err != nil {
3434
shortHash := git.RunUnchecked("rev-parse", "--short", "HEAD")
35-
fmt.Printf("Branch: (detached HEAD at %s)\n", shortHash)
35+
fmt.Printf("%s (detached HEAD at %s)\n", ui.LabelStyle.Render("Branch:"), ui.HashStyle.Render(shortHash))
3636
ui.PrintWarning("You are in detached HEAD state.")
3737
} else {
38-
fmt.Printf("Branch: %s\n", branch)
38+
fmt.Printf("%s %s\n", ui.LabelStyle.Render("Branch:"), ui.BranchStyle.Render(branch))
3939

4040
// Tracking
4141
tracking := git.RunUnchecked("rev-parse", "--abbrev-ref", branch+"@{upstream}")
4242
if tracking != "" {
4343
ahead, behind := git.AheadBehind(branch, tracking)
4444
if ahead == 0 && behind == 0 {
45-
fmt.Printf("Tracking: %s (up to date)\n", tracking)
45+
fmt.Printf("%s %s %s\n", ui.LabelStyle.Render("Tracking:"), tracking, ui.DimStyle.Render("(up to date)"))
4646
} else {
4747
parts := ""
4848
if ahead > 0 {
49-
parts += fmt.Sprintf("%d ahead", ahead)
49+
parts += ui.AddStyle.Render(fmt.Sprintf("%d ahead", ahead))
5050
}
5151
if behind > 0 {
5252
if parts != "" {
5353
parts += ", "
5454
}
55-
parts += fmt.Sprintf("%d behind", behind)
55+
parts += ui.DelStyle.Render(fmt.Sprintf("%d behind", behind))
5656
}
57-
fmt.Printf("Tracking: %s (%s)\n", tracking, parts)
57+
fmt.Printf("%s %s (%s)\n", ui.LabelStyle.Render("Tracking:"), tracking, parts)
5858
}
5959
}
6060

6161
// vs HEAD branch
6262
headBranch := git.HeadBranch()
6363
if branch != headBranch {
6464
ahead, behind := git.AheadBehind(branch, headBranch)
65-
fmt.Printf("vs %s: %d ahead, %d behind\n", headBranch, ahead, behind)
65+
aheadStr := ui.AddStyle.Render(fmt.Sprintf("%d ahead", ahead))
66+
behindStr := ui.DelStyle.Render(fmt.Sprintf("%d behind", behind))
67+
fmt.Printf("%s %s, %s\n", ui.LabelStyle.Render(fmt.Sprintf("vs %s:", headBranch)), aheadStr, behindStr)
6668
}
6769
}
6870

@@ -71,17 +73,17 @@ func runContext(cmd *cobra.Command, args []string) error {
7173
// Last commit
7274
_, shortHash, message, _, date := git.LastCommit()
7375
if shortHash != "" {
74-
fmt.Printf("Last commit: %s \"%s\" (%s)\n", shortHash, message, git.TimeAgo(date))
76+
fmt.Printf("%s %s \"%s\" %s\n", ui.LabelStyle.Render("Last commit:"), ui.HashStyle.Render(shortHash), message, ui.DateStyle.Render("("+git.TimeAgo(date)+")"))
7577
} else {
76-
fmt.Println("Last commit: No commits yet")
78+
fmt.Printf("%s %s\n", ui.LabelStyle.Render("Last commit:"), ui.DimStyle.Render("No commits yet"))
7779
}
7880

7981
fmt.Println()
8082

8183
// Working tree
8284
status := git.RunUnchecked("status", "--porcelain")
8385
if status == "" {
84-
fmt.Println("Working tree: clean")
86+
fmt.Printf("%s %s\n", ui.LabelStyle.Render("Working tree:"), ui.SuccessStyle.Render("clean"))
8587
} else {
8688
modified, staged, untracked := 0, 0, 0
8789
for _, line := range strings.Split(status, "\n") {
@@ -99,15 +101,15 @@ func runContext(cmd *cobra.Command, args []string) error {
99101
}
100102
}
101103
}
102-
fmt.Println("Working tree:")
104+
fmt.Println(ui.LabelStyle.Render("Working tree:"))
103105
if modified > 0 {
104-
fmt.Printf(" Modified: %d file%s\n", modified, ui.Plural(modified))
106+
fmt.Printf(" %s %s\n", ui.LabelStyle.Render("Modified:"), ui.WarningStyle.Render(fmt.Sprintf("%d file%s", modified, ui.Plural(modified))))
105107
}
106108
if staged > 0 {
107-
fmt.Printf(" Staged: %d file%s\n", staged, ui.Plural(staged))
109+
fmt.Printf(" %s %s\n", ui.LabelStyle.Render("Staged:"), ui.AddStyle.Render(fmt.Sprintf("%d file%s", staged, ui.Plural(staged))))
108110
}
109111
if untracked > 0 {
110-
fmt.Printf(" Untracked: %d file%s\n", untracked, ui.Plural(untracked))
112+
fmt.Printf(" %s %s\n", ui.LabelStyle.Render("Untracked:"), ui.DimStyle.Render(fmt.Sprintf("%d file%s", untracked, ui.Plural(untracked))))
111113
}
112114
}
113115

@@ -116,9 +118,9 @@ func runContext(cmd *cobra.Command, args []string) error {
116118
// Stash
117119
stashCount := git.StashCount()
118120
if stashCount > 0 {
119-
fmt.Printf("Stash: %d entr%s\n", stashCount, ui.PluralIES(stashCount))
121+
fmt.Printf("%s %d entr%s\n", ui.LabelStyle.Render("Stash:"), stashCount, ui.PluralIES(stashCount))
120122
} else {
121-
fmt.Println("Stash: empty")
123+
fmt.Printf("%s %s\n", ui.LabelStyle.Render("Stash:"), ui.DimStyle.Render("empty"))
122124
}
123125

124126
// Active operations

cmd/drift.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@ func runDrift(cmd *cobra.Command, args []string) error {
7575
return nil
7676
}
7777

78-
fmt.Printf("%s is %d ahead, %d behind %s\n\n", ui.BoldStyle.Render(current), ahead, behind, ui.BoldStyle.Render(target))
78+
aheadStr := ui.AddStyle.Render(fmt.Sprintf("%d ahead", ahead))
79+
behindStr := ui.DelStyle.Render(fmt.Sprintf("%d behind", behind))
80+
fmt.Printf("%s is %s, %s %s\n\n", ui.BranchStyle.Render(current), aheadStr, behindStr, ui.BranchStyle.Render(target))
7981

8082
maxCommits := 20
8183
if full {
@@ -122,6 +124,6 @@ func showCommits(from, to string, limit int) {
122124
continue
123125
}
124126
age := git.TimeAgo(parts[1])
125-
fmt.Printf(" %s %-12s %s\n", ui.DimStyle.Render(parts[0]), age, parts[3])
127+
fmt.Printf(" %s %s %s\n", ui.HashStyle.Render(parts[0]), ui.DateStyle.Render(fmt.Sprintf("%-12s", age)), parts[3])
126128
}
127129
}

cmd/graph.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,42 +54,42 @@ func runGraph(cmd *cobra.Command, args []string) error {
5454
}
5555

5656
func renderNode(node *stack.BranchNode, prefix string, isLast bool) {
57-
connector := "|-- "
57+
connector := ui.DimStyle.Render("|-- ")
5858
if isLast {
59-
connector = "`-- "
59+
connector = ui.DimStyle.Render("`-- ")
6060
}
6161

6262
// Status indicators
6363
indicators := ""
6464
if node.IsHead {
65-
indicators += " " + ui.SuccessStyle.Bold(true).Render("* HEAD")
65+
indicators += " " + ui.HeadMarker.Render("* HEAD")
6666
}
6767
if node.IsMerged {
6868
indicators += " " + ui.DimStyle.Render("+ merged")
6969
} else if node.IsOrphan {
7070
indicators += " " + ui.WarningStyle.Render("! orphaned")
7171
} else if node.Ahead > 0 || node.Behind > 0 {
72-
indicators += fmt.Sprintf(" (+%d/-%d)", node.Ahead, node.Behind)
72+
indicators += " " + ui.BranchStyle.Render(fmt.Sprintf("(+%d/-%d)", node.Ahead, node.Behind))
7373
}
7474

7575
// Branch name color
7676
var name string
7777
switch {
7878
case node.IsHead:
79-
name = ui.SuccessStyle.Bold(true).Render(node.Name)
79+
name = ui.HeadMarker.Render(node.Name)
8080
case node.IsMerged:
8181
name = ui.DimStyle.Render(node.Name)
8282
case node.IsOrphan:
8383
name = ui.WarningStyle.Render(node.Name)
8484
default:
85-
name = ui.InfoStyle.Render(node.Name)
85+
name = ui.BranchStyle.Render(node.Name)
8686
}
8787

8888
fmt.Printf("%s%s%s%s\n", prefix, connector, name, indicators)
8989

90-
childPrefix := prefix + " "
91-
if !isLast {
92-
childPrefix = prefix + "| "
90+
childPrefix := prefix + ui.DimStyle.Render("|") + " "
91+
if isLast {
92+
childPrefix = prefix + " "
9393
}
9494
for i, child := range node.Children {
9595
renderNode(child, childPrefix, i == len(node.Children)-1)

cmd/handoff.go

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -128,22 +128,38 @@ func runHandoff(cmd *cobra.Command, args []string) error {
128128
func formatHandoffPlain(branch, base string, isStacked bool, commits []handoffCommit, stat string, files []string) string {
129129
var b strings.Builder
130130
if isStacked {
131-
fmt.Fprintf(&b, "%s (on %s)\n", branch, base)
131+
fmt.Fprintf(&b, "%s (on %s)\n", ui.BranchStyle.Render(branch), ui.DimStyle.Render(base))
132132
} else {
133-
fmt.Fprintf(&b, "%s (vs %s)\n", branch, base)
133+
fmt.Fprintf(&b, "%s (vs %s)\n", ui.BranchStyle.Render(branch), ui.DimStyle.Render(base))
134134
}
135-
fmt.Fprintf(&b, "\nCommits (%d):\n", len(commits))
135+
fmt.Fprintf(&b, "\n%s\n", ui.BoldStyle.Render(fmt.Sprintf("Commits (%d):", len(commits))))
136136
for _, c := range commits {
137-
fmt.Fprintf(&b, " %s %s\n", c.hash, c.msg)
137+
fmt.Fprintf(&b, " %s %s\n", ui.HashStyle.Render(c.hash), c.msg)
138138
}
139-
fmt.Fprintf(&b, "\n%s\n", stat)
140-
fmt.Fprintf(&b, "\nFiles:\n")
139+
// Color the stat summary line
140+
colored := colorStatLine(stat)
141+
fmt.Fprintf(&b, "\n%s\n", colored)
142+
fmt.Fprintf(&b, "\n%s\n", ui.BoldStyle.Render("Files:"))
141143
for _, f := range files {
142-
fmt.Fprintf(&b, " %s\n", f)
144+
fmt.Fprintf(&b, " %s\n", ui.FileStyle.Render(f))
143145
}
144146
return b.String()
145147
}
146148

149+
func colorStatLine(stat string) string {
150+
// Color insertions green and deletions red in stat summary
151+
parts := strings.Split(stat, ",")
152+
for i, p := range parts {
153+
trimmed := strings.TrimSpace(p)
154+
if strings.Contains(trimmed, "insertion") {
155+
parts[i] = " " + ui.AddStyle.Render(trimmed)
156+
} else if strings.Contains(trimmed, "deletion") {
157+
parts[i] = " " + ui.DelStyle.Render(trimmed)
158+
}
159+
}
160+
return strings.Join(parts, ",")
161+
}
162+
147163
func formatHandoffMD(branch, base string, commits []handoffCommit, stat string, files []string) string {
148164
var b strings.Builder
149165
fmt.Fprintf(&b, "## %s\n", branch)

cmd/nuke.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ func runNuke(cmd *cobra.Command, args []string) error {
7474
for _, b := range branches {
7575
local := git.BranchExists(b)
7676
remote := git.RemoteBranchExists(b)
77-
actions = append(actions, fmt.Sprintf(" %s Local: %v Remote: %v Merged: %v", b, local, remote, mergedSet[b]))
77+
actions = append(actions, fmt.Sprintf(" %s Local: %v Remote: %v Merged: %v", ui.BranchStyle.Render(b), local, remote, mergedSet[b]))
7878
}
79-
actions = append(actions, "", fmt.Sprintf("Would delete: %d branches", len(branches)))
79+
actions = append(actions, "", fmt.Sprintf("Would delete: %s", ui.WarningStyle.Render(fmt.Sprintf("%d branches", len(branches)))))
8080
ui.PrintDryRun(actions)
8181
return nil
8282
}
@@ -86,7 +86,7 @@ func runNuke(cmd *cobra.Command, args []string) error {
8686
for _, b := range branches {
8787
if !mergedSet[b] {
8888
hasUnmerged = true
89-
fmt.Printf("\n %s is NOT merged into %s.\n", b, head)
89+
fmt.Printf("\n %s is %s into %s.\n", ui.BranchStyle.Render(b), ui.ErrorStyle.Bold(true).Render("NOT merged"), ui.BranchStyle.Render(head))
9090
}
9191
children := stack.Children(b)
9292
if len(children) > 0 {
@@ -140,7 +140,7 @@ func nukeOrphans(cmd *cobra.Command) error {
140140
fmt.Println()
141141
fmt.Println(ui.BoldStyle.Render("Orphaned branches:"))
142142
for _, o := range tree.Orphans {
143-
fmt.Println(" " + o.Name)
143+
fmt.Println(" " + ui.BranchStyle.Render(o.Name))
144144
}
145145
fmt.Println()
146146

cmd/recap.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func recapAuthor(author, since string, days, limit int, repoName string) error {
9797
currentDate = dateLabel
9898
fmt.Printf(" %s\n", ui.BoldStyle.Render(dateLabel+":"))
9999
}
100-
fmt.Printf(" %s %s %s\n", ui.DimStyle.Render(parts[0]), t.Format("15:04"), parts[2])
100+
fmt.Printf(" %s %s %s\n", ui.HashStyle.Render(parts[0]), ui.DateStyle.Render(t.Format("15:04")), parts[2])
101101
}
102102

103103
fmt.Printf("\n %d commits\n", commitCount)
@@ -144,10 +144,16 @@ func recapAll(since string, days, limit int, repoName string) error {
144144
if author == currentUser {
145145
display = "You"
146146
}
147-
fmt.Printf(" %s (%d commit%s):\n", ui.BoldStyle.Render(display), len(commits), ui.Plural(len(commits)))
147+
displayStyled := ui.BoldStyle.Render(display)
148+
if display == "You" {
149+
displayStyled = ui.SuccessStyle.Bold(true).Render(display)
150+
} else {
151+
displayStyled = ui.AuthorStyle.Bold(true).Render(display)
152+
}
153+
fmt.Printf(" %s (%d commit%s):\n", displayStyled, len(commits), ui.Plural(len(commits)))
148154
for _, c := range commits {
149155
t, _ := time.Parse(time.RFC3339, c.date)
150-
fmt.Printf(" %s %s %s\n", ui.DimStyle.Render(c.hash), t.Format("15:04"), c.msg)
156+
fmt.Printf(" %s %s %s\n", ui.HashStyle.Render(c.hash), ui.DateStyle.Render(t.Format("15:04")), c.msg)
151157
}
152158
fmt.Println()
153159
total += len(commits)

cmd/shelf.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,11 @@ func runShelfList(cmd *cobra.Command, args []string) error {
157157
for _, s := range stashes {
158158
b := s.branch
159159
if b == "" {
160-
b = "--"
160+
b = ui.DimStyle.Render("--")
161+
} else {
162+
b = ui.BranchStyle.Render(b)
161163
}
162-
rows = append(rows, []string{fmt.Sprintf("%d", s.index), s.time, b, s.msg})
164+
rows = append(rows, []string{ui.HashStyle.Render(fmt.Sprintf("%d", s.index)), ui.DateStyle.Render(s.time), b, s.msg})
163165
}
164166
ui.PrintTable([]string{"#", "Age", "Branch", "Message"}, rows, "")
165167
return nil
@@ -181,7 +183,7 @@ func runShelfClear(cmd *cobra.Command, args []string) error {
181183

182184
fmt.Printf("\nThis will permanently delete ALL %d stashes:\n\n", len(stashes))
183185
for _, s := range stashes {
184-
fmt.Printf(" %s %-15s %s\n", s.id, s.time, s.msg)
186+
fmt.Printf(" %s %s %s\n", ui.HashStyle.Render(s.id), ui.DateStyle.Render(fmt.Sprintf("%-15s", s.time)), s.msg)
185187
}
186188
fmt.Println()
187189

cmd/sweep.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,26 +97,30 @@ func runSweep(cmd *cobra.Command, args []string) error {
9797
if len(merged) > 0 {
9898
fmt.Println(ui.BoldStyle.Render("Merged branches (safe to delete):"))
9999
for _, b := range merged {
100-
fmt.Printf(" %s\n", b)
100+
fmt.Printf(" %s\n", ui.BranchStyle.Render(b))
101101
}
102102
fmt.Println()
103103
}
104104
if len(squashMerged) > 0 {
105105
fmt.Println(ui.BoldStyle.Render("Likely squash-merged branches:"))
106106
for _, b := range squashMerged {
107-
fmt.Printf(" %s\n", b)
107+
fmt.Printf(" %s\n", ui.BranchStyle.Render(b))
108108
}
109109
fmt.Println()
110110
}
111111
if len(staleRefs) > 0 {
112112
fmt.Println(ui.BoldStyle.Render("Stale remote tracking refs:"))
113113
for _, r := range staleRefs {
114-
fmt.Printf(" %s\n", r)
114+
fmt.Printf(" %s\n", ui.DimStyle.Render(r))
115115
}
116116
fmt.Println()
117117
}
118118

119-
fmt.Printf("Summary: %d merged, %d likely squash-merged, %d stale refs\n\n", len(merged), len(squashMerged), len(staleRefs))
119+
fmt.Printf("%s %s merged, %s likely squash-merged, %s stale refs\n\n",
120+
ui.BoldStyle.Render("Summary:"),
121+
ui.BoldStyle.Render(fmt.Sprintf("%d", len(merged))),
122+
ui.BoldStyle.Render(fmt.Sprintf("%d", len(squashMerged))),
123+
ui.BoldStyle.Render(fmt.Sprintf("%d", len(staleRefs))))
120124

121125
if dryRun {
122126
fmt.Printf("%s would delete %d branches, %d stale refs\n", ui.WarningStyle.Render("DRY RUN"), len(merged)+len(squashMerged), len(staleRefs))

cmd/switch.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ func pickBranch(branches []branchInfo) string {
134134
} else {
135135
for i, b := range filtered {
136136
age := git.TimeAgo(b.date)
137-
fmt.Printf(" %3d %-40s %-15s %s\n", i+1, b.name, age, b.author)
137+
fmt.Printf(" %s %-40s %s %s\n", ui.DimStyle.Render(fmt.Sprintf("%3d", i+1)), ui.BranchStyle.Render(b.name), ui.DateStyle.Render(fmt.Sprintf("%-15s", age)), ui.AuthorStyle.Render(b.author))
138138
}
139139
}
140140

0 commit comments

Comments
 (0)