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) } // ParseLevel parses a string and returns a Beaver Level's Color, defaulting to Info func ParseLevel(level string) *Color { switch strings.ToUpper(level) { case "T", "TRACE": return Trace case "D", "DEBUG": return Debug case "I", "INFO": return Info case "W", "WARN": return Warn case "E", "ERROR": return Error case "F", "FATAL": return Fatal } return Info } var ( Trace = New(Bold, FgCyan) Debug = New(Bold, FgBlue) Info = New(Bold, FgGreen) Warn = New(Bold, FgYellow) Error = New(Bold, FgRed) Fatal = New(Bold, BgRed) Default = New() Time = Default Stack = Default )