Repository: pterm/pterm
Pull request #474 (2023-03-31 23:09:13)

feat(rgb): made it possible to use RGB colors as background


Patch:
diff --git a/_examples/coloring/print-color-rgb/main.go b/_examples/coloring/print-color-rgb/main.go
index c849785d..853a09f0 100644
--- a/_examples/coloring/print-color-rgb/main.go
+++ b/_examples/coloring/print-color-rgb/main.go
@@ -7,5 +7,5 @@ func main() {
 	// NOTICE: This only works with terminals which support TrueColor.
 	pterm.NewRGB(178, 44, 199).Println("This text is printed with a custom RGB!")
 	pterm.NewRGB(15, 199, 209).Println("This text is printed with a custom RGB!")
-	pterm.NewRGB(201, 144, 30).Println("This text is printed with a custom RGB!")
+	pterm.NewRGB(201, 144, 30, true).Println("This text is printed with a custom RGB background!")
 }
diff --git a/rgb.go b/rgb.go
index fee602a5..008455ff 100644
--- a/rgb.go
+++ b/rgb.go
@@ -12,9 +12,10 @@ import (
 // The name of the model comes from the initials of the three additive primary colors, red, green, and blue.
 // https://en.wikipedia.org/wiki/RGB_color_model
 type RGB struct {
-	R uint8
-	G uint8
-	B uint8
+	R          uint8
+	G          uint8
+	B          uint8
+	Background bool
 }
 
 // GetValues returns the RGB values separately.
@@ -23,8 +24,14 @@ func (p RGB) GetValues() (r, g, b uint8) {
 }
 
 // NewRGB returns a new RGB.
-func NewRGB(r, g, b uint8) RGB {
-	return RGB{R: r, G: g, B: b}
+func NewRGB(r, g, b uint8, background ...bool) RGB {
+	var bg bool
+
+	if len(background) > 0 {
+		bg = background[0]
+	}
+
+	return RGB{R: r, G: g, B: b, Background: bg}
 }
 
 // Fade fades one RGB value (over other RGB values) to another RGB value, by giving the function a minimum, maximum and current value.
@@ -36,9 +43,10 @@ func (p RGB) Fade(min, max, current float32, end ...RGB) RGB {
 	}
 	if len(end) == 1 {
 		return RGB{
-			R: uint8(internal.MapRangeToRange(min, max, float32(p.R), float32(end[0].R), current)),
-			G: uint8(internal.MapRangeToRange(min, max, float32(p.G), float32(end[0].G), current)),
-			B: uint8(internal.MapRangeToRange(min, max, float32(p.B), float32(end[0].B), current)),
+			R:          uint8(internal.MapRangeToRange(min, max, float32(p.R), float32(end[0].R), current)),
+			G:          uint8(internal.MapRangeToRange(min, max, float32(p.G), float32(end[0].G), current)),
+			B:          uint8(internal.MapRangeToRange(min, max, float32(p.B), float32(end[0].B), current)),
+			Background: p.Background,
 		}
 	} else if len(end) > 1 {
 		f := (max - min) / float32(len(end))
@@ -60,7 +68,10 @@ func (p RGB) Fade(min, max, current float32, end ...RGB) RGB {
 // Sprint formats using the default formats for its operands and returns the resulting string.
 // Spaces are added between operands when neither is a string.
 func (p RGB) Sprint(a ...interface{}) string {
-	return color.RGB(p.R, p.G, p.B).Sprint(a...)
+	if p.Background {
+		return color.RGB(p.R, p.G, p.B, p.Background).Sprint(a...) + "\033[0m\033[K"
+	}
+	return color.RGB(p.R, p.G, p.B, p.Background).Sprint(a...)
 }
 
 // Sprintln formats using the default formats for its operands and returns the resulting string.


Test patch:
diff --git a/rgb_test.go b/rgb_test.go
index 5289992a..28619056 100644
--- a/rgb_test.go
+++ b/rgb_test.go
@@ -23,10 +23,10 @@ func TestNewRGB(t *testing.T) {
 		args args
 		want pterm.RGB
 	}{
-		{name: "1", args: args{0, 0, 0}, want: pterm.RGB{0, 0, 0}},
-		{name: "3", args: args{255, 255, 255}, want: pterm.RGB{255, 255, 255}},
-		{name: "4", args: args{127, 127, 127}, want: pterm.RGB{127, 127, 127}},
-		{name: "5", args: args{1, 2, 3}, want: pterm.RGB{1, 2, 3}},
+		{name: "1", args: args{0, 0, 0}, want: pterm.RGB{0, 0, 0, false}},
+		{name: "3", args: args{255, 255, 255}, want: pterm.RGB{255, 255, 255, false}},
+		{name: "4", args: args{127, 127, 127}, want: pterm.RGB{127, 127, 127, false}},
+		{name: "5", args: args{1, 2, 3}, want: pterm.RGB{1, 2, 3, false}},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
@@ -93,15 +93,15 @@ func TestRGB_Fade(t *testing.T) {
 		args   args
 		want   pterm.RGB
 	}{
-		{name: "Middle", fields: fields{0, 0, 0}, args: args{min: 0, max: 100, current: 50, end: []pterm.RGB{{255, 255, 255}}}, want: pterm.RGB{127, 127, 127}},
-		{name: "ZeroToZero", fields: fields{0, 0, 0}, args: args{min: 0, max: 100, current: 50, end: []pterm.RGB{{0, 0, 0}}}, want: pterm.RGB{0, 0, 0}},
-		{name: "DifferentValues", fields: fields{0, 1, 2}, args: args{min: 0, max: 100, current: 50, end: []pterm.RGB{{0, 1, 2}}}, want: pterm.RGB{0, 1, 2}},
-		{name: "NegativeRangeMiddle", fields: fields{0, 0, 0}, args: args{min: -50, max: 50, current: 0, end: []pterm.RGB{{255, 255, 255}}}, want: pterm.RGB{127, 127, 127}},
-		{name: "NegativeRangeMiddleMultipleRGB", fields: fields{0, 0, 0}, args: args{min: -50, max: 50, current: 0, end: []pterm.RGB{{127, 127, 127}, {255, 255, 255}}}, want: pterm.RGB{127, 127, 127}},
-		{name: "MiddleMultipleRGB", fields: fields{0, 0, 0}, args: args{min: 0, max: 100, current: 50, end: []pterm.RGB{{127, 127, 127}, {255, 255, 255}}}, want: pterm.RGB{127, 127, 127}},
-		{name: "1/4MultipleRGB", fields: fields{0, 0, 0}, args: args{min: 0, max: 100, current: 25, end: []pterm.RGB{{255, 255, 255}, {255, 255, 255}}}, want: pterm.RGB{127, 127, 127}},
-		{name: "MiddleMultipleRGBPositiveMin", fields: fields{0, 0, 0}, args: args{min: 10, max: 110, current: 60, end: []pterm.RGB{{127, 127, 127}, {255, 255, 255}}}, want: pterm.RGB{127, 127, 127}},
-		{name: "MiddleNoRGB", fields: fields{0, 0, 0}, args: args{min: 10, max: 110, current: 60, end: []pterm.RGB{}}, want: pterm.RGB{0, 0, 0}},
+		{name: "Middle", fields: fields{0, 0, 0}, args: args{min: 0, max: 100, current: 50, end: []pterm.RGB{{255, 255, 255, false}}}, want: pterm.RGB{127, 127, 127, false}},
+		{name: "ZeroToZero", fields: fields{0, 0, 0}, args: args{min: 0, max: 100, current: 50, end: []pterm.RGB{{0, 0, 0, false}}}, want: pterm.RGB{0, 0, 0, false}},
+		{name: "DifferentValues", fields: fields{0, 1, 2}, args: args{min: 0, max: 100, current: 50, end: []pterm.RGB{{0, 1, 2, false}}}, want: pterm.RGB{0, 1, 2, false}},
+		{name: "NegativeRangeMiddle", fields: fields{0, 0, 0}, args: args{min: -50, max: 50, current: 0, end: []pterm.RGB{{255, 255, 255, false}}}, want: pterm.RGB{127, 127, 127, false}},
+		{name: "NegativeRangeMiddleMultipleRGB", fields: fields{0, 0, 0}, args: args{min: -50, max: 50, current: 0, end: []pterm.RGB{{127, 127, 127, false}, {255, 255, 255, false}}}, want: pterm.RGB{127, 127, 127, false}},
+		{name: "MiddleMultipleRGB", fields: fields{0, 0, 0}, args: args{min: 0, max: 100, current: 50, end: []pterm.RGB{{127, 127, 127, false}, {255, 255, 255, false}}}, want: pterm.RGB{127, 127, 127, false}},
+		{name: "1/4MultipleRGB", fields: fields{0, 0, 0}, args: args{min: 0, max: 100, current: 25, end: []pterm.RGB{{255, 255, 255, false}, {255, 255, 255, false}}}, want: pterm.RGB{127, 127, 127, false}},
+		{name: "MiddleMultipleRGBPositiveMin", fields: fields{0, 0, 0}, args: args{min: 10, max: 110, current: 60, end: []pterm.RGB{{127, 127, 127, false}, {255, 255, 255, false}}}, want: pterm.RGB{127, 127, 127, false}},
+		{name: "MiddleNoRGB", fields: fields{0, 0, 0}, args: args{min: 10, max: 110, current: 60, end: []pterm.RGB{}}, want: pterm.RGB{0, 0, 0, false}},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
@@ -155,7 +155,7 @@ func TestRGB_GetValues(t *testing.T) {
 }
 
 func TestRGB_Print(t *testing.T) {
-	RGBs := []pterm.RGB{{0, 0, 0}, {127, 127, 127}, {255, 255, 255}}
+	RGBs := []pterm.RGB{{0, 0, 0, false}, {127, 127, 127, false}, {255, 255, 255, false}}
 
 	for _, rgb := range RGBs {
 		t.Run(pterm.Sprintf("%v %v %v", rgb.R, rgb.G, rgb.B), func(t *testing.T) {
@@ -168,7 +168,7 @@ func TestRGB_Print(t *testing.T) {
 }
 
 func TestRGB_Printf(t *testing.T) {
-	RGBs := []pterm.RGB{{0, 0, 0}, {127, 127, 127}, {255, 255, 255}}
+	RGBs := []pterm.RGB{{0, 0, 0, false}, {127, 127, 127, false}, {255, 255, 255, false}}
 
 	for _, rgb := range RGBs {
 		t.Run(pterm.Sprintf("%v %v %v", rgb.R, rgb.G, rgb.B), func(t *testing.T) {
@@ -181,7 +181,7 @@ func TestRGB_Printf(t *testing.T) {
 }
 
 func TestRGB_Printfln(t *testing.T) {
-	RGBs := []pterm.RGB{{0, 0, 0}, {127, 127, 127}, {255, 255, 255}}
+	RGBs := []pterm.RGB{{0, 0, 0, false}, {127, 127, 127, false}, {255, 255, 255, false}}
 
 	for _, rgb := range RGBs {
 		t.Run(pterm.Sprintfln("%v %v %v", rgb.R, rgb.G, rgb.B), func(t *testing.T) {
@@ -194,7 +194,7 @@ func TestRGB_Printfln(t *testing.T) {
 }
 
 func TestRGB_Println(t *testing.T) {
-	RGBs := []pterm.RGB{{0, 0, 0}, {127, 127, 127}, {255, 255, 255}}
+	RGBs := []pterm.RGB{{0, 0, 0, false}, {127, 127, 127, false}, {255, 255, 255, false}}
 
 	for _, rgb := range RGBs {
 		t.Run(pterm.Sprintf("%v %v %v", rgb.R, rgb.G, rgb.B), func(t *testing.T) {
@@ -207,7 +207,7 @@ func TestRGB_Println(t *testing.T) {
 }
 
 func TestRGB_Sprint(t *testing.T) {
-	RGBs := []pterm.RGB{{0, 0, 0}, {127, 127, 127}, {255, 255, 255}}
+	RGBs := []pterm.RGB{{0, 0, 0, false}, {127, 127, 127, false}, {255, 255, 255, false}}
 
 	for _, rgb := range RGBs {
 		t.Run(pterm.Sprintf("%v %v %v", rgb.R, rgb.G, rgb.B), func(t *testing.T) {
@@ -219,7 +219,7 @@ func TestRGB_Sprint(t *testing.T) {
 }
 
 func TestRGB_Sprintf(t *testing.T) {
-	RGBs := []pterm.RGB{{0, 0, 0}, {127, 127, 127}, {255, 255, 255}}
+	RGBs := []pterm.RGB{{0, 0, 0, false}, {127, 127, 127, false}, {255, 255, 255, false}}
 
 	for _, rgb := range RGBs {
 		t.Run("", func(t *testing.T) {
@@ -231,7 +231,7 @@ func TestRGB_Sprintf(t *testing.T) {
 }
 
 func TestRGB_Sprintfln(t *testing.T) {
-	RGBs := []pterm.RGB{{0, 0, 0}, {127, 127, 127}, {255, 255, 255}}
+	RGBs := []pterm.RGB{{0, 0, 0, false}, {127, 127, 127, false}, {255, 255, 255, false}}
 
 	for _, rgb := range RGBs {
 		t.Run("", func(t *testing.T) {
@@ -243,7 +243,7 @@ func TestRGB_Sprintfln(t *testing.T) {
 }
 
 func TestRGB_Sprintln(t *testing.T) {
-	RGBs := []pterm.RGB{{0, 0, 0}, {127, 127, 127}, {255, 255, 255}}
+	RGBs := []pterm.RGB{{0, 0, 0, false}, {127, 127, 127, false}, {255, 255, 255, false}}
 
 	for _, rgb := range RGBs {
 		t.Run(pterm.Sprintf("%v %v %v", rgb.R, rgb.G, rgb.B), func(t *testing.T) {
@@ -255,7 +255,7 @@ func TestRGB_Sprintln(t *testing.T) {
 }
 
 func TestRGB_PrintOnError(t *testing.T) {
-	RGBs := []pterm.RGB{{0, 0, 0}, {127, 127, 127}, {255, 255, 255}}
+	RGBs := []pterm.RGB{{0, 0, 0, false}, {127, 127, 127, false}, {255, 255, 255, false}}
 
 	for _, rgb := range RGBs {
 		t.Run("PrintOnError", func(t *testing.T) {
@@ -268,7 +268,7 @@ func TestRGB_PrintOnError(t *testing.T) {
 }
 
 func TestRGB_PrintIfError_WithoutError(t *testing.T) {
-	RGBs := []pterm.RGB{{0, 0, 0}, {127, 127, 127}, {255, 255, 255}}
+	RGBs := []pterm.RGB{{0, 0, 0, false}, {127, 127, 127, false}, {255, 255, 255, false}}
 
 	for _, rgb := range RGBs {
 		t.Run("PrintIfError_WithoutError", func(t *testing.T) {
@@ -281,7 +281,7 @@ func TestRGB_PrintIfError_WithoutError(t *testing.T) {
 }
 
 func TestRGB_PrintOnErrorf(t *testing.T) {
-	RGBs := []pterm.RGB{{0, 0, 0}, {127, 127, 127}, {255, 255, 255}}
+	RGBs := []pterm.RGB{{0, 0, 0, false}, {127, 127, 127, false}, {255, 255, 255, false}}
 
 	for _, rgb := range RGBs {
 		t.Run("PrintOnErrorf", func(t *testing.T) {
@@ -294,7 +294,7 @@ func TestRGB_PrintOnErrorf(t *testing.T) {
 }
 
 func TestRGB_PrintIfError_WithoutErrorf(t *testing.T) {
-	RGBs := []pterm.RGB{{0, 0, 0}, {127, 127, 127}, {255, 255, 255}}
+	RGBs := []pterm.RGB{{0, 0, 0, false}, {127, 127, 127, false}, {255, 255, 255, false}}
 
 	for _, rgb := range RGBs {
 		t.Run("PrintIfError_WithoutErrorf", func(t *testing.T) {