From 2b36b34ba460d117cb81f7c61d364151c25d81c4 Mon Sep 17 00:00:00 2001 From: inhere Date: Fri, 24 Aug 2018 00:28:45 +0800 Subject: [PATCH] update readme. add more tests --- README.md | 86 +++++++++++++++++++++++++++- README_cn.md | 93 ++++++++++++++++++++++++++++-- color.go | 25 ++++++--- color_256.go | 2 +- color_not_win.go | 13 +---- color_rgb.go | 8 +-- color_test.go | 143 ++++++++++++++++++++++++++++++++++++++++------- color_windows.go | 8 +-- tag_test.go | 30 ++++++++++ utils.go | 16 ------ 10 files changed, 351 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index 3d61598..6afac32 100644 --- a/README.md +++ b/README.md @@ -12,12 +12,14 @@ Command line color library. rich color rendering output, universal API method, c ## Features - Simple to use -- Supports rich color output +- Supports rich color output 16色(4bit),256色(8bit),RGB色彩(24bit) + - 16 color (4bit) is the most commonly used and most widely supported, supporting Windows `cmd.exe` + - 256 and RGB color support `linux` `mac` and Windows `CONEMU` `git-bash` `mintty` part terminal - Generic API method: `Print` `Printf` `Println` `Sprint` `Sprintf` - Supports html tab-style color rendering. like: `message` -- Compatible with Windows system environment - Basic color: `Bold` `Black` `White` `Gray` `Red` `Green` `Yellow` `Blue` `Magenta` `Cyan` - Extra style: `Info` `Note` `Light` `Error` `Danger` `Notice` `Success` `Comment` `Primary` `Warning` `Question` `Secondary` +- Compatible with Windows system environment ## Install @@ -178,6 +180,86 @@ color.Tag("info").Println("info style text") ![color-tags](_examples/images/color-tags.jpg) +## Use 256 color + +### Use foreground or background color + +- `color.C256(val uint8, isBg ...bool) Color256` + +```go +c := color.C256(132) // fg color +c.Println("message") +c.Printf("format %s", "message") + +c := color.C256(132, true) // bg color +c.Println("message") +c.Printf("format %s", "message") +``` + +### Use 256 color style + +> Can set foreground and background colors at the same time + +- `color.S256(fgAndBg ...uint8) *Style256` + +```go +s := color.S256(32, 203) +s.Println("message") +s.Printf("format %s", "message") +``` + +> run demo: `go run ./_examples/color256.go` + +![color-tags](_examples/images/256-color.jpg) + +## Use RGB color + +### Use foreground or background color + +- `color.RGB(r, g, b uint8, isBg ...bool) RGBColor` + +```go +c := color.RGB(30,144,255) // fg color +c.Println("message") +c.Printf("format %s", "message") + +c := color.RGB(30,144,255, true) // bg color +c.Println("message") +c.Printf("format %s", "message") +``` + +- `color.HEX(hex string, isBg ...bool) RGBColor` Create from hexadecimal color string + +```go +c := HEX("ccc") // 也可以写为: "cccccc" "#cccccc" +c.Println("message") +c.Printf("format %s", "message") + +c = HEX("aabbcc", true) // as bg color +c.Println("message") +c.Printf("format %s", "message") +``` + +### Use RGB color style + +> Can set foreground and background colors at the same time + +- `color.NewRGBStyle(fg RGBColor, bg ...RGBColor) *RGBStyle` + +```go +s := NewRGBStyle(RGB(20, 144, 234), RGB(234, 78, 23)) +s.Println("message") +s.Printf("format %s", "message") +``` + +- `color.HEXStyle(fg string, bg ...string) *RGBStyle` Create from hexadecimal color string + +```go +s := HEXStyle("11aa23", "eee") +s.Println("message") +s.Printf("format %s", "message") +``` + ## Refer - `issue9/term` https://github.com/issue9/term diff --git a/README_cn.md b/README_cn.md index 0ad166c..09b057c 100644 --- a/README_cn.md +++ b/README_cn.md @@ -5,19 +5,21 @@ [![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) -golang下的命令行色彩使用库 +golang下的命令行色彩使用库, 拥有丰富的色彩渲染输出,通用的API方法,兼容Windows系统 **[EN Readme](README.md)** ## 功能特色 - 使用简单方便 -- 支持丰富的颜色输出 +- 支持丰富的颜色输出, 16色(4bit),256色(8bit),RGB色彩(24bit) + - 16色(4bit)是最常用和支持最广的,支持Windows `cmd.exe` + - 另外两种支持 `linux` `mac` 和 Windows下的 `CONEMU` `git-bash` `mintty` 等部分终端 - 通用的API方法:`Print` `Printf` `Println` `Sprint` `Sprintf` - 同时支持html标签式的颜色渲染. eg: `message` -- 兼容Windows系统环境 - 基础色彩: `Bold` `Black` `White` `Gray` `Red` `Green` `Yellow` `Blue` `Magenta` `Cyan` - 扩展风格: `Info` `Note` `Light` `Error` `Danger` `Notice` `Success` `Comment` `Primary` `Warning` `Question` `Secondary` +- 兼容Windows系统环境 ## 获取安装 @@ -179,12 +181,11 @@ color.Success.Println("Success message") ![theme-style](_examples/images/theme-style.jpg) - -### 使用颜色html标签 +### 使用颜色标签 > **不** 支持在windows `cmd.exe` 使用,但不影响使用,会自动去除颜色标签 -使用内置的颜色标签可以非常方便简单的构建自己需要的任何格式 +使用内置的颜色标签,可以非常方便简单的构建自己需要的任何格式 ```go // 使用内置的 color tag @@ -212,6 +213,86 @@ color.Tag("info").Println("info style text") ![color-tags](_examples/images/color-tags.jpg) +## 256色使用 + +### 使用前景或后景色 + +- `color.C256(val uint8, isBg ...bool) Color256` + +```go +c := color.C256(132) // fg color +c.Println("message") +c.Printf("format %s", "message") + +c := color.C256(132, true) // bg color +c.Println("message") +c.Printf("format %s", "message") +``` + +### 使用风格 + +> 可同时设置前景和背景色 + +- `color.S256(fgAndBg ...uint8) *Style256` + +```go +s := color.S256(32, 203) +s.Println("message") +s.Printf("format %s", "message") +``` + +> 运行 demo: `go run ./_examples/color256.go` + +![color-tags](_examples/images/256-color.jpg) + +## RGB色彩使用 + +### 使用前景或后景色 + +- `color.RGB(r, g, b uint8, isBg ...bool) RGBColor` + +```go +c := color.RGB(30,144,255) // fg color +c.Println("message") +c.Printf("format %s", "message") + +c := color.RGB(30,144,255, true) // bg color +c.Println("message") +c.Printf("format %s", "message") +``` + +- `color.HEX(hex string, isBg ...bool) RGBColor` 从16进制颜色创建 + +```go +c := HEX("ccc") // 也可以写为: "cccccc" "#cccccc" +c.Println("message") +c.Printf("format %s", "message") + +c = HEX("aabbcc", true) // as bg color +c.Println("message") +c.Printf("format %s", "message") +``` + +### 使用风格 + +> 可同时设置前景和背景色 + +- `color.NewRGBStyle(fg RGBColor, bg ...RGBColor) *RGBStyle` + +```go +s := NewRGBStyle(RGB(20, 144, 234), RGB(234, 78, 23)) +s.Println("message") +s.Printf("format %s", "message") +``` + +- `color.HEXStyle(fg string, bg ...string) *RGBStyle` 从16进制颜色创建 + +```go +s := HEXStyle("11aa23", "eee") +s.Println("message") +s.Printf("format %s", "message") +``` + ## 参考项目 - `issue9/term` https://github.com/issue9/term diff --git a/color.go b/color.go index 5729344..58d1dbe 100644 --- a/color.go +++ b/color.go @@ -16,12 +16,12 @@ import ( ) // console color mode -const ( - ModeNormal = iota - Mode256 // 8 bite - ModeRGB // 24 bite - ModeGrayscale -) +// const ( +// ModeNormal = iota +// Mode256 // 8 bite +// ModeRGB // 24 bite +// ModeGrayscale +// ) // color render templates const ( @@ -29,9 +29,6 @@ const ( FullColorTpl = "\x1b[%sm%s\x1b[0m" ) -// ResetCode value -const ResetCode = "0" - // ResetSet 重置/正常 关闭所有属性。 const ResetSet = "\x1b[0m" @@ -156,6 +153,11 @@ type Printer struct { ColorCode string } +// NewPrinter instance +func NewPrinter(colorCode string) *Printer { + return &Printer{colorCode} +} + // String returns color code string. eg: "32;45;3" func (p *Printer) String() string { // panic("implement me") @@ -186,3 +188,8 @@ func (p *Printer) Printf(format string, a ...interface{}) { func (p *Printer) Println(a ...interface{}) { fmt.Println(RenderCode(p.String(), a...)) } + +// IsEmpty color code +func (p *Printer) IsEmpty() bool { + return p.ColorCode == "" +} diff --git a/color_256.go b/color_256.go index f826ccf..720cce5 100644 --- a/color_256.go +++ b/color_256.go @@ -107,7 +107,7 @@ func (c Color256) String() string { } // empty - return ResetCode + return "" } // IsEmpty value diff --git a/color_not_win.go b/color_not_win.go index 180fd97..7a34fd9 100644 --- a/color_not_win.go +++ b/color_not_win.go @@ -5,22 +5,13 @@ package color -// winSet func winSet(_ ...Color) (n int, err error) { return } -// winReset func winReset() (n int, err error) { return } -// winPrint -func winPrint(_ string, _ ...Color) (n int, err error) { - return -} - -// winPrintln -func winPrintln(_ string, _ ...Color) (n int, err error) { - return -} +func winPrint(_ string, _ ...Color) {} +func winPrintln(_ string, _ ...Color) {} diff --git a/color_rgb.go b/color_rgb.go index 5f99992..a28a2a0 100644 --- a/color_rgb.go +++ b/color_rgb.go @@ -147,7 +147,7 @@ func (c RGBColor) String() string { } // >1 is empty - return ResetCode + return "" } // IsEmpty value @@ -314,6 +314,6 @@ func (s *RGBStyle) IsEmpty() bool { } // RGBto256 value -func RGBto256(r, g, b uint8) { - -} +// func RGBto256(r, g, b uint8) { +// +// } diff --git a/color_test.go b/color_test.go index e26af7d..946306f 100644 --- a/color_test.go +++ b/color_test.go @@ -1,6 +1,7 @@ package color import ( + "bytes" "fmt" "github.com/stretchr/testify/assert" "io/ioutil" @@ -67,11 +68,27 @@ func TestSet(t *testing.T) { Set(FgGreen) str := restoreStdout() at.Equal("\x1b[32m", str) + // unset rewriteStdout() Reset() str = restoreStdout() at.Equal("\x1b[0m", str) + + old = isLikeInCmd + isLikeInCmd = true + // set + rewriteStdout() + Set(FgGreen) + str = restoreStdout() + at.Equal("", str) + + // unset + rewriteStdout() + Reset() + str = restoreStdout() + at.Equal("", str) + isLikeInCmd = old } func TestRenderCode(t *testing.T) { @@ -118,6 +135,46 @@ func TestClearCode(t *testing.T) { art.Equal("Text other", ClearCode("\033[36;1mText\x1b[0m other")) } +/************************************************************* + * test printer + *************************************************************/ + +func TestPrinter(t *testing.T) { + forceOpenColorRender() + defer resetColorRender() + at := assert.New(t) + + p := NewPrinter("48;5;132") + + // Color256.Sprint + str := p.Sprint("msg") + at.Equal("\x1b[48;5;132mmsg\x1b[0m", str) + // Color256.Sprintf + str = p.Sprintf("msg") + at.Equal("\x1b[48;5;132mmsg\x1b[0m", str) + + at.False(p.IsEmpty()) + at.Equal("48;5;132", p.String()) + + // Color256.Print + rewriteStdout() + p.Print("MSG") + str = restoreStdout() + at.Equal("\x1b[48;5;132mMSG\x1b[0m", str) + + // Color256.Printf + rewriteStdout() + p.Printf("A %s", "MSG") + str = restoreStdout() + at.Equal("\x1b[48;5;132mA MSG\x1b[0m", str) + + // Color256.Println + rewriteStdout() + p.Println("MSG") + str = restoreStdout() + at.Equal("\x1b[48;5;132mMSG\x1b[0m\n", str) +} + /************************************************************* * test 16 color *************************************************************/ @@ -180,7 +237,7 @@ func TestColor256(t *testing.T) { // empty c := Color256{1: 99} at.True(c.IsEmpty()) - at.Equal(ResetCode, c.String()) + at.Equal("", c.String()) // fg c = Bit8(132) @@ -285,7 +342,7 @@ func TestRGBColor(t *testing.T) { // empty c := RGBColor{3: 99} at.True(c.IsEmpty()) - at.Equal(ResetCode, c.String()) + at.Equal("", c.String()) // bg c = RGB(204, 204, 204, true) @@ -339,31 +396,31 @@ func TestRGBFromString(t *testing.T) { 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()) + c := HEX("ccc") // rgb: [204 204 204] + at.False(c.IsEmpty()) + at.Equal("38;2;204;204;204", c.String()) - rgb = HEX("aabbcc") // rgb: [170 187 204] - at.Equal("38;2;170;187;204", rgb.String()) + c = HEX("aabbcc") // rgb: [170 187 204] + at.Equal("38;2;170;187;204", c.String()) - rgb = HEX("#aabbcc") // rgb: [170 187 204] - at.Equal("38;2;170;187;204", rgb.String()) + c = HEX("#aabbcc") // rgb: [170 187 204] + at.Equal("38;2;170;187;204", c.String()) - rgb = HEX("0xad99c0") // rgb: [170 187 204] - at.Equal("38;2;173;153;192", rgb.String()) + c = HEX("0xad99c0") // rgb: [170 187 204] + at.Equal("38;2;173;153;192", c.String()) - rgb = HEX(" ") - at.True(rgb.IsEmpty()) - at.Equal(ResetCode, rgb.String()) + c = HEX(" ") + at.True(c.IsEmpty()) + at.Equal("", c.String()) - rgb = HEX("!#$bbcc") - at.Equal(ResetCode, rgb.String()) + c = HEX("!#$bbcc") + at.Equal("", c.String()) - rgb = HEX("#invalid") - at.Equal(ResetCode, rgb.String()) + c = HEX("#invalid") + at.Equal("", c.String()) - rgb = HEX("invalid code") - at.Equal(ResetCode, rgb.String()) + c = HEX("invalid code") + at.Equal("", c.String()) } func TestRGBStyle(t *testing.T) { @@ -373,15 +430,61 @@ func TestRGBStyle(t *testing.T) { s := &RGBStyle{} at.True(s.IsEmpty()) + at.Equal("", s.String()) + s.Set(RGB(20, 144, 234), RGB(234, 78, 23)) + at.False(s.IsEmpty()) + at.Equal("38;2;20;144;234;48;2;234;78;23", s.String()) + // NewRGBStyle + s = NewRGBStyle(RGB(20, 144, 234)) + at.False(s.IsEmpty()) + at.Equal("38;2;20;144;234", s.String()) + s = NewRGBStyle(RGB(20, 144, 234), RGB(234, 78, 23)) at.False(s.IsEmpty()) + at.Equal("38;2;20;144;234;48;2;234;78;23", s.String()) + // HEXStyle s = HEXStyle("555", "eee") at.False(s.IsEmpty()) + at.Equal("38;2;85;85;85;48;2;238;238;238", s.String()) + // RGBStyleFromString s = RGBStyleFromString("20, 144, 234", "234, 78, 23") at.False(s.IsEmpty()) + at.Equal("38;2;20;144;234;48;2;234;78;23", s.String()) + + // RGBColor.Sprint + at.Equal("\x1b[38;2;20;144;234;48;2;234;78;23mmsg\x1b[0m", s.Sprint("msg")) + // RGBColor.Sprintf + at.Equal("\x1b[38;2;20;144;234;48;2;234;78;23mmsg\x1b[0m", s.Sprintf("m%s", "sg")) + + // RGBColor.Print + rewriteStdout() + s.Print("msg") + str := restoreStdout() + at.Equal("\x1b[38;2;20;144;234;48;2;234;78;23mmsg\x1b[0m", str) + + // RGBColor.Printf + rewriteStdout() + s.Printf("m%s", "sg") + str = restoreStdout() + at.Equal("\x1b[38;2;20;144;234;48;2;234;78;23mmsg\x1b[0m", str) + + // RGBColor.Println + rewriteStdout() + s.Println("msg") + str = restoreStdout() + at.Equal("\x1b[38;2;20;144;234;48;2;234;78;23mmsg\x1b[0m\n", str) +} + +func TestOther(t *testing.T) { + at := assert.New(t) + + at.True(IsConsole(os.Stdout)) + at.False(IsConsole(&bytes.Buffer{})) + + at.False(IsMSys()) } /************************************************************* diff --git a/color_windows.go b/color_windows.go index 94e49f8..9c7b180 100644 --- a/color_windows.go +++ b/color_windows.go @@ -184,13 +184,13 @@ func initWinColorsMap() { } // winPrint -func winPrint(str string, colors ...Color) (int, error) { - return winInternalPrint(str, convertColorsToWinAttr(colors), false) +func winPrint(str string, colors ...Color) { + winInternalPrint(str, convertColorsToWinAttr(colors), false) } // winPrintln -func winPrintln(str string, colors ...Color) (int, error) { - return winInternalPrint(str, convertColorsToWinAttr(colors), true) +func winPrintln(str string, colors ...Color) { + winInternalPrint(str, convertColorsToWinAttr(colors), true) } // winInternalPrint diff --git a/tag_test.go b/tag_test.go index b435294..9c2554c 100644 --- a/tag_test.go +++ b/tag_test.go @@ -62,6 +62,11 @@ func TestPrint(t *testing.T) { defer resetColorRender() at := assert.New(t) + at.True(len(GetColorTags()) > 0) + at.True(IsDefinedTag("info")) + at.Equal("0;32", GetTagCode("info")) + at.Equal("", GetTagCode("not-exist")) + s := Sprint("MSG") at.Equal("\x1b[0;31mMSG\x1b[0m", s) @@ -70,6 +75,24 @@ func TestPrint(t *testing.T) { s = Sprintf("%s", "MSG") at.Equal("\x1b[0;31mMSG\x1b[0m", s) + + // Print + rewriteStdout() + Print("MSG") + s = restoreStdout() + at.Equal("\x1b[0;31mMSG\x1b[0m", s) + + // Printf + rewriteStdout() + Printf("%s", "MSG") + s = restoreStdout() + at.Equal("\x1b[0;31mMSG\x1b[0m", s) + + // Println + rewriteStdout() + Println("MSG") + s = restoreStdout() + at.Equal("\x1b[0;31mMSG\x1b[0m\n", s) } func TestWrapTag(t *testing.T) { @@ -77,6 +100,13 @@ func TestWrapTag(t *testing.T) { at.Equal("text", WrapTag("text", "info")) } +func TestApplyTag(t *testing.T) { + forceOpenColorRender() + defer resetColorRender() + at := assert.New(t) + at.Equal("\x1b[0;32mMSG\x1b[0m", ApplyTag("info", "MSG")) +} + func TestClearTag(t *testing.T) { at := assert.New(t) at.Equal("text", ClearTag("text")) diff --git a/utils.go b/utils.go index 8472482..24c6bd4 100644 --- a/utils.go +++ b/utils.go @@ -3,25 +3,9 @@ package color import ( "io" "os" - "runtime" "strings" ) -// IsWin linux windows darwin -func IsWin() bool { - return runtime.GOOS == "windows" -} - -// IsMac system -func IsMac() bool { - return runtime.GOOS == "darwin" -} - -// IsLinux system -func IsLinux() bool { - return runtime.GOOS == "linux" -} - // IsConsole 判断 w 是否为 stderr、stdout、stdin 三者之一 func IsConsole(out io.Writer) bool { o, ok := out.(*os.File)