diff --git a/README.md b/README.md index 7298356..3d61598 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Coverage Status](https://coveralls.io/repos/github/gookit/color/badge.svg?branch=master)](https://coveralls.io/github/gookit/color?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/gookit/color)](https://goreportcard.com/report/github.com/gookit/color) -Command line color library, written using golang +Command line color library. rich color rendering output, universal API method, compatible with Windows system **[中文说明](README_cn.md)** diff --git a/_examples/256color.go b/_examples/256color.go deleted file mode 100644 index 7905807..0000000 --- a/_examples/256color.go +++ /dev/null @@ -1,5 +0,0 @@ -package main - -func main() { - -} diff --git a/_examples/color256.go b/_examples/color256.go new file mode 100644 index 0000000..4f34d1d --- /dev/null +++ b/_examples/color256.go @@ -0,0 +1,56 @@ +package main + +import ( + "github.com/gookit/color" + "fmt" +) + +// go run ./_examples/color256.go +func main() { + // var s *color.Style256 + + fmt.Printf("%-45s 256 Color(16 bit) Table %-35s\n", " ", " ") + // 0 - 16 + fmt.Printf("%-22sStandard Color %-42sExtended Color \n", " ", " ") + for i := range []int{7:0} {// 0 -7 -> 8/16color: 30–37 + color.S256(255, uint8(i)).Printf(" %-4d", i) + } + fmt.Print(" ") + for i := range []int{7:0} {// 8 -15 -> 16color: 90–97 + i += 8 + color.S256(0, uint8(i)).Printf(" %-4d", i) + } + + var fg uint8 = 255 + fmt.Printf("\n%-50s216 Color\n", " ") + for i := range []int{215:0} {// 16-231:6 × 6 × 6 立方(216色): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5) + v := i + 16 + + if i != 0 { + if i%18 == 0 { + fg = 0 + fmt.Println() // new line + } + + if i % 36 == 0 { + fg = 255 + // fmt.Println() // new line + } + } + + color.S256(fg, uint8(v)).Printf(" %-4d", v) + } + + fmt.Printf("\n%-50s24th Order Grayscale Color\n", " ") + for i := range []int{23:0} {// // 232-255:从黑到白的24阶灰度色 + if i < 12 { + fg = 255 + } else { + fg = 0 + } + + i += 232 + color.S256(fg, uint8(i)).Printf(" %-4d", i) + } + fmt.Println() +} diff --git a/_examples/images/256-color.jpg b/_examples/images/256-color.jpg new file mode 100644 index 0000000..9cfba3b Binary files /dev/null and b/_examples/images/256-color.jpg differ diff --git a/_examples/images/cmd-term-colors.jpg b/_examples/ref/4bit-colors.jpg similarity index 100% rename from _examples/images/cmd-term-colors.jpg rename to _examples/ref/4bit-colors.jpg diff --git a/_examples/images/8-byte-colors.jpg b/_examples/ref/8bit-colors.jpg similarity index 100% rename from _examples/images/8-byte-colors.jpg rename to _examples/ref/8bit-colors.jpg diff --git "a/_examples/ref/ANSI\350\275\254\344\271\211\345\272\217\345\210\227.md" b/_examples/ref/ANSI-escape-sequence.md similarity index 98% rename from "_examples/ref/ANSI\350\275\254\344\271\211\345\272\217\345\210\227.md" rename to _examples/ref/ANSI-escape-sequence.md index c4e4f9a..47eab08 100644 --- "a/_examples/ref/ANSI\350\275\254\344\271\211\345\272\217\345\210\227.md" +++ b/_examples/ref/ANSI-escape-sequence.md @@ -61,7 +61,7 @@ 当硬件开始使用8位DAC时,多个软件为这些颜色名称分配了24位的代码。下面的图表显示了发送到DAC的一些常用硬件和软件的值。 -![cmd-term-colors](../images/cmd-term-colors.jpg) +![cmd-term-colors](4bit-colors.jpg) ### 8位 @@ -77,7 +77,7 @@ 232-255:从黑到白的24阶灰度色 ``` -![8-byte-colors](../images/8-byte-colors.jpg) +![8-byte-colors](8bit-colors.jpg) ### 24位 diff --git a/color.go b/color.go index d918898..5729344 100644 --- a/color.go +++ b/color.go @@ -1,5 +1,6 @@ /* -Package color is command line color library, written using golang +Package color is Command line color library. +Support rich color rendering output, universal API method, compatible with Windows system Source code and other details for the project are available at GitHub: @@ -16,9 +17,9 @@ import ( // console color mode const ( - ModeNormal = iota - Mode256 // 8 bite - ModeRGB // 24 bite + ModeNormal = iota + Mode256 // 8 bite + ModeRGB // 24 bite ModeGrayscale ) @@ -131,3 +132,57 @@ func RenderString(code string, str string) string { func ClearCode(str string) string { return codeRegex.ReplaceAllString(str, "") } + +/************************************************************* + * colored message Printer + *************************************************************/ + +// PrinterFace interface +type PrinterFace interface { + fmt.Stringer + Sprint(a ...interface{}) string + Sprintf(format string, a ...interface{}) string + Print(a ...interface{}) + Printf(format string, a ...interface{}) + Println(a ...interface{}) +} + +// Printer a generic color message printer. +// Usage: +// p := &Printer{"32;45;3"} +// p.Print("message") +type Printer struct { + // ColorCode color code string. eg "32;45;3" + ColorCode string +} + +// String returns color code string. eg: "32;45;3" +func (p *Printer) String() string { + // panic("implement me") + return p.ColorCode +} + +// Sprint returns rendering colored messages +func (p *Printer) Sprint(a ...interface{}) string { + return RenderCode(p.String(), a...) +} + +// Sprintf returns format and rendering colored messages +func (p *Printer) Sprintf(format string, a ...interface{}) string { + return RenderString(p.String(), fmt.Sprintf(format, a...)) +} + +// Print rendering colored messages +func (p *Printer) Print(a ...interface{}) { + fmt.Print(RenderCode(p.String(), a...)) +} + +// Printf format and rendering colored messages +func (p *Printer) Printf(format string, a ...interface{}) { + fmt.Print(RenderString(p.String(), fmt.Sprintf(format, a...))) +} + +// Println rendering colored messages with newline +func (p *Printer) Println(a ...interface{}) { + fmt.Println(RenderCode(p.String(), a...)) +} diff --git a/color_256.go b/color_256.go index 94db5f9..f826ccf 100644 --- a/color_256.go +++ b/color_256.go @@ -6,7 +6,7 @@ import ( ) /* -from wikipedia: +from wikipedia, 256 color: ESC[ … 38;5; … m选择前景色 ESC[ … 48;5; … m选择背景色 0- 7:标准颜色(同 ESC[30–37m) @@ -96,7 +96,7 @@ func (c Color256) Value() uint8 { return c[0] } -// String convert to string +// String convert to color code string. func (c Color256) String() string { if c[1] == AsFg { // 0 is Fg return fmt.Sprintf(TplFg256, c[0]) @@ -125,7 +125,10 @@ func (c Color256) IsEmpty() bool { // 都是由两位uint8组成, 第一位是色彩值; // 第二位与Bit8Color不一样的是,在这里表示是否设置了值 0 未设置 ^0 已设置 type Style256 struct { - Name string + p *Printer + // Name of the style + Name string + // fg and bg color fg, bg Color256 } @@ -205,21 +208,3 @@ func (s *Style256) String() string { return strings.Join(ss, ";") } - -// Color256Table display -func Color256Table() { - -} - -// RGBto216 16-231:6 × 6 × 6 立方(216色): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5) -func RGBto216(n int) int { - if n < 0 { - return 0 - } - - if n > 5 { - return 5 - } - - return n -} diff --git a/color_rgb.go b/color_rgb.go index 93b2c13..5f99992 100644 --- a/color_rgb.go +++ b/color_rgb.go @@ -6,12 +6,12 @@ import ( "strings" ) -// TplFgRGB 24 bit RGB color +// 24 bit RGB color // RGB: // R 0-255 G 0-255 B 0-255 // R 00-FF G 00-FF B 00-FF (16进制) // -// format: +// Format: // ESC[ … 38;2;;; … m // 选择RGB前景色 // ESC[ … 48;2;;; … m // 选择RGB背景色 // @@ -27,14 +27,14 @@ const ( TplBgRGB = "48;2;%d;%d;%d" ) -// mark color is fg or bg +// mark color is fg or bg. const ( AsFg uint8 = iota AsBg ) /************************************************************* - * RGB Color + * RGB Color(Bit24Color, TrueColor) *************************************************************/ // RGBColor definition. @@ -49,11 +49,16 @@ const ( // RGBColor{30,144,255, 1} type RGBColor [4]uint8 -// RGB color create +// create a empty RGBColor +var emptyRGBColor = RGBColor{3: 99} + +// RGB color create. +// Usage: +// c := RGB(30,144,255) +// c := RGB(30,144,255, true) +// c.Print("message") func RGB(r, g, b uint8, isBg ...bool) RGBColor { rgb := RGBColor{r, g, b} - - // mark is bg color if len(isBg) > 0 && isBg[0] { rgb[3] = AsBg } @@ -61,6 +66,45 @@ func RGB(r, g, b uint8, isBg ...bool) RGBColor { return rgb } +// HEX create RGB color from a HEX color string. +// Usage: +// c := HEX("ccc") // rgb: [204 204 204] +// c := HEX("aabbcc") // rgb: [170 187 204] +// c := HEX("#aabbcc") +// c := HEX("0xaabbcc") +// c.Print("message") +func HEX(hex string, isBg ...bool) RGBColor { + if rgb := HexToRGB(hex); len(rgb) > 0 { + return RGB(uint8(rgb[0]), uint8(rgb[1]), uint8(rgb[2]), isBg...) + } + + // mark is empty + return emptyRGBColor +} + +// RGBFromString create RGB color from a string. +// Usage: +// c := RGBFromString("170,187,204") +// c.Print("message") +func RGBFromString(rgb string, isBg ...bool) RGBColor { + ss := stringToArr(rgb, ",") + if len(ss) != 3 { + return emptyRGBColor + } + + var ar [3]int + for i, val := range ss { + iv, err := strconv.Atoi(val) + if err != nil { + return emptyRGBColor + } + + ar[i] = iv + } + + return RGB(uint8(ar[0]), uint8(ar[1]), uint8(ar[2]), isBg...) +} + // Print print message func (c RGBColor) Print(a ...interface{}) { fmt.Print(RenderCode(c.String(), a...)) @@ -102,7 +146,7 @@ func (c RGBColor) String() string { } - // is empty + // >1 is empty return ResetCode } @@ -111,20 +155,11 @@ func (c RGBColor) IsEmpty() bool { return c[3] > 1 } -// HEX string to RGBColor -func HEX(hex string, isBg ...bool) RGBColor { - if rgb := HexToRGB(hex); len(rgb) > 0 { - return RGB(uint8(rgb[0]), uint8(rgb[1]), uint8(rgb[2]), isBg...) - } - - // mark is empty - return RGBColor{3: 99} -} - // HexToRGB hex color string to RGB numbers // Usage: // rgb := HexToRGB("ccc") // rgb: [204 204 204] // rgb := HexToRGB("aabbcc") // rgb: [170 187 204] +// rgb := HexToRGB("#aabbcc") // rgb: [170 187 204] // rgb := HexToRGB("0xad99c0") // rgb: [170 187 204] func HexToRGB(hex string) (rgb []int) { hex = strings.TrimSpace(hex) @@ -132,30 +167,33 @@ func HexToRGB(hex string) (rgb []int) { return } + // like from css. eg "#ccc" "#ad99c0" + if hex[0] == '#' { + hex = hex[1:] + } + hex = strings.ToLower(hex) switch len(hex) { case 3: // "ccc" hex = string([]byte{hex[0], hex[0], hex[1], hex[1], hex[2], hex[2]}) - case 6: // "ad99c0" case 8: // "0xad99c0" hex = strings.TrimPrefix(hex, "0x") - default: // invalid - return } - // convert string to int64 - i64, err := strconv.ParseInt(hex, 16, 32) - if err != nil { - // panic("invalid color string, error: " + err.Error()) + // recheck + if len(hex) != 6 { return } - color := int(i64) - // parse int - rgb = make([]int, 3) - rgb[0] = color >> 16 - rgb[1] = (color & 0x00FF00) >> 8 - rgb[2] = color & 0x0000FF + // convert string to int64 + if i64, err := strconv.ParseInt(hex, 16, 32); err == nil { + color := int(i64) + // parse int + rgb = make([]int, 3) + rgb[0] = color >> 16 + rgb[1] = (color & 0x00FF00) >> 8 + rgb[2] = color & 0x0000FF + } return } @@ -168,35 +206,111 @@ func HexToRGB(hex string) (rgb []int) { // // 前/背景色 // 都是由4位uint8组成, 前三位是色彩值; -// 最后一位与RGBColor不一样的是,在这里表示是否设置了值 +// 最后一位与RGBColor不一样的是,在这里表示是否设置了值 1 表示已设置 ^1 未设置 type RGBStyle struct { - Name string + // Name of the style + Name string + // fg and bg color fg, bg RGBColor } +// NewRGBStyle create a RGBStyle. +func NewRGBStyle(fg RGBColor, bg ...RGBColor) *RGBStyle { + s := &RGBStyle{} + if len(bg) > 0 { + s.SetBg(bg[0]) + } + + return s.SetFg(fg) +} + +// HEXStyle create a RGBStyle from HEX color string. +// Usage: +// s := HEXStyle("aabbcc", "eee") +// s.Print("message") +func HEXStyle(fg string, bg ...string) *RGBStyle { + s := &RGBStyle{} + if len(bg) > 0 { + s.SetBg(HEX(bg[0])) + } + + return s.SetFg(HEX(fg)) +} + +// RGBStyleFromString create a RGBStyle from color value string. +// Usage: +// s := RGBStyleFromString("170,187,204", "70,87,4") +// s.Print("message") +func RGBStyleFromString(fg string, bg ...string) *RGBStyle { + s := &RGBStyle{} + if len(bg) > 0 { + s.SetBg(RGBFromString(bg[0])) + } + + return s.SetFg(RGBFromString(fg)) +} + +// Set fg and bg color +func (s *RGBStyle) Set(fg, bg RGBColor) *RGBStyle { + return s.SetFg(fg).SetBg(bg) +} + +// SetBg set fg color +func (s *RGBStyle) SetFg(fg RGBColor) *RGBStyle { + fg[3] = 1 + s.fg = fg + return s +} + +// SetBg set bg color +func (s *RGBStyle) SetBg(bg RGBColor) *RGBStyle { + bg[3] = 1 + s.bg = bg + return s +} + +// Print print message +func (s *RGBStyle) Print(a ...interface{}) { + fmt.Print(RenderCode(s.String(), a...)) +} + +// Printf format and print message +func (s *RGBStyle) Printf(format string, a ...interface{}) { + fmt.Print(RenderString(s.String(), fmt.Sprintf(format, a...))) +} + +// Println print message with newline +func (s *RGBStyle) Println(a ...interface{}) { + fmt.Println(RenderCode(s.String(), a...)) +} + +// Sprint returns rendered message +func (s *RGBStyle) Sprint(a ...interface{}) string { + return RenderCode(s.String(), a...) +} + +// Sprintf returns format and rendered message +func (s *RGBStyle) Sprintf(format string, a ...interface{}) string { + return RenderString(s.String(), fmt.Sprintf(format, a...)) +} + // String convert to color code string func (s *RGBStyle) String() string { var ss []string - if s.fg[3] > 0 { // last value ensure is enable. + if s.fg[3] == 1 { // last value ensure is enable. ss = append(ss, fmt.Sprintf(TplFgRGB, s.fg[0], s.fg[1], s.fg[2])) } - if s.bg[3] > 0 { + if s.bg[3] == 1 { ss = append(ss, fmt.Sprintf(TplBgRGB, s.bg[0], s.bg[1], s.bg[2])) } return strings.Join(ss, ";") } -// Bit24Color use RGB color -func Bit24Color(str string) { - fmt.Printf("\x1b[38;2;30;144;255m%s\x1b[0m\n", str) -} - -// TrueColor use RGB color -func TrueColor(str string, rgb RGBColor) { - // RGBStyle{RGBColor{'dd', 'cc', 'dd'}, RGBColor{'dd', 'cc', 'dd'}} - +// IsEmpty style +func (s *RGBStyle) IsEmpty() bool { + return s.fg[3] != 1 && s.bg[3] != 1 } // RGBto256 value diff --git a/color_test.go b/color_test.go index 570451a..e26af7d 100644 --- a/color_test.go +++ b/color_test.go @@ -3,9 +3,9 @@ package color import ( "fmt" "github.com/stretchr/testify/assert" - "testing" - "os" "io/ioutil" + "os" + "testing" ) func Example() { @@ -188,8 +188,10 @@ func TestColor256(t *testing.T) { at.Equal(uint8(132), c.Value()) at.Equal("38;5;132", c.String()) + // Color256.Sprint str := c.Sprint("msg") at.Equal("\x1b[38;5;132mmsg\x1b[0m", str) + // Color256.Sprintf str = c.Sprintf("msg") at.Equal("\x1b[38;5;132mmsg\x1b[0m", str) @@ -197,6 +199,25 @@ func TestColor256(t *testing.T) { c = Bit8(132, true) at.False(c.IsEmpty()) at.Equal("48;5;132", c.String()) + + c = C256(132) + // Color256.Print + rewriteStdout() + c.Print("MSG") + str = restoreStdout() + at.Equal("\x1b[38;5;132mMSG\x1b[0m", str) + + // Color256.Printf + rewriteStdout() + c.Printf("A %s", "MSG") + str = restoreStdout() + at.Equal("\x1b[38;5;132mA MSG\x1b[0m", str) + + // Color256.Println + rewriteStdout() + c.Println("MSG") + str = restoreStdout() + at.Equal("\x1b[38;5;132mMSG\x1b[0m\n", str) } func TestStyle256(t *testing.T) { @@ -230,6 +251,26 @@ func TestStyle256(t *testing.T) { s = S256().SetFg(132).SetBg(23) at.Equal("38;5;132;48;5;23", s.String()) at.Equal("\x1b[38;5;132;48;5;23mMSG\x1b[0m", s.Sprint("MSG")) + + s = S256(132) + + // Color256.Print + rewriteStdout() + s.Print("MSG") + str := restoreStdout() + at.Equal("\x1b[38;5;132mMSG\x1b[0m", str) + + // Color256.Printf + rewriteStdout() + s.Printf("A %s", "MSG") + str = restoreStdout() + at.Equal("\x1b[38;5;132mA MSG\x1b[0m", str) + + // Color256.Println + rewriteStdout() + s.Println("MSG") + str = restoreStdout() + at.Equal("\x1b[38;5;132mMSG\x1b[0m\n", str) } /************************************************************* @@ -239,7 +280,6 @@ func TestStyle256(t *testing.T) { func TestRGBColor(t *testing.T) { forceOpenColorRender() defer resetColorRender() - at := assert.New(t) // empty @@ -247,37 +287,103 @@ func TestRGBColor(t *testing.T) { at.True(c.IsEmpty()) at.Equal(ResetCode, c.String()) + // bg + c = RGB(204, 204, 204, true) + at.False(c.IsEmpty()) + at.Equal("48;2;204;204;204", c.String()) + // fg c = RGB(204, 204, 204) at.False(c.IsEmpty()) at.Equal("38;2;204;204;204", c.String()) + // RGBColor.Sprint str := c.Sprint("msg") at.Equal("\x1b[38;2;204;204;204mmsg\x1b[0m", str) + + // RGBColor.Sprintf str = c.Sprintf("msg") at.Equal("\x1b[38;2;204;204;204mmsg\x1b[0m", str) + at.Equal("[204 204 204]", fmt.Sprint(c.Values())) - // bg - c = RGB(204, 204, 204, true) - at.False(c.IsEmpty()) - at.Equal("48;2;204;204;204", c.String()) + // RGBColor.Print + rewriteStdout() + c.Print("msg") + str = restoreStdout() + at.Equal("\x1b[38;2;204;204;204mmsg\x1b[0m", str) + + // RGBColor.Printf + rewriteStdout() + c.Printf("m%s", "sg") + str = restoreStdout() + at.Equal("\x1b[38;2;204;204;204mmsg\x1b[0m", str) + + // RGBColor.Println + rewriteStdout() + c.Println("msg") + str = restoreStdout() + at.Equal("\x1b[38;2;204;204;204mmsg\x1b[0m\n", str) +} + +func TestRGBFromString(t *testing.T) { + forceOpenColorRender() + defer resetColorRender() + at := assert.New(t) + + c := RGBFromString("170,187,204") + at.Equal("\x1b[38;2;170;187;204mmsg\x1b[0m", c.Sprint("msg")) + + c = RGBFromString("170,187,204", true) + at.Equal("\x1b[48;2;170;187;204mmsg\x1b[0m", c.Sprint("msg")) } func TestHexToRGB(t *testing.T) { at := assert.New(t) rgb := HEX("ccc") // rgb: [204 204 204] + at.False(rgb.IsEmpty()) at.Equal("38;2;204;204;204", rgb.String()) rgb = HEX("aabbcc") // rgb: [170 187 204] at.Equal("38;2;170;187;204", rgb.String()) + rgb = HEX("#aabbcc") // rgb: [170 187 204] + at.Equal("38;2;170;187;204", rgb.String()) + rgb = HEX("0xad99c0") // rgb: [170 187 204] at.Equal("38;2;173;153;192", rgb.String()) + rgb = HEX(" ") + at.True(rgb.IsEmpty()) + at.Equal(ResetCode, rgb.String()) + + rgb = HEX("!#$bbcc") + at.Equal(ResetCode, rgb.String()) + + rgb = HEX("#invalid") + at.Equal(ResetCode, rgb.String()) + rgb = HEX("invalid code") at.Equal(ResetCode, rgb.String()) } +func TestRGBStyle(t *testing.T) { + forceOpenColorRender() + defer resetColorRender() + at := assert.New(t) + + s := &RGBStyle{} + at.True(s.IsEmpty()) + // NewRGBStyle + s = NewRGBStyle(RGB(20, 144, 234), RGB(234, 78, 23)) + at.False(s.IsEmpty()) + // HEXStyle + s = HEXStyle("555", "eee") + at.False(s.IsEmpty()) + // RGBStyleFromString + s = RGBStyleFromString("20, 144, 234", "234, 78, 23") + at.False(s.IsEmpty()) +} + /************************************************************* * test helpers *************************************************************/ @@ -300,7 +406,7 @@ var oldStdout, newReader *os.File // rewriteStdout() // fmt.Println("Hello, playground") // msg := restoreStdout() -func rewriteStdout() { +func rewriteStdout() { oldStdout = os.Stdout r, w, _ := os.Pipe() newReader = r @@ -328,4 +434,3 @@ func restoreStdout() string { return string(out) } - diff --git a/color_windows.go b/color_windows.go index bf3d3d1..94e49f8 100644 --- a/color_windows.go +++ b/color_windows.go @@ -296,7 +296,7 @@ func IsTerminal(fd int) bool { // from package: golang.org/x/sys/windows type ( short int16 - word uint16 + word uint16 // coord cursor position coordinates coord struct { diff --git a/style.go b/style.go index e900803..5e9084c 100644 --- a/style.go +++ b/style.go @@ -38,20 +38,25 @@ func (s Style) Sprint(a ...interface{}) string { return RenderCode(s.String(), a...) } +// Sprintf is alias of the 'Render' +func (s Style) Sprintf(format string, a ...interface{}) string { + return RenderString(s.String(), fmt.Sprintf(format, a...)) +} + // Print render and Print text func (s Style) Print(a ...interface{}) { if isLikeInCmd { - winPrint(fmt.Sprint(a...), s...) + winPrint(fmt.Sprint(a...), s...) } else { fmt.Print(RenderCode(s.String(), a...)) } } // Printf render and print text -func (s Style) Printf(format string, args ...interface{}) { - message := fmt.Sprintf(format, args...) +func (s Style) Printf(format string, a ...interface{}) { + message := fmt.Sprintf(format, a...) if isLikeInCmd { - winPrint(message, s...) + winPrint(message, s...) } else { fmt.Print(RenderString(s.String(), message)) } @@ -60,7 +65,7 @@ func (s Style) Printf(format string, args ...interface{}) { // Println render and print text line func (s Style) Println(a ...interface{}) { if isLikeInCmd { - winPrintln(fmt.Sprint(a...), s...) + winPrintln(fmt.Sprint(a...), s...) } else { fmt.Println(RenderCode(s.String(), a...)) } diff --git a/utils.go b/utils.go index 50d25ca..8472482 100644 --- a/utils.go +++ b/utils.go @@ -72,3 +72,19 @@ func IsSupport256Color() bool { // "TERM=xterm-256color" return strings.Contains(os.Getenv("TERM"), "256color") } + +func stringToArr(str, sep string) (arr []string) { + str = strings.TrimSpace(str) + if str == "" { + return + } + + ss := strings.Split(str, sep) + for _, val := range ss { + if val = strings.TrimSpace(val); val != "" { + arr = append(arr, val) + } + } + + return +}