diff --git a/colors.go b/colors.go index 5536912..405200c 100644 --- a/colors.go +++ b/colors.go @@ -21,6 +21,9 @@ package bunt import ( + "image/color" + "math" + "math/rand" "strings" colorful "github.com/lucasb-eyer/go-colorful" @@ -344,3 +347,57 @@ func lookupColorByName(colorName string) *colorful.Color { // Give up return nil } + +// RandomTerminalFriendlyColors creates a list of random 24 bit colors based on +// the 4 bit colors that most terminals support. +func RandomTerminalFriendlyColors(n int) []colorful.Color { + if n < 0 { + panic("size is out of bounds, must be greater than zero") + } + + f := func(i uint8) uint8 { + const threshold = 128 + if i < threshold { + return i + } + + maxFactor := .5 + randomFactor := 1 + (rand.Float64()*2*maxFactor - maxFactor) + + return uint8(math.Max( + math.Min( + randomFactor*float64(i), + 255.0, + ), + float64(threshold), + )) + } + + baseColors := [][]uint8{ + {0xAA, 0x00, 0x00}, + {0x00, 0xAA, 0x00}, + {0xFF, 0xFF, 0x00}, + {0x00, 0x00, 0xAA}, + {0xAA, 0x00, 0xAA}, + {0x00, 0xAA, 0xAA}, + {0xAA, 0xAA, 0xAA}, + {0xFF, 0x55, 0x55}, + {0x55, 0xFF, 0x55}, + {0xFF, 0xFF, 0x55}, + {0x55, 0x55, 0xFF}, + {0xFF, 0x55, 0xFF}, + {0x55, 0xFF, 0xFF}, + {0xFF, 0xFF, 0xFF}, + } + + result := make([]colorful.Color, n) + for i := 0; i < n; i++ { + baseColorRGB := baseColors[i%len(baseColors)] + r, g, b := baseColorRGB[0], baseColorRGB[1], baseColorRGB[2] + + color, _ := colorful.MakeColor(color.RGBA{f(r), f(g), f(b), 0xFF}) + result[i] = color + } + + return result +} diff --git a/colors_test.go b/colors_test.go index d5cad14..791de7a 100644 --- a/colors_test.go +++ b/colors_test.go @@ -223,4 +223,27 @@ var _ = Describe("color specific tests", func() { BeEquivalentTo(Sprint("CornflowerBlue{CornflowerBlue}"))) }) }) + + Context("random colors", func() { + BeforeEach(func() { + ColorSetting = ON + TrueColorSetting = OFF + }) + + AfterEach(func() { + ColorSetting = AUTO + TrueColorSetting = AUTO + }) + + It("should create a list of random terminal friendly colors", func() { + colors := RandomTerminalFriendlyColors(16) + Expect(len(colors)).To(BeEquivalentTo(16)) + }) + + It("should panic if negative number is given", func() { + Expect(func() { + RandomTerminalFriendlyColors(-1) + }).To(Panic()) + }) + }) })