Update colors

Signed-off-by: jolheiser <john.olheiser@gmail.com>
pull/2/head
jolheiser 2020-02-26 13:54:39 -06:00
parent 1050a04a88
commit 11378d6bc2
No known key found for this signature in database
GPG Key ID: 83E486E71AFEB820
6 changed files with 172 additions and 117 deletions

View File

@ -48,4 +48,6 @@ Beaver allows you to customize the colors of various parts of the message
```go
// Set Trace logging to Magenta instead of Bold-Cyan
color.Trace = color.New(color.FgMagenta)
```
```
[More info for the `color` package](color/README.md)

46
color/README.md 100644
View File

@ -0,0 +1,46 @@
# Color
Beaver comes with the `color` sub-package that can be used even without Beaver calls.
## Formatting a string with a single attribute
```go
text := color.FgRed.Format("red")
```
## Formatting a string with a full color
```go
c := color.New(color.BgGreen, color.FgRed, color.Bold)
text := c.Format("green background, red text, and bold")
```
## Formatting strings with multiple colors
The following are different ways to print `This is a color test!`
where the word `color` is red while everything else is `green`.
### setup
Assuming each example is preceded by
```go
green := color.New(color.FgGreen)
red := color.New(color.FgRed)
```
#### pure `fmt.Println`
```go
fmt.Println(green.Format("This is a"), red.Format("color"), green.Format("test!"))
```
#### `color.Wrap`
```go
fmt.Println(green.Wrap("This is a #{color} test!", red))
```
#### string formatting with `fmt.Printf` and `color.Wrap`
```go
fmt.Printf(green.Wrap("This is a #{%s} test!\n", red), "color")
```
#### using a different directive prefix
```go
color.DirectivePrefix('$')
fmt.Printf(green.Wrap("This is a ${%s} test!\n", red), "color")
```

87
color/attribute.go 100644
View File

@ -0,0 +1,87 @@
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...)
}

View File

@ -2,82 +2,28 @@ 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
}
// Attribute defines a single SGR Code
type Attribute int
const escape = "\x1b"
// 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
)
// New returns a new Color with attrs Attributes
func New(attrs ...Attribute) *Color {
return &Color{Attrs: attrs}
@ -129,6 +75,7 @@ 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)
@ -136,20 +83,26 @@ func (c *Color) Format(text string) string {
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 (c *Color) Wrap(color *Color, text string) string {
return unformat() + c.Format(text) + color.format()
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
}
func (c *Color) Wrapf(color *Color, format string, v ...interface{}) string {
args := make([]interface{}, len(v))
for idx, arg := range v {
args[idx] = color.Wrap(c, fmt.Sprintf("%v", arg))
}
return unformat() + c.Formatf(format, args...) + color.format()
// 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
@ -172,18 +125,12 @@ func ParseLevel(level string) *Color {
}
var (
Trace = New(FgCyan)
Tracef = New(Bold, FgCyan)
Debug = New(FgBlue)
Debugf = New(Bold, FgBlue)
Info = New(FgGreen)
Infof = New(Bold, FgGreen)
Warn = New(FgYellow)
Warnf = New(Bold, FgYellow)
Error = New(FgRed)
Errorf = New(Bold, FgRed)
Fatal = New(BgRed)
Fatalf = New(Bold, BgRed)
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

View File

@ -8,10 +8,7 @@ import (
"go.jolheiser.com/beaver/color"
)
var (
bold = color.New(color.Bold)
italic = color.New(color.Italic)
)
var bold = color.New(color.Bold)
// Level defines a Beaver logging level
type Level int
@ -85,26 +82,6 @@ func (l Level) Color() *color.Color {
}
}
// Color returns a Level's colorf, defaulting to italic
func (l Level) Colorf() *color.Color {
switch l {
case TRACE:
return color.Tracef
case DEBUG:
return color.Debugf
case INFO:
return color.Infof
case WARN:
return color.Warnf
case ERROR:
return color.Errorf
case FATAL:
return color.Fatalf
default:
return italic
}
}
// Levels returns a list of Beaver logging levels
func Levels() []Level {
return []Level{TRACE, DEBUG, INFO, WARN, ERROR, FATAL}

View File

@ -26,7 +26,6 @@ type FormatOptions struct {
LevelPrefix bool
LevelColor bool
MessageColor bool
StyleArgs bool
}
// New returns a new Beaver logger
@ -41,12 +40,12 @@ func New(writer io.Writer, level Level, opts FormatOptions) *Logger {
func (l *Logger) write(level Level, text string) {
if l.Level <= level {
_, file, line, _ := runtime.Caller(l.skip)
var message string
if l.Format.TimePrefix {
message += color.Time.Format(timePrefix(time.Now())) + " "
}
if l.Format.StackPrefix {
_, file, line, _ := runtime.Caller(l.skip)
idx := len(file) - l.Format.StackLimit
if l.Format.StackLimit <= 0 {
idx = 0
@ -81,9 +80,6 @@ func (l *Logger) log(level Level, v ...interface{}) {
func (l *Logger) logf(level Level, format string, v ...interface{}) {
text := fmt.Sprintf(format, v...)
if l.Format.StyleArgs {
}
l.write(level, text)
}