Extended and true colors
Signed-off-by: jolheiser <john.olheiser@gmail.com>pull/3/head
parent
5e1722bd43
commit
a99fb9facd
|
@ -104,4 +104,12 @@ func main() {
|
||||||
color.Time = color.New(color.FgCyan)
|
color.Time = color.New(color.FgCyan)
|
||||||
color.Stack = color.New(color.FgGreen)
|
color.Stack = color.New(color.FgGreen)
|
||||||
b.Info("Full options emulating Gitea")
|
b.Info("Full options emulating Gitea")
|
||||||
|
|
||||||
|
// Extended example
|
||||||
|
ex := color.NewExtended(color.Gold1, color.DarkGreen)
|
||||||
|
fmt.Println(ex.Format("Gold on Dark Green"))
|
||||||
|
|
||||||
|
// True color example
|
||||||
|
birb := color.NewTrue(color.MustParseHex("#007D96"), &color.RGB{})
|
||||||
|
fmt.Println(birb.Format("Birb blue on black"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,87 +0,0 @@
|
||||||
package color
|
|
||||||
|
|
||||||
// Attribute defines a single SGR Code
|
|
||||||
type Attribute int
|
|
||||||
|
|
||||||
// Logger attributes
|
|
||||||
const (
|
|
||||||
Reset Attribute = iota
|
|
||||||
Bold
|
|
||||||
Faint
|
|
||||||
Italic
|
|
||||||
Underline
|
|
||||||
BlinkSlow
|
|
||||||
BlinkRapid
|
|
||||||
ReverseVideo
|
|
||||||
Concealed
|
|
||||||
CrossedOut
|
|
||||||
)
|
|
||||||
|
|
||||||
// Foreground text colors
|
|
||||||
const (
|
|
||||||
FgBlack Attribute = iota + 30
|
|
||||||
FgRed
|
|
||||||
FgGreen
|
|
||||||
FgYellow
|
|
||||||
FgBlue
|
|
||||||
FgMagenta
|
|
||||||
FgCyan
|
|
||||||
FgWhite
|
|
||||||
)
|
|
||||||
|
|
||||||
// Foreground Hi-Intensity text colors
|
|
||||||
const (
|
|
||||||
FgHiBlack Attribute = iota + 90
|
|
||||||
FgHiRed
|
|
||||||
FgHiGreen
|
|
||||||
FgHiYellow
|
|
||||||
FgHiBlue
|
|
||||||
FgHiMagenta
|
|
||||||
FgHiCyan
|
|
||||||
FgHiWhite
|
|
||||||
)
|
|
||||||
|
|
||||||
// Background text colors
|
|
||||||
const (
|
|
||||||
BgBlack Attribute = iota + 40
|
|
||||||
BgRed
|
|
||||||
BgGreen
|
|
||||||
BgYellow
|
|
||||||
BgBlue
|
|
||||||
BgMagenta
|
|
||||||
BgCyan
|
|
||||||
BgWhite
|
|
||||||
)
|
|
||||||
|
|
||||||
// Background Hi-Intensity text colors
|
|
||||||
const (
|
|
||||||
BgHiBlack Attribute = iota + 100
|
|
||||||
BgHiRed
|
|
||||||
BgHiGreen
|
|
||||||
BgHiYellow
|
|
||||||
BgHiBlue
|
|
||||||
BgHiMagenta
|
|
||||||
BgHiCyan
|
|
||||||
BgHiWhite
|
|
||||||
)
|
|
||||||
|
|
||||||
var attrCache = make(map[string]*Color)
|
|
||||||
|
|
||||||
func attr(a Attribute) *Color {
|
|
||||||
if c, ok := attrCache[string(a)]; ok {
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
c := New(a)
|
|
||||||
attrCache[string(a)] = c
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format is a quick way to format a string using a single attribute
|
|
||||||
func (a Attribute) Format(text string) string {
|
|
||||||
return attr(a).Format(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format is a quick way to format a formatted string using a single attribute
|
|
||||||
func (a Attribute) Formatf(text string, v ...interface{}) string {
|
|
||||||
return attr(a).Formatf(text, v...)
|
|
||||||
}
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
package color
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Interface guard
|
||||||
|
var _ Color = &Basic{}
|
||||||
|
|
||||||
|
// Basic defines a custom color object which is defined by SGR parameters.
|
||||||
|
type Basic struct {
|
||||||
|
Attrs []BasicAttribute
|
||||||
|
}
|
||||||
|
|
||||||
|
// BasicAttribute defines a single SGR Code
|
||||||
|
type BasicAttribute int
|
||||||
|
|
||||||
|
// Logger attributes
|
||||||
|
const (
|
||||||
|
Reset BasicAttribute = iota
|
||||||
|
Bold
|
||||||
|
Faint
|
||||||
|
Italic
|
||||||
|
Underline
|
||||||
|
BlinkSlow
|
||||||
|
BlinkRapid
|
||||||
|
ReverseVideo
|
||||||
|
Concealed
|
||||||
|
CrossedOut
|
||||||
|
)
|
||||||
|
|
||||||
|
// New returns a new Color with attrs Attributes
|
||||||
|
func New(attrs ...BasicAttribute) *Basic {
|
||||||
|
return &Basic{Attrs: attrs}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add adds new Attributes to a Color
|
||||||
|
func (b *Basic) Add(attrs ...BasicAttribute) {
|
||||||
|
for _, attr := range attrs {
|
||||||
|
has := false
|
||||||
|
for _, att := range b.Attrs {
|
||||||
|
if attr == att {
|
||||||
|
has = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !has {
|
||||||
|
b.Attrs = append(b.Attrs, attr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a string representation of the sum of a Color's Attributes
|
||||||
|
func (b *Basic) String() string {
|
||||||
|
attrs := 0
|
||||||
|
for _, attr := range b.Attrs {
|
||||||
|
attrs += int(attr)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%d", attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Basic) sequence() string {
|
||||||
|
format := make([]string, len(b.Attrs))
|
||||||
|
for i, v := range b.Attrs {
|
||||||
|
format[i] = strconv.Itoa(int(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(format, ";")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Basic) wrap(s string) string {
|
||||||
|
return b.format() + s + b.unformat()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Basic) format() string {
|
||||||
|
return fmt.Sprintf("%s[%sm", escape, b.sequence())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Basic) unformat() string {
|
||||||
|
return fmt.Sprintf("%s[%dm", escape, Reset)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Basic) Format(text string) string {
|
||||||
|
if len(b.Attrs) > 0 {
|
||||||
|
return b.wrap(text)
|
||||||
|
}
|
||||||
|
return text
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
package color
|
||||||
|
|
||||||
|
// Foreground text colors
|
||||||
|
const (
|
||||||
|
FgBlack BasicAttribute = iota + 30
|
||||||
|
FgRed
|
||||||
|
FgGreen
|
||||||
|
FgYellow
|
||||||
|
FgBlue
|
||||||
|
FgMagenta
|
||||||
|
FgCyan
|
||||||
|
FgWhite
|
||||||
|
)
|
||||||
|
|
||||||
|
// Foreground Hi-Intensity text colors
|
||||||
|
const (
|
||||||
|
FgHiBlack BasicAttribute = iota + 90
|
||||||
|
FgHiRed
|
||||||
|
FgHiGreen
|
||||||
|
FgHiYellow
|
||||||
|
FgHiBlue
|
||||||
|
FgHiMagenta
|
||||||
|
FgHiCyan
|
||||||
|
FgHiWhite
|
||||||
|
)
|
||||||
|
|
||||||
|
// Background text colors
|
||||||
|
const (
|
||||||
|
BgBlack BasicAttribute = iota + 40
|
||||||
|
BgRed
|
||||||
|
BgGreen
|
||||||
|
BgYellow
|
||||||
|
BgBlue
|
||||||
|
BgMagenta
|
||||||
|
BgCyan
|
||||||
|
BgWhite
|
||||||
|
)
|
||||||
|
|
||||||
|
// Background Hi-Intensity text colors
|
||||||
|
const (
|
||||||
|
BgHiBlack BasicAttribute = iota + 100
|
||||||
|
BgHiRed
|
||||||
|
BgHiGreen
|
||||||
|
BgHiYellow
|
||||||
|
BgHiBlue
|
||||||
|
BgHiMagenta
|
||||||
|
BgHiCyan
|
||||||
|
BgHiWhite
|
||||||
|
)
|
|
@ -0,0 +1,38 @@
|
||||||
|
package color
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var color = New()
|
||||||
|
|
||||||
|
func TestColor(t *testing.T) {
|
||||||
|
tt := []struct {
|
||||||
|
Name string
|
||||||
|
SetAttrs []BasicAttribute
|
||||||
|
AddAttrs []BasicAttribute
|
||||||
|
Size int
|
||||||
|
}{
|
||||||
|
{"Init", nil, nil, 0},
|
||||||
|
{"Set 2", []BasicAttribute{Bold, FgBlack}, nil, 2},
|
||||||
|
{"Add 2", nil, []BasicAttribute{Italic, BgWhite}, 4},
|
||||||
|
{"Set 3", []BasicAttribute{Bold, FgBlack, BgWhite}, nil, 3},
|
||||||
|
{"Add 3", nil, []BasicAttribute{Italic, FgWhite, BgBlack}, 6},
|
||||||
|
{"Add Same", nil, []BasicAttribute{Italic, FgWhite, BgBlack}, 6},
|
||||||
|
{"Add 2 Same", nil, []BasicAttribute{Italic, FgWhite, BgGreen}, 7},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
t.Run(tc.Name, func(t *testing.T) {
|
||||||
|
if tc.SetAttrs != nil {
|
||||||
|
color.Attrs = tc.SetAttrs
|
||||||
|
}
|
||||||
|
if tc.AddAttrs != nil {
|
||||||
|
color.Add(tc.AddAttrs...)
|
||||||
|
}
|
||||||
|
if len(color.Attrs) != tc.Size {
|
||||||
|
t.Logf("color has `%d` attributes, but should have `%d`", len(color.Attrs), tc.Size)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
101
color/color.go
101
color/color.go
|
@ -1,112 +1,17 @@
|
||||||
package color
|
package color
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const escape = "\x1b"
|
const escape = "\x1b"
|
||||||
|
|
||||||
var (
|
type Color interface {
|
||||||
directive = `{[^}]*}`
|
Format(text string) string
|
||||||
directiveRe = regexp.MustCompile("[#]" + directive)
|
|
||||||
)
|
|
||||||
|
|
||||||
// DirectivePrefix changes the directive prefix for parsing color wrap directives
|
|
||||||
func DirectivePrefix(p rune) {
|
|
||||||
directiveRe = regexp.MustCompile("[" + string(p) + "]" + directive)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Color defines a custom color object which is defined by SGR parameters.
|
|
||||||
type Color struct {
|
|
||||||
Attrs []Attribute
|
|
||||||
}
|
|
||||||
|
|
||||||
// New returns a new Color with attrs Attributes
|
|
||||||
func New(attrs ...Attribute) *Color {
|
|
||||||
return &Color{Attrs: attrs}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add adds new Attributes to a Color
|
|
||||||
func (c *Color) Add(attrs ...Attribute) {
|
|
||||||
for _, attr := range attrs {
|
|
||||||
has := false
|
|
||||||
for _, att := range c.Attrs {
|
|
||||||
if attr == att {
|
|
||||||
has = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !has {
|
|
||||||
c.Attrs = append(c.Attrs, attr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string representation of the sum of a Color's Attributes
|
|
||||||
func (c *Color) String() string {
|
|
||||||
attrs := 0
|
|
||||||
for _, attr := range c.Attrs {
|
|
||||||
attrs += int(attr)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%d", attrs)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Color) sequence() string {
|
|
||||||
format := make([]string, len(c.Attrs))
|
|
||||||
for i, v := range c.Attrs {
|
|
||||||
format[i] = strconv.Itoa(int(v))
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.Join(format, ";")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Color) wrap(s string) string {
|
|
||||||
return c.format() + s + unformat()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Color) format() string {
|
|
||||||
return fmt.Sprintf("%s[%sm", escape, c.sequence())
|
|
||||||
}
|
|
||||||
|
|
||||||
func unformat() string {
|
|
||||||
return fmt.Sprintf("%s[%dm", escape, Reset)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format returns a string wrapped in the color
|
|
||||||
func (c *Color) Format(text string) string {
|
|
||||||
if len(c.Attrs) > 0 {
|
|
||||||
return c.wrap(text)
|
|
||||||
}
|
|
||||||
return text
|
|
||||||
}
|
|
||||||
|
|
||||||
// Formatf returns a formatted string wrapped in the color
|
|
||||||
func (c *Color) Formatf(format string, v ...interface{}) string {
|
|
||||||
return c.Format(fmt.Sprintf(format, v...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func parse(text string, primary, secondary *Color) string {
|
|
||||||
for {
|
|
||||||
loc := directiveRe.FindStringIndex(text)
|
|
||||||
if loc == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
text = text[:loc[0]] + unformat() + secondary.Format(text[loc[0]+2:loc[1]-1]) + primary.format() + text[loc[1]:]
|
|
||||||
}
|
|
||||||
return text
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrap returns a string wrapped in a primary color, with #{} directives wrapped in a secondary color
|
|
||||||
func (c *Color) Wrap(text string, secondary *Color) string {
|
|
||||||
text = parse(text, c, secondary)
|
|
||||||
return c.Format(text)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseLevel parses a string and returns a Beaver Level's Color, defaulting to Info
|
// ParseLevel parses a string and returns a Beaver Level's Color, defaulting to Info
|
||||||
func ParseLevel(level string) *Color {
|
func ParseLevel(level string) Color {
|
||||||
switch strings.ToUpper(level) {
|
switch strings.ToUpper(level) {
|
||||||
case "T", "TRACE":
|
case "T", "TRACE":
|
||||||
return Trace
|
return Trace
|
||||||
|
|
|
@ -5,47 +5,14 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
var color = New()
|
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
os.Exit(m.Run())
|
os.Exit(m.Run())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestColor(t *testing.T) {
|
|
||||||
tt := []struct {
|
|
||||||
Name string
|
|
||||||
SetAttrs []Attribute
|
|
||||||
AddAttrs []Attribute
|
|
||||||
Size int
|
|
||||||
}{
|
|
||||||
{"Init", nil, nil, 0},
|
|
||||||
{"Set 2", []Attribute{Bold, FgBlack}, nil, 2},
|
|
||||||
{"Add 2", nil, []Attribute{Italic, BgWhite}, 4},
|
|
||||||
{"Set 3", []Attribute{Bold, FgBlack, BgWhite}, nil, 3},
|
|
||||||
{"Add 3", nil, []Attribute{Italic, FgWhite, BgBlack}, 6},
|
|
||||||
{"Add Same", nil, []Attribute{Italic, FgWhite, BgBlack}, 6},
|
|
||||||
{"Add 2 Same", nil, []Attribute{Italic, FgWhite, BgGreen}, 7},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range tt {
|
|
||||||
t.Run(tc.Name, func(t *testing.T) {
|
|
||||||
if tc.SetAttrs != nil {
|
|
||||||
color.Attrs = tc.SetAttrs
|
|
||||||
}
|
|
||||||
if tc.AddAttrs != nil {
|
|
||||||
color.Add(tc.AddAttrs...)
|
|
||||||
}
|
|
||||||
if len(color.Attrs) != tc.Size {
|
|
||||||
t.Logf("color has `%d` attributes, but should have `%d`", len(color.Attrs), tc.Size)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseLevel(t *testing.T) {
|
func TestParseLevel(t *testing.T) {
|
||||||
tt := []struct {
|
tt := []struct {
|
||||||
Parse string
|
Parse string
|
||||||
Expected *Color
|
Expected Color
|
||||||
}{
|
}{
|
||||||
{"T", Trace},
|
{"T", Trace},
|
||||||
{"Trace", Trace},
|
{"Trace", Trace},
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
package color
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Interface guard
|
||||||
|
var _ Color = &Extended{}
|
||||||
|
|
||||||
|
const (
|
||||||
|
extendedFG = "38;5;"
|
||||||
|
extendedBG = "48;5;"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Extended defines a custom color object which is defined by SGR parameters.
|
||||||
|
type Extended struct {
|
||||||
|
FG ExtendedAttribute
|
||||||
|
BG ExtendedAttribute
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewExtended returns a new Color with an ExtendedAttribute FG and BG
|
||||||
|
func NewExtended(fg, bg ExtendedAttribute) *Extended {
|
||||||
|
return &Extended{
|
||||||
|
FG: fg,
|
||||||
|
BG: bg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a string representation of the sum of a Color's Attributes
|
||||||
|
func (e *Extended) String() string {
|
||||||
|
return fmt.Sprintf("%d", e.FG+e.BG)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Extended) wrap(s string) string {
|
||||||
|
return e.format() + s + e.unformat()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Extended) format() string {
|
||||||
|
return fmt.Sprintf("%s[%s%dm%s[%s%dm", escape, extendedFG, e.FG, escape, extendedBG, e.BG)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Extended) unformat() string {
|
||||||
|
return fmt.Sprintf("%s[%dm", escape, Reset)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Extended) Format(text string) string {
|
||||||
|
return e.wrap(text)
|
||||||
|
}
|
|
@ -0,0 +1,519 @@
|
||||||
|
package color
|
||||||
|
|
||||||
|
// ExtendedAttribute defines an extended color
|
||||||
|
type ExtendedAttribute int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// #000000
|
||||||
|
Black ExtendedAttribute = iota
|
||||||
|
// #800000
|
||||||
|
Maroon
|
||||||
|
// #008000
|
||||||
|
Green
|
||||||
|
// #808000
|
||||||
|
Olive
|
||||||
|
// #000080
|
||||||
|
Navy
|
||||||
|
// #800080
|
||||||
|
Purple
|
||||||
|
// #008080
|
||||||
|
Teal
|
||||||
|
// #c0c0c0
|
||||||
|
Silver
|
||||||
|
// #808080
|
||||||
|
Grey
|
||||||
|
// #ff0000
|
||||||
|
Red
|
||||||
|
// #00ff00
|
||||||
|
Lime
|
||||||
|
// #ffff00
|
||||||
|
Yellow
|
||||||
|
// #0000ff
|
||||||
|
Blue
|
||||||
|
// #ff00ff
|
||||||
|
Fuchsia
|
||||||
|
// #00ffff
|
||||||
|
Aqua
|
||||||
|
// #ffffff
|
||||||
|
White
|
||||||
|
// #000000
|
||||||
|
Grey0
|
||||||
|
// #00005f
|
||||||
|
NavyBlue
|
||||||
|
// #000087
|
||||||
|
DarkBlue
|
||||||
|
// #0000af
|
||||||
|
Blue3
|
||||||
|
// #0000d7
|
||||||
|
Blue3_1
|
||||||
|
// #0000ff
|
||||||
|
Blue1
|
||||||
|
// #005f00
|
||||||
|
DarkGreen
|
||||||
|
// #005f5f
|
||||||
|
DeepSkyBlue4
|
||||||
|
// #005f87
|
||||||
|
DeepSkyBlue4_1
|
||||||
|
// #005faf
|
||||||
|
DeepSkyBlue4_2
|
||||||
|
// #005fd7
|
||||||
|
DodgerBlue3
|
||||||
|
// #005fff
|
||||||
|
DodgerBlue2
|
||||||
|
// #008700
|
||||||
|
Green4
|
||||||
|
// #00875f
|
||||||
|
SpringGreen4
|
||||||
|
// #008787
|
||||||
|
Turquoise4
|
||||||
|
// #0087af
|
||||||
|
DeepSkyBlue3
|
||||||
|
// #0087d7
|
||||||
|
DeepSkyBlue3_1
|
||||||
|
// #0087ff
|
||||||
|
DodgerBlue1
|
||||||
|
// #00af00
|
||||||
|
Green3
|
||||||
|
// #00af5f
|
||||||
|
SpringGreen3
|
||||||
|
// #00af87
|
||||||
|
DarkCyan
|
||||||
|
// #00afaf
|
||||||
|
LightSeaGreen
|
||||||
|
// #00afd7
|
||||||
|
DeepSkyBlue2
|
||||||
|
// #00afff
|
||||||
|
DeepSkyBlue1
|
||||||
|
// #00d700
|
||||||
|
Green3_1
|
||||||
|
// #00d75f
|
||||||
|
SpringGreen3_1
|
||||||
|
// #00d787
|
||||||
|
SpringGreen2
|
||||||
|
// #00d7af
|
||||||
|
Cyan3
|
||||||
|
// #00d7d7
|
||||||
|
DarkTurquoise
|
||||||
|
// #00d7ff
|
||||||
|
Turquoise2
|
||||||
|
// #00ff00
|
||||||
|
Green1
|
||||||
|
// #00ff5f
|
||||||
|
SpringGreen2_1
|
||||||
|
// #00ff87
|
||||||
|
SpringGreen1
|
||||||
|
// #00ffaf
|
||||||
|
MediumSpringGreen
|
||||||
|
// #00ffd7
|
||||||
|
Cyan2
|
||||||
|
// #00ffff
|
||||||
|
Cyan1
|
||||||
|
// #5f0000
|
||||||
|
DarkRed
|
||||||
|
// #5f005f
|
||||||
|
DeepPink4
|
||||||
|
// #5f0087
|
||||||
|
Purple4
|
||||||
|
// #5f00af
|
||||||
|
Purple4_1
|
||||||
|
// #5f00d7
|
||||||
|
Purple3
|
||||||
|
// #5f00ff
|
||||||
|
BlueViolet
|
||||||
|
// #5f5f00
|
||||||
|
Orange4
|
||||||
|
// #5f5f5f
|
||||||
|
Grey37
|
||||||
|
// #5f5f87
|
||||||
|
MediumPurple4
|
||||||
|
// #5f5faf
|
||||||
|
SlateBlue3
|
||||||
|
// #5f5fd7
|
||||||
|
SlateBlue3_1
|
||||||
|
// #5f5fff
|
||||||
|
RoyalBlue1
|
||||||
|
// #5f8700
|
||||||
|
Chartreuse4
|
||||||
|
// #5f875f
|
||||||
|
DarkSeaGreen4
|
||||||
|
// #5f8787
|
||||||
|
PaleTurquoise4
|
||||||
|
// #5f87af
|
||||||
|
SteelBlue
|
||||||
|
// #5f87d7
|
||||||
|
SteelBlue3
|
||||||
|
// #5f87ff
|
||||||
|
CornflowerBlue
|
||||||
|
// #5faf00
|
||||||
|
Chartreuse3
|
||||||
|
// #5faf5f
|
||||||
|
DarkSeaGreen4_1
|
||||||
|
// #5faf87
|
||||||
|
CadetBlue
|
||||||
|
// #5fafaf
|
||||||
|
CadetBlue_1
|
||||||
|
// #5fafd7
|
||||||
|
SkyBlue3
|
||||||
|
// #5fafff
|
||||||
|
SteelBlue1
|
||||||
|
// #5fd700
|
||||||
|
Chartreuse3_1
|
||||||
|
// #5fd75f
|
||||||
|
PaleGreen3
|
||||||
|
// #5fd787
|
||||||
|
SeaGreen3
|
||||||
|
// #5fd7af
|
||||||
|
Aquamarine3
|
||||||
|
// #5fd7d7
|
||||||
|
MediumTurquoise
|
||||||
|
// #5fd7ff
|
||||||
|
SteelBlue1_1
|
||||||
|
// #5fff00
|
||||||
|
Chartreuse2
|
||||||
|
// #5fff5f
|
||||||
|
SeaGreen2
|
||||||
|
// #5fff87
|
||||||
|
SeaGreen1
|
||||||
|
// #5fffaf
|
||||||
|
SeaGreen1_1
|
||||||
|
// #5fffd7
|
||||||
|
Aquamarine1
|
||||||
|
// #5fffff
|
||||||
|
DarkSlateGray2
|
||||||
|
// #870000
|
||||||
|
DarkRed_1
|
||||||
|
// #87005f
|
||||||
|
DeepPink4_1
|
||||||
|
// #870087
|
||||||
|
DarkMagenta
|
||||||
|
// #8700af
|
||||||
|
DarkMagenta_1
|
||||||
|
// #8700d7
|
||||||
|
DarkViolet
|
||||||
|
// #8700ff
|
||||||
|
Purple_1
|
||||||
|
// #875f00
|
||||||
|
Orange4_1
|
||||||
|
// #875f5f
|
||||||
|
LightPink4
|
||||||
|
// #875f87
|
||||||
|
Plum4
|
||||||
|
// #875faf
|
||||||
|
MediumPurple3
|
||||||
|
// #875fd7
|
||||||
|
MediumPurple3_1
|
||||||
|
// #875fff
|
||||||
|
SlateBlue1
|
||||||
|
// #878700
|
||||||
|
Yellow4
|
||||||
|
// #87875f
|
||||||
|
Wheat4
|
||||||
|
// #878787
|
||||||
|
Grey53
|
||||||
|
// #8787af
|
||||||
|
LightSlateGrey
|
||||||
|
// #8787d7
|
||||||
|
MediumPurple
|
||||||
|
// #8787ff
|
||||||
|
LightSlateBlue
|
||||||
|
// #87af00
|
||||||
|
Yellow4_1
|
||||||
|
// #87af5f
|
||||||
|
DarkOliveGreen3
|
||||||
|
// #87af87
|
||||||
|
DarkSeaGreen
|
||||||
|
// #87afaf
|
||||||
|
LightSkyBlue3
|
||||||
|
// #87afd7
|
||||||
|
LightSkyBlue3_1
|
||||||
|
// #87afff
|
||||||
|
SkyBlue2
|
||||||
|
// #87d700
|
||||||
|
Chartreuse2_1
|
||||||
|
// #87d75f
|
||||||
|
DarkOliveGreen3_1
|
||||||
|
// #87d787
|
||||||
|
PaleGreen3_1
|
||||||
|
// #87d7af
|
||||||
|
DarkSeaGreen3
|
||||||
|
// #87d7d7
|
||||||
|
DarkSlateGray3
|
||||||
|
// #87d7ff
|
||||||
|
SkyBlue1
|
||||||
|
// #87ff00
|
||||||
|
Chartreuse1
|
||||||
|
// #87ff5f
|
||||||
|
LightGreen
|
||||||
|
// #87ff87
|
||||||
|
LightGreen_1
|
||||||
|
// #87ffaf
|
||||||
|
PaleGreen1
|
||||||
|
// #87ffd7
|
||||||
|
Aquamarine1_1
|
||||||
|
// #87ffff
|
||||||
|
DarkSlateGray1
|
||||||
|
// #af0000
|
||||||
|
Red3
|
||||||
|
// #af005f
|
||||||
|
DeepPink4_2
|
||||||
|
// #af0087
|
||||||
|
MediumVioletRed
|
||||||
|
// #af00af
|
||||||
|
Magenta3
|
||||||
|
// #af00d7
|
||||||
|
DarkViolet_1
|
||||||
|
// #af00ff
|
||||||
|
Purple_2
|
||||||
|
// #af5f00
|
||||||
|
DarkOrange3
|
||||||
|
// #af5f5f
|
||||||
|
IndianRed
|
||||||
|
// #af5f87
|
||||||
|
HotPink3
|
||||||
|
// #af5faf
|
||||||
|
MediumOrchid3
|
||||||
|
// #af5fd7
|
||||||
|
MediumOrchid
|
||||||
|
// #af5fff
|
||||||
|
MediumPurple2
|
||||||
|
// #af8700
|
||||||
|
DarkGoldenrod
|
||||||
|
// #af875f
|
||||||
|
LightSalmon3
|
||||||
|
// #af8787
|
||||||
|
RosyBrown
|
||||||
|
// #af87af
|
||||||
|
Grey63
|
||||||
|
// #af87d7
|
||||||
|
MediumPurple2_1
|
||||||
|
// #af87ff
|
||||||
|
MediumPurple1
|
||||||
|
// #afaf00
|
||||||
|
Gold3
|
||||||
|
// #afaf5f
|
||||||
|
DarkKhaki
|
||||||
|
// #afaf87
|
||||||
|
NavajoWhite3
|
||||||
|
// #afafaf
|
||||||
|
Grey69
|
||||||
|
// #afafd7
|
||||||
|
LightSteelBlue3
|
||||||
|
// #afafff
|
||||||
|
LightSteelBlue
|
||||||
|
// #afd700
|
||||||
|
Yellow3
|
||||||
|
// #afd75f
|
||||||
|
DarkOliveGreen3_2
|
||||||
|
// #afd787
|
||||||
|
DarkSeaGreen3_1
|
||||||
|
// #afd7af
|
||||||
|
DarkSeaGreen2
|
||||||
|
// #afd7d7
|
||||||
|
LightCyan3
|
||||||
|
// #afd7ff
|
||||||
|
LightSkyBlue1
|
||||||
|
// #afff00
|
||||||
|
GreenYellow
|
||||||
|
// #afff5f
|
||||||
|
DarkOliveGreen2
|
||||||
|
// #afff87
|
||||||
|
PaleGreen1_1
|
||||||
|
// #afffaf
|
||||||
|
DarkSeaGreen2_1
|
||||||
|
// #afffd7
|
||||||
|
DarkSeaGreen1
|
||||||
|
// #afffff
|
||||||
|
PaleTurquoise1
|
||||||
|
// #d70000
|
||||||
|
Red3_1
|
||||||
|
// #d7005f
|
||||||
|
DeepPink3
|
||||||
|
// #d70087
|
||||||
|
DeepPink3_1
|
||||||
|
// #d700af
|
||||||
|
Magenta3_1
|
||||||
|
// #d700d7
|
||||||
|
Magenta3_2
|
||||||
|
// #d700ff
|
||||||
|
Magenta2
|
||||||
|
// #d75f00
|
||||||
|
DarkOrange3_1
|
||||||
|
// #d75f5f
|
||||||
|
IndianRed_1
|
||||||
|
// #d75f87
|
||||||
|
HotPink3_1
|
||||||
|
// #d75faf
|
||||||
|
HotPink2
|
||||||
|
// #d75fd7
|
||||||
|
Orchid
|
||||||
|
// #d75fff
|
||||||
|
MediumOrchid1
|
||||||
|
// #d78700
|
||||||
|
Orange3
|
||||||
|
// #d7875f
|
||||||
|
LightSalmon3_1
|
||||||
|
// #d78787
|
||||||
|
LightPink3
|
||||||
|
// #d787af
|
||||||
|
Pink3
|
||||||
|
// #d787d7
|
||||||
|
Plum3
|
||||||
|
// #d787ff
|
||||||
|
Violet
|
||||||
|
// #d7af00
|
||||||
|
Gold3_1
|
||||||
|
// #d7af5f
|
||||||
|
LightGoldenrod3
|
||||||
|
// #d7af87
|
||||||
|
Tan
|
||||||
|
// #d7afaf
|
||||||
|
MistyRose3
|
||||||
|
// #d7afd7
|
||||||
|
Thistle3
|
||||||
|
// #d7afff
|
||||||
|
Plum2
|
||||||
|
// #d7d700
|
||||||
|
Yellow3_1
|
||||||
|
// #d7d75f
|
||||||
|
Khaki3
|
||||||
|
// #d7d787
|
||||||
|
LightGoldenrod2
|
||||||
|
// #d7d7af
|
||||||
|
LightYellow3
|
||||||
|
// #d7d7d7
|
||||||
|
Grey84
|
||||||
|
// #d7d7ff
|
||||||
|
LightSteelBlue1
|
||||||
|
// #d7ff00
|
||||||
|
Yellow2
|
||||||
|
// #d7ff5f
|
||||||
|
DarkOliveGreen1
|
||||||
|
// #d7ff87
|
||||||
|
DarkOliveGreen1_1
|
||||||
|
// #d7ffaf
|
||||||
|
DarkSeaGreen1_1
|
||||||
|
// #d7ffd7
|
||||||
|
Honeydew2
|
||||||
|
// #d7ffff
|
||||||
|
LightCyan1
|
||||||
|
// #ff0000
|
||||||
|
Red1
|
||||||
|
// #ff005f
|
||||||
|
DeepPink2
|
||||||
|
// #ff0087
|
||||||
|
DeepPink1
|
||||||
|
// #ff00af
|
||||||
|
DeepPink1_1
|
||||||
|
// #ff00d7
|
||||||
|
Magenta2_1
|
||||||
|
// #ff00ff
|
||||||
|
Magenta1
|
||||||
|
// #ff5f00
|
||||||
|
OrangeRed1
|
||||||
|
// #ff5f5f
|
||||||
|
IndianRed1
|
||||||
|
// #ff5f87
|
||||||
|
IndianRed1_1
|
||||||
|
// #ff5faf
|
||||||
|
HotPink
|
||||||
|
// #ff5fd7
|
||||||
|
HotPink_1
|
||||||
|
// #ff5fff
|
||||||
|
MediumOrchid1_1
|
||||||
|
// #ff8700
|
||||||
|
DarkOrange
|
||||||
|
// #ff875f
|
||||||
|
Salmon1
|
||||||
|
// #ff8787
|
||||||
|
LightCoral
|
||||||
|
// #ff87af
|
||||||
|
PaleVioletRed1
|
||||||
|
// #ff87d7
|
||||||
|
Orchid2
|
||||||
|
// #ff87ff
|
||||||
|
Orchid1
|
||||||
|
// #ffaf00
|
||||||
|
Orange1
|
||||||
|
// #ffaf5f
|
||||||
|
SandyBrown
|
||||||
|
// #ffaf87
|
||||||
|
LightSalmon1
|
||||||
|
// #ffafaf
|
||||||
|
LightPink1
|
||||||
|
// #ffafd7
|
||||||
|
Pink1
|
||||||
|
// #ffafff
|
||||||
|
Plum1
|
||||||
|
// #ffd700
|
||||||
|
Gold1
|
||||||
|
// #ffd75f
|
||||||
|
LightGoldenrod2_1
|
||||||
|
// #ffd787
|
||||||
|
LightGoldenrod2_2
|
||||||
|
// #ffd7af
|
||||||
|
NavajoWhite1
|
||||||
|
// #ffd7d7
|
||||||
|
MistyRose1
|
||||||
|
// #ffd7ff
|
||||||
|
Thistle1
|
||||||
|
// #ffff00
|
||||||
|
Yellow1
|
||||||
|
// #ffff5f
|
||||||
|
LightGoldenrod1
|
||||||
|
// #ffff87
|
||||||
|
Khaki1
|
||||||
|
// #ffffaf
|
||||||
|
Wheat1
|
||||||
|
// #ffffd7
|
||||||
|
Cornsilk1
|
||||||
|
// #ffffff
|
||||||
|
Grey100
|
||||||
|
// #080808
|
||||||
|
Grey3
|
||||||
|
// #121212
|
||||||
|
Grey7
|
||||||
|
// #1c1c1c
|
||||||
|
Grey11
|
||||||
|
// #262626
|
||||||
|
Grey15
|
||||||
|
// #303030
|
||||||
|
Grey19
|
||||||
|
// #3a3a3a
|
||||||
|
Grey23
|
||||||
|
// #444444
|
||||||
|
Grey27
|
||||||
|
// #4e4e4e
|
||||||
|
Grey30
|
||||||
|
// #585858
|
||||||
|
Grey35
|
||||||
|
// #626262
|
||||||
|
Grey39
|
||||||
|
// #6c6c6c
|
||||||
|
Grey42
|
||||||
|
// #767676
|
||||||
|
Grey46
|
||||||
|
// #808080
|
||||||
|
Grey50
|
||||||
|
// #8a8a8a
|
||||||
|
Grey54
|
||||||
|
// #949494
|
||||||
|
Grey58
|
||||||
|
// #9e9e9e
|
||||||
|
Grey62
|
||||||
|
// #a8a8a8
|
||||||
|
Grey66
|
||||||
|
// #b2b2b2
|
||||||
|
Grey70
|
||||||
|
// #bcbcbc
|
||||||
|
Grey74
|
||||||
|
// #c6c6c6
|
||||||
|
Grey78
|
||||||
|
// #d0d0d0
|
||||||
|
Grey82
|
||||||
|
// #dadada
|
||||||
|
Grey85
|
||||||
|
// #e4e4e4
|
||||||
|
Grey89
|
||||||
|
// #eeeeee
|
||||||
|
Grey93
|
||||||
|
)
|
|
@ -0,0 +1,66 @@
|
||||||
|
package color
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RGB struct {
|
||||||
|
Red int
|
||||||
|
Green int
|
||||||
|
Blue int
|
||||||
|
}
|
||||||
|
|
||||||
|
func MustParseHex(hexColor string) *RGB {
|
||||||
|
c, err := ParseHex(hexColor)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseHex(hexColor string) (*RGB, error) {
|
||||||
|
hexColor = strings.TrimPrefix(hexColor, "#")
|
||||||
|
|
||||||
|
// Convert to individual parts
|
||||||
|
var rh, gh, bh string
|
||||||
|
switch len(hexColor) {
|
||||||
|
case 3:
|
||||||
|
rh, gh, bh = hexColor[:1]+hexColor[:1], hexColor[1:2]+hexColor[1:2], hexColor[2:3]+hexColor[2:3]
|
||||||
|
case 6:
|
||||||
|
rh, gh, bh = hexColor[0:2], hexColor[2:4], hexColor[4:6]
|
||||||
|
default:
|
||||||
|
return nil, errors.New("invalid hex string")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to bytes
|
||||||
|
rb, err := hex.DecodeString(rh)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
gb, err := hex.DecodeString(gh)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
bb, err := hex.DecodeString(bh)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &RGB{
|
||||||
|
Red: int(rb[0]),
|
||||||
|
Green: int(gb[0]),
|
||||||
|
Blue: int(bb[0]),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns an r;g;b representation of an RGB
|
||||||
|
func (r *RGB) String() string {
|
||||||
|
return r.format()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RGB) format() string {
|
||||||
|
return fmt.Sprintf("%d;%d;%d", r.Red, r.Green, r.Blue)
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package color
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestParseHex(t *testing.T) {
|
||||||
|
tt := []struct {
|
||||||
|
Name string
|
||||||
|
Hex string
|
||||||
|
RGB *RGB
|
||||||
|
Error bool
|
||||||
|
}{
|
||||||
|
{Name: "WhiteShort", Hex: "FFF", RGB: &RGB{255, 255, 255}, Error: false},
|
||||||
|
{Name: "WhiteLong", Hex: "FFFFFF", RGB: &RGB{255, 255, 255}, Error: false},
|
||||||
|
{Name: "WhiteInvalid", Hex: "F", RGB: nil, Error: true},
|
||||||
|
{Name: "InvalidHex", Hex: "ZZZ", RGB: nil, Error: true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
t.Run(tc.Name, func(t *testing.T) {
|
||||||
|
rgb, err := ParseHex(tc.Hex)
|
||||||
|
if err != nil {
|
||||||
|
if tc.Error {
|
||||||
|
return // Pass
|
||||||
|
}
|
||||||
|
t.Log(err)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
if rgb.Red != tc.RGB.Red || rgb.Green != tc.RGB.Green || rgb.Blue != tc.RGB.Blue {
|
||||||
|
t.Logf("hex was parsed incorrectly: parsed %#v vs expected %#v", rgb, tc.RGB)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
package color
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// Interface guard
|
||||||
|
var _ Color = &True{}
|
||||||
|
|
||||||
|
const (
|
||||||
|
trueFG = "38;2;"
|
||||||
|
trueBG = "48;2;"
|
||||||
|
)
|
||||||
|
|
||||||
|
type True struct {
|
||||||
|
FG *RGB
|
||||||
|
BG *RGB
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTrue returns a new Color with RGB FG and BG
|
||||||
|
func NewTrue(fg, bg *RGB) *True {
|
||||||
|
return &True{
|
||||||
|
FG: fg,
|
||||||
|
BG: bg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a string representation of the sum of a Color's Attributes
|
||||||
|
func (t *True) String() string {
|
||||||
|
return fmt.Sprintf("%d", t.FG.Red+t.FG.Green+t.FG.Blue+t.BG.Red+t.BG.Green+t.BG.Blue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *True) wrap(s string) string {
|
||||||
|
return t.format() + s + t.unformat()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *True) format() string {
|
||||||
|
return fmt.Sprintf("%s[%s%sm%s[%s%sm", escape, trueFG, t.FG.format(), escape, trueBG, t.BG.format())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *True) unformat() string {
|
||||||
|
return fmt.Sprintf("%s[%dm", escape, Reset)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *True) Format(text string) string {
|
||||||
|
return t.wrap(text)
|
||||||
|
}
|
2
level.go
2
level.go
|
@ -63,7 +63,7 @@ func (l Level) Prefix() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Color returns a Level's color, defaulting to bold
|
// Color returns a Level's color, defaulting to bold
|
||||||
func (l Level) Color() *color.Color {
|
func (l Level) Color() color.Color {
|
||||||
switch l {
|
switch l {
|
||||||
case TRACE:
|
case TRACE:
|
||||||
return color.Trace
|
return color.Trace
|
||||||
|
|
Reference in New Issue