-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from soluble-ai/init
initial code
- Loading branch information
Showing
8 changed files
with
309 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Copyright 2019 Soluble Inc | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
steps: | ||
- label: ":rocket: Go" | ||
command: "golangci-lint run -E gofmt -E stylecheck && go test -cover" | ||
plugins: | ||
- docker#v3.3.0: | ||
image: gcr.io/soluble-ci/go-jnode-ci:latest | ||
always-pull: true | ||
shell: [ "/bin/bash", "-e", "-c" ] | ||
propagate-uid-gid: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,18 @@ | ||
# go-colorize | ||
# go-colorize | ||
|
||
Go from this: | ||
|
||
```go | ||
Colorize("\n{primary:%s} eat {bg-success:pizza :pizza:}{bg-primary: and drink }{warning:beer} %s, but not {bg-danger:%s}\n\n", | ||
"Most folks like to", ":beer:", "everyone") | ||
``` | ||
|
||
To this: | ||
|
||
![Screenshot](screenshot.png) | ||
|
||
Works with https://github.com/kyokomi/emoji and https://github.com/fatih/color. | ||
|
||
Default styles are: | ||
|
||
![Default Styles](default_styles.png) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
// Copyright 2019 Soluble Inc | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
/* | ||
colorize does ANSI colored output and emoji substitution. | ||
Colorize takes a fmt.Printf() template string and looks for styles | ||
in the format: | ||
{style-name:text} | ||
And inserts the color esacpe sequences around the text. It then passes | ||
the template off to emoji.Sprintf() from https://github.com/kyokomi/emoji. | ||
It uses the color attribute names, color.Output, and color.NoColor from | ||
https://github.com/fatih/color. | ||
The style names are modeled off the basic bootstrap color names. | ||
Example use: | ||
colorize.Colorize("{primary:We} want {bg-success:beer :beer:} and {warning:pizza} :pizza:") | ||
*/ | ||
package colorize | ||
|
||
import ( | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/fatih/color" | ||
"github.com/kyokomi/emoji" | ||
) | ||
|
||
const escape = "\x1b" | ||
|
||
// Style is a ANSI escape code sequence | ||
type Style struct { | ||
sequence string | ||
enable *bool | ||
} | ||
|
||
// NewStyle creates a style from a set of attributes | ||
func NewStyle(attributes ...color.Attribute) *Style { | ||
codes := make([]string, len(attributes)) | ||
for i, attr := range attributes { | ||
codes[i] = strconv.Itoa(int(attr)) | ||
} | ||
sequence := fmt.Sprintf("%s[%sm", escape, strings.Join(codes, ";")) | ||
return &Style{sequence, nil} | ||
} | ||
|
||
// Styles maps style names to styles | ||
var Styles = map[string]*Style{ | ||
"primary": NewStyle(color.FgHiBlue), | ||
"secondary": NewStyle(color.FgBlue), | ||
"light": NewStyle(color.BgHiBlack), | ||
"info": nil, | ||
"success": NewStyle(color.FgGreen), | ||
"warning": NewStyle(color.FgYellow), | ||
"danger": NewStyle(color.FgHiRed), | ||
"bg-primary": NewStyle(color.FgHiWhite, color.BgHiBlue), | ||
"bg-secondary": NewStyle(color.FgHiWhite, color.BgBlue), | ||
"bg-success": NewStyle(color.FgHiWhite, color.BgGreen), | ||
"bg-warning": NewStyle(color.FgBlack, color.BgYellow), | ||
"bg-danger": NewStyle(color.FgBlack, color.BgHiRed), | ||
} | ||
var reset = NewStyle(color.Reset) | ||
|
||
// IsEnabled returns true if the style is enabled, either specifically | ||
// to this style or globally via color.NoColor | ||
func (style *Style) IsEnabled() bool { | ||
if style == nil { | ||
return false | ||
} | ||
if style.enable != nil { | ||
return *style.enable | ||
} | ||
return !color.NoColor | ||
} | ||
|
||
// Enable or disable this style | ||
func (style *Style) Enable(val bool) *Style { | ||
style.enable = &val | ||
return style | ||
} | ||
|
||
// Colorize some text, printing the output to color.Output | ||
func Colorize(template string, values ...interface{}) { | ||
fmt.Fprint(color.Output, SColorize(template, values...)) | ||
} | ||
|
||
// Colorize some text, returning a string | ||
func SColorize(template string, values ...interface{}) string { | ||
var b strings.Builder | ||
state := ' ' | ||
var nameStart int | ||
var style *Style | ||
var frag strings.Builder | ||
for i, ch := range template { | ||
switch state { | ||
case ' ': | ||
if ch == '{' { | ||
nameStart = i | ||
state = ch | ||
} else { | ||
b.WriteRune(ch) | ||
if ch == '\\' { | ||
state = ch | ||
} | ||
} | ||
case '\\': | ||
b.WriteRune(ch) | ||
state = ' ' | ||
case '{': | ||
if ch == ':' { | ||
name := template[nameStart+1 : i] | ||
style = Styles[name] | ||
frag.Reset() | ||
state = '}' | ||
} | ||
case '}': | ||
if ch == '\\' { | ||
state = ']' | ||
} else if ch == '}' { | ||
var enabled = style.IsEnabled() | ||
if enabled { | ||
b.WriteString(style.sequence) | ||
} | ||
b.WriteString(frag.String()) | ||
if enabled { | ||
b.WriteString(reset.sequence) | ||
} | ||
state = ' ' | ||
} else { | ||
frag.WriteRune(ch) | ||
} | ||
case ']': | ||
frag.WriteRune(ch) | ||
state = '}' | ||
|
||
} | ||
} | ||
switch state { | ||
case '{', '}', ']': | ||
// if we found a '{' w/o completion, append everything from the start | ||
b.WriteString(template[nameStart:]) | ||
} | ||
template = b.String() | ||
return emoji.Sprintf(template, values...) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
// Copyright 2019 Soluble Inc | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package colorize | ||
|
||
import ( | ||
"fmt" | ||
"github.com/fatih/color" | ||
"sort" | ||
"strings" | ||
"testing" | ||
) | ||
|
||
func TestDemoDefaults(t *testing.T) { | ||
t.SkipNow() | ||
var template strings.Builder | ||
params := make([]interface{}, 0, len(Styles)) | ||
names := make([]string, 0, len(Styles)) | ||
for k := range Styles { | ||
names = append(names, k) | ||
} | ||
sort.Strings(names) | ||
for _, k := range names { | ||
template.WriteString(fmt.Sprintf("{%s: %%12s }\n", k)) | ||
params = append(params, k) | ||
} | ||
Colorize(template.String(), params...) | ||
Colorize("\n{primary:%s} eat {bg-success:pizza :pizza:}{bg-primary: and drink }{warning:beer} %s, but not {bg-danger:%s}\n\n", | ||
"Most folks like to", ":beer:", "everyone") | ||
} | ||
|
||
func TestBasic(t *testing.T) { | ||
s := SColorize("{primary:%s} %s", "hello", "world") | ||
if !strings.Contains(s, "hello") || !strings.Contains(s, "world") { | ||
t.Errorf("string contents wrong") | ||
} | ||
Styles["primary"].Enable(false) | ||
if Styles["primary"].IsEnabled() { | ||
t.Error("primary is enabled") | ||
} | ||
if Styles["nope"].IsEnabled() { | ||
t.Error("nope is enabled") | ||
} | ||
if SColorize("{primary:hello} world") != "hello world" { | ||
t.Error("disable style didn't work") | ||
} | ||
color.Output = &strings.Builder{} | ||
Colorize("hello, world") | ||
if color.Output.(*strings.Builder).String() != "hello, world" { | ||
t.Error("string didn't output") | ||
} | ||
} | ||
|
||
func TestEscapes(t *testing.T) { | ||
if e := SColorize("\\\n\r\t\v"); e != "\\\n\r\t\v" { | ||
t.Errorf("escape sequences wrong: %s", e) | ||
} | ||
} | ||
|
||
func TestIncomplete(t *testing.T) { | ||
if s := SColorize("{primary:foo"); s != "{primary:foo" { | ||
t.Error(s) | ||
} | ||
if s := SColorize("{nope:xxx\\}}"); s != "xxx}" { | ||
t.Error(s) | ||
} | ||
if s := SColorize("{nope:foo\\ bar"); s != "{nope:foo\\ bar" { | ||
t.Error(s) | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
module github.com/soluble-ai/go-colorize | ||
|
||
go 1.13 | ||
|
||
require ( | ||
github.com/fatih/color v1.7.0 | ||
github.com/kyokomi/emoji v2.1.0+incompatible | ||
github.com/mattn/go-colorable v0.1.4 // indirect | ||
github.com/mattn/go-isatty v0.0.10 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= | ||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= | ||
github.com/kyokomi/emoji v2.1.0+incompatible h1:+DYU2RgpI6OHG4oQkM5KlqD3Wd3UPEsX8jamTo1Mp6o= | ||
github.com/kyokomi/emoji v2.1.0+incompatible/go.mod h1:mZ6aGCD7yk8j6QY6KICwnZ2pxoszVseX1DNoGtU2tBA= | ||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= | ||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= | ||
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= | ||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= | ||
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10= | ||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= | ||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8= | ||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU= | ||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.