Update colors (#2)
Simplify example Update colors Add wrapping Signed-off-by: jolheiser <john.olheiser@gmail.com> Co-authored-by: jolheiser <john.olheiser@gmail.com> Reviewed-on: https://gitea.com/jolheiser/beaver/pulls/2pull/4/head v1.0.2
parent
f3053ba01b
commit
5e1722bd43
|
@ -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)
|
|
@ -0,0 +1,45 @@
|
|||
# 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
|
||||
text := color.New(color.BgGreen, color.FgRed, color.Bold).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")
|
||||
```
|
|
@ -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...)
|
||||
}
|
107
color/color.go
107
color/color.go
|
@ -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}
|
||||
|
@ -118,17 +64,18 @@ func (c *Color) sequence() string {
|
|||
}
|
||||
|
||||
func (c *Color) wrap(s string) string {
|
||||
return c.format() + s + c.unformat()
|
||||
return c.format() + s + unformat()
|
||||
}
|
||||
|
||||
func (c *Color) format() string {
|
||||
return fmt.Sprintf("%s[%sm", escape, c.sequence())
|
||||
}
|
||||
|
||||
func (c *Color) unformat() string {
|
||||
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,6 +83,28 @@ 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 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) {
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.jolheiser.com/beaver/color"
|
||||
|
@ -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
|
||||
|
@ -75,11 +74,7 @@ func (l *Logger) write(level Level, text string) {
|
|||
}
|
||||
|
||||
func (l *Logger) log(level Level, v ...interface{}) {
|
||||
var args = make([]string, len(v))
|
||||
for i := 0; i < len(v); i++ {
|
||||
args[i] = fmt.Sprintf("%v", v[i])
|
||||
}
|
||||
text := strings.Join(args, " ")
|
||||
text := fmt.Sprint(v...)
|
||||
l.write(level, text)
|
||||
}
|
||||
|
||||
|
|
Reference in New Issue