From c3b52193891371f4460f192d3ecd400f31241989 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=85=B8=E6=9F=A0=E6=AA=AC=E7=8C=B9/SourLemonJuice?= Date: Mon, 29 Sep 2025 09:04:32 +0800 Subject: [PATCH 1/3] Redefine .noColor field of Color, NO_COLOR won't affect at runtime Redefine the ".noColor *bool" field to ".useColor bool" of type "Color", this removed the pointless pointer and reduced the complexity. Which also removed the boolPtr() method(?) The test "TestNoColor_Env" now removed, because the NO_COLOR env should not affect at runtime. --- color.go | 45 +++++++++++++++++---------------------------- color_test.go | 48 +++--------------------------------------------- 2 files changed, 20 insertions(+), 73 deletions(-) diff --git a/color.go b/color.go index b2795fed..fce20f78 100644 --- a/color.go +++ b/color.go @@ -19,7 +19,8 @@ var ( // set (regardless of its value). This is a global option and affects all // colors. For more control over each color block use the methods // DisableColor() individually. - NoColor = noColorIsSet() || os.Getenv("TERM") == "dumb" || + // NOTE: NO_COLOR environment variable will only be checked at init. + NoColor = hasNoColorEnv() || os.Getenv("TERM") == "dumb" || (!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd())) // Output defines the standard output of the print functions. By default, @@ -35,15 +36,15 @@ var ( colorsCacheMu sync.Mutex // protects colorsCache ) -// noColorIsSet returns true if the environment variable NO_COLOR is set to a non-empty string. -func noColorIsSet() bool { +// hasNoColorEnv returns true if the environment variable NO_COLOR is set to a non-empty string. +func hasNoColorEnv() bool { return os.Getenv("NO_COLOR") != "" } // Color defines a custom color object which is defined by SGR parameters. type Color struct { - params []Attribute - noColor *bool + params []Attribute + useColor bool } // Attribute defines a single SGR Code @@ -148,8 +149,10 @@ func New(value ...Attribute) *Color { params: make([]Attribute, 0), } - if noColorIsSet() { - c.noColor = boolPtr(true) + if NoColor { + c.useColor = false + } else { + c.useColor = true } c.Add(value...) @@ -200,7 +203,7 @@ func Unset() { // Set sets the SGR sequence. func (c *Color) Set() *Color { - if c.isNoColorSet() { + if !c.useColor { return c } @@ -209,7 +212,7 @@ func (c *Color) Set() *Color { } func (c *Color) unset() { - if c.isNoColorSet() { + if !c.useColor { return } @@ -220,7 +223,7 @@ func (c *Color) unset() { // a low-level function, and users should use the higher-level functions, such // as color.Fprint, color.Print, etc. func (c *Color) SetWriter(w io.Writer) *Color { - if c.isNoColorSet() { + if !c.useColor { return c } @@ -231,7 +234,7 @@ func (c *Color) SetWriter(w io.Writer) *Color { // UnsetWriter resets all escape attributes and clears the output with the give // io.Writer. Usually should be called after SetWriter(). func (c *Color) UnsetWriter(w io.Writer) { - if c.isNoColorSet() { + if !c.useColor { return } @@ -414,7 +417,7 @@ func (c *Color) sequence() string { // wrap wraps the s string with the colors attributes. The string is ready to // be printed. func (c *Color) wrap(s string) string { - if c.isNoColorSet() { + if !c.useColor { return s } @@ -444,23 +447,13 @@ func (c *Color) unformat() string { // code and still being able to output. Can be used for flags like // "--no-color". To enable back use EnableColor() method. func (c *Color) DisableColor() { - c.noColor = boolPtr(true) + c.useColor = false } // EnableColor enables the color output. Use it in conjunction with // DisableColor(). Otherwise, this method has no side effects. func (c *Color) EnableColor() { - c.noColor = boolPtr(false) -} - -func (c *Color) isNoColorSet() bool { - // check first if we have user set action - if c.noColor != nil { - return *c.noColor - } - - // if not return the global option, which is disabled by default - return NoColor + c.useColor = true } // Equals returns a boolean value indicating whether two colors are equal. @@ -494,10 +487,6 @@ func (c *Color) attrExists(a Attribute) bool { return false } -func boolPtr(v bool) *bool { - return &v -} - func getCachedColor(p Attribute) *Color { colorsCacheMu.Lock() defer colorsCacheMu.Unlock() diff --git a/color_test.go b/color_test.go index 586039b4..6f2eed53 100644 --- a/color_test.go +++ b/color_test.go @@ -158,49 +158,7 @@ func TestNoColor(t *testing.T) { } } -func TestNoColor_Env(t *testing.T) { - rb := new(bytes.Buffer) - Output = rb - - testColors := []struct { - text string - code Attribute - }{ - {text: "black", code: FgBlack}, - {text: "red", code: FgRed}, - {text: "green", code: FgGreen}, - {text: "yellow", code: FgYellow}, - {text: "blue", code: FgBlue}, - {text: "magent", code: FgMagenta}, - {text: "cyan", code: FgCyan}, - {text: "white", code: FgWhite}, - {text: "hblack", code: FgHiBlack}, - {text: "hred", code: FgHiRed}, - {text: "hgreen", code: FgHiGreen}, - {text: "hyellow", code: FgHiYellow}, - {text: "hblue", code: FgHiBlue}, - {text: "hmagent", code: FgHiMagenta}, - {text: "hcyan", code: FgHiCyan}, - {text: "hwhite", code: FgHiWhite}, - } - - os.Setenv("NO_COLOR", "1") - t.Cleanup(func() { - os.Unsetenv("NO_COLOR") - }) - - for _, c := range testColors { - p := New(c.code) - p.Print(c.text) - - line, _ := rb.ReadString('\n') - if line != c.text { - t.Errorf("Expecting %s, got '%s'\n", c.text, line) - } - } -} - -func Test_noColorIsSet(t *testing.T) { +func Test_hasNoColorEnv(t *testing.T) { tests := []struct { name string act func() @@ -228,8 +186,8 @@ func Test_noColorIsSet(t *testing.T) { os.Unsetenv("NO_COLOR") }) tt.act() - if got := noColorIsSet(); got != tt.want { - t.Errorf("noColorIsSet() = %v, want %v", got, tt.want) + if got := hasNoColorEnv(); got != tt.want { + t.Errorf("hasNoColorEnv() = %v, want %v", got, tt.want) } }) } From f7f3f1e7dd4c94a4fbdfaeda061dcdda7e7ffeb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=85=B8=E6=9F=A0=E6=AA=AC=E7=8C=B9/SourLemonJuice?= Date: Mon, 29 Sep 2025 14:50:32 +0800 Subject: [PATCH 2/3] Change .useColor field of type Color to .isNoColor --- color.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/color.go b/color.go index fce20f78..9cccf218 100644 --- a/color.go +++ b/color.go @@ -43,8 +43,8 @@ func hasNoColorEnv() bool { // Color defines a custom color object which is defined by SGR parameters. type Color struct { - params []Attribute - useColor bool + params []Attribute + isNoColor bool } // Attribute defines a single SGR Code @@ -150,9 +150,9 @@ func New(value ...Attribute) *Color { } if NoColor { - c.useColor = false + c.isNoColor = true } else { - c.useColor = true + c.isNoColor = false } c.Add(value...) @@ -203,7 +203,7 @@ func Unset() { // Set sets the SGR sequence. func (c *Color) Set() *Color { - if !c.useColor { + if c.isNoColor { return c } @@ -212,7 +212,7 @@ func (c *Color) Set() *Color { } func (c *Color) unset() { - if !c.useColor { + if c.isNoColor { return } @@ -223,7 +223,7 @@ func (c *Color) unset() { // a low-level function, and users should use the higher-level functions, such // as color.Fprint, color.Print, etc. func (c *Color) SetWriter(w io.Writer) *Color { - if !c.useColor { + if c.isNoColor { return c } @@ -234,7 +234,7 @@ func (c *Color) SetWriter(w io.Writer) *Color { // UnsetWriter resets all escape attributes and clears the output with the give // io.Writer. Usually should be called after SetWriter(). func (c *Color) UnsetWriter(w io.Writer) { - if !c.useColor { + if c.isNoColor { return } @@ -417,7 +417,7 @@ func (c *Color) sequence() string { // wrap wraps the s string with the colors attributes. The string is ready to // be printed. func (c *Color) wrap(s string) string { - if !c.useColor { + if c.isNoColor { return s } @@ -447,13 +447,13 @@ func (c *Color) unformat() string { // code and still being able to output. Can be used for flags like // "--no-color". To enable back use EnableColor() method. func (c *Color) DisableColor() { - c.useColor = false + c.isNoColor = true } // EnableColor enables the color output. Use it in conjunction with // DisableColor(). Otherwise, this method has no side effects. func (c *Color) EnableColor() { - c.useColor = true + c.isNoColor = false } // Equals returns a boolean value indicating whether two colors are equal. From 35b26b0dc13feed67aa385bb307924bae83de29e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=85=B8=E6=9F=A0=E6=AA=AC=E7=8C=B9/SourLemonJuice?= Date: Sat, 4 Oct 2025 01:46:59 +0800 Subject: [PATCH 3/3] Change .isNoColor field of type Color to .noColor --- color.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/color.go b/color.go index 9cccf218..1e0eb5a8 100644 --- a/color.go +++ b/color.go @@ -43,8 +43,8 @@ func hasNoColorEnv() bool { // Color defines a custom color object which is defined by SGR parameters. type Color struct { - params []Attribute - isNoColor bool + params []Attribute + noColor bool } // Attribute defines a single SGR Code @@ -150,9 +150,9 @@ func New(value ...Attribute) *Color { } if NoColor { - c.isNoColor = true + c.noColor = true } else { - c.isNoColor = false + c.noColor = false } c.Add(value...) @@ -203,7 +203,7 @@ func Unset() { // Set sets the SGR sequence. func (c *Color) Set() *Color { - if c.isNoColor { + if c.noColor { return c } @@ -212,7 +212,7 @@ func (c *Color) Set() *Color { } func (c *Color) unset() { - if c.isNoColor { + if c.noColor { return } @@ -223,7 +223,7 @@ func (c *Color) unset() { // a low-level function, and users should use the higher-level functions, such // as color.Fprint, color.Print, etc. func (c *Color) SetWriter(w io.Writer) *Color { - if c.isNoColor { + if c.noColor { return c } @@ -234,7 +234,7 @@ func (c *Color) SetWriter(w io.Writer) *Color { // UnsetWriter resets all escape attributes and clears the output with the give // io.Writer. Usually should be called after SetWriter(). func (c *Color) UnsetWriter(w io.Writer) { - if c.isNoColor { + if c.noColor { return } @@ -417,7 +417,7 @@ func (c *Color) sequence() string { // wrap wraps the s string with the colors attributes. The string is ready to // be printed. func (c *Color) wrap(s string) string { - if c.isNoColor { + if c.noColor { return s } @@ -447,13 +447,13 @@ func (c *Color) unformat() string { // code and still being able to output. Can be used for flags like // "--no-color". To enable back use EnableColor() method. func (c *Color) DisableColor() { - c.isNoColor = true + c.noColor = true } // EnableColor enables the color output. Use it in conjunction with // DisableColor(). Otherwise, this method has no side effects. func (c *Color) EnableColor() { - c.isNoColor = false + c.noColor = false } // Equals returns a boolean value indicating whether two colors are equal.