diff --git a/color_16.go b/color_16.go index 4dcd2aa..9d42550 100644 --- a/color_16.go +++ b/color_16.go @@ -2,6 +2,7 @@ package color import ( "fmt" + "strconv" "strings" ) @@ -9,6 +10,33 @@ import ( // 3(2^3=8) OR 4(2^4=16) bite color. type Color uint8 +// Opts basic color options. code: 0 - 9 +type Opts []Color + +// Add option value +func (o *Opts) Add(ops ...Color) { + for _, op := range ops { + if uint8(op) < 10 { + *o = append(*o, op) + } + } +} + +// IsValid options +func (o Opts) IsValid() bool { + return len(o) > 0 +} + +// IsEmpty options +func (o Opts) IsEmpty() bool { + return len(o) == 0 +} + +// String options to string. eg: "1;3" +func (o Opts) String() string { + return colors2code(o...) +} + /************************************************************* * Basic 16 color definition *************************************************************/ @@ -202,12 +230,14 @@ func (c Color) Darken() Color { // Code convert to code string. eg "35" func (c Color) Code() string { - return fmt.Sprintf("%d", c) + // return fmt.Sprintf("%d", c) + return strconv.Itoa(int(c)) } // String convert to code string. eg "35" func (c Color) String() string { - return fmt.Sprintf("%d", c) + // return fmt.Sprintf("%d", c) + return strconv.Itoa(int(c)) } // IsValid color value diff --git a/color_256.go b/color_256.go index f0ca209..ae37ba6 100644 --- a/color_256.go +++ b/color_256.go @@ -128,9 +128,12 @@ func (c Color256) IsEmpty() bool { // 都是由两位uint8组成, 第一位是色彩值; // 第二位与Bit8Color不一样的是,在这里表示是否设置了值 0 未设置 ^0 已设置 type Style256 struct { - p *Printer + // p Printer + // Name of the style Name string + // color options of the style + opts Opts // fg and bg color fg, bg Color256 } @@ -155,9 +158,10 @@ func S256(fgAndBg ...uint8) *Style256 { } // Set fg and bg color value -func (s *Style256) Set(fgVal, bgVal uint8) *Style256 { +func (s *Style256) Set(fgVal, bgVal uint8, ops ...Color) *Style256 { s.fg = Color256{fgVal, 1} s.bg = Color256{bgVal, 1} + s.opts.Add(ops...) return s } @@ -173,7 +177,19 @@ func (s *Style256) SetFg(fgVal uint8) *Style256 { return s } -// Print print message +// SetOpts set options +func (s *Style256) SetOpts(opts Opts) *Style256 { + s.opts = opts + return s +} + +// AddOpts add options +func (s *Style256) AddOpts(opts ...Color) *Style256 { + s.opts.Add(opts...) + return s +} + +// Print message func (s *Style256) Print(a ...interface{}) { doPrintV2(s.String(), fmt.Sprint(a...)) } @@ -214,5 +230,9 @@ func (s *Style256) String() string { ss = append(ss, fmt.Sprintf(TplBg256, s.bg[0])) } + if s.opts.IsValid() { + ss = append(ss, s.opts.String()) + } + return strings.Join(ss, ";") } diff --git a/color_rgb.go b/color_rgb.go index 2e60c3f..a20b725 100644 --- a/color_rgb.go +++ b/color_rgb.go @@ -144,11 +144,11 @@ func (c RGBColor) Code() string { // String to color code string func (c RGBColor) String() string { - if c[3] == AsFg { // 0 is Fg + if c[3] == AsFg { return fmt.Sprintf(TplFgRGB, c[0], c[1], c[2]) } - if c[3] == AsBg { // 1 is Bg + if c[3] == AsBg { return fmt.Sprintf(TplBgRGB, c[0], c[1], c[2]) } @@ -159,19 +159,17 @@ func (c RGBColor) String() string { // IsEmpty value func (c RGBColor) IsEmpty() bool { - return c[3] > 1 + return c[3] > AsBg } +// IsValid value +// func (c RGBColor) IsValid() bool { +// return c[3] <= AsBg +// } + // C256 returns the closest approximate 256 (8 bit) color func (c RGBColor) C256() Color256 { - var isBg bool - if c[3] == 0 { - isBg = false - } else if c[3] == 1 { - isBg = true - } - - return C256(rgb2short(c[0], c[1], c[2]), isBg) + return C256(rgb2short(c[0], c[1], c[2]), c[3] == AsBg) } /************************************************************* @@ -188,6 +186,8 @@ func (c RGBColor) C256() Color256 { type RGBStyle struct { // Name of the style Name string + // color options of the style + opts Opts // fg and bg color fg, bg RGBColor } @@ -233,24 +233,36 @@ func RGBStyleFromString(fg string, bg ...string) *RGBStyle { } // Set fg and bg color -func (s *RGBStyle) Set(fg, bg RGBColor) *RGBStyle { - return s.SetFg(fg).SetBg(bg) +func (s *RGBStyle) Set(fg, bg RGBColor, opts ...Color) *RGBStyle { + return s.SetFg(fg).SetBg(bg).SetOpts(opts) } // SetFg set fg color func (s *RGBStyle) SetFg(fg RGBColor) *RGBStyle { - fg[3] = 1 + fg[3] = 1 // add fixed value, mark is valid s.fg = fg return s } // SetBg set bg color func (s *RGBStyle) SetBg(bg RGBColor) *RGBStyle { - bg[3] = 1 + bg[3] = 1 // add fixed value, mark is valid s.bg = bg return s } +// SetOpts set options +func (s *RGBStyle) SetOpts(opts Opts) *RGBStyle { + s.opts = opts + return s +} + +// AddOpts add options +func (s *RGBStyle) AddOpts(opts ...Color) *RGBStyle { + s.opts.Add(opts...) + return s +} + // Print print message func (s *RGBStyle) Print(a ...interface{}) { doPrintV2(s.String(), fmt.Sprint(a...)) @@ -284,7 +296,8 @@ func (s *RGBStyle) Code() string { // String convert to color code string func (s *RGBStyle) String() string { var ss []string - if s.fg[3] == 1 { // last value ensure is enable. + // last value ensure is enable. + if s.fg[3] == 1 { ss = append(ss, fmt.Sprintf(TplFgRGB, s.fg[0], s.fg[1], s.fg[2])) } @@ -292,6 +305,10 @@ func (s *RGBStyle) String() string { ss = append(ss, fmt.Sprintf(TplBgRGB, s.bg[0], s.bg[1], s.bg[2])) } + if s.opts.IsValid() { + ss = append(ss, s.opts.String()) + } + return strings.Join(ss, ";") } diff --git a/color_rgb_test.go b/color_rgb_test.go index 0881f34..4778259 100644 --- a/color_rgb_test.go +++ b/color_rgb_test.go @@ -13,6 +13,14 @@ func testRgbToC256Color(t *testing.T, name string, c RGBColor, expected uint8) { } } +func TestRGBStyle_SetOpts(t *testing.T) { + s := NewRGBStyle(RGB(234, 78, 23), RGB(20, 144, 234)) + s.Println("rgb style message") + + s.SetOpts(Opts{OpItalic, OpBold, OpUnderscore}) + s.Println("RGB style message with options") +} + func TestRgbToC256(t *testing.T) { testRgbToC256Color(t, "white", RGB(255, 255, 255), 15) testRgbToC256Color(t, "red", RGB(255, 0, 0), 9) diff --git a/color_test.go b/color_test.go index b61ffe0..ab0aa2b 100644 --- a/color_test.go +++ b/color_test.go @@ -374,12 +374,24 @@ func TestColor256(t *testing.T) { } func TestStyle256(t *testing.T) { + is := assert.New(t) + s := S256(192, 38) + s.Println("style 256 colored text") + is.Equal("\x1b[38;5;192;48;5;38m MSG \x1b[0m", s.Sprint(" MSG ")) + + s.SetOpts(Opts{OpUnderscore}) + s.Println("style 256 colored text - with option OpUnderscore") + is.Equal("\x1b[38;5;192;48;5;38;4m MSG \x1b[0m", s.Sprint(" MSG ")) + + s.AddOpts(OpBold) + s.Println("style 256 colored text - add option OpBold") + is.Equal("\x1b[38;5;192;48;5;38;4;1m MSG \x1b[0m", s.Sprint(" MSG ")) + buf := forceOpenColorRender() defer resetColorRender() - is := assert.New(t) // empty - s := S256() + s = S256() is.Equal("", s.String()) is.Equal("MSG", s.Sprint("MSG")) @@ -398,9 +410,13 @@ func TestStyle256(t *testing.T) { s = S256(132, 23) is.Equal("38;5;132;48;5;23", s.String()) is.Equal("\x1b[38;5;132;48;5;23mMSG\x1b[0m", s.Sprint("MSG")) + s = S256().Set(132, 23) is.Equal("38;5;132;48;5;23", s.String()) is.Equal("\x1b[38;5;132;48;5;23mMSG\x1b[0m", s.Sprint("MSG")) + s = S256().Set(132, 23, OpStrikethrough) + is.Equal("38;5;132;48;5;23;9", s.String()) + s = S256().SetFg(132).SetBg(23) is.Equal("38;5;132;48;5;23", s.String()) is.Equal("\x1b[38;5;132;48;5;23mMSG\x1b[0m", s.Sprint("MSG")) @@ -547,58 +563,79 @@ func TestHexToRGB(t *testing.T) { } func TestRGBStyle(t *testing.T) { - buf := forceOpenColorRender() - defer resetColorRender() - at := assert.New(t) + is := assert.New(t) + + fg := RGB(20, 144, 234) + bg := RGB(234, 78, 23) s := &RGBStyle{} - at.True(s.IsEmpty()) - at.Equal("", s.String()) - s.Set(RGB(20, 144, 234), RGB(234, 78, 23)) - at.False(s.IsEmpty()) - at.Equal("38;2;20;144;234;48;2;234;78;23", s.String()) + is.True(s.IsEmpty()) + is.Equal("", s.String()) + + s.Set(fg, bg) + is.False(s.IsEmpty()) + is.Equal("38;2;20;144;234;48;2;234;78;23", s.String()) + + s = &RGBStyle{} + s.Set(fg, bg, OpUnderscore) + is.False(s.IsEmpty()) + is.Equal("38;2;20;144;234;48;2;234;78;23;4", s.String()) + + s.SetOpts(Opts{OpBold, OpBlink}) + is.Equal("38;2;20;144;234;48;2;234;78;23;1;5", s.String()) + + s.AddOpts(OpItalic) + is.Equal("38;2;20;144;234;48;2;234;78;23;1;5;3", s.String()) // NewRGBStyle s = NewRGBStyle(RGB(20, 144, 234)) - at.False(s.IsEmpty()) - at.Equal("38;2;20;144;234", s.String()) + is.False(s.IsEmpty()) + is.Equal("38;2;20;144;234", s.String()) s = NewRGBStyle(RGB(20, 144, 234), RGB(234, 78, 23)) - at.False(s.IsEmpty()) - at.Equal("38;2;20;144;234;48;2;234;78;23", s.String()) + is.False(s.IsEmpty()) + is.Equal("38;2;20;144;234;48;2;234;78;23", s.String()) // HEXStyle s = HEXStyle("555", "eee") - at.False(s.IsEmpty()) - at.Equal("38;2;85;85;85;48;2;238;238;238", s.String()) + is.False(s.IsEmpty()) + is.Equal("38;2;85;85;85;48;2;238;238;238", s.String()) // RGBStyleFromString s = RGBStyleFromString("20, 144, 234", "234, 78, 23") - at.False(s.IsEmpty()) - at.Equal("38;2;20;144;234;48;2;234;78;23", s.String()) + is.False(s.IsEmpty()) + is.Equal("38;2;20;144;234;48;2;234;78;23", s.String()) // RGBColor.Sprint - at.Equal("\x1b[38;2;20;144;234;48;2;234;78;23mmsg\x1b[0m", s.Sprint("msg")) + is.Equal("\x1b[38;2;20;144;234;48;2;234;78;23mmsg\x1b[0m", s.Sprint("msg")) // RGBColor.Sprintf - at.Equal("\x1b[38;2;20;144;234;48;2;234;78;23mmsg\x1b[0m", s.Sprintf("m%s", "sg")) + is.Equal("\x1b[38;2;20;144;234;48;2;234;78;23mmsg\x1b[0m", s.Sprintf("m%s", "sg")) + + s.Println("hello, this is use RGB color") + fmt.Println("\x1b[38;2;20;144;234;48;2;234;78;23mTEXT\x1b[0m") + // add option: OpItalic + fmt.Println("\x1b[38;2;20;144;234;48;2;234;78;23;3mTEXT\x1b[0m") + + buf := forceOpenColorRender() + defer resetColorRender() // RGBColor.Print s.Print("msg") str := buf.String() buf.Reset() - at.Equal("\x1b[38;2;20;144;234;48;2;234;78;23mmsg\x1b[0m", str) + is.Equal("\x1b[38;2;20;144;234;48;2;234;78;23mmsg\x1b[0m", str) // RGBColor.Printf s.Printf("m%s", "sg") str = buf.String() buf.Reset() - at.Equal("\x1b[38;2;20;144;234;48;2;234;78;23mmsg\x1b[0m", str) + is.Equal("\x1b[38;2;20;144;234;48;2;234;78;23mmsg\x1b[0m", str) // RGBColor.Println s.Println("msg") str = buf.String() buf.Reset() - at.Equal("\x1b[38;2;20;144;234;48;2;234;78;23mmsg\x1b[0m\n", str) + is.Equal("\x1b[38;2;20;144;234;48;2;234;78;23mmsg\x1b[0m\n", str) } func TestPrintRGBColor(t *testing.T) { @@ -609,6 +646,20 @@ func TestPrintRGBColor(t *testing.T) { HEXStyle("eee", "D50000").Println("deep-purple color") } +func TestOpts_Add(t *testing.T) { + is := assert.New(t) + + op := Opts{OpBold, OpBlink} + is.False(op.IsEmpty()) + is.Equal("1;5", op.String()) + + op.Add(Color(45)) + is.Equal("1;5", op.String()) + + op.Add(OpUnderscore) + is.Equal("1;5;4", op.String()) +} + func TestUtilFuncs(t *testing.T) { is := assert.New(t) diff --git a/style.go b/style.go index 84d2705..f2e8812 100644 --- a/style.go +++ b/style.go @@ -157,7 +157,7 @@ var ( // Notice color style Notice = &Theme{"notice", Style{OpBold, FgCyan}} // Comment color style - Comment = &Theme{"comment", Style{OpReset, FgLightYellow}} + Comment = &Theme{"comment", Style{OpReset, FgYellow}} // Success color style Success = &Theme{"success", Style{OpBold, FgGreen}} // Primary color style