Repository: onsi/ginkgo (language: go)

Issue:
Support shorter aliases for color escape codes
#1095 introduced support for configuring colors through environment variables.

In order to support simpler configuration it would be nice to support shorter versions of the escape codes. The following values would be nice to map.

For the standard 16 colors (0-15)
`red` => `\x1b[31m`
`1` => `\x1b[31m`
`bright-red` => `\x1b[31;1m`
`8` => `\x1b[31;1m`

For extended 256 colors (16-255)
`16` => `\x1b[38;5;16m`
      


Discussion / hints:

Fix patch:
diff --git a/formatter/formatter.go b/formatter/formatter.go
index da224eab6..ece35d17b 100644
--- a/formatter/formatter.go
+++ b/formatter/formatter.go
@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"os"
 	"regexp"
+	"strconv"
 	"strings"
 )
 
@@ -50,13 +51,35 @@ func NewWithNoColorBool(noColor bool) Formatter {
 }
 
 func New(colorMode ColorMode) Formatter {
+	colorAliases := map[string]int{
+		"black":   0,
+		"red":     1,
+		"green":   2,
+		"yellow":  3,
+		"blue":    4,
+		"magenta": 5,
+		"cyan":    6,
+		"white":   7,
+	}
+	for colorAlias, n := range colorAliases {
+		colorAliases[fmt.Sprintf("bright-%s", colorAlias)] = n + 8
+	}
+
 	getColor := func(color, defaultEscapeCode string) string {
 		color = strings.ToUpper(strings.ReplaceAll(color, "-", "_"))
 		envVar := fmt.Sprintf("GINKGO_CLI_COLOR_%s", color)
-		if escapeCode := os.Getenv(envVar); escapeCode != "" {
-			return escapeCode
+		envVarColor := os.Getenv(envVar)
+		if envVarColor == "" {
+			return defaultEscapeCode
+		}
+		if colorCode, ok := colorAliases[envVarColor]; ok {
+			return fmt.Sprintf("\x1b[38;5;%dm", colorCode)
+		}
+		colorCode, err := strconv.Atoi(envVarColor)
+		if err != nil || colorCode < 0 || colorCode > 255 {
+			return defaultEscapeCode
 		}
-		return defaultEscapeCode
+		return fmt.Sprintf("\x1b[38;5;%dm", colorCode)
 	}
 
 	f := Formatter{


Test patch:
diff --git a/formatter/formatter_test.go b/formatter/formatter_test.go
index b8db73164..17503d7dd 100644
--- a/formatter/formatter_test.go
+++ b/formatter/formatter_test.go
@@ -62,19 +62,46 @@ var _ = Describe("Formatter", func() {
 		})
 	})
 
-	Context("with environment overrides", func() {
-		BeforeEach(func() {
-			os.Setenv("GINKGO_CLI_COLOR_RED", "\x1b[31m")
-		})
+	DescribeTable("with environment overrides",
+		func(envVars map[string]string, input, expected string) {
+			for envVar, value := range envVars {
+				os.Setenv(envVar, value)
+			}
+			f := formatter.New(colorMode)
+			Ω(f.F(input)).Should(Equal(expected))
+			for envVar := range envVars {
+				os.Unsetenv(envVar)
+			}
+		},
 
-		AfterEach(func() {
-			os.Unsetenv("GINKGO_CLI_COLOR_RED")
-		})
+		Entry("uses default for too low codes", map[string]string{
+			"GINKGO_CLI_COLOR_RED": "-1",
+		}, "{{red}}hi there{{/}}", "\x1b[38;5;9mhi there\x1b[0m"),
 
-		It("uses the escape codes from the environment variables", func() {
-			Ω(f.F("{{red}}hi there{{/}}")).Should(Equal("\x1b[31mhi there\x1b[0m"))
-		})
-	})
+		Entry("uses default for too high codes", map[string]string{
+			"GINKGO_CLI_COLOR_RED": "256",
+		}, "{{red}}hi there{{/}}", "\x1b[38;5;9mhi there\x1b[0m"),
+
+		Entry("supports literal alias for 8bit color", map[string]string{
+			"GINKGO_CLI_COLOR_RED": "red",
+		}, "{{red}}hi there{{/}}", "\x1b[38;5;1mhi there\x1b[0m"),
+
+		Entry("supports number alias for 8bit color", map[string]string{
+			"GINKGO_CLI_COLOR_RED": "1",
+		}, "{{red}}hi there{{/}}", "\x1b[38;5;1mhi there\x1b[0m"),
+
+		Entry("supports 16bit colors (bright)", map[string]string{
+			"GINKGO_CLI_COLOR_RED": "9",
+		}, "{{red}}hi there{{/}}", "\x1b[38;5;9mhi there\x1b[0m"),
+
+		Entry("supports 16bit color literal aliases (bright)", map[string]string{
+			"GINKGO_CLI_COLOR_RED": "bright-red",
+		}, "{{red}}hi there{{/}}", "\x1b[38;5;9mhi there\x1b[0m"),
+
+		Entry("supports extended 256 colors", map[string]string{
+			"GINKGO_CLI_COLOR_RED": "16",
+		}, "{{red}}hi there{{/}}", "\x1b[38;5;16mhi there\x1b[0m"),
+	)
 
 	Describe("NewWithNoColorBool", func() {
 		Context("when the noColor bool is true", func() {