From 308b7c980fd982ad3c6215734124f5c2ef7e7d14 Mon Sep 17 00:00:00 2001 From: jolheiser Date: Thu, 20 Feb 2020 10:52:29 -0600 Subject: [PATCH 1/7] Update import Signed-off-by: jolheiser --- Makefile | 6 +++++- _examples/examples.go | 4 ++-- go.mod | 2 +- level.go | 2 +- logger.go | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index b277945..888096f 100644 --- a/Makefile +++ b/Makefile @@ -10,4 +10,8 @@ lint: .PHONY: fmt fmt: - $(GO) fmt ./... \ No newline at end of file + $(GO) fmt ./... + +.PHONY: test +test: + $(GO) test -race ./... \ No newline at end of file diff --git a/_examples/examples.go b/_examples/examples.go index 22f9a6d..55af5e2 100644 --- a/_examples/examples.go +++ b/_examples/examples.go @@ -4,8 +4,8 @@ import ( "fmt" "os" - "gitea.com/jolheiser/beaver" - "gitea.com/jolheiser/beaver/color" + "go.jolheiser.com/beaver" + "go.jolheiser.com/beaver/color" ) func main() { diff --git a/go.mod b/go.mod index 2e62c98..25bf78f 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module gitea.com/jolheiser/beaver +module go.jolheiser.com/beaver go 1.12 diff --git a/level.go b/level.go index d8e5950..314121a 100644 --- a/level.go +++ b/level.go @@ -5,7 +5,7 @@ import ( "strings" "time" - "gitea.com/jolheiser/beaver/color" + "go.jolheiser.com/beaver/color" ) var bold = color.New(color.Bold) diff --git a/logger.go b/logger.go index c337d62..4e8b3e5 100644 --- a/logger.go +++ b/logger.go @@ -8,7 +8,7 @@ import ( "strings" "time" - "gitea.com/jolheiser/beaver/color" + "go.jolheiser.com/beaver/color" ) // Logger is a base Beaver logger -- 2.41.0 From f3053ba01b8173f207c9ee96bf3cec530b1f0328 Mon Sep 17 00:00:00 2001 From: John Olheiser Date: Thu, 20 Feb 2020 17:25:24 +0000 Subject: [PATCH 2/7] Update import (#1) Update import Signed-off-by: jolheiser Co-authored-by: jolheiser Reviewed-on: https://gitea.com/jolheiser/beaver/pulls/1 --- Makefile | 6 +++++- _examples/examples.go | 4 ++-- go.mod | 2 +- level.go | 2 +- logger.go | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index b277945..888096f 100644 --- a/Makefile +++ b/Makefile @@ -10,4 +10,8 @@ lint: .PHONY: fmt fmt: - $(GO) fmt ./... \ No newline at end of file + $(GO) fmt ./... + +.PHONY: test +test: + $(GO) test -race ./... \ No newline at end of file diff --git a/_examples/examples.go b/_examples/examples.go index 22f9a6d..55af5e2 100644 --- a/_examples/examples.go +++ b/_examples/examples.go @@ -4,8 +4,8 @@ import ( "fmt" "os" - "gitea.com/jolheiser/beaver" - "gitea.com/jolheiser/beaver/color" + "go.jolheiser.com/beaver" + "go.jolheiser.com/beaver/color" ) func main() { diff --git a/go.mod b/go.mod index 2e62c98..25bf78f 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module gitea.com/jolheiser/beaver +module go.jolheiser.com/beaver go 1.12 diff --git a/level.go b/level.go index d8e5950..314121a 100644 --- a/level.go +++ b/level.go @@ -5,7 +5,7 @@ import ( "strings" "time" - "gitea.com/jolheiser/beaver/color" + "go.jolheiser.com/beaver/color" ) var bold = color.New(color.Bold) diff --git a/logger.go b/logger.go index c337d62..4e8b3e5 100644 --- a/logger.go +++ b/logger.go @@ -8,7 +8,7 @@ import ( "strings" "time" - "gitea.com/jolheiser/beaver/color" + "go.jolheiser.com/beaver/color" ) // Logger is a base Beaver logger -- 2.41.0 From 5e1722bd4357aba706501845203f1d1fb9b5d373 Mon Sep 17 00:00:00 2001 From: John Olheiser Date: Wed, 26 Feb 2020 20:01:20 +0000 Subject: [PATCH 3/7] Update colors (#2) Simplify example Update colors Add wrapping Signed-off-by: jolheiser Co-authored-by: jolheiser Reviewed-on: https://gitea.com/jolheiser/beaver/pulls/2 --- README.md | 4 +- color/README.md | 45 +++++++++++++++++++ color/attribute.go | 87 ++++++++++++++++++++++++++++++++++++ color/color.go | 107 ++++++++++++++++----------------------------- logger.go | 9 +--- 5 files changed, 175 insertions(+), 77 deletions(-) create mode 100644 color/README.md create mode 100644 color/attribute.go diff --git a/README.md b/README.md index 9d495e3..daa4c77 100644 --- a/README.md +++ b/README.md @@ -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) -``` \ No newline at end of file +``` + +[More info for the `color` package](color/README.md) \ No newline at end of file diff --git a/color/README.md b/color/README.md new file mode 100644 index 0000000..1557d77 --- /dev/null +++ b/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") +``` \ No newline at end of file diff --git a/color/attribute.go b/color/attribute.go new file mode 100644 index 0000000..31f3b58 --- /dev/null +++ b/color/attribute.go @@ -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...) +} diff --git a/color/color.go b/color/color.go index 27b06ea..04483fb 100644 --- a/color/color.go +++ b/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) { diff --git a/logger.go b/logger.go index 4e8b3e5..d586d9b 100644 --- a/logger.go +++ b/logger.go @@ -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) } -- 2.41.0 From c628fd1987e4654ce497db68f0378fd3fc1c0780 Mon Sep 17 00:00:00 2001 From: John Olheiser Date: Wed, 17 Feb 2021 05:44:17 +0800 Subject: [PATCH 4/7] Add extended and true colors (#3) Co-authored-by: jolheiser Reviewed-on: https://gitea.com/jolheiser/beaver/pulls/3 Co-authored-by: John Olheiser Co-committed-by: John Olheiser --- .golangci.yml | 23 -- LICENSE | 7 + Makefile | 8 - README.md | 6 +- _examples/examples.go | 8 + color/README.md | 35 +-- color/attribute.go | 87 ------- color/basic.go | 90 +++++++ color/basic_colors.go | 49 ++++ color/basic_test.go | 38 +++ color/color.go | 101 +------- color/color_test.go | 35 +-- color/extended.go | 48 ++++ color/extended_colors.go | 519 +++++++++++++++++++++++++++++++++++++++ color/rgb.go | 66 +++++ color/rgb_test.go | 35 +++ color/true.go | 45 ++++ level.go | 2 +- 18 files changed, 922 insertions(+), 280 deletions(-) delete mode 100644 .golangci.yml create mode 100644 LICENSE delete mode 100644 color/attribute.go create mode 100644 color/basic.go create mode 100644 color/basic_colors.go create mode 100644 color/basic_test.go create mode 100644 color/extended.go create mode 100644 color/extended_colors.go create mode 100644 color/rgb.go create mode 100644 color/rgb_test.go create mode 100644 color/true.go diff --git a/.golangci.yml b/.golangci.yml deleted file mode 100644 index 6d71439..0000000 --- a/.golangci.yml +++ /dev/null @@ -1,23 +0,0 @@ -linters: - enable: - - deadcode - - dogsled - - dupl - - errcheck - - funlen - - gocognit - - goconst - - gocritic - - gocyclo - - gofmt - - golint - - gosimple - - govet - - misspell - - prealloc - - staticcheck - - structcheck - - typecheck - - unparam - - unused - - varcheck \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0f02641 --- /dev/null +++ b/LICENSE @@ -0,0 +1,7 @@ +Copyright 2020 John Olheiser + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/Makefile b/Makefile index 888096f..2f88598 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,5 @@ GO ?= go -.PHONY: lint -lint: - @hash golangci-lint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - export BINARY="golangci-lint"; \ - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.23.1; \ - fi - golangci-lint run --timeout 5m - .PHONY: fmt fmt: $(GO) fmt ./... diff --git a/README.md b/README.md index daa4c77..d2d613e 100644 --- a/README.md +++ b/README.md @@ -50,4 +50,8 @@ Beaver allows you to customize the colors of various parts of the message color.Trace = color.New(color.FgMagenta) ``` -[More info for the `color` package](color/README.md) \ No newline at end of file +[More info for the `color` package](color/README.md) + +## LICENSE + +[MIT](LICENSE) \ No newline at end of file diff --git a/_examples/examples.go b/_examples/examples.go index 55af5e2..14df6ac 100644 --- a/_examples/examples.go +++ b/_examples/examples.go @@ -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")) } diff --git a/color/README.md b/color/README.md index 1557d77..d304518 100644 --- a/color/README.md +++ b/color/README.md @@ -2,6 +2,9 @@ Beaver comes with the `color` sub-package that can be used even without Beaver calls. +`Color` is an interface that simply needs `Format(text string) string` to fulfill it. +Any logger in beaver can be set to a `Color`. + ## Formatting a string with a single attribute ```go text := color.FgRed.Format("red") @@ -12,34 +15,10 @@ text := color.FgRed.Format("red") 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`. +## Extended colors -### setup -Assuming each example is preceded by -```go -green := color.New(color.FgGreen) -red := color.New(color.FgRed) -``` +Extended colors are 256-color extensions. They can be referred to by name, available in [extended_colors.go](extended_colors.go). -#### pure `fmt.Println` -```go -fmt.Println(green.Format("This is a"), red.Format("color"), green.Format("test!")) -``` +## True colors -#### `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") -``` \ No newline at end of file +True colors are full RBG colors, they can be either created with RGB values or parsed from hex. \ No newline at end of file diff --git a/color/attribute.go b/color/attribute.go deleted file mode 100644 index 31f3b58..0000000 --- a/color/attribute.go +++ /dev/null @@ -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...) -} diff --git a/color/basic.go b/color/basic.go new file mode 100644 index 0000000..99247a1 --- /dev/null +++ b/color/basic.go @@ -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 +} diff --git a/color/basic_colors.go b/color/basic_colors.go new file mode 100644 index 0000000..0a9ca24 --- /dev/null +++ b/color/basic_colors.go @@ -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 +) diff --git a/color/basic_test.go b/color/basic_test.go new file mode 100644 index 0000000..24c3f38 --- /dev/null +++ b/color/basic_test.go @@ -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) + } + }) + } +} diff --git a/color/color.go b/color/color.go index 04483fb..2cd4e02 100644 --- a/color/color.go +++ b/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 diff --git a/color/color_test.go b/color/color_test.go index 8a03220..f5059aa 100644 --- a/color/color_test.go +++ b/color/color_test.go @@ -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}, diff --git a/color/extended.go b/color/extended.go new file mode 100644 index 0000000..0a08b84 --- /dev/null +++ b/color/extended.go @@ -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) +} diff --git a/color/extended_colors.go b/color/extended_colors.go new file mode 100644 index 0000000..a264b48 --- /dev/null +++ b/color/extended_colors.go @@ -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 +) diff --git a/color/rgb.go b/color/rgb.go new file mode 100644 index 0000000..90546bd --- /dev/null +++ b/color/rgb.go @@ -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) +} diff --git a/color/rgb_test.go b/color/rgb_test.go new file mode 100644 index 0000000..0290bfc --- /dev/null +++ b/color/rgb_test.go @@ -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() + } + }) + } +} diff --git a/color/true.go b/color/true.go new file mode 100644 index 0000000..3d6aa5e --- /dev/null +++ b/color/true.go @@ -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) +} diff --git a/level.go b/level.go index 314121a..baf8887 100644 --- a/level.go +++ b/level.go @@ -63,7 +63,7 @@ func (l Level) Prefix() string { } // Color returns a Level's color, defaulting to bold -func (l Level) Color() *color.Color { +func (l Level) Color() color.Color { switch l { case TRACE: return color.Trace -- 2.41.0 From 262effd971740480b2e2a47daa39c36549fbcd0b Mon Sep 17 00:00:00 2001 From: John Olheiser Date: Wed, 17 Feb 2021 13:40:21 +0800 Subject: [PATCH 5/7] Fix legacy code (#4) Co-authored-by: jolheiser Reviewed-on: https://gitea.com/jolheiser/beaver/pulls/4 Co-authored-by: John Olheiser Co-committed-by: John Olheiser --- color/basic.go | 6 ++++++ color/basic_colors.go | 21 +++++++++++++++++++++ color/color.go | 1 + color/extended.go | 6 ++++++ color/true.go | 6 ++++++ 5 files changed, 40 insertions(+) diff --git a/color/basic.go b/color/basic.go index 99247a1..b2b3ca4 100644 --- a/color/basic.go +++ b/color/basic.go @@ -82,9 +82,15 @@ func (b *Basic) unformat() string { return fmt.Sprintf("%s[%dm", escape, Reset) } +// Format returns a string wrapped in the basic color func (b *Basic) Format(text string) string { if len(b.Attrs) > 0 { return b.wrap(text) } return text } + +// Formatf returns a formatted string wrapped in the basic color +func (b *Basic) Formatf(format string, v ...interface{}) string { + return b.Format(fmt.Sprintf(format, v...)) +} diff --git a/color/basic_colors.go b/color/basic_colors.go index 0a9ca24..f44ebcc 100644 --- a/color/basic_colors.go +++ b/color/basic_colors.go @@ -47,3 +47,24 @@ const ( BgHiCyan BgHiWhite ) + +var attrCache = make(map[BasicAttribute]*Basic) + +func attr(a BasicAttribute) *Basic { + if c, ok := attrCache[a]; ok { + return c + } + c := New(a) + attrCache[a] = c + return c +} + +// Format is a quick way to format a string using a single attribute +func (a BasicAttribute) 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 BasicAttribute) Formatf(text string, v ...interface{}) string { + return attr(a).Formatf(text, v...) +} diff --git a/color/color.go b/color/color.go index 2cd4e02..df5d90f 100644 --- a/color/color.go +++ b/color/color.go @@ -8,6 +8,7 @@ const escape = "\x1b" type Color interface { Format(text string) string + Formatf(text string, v ...interface{}) string } // ParseLevel parses a string and returns a Beaver Level's Color, defaulting to Info diff --git a/color/extended.go b/color/extended.go index 0a08b84..a8a7798 100644 --- a/color/extended.go +++ b/color/extended.go @@ -43,6 +43,12 @@ func (e *Extended) unformat() string { return fmt.Sprintf("%s[%dm", escape, Reset) } +// Format returns a string wrapped in the extended color func (e *Extended) Format(text string) string { return e.wrap(text) } + +// Formatf returns a formatted string wrapped in the extended color +func (e *Extended) Formatf(text string, v ...interface{}) string { + return e.wrap(fmt.Sprintf(text, v...)) +} diff --git a/color/true.go b/color/true.go index 3d6aa5e..5601db1 100644 --- a/color/true.go +++ b/color/true.go @@ -40,6 +40,12 @@ func (t *True) unformat() string { return fmt.Sprintf("%s[%dm", escape, Reset) } +// Format returns a string wrapped in the true color func (t *True) Format(text string) string { return t.wrap(text) } + +// Formatf returns a formatted string wrapped in the true color +func (t *True) Formatf(text string, v ...interface{}) string { + return t.wrap(fmt.Sprintf(text, v...)) +} -- 2.41.0 From 0b1a1e4bd0f8f5a149d4313e7b0d75dbe86ee0bd Mon Sep 17 00:00:00 2001 From: John Olheiser Date: Wed, 17 Feb 2021 13:58:17 +0800 Subject: [PATCH 6/7] Time format (#5) Co-authored-by: jolheiser Reviewed-on: https://gitea.com/jolheiser/beaver/pulls/5 Co-authored-by: John Olheiser Co-committed-by: John Olheiser --- level.go | 36 ------------------------------------ logger.go | 2 +- 2 files changed, 1 insertion(+), 37 deletions(-) diff --git a/level.go b/level.go index baf8887..7b1004f 100644 --- a/level.go +++ b/level.go @@ -3,7 +3,6 @@ package beaver import ( "fmt" "strings" - "time" "go.jolheiser.com/beaver/color" ) @@ -105,38 +104,3 @@ func ParseLevel(level string) Level { } return INFO } - -func timePrefix(t time.Time) string { - var buf = &[]byte{} - year, month, day := t.Date() - itoa(buf, int(month), 2) - *buf = append(*buf, '/') - itoa(buf, day, 2) - *buf = append(*buf, '/') - itoa(buf, year, 4) - *buf = append(*buf, ' ') - - hour, min, sec := t.Clock() - itoa(buf, hour, 2) - *buf = append(*buf, ':') - itoa(buf, min, 2) - *buf = append(*buf, ':') - itoa(buf, sec, 2) - - return string(*buf) -} - -func itoa(buf *[]byte, i int, wid int) { - var b [20]byte - bp := len(b) - 1 - for i >= 10 || wid > 1 { - wid-- - q := i / 10 - b[bp] = byte('0' + i - q*10) - bp-- - i = q - } - // i < 10 - b[bp] = byte('0' + i) - *buf = append(*buf, b[bp:]...) -} diff --git a/logger.go b/logger.go index d586d9b..39c096d 100644 --- a/logger.go +++ b/logger.go @@ -42,7 +42,7 @@ func (l *Logger) write(level Level, text string) { if l.Level <= level { var message string if l.Format.TimePrefix { - message += color.Time.Format(timePrefix(time.Now())) + " " + message += color.Time.Format(time.Now().Format("01/02/2006 15:04:05")) + " " } if l.Format.StackPrefix { _, file, line, _ := runtime.Caller(l.skip) -- 2.41.0 From 8af49ac71fc3c78fcf6ecb9ab06652b45b7b3549 Mon Sep 17 00:00:00 2001 From: jolheiser Date: Mon, 21 Jun 2021 21:47:43 +0000 Subject: [PATCH 7/7] Print to stderr by default --- console.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console.go b/console.go index ccf081e..83d3be9 100644 --- a/console.go +++ b/console.go @@ -6,7 +6,7 @@ import ( var ( Console = &Logger{ - Writer: os.Stdout, + Writer: os.Stderr, Level: INFO, Format: FormatOptions{ MessageColor: true, -- 2.41.0