Skip to content

Commit aa656b0

Browse files
Merge pull request #40 from kaffarell/master
add NO_COLOR env variable to avoid ansi escape codes
2 parents d989273 + b989fa3 commit aa656b0

5 files changed

Lines changed: 101 additions & 32 deletions

File tree

internal/pretty/ansi.go

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,72 @@
11
// ANSI escape codes
22
package pretty
33

4-
const Reset string = "\x1b[0m"
4+
var colorEnabled = true
55

6-
const Green string = "\x1b[32m"
7-
const Red string = "\x1b[31m"
8-
const DefaultColor string = "\x1b[39m"
6+
// SetColorEnabled controls whether ANSI color codes are output
7+
func SetColorEnabled(enabled bool) {
8+
colorEnabled = enabled
9+
}
910

10-
const Dim string = "\x1b[2m"
11-
const Invert string = "\x1b[7m"
11+
// GetColorEnabled returns whether ANSI color codes are currently enabled
12+
func GetColorEnabled() bool {
13+
return colorEnabled
14+
}
1215

16+
const resetCode string = "\x1b[0m"
17+
const greenCode string = "\x1b[32m"
18+
const redCode string = "\x1b[31m"
19+
const defaultColorCode string = "\x1b[39m"
20+
const dimCode string = "\x1b[2m"
21+
const invertCode string = "\x1b[7m"
22+
23+
// Reset returns the reset ANSI code if colors are enabled, empty string otherwise
24+
func Reset() string {
25+
if colorEnabled {
26+
return resetCode
27+
}
28+
return ""
29+
}
30+
31+
// Green returns the green ANSI code if colors are enabled, empty string otherwise
32+
func Green() string {
33+
if colorEnabled {
34+
return greenCode
35+
}
36+
return ""
37+
}
38+
39+
// Red returns the red ANSI code if colors are enabled, empty string otherwise
40+
func Red() string {
41+
if colorEnabled {
42+
return redCode
43+
}
44+
return ""
45+
}
46+
47+
// DefaultColor returns the default color ANSI code if colors are enabled, empty string otherwise
48+
func DefaultColor() string {
49+
if colorEnabled {
50+
return defaultColorCode
51+
}
52+
return ""
53+
}
54+
55+
// Dim returns the dim ANSI code if colors are enabled, empty string otherwise
56+
func Dim() string {
57+
if colorEnabled {
58+
return dimCode
59+
}
60+
return ""
61+
}
62+
63+
// Invert returns the invert ANSI code if colors are enabled, empty string otherwise
64+
func Invert() string {
65+
if colorEnabled {
66+
return invertCode
67+
}
68+
return ""
69+
}
70+
71+
// EraseLine always returns the erase line code as it's used for progress indicators
1372
const EraseLine string = "\x1b[2K"

internal/subcommands/hist.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -184,10 +184,10 @@ func drawPlot(
184184
"%s ┤ %s%s%-*s%s %s\n",
185185
bucket.Name,
186186
valueBar,
187-
pretty.Dim,
187+
pretty.Dim(),
188188
barWidth-clampedValue,
189189
totalBar,
190-
pretty.Reset,
190+
pretty.Reset(),
191191
tallyPart,
192192
)
193193

@@ -213,12 +213,12 @@ func fmtHistTally(
213213
case tally.LinesMode:
214214
metric = fmt.Sprintf(
215215
"(%s%s%s / %s%s%s)",
216-
pretty.Green,
216+
pretty.Green(),
217217
format.Number(t.LinesAdded),
218-
pretty.DefaultColor,
219-
pretty.Red,
218+
pretty.DefaultColor(),
219+
pretty.Red(),
220220
format.Number(t.LinesRemoved),
221-
pretty.DefaultColor,
221+
pretty.DefaultColor(),
222222
)
223223
default:
224224
panic("unrecognized tally mode in switch")
@@ -234,10 +234,10 @@ func fmtHistTally(
234234
if fade {
235235
return fmt.Sprintf(
236236
"%s%s %s%s",
237-
pretty.Dim,
237+
pretty.Dim(),
238238
author,
239239
metric,
240-
pretty.Reset,
240+
pretty.Reset(),
241241
)
242242
} else {
243243
return fmt.Sprintf("%s %s", author, metric)

internal/subcommands/table.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -314,17 +314,17 @@ func writeTable(
314314
for i, t := range tallies {
315315
alternating := ""
316316
if totalRows > maxBeforeColorAlternating && i%2 == 1 {
317-
alternating = pretty.Invert
317+
alternating = pretty.Invert()
318318
}
319319

320320
lines := fmt.Sprintf(
321321
"%s%7s%s / %s%7s%s",
322-
pretty.Green,
322+
pretty.Green(),
323323
format.Number(t.LinesAdded),
324-
pretty.DefaultColor,
325-
pretty.Red,
324+
pretty.DefaultColor(),
325+
pretty.Red(),
326326
format.Number(t.LinesRemoved),
327-
pretty.DefaultColor,
327+
pretty.DefaultColor(),
328328
)
329329

330330
if mode == tally.LinesMode || mode == tally.FilesMode {
@@ -336,7 +336,7 @@ func writeTable(
336336
format.Number(t.Commits),
337337
format.Number(t.FileCount),
338338
lines,
339-
pretty.Reset,
339+
pretty.Reset(),
340340
)
341341
} else if mode == tally.FirstModifiedMode {
342342
fmt.Printf(
@@ -345,7 +345,7 @@ func writeTable(
345345
formatAuthor(t, showEmail, colwidth-22),
346346
format.RelativeTime(progStart, t.FirstCommitTime),
347347
format.Number(t.Commits),
348-
pretty.Reset,
348+
pretty.Reset(),
349349
)
350350
} else {
351351
fmt.Printf(
@@ -354,7 +354,7 @@ func writeTable(
354354
formatAuthor(t, showEmail, colwidth-22),
355355
format.RelativeTime(progStart, t.LastCommitTime),
356356
format.Number(t.Commits),
357-
pretty.Reset,
357+
pretty.Reset(),
358358
)
359359
}
360360
}

internal/subcommands/tree.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -315,12 +315,12 @@ func fmtTallyMetric(t tally.FinalTally, opts printTreeOpts) string {
315315
case tally.LinesMode:
316316
return fmt.Sprintf(
317317
"(%s%s%s / %s%s%s)",
318-
pretty.Green,
318+
pretty.Green(),
319319
format.Number(t.LinesAdded),
320-
pretty.DefaultColor,
321-
pretty.Red,
320+
pretty.DefaultColor(),
321+
pretty.Red(),
322322
format.Number(t.LinesRemoved),
323-
pretty.DefaultColor,
323+
pretty.DefaultColor(),
324324
)
325325
case tally.LastModifiedMode:
326326
return fmt.Sprintf(
@@ -356,7 +356,7 @@ func printTree(lines []treeOutputLine, showEmail bool) {
356356

357357
var path string
358358
if line.dimPath {
359-
path = fmt.Sprintf("%s%s%s", pretty.Dim, line.path, pretty.Reset)
359+
path = fmt.Sprintf("%s%s%s", pretty.Dim(), line.path, pretty.Reset())
360360
} else {
361361
path = line.path
362362
}
@@ -382,9 +382,9 @@ func printTree(lines []treeOutputLine, showEmail bool) {
382382
"%s%s%s%s%s%s %s\n",
383383
line.indent,
384384
path,
385-
pretty.Dim,
385+
pretty.Dim(),
386386
separator,
387-
pretty.Reset,
387+
pretty.Reset(),
388388
author,
389389
line.metric,
390390
)
@@ -393,11 +393,11 @@ func printTree(lines []treeOutputLine, showEmail bool) {
393393
"%s%s%s%s%s %s%s\n",
394394
line.indent,
395395
path,
396-
pretty.Dim,
396+
pretty.Dim(),
397397
separator,
398398
author,
399399
line.metric,
400-
pretty.Reset,
400+
pretty.Reset(),
401401
)
402402
}
403403
}

main.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"strings"
1010

1111
"github.com/sinclairtarget/git-who/internal/git"
12+
"github.com/sinclairtarget/git-who/internal/pretty"
1213
"github.com/sinclairtarget/git-who/internal/subcommands"
1314
"github.com/sinclairtarget/git-who/internal/tally"
1415
"github.com/sinclairtarget/git-who/internal/utils/flagutils"
@@ -40,6 +41,7 @@ func main() {
4041

4142
versionFlag := mainFlagSet.Bool("version", false, "Print version and exit")
4243
verboseFlag := mainFlagSet.Bool("v", false, "Enables debug logging")
44+
colorFlag := mainFlagSet.Bool("color", false, "Force enable ANSI color output (overrides NO_COLOR env var)")
4345

4446
mainFlagSet.Usage = func() {
4547
fmt.Println("Usage: git-who [-v] [subcommand] [subcommand options...]")
@@ -71,7 +73,7 @@ func main() {
7173
loop:
7274
for subcmdIndex < len(os.Args) {
7375
switch os.Args[subcmdIndex] {
74-
case "-version", "--version", "-v", "--v", "-h", "--help":
76+
case "-version", "--version", "-v", "--v", "-h", "--help", "-color", "--color":
7577
subcmdIndex += 1
7678
default:
7779
break loop
@@ -85,6 +87,14 @@ loop:
8587
return
8688
}
8789

90+
// Handle color settings according to NO_COLOR spec
91+
// Priority: --color flag > NO_COLOR env var > default (enabled)
92+
if *colorFlag {
93+
pretty.SetColorEnabled(true)
94+
} else if noColor, exists := os.LookupEnv("NO_COLOR"); exists && noColor != "" {
95+
pretty.SetColorEnabled(false)
96+
}
97+
8898
if *verboseFlag {
8999
configureLogging(slog.LevelDebug)
90100
logger().Debug("log level set to DEBUG")

0 commit comments

Comments
 (0)