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.Stack = color.New(color.FgGreen)
|
||||
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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const escape = "\x1b"
|
||||
|
||||
var (
|
||||
directive = `{[^}]*}`
|
||||
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)
|
||||
type Color interface {
|
||||
Format(text string) string
|
||||
}
|
||||
|
||||
// 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) {
|
||||
case "T", "TRACE":
|
||||
return Trace
|
||||
|
|
|
@ -5,47 +5,14 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
var color = New()
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
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) {
|
||||
tt := []struct {
|
||||
Parse string
|
||||
Expected *Color
|
||||
Expected Color
|
||||
}{
|
||||
{"T", 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)
|
||||
}
|
Reference in New Issue