Bump github.com/gookit/color from 1.4.2 to 1.6.0

Bumps [github.com/gookit/color](https://github.com/gookit/color) from 1.4.2 to 1.6.0.
- [Release notes](https://github.com/gookit/color/releases)
- [Commits](https://github.com/gookit/color/compare/v1.4.2...v1.6.0)

---
updated-dependencies:
- dependency-name: github.com/gookit/color
  dependency-version: 1.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot] 2026-04-26 17:32:06 +00:00 committed by GitHub
parent c852855238
commit 1a7bbd2067
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 1934 additions and 906 deletions

2
go.mod
View file

@ -15,7 +15,7 @@ require (
github.com/creack/pty v1.1.24
github.com/gdamore/tcell/v2 v2.13.8
github.com/go-errors/errors v1.5.1
github.com/gookit/color v1.4.2
github.com/gookit/color v1.6.0
github.com/integrii/flaggy v1.8.0
github.com/jesseduffield/generics v0.0.0-20250517122708-b0b4a53a6f5c
github.com/jesseduffield/gocui v0.3.1-0.20260327132312-944dab3bc980

9
go.sum
View file

@ -38,8 +38,10 @@ github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/gookit/color v1.4.2 h1:tXy44JFSFkKnELV6WaMo/lLfu/meqITX3iAV52do7lk=
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
github.com/gookit/assert v0.1.1 h1:lh3GcawXe/p+cU7ESTZ5Ui3Sm/x8JWpIis4/1aF0mY0=
github.com/gookit/assert v0.1.1/go.mod h1:jS5bmIVQZTIwk42uXl4lyj4iaaxx32tqH16CFj0VX2E=
github.com/gookit/color v1.6.0 h1:JjJXBTk1ETNyqyilJhkTXJYYigHG24TM9Xa2M1xAhRA=
github.com/gookit/color v1.6.0/go.mod h1:9ACFc7/1IpHGBW8RwuDm/0YEnhg3dwwXpoMsmtyHfjs=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/integrii/flaggy v1.8.0 h1:tC1qWwg4fhF2Qdaj+MpPK04cxlOSq0+HoMZqAW6Arao=
@ -121,14 +123,12 @@ github.com/stefanhaller/git-todo-parser v0.0.7-0.20250905083220-c50528f08304 h1:
github.com/stefanhaller/git-todo-parser v0.0.7-0.20250905083220-c50528f08304/go.mod h1:HFt9hGqMzgQ+gVxMKcvTvGaFz4Y0yYycqqAp2V3wcJY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/urfave/cli v1.20.1-0.20180226030253-8e01ec4cd3e2/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
@ -154,7 +154,6 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View file

@ -15,6 +15,7 @@
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
*.cov
.DS_Store
app
demo

0
vendor/github.com/gookit/color/.nojekyll generated vendored Normal file
View file

View file

@ -2,14 +2,13 @@
![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/gookit/color?style=flat-square)
[![Actions Status](https://github.com/gookit/color/workflows/action-tests/badge.svg)](https://github.com/gookit/color/actions)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/51b28c5f7ffe4cc2b0f12ecf25ed247f)](https://app.codacy.com/app/inhere/color)
[![GoDoc](https://godoc.org/github.com/gookit/color?status.svg)](https://pkg.go.dev/github.com/gookit/color?tab=overview)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/7fef8d74c1d64afc99ce0f2c6d3f8af1)](https://www.codacy.com/gh/gookit/color/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=gookit/color&amp;utm_campaign=Badge_Grade)
[![GoDoc](https://pkg.go.dev/badge/github.com/gookit/color.svg)](https://pkg.go.dev/github.com/gookit/color?tab=overview)
[![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/gookit/color)](https://github.com/gookit/color)
[![Build Status](https://travis-ci.org/gookit/color.svg?branch=master)](https://travis-ci.org/gookit/color)
[![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)
A command-line color library with true color support, universal API methods and Windows support.
A command-line color library with 16/256/True color support, universal API methods and Windows support.
> **[中文说明](README.zh-CN.md)**
@ -28,8 +27,9 @@ Now, 256 colors and RGB colors have also been supported to work in Windows CMD a
- 16-color output is the most commonly used and most widely supported, working on any Windows version
- Since `v1.2.4` **the 256-color (8-bit), true color (24-bit) support windows CMD and PowerShell**
- See [this gist](https://gist.github.com/XVilka/8346728) for information on true color support
- Support converts `HEX` `HSL` value to RGB color
- Generic API methods: `Print`, `Printf`, `Println`, `Sprint`, `Sprintf`
- Supports HTML tag-style color rendering, such as `<green>message</>`.
- Supports HTML tag-style color rendering, such as `<green>message</> <fg=red;bg=blue>text</>`.
- In addition to using built-in tags, it also supports custom color attributes
- Custom color attributes support the use of 16 color names, 256 color values, rgb color values and hex color values
- Support working on Windows `cmd` and `powerShell` terminal
@ -40,8 +40,7 @@ Now, 256 colors and RGB colors have also been supported to work in Windows CMD a
## GoDoc
- [godoc for gopkg](https://pkg.go.dev/gopkg.in/gookit/color.v1)
- [godoc for github](https://pkg.go.dev/github.com/gookit/color)
See [godoc for github](https://pkg.go.dev/github.com/gookit/color)
## Install
@ -120,11 +119,6 @@ Supported on any Windows version. Provide generic API methods: `Print`, `Printf`
```go
color.Bold.Println("bold message")
color.Black.Println("bold message")
color.White.Println("bold message")
color.Gray.Println("bold message")
color.Red.Println("yellow message")
color.Blue.Println("yellow message")
color.Cyan.Println("yellow message")
color.Yellow.Println("yellow message")
color.Magenta.Println("yellow message")
@ -171,15 +165,9 @@ print message use defined style:
```go
color.Info.Println("Info message")
color.Note.Println("Note message")
color.Notice.Println("Notice message")
color.Error.Println("Error message")
color.Danger.Println("Danger message")
color.Warn.Println("Warn message")
color.Debug.Println("Debug message")
color.Primary.Println("Primary message")
color.Question.Println("Question message")
color.Secondary.Println("Secondary message")
// ...
```
Run demo: `go run ./_examples/theme_basic.go`
@ -190,14 +178,8 @@ Run demo: `go run ./_examples/theme_basic.go`
```go
color.Info.Tips("Info tips message")
color.Note.Tips("Note tips message")
color.Notice.Tips("Notice tips message")
color.Error.Tips("Error tips message")
color.Danger.Tips("Danger tips message")
color.Warn.Tips("Warn tips message")
color.Debug.Tips("Debug tips message")
color.Primary.Tips("Primary tips message")
color.Question.Tips("Question tips message")
color.Secondary.Tips("Secondary tips message")
```
@ -209,15 +191,9 @@ Run demo: `go run ./_examples/theme_tips.go`
```go
color.Info.Prompt("Info prompt message")
color.Note.Prompt("Note prompt message")
color.Notice.Prompt("Notice prompt message")
color.Error.Prompt("Error prompt message")
color.Danger.Prompt("Danger prompt message")
color.Warn.Prompt("Warn prompt message")
color.Debug.Prompt("Debug prompt message")
color.Primary.Prompt("Primary prompt message")
color.Question.Prompt("Question prompt message")
color.Secondary.Prompt("Secondary prompt message")
// ...
```
Run demo: `go run ./_examples/theme_prompt.go`
@ -227,16 +203,9 @@ Run demo: `go run ./_examples/theme_prompt.go`
**Block Style**
```go
color.Info.Block("Info block message")
color.Note.Block("Note block message")
color.Notice.Block("Notice block message")
color.Error.Block("Error block message")
color.Danger.Block("Danger block message")
color.Warn.Block("Warn block message")
color.Debug.Block("Debug block message")
color.Primary.Block("Primary block message")
color.Question.Block("Question block message")
color.Secondary.Block("Secondary block message")
// ...
```
Run demo: `go run ./_examples/theme_block.go`
@ -371,7 +340,32 @@ s.Printf("style with %s\n", "options")
## HTML-like tag usage
**Supported** on Windows `cmd.exe` `PowerShell` .
`Print,Printf,Println` functions support auto parse and render color tags.
```go
text := `
<mga1>gookit/color:</>
A <green>command-line</>
<cyan>color library</> with <fg=167;bg=232>256-color</>
and <fg=11aa23;op=bold>True-color</> support,
<fg=mga;op=i>universal API</> methods
and <cyan>Windows</> support.
`
color.Print(text)
```
Preview, code please see [_examples/demo_tag.go](_examples/demo_tag.go):
![demo_tag](_examples/images/demo_tag.png)
**Tag formats:**
- Use built in tags: `<TAG_NAME>CONTENT</>` e.g: `<info>message</>`
- Custom tag attributes: `<fg=VALUE;bg=VALUE;op=VALUES>CONTENT</>` e.g: `<fg=167;bg=232>wel</>`
> **Supported** on Windows `cmd.exe` `PowerShell`.
Examples:
```go
// use style tag
@ -386,8 +380,55 @@ color.Print("<fg=yellow;bg=black;op=underscore;>hello, welcome</>\n")
// Custom label attr: Supports the use of 16 color names, 256 color values, rgb color values and hex color values
color.Println("<fg=11aa23>he</><bg=120,35,156>llo</>, <fg=167;bg=232>wel</><fg=red>come</>")
```
### Tag attributes
- `color.Tag`
tag attributes format:
```text
attr format:
// VALUE please see var: FgColors, BgColors, AllOptions
"fg=VALUE;bg=VALUE;op=VALUE"
16 color:
"fg=yellow"
"bg=red"
"op=bold,underscore" // option is allow multi value
"fg=white;bg=blue;op=bold"
"fg=white;op=bold,underscore"
256 color:
"fg=167"
"fg=167;bg=23"
"fg=167;bg=23;op=bold"
True color:
// hex
"fg=fc1cac"
"fg=fc1cac;bg=c2c3c4"
// r,g,b
"fg=23,45,214"
"fg=23,45,214;bg=109,99,88"
```
> tag attributes parse please see `func ParseCodeFromAttr()`
### Built-in tags
Built-in tags please see var `colorTags` in [color_tag.go](color_tag.go)
```go
// use style tag
color.Print("<suc>he</><comment>llo</>, <cyan>wel</><red>come</>")
color.Println("<suc>hello</>")
color.Println("<error>hello</>")
```
Run demo: `go run ./_examples/color_tag.go`
![color-tags](_examples/images/color-tags.png)
**Use `color.Tag` build message**:
```go
// set a style tag
@ -396,10 +437,6 @@ color.Tag("info").Printf("%s style text", "info")
color.Tag("info").Println("info style text")
```
Run demo: `go run ./_examples/color_tag.go`
![color-tags](_examples/images/color-tags.png)
## Color convert
Supports conversion between Rgb, 256, 16 colors, `Rgb <=> 256 <=> 16`
@ -417,7 +454,49 @@ rgb.Println("rgb color")
rgb.C256().Println("256 color")
```
## Func refer
### Convert utils
`color` has many built-in color conversion utility functions.
```go
func Basic2hex(val uint8) string
func Bg2Fg(val uint8) uint8
func Fg2Bg(val uint8) uint8
func C256ToRgb(val uint8) (rgb []uint8)
func C256ToRgbV1(val uint8) (rgb []uint8)
func Hex2basic(hex string, asBg ...bool) uint8
func Hex2rgb(hex string) []int
func HexToRGB(hex string) []int
func HexToRgb(hex string) (rgb []int)
func HslIntToRgb(h, s, l int) (rgb []uint8)
func HslToRgb(h, s, l float64) (rgb []uint8)
func HsvToRgb(h, s, v int) (rgb []uint8)
func Rgb2ansi(r, g, b uint8, isBg bool) uint8
func Rgb2basic(r, g, b uint8, isBg bool) uint8
func Rgb2hex(rgb []int) string
func Rgb2short(r, g, b uint8) uint8
func RgbTo256(r, g, b uint8) uint8
func RgbTo256Table() map[string]uint8
func RgbToAnsi(r, g, b uint8, isBg bool) uint8
func RgbToHex(rgb []int) string
func RgbToHsl(r, g, b uint8) []float64
func RgbToHslInt(r, g, b uint8) []int
```
**Convert to `RGBColor`**:
- `func RGBFromSlice(rgb []uint8, isBg ...bool) RGBColor`
- `func RGBFromString(rgb string, isBg ...bool) RGBColor`
- `func HEX(hex string, isBg ...bool) RGBColor`
- `func HSL(h, s, l float64, isBg ...bool) RGBColor`
- `func HSLInt(h, s, l int, isBg ...bool) RGBColor`
## Util functions
There are some useful functions reference
@ -428,15 +507,45 @@ There are some useful functions reference
- `ClearCode(str string) string` Use for clear color codes
- `ClearTag(s string) string` clear all color html-tag for a string
- `IsConsole(w io.Writer)` Determine whether w is one of stderr, stdout, stdin
- `HexToRgb(hex string) (rgb []int)` Convert hex color string to RGB numbers
- `RgbToHex(rgb []int) string` Convert RGB to hex code
- More useful func please see https://pkg.go.dev/github.com/gookit/color
## Project use
> More useful func please see https://pkg.go.dev/github.com/gookit/color
### Detect color level
`color` automatically checks the color levels supported by the current environment.
```go
// Level is the color level supported by a terminal.
type Level = terminfo.ColorLevel
// terminal color available level alias of the terminfo.ColorLevel*
const (
LevelNo = terminfo.ColorLevelNone // not support color.
Level16 = terminfo.ColorLevelBasic // basic - 3/4 bit color supported
Level256 = terminfo.ColorLevelHundreds // hundreds - 8-bit color supported
LevelRgb = terminfo.ColorLevelMillions // millions - (24 bit)true color supported
)
```
- `func SupportColor() bool` Whether the current environment supports color output
- `func Support256Color() bool` Whether the current environment supports 256-color output
- `func SupportTrueColor() bool` Whether the current environment supports (RGB)True-color output
- `func TermColorLevel() Level` Get the currently supported color level
## Projects using color
Check out these projects, which use https://github.com/gookit/color :
- https://github.com/Delta456/box-cli-maker Make Highly Customized Boxes for your CLI
- https://github.com/flipped-aurora/gin-vue-admin 基于gin+vue搭建的后台系统框架
- https://github.com/JanDeDobbeleer/oh-my-posh A prompt theme engine for any shell.
- https://github.com/jesseduffield/lazygit Simple terminal UI for git commands
- https://github.com/olivia-ai/olivia 💁Your new best friend powered by an artificial neural network
- https://github.com/pterm/pterm PTerm is a modern Go module to beautify console output. Featuring charts, progressbars, tables, trees, etc.
- https://github.com/securego/gosec Golang security checker
- https://github.com/TNK-Studio/lazykube ⎈ The lazier way to manage kubernetes.
- [+ See More](https://pkg.go.dev/github.com/gookit/color?tab=importedby)
## Gookit packages
@ -459,6 +568,7 @@ Check out these projects, which use https://github.com/gookit/color :
- [xo/terminfo](https://github.com/xo/terminfo)
- [beego/bee](https://github.com/beego/bee)
- [issue9/term](https://github.com/issue9/term)
- [muesli/termenv](https://github.com/muesli/termenv)
- [ANSI escape code](https://en.wikipedia.org/wiki/ANSI_escape_code)
- [Standard ANSI color map](https://conemu.github.io/en/AnsiEscapeCodes.html#Standard_ANSI_color_map)
- [Terminal Colors](https://gist.github.com/XVilka/8346728)

View file

@ -2,14 +2,13 @@
![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/gookit/color?style=flat-square)
[![Actions Status](https://github.com/gookit/color/workflows/action-tests/badge.svg)](https://github.com/gookit/color/actions)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/51b28c5f7ffe4cc2b0f12ecf25ed247f)](https://app.codacy.com/app/inhere/color)
[![GoDoc](https://godoc.org/github.com/gookit/color?status.svg)](https://pkg.go.dev/github.com/gookit/color?tab=overview)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/7fef8d74c1d64afc99ce0f2c6d3f8af1)](https://www.codacy.com/gh/gookit/color/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=gookit/color&amp;utm_campaign=Badge_Grade)
[![GoDoc](https://pkg.go.dev/badge/github.com/gookit/color.svg)](https://pkg.go.dev/github.com/gookit/color?tab=overview)
[![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/gookit/color)](https://github.com/gookit/color)
[![Build Status](https://travis-ci.org/gookit/color.svg?branch=master)](https://travis-ci.org/gookit/color)
[![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下的命令行色彩使用库, 拥有丰富的色彩渲染输出通用的API方法兼容Windows系统
Golang下的命令行色彩使用库, 拥有丰富的色彩(16/256/True)渲染输出通用的API方法兼容Windows系统
> **[EN README](README.md)**
@ -28,9 +27,10 @@ Golang下的命令行色彩使用库, 拥有丰富的色彩渲染输出,通用
- 16色(4bit)是最常用和支持最广的支持Windows `cmd.exe`
- 自 `v1.2.4` 起 **256色(8bit)RGB色彩(24bit)均支持Windows CMD和PowerShell终端**
- 请查看 [this gist](https://gist.github.com/XVilka/8346728) 了解支持RGB色彩的终端
- 支持转换 `HEX` `HSL` 等为RGB色彩
- 提供通用的API方法`Print` `Printf` `Println` `Sprint` `Sprintf`
- 同时支持html标签式的颜色渲染除了使用内置标签同时支持自定义颜色属性
- 例如: `this an <green>message</>` 标签内部的文本将会渲染为绿色字体
- 例如: `this an <green>message</> <fg=red;bg=blue>text</>` 标签内部文本将会渲染对应色彩
- 自定义颜色属性: 支持使用16色彩名称256色彩值rgb色彩值以及hex色彩值
- 基础色彩: `Bold` `Black` `White` `Gray` `Red` `Green` `Yellow` `Blue` `Magenta` `Cyan`
- 扩展风格: `Info` `Note` `Light` `Error` `Danger` `Notice` `Success` `Comment` `Primary` `Warning` `Question` `Secondary`
@ -40,8 +40,7 @@ Golang下的命令行色彩使用库, 拥有丰富的色彩渲染输出,通用
## GoDoc
- [godoc for gopkg](https://pkg.go.dev/gopkg.in/gookit/color.v1)
- [godoc for github](https://pkg.go.dev/github.com/gookit/color)
[godoc for github](https://pkg.go.dev/github.com/gookit/color)
## 安装
@ -124,12 +123,7 @@ func main() {
color.Bold.Println("bold message")
color.Black.Println("bold message")
color.White.Println("bold message")
color.Gray.Println("bold message")
color.Red.Println("yellow message")
color.Blue.Println("yellow message")
color.Cyan.Println("yellow message")
color.Yellow.Println("yellow message")
color.Magenta.Println("yellow message")
// ...
// Only use foreground color
color.FgCyan.Printf("Simple to use %s\n", "color")
@ -185,13 +179,7 @@ color.Reset()
color.Info.Println("Info message")
color.Note.Println("Note message")
color.Notice.Println("Notice message")
color.Error.Println("Error message")
color.Danger.Println("Danger message")
color.Warn.Println("Warn message")
color.Debug.Println("Debug message")
color.Primary.Println("Primary message")
color.Question.Println("Question message")
color.Secondary.Println("Secondary message")
// ...
```
Run demo: `go run ./_examples/theme_basic.go`
@ -202,15 +190,9 @@ Run demo: `go run ./_examples/theme_basic.go`
```go
color.Info.Tips("Info tips message")
color.Note.Tips("Note tips message")
color.Notice.Tips("Notice tips message")
color.Error.Tips("Error tips message")
color.Danger.Tips("Danger tips message")
color.Warn.Tips("Warn tips message")
color.Debug.Tips("Debug tips message")
color.Primary.Tips("Primary tips message")
color.Question.Tips("Question tips message")
color.Secondary.Tips("Secondary tips message")
// ...
```
Run demo: `go run ./_examples/theme_tips.go`
@ -221,8 +203,6 @@ Run demo: `go run ./_examples/theme_tips.go`
```go
color.Info.Prompt("Info prompt message")
color.Note.Prompt("Note prompt message")
color.Notice.Prompt("Notice prompt message")
color.Error.Prompt("Error prompt message")
color.Danger.Prompt("Danger prompt message")
```
@ -236,9 +216,7 @@ Run demo: `go run ./_examples/theme_prompt.go`
```go
color.Warn.Block("Warn block message")
color.Debug.Block("Debug block message")
color.Primary.Block("Primary block message")
color.Question.Block("Question block message")
color.Secondary.Block("Secondary block message")
```
Run demo: `go run ./_examples/theme_block.go`
@ -251,7 +229,7 @@ Run demo: `go run ./_examples/theme_block.go`
### 使用前景或后景色
- `color.C256(val uint8, isBg ...bool) Color256`
- `color.C256(val uint8, isBg ...bool) Color256`
```go
c := color.C256(132) // fg color
@ -339,7 +317,7 @@ c.Printf("format %s", "message")
### 使用RGB风格
> 可同时设置前景和背景色
> TIP: 可同时设置前景和背景色
- `color.NewRGBStyle(fg RGBColor, bg ...RGBColor) *RGBStyle`
@ -369,8 +347,33 @@ s.Printf("style with %s\n", "options")
## 使用颜色标签
`Print,Printf,Println` 等方法支持自动解析并渲染 HTML 风格的颜色标签
> **支持** 在windows `cmd.exe` `PowerShell` 使用
简单示例:
```go
text := `
<mga1>gookit/color:</>
A <green>command-line</>
<cyan>color library</> with <fg=167;bg=232>256-color</>
and <fg=11aa23;op=bold>True-color</> support,
<fg=mga;op=i>universal API</> methods
and <cyan>Windows</> support.
`
color.Print(text)
```
输出效果, 示例代码请看 [_examples/demo_tag.go](_examples/demo_tag.go):
![demo_tag](_examples/images/demo_tag.png)
**颜色标签格式:**
- 直接使用内置风格标签: `<TAG_NAME>CONTENT</>` e.g: `<info>message</>`
- 自定义标签属性: `<fg=VALUE;bg=VALUE;op=VALUES>CONTENT</>` e.g: `<fg=167;bg=232>wel</>`
使用内置的颜色标签,可以非常方便简单的构建自己需要的任何格式
> 同时支持自定义颜色属性: 支持使用16色彩名称256色彩值rgb色彩值以及hex色彩值
@ -389,9 +392,56 @@ color.Print("<fg=yellow;bg=black;op=underscore;>hello, welcome</>\n")
color.Println("<fg=11aa23>he</><bg=120,35,156>llo</>, <fg=167;bg=232>wel</><fg=red>come</>")
```
- 使用 `color.Tag`
### 自定义标签属性
给后面输出的文本信息加上给定的颜色风格标签
标签属性格式:
```text
attr format:
// VALUE please see var: FgColors, BgColors, AllOptions
"fg=VALUE;bg=VALUE;op=VALUE"
16 color:
"fg=yellow"
"bg=red"
"op=bold,underscore" // option is allow multi value
"fg=white;bg=blue;op=bold"
"fg=white;op=bold,underscore"
256 color:
"fg=167"
"fg=167;bg=23"
"fg=167;bg=23;op=bold"
True color:
// hex
"fg=fc1cac"
"fg=fc1cac;bg=c2c3c4"
// r,g,b
"fg=23,45,214"
"fg=23,45,214;bg=109,99,88"
```
> tag attributes parse please see `func ParseCodeFromAttr()`
### 内置标签
内置标签请参见变量 `colorTags` 定义, 源文件 [color_tag.go](color_tag.go)
```go
// use style tag
color.Print("<suc>he</><comment>llo</>, <cyan>wel</><red>come</>")
color.Println("<suc>hello</>")
color.Println("<error>hello</>")
```
> 运行 demo: `go run ./_examples/color_tag.go`
![color-tags](_examples/images/color-tags.png)
**使用 `color.Tag` 包装标签**:
可以使用通用的输出API方法,给后面输出的文本信息加上给定的颜色风格标签
```go
// set a style tag
@ -400,10 +450,6 @@ color.Tag("info").Printf("%s style text", "info")
color.Tag("info").Println("info style text")
```
> 运行 demo: `go run ./_examples/color_tag.go`
![color-tags](_examples/images/color-tags.png)
## 颜色转换
支持 Rgb, 256, 16 色彩之间的互相转换 `Rgb <=> 256 <=> 16`
@ -421,26 +467,96 @@ rgb.Println("rgb color")
rgb.C256().Println("256 color")
```
## 方法参考
### 颜色转换方法
`color` 内置了许多颜色转换工具方法
```go
func Basic2hex(val uint8) string
func Bg2Fg(val uint8) uint8
func Fg2Bg(val uint8) uint8
func C256ToRgb(val uint8) (rgb []uint8)
func C256ToRgbV1(val uint8) (rgb []uint8)
func Hex2basic(hex string, asBg ...bool) uint8
func Hex2rgb(hex string) []int
func HexToRGB(hex string) []int
func HexToRgb(hex string) (rgb []int)
func HslIntToRgb(h, s, l int) (rgb []uint8)
func HslToRgb(h, s, l float64) (rgb []uint8)
func HsvToRgb(h, s, v int) (rgb []uint8)
func Rgb2ansi(r, g, b uint8, isBg bool) uint8
func Rgb2basic(r, g, b uint8, isBg bool) uint8
func Rgb2hex(rgb []int) string
func Rgb2short(r, g, b uint8) uint8
func RgbTo256(r, g, b uint8) uint8
func RgbTo256Table() map[string]uint8
func RgbToAnsi(r, g, b uint8, isBg bool) uint8
func RgbToHex(rgb []int) string
func RgbToHsl(r, g, b uint8) []float64
func RgbToHslInt(r, g, b uint8) []int
```
**转换为 `RGBColor`**:
- `func RGBFromSlice(rgb []uint8, isBg ...bool) RGBColor`
- `func RGBFromString(rgb string, isBg ...bool) RGBColor`
- `func HEX(hex string, isBg ...bool) RGBColor`
- `func HSL(h, s, l float64, isBg ...bool) RGBColor`
- `func HSLInt(h, s, l int, isBg ...bool) RGBColor`
## 工具方法参考
一些有用的工具方法参考
- `Disable()` disable color render
- `SetOutput(io.Writer)` custom set the colored text output writer
- `ForceOpenColor()` force open color render
- `Disable()` 禁用颜色渲染输出
- `SetOutput(io.Writer)` 自定义设置渲染后的彩色文本输出位置
- `ForceOpenColor()` 强制开启颜色渲染
- `ClearCode(str string) string` Use for clear color codes
- `Colors2code(colors ...Color) string` Convert colors to code. return like "32;45;3"
- `ClearTag(s string) string` clear all color html-tag for a string
- `IsConsole(w io.Writer)` Determine whether w is one of stderr, stdout, stdin
- `HexToRgb(hex string) (rgb []int)` Convert hex color string to RGB numbers
- `RgbToHex(rgb []int) string` Convert RGB to hex code
- 更多请查看文档 https://pkg.go.dev/github.com/gookit/color
## 使用color的项目
### 检测支持的颜色级别
`color` 会自动检查当前环境支持的颜色级别
```go
// Level is the color level supported by a terminal.
type Level = terminfo.ColorLevel
// terminal color available level alias of the terminfo.ColorLevel*
const (
LevelNo = terminfo.ColorLevelNone // not support color.
Level16 = terminfo.ColorLevelBasic // basic - 3/4 bit color supported
Level256 = terminfo.ColorLevelHundreds // hundreds - 8-bit color supported
LevelRgb = terminfo.ColorLevelMillions // millions - (24 bit)true color supported
)
```
- `func SupportColor() bool` 当前环境是否支持色彩输出
- `func Support256Color() bool` 当前环境是否支持256色彩输出
- `func SupportTrueColor() bool` 当前环境是否支持(RGB)True色彩输出
- `func TermColorLevel() Level` 获取当前支持的颜色级别
## 使用Color的项目
看看这些使用了 https://github.com/gookit/color 的项目:
- https://github.com/Delta456/box-cli-maker Make Highly Customized Boxes for your CLI
- https://github.com/flipped-aurora/gin-vue-admin 基于gin+vue搭建的后台系统框架
- https://github.com/JanDeDobbeleer/oh-my-posh A prompt theme engine for any shell.
- https://github.com/jesseduffield/lazygit Simple terminal UI for git commands
- https://github.com/olivia-ai/olivia 💁Your new best friend powered by an artificial neural network
- https://github.com/pterm/pterm PTerm is a modern Go module to beautify console output. Featuring charts, progressbars, tables, trees, etc.
- https://github.com/securego/gosec Golang security checker
- https://github.com/TNK-Studio/lazykube ⎈ The lazier way to manage kubernetes.
- [+ See More](https://pkg.go.dev/github.com/gookit/color?tab=importedby)
## Gookit 工具包
@ -460,6 +576,7 @@ rgb.C256().Println("256 color")
## 参考项目
- [inhere/console](https://github.com/inhere/php-console)
- [muesli/termenv](https://github.com/muesli/termenv)
- [xo/terminfo](https://github.com/xo/terminfo)
- [beego/bee](https://github.com/beego/bee)
- [issue9/term](https://github.com/issue9/term)

View file

@ -1,12 +1,12 @@
/*
Package color is Command line color library.
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:
https://github.com/gookit/color
More usage please see README and tests.
For more usage, please see README and tests.
*/
package color
@ -15,29 +15,27 @@ import (
"io"
"os"
"regexp"
"github.com/xo/terminfo"
)
// terminal color available level alias of the terminfo.ColorLevel*
const (
LevelNo = terminfo.ColorLevelNone // not support color.
Level16 = terminfo.ColorLevelBasic // 3/4 bit color supported
Level256 = terminfo.ColorLevelHundreds // 8 bit color supported
LevelRgb = terminfo.ColorLevelMillions // (24 bit)true color supported
"strings"
)
// color render templates
//
// ESC 操作的表示:
// "\033"(Octal 8进制) = "\x1b"(Hexadecimal 16进制) = 27 (10进制)
//
// "\033"(Octal 8进制) = "\x1b"(Hexadecimal 16进制) = 27 (10进制)
const (
SettingTpl = "\x1b[%sm"
// StartSet chars
StartSet = "\x1b["
// ResetSet close all properties.
ResetSet = "\x1b[0m"
// SettingTpl string.
SettingTpl = "\x1b[%sm"
// FullColorTpl for build color code
FullColorTpl = "\x1b[%sm%s\x1b[0m"
// CodeSuffix string for color code.
CodeSuffix = "[0m"
)
// ResetSet Close all properties.
const ResetSet = "\x1b[0m"
// CodeExpr regex to clear color codes eg "\033[1;36mText\x1b[0m"
const CodeExpr = `\033\[[\d;?]+m`
@ -49,6 +47,9 @@ var (
Enable = os.Getenv("NO_COLOR") == ""
// RenderTag render HTML tag on call color.Xprint, color.PrintX
RenderTag = true
)
var (
// debug mode for development.
//
// set env:
@ -60,49 +61,30 @@ var (
innerErrs []error
// output the default io.Writer message print
output io.Writer = os.Stdout
// mark current env, It's like in `cmd.exe`
// if not in windows, it's always is False.
isLikeInCmd bool
// the color support level for current terminal
// needVTP - need enable VTP, only for windows OS
// needVTP - need enable VTP, only for Windows OS
colorLevel, needVTP = detectTermColorLevel()
// match color codes
codeRegex = regexp.MustCompile(CodeExpr)
// mark current env is support color.
// Always: isLikeInCmd != supportColor
// supportColor = IsSupportColor()
)
// TermColorLevel value on current ENV
func TermColorLevel() terminfo.ColorLevel {
return colorLevel
}
// TermColorLevel Get the currently supported color level
func TermColorLevel() Level { return colorLevel }
// SupportColor on the current ENV
func SupportColor() bool {
return colorLevel > terminfo.ColorLevelNone
}
// SupportColor Whether the current environment supports color output
func SupportColor() bool { return colorLevel > LevelNo }
// Support16Color on the current ENV
// func Support16Color() bool {
// return colorLevel > terminfo.ColorLevelNone
// }
// Support256Color Whether the current environment supports 256-color output
func Support256Color() bool { return colorLevel > Level16 }
// Support256Color on the current ENV
func Support256Color() bool {
return colorLevel > terminfo.ColorLevelBasic
}
// SupportTrueColor on the current ENV
func SupportTrueColor() bool {
return colorLevel > terminfo.ColorLevelHundreds
}
// SupportTrueColor Whether the current environment supports (RGB)True-color output
func SupportTrueColor() bool { return colorLevel > Level256 }
/*************************************************************
* global settings
*************************************************************/
// Set set console color attributes
// Set console color attributes
func Set(colors ...Color) (int, error) {
code := Colors2code(colors...)
err := SetTerminal(code)
@ -123,19 +105,13 @@ func Disable() bool {
}
// NotRenderTag on call color.Xprint, color.PrintX
func NotRenderTag() {
RenderTag = false
}
func NotRenderTag() { RenderTag = false }
// SetOutput set default colored text output
func SetOutput(w io.Writer) {
output = w
}
func SetOutput(w io.Writer) { output = w }
// ResetOutput reset output
func ResetOutput() {
output = os.Stdout
}
func ResetOutput() { output = os.Stdout }
// ResetOptions reset all package option setting
func ResetOptions() {
@ -144,49 +120,69 @@ func ResetOptions() {
output = os.Stdout
}
// ForceColor force open color render
func ForceSetColorLevel(level terminfo.ColorLevel) terminfo.ColorLevel {
// ForceSetColorLevel force open color render
func ForceSetColorLevel(level Level) Level {
oldLevelVal := colorLevel
colorLevel = level
return oldLevelVal
}
// ForceColor force open color render
func ForceColor() terminfo.ColorLevel {
return ForceOpenColor()
}
func ForceColor() Level { return ForceOpenColor() }
// ForceOpenColor force open color render
func ForceOpenColor() terminfo.ColorLevel {
func ForceOpenColor() Level {
// TODO should set level to ?
return ForceSetColorLevel(terminfo.ColorLevelMillions)
return ForceSetColorLevel(LevelRgb)
}
// IsLikeInCmd check result
// Deprecated
func IsLikeInCmd() bool {
return isLikeInCmd
}
// EnableDebug enable debug mode
func EnableDebug() { debugMode = true }
// ResetDebug reset debug mode
func ResetDebug() { debugMode = false }
// InnerErrs info
func InnerErrs() []error {
return innerErrs
}
func InnerErrs() []error { return innerErrs }
/*************************************************************
* render color code
*************************************************************/
// RenderCode render message by color code.
//
// Usage:
// msg := RenderCode("3;32;45", "some", "message")
func RenderCode(code string, args ...interface{}) string {
//
// msg := RenderCode("3;32;45", "some", "message")
func RenderCode(code string, args ...any) string {
var message string
if ln := len(args); ln == 0 {
// Fast path optimizations
if ln := len(args); ln == 1 {
// Single argument - avoid fmt.Sprint overhead
if str, ok := args[0].(string); ok {
message = str
} else {
message = fmt.Sprint(args[0])
}
} else if ln == 2 {
// Two arguments - common case, try to optimize if both are strings
if str1, ok1 := args[0].(string); ok1 {
if str2, ok2 := args[1].(string); ok2 {
message = str1 + str2
} else {
message = fmt.Sprint(args...)
}
} else {
message = fmt.Sprint(args...)
}
} else if ln == 0 {
return ""
} else {
// Multiple arguments - use fmt.Sprint for safety
message = fmt.Sprint(args...)
}
message = fmt.Sprint(args...)
if len(code) == 0 {
return message
}
@ -196,28 +192,31 @@ func RenderCode(code string, args ...interface{}) string {
return ClearCode(message)
}
return fmt.Sprintf(FullColorTpl, code, message)
// return fmt.Sprintf(FullColorTpl, code, message)
return StartSet + code + "m" + message + ResetSet
}
// RenderWithSpaces Render code with spaces.
// If the number of args is > 1, a space will be added between the args
func RenderWithSpaces(code string, args ...interface{}) string {
message := formatArgsForPrintln(args)
func RenderWithSpaces(code string, args ...any) string {
msg := formatLikePrintln(args)
if len(code) == 0 {
return message
return msg
}
// disabled OR not support color
if !Enable || !SupportColor() {
return ClearCode(message)
return ClearCode(msg)
}
return fmt.Sprintf(FullColorTpl, code, message)
return StartSet + code + "m" + msg + ResetSet
}
// RenderString render a string with color code.
//
// Usage:
// msg := RenderString("3;32;45", "a message")
//
// msg := RenderString("3;32;45", "a message")
func RenderString(code string, str string) string {
if len(code) == 0 || str == "" {
return str
@ -228,11 +227,18 @@ func RenderString(code string, str string) string {
return ClearCode(str)
}
return fmt.Sprintf(FullColorTpl, code, str)
// return fmt.Sprintf(FullColorTpl, code, str)
return StartSet + code + "m" + str + ResetSet
}
// ClearCode clear color codes.
// eg: "\033[36;1mText\x1b[0m" -> "Text"
//
// eg:
//
// "\033[36;1mText\x1b[0m" -> "Text"
func ClearCode(str string) string {
if !strings.Contains(str, CodeSuffix) {
return str
}
return codeRegex.ReplaceAllString(str, "")
}

View file

@ -41,13 +41,27 @@ func (o Opts) String() string {
* Basic 16 color definition
*************************************************************/
// Base value for foreground/background color
const (
// OptMax max option value. range: 0 - 9
OptMax = 10
// DiffFgBg diff foreground and background color
DiffFgBg = 10
)
// Boundary value for foreground/background color 16
//
// - base: fg 30~37, bg 40~47
// - light: fg 90~97, bg 100~107
const (
FgBase uint8 = 30
FgMax uint8 = 37
BgBase uint8 = 40
// hi color base code
BgMax uint8 = 47
HiFgBase uint8 = 90
HiFgMax uint8 = 97
HiBgBase uint8 = 100
HiBgMax uint8 = 107
)
// Foreground colors. basic foreground colors 30 - 37
@ -92,7 +106,7 @@ const (
BgDefault Color = 49
)
// Extra background color 100 - 107(非标准)
// Extra background color 100 - 107 (non-standard)
const (
BgDarkGray Color = iota + 100
BgLightRed
@ -106,7 +120,7 @@ const (
BgGray Color = 100
)
// Option settings
// Option settings. range: 0 - 9
const (
OpReset Color = iota // 0 重置所有设置
OpBold // 1 加粗
@ -114,7 +128,7 @@ const (
OpItalic // 3 斜体(不是所有的终端仿真器都支持)
OpUnderscore // 4 下划线
OpBlink // 5 闪烁
OpFastBlink // 5 快速闪烁(未广泛支持)
OpFastBlink // 6 快速闪烁(未广泛支持)
OpReverse // 7 颠倒的 交换背景色与前景色
OpConcealed // 8 隐匿的
OpStrikethrough // 9 删除的,删除线(未广泛支持)
@ -164,10 +178,8 @@ const (
BgHiMagenta = BgLightMagenta
)
// Bit4 an method for create Color
func Bit4(code uint8) Color {
return Color(code)
}
// Bit4 a method for create Color
func Bit4(code uint8) Color { return Color(code) }
/*************************************************************
* Color render methods
@ -183,70 +195,74 @@ func (c Color) Name() string {
}
// Text render a text message
func (c Color) Text(message string) string {
return RenderString(c.String(), message)
}
func (c Color) Text(message string) string { return RenderString(c.String(), message) }
// Render messages by color setting
//
// Usage:
// green := color.FgGreen.Render
// fmt.Println(green("message"))
func (c Color) Render(a ...interface{}) string {
return RenderCode(c.String(), a...)
}
//
// green := color.FgGreen.Render
// fmt.Println(green("message"))
func (c Color) Render(a ...any) string { return RenderCode(c.String(), a...) }
// Renderln messages by color setting.
// like Println, will add spaces for each argument
//
// Usage:
// green := color.FgGreen.Renderln
// fmt.Println(green("message"))
func (c Color) Renderln(a ...interface{}) string {
return RenderWithSpaces(c.String(), a...)
}
//
// green := color.FgGreen.Renderln
// fmt.Println(green("message"))
func (c Color) Renderln(a ...any) string { return RenderWithSpaces(c.String(), a...) }
// Sprint render messages by color setting. is alias of the Render()
func (c Color) Sprint(a ...interface{}) string {
return RenderCode(c.String(), a...)
}
func (c Color) Sprint(a ...any) string { return RenderCode(c.String(), a...) }
// Sprintf format and render message.
//
// Usage:
//
// green := color.Green.Sprintf
// colored := green("message")
func (c Color) Sprintf(format string, args ...interface{}) string {
// colored := green("message")
func (c Color) Sprintf(format string, args ...any) string {
return RenderString(c.String(), fmt.Sprintf(format, args...))
}
// Print messages.
//
// Usage:
// color.Green.Print("message")
//
// color.Green.Print("message")
//
// OR:
// green := color.FgGreen.Print
// green("message")
func (c Color) Print(args ...interface{}) {
//
// green := color.FgGreen.Print
// green("message")
func (c Color) Print(args ...any) {
doPrintV2(c.Code(), fmt.Sprint(args...))
}
// Printf format and print messages.
//
// Usage:
// color.Cyan.Printf("string %s", "arg0")
func (c Color) Printf(format string, a ...interface{}) {
//
// color.Cyan.Printf("string %s", "arg0")
func (c Color) Printf(format string, a ...any) {
doPrintV2(c.Code(), fmt.Sprintf(format, a...))
}
// Println messages with new line
func (c Color) Println(a ...interface{}) {
doPrintlnV2(c.String(), a)
}
func (c Color) Println(a ...any) { doPrintlnV2(c.String(), a) }
// Light current color. eg: 36(FgCyan) -> 96(FgLightCyan).
//
// Usage:
// lightCyan := Cyan.Light()
// lightCyan.Print("message")
//
// lightCyan := Cyan.Light()
// lightCyan.Print("message")
func (c Color) Light() Color {
val := int(c)
val := uint8(c)
if val >= 30 && val <= 47 {
return Color(uint8(c) + 60)
return Color(val + 60)
}
// don't change
@ -254,13 +270,15 @@ func (c Color) Light() Color {
}
// Darken current color. eg. 96(FgLightCyan) -> 36(FgCyan)
//
// Usage:
// cyan := LightCyan.Darken()
// cyan.Print("message")
//
// cyan := LightCyan.Darken()
// cyan.Print("message")
func (c Color) Darken() Color {
val := int(c)
val := uint8(c)
if val >= 90 && val <= 107 {
return Color(uint8(c) - 60)
return Color(val - 60)
}
// don't change
@ -291,6 +309,26 @@ func (c Color) C256() Color256 {
return Color256{val}
}
// ToFg always convert fg
func (c Color) ToFg() Color {
val := uint8(c)
// option code, don't change
if val < 10 {
return c
}
return Color(Bg2Fg(val))
}
// ToBg always convert bg
func (c Color) ToBg() Color {
val := uint8(c)
// option code, don't change
if val < 10 {
return c
}
return Color(Fg2Bg(val))
}
// RGB convert 16 color to 256-color code.
func (c Color) RGB() RGBColor {
val := uint8(c)
@ -298,26 +336,33 @@ func (c Color) RGB() RGBColor {
return emptyRGBColor
}
return HEX(Basic2hex(val))
return HEX(Basic2hex(val), c.IsBg())
}
// Code convert to code string. eg "35"
func (c Color) Code() string {
// return fmt.Sprintf("%d", c)
return strconv.Itoa(int(c))
}
func (c Color) Code() string { return strconv.FormatInt(int64(c), 10) }
// String convert to code string. eg "35"
func (c Color) String() string {
// return fmt.Sprintf("%d", c)
return strconv.Itoa(int(c))
func (c Color) String() string { return strconv.FormatInt(int64(c), 10) }
// IsBg check is background color
func (c Color) IsBg() bool {
val := uint8(c)
return val >= BgBase && val <= BgMax || val >= HiBgBase && val <= HiBgMax
}
// IsValid color value
func (c Color) IsValid() bool {
return c < 107
// IsFg check is foreground color
func (c Color) IsFg() bool {
val := uint8(c)
return val >= FgBase && val <= FgMax || val >= HiFgBase && val <= HiFgMax
}
// IsOption check is option code: 0-9
func (c Color) IsOption() bool { return uint8(c) < OptMax }
// IsValid color value
func (c Color) IsValid() bool { return uint8(c) < HiBgMax }
/*************************************************************
* basic color maps
*************************************************************/
@ -373,8 +418,8 @@ var ExBgColors = map[string]Color{
}
// Options color options map
// Deprecated
// NOTICE: please use AllOptions instead.
//
// Deprecated: please use AllOptions instead.
var Options = AllOptions
// AllOptions color options map
@ -392,9 +437,10 @@ var AllOptions = map[string]Color{
var (
// TODO basic name alias
// basicNameAlias = map[string]string{}
// optionWithAlias = buildOpWithAlias()
// basic color name to code
name2basicMap = initName2basicMap()
// name2basicMap = initName2basicMap()
// basic2nameMap basic color code to name
basic2nameMap = map[uint8]string{
30: "black",
@ -426,15 +472,36 @@ var (
}
)
// Basic2nameMap data
func Basic2nameMap() map[uint8]string {
return basic2nameMap
// Bg2Fg bg color value to fg value
func Bg2Fg(val uint8) uint8 {
if val >= BgBase && val <= 47 { // is bg
val = val - 10
} else if val >= HiBgBase && val <= 107 { // is hi bg
val = val - 10
}
return val
}
func initName2basicMap() map[string]uint8 {
n2b := make(map[string]uint8, len(basic2nameMap))
for u, s := range basic2nameMap {
n2b[s] = u
// Fg2Bg fg color value to bg value
func Fg2Bg(val uint8) uint8 {
if val >= FgBase && val <= 37 { // is fg
val = val + 10
} else if val >= HiFgBase && val <= 97 { // is hi fg
val = val + 10
}
return n2b
return val
}
// Basic2nameMap data
func Basic2nameMap() map[uint8]string { return basic2nameMap }
// func initName2basicMap() map[string]uint8 {
// n2b := make(map[string]uint8, len(basic2nameMap))
// for u, s := range basic2nameMap {
// n2b[s] = u
// }
// return n2b
// }
// func buildOpWithAlias() map[string]uint8 {
// }

View file

@ -19,16 +19,19 @@ from wikipedia, 256 color:
// tpl for 8 bit 256 color(`2^8`)
//
// format:
// ESC[ … 38;5;<n> … m // 选择前景色
// ESC[ … 48;5;<n> … m // 选择背景色
//
// ESC[ … 38;5;<n> … m // 选择前景色
// ESC[ … 48;5;<n> … m // 选择背景色
//
// example:
// fg "\x1b[38;5;242m"
// bg "\x1b[48;5;208m"
// both "\x1b[38;5;242;48;5;208m"
//
// fg "\x1b[38;5;242m"
// bg "\x1b[48;5;208m"
// both "\x1b[38;5;242;48;5;208m"
//
// links:
// https://zh.wikipedia.org/wiki/ANSI%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97#8位
//
// https://zh.wikipedia.org/wiki/ANSI%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97#8位
const (
TplFg256 = "38;5;%d"
TplBg256 = "48;5;%d"
@ -40,19 +43,21 @@ const (
* 8bit(256) Color: Bit8Color Color256
*************************************************************/
// Color256 256 color (8 bit), uint8 range at 0 - 255
// Color256 256 color (8 bit), uint8 range at 0 - 255.
// Support 256 color on windows CMD, PowerShell
//
// 颜色值使用10进制和16进制都可 0x98 = 152
//
// The color consists of two uint8:
// 0: color value
// 1: color type; Fg=0, Bg=1, >1: unset value
//
// 0: color value
// 1: color type; Fg=0, Bg=1, >1: unset value
//
// example:
// fg color: [152, 0]
// bg color: [152, 1]
//
// NOTICE: now support 256 color on windows CMD, PowerShell
// fg color: [152, 0]
// bg color: [152, 1]
//
// lint warn - Name starts with package name
type Color256 [2]uint8
type Bit8Color = Color256 // alias
@ -60,9 +65,7 @@ type Bit8Color = Color256 // alias
var emptyC256 = Color256{1: 99}
// Bit8 create a color256
func Bit8(val uint8, isBg ...bool) Color256 {
return C256(val, isBg...)
}
func Bit8(val uint8, isBg ...bool) Color256 { return C256(val, isBg...) }
// C256 create a color256
func C256(val uint8, isBg ...bool) Color256 {
@ -77,49 +80,39 @@ func C256(val uint8, isBg ...bool) Color256 {
}
// Set terminal by 256 color code
func (c Color256) Set() error {
return SetTerminal(c.String())
}
func (c Color256) Set() error { return SetTerminal(c.String()) }
// Reset terminal. alias of the ResetTerminal()
func (c Color256) Reset() error {
return ResetTerminal()
}
func (c Color256) Reset() error { return ResetTerminal() }
// Print print message
func (c Color256) Print(a ...interface{}) {
func (c Color256) Print(a ...any) {
doPrintV2(c.String(), fmt.Sprint(a...))
}
// Printf format and print message
func (c Color256) Printf(format string, a ...interface{}) {
func (c Color256) Printf(format string, a ...any) {
doPrintV2(c.String(), fmt.Sprintf(format, a...))
}
// Println print message with newline
func (c Color256) Println(a ...interface{}) {
func (c Color256) Println(a ...any) {
doPrintlnV2(c.String(), a)
}
// Sprint returns rendered message
func (c Color256) Sprint(a ...interface{}) string {
return RenderCode(c.String(), a...)
}
func (c Color256) Sprint(a ...any) string { return RenderCode(c.String(), a...) }
// Sprintf returns format and rendered message
func (c Color256) Sprintf(format string, a ...interface{}) string {
func (c Color256) Sprintf(format string, a ...any) string {
return RenderString(c.String(), fmt.Sprintf(format, a...))
}
// C16 convert color-256 to 16 color.
func (c Color256) C16() Color {
return c.Basic()
}
func (c Color256) C16() Color { return c.Basic() }
// Basic convert color-256 to basic 16 color.
func (c Color256) Basic() Color {
return Color(c[0]) // TODO
}
func (c Color256) Basic() Color { return Color(c[0]) /* TODO */ }
// RGB convert color-256 to RGB color.
func (c Color256) RGB() RGBColor {
@ -127,44 +120,31 @@ func (c Color256) RGB() RGBColor {
}
// RGBColor convert color-256 to RGB color.
func (c Color256) RGBColor() RGBColor {
return c.RGB()
}
func (c Color256) RGBColor() RGBColor { return c.RGB() }
// Value return color value
func (c Color256) Value() uint8 {
return c[0]
}
func (c Color256) Value() uint8 { return c[0] }
// Code convert to color code string. eg: "12"
func (c Color256) Code() string {
return strconv.Itoa(int(c[0]))
}
func (c Color256) Code() string { return strconv.Itoa(int(c[0])) }
// FullCode convert to color code string with prefix. eg: "38;5;12"
func (c Color256) FullCode() string {
return c.String()
}
func (c Color256) FullCode() string { return c.String() }
// String convert to color code string with prefix. eg: "38;5;12"
func (c Color256) String() string {
if c[1] == AsFg { // 0 is Fg
// return fmt.Sprintf(TplFg256, c[0])
return Fg256Pfx + strconv.Itoa(int(c[0]))
}
if c[1] == AsBg { // 1 is Bg
// return fmt.Sprintf(TplBg256, c[0])
return Bg256Pfx + strconv.Itoa(int(c[0]))
}
return "" // empty
}
// IsFg color
func (c Color256) IsFg() bool {
return c[1] == AsFg
}
func (c Color256) IsFg() bool { return c[1] == AsFg }
// ToFg 256 color
func (c Color256) ToFg() Color256 {
@ -173,9 +153,7 @@ func (c Color256) ToFg() Color256 {
}
// IsBg color
func (c Color256) IsBg() bool {
return c[1] == AsBg
}
func (c Color256) IsBg() bool { return c[1] == AsBg }
// ToBg 256 color
func (c Color256) ToBg() Color256 {
@ -184,9 +162,7 @@ func (c Color256) ToBg() Color256 {
}
// IsEmpty value
func (c Color256) IsEmpty() bool {
return c[1] > 1
}
func (c Color256) IsEmpty() bool { return c[1] > 1 }
/*************************************************************
* 8bit(256) Style
@ -198,8 +174,6 @@ func (c Color256) IsEmpty() bool {
// 都是由两位uint8组成, 第一位是色彩值;
// 第二位与 Bit8Color 不一样的是,在这里表示是否设置了值 0 未设置 !=0 已设置
type Style256 struct {
// p Printer
// Name of the style
Name string
// color options of the style
@ -209,10 +183,12 @@ type Style256 struct {
}
// S256 create a color256 style
//
// Usage:
// s := color.S256()
// s := color.S256(132) // fg
// s := color.S256(132, 203) // fg and bg
//
// s := color.S256()
// s := color.S256(132) // fg
// s := color.S256(132, 203) // fg and bg
func S256(fgAndBg ...uint8) *Style256 {
s := &Style256{}
vl := len(fgAndBg)
@ -260,49 +236,44 @@ func (s *Style256) AddOpts(opts ...Color) *Style256 {
}
// Print message
func (s *Style256) Print(a ...interface{}) {
func (s *Style256) Print(a ...any) {
doPrintV2(s.String(), fmt.Sprint(a...))
}
// Printf format and print message
func (s *Style256) Printf(format string, a ...interface{}) {
func (s *Style256) Printf(format string, a ...any) {
doPrintV2(s.String(), fmt.Sprintf(format, a...))
}
// Println print message with newline
func (s *Style256) Println(a ...interface{}) {
func (s *Style256) Println(a ...any) {
doPrintlnV2(s.String(), a)
}
// Sprint returns rendered message
func (s *Style256) Sprint(a ...interface{}) string {
return RenderCode(s.Code(), a...)
}
func (s *Style256) Sprint(a ...any) string { return RenderCode(s.Code(), a...) }
// Sprintf returns format and rendered message
func (s *Style256) Sprintf(format string, a ...interface{}) string {
func (s *Style256) Sprintf(format string, a ...any) string {
return RenderString(s.Code(), fmt.Sprintf(format, a...))
}
// Code convert to color code string
func (s *Style256) Code() string {
return s.String()
}
func (s *Style256) Code() string { return s.String() }
// String convert to color code string
func (s *Style256) String() string {
var ss []string
if s.fg[1] > 0 {
ss = append(ss, fmt.Sprintf(TplFg256, s.fg[0]))
ss = append(ss, Fg256Pfx+strconv.FormatInt(int64(s.fg[0]), 10))
}
if s.bg[1] > 0 {
ss = append(ss, fmt.Sprintf(TplBg256, s.bg[0]))
ss = append(ss, Bg256Pfx+strconv.FormatInt(int64(s.bg[0]), 10))
}
if s.opts.IsValid() {
ss = append(ss, s.opts.String())
}
return strings.Join(ss, ";")
}

View file

@ -8,20 +8,24 @@ import (
// 24 bit RGB color
// RGB:
// R 0-255 G 0-255 B 0-255
// R 00-FF G 00-FF B 00-FF (16进制)
//
// R 0-255 G 0-255 B 0-255
// R 00-FF G 00-FF B 00-FF (16进制)
//
// Format:
// ESC[ … 38;2;<r>;<g>;<b> … m // Select RGB foreground color
// ESC[ … 48;2;<r>;<g>;<b> … m // Choose RGB background color
//
// ESC[ … 38;2;<r>;<g>;<b> … m // Select RGB foreground color
// ESC[ … 48;2;<r>;<g>;<b> … m // Choose RGB background color
//
// links:
// https://zh.wikipedia.org/wiki/ANSI%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97#24位
//
// https://zh.wikipedia.org/wiki/ANSI%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97#24位
//
// example:
// fg: \x1b[38;2;30;144;255mMESSAGE\x1b[0m
// bg: \x1b[48;2;30;144;255mMESSAGE\x1b[0m
// both: \x1b[38;2;233;90;203;48;2;30;144;255mMESSAGE\x1b[0m
//
// fg: \x1b[38;2;30;144;255mMESSAGE\x1b[0m
// bg: \x1b[48;2;30;144;255mMESSAGE\x1b[0m
// both: \x1b[38;2;233;90;203;48;2;30;144;255mMESSAGE\x1b[0m
const (
TplFgRGB = "38;2;%d;%d;%d"
TplBgRGB = "48;2;%d;%d;%d"
@ -35,53 +39,34 @@ const (
AsBg
)
// values from https://github.com/go-terminfo/terminfo
// var (
// RgbaBlack = image_color.RGBA{0, 0, 0, 255}
// Red = color.RGBA{205, 0, 0, 255}
// Green = color.RGBA{0, 205, 0, 255}
// Orange = color.RGBA{205, 205, 0, 255}
// Blue = color.RGBA{0, 0, 238, 255}
// Magenta = color.RGBA{205, 0, 205, 255}
// Cyan = color.RGBA{0, 205, 205, 255}
// LightGrey = color.RGBA{229, 229, 229, 255}
//
// DarkGrey = color.RGBA{127, 127, 127, 255}
// LightRed = color.RGBA{255, 0, 0, 255}
// LightGreen = color.RGBA{0, 255, 0, 255}
// Yellow = color.RGBA{255, 255, 0, 255}
// LightBlue = color.RGBA{92, 92, 255, 255}
// LightMagenta = color.RGBA{255, 0, 255, 255}
// LightCyan = color.RGBA{0, 255, 255, 255}
// White = color.RGBA{255, 255, 255, 255}
// )
/*************************************************************
* RGB Color(Bit24Color, TrueColor)
*************************************************************/
// RGBColor definition.
// Support RGB color on Windows CMD, PowerShell
//
// The first to third digits represent the color value.
// The last digit represents the foreground(0), background(1), >1 is unset value
//
// Usage:
// // 0, 1, 2 is R,G,B.
// // 3rd: Fg=0, Bg=1, >1: unset value
// RGBColor{30,144,255, 0}
// RGBColor{30,144,255, 1}
//
// NOTICE: now support RGB color on windows CMD, PowerShell
// // 0, 1, 2 is R,G,B.
// // 3rd: Fg=0, Bg=1, >1: unset value
// RGBColor{30,144,255, 0}
// RGBColor{30,144,255, 1}
type RGBColor [4]uint8
// create a empty RGBColor
// create an 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")
//
// 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}
if len(isBg) > 0 && isBg[0] {
@ -97,18 +82,23 @@ func Rgb(r, g, b uint8, isBg ...bool) RGBColor { return RGB(r, g, b, isBg...) }
// Bit24 alias of the RGB()
func Bit24(r, g, b uint8, isBg ...bool) RGBColor { return RGB(r, g, b, isBg...) }
// RGBFromSlice quick RGBColor from slice
func RGBFromSlice(rgb []uint8, isBg ...bool) RGBColor {
return RGB(rgb[0], rgb[1], rgb[2], isBg...)
// RgbFromInt create instance from int r,g,b value
func RgbFromInt(r, g, b int, isBg ...bool) RGBColor { return RGB(uint8(r), uint8(g), uint8(b), isBg...) }
// RgbFromInts create instance from []int r,g,b value
func RgbFromInts(rgb []int, isBg ...bool) RGBColor {
return RGB(uint8(rgb[0]), uint8(rgb[1]), uint8(rgb[2]), isBg...)
}
// 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")
//
// 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...)
@ -121,61 +111,93 @@ func HEX(hex string, isBg ...bool) RGBColor {
// Hex alias of the HEX()
func Hex(hex string, isBg ...bool) RGBColor { return HEX(hex, isBg...) }
// RGBFromHEX quick RGBColor from hex string, alias of HEX()
func RGBFromHEX(hex string, isBg ...bool) RGBColor { return HEX(hex, isBg...) }
// HSL create RGB color from a hsl value.
// more see HslToRgb()
func HSL(h, s, l float64, isBg ...bool) RGBColor {
rgb := HslToRgb(h, s, l)
return RGB(rgb[0], rgb[1], rgb[2], isBg...)
}
// Hsl alias of the HSL()
func Hsl(h, s, l float64, isBg ...bool) RGBColor { return HSL(h, s, l, isBg...) }
// HSLInt create RGB color from a hsl int value.
// more see HslIntToRgb()
func HSLInt(h, s, l int, isBg ...bool) RGBColor {
rgb := HslIntToRgb(h, s, l)
return RGB(rgb[0], rgb[1], rgb[2], isBg...)
}
// HslInt alias of the HSLInt()
func HslInt(h, s, l int, isBg ...bool) RGBColor { return HSLInt(h, s, l, isBg...) }
// RGBFromSlice quick RGBColor from slice[3]
func RGBFromSlice(rgb []uint8, isBg ...bool) RGBColor { return RGB(rgb[0], rgb[1], rgb[2], isBg...) }
// RGBFromString create RGB color from a string.
// Support use color name in the {namedRgbMap}
//
// Usage:
// c := RGBFromString("170,187,204")
// c.Print("message")
//
// c := RGBFromString("170,187,204")
// c.Print("message")
//
// c := RGBFromString("brown")
// c.Print("message with color brown")
func RGBFromString(rgb string, isBg ...bool) RGBColor {
// use color name in the {namedRgbMap}
if rgbVal, ok := namedRgbMap[rgb]; ok {
rgb = rgbVal
}
// use rgb string.
ss := stringToArr(rgb, ",")
if len(ss) != 3 {
return emptyRGBColor
}
var ar [3]int
var ar [3]uint8
for i, val := range ss {
iv, err := strconv.Atoi(val)
if err != nil {
if err != nil || !isValidUint8(iv) {
return emptyRGBColor
}
ar[i] = iv
ar[i] = uint8(iv)
}
return RGB(uint8(ar[0]), uint8(ar[1]), uint8(ar[2]), isBg...)
return RGB(ar[0], ar[1], ar[2], isBg...)
}
// Set terminal by rgb/true color code
func (c RGBColor) Set() error {
return SetTerminal(c.String())
}
func (c RGBColor) Set() error { return SetTerminal(c.String()) }
// Reset terminal. alias of the ResetTerminal()
func (c RGBColor) Reset() error {
return ResetTerminal()
}
func (c RGBColor) Reset() error { return ResetTerminal() }
// Print print message
func (c RGBColor) Print(a ...interface{}) {
func (c RGBColor) Print(a ...any) {
doPrintV2(c.String(), fmt.Sprint(a...))
}
// Printf format and print message
func (c RGBColor) Printf(format string, a ...interface{}) {
func (c RGBColor) Printf(format string, a ...any) {
doPrintV2(c.String(), fmt.Sprintf(format, a...))
}
// Println print message with newline
func (c RGBColor) Println(a ...interface{}) {
func (c RGBColor) Println(a ...any) {
doPrintlnV2(c.String(), a)
}
// Sprint returns rendered message
func (c RGBColor) Sprint(a ...interface{}) string {
return RenderCode(c.String(), a...)
}
func (c RGBColor) Sprint(a ...any) string { return RenderCode(c.String(), a...) }
// Sprintf returns format and rendered message
func (c RGBColor) Sprintf(format string, a ...interface{}) string {
func (c RGBColor) Sprintf(format string, a ...any) string {
return RenderString(c.String(), fmt.Sprintf(format, a...))
}
@ -185,19 +207,18 @@ func (c RGBColor) Values() []int {
}
// Code to color code string without prefix. eg: "204;123;56"
func (c RGBColor) Code() string {
return fmt.Sprintf("%d;%d;%d", c[0], c[1], c[2])
}
func (c RGBColor) Code() string { return fmt.Sprintf("%d;%d;%d", c[0], c[1], c[2]) }
// Hex color rgb to hex string. as in "ff0080".
func (c RGBColor) Hex() string {
return fmt.Sprintf("%02x%02x%02x", c[0], c[1], c[2])
func (c RGBColor) Hex() string { return fmt.Sprintf("%02x%02x%02x", c[0], c[1], c[2]) }
// RgbString to color code string without prefix. eg: "204,123,56"
func (c RGBColor) RgbString() string {
return fmt.Sprintf("%d,%d,%d", c[0], c[1], c[2])
}
// FullCode to color code string with prefix
func (c RGBColor) FullCode() string {
return c.String()
}
func (c RGBColor) FullCode() string { return c.String() }
// String to color code string with prefix. eg: "38;2;204;123;56"
func (c RGBColor) String() string {
@ -213,11 +234,21 @@ func (c RGBColor) String() string {
return ""
}
// IsEmpty value
func (c RGBColor) IsEmpty() bool {
return c[3] > AsBg
// ToBg convert to background color
func (c RGBColor) ToBg() RGBColor {
c[3] = AsBg
return c
}
// ToFg convert to foreground color
func (c RGBColor) ToFg() RGBColor {
c[3] = AsFg
return c
}
// IsEmpty value
func (c RGBColor) IsEmpty() bool { return c[3] > AsBg }
// IsValid value
// func (c RGBColor) IsValid() bool {
// return c[3] <= AsBg
@ -244,13 +275,13 @@ func (c RGBColor) C16() Color { return c.Basic() }
* RGB Style
*************************************************************/
// RGBStyle definition.
// RGBStyle supports set foreground and background color
//
// Foreground/Background color
// All are composed of 4 digits uint8, the first three digits are the color value;
// The last bit is different from RGBColor, here it indicates whether the value is set.
// - 1 Has been set
// - ^1 Not set
//
// 1 Has been set
// ^1 Not set
type RGBStyle struct {
// Name of the style
Name string
@ -271,9 +302,11 @@ func NewRGBStyle(fg RGBColor, bg ...RGBColor) *RGBStyle {
}
// HEXStyle create a RGBStyle from HEX color string.
//
// Usage:
// s := HEXStyle("aabbcc", "eee")
// s.Print("message")
//
// s := HEXStyle("aabbcc", "eee")
// s.Print("message")
func HEXStyle(fg string, bg ...string) *RGBStyle {
s := &RGBStyle{}
if len(bg) > 0 {
@ -283,14 +316,15 @@ func HEXStyle(fg string, bg ...string) *RGBStyle {
if len(fg) > 0 {
s.SetFg(HEX(fg))
}
return s
}
// RGBStyleFromString create a RGBStyle from color value string.
//
// Usage:
// s := RGBStyleFromString("170,187,204", "70,87,4")
// s.Print("message")
//
// s := RGBStyleFromString("170,187,204", "70,87,4")
// s.Print("message")
func RGBStyleFromString(fg string, bg ...string) *RGBStyle {
s := &RGBStyle{}
if len(bg) > 0 {
@ -332,39 +366,33 @@ func (s *RGBStyle) AddOpts(opts ...Color) *RGBStyle {
}
// Print print message
func (s *RGBStyle) Print(a ...interface{}) {
func (s *RGBStyle) Print(a ...any) {
doPrintV2(s.String(), fmt.Sprint(a...))
}
// Printf format and print message
func (s *RGBStyle) Printf(format string, a ...interface{}) {
func (s *RGBStyle) Printf(format string, a ...any) {
doPrintV2(s.String(), fmt.Sprintf(format, a...))
}
// Println print message with newline
func (s *RGBStyle) Println(a ...interface{}) {
func (s *RGBStyle) Println(a ...any) {
doPrintlnV2(s.String(), a)
}
// Sprint returns rendered message
func (s *RGBStyle) Sprint(a ...interface{}) string {
return RenderCode(s.String(), a...)
}
func (s *RGBStyle) Sprint(a ...any) string { return RenderCode(s.String(), a...) }
// Sprintf returns format and rendered message
func (s *RGBStyle) Sprintf(format string, a ...interface{}) string {
func (s *RGBStyle) Sprintf(format string, a ...any) string {
return RenderString(s.String(), fmt.Sprintf(format, a...))
}
// Code convert to color code string
func (s *RGBStyle) Code() string {
return s.String()
}
func (s *RGBStyle) Code() string { return s.String() }
// FullCode convert to color code string
func (s *RGBStyle) FullCode() string {
return s.String()
}
func (s *RGBStyle) FullCode() string { return s.String() }
// String convert to color code string
func (s *RGBStyle) String() string {
@ -386,6 +414,4 @@ func (s *RGBStyle) String() string {
}
// IsEmpty style
func (s *RGBStyle) IsEmpty() bool {
return s.fg[3] != 1 && s.bg[3] != 1
}
func (s *RGBStyle) IsEmpty() bool { return s.fg[3] != 1 && s.bg[3] != 1 }

View file

@ -38,8 +38,12 @@ var (
* internal defined color tags
*************************************************************/
// There are internal defined color tags
// Usage: <tag>content text</>
// There are internal defined fg color tags
//
// Usage:
//
// <tag>content text</>
//
// @notice 加 0 在前面是为了防止之前的影响到现在的设置
var colorTags = map[string]string{
// basic tags
@ -72,7 +76,9 @@ var colorTags = map[string]string{
"magenta": "0;35",
"mga": "0;35", // short name
"magentaB": "1;35", // with bold
"magenta1": "1;35",
"mgb": "1;35",
"mga1": "1;35",
"mgaB": "1;35",
// light/hi tags
@ -90,7 +96,7 @@ var colorTags = map[string]string{
"light_magenta": "0;95",
"hiMagenta": "0;95",
"hi_magenta": "0;95",
"lightMagentaB": "1;95", // with bold
"lightMagenta1": "1;95", // with bold
"hiMagentaB": "1;95", // with bold
"hi_magenta_b": "1;95",
"lightRed": "0;91",
@ -127,9 +133,14 @@ var colorTags = map[string]string{
// option
"bold": "1",
"b": "1",
"italic": "3",
"i": "3", // italic
"underscore": "4",
"us": "4", // short name for 'underscore'
"blink": "5",
"fb": "6", // fast blink
"reverse": "7",
"st": "9", // strikethrough
// alert tags, like bootstrap's alert
"suc": "1;32", // same "green" and "bold"
@ -146,12 +157,141 @@ var colorTags = map[string]string{
"error": "97;41", // fg light white; bg red
}
/*************************************************************
* internal defined tag attributes
*************************************************************/
// built-in attributes for fg,bg 16-colors and op codes.
var (
attrFgs = map[string]string{
// basic colors
"black": FgBlack.Code(),
"red": "31",
"green": "32",
"brown": "33", // #A52A2A
"yellow": "33",
"ylw": "33",
"blue": "34",
"cyan": "36",
"magenta": "35",
"mga": "35",
"white": FgWhite.Code(),
"default": "39", // no color
"normal": "39", // no color
// light/hi colors
"darkGray": FgDarkGray.Code(),
"dark_gray": "90",
"gray": "90",
"lightYellow": "93",
"light_yellow": "93",
"hiYellow": "93",
"hi_yellow": "93",
"lightMagenta": "95",
"light_magenta": "95",
"hiMagenta": "95",
"hi_magenta": "95",
"hi_mga": "95",
"lightRed": "91",
"light_red": "91",
"hiRed": "91",
"hi_red": "91",
"lightGreen": "92",
"light_green": "92",
"hiGreen": "92",
"hi_green": "92",
"lightBlue": "94",
"light_blue": "94",
"hiBlue": "94",
"hi_blue": "94",
"lightCyan": "96",
"light_cyan": "96",
"hiCyan": "96",
"hi_cyan": "96",
"lightWhite": "97",
"light_white": "97",
}
attrBgs = map[string]string{
// basic colors
"black": BgBlack.Code(),
"red": "41",
"green": "42",
"brown": "43", // #A52A2A
"yellow": "43",
"ylw": "43",
"blue": "44",
"cyan": "46",
"magenta": "45",
"mga": "45",
"white": FgWhite.Code(),
"default": "49", // no color
"normal": "49", // no color
// light/hi colors
"darkGray": BgDarkGray.Code(),
"dark_gray": "100",
"gray": "100",
"lightYellow": "103",
"light_yellow": "103",
"hiYellow": "103",
"hi_yellow": "103",
"lightMagenta": "105",
"light_magenta": "105",
"hiMagenta": "105",
"hi_magenta": "105",
"hi_mga": "105",
"lightRed": "101",
"light_red": "101",
"hiRed": "101",
"hi_red": "101",
"lightGreen": "102",
"light_green": "102",
"hiGreen": "102",
"hi_green": "102",
"lightBlue": "104",
"light_blue": "104",
"hiBlue": "104",
"hi_blue": "104",
"lightCyan": "106",
"light_cyan": "106",
"hiCyan": "106",
"hi_cyan": "106",
"lightWhite": BgLightWhite.Code(),
"light_white": "107",
}
attrOpts = map[string]string{
"reset": OpReset.Code(),
"bold": OpBold.Code(),
"b": OpBold.Code(),
"fuzzy": OpFuzzy.Code(),
"italic": OpItalic.Code(),
"i": OpItalic.Code(),
"underscore": OpUnderscore.Code(),
"us": OpUnderscore.Code(),
"u": OpUnderscore.Code(),
"blink": OpBlink.Code(),
"fastblink": OpFastBlink.Code(),
"fb": OpFastBlink.Code(),
"reverse": OpReverse.Code(),
"concealed": OpConcealed.Code(),
"strikethrough": OpStrikethrough.Code(),
"st": OpStrikethrough.Code(),
}
)
/*************************************************************
* parse color tags
*************************************************************/
var (
tagParser = TagParser{}
// regex for match color 256 code
rxNumStr = regexp.MustCompile("^[0-9]{1,3}$")
rxHexCode = regexp.MustCompile("^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$")
)
@ -182,11 +322,20 @@ func (tp *TagParser) ParseByEnv(str string) string {
if !Enable || !SupportColor() {
return ClearTag(str)
}
return tp.Parse(str)
}
// Parse parse given string, replace color tag and return rendered string
// Parse given string, replace color tag and return rendered string
//
// Use built in tags:
//
// <TAG_NAME>CONTENT</>
// // e.g: `<info>message</>`
//
// Custom tag attributes:
//
// `<fg=VALUE;bg=VALUE;op=VALUES>CONTENT</>`
// // e.g: `<fg=167;bg=232>wel</>`
func (tp *TagParser) Parse(str string) string {
// not contains color tag
if !strings.Contains(str, "</>") {
@ -198,14 +347,15 @@ func (tp *TagParser) Parse(str string) string {
// item: 0 full text 1 tag name 2 tag content
for _, item := range matched {
full, tag, content := item[0], item[1], item[2]
full, tag, body := repairMatchedTag(item[0], item[1], item[2])
// use defined tag name: "<info>content</>" -> tag: "info"
// use defined color tag name: "<info>content</>" -> tag: "info"
if !strings.ContainsRune(tag, '=') {
code := colorTags[tag]
if len(code) > 0 {
now := RenderString(code, content)
// old := WrapTag(content, tag) is equals to var 'full'
if code := colorTags[tag]; len(code) > 0 {
str = strings.Replace(str, full, RenderString(code, body), 1)
} else if code, ok := namedRgbMap[tag]; ok {
code = strings.Replace(code, ",", ";", -1)
now := RenderString(FgRGBPfx+code, body)
str = strings.Replace(str, full, now, 1)
}
continue
@ -214,17 +364,25 @@ func (tp *TagParser) Parse(str string) string {
// custom color in tag
// - basic: "fg=white;bg=blue;op=bold"
if code := ParseCodeFromAttr(tag); len(code) > 0 {
now := RenderString(code, content)
str = strings.Replace(str, full, now, 1)
str = strings.Replace(str, full, RenderString(code, body), 1)
}
}
return str
}
// func (tp *TagParser) ParseAttr(attr string) (code string) {
// return
// }
func repairMatchedTag(full, tag, body string) (string, string, string) {
if len(colorTags[tag]) == 0 && len(namedRgbMap[tag]) == 0 && len(ParseCodeFromAttr(tag)) == 0 {
if matched := matchRegex.FindAllStringSubmatch(strings.TrimPrefix(full, "<"+tag+">"), -1); len(matched) > 0 {
full = matched[0][0]
tag = matched[0][1]
body = matched[0][2]
return repairMatchedTag(full, tag, body)
}
}
return full, tag, body
}
// ReplaceTag parse string, replace color tag and return rendered string
func ReplaceTag(str string) string {
@ -234,23 +392,30 @@ func ReplaceTag(str string) string {
// ParseCodeFromAttr parse color attributes.
//
// attr format:
// // VALUE please see var: FgColors, BgColors, AllOptions
// "fg=VALUE;bg=VALUE;op=VALUE"
//
// // VALUE please see var: FgColors, BgColors, AllOptions
// "fg=VALUE;bg=VALUE;op=VALUE"
//
// 16 color:
// "fg=yellow"
// "bg=red"
// "op=bold,underscore" option is allow multi value
// "fg=white;bg=blue;op=bold"
// "fg=white;op=bold,underscore"
//
// "fg=yellow"
// "bg=red"
// "op=bold,underscore" // option is allow multi value
// "fg=white;bg=blue;op=bold"
// "fg=white;op=bold,underscore"
//
// 256 color:
//
// "fg=167"
// "fg=167;bg=23"
// "fg=167;bg=23;op=bold"
// true color:
// // hex
//
// True color:
//
// // hex
// "fg=fc1cac"
// "fg=fc1cac;bg=c2c3c4"
// // r,g,b
// // r,g,b
// "fg=23,45,214"
// "fg=23,45,214;bg=109,99,88"
func ParseCodeFromAttr(attr string) (code string) {
@ -270,18 +435,14 @@ func ParseCodeFromAttr(attr string) (code string) {
pos, val := item[1], item[2]
switch pos {
case "fg":
if c, ok := FgColors[val]; ok { // basic
codes = append(codes, c.String())
} else if c, ok := ExFgColors[val]; ok { // extra
codes = append(codes, c.String())
if code, ok := attrFgs[val]; ok { // attr fg
codes = append(codes, code)
} else if code := rgbHex256toCode(val, false); code != "" {
codes = append(codes, code)
}
case "bg":
if c, ok := BgColors[val]; ok { // basic bg
codes = append(codes, c.String())
} else if c, ok := ExBgColors[val]; ok { // extra bg
codes = append(codes, c.String())
if code, ok := attrBgs[val]; ok { // attr bg
codes = append(codes, code)
} else if code := rgbHex256toCode(val, true); code != "" {
codes = append(codes, code)
}
@ -289,12 +450,12 @@ func ParseCodeFromAttr(attr string) (code string) {
if strings.Contains(val, ",") {
ns := strings.Split(val, ",")
for _, n := range ns {
if c, ok := AllOptions[n]; ok {
codes = append(codes, c.String())
if code, ok := attrOpts[n]; ok { // attr ops
codes = append(codes, code)
}
}
} else if c, ok := AllOptions[val]; ok {
codes = append(codes, c.String())
} else if code, ok := attrOpts[val]; ok {
codes = append(codes, code)
}
}
}
@ -327,7 +488,6 @@ func ClearTag(s string) string {
if !strings.Contains(s, "</>") {
return s
}
return stripRegex.ReplaceAllString(s, "")
}
@ -336,12 +496,10 @@ func ClearTag(s string) string {
*************************************************************/
// GetTagCode get color code by tag name
func GetTagCode(name string) string {
return colorTags[name]
}
func GetTagCode(name string) string { return colorTags[name] }
// ApplyTag for messages
func ApplyTag(tag string, a ...interface{}) string {
func ApplyTag(tag string, a ...any) string {
return RenderCode(GetTagCode(tag), a...)
}
@ -350,7 +508,6 @@ func WrapTag(s string, tag string) string {
if s == "" || tag == "" {
return s
}
return fmt.Sprintf("<%s>%s</>", tag, s)
}
@ -371,11 +528,12 @@ func IsDefinedTag(name string) bool {
// Tag value is a defined style name
// Usage:
// Tag("info").Println("message")
//
// Tag("info").Println("message")
type Tag string
// Print messages
func (tg Tag) Print(a ...interface{}) {
func (tg Tag) Print(a ...any) {
name := string(tg)
str := fmt.Sprint(a...)
@ -387,7 +545,7 @@ func (tg Tag) Print(a ...interface{}) {
}
// Printf format and print messages
func (tg Tag) Printf(format string, a ...interface{}) {
func (tg Tag) Printf(format string, a ...any) {
name := string(tg)
str := fmt.Sprintf(format, a...)
@ -399,7 +557,7 @@ func (tg Tag) Printf(format string, a ...interface{}) {
}
// Println messages line
func (tg Tag) Println(a ...interface{}) {
func (tg Tag) Println(a ...any) {
name := string(tg)
if stl := GetStyle(name); !stl.IsEmpty() {
stl.Println(a...)
@ -409,17 +567,12 @@ func (tg Tag) Println(a ...interface{}) {
}
// Sprint render messages
func (tg Tag) Sprint(a ...interface{}) string {
name := string(tg)
// if stl := GetStyle(name); !stl.IsEmpty() {
// return stl.Render(args...)
// }
return RenderCode(GetTagCode(name), a...)
func (tg Tag) Sprint(a ...any) string {
return RenderCode(GetTagCode(string(tg)), a...)
}
// Sprintf format and render messages
func (tg Tag) Sprintf(format string, a ...interface{}) string {
func (tg Tag) Sprintf(format string, a ...any) string {
tag := string(tg)
str := fmt.Sprintf(format, a...)

View file

@ -3,10 +3,32 @@ package color
import (
"fmt"
"math"
"sort"
"strconv"
"strings"
)
// values from https://github.com/go-terminfo/terminfo
// var (
// RgbaBlack = image_color.RGBA{0, 0, 0, 255}
// Red = color.RGBA{205, 0, 0, 255}
// Green = color.RGBA{0, 205, 0, 255}
// Orange = color.RGBA{205, 205, 0, 255}
// Blue = color.RGBA{0, 0, 238, 255}
// Magenta = color.RGBA{205, 0, 205, 255}
// Cyan = color.RGBA{0, 205, 205, 255}
// LightGrey = color.RGBA{229, 229, 229, 255}
//
// DarkGrey = color.RGBA{127, 127, 127, 255}
// LightRed = color.RGBA{255, 0, 0, 255}
// LightGreen = color.RGBA{0, 255, 0, 255}
// Yellow = color.RGBA{255, 255, 0, 255}
// LightBlue = color.RGBA{92, 92, 255, 255}
// LightMagenta = color.RGBA{255, 0, 255, 255}
// LightCyan = color.RGBA{0, 255, 255, 255}
// White = color.RGBA{255, 255, 255, 255}
// )
var (
// ---------- basic(16) <=> 256 color convert ----------
basicTo256Map = map[uint8]uint8{
@ -30,6 +52,7 @@ var (
// ---------- basic(16) <=> RGB color convert ----------
// refer from Hyper app
// Tip: only keep foreground color, background color need convert to foreground color for convert to RGB
basic2hexMap = map[uint8]string{
30: "000000", // black
31: "c51e14", // red
@ -39,6 +62,15 @@ var (
35: "c839c5", // magenta
36: "20c5c6", // cyan
37: "c7c7c7", // white
// - don't add bg color, convert to fg color for convert to RGB
// 40: "000000", // black
// 41: "c51e14", // red
// 42: "1dc121", // green
// 43: "c7c329", // yellow
// 44: "0a2fc4", // blue
// 45: "c839c5", // magenta
// 46: "20c5c6", // cyan
// 47: "c7c7c7", // white
90: "686868", // lightBlack/darkGray
91: "fd6f6b", // lightRed
92: "67f86f", // lightGreen
@ -47,6 +79,15 @@ var (
95: "fd7cfc", // lightMagenta
96: "68fdfe", // lightCyan
97: "ffffff", // lightWhite
// - don't add bg color
// 100: "686868", // lightBlack/darkGray
// 101: "fd6f6b", // lightRed
// 102: "67f86f", // lightGreen
// 103: "fffa72", // lightYellow
// 104: "6a76fb", // lightBlue
// 105: "fd7cfc", // lightMagenta
// 106: "68fdfe", // lightCyan
// 107: "ffffff", // lightWhite
}
// will convert data from basic2hexMap
hex2basicMap = initHex2basicMap()
@ -376,6 +417,7 @@ func Colors2code(colors ...Color) string {
}
/*************************************************************
* region HEX <=> RGB
* HEX code <=> RGB/True color code
*************************************************************/
@ -388,10 +430,11 @@ func HexToRGB(hex string) []int { return HexToRgb(hex) }
// HexToRgb convert 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]
//
// 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)
if hex == "" {
@ -434,9 +477,10 @@ func Rgb2hex(rgb []int) string { return RgbToHex(rgb) }
// RgbToHex convert RGB-code to hex-code
//
// Usage:
//
// hex := RgbToHex([]int{170, 187, 204}) // hex: "aabbcc"
func RgbToHex(rgb []int) string {
hexNodes := make([]string, len(rgb))
hexNodes := make([]string, 0, len(rgb))
for _, v := range rgb {
hexNodes = append(hexNodes, strconv.FormatInt(int64(v), 16))
@ -445,17 +489,29 @@ func RgbToHex(rgb []int) string {
}
/*************************************************************
* region 4bit(16) <=> RGB
* 4bit(16) color <=> RGB/True color
*************************************************************/
// Basic2hex convert basic color to hex string.
func Basic2hex(val uint8) string {
// BasicToHex convert basic color to hex string.
func BasicToHex(val uint8) string {
val = Bg2Fg(val)
return basic2hexMap[val]
}
// Basic2hex convert basic color to hex string.
func Basic2hex(val uint8) string {
return BasicToHex(val)
}
// Hex2basic convert hex string to basic color code.
func Hex2basic(hex string) uint8 {
return hex2basicMap[hex]
func Hex2basic(hex string, asBg ...bool) uint8 {
val := hex2basicMap[hex]
if len(asBg) > 0 && asBg[0] {
return Fg2Bg(val)
}
return val
}
// Rgb2basic alias of the RgbToAnsi()
@ -472,7 +528,7 @@ func Rgb2basic(r, g, b uint8, isBg bool) uint8 {
return RgbToAnsi(r, g, b, isBg)
}
// Rgb2ansi alias of the RgbToAnsi()
// Rgb2ansi convert RGB-code to 16-code, alias of the RgbToAnsi()
func Rgb2ansi(r, g, b uint8, isBg bool) uint8 {
return RgbToAnsi(r, g, b, isBg)
}
@ -591,3 +647,508 @@ func C256ToRgbV1(val uint8) (rgb []uint8) {
return []uint8{r, g, b}
}
/**************************************************************
* region HSL <=> RGB color
************************************************************
* h,s,l = Hue, Saturation, Lightness 色相饱和度亮度
*
* refers
* http://en.wikipedia.org/wiki/HSL_color_space
* https://www.w3.org/TR/css-color-3/#hsl-color
* https://stackoverflow.com/questions/2353211/hsl-to-rgb-color-conversion
* https://github.com/less/less.js/blob/master/packages/less/src/less/functions/color.js
* https://github.com/d3/d3-color/blob/v3.0.1/README.md#hsl
*
* examples:
* color: hsl(0, 100%, 50%) // red
* color: hsl(120, 100%, 50%) // lime
* color: hsl(120, 100%, 25%) // dark green
* color: hsl(120, 100%, 75%) // light green
* color: hsl(120, 75%, 75%) // pastel green, and so on
*/
// HslIntToRgb Converts an HSL color value to RGB
// Assumes h: 0-360, s: 0-100%, l: 0-100%
// returns r, g, and b in the set [0, 255].
//
// Usage:
//
// HslIntToRgb(0, 100, 50) // red
// HslIntToRgb(120, 100, 50) // lime
// HslIntToRgb(120, 100, 25) // dark green
// HslIntToRgb(120, 100, 75) // light green
func HslIntToRgb(h, s, l int) (rgb []uint8) {
return HslToRgb(float64(h)/360, float64(s)/100, float64(l)/100)
}
// HslToRgb Converts an HSL color value to RGB. Conversion formula
// adapted from http://en.wikipedia.org/wiki/HSL_color_space.
// Assumes h, s, and l are contained in the set [0, 1]
// returns r, g, and b in the set [0, 255].
//
// Usage:
//
// rgbVals := HslToRgb(0, 1, 0.5) // red
func HslToRgb(h, s, l float64) (rgb []uint8) {
var r, g, b float64
if s == 0 { // achromatic
r, g, b = l, l, l
} else {
// q = l < 0.5 ? l * (1 + s) : l + s - l*s
var q float64
if l < 0.5 {
q = l * (1.0 + s)
} else {
q = l + s - l*s
}
var p = 2.0*l - q
r = hue2rgb(p, q, h+1.0/3.0)
g = hue2rgb(p, q, h)
b = hue2rgb(p, q, h-1.0/3.0)
}
// return []uint8{uint8(r * 255), uint8(g * 255), uint8(b * 255)}
return []uint8{
uint8(math.Round(r * 255)),
uint8(math.Round(g * 255)),
uint8(math.Round(b * 255)),
}
}
var hue2rgb = func(p, q, t float64) float64 {
if t < 0.0 {
t += 1
}
if t > 1.0 {
t -= 1
}
if t < 1.0/6.0 {
return p + (q-p)*6.0*t
}
if t < 1.0/2.0 {
return q
}
if t < 2.0/3.0 {
return p + (q-p)*(2.0/3.0-t)*6.0
}
return p
}
// RgbStrToHslInts convert rgb(r,g,b) string to HSL int values.
func RgbStrToHslInts(rgbStr string) []int {
f64s := RgbStrToHsl(rgbStr)
if f64s == nil {
return nil
}
return []int{
int(math.Round(f64s[0] * 360)),
int(math.Round(f64s[1] * 100)),
int(math.Round(f64s[2] * 100)),
}
}
// RgbStrToHsl convert rgb(r,g,b) string to HSL
func RgbStrToHsl(rgbStr string) []float64 {
if pos := strings.IndexByte(rgbStr, '('); pos > 0 {
rgbStr = strings.TrimRight(rgbStr[pos+1:], "()")
}
rgbVals := strings.Split(rgbStr, ",")
if len(rgbVals) != 3 {
return nil
}
r, e1 := strconv.ParseInt(strings.TrimSpace(rgbVals[0]), 10, 0)
if e1 != nil {
return nil
}
g, e2 := strconv.ParseInt(strings.TrimSpace(rgbVals[1]), 10, 0)
if e2 != nil {
return nil
}
b, e3 := strconv.ParseInt(strings.TrimSpace(rgbVals[2]), 10, 0)
if e3 != nil {
return nil
}
return RgbToHsl(uint8(r), uint8(g), uint8(b))
}
// RgbToHslInt Converts an RGB color value to HSL. Conversion formula
// Assumes r, g, and b are contained in the set [0, 255] and
// returns [h,s,l] h: 0-360, s: 0-100%, l: 0-100%.
func RgbToHslInt(r, g, b uint8) []int {
f64s := RgbToHsl(r, g, b)
return []int{
int(math.Round(f64s[0] * 360)),
int(math.Round(f64s[1] * 100)),
int(math.Round(f64s[2] * 100)),
}
}
// RgbToHsl Converts an RGB color value to HSL. Conversion formula
//
// adapted from http://en.wikipedia.org/wiki/HSL_color_space.
//
// e.g: rgb(59, 130, 246) = hsl(217, 91%, 60%)
//
// Assumes r, g, and b are contained in the set [0, 255] and
// returns h, s, and l in the set [0, 1].
func RgbToHsl(r, g, b uint8) []float64 {
// to float64
fr, fg, fb := float64(r), float64(g), float64(b)
// percentage
pr, pg, pb := fr/255.0, fg/255.0, fb/255.0
ps := []float64{pr, pg, pb}
sort.Float64s(ps)
min1, max1 := ps[0], ps[2]
// max := math.Max(math.Max(pr, pg), pb)
// min := math.Min(math.Min(pr, pg), pb)
mid := (max1 + min1) / 2.0 // call Lightness
h, s, l := mid, mid, mid
// calc Saturation
if max1 == min1 {
h, s = 0, 0 // achromatic
} else {
var d = max1 - min1 // 计算色差
// s = l > 0.5 ? d / (2 - max1 - min1) : d / (max1 + min1)
s = compareF64(l > 0.5, d/(2.0-max1-min1), d/(max1+min1))
// calc Hue
switch max1 {
case pr:
// h = (g - b) / d + (g < b ? 6 : 0)
h = (pg - pb) / d
h += compareF64(g < b, 6, 0)
case pg:
h = (pb-pr)/d + 2
case pb:
h = (pr-pg)/d + 4
}
h /= 6
}
return []float64{h, s, l}
}
/**************************************************************
* region HSV/HSB <=> RGB color
************************************************************
* h,s,v/b = Hue, Saturation, Value(Brightness) 色相饱和度亮度
*
* refers
* https://stackoverflow.com/questions/2353211/hsl-to-rgb-color-conversion
* https://github.com/less/less.js/blob/master/packages/less/src/less/functions/color.js
* https://github.com/d3/d3-color/blob/v3.0.1/README.md#hsl
*/
// function aliases
var (
HsvToRgb = HSVToRGB
// HsvIntToRgbInts alias for HSVIntToRGBInts
HsvIntToRgbInts = HSVIntToRGBInts
)
// HSVIntToRGBInts Converts an HSL color value to RGB slice. Conversion formula
// adapted from https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB
//
// Assumes h: 0-360, s: 0-100, l: 0-100
// returns r, g, and b in the set [0, 255].
func HSVIntToRGBInts(h, s, v int) []uint8 {
r, g, b := HSVToRGB(float64(h), float64(s)/100, float64(v)/100)
return []uint8{r, g, b}
}
// HSVToRGB Convert HSV values to RGB values
// - inputs: h (0-360), s (0-1.0), v (0-1.0)
// - returns: r, g, b (0-255)
func HSVToRGB(h, s, v float64) (r, g, b uint8) {
// 1. 处理特殊情况饱和度为0灰色
if s == 0 {
gray := uint8(v * 255)
return gray, gray, gray
}
// 2. 确保h在0-360范围内
h = math.Mod(h, 360)
if h < 0 {
h += 360
}
// 3. 将h转换为0-6范围
hSector := float64(h) / 60.0
fraction := hSector - math.Floor(hSector)
sector := int(math.Floor(hSector))
// 4. 计算中间值
p := v * (1 - s)
q := v * (1 - fraction*s)
t := v * (1 - (1-fraction)*s)
// 5. 根据色相扇区计算RGB
switch sector {
case 0:
r = uint8(v * 255)
g = uint8(t * 255)
b = uint8(p * 255)
case 1:
r = uint8(q * 255)
g = uint8(v * 255)
b = uint8(p * 255)
case 2:
r = uint8(p * 255)
g = uint8(v * 255)
b = uint8(t * 255)
case 3:
r = uint8(p * 255)
g = uint8(q * 255)
b = uint8(v * 255)
case 4:
r = uint8(t * 255)
g = uint8(p * 255)
b = uint8(v * 255)
case 5:
r = uint8(v * 255)
g = uint8(p * 255)
b = uint8(q * 255)
}
return r, g, b
}
// function aliases
var (
RgbToHsv = RGBToHSV
RgbToHsvInts = RGBToHSVInts
RgbToHsvSlice = RGBToHSVSlice
)
// RGBToHSVInts convert RGB to HSV int values.
//
// r, g, b: [0, 255] => h (0-360), s (0-100), v (0-100)
func RGBToHSVInts(r, g, b uint8) []int {
h, s, v := RGBToHSV(r, g, b)
return []int{int(h), int(math.Round(s * 100)), int(math.Round(v * 100))}
}
// RGBToHSVSlice Convert RGB values to HSV values slice.
//
// r, g, b (0-255) => h (0-360), s (0-1.0), v (0-1.0)
func RGBToHSVSlice(r, g, b uint8) []float64 {
h, s, v := RGBToHSV(r, g, b)
return []float64{h, s, v}
}
// RGBToHSV Convert RGB values to HSV values
// - inputs: r, g, b (0-255)
// - returns: h (0-360), s (0-1.0), v (0-1.0)
func RGBToHSV(r, g, b uint8) (h, s, v float64) {
// 1. 将RGB值归一化到 [0, 1] 范围
rNorm := float64(r) / 255.0
gNorm := float64(g) / 255.0
bNorm := float64(b) / 255.0
// 2. 找出最大值和最小值
max1 := math.Max(math.Max(rNorm, gNorm), bNorm)
min1 := math.Min(math.Min(rNorm, gNorm), bNorm)
delta := max1 - min1
// 3. 计算明度 (Value)
v = max1
// 4. 计算饱和度 (Saturation)
if max1 == 0 {
// 黑色情况饱和度为0
s = 0
} else {
s = delta / max1
}
// 5. 计算色相 (Hue)
if delta == 0 {
// 灰色情况色相为0
h = 0
} else {
switch max1 {
case rNorm:
h = (gNorm - bNorm) / delta
if gNorm < bNorm {
h += 6
}
case gNorm:
h = (bNorm-rNorm)/delta + 2
case bNorm:
h = (rNorm-gNorm)/delta + 4
}
h *= 60 // 转换为角度 (0-360度)
}
return h, s, v
}
//
// region Named RGB color
//
// Named rgb colors
// https://www.w3.org/TR/css-color-3/#svg-color
var namedRgbMap = map[string]string{
"aliceblue": "240,248,255", // #F0F8FF
"antiquewhite": "250,235,215", // #FAEBD7
"aqua": "0,255,255", // #00FFFF
"aquamarine": "127,255,212", // #7FFFD4
"azure": "240,255,255", // #F0FFFF
"beige": "245,245,220", // #F5F5DC
"bisque": "255,228,196", // #FFE4C4
"black": "0,0,0", // #000000
"blanchedalmond": "255,235,205", // #FFEBCD
"blue": "0,0,255", // #0000FF
"blueviolet": "138,43,226", // #8A2BE2
"brown": "165,42,42", // #A52A2A
"burlywood": "222,184,135", // #DEB887
"cadetblue": "95,158,160", // #5F9EA0
"chartreuse": "127,255,0", // #7FFF00
"chocolate": "210,105,30", // #D2691E
"coral": "255,127,80", // #FF7F50
"cornflowerblue": "100,149,237", // #6495ED
"cornsilk": "255,248,220", // #FFF8DC
"crimson": "220,20,60", // #DC143C
"cyan": "0,255,255", // #00FFFF
"darkblue": "0,0,139", // #00008B
"darkcyan": "0,139,139", // #008B8B
"darkgoldenrod": "184,134,11", // #B8860B
"darkgray": "169,169,169", // #A9A9A9
"darkgreen": "0,100,0", // #006400
"darkgrey": "169,169,169", // #A9A9A9
"darkkhaki": "189,183,107", // #BDB76B
"darkmagenta": "139,0,139", // #8B008B
"darkolivegreen": "85,107,47", // #556B2F
"darkorange": "255,140,0", // #FF8C00
"darkorchid": "153,50,204", // #9932CC
"darkred": "139,0,0", // #8B0000
"darksalmon": "233,150,122", // #E9967A
"darkseagreen": "143,188,143", // #8FBC8F
"darkslateblue": "72,61,139", // #483D8B
"darkslategray": "47,79,79", // #2F4F4F
"darkslategrey": "47,79,79", // #2F4F4F
"darkturquoise": "0,206,209", // #00CED1
"darkviolet": "148,0,211", // #9400D3
"deeppink": "255,20,147", // #FF1493
"deepskyblue": "0,191,255", // #00BFFF
"dimgray": "105,105,105", // #696969
"dimgrey": "105,105,105", // #696969
"dodgerblue": "30,144,255", // #1E90FF
"firebrick": "178,34,34", // #B22222
"floralwhite": "255,250,240", // #FFFAF0
"forestgreen": "34,139,34", // #228B22
"fuchsia": "255,0,255", // #FF00FF
"gainsboro": "220,220,220", // #DCDCDC
"ghostwhite": "248,248,255", // #F8F8FF
"gold": "255,215,0", // #FFD700
"goldenrod": "218,165,32", // #DAA520
"gray": "128,128,128", // #808080
"green": "0,128,0", // #008000
"greenyellow": "173,255,47", // #ADFF2F
"grey": "128,128,128", // #808080
"honeydew": "240,255,240", // #F0FFF0
"hotpink": "255,105,180", // #FF69B4
"indianred": "205,92,92", // #CD5C5C
"indigo": "75,0,130", // #4B0082
"ivory": "255,255,240", // #FFFFF0
"khaki": "240,230,140", // #F0E68C
"lavender": "230,230,250", // #E6E6FA
"lavenderblush": "255,240,245", // #FFF0F5
"lawngreen": "124,252,0", // #7CFC00
"lemonchiffon": "255,250,205", // #FFFACD
"lightblue": "173,216,230", // #ADD8E6
"lightcoral": "240,128,128", // #F08080
"lightcyan": "224,255,255", // #E0FFFF
"lightgoldenrodyellow": "250,250,210", // #FAFAD2
"lightgray": "211,211,211", // #D3D3D3
"lightgreen": "144,238,144", // #90EE90
"lightgrey": "211,211,211", // #D3D3D3
"lightpink": "255,182,193", // #FFB6C1
"lightsalmon": "255,160,122", // #FFA07A
"lightseagreen": "32,178,170", // #20B2AA
"lightskyblue": "135,206,250", // #87CEFA
"lightslategray": "119,136,153", // #778899
"lightslategrey": "119,136,153", // #778899
"lightsteelblue": "176,196,222", // #B0C4DE
"lightyellow": "255,255,224", // #FFFFE0
"lime": "0,255,0", // #00FF00
"limegreen": "50,205,50", // #32CD32
"linen": "250,240,230", // #FAF0E6
"magenta": "255,0,255", // #FF00FF
"maroon": "128,0,0", // #800000
"mediumaquamarine": "102,205,170", // #66CDAA
"mediumblue": "0,0,205", // #0000CD
"mediumorchid": "186,85,211", // #BA55D3
"mediumpurple": "147,112,219", // #9370DB
"mediumseagreen": "60,179,113", // #3CB371
"mediumslateblue": "123,104,238", // #7B68EE
"mediumspringgreen": "0,250,154", // #00FA9A
"mediumturquoise": "72,209,204", // #48D1CC
"mediumvioletred": "199,21,133", // #C71585
"midnightblue": "25,25,112", // #191970
"mintcream": "245,255,250", // #F5FFFA
"mistyrose": "255,228,225", // #FFE4E1
"moccasin": "255,228,181", // #FFE4B5
"navajowhite": "255,222,173", // #FFDEAD
"navy": "0,0,128", // #000080
"oldlace": "253,245,230", // #FDF5E6
"olive": "128,128,0", // #808000
"olivedrab": "107,142,35", // #6B8E23
"orange": "255,165,0", // #FFA500
"orangered": "255,69,0", // #FF4500
"orchid": "218,112,214", // #DA70D6
"palegoldenrod": "238,232,170", // #EEE8AA
"palegreen": "152,251,152", // #98FB98
"paleturquoise": "175,238,238", // #AFEEEE
"palevioletred": "219,112,147", // #DB7093
"papayawhip": "255,239,213", // #FFEFD5
"peachpuff": "255,218,185", // #FFDAB9
"peru": "205,133,63", // #CD853F
"pink": "255,192,203", // #FFC0CB
"plum": "221,160,221", // #DDA0DD
"powderblue": "176,224,230", // #B0E0E6
"purple": "128,0,128", // #800080
"red": "255,0,0", // #FF0000
"rosybrown": "188,143,143", // #BC8F8F
"royalblue": "65,105,225", // #4169E1
"saddlebrown": "139,69,19", // #8B4513
"salmon": "250,128,114", // #FA8072
"sandybrown": "244,164,96", // #F4A460
"seagreen": "46,139,87", // #2E8B57
"seashell": "255,245,238", // #FFF5EE
"sienna": "160,82,45", // #A0522D
"silver": "192,192,192", // #C0C0C0
"skyblue": "135,206,235", // #87CEEB
"slateblue": "106,90,205", // #6A5ACD
"slategray": "112,128,144", // #708090
"slategrey": "112,128,144", // #708090
"snow": "255,250,250", // #FFFAFA
"springgreen": "0,255,127", // #00FF7F
"steelblue": "70,130,180", // #4682B4
"tan": "210,180,140", // #D2B48C
"teal": "0,128,128", // #008080
"thistle": "216,191,216", // #D8BFD8
"tomato": "255,99,71", // #FF6347
"turquoise": "64,224,208", // #40E0D0
"violet": "238,130,238", // #EE82EE
"wheat": "245,222,179", // #F5DEB3
"white": "255,255,255", // #FFFFFF
"whitesmoke": "245,245,245", // #F5F5F5
"yellow": "255,255,0", // #FFFF00
"yellowgreen": "154,205,50", // #9ACD32
}

View file

@ -2,7 +2,6 @@ package color
import (
"io"
"io/ioutil"
"os"
"runtime"
"strconv"
@ -12,6 +11,17 @@ import (
"github.com/xo/terminfo"
)
// Level is the color level supported by a terminal.
type Level = terminfo.ColorLevel
// terminal color available level alias of the terminfo.ColorLevel*
const (
LevelNo = terminfo.ColorLevelNone // not support color.
Level16 = terminfo.ColorLevelBasic // basic - 3/4 bit color supported
Level256 = terminfo.ColorLevelHundreds // hundreds - 8-bit color supported
LevelRgb = terminfo.ColorLevelMillions // millions - (24 bit)true color supported
)
/*************************************************************
* helper methods for detect color supports
*************************************************************/
@ -19,8 +29,9 @@ import (
// DetectColorLevel for current env
//
// NOTICE: The method will detect terminal info each times,
// if only want get current color level, please direct call SupportColor() or TermColorLevel()
func DetectColorLevel() terminfo.ColorLevel {
//
// if only want to get current color level, please direct call SupportColor() or TermColorLevel()
func DetectColorLevel() Level {
level, _ := detectTermColorLevel()
return level
}
@ -28,7 +39,7 @@ func DetectColorLevel() terminfo.ColorLevel {
// detect terminal color support level
//
// refer https://github.com/Delta456/box-cli-maker
func detectTermColorLevel() (level terminfo.ColorLevel, needVTP bool) {
func detectTermColorLevel() (level Level, needVTP bool) {
// on windows WSL:
// - runtime.GOOS == "Linux"
// - support true-color
@ -38,7 +49,7 @@ func detectTermColorLevel() (level terminfo.ColorLevel, needVTP bool) {
// detect WSL as it has True Color support
if detectWSL() {
debugf("True Color support on WSL environment")
return terminfo.ColorLevelMillions, false
return LevelRgb, false
}
}
@ -54,7 +65,7 @@ func detectTermColorLevel() (level terminfo.ColorLevel, needVTP bool) {
val := os.Getenv("TERMINAL_EMULATOR")
if val == "JetBrains-JediTerm" {
debugf("True Color support on JetBrains-JediTerm, is win: %v", isWin)
return terminfo.ColorLevelMillions, isWin
return LevelRgb, isWin
}
}
@ -63,7 +74,7 @@ func detectTermColorLevel() (level terminfo.ColorLevel, needVTP bool) {
debugf("color level by detectColorLevelFromEnv: %s", level.String())
// fallback: simple detect by TERM value string.
if level == terminfo.ColorLevelNone {
if level == LevelNo {
debugf("level none - fallback check special term color support")
// on Windows: enable VTP as it has True Color support
level, needVTP = detectSpecialTermColor(termVal)
@ -76,29 +87,27 @@ func detectTermColorLevel() (level terminfo.ColorLevel, needVTP bool) {
//
// refer the terminfo.ColorLevelFromEnv()
// https://en.wikipedia.org/wiki/Terminfo
func detectColorLevelFromEnv(termVal string, isWin bool) terminfo.ColorLevel {
func detectColorLevelFromEnv(termVal string, isWin bool) Level {
// on TERM=screen: not support true-color
if termVal == "screen" {
return Level256
}
// check for overriding environment variables
colorTerm, termProg, forceColor := os.Getenv("COLORTERM"), os.Getenv("TERM_PROGRAM"), os.Getenv("FORCE_COLOR")
switch {
case strings.Contains(colorTerm, "truecolor") || strings.Contains(colorTerm, "24bit"):
if termVal == "screen" { // on TERM=screen: not support true-color
return terminfo.ColorLevelHundreds
}
return terminfo.ColorLevelMillions
return LevelRgb
case colorTerm != "" || forceColor != "":
return terminfo.ColorLevelBasic
if strings.Contains(termVal, "256color") {
return Level256
}
return Level16
case termProg == "Apple_Terminal":
return terminfo.ColorLevelHundreds
return Level256
case termProg == "Terminus" || termProg == "Hyper":
if termVal == "screen" { // on TERM=screen: not support true-color
return terminfo.ColorLevelHundreds
}
return terminfo.ColorLevelMillions
return LevelRgb
case termProg == "iTerm.app":
if termVal == "screen" { // on TERM=screen: not support true-color
return terminfo.ColorLevelHundreds
}
// check iTerm version
ver := os.Getenv("TERM_PROGRAM_VERSION")
if ver != "" {
@ -106,13 +115,13 @@ func detectColorLevelFromEnv(termVal string, isWin bool) terminfo.ColorLevel {
if err != nil {
saveInternalError(terminfo.ErrInvalidTermProgramVersion)
// return terminfo.ColorLevelNone
return terminfo.ColorLevelHundreds
return Level256
}
if i == 3 {
return terminfo.ColorLevelMillions
return LevelRgb
}
}
return terminfo.ColorLevelHundreds
return Level256
}
// otherwise determine from TERM's max_colors capability
@ -121,22 +130,22 @@ func detectColorLevelFromEnv(termVal string, isWin bool) terminfo.ColorLevel {
ti, err := terminfo.Load(termVal)
if err != nil {
saveInternalError(err)
return terminfo.ColorLevelNone
return LevelNo
}
debugf("the loaded term info file is: %s", ti.File)
v, ok := ti.Nums[terminfo.MaxColors]
switch {
case !ok || v <= 16:
return terminfo.ColorLevelNone
return LevelNo
case ok && v >= 256:
return terminfo.ColorLevelHundreds
return Level256
}
return terminfo.ColorLevelBasic
return Level16
}
// no TERM env value. default return none level
return terminfo.ColorLevelNone
return LevelNo
// return terminfo.ColorLevelBasic
}
@ -146,13 +155,15 @@ var wslContents string
// https://github.com/Microsoft/WSL/issues/423#issuecomment-221627364
func detectWSL() bool {
if !detectedWSL {
detectedWSL = true
b := make([]byte, 1024)
// `cat /proc/version`
// on mac:
// !not the file!
// on Mac, Windows cmd/pwsh:
// !NOT THE FILE!
// on linux(debian,ubuntu,alpine):
// Linux version 4.19.121-linuxkit (root@18b3f92ade35) (gcc version 9.2.0 (Alpine 9.2.0)) #1 SMP Thu Jan 21 15:36:34 UTC 2021
// on win git bash, conEmu:
// on Win git bash, conEmu:
// MINGW64_NT-10.0-19042 version 3.1.7-340.x86_64 (@WIN-N0G619FD3UK) (gcc version 9.3.0 (GCC) ) 2020-10-23 13:08 UTC
// on WSL:
// Linux version 4.4.0-19041-Microsoft (Microsoft@Microsoft.com) (gcc version 5.4.0 (GCC) ) #488-Microsoft Mon Sep 01 13:43:00 PST 2020
@ -164,12 +175,13 @@ func detectWSL() bool {
}
wslContents = string(b)
return strings.Contains(wslContents, "Microsoft")
}
detectedWSL = true
}
return strings.Contains(wslContents, "Microsoft")
return false
}
/*
// refer
// https://github.com/Delta456/box-cli-maker/blob/7b5a1ad8a016ce181e7d8b05e24b54ff60b4b38a/detect_unix.go#L27-L45
// detect WSL as it has True Color support
@ -196,19 +208,18 @@ func isWSL() bool {
}
// it gives "Microsoft" for WSL and "microsoft" for WSL 2
// it support True-color
// it supports True-color
content := strings.ToLower(string(wsl))
return strings.Contains(content, "microsoft")
}
*/
/*************************************************************
* helper methods for check env
*************************************************************/
// IsWindows OS env
func IsWindows() bool {
return runtime.GOOS == "windows"
}
func IsWindows() bool { return runtime.GOOS == "windows" }
// IsConsole Determine whether w is one of stderr, stdout, stdin
func IsConsole(w io.Writer) bool {
@ -224,58 +235,52 @@ func IsConsole(w io.Writer) bool {
}
// IsMSys msys(MINGW64) environment, does not necessarily support color
func IsMSys() bool {
// like "MSYSTEM=MINGW64"
if len(os.Getenv("MSYSTEM")) > 0 {
return true
}
return false
}
func IsMSys() bool { /* like "MSYSTEM=MINGW64" */ return len(os.Getenv("MSYSTEM")) > 0 }
// IsSupportColor check current console is support color.
//
// NOTICE: The method will detect terminal info each times,
// if only want get current color level, please direct call SupportColor() or TermColorLevel()
func IsSupportColor() bool {
return IsSupport16Color()
}
//
// if only want to get current color level, please direct call SupportColor() or TermColorLevel()
func IsSupportColor() bool { return IsSupport16Color() }
// IsSupportColor check current console is support color.
// IsSupport16Color check current console is support color.
//
// NOTICE: The method will detect terminal info each times,
// if only want get current color level, please direct call SupportColor() or TermColorLevel()
//
// if only want to get current color level, please direct call SupportColor() or TermColorLevel()
func IsSupport16Color() bool {
level, _ := detectTermColorLevel()
return level > terminfo.ColorLevelNone
return level > LevelNo
}
// IsSupport256Color render check
//
// NOTICE: The method will detect terminal info each times,
// if only want get current color level, please direct call SupportColor() or TermColorLevel()
//
// if only want to get current color level, please direct call SupportColor() or TermColorLevel()
func IsSupport256Color() bool {
level, _ := detectTermColorLevel()
return level > terminfo.ColorLevelBasic
return level > Level16
}
// IsSupportRGBColor check. alias of the IsSupportTrueColor()
//
// NOTICE: The method will detect terminal info each times,
// if only want get current color level, please direct call SupportColor() or TermColorLevel()
func IsSupportRGBColor() bool {
return IsSupportTrueColor()
}
//
// if only want to get current color level, please direct call SupportColor() or TermColorLevel()
func IsSupportRGBColor() bool { return IsSupportTrueColor() }
// IsSupportTrueColor render check.
//
// NOTICE: The method will detect terminal info each times,
// if only want get current color level, please direct call SupportColor() or TermColorLevel()
//
// if only want get current color level, please direct call SupportColor() or TermColorLevel()
//
// ENV:
// "COLORTERM=truecolor"
// "COLORTERM=24bit"
func IsSupportTrueColor() bool {
level, _ := detectTermColorLevel()
return level > terminfo.ColorLevelHundreds
return level > Level256
}

View file

@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
// The method in the file has no effect
@ -8,14 +9,12 @@ package color
import (
"strings"
"syscall"
"github.com/xo/terminfo"
)
// detect special term color support
func detectSpecialTermColor(termVal string) (terminfo.ColorLevel, bool) {
func detectSpecialTermColor(termVal string) (Level, bool) {
if termVal == "" {
return terminfo.ColorLevelNone, false
return LevelNo, false
}
debugf("terminfo check fail - fallback detect color by check TERM value")
@ -23,26 +22,27 @@ func detectSpecialTermColor(termVal string) (terminfo.ColorLevel, bool) {
// on TERM=screen:
// - support 256, not support true-color. test on macOS
if termVal == "screen" {
return terminfo.ColorLevelHundreds, false
return Level256, false
}
if strings.Contains(termVal, "256color") {
return terminfo.ColorLevelHundreds, false
return Level256, false
}
if strings.Contains(termVal, "xterm") {
return terminfo.ColorLevelHundreds, false
return Level256, false
// return terminfo.ColorLevelBasic, false
}
// return terminfo.ColorLevelNone, nil
return terminfo.ColorLevelBasic, false
// return LevelNo, nil
return Level16, false
}
// IsTerminal returns true if the given file descriptor is a terminal.
//
// Usage:
// IsTerminal(os.Stdout.Fd())
//
// IsTerminal(os.Stdout.Fd())
func IsTerminal(fd uintptr) bool {
return fd == uintptr(syscall.Stdout) || fd == uintptr(syscall.Stdin) || fd == uintptr(syscall.Stderr)
}

View file

@ -1,18 +1,20 @@
//go:build windows
// +build windows
// Display color on windows
// refer:
// golang.org/x/sys/windows
// golang.org/x/crypto/ssh/terminal
// https://docs.microsoft.com/en-us/windows/console
package color
// Display color on Windows
//
// refer:
//
// golang.org/x/sys/windows
// golang.org/x/crypto/ssh/terminal
// https://docs.microsoft.com/en-us/windows/console
import (
"os"
"syscall"
"unsafe"
"github.com/xo/terminfo"
"golang.org/x/sys/windows"
)
@ -28,17 +30,15 @@ var (
)
func init() {
if !SupportColor() {
isLikeInCmd = true
// if support color 16+, don't need to enable VTP
if colorLevel > Level16 {
return
}
if !Enable { // disable color
return
}
// if disabled.
if !Enable {
return
}
// if at windows's ConEmu, Cmder, putty ... terminals not need VTP
// if at Windows's ConEmu, Cmder, putty ... terminals not need VTP
// -------- try force enable colors on windows terminal -------
tryEnableVTP(needVTP)
@ -47,7 +47,7 @@ func init() {
// err := getConsoleScreenBufferInfo(uintptr(syscall.Stdout), &defScreenInfo)
}
// try force enable colors on windows terminal
// try force enable colors on Windows terminal
func tryEnableVTP(enable bool) bool {
if !enable {
return false
@ -57,7 +57,7 @@ func tryEnableVTP(enable bool) bool {
initKernel32Proc()
// enable colors on windows terminal
// enable colors on Windows terminal
if tryEnableOnCONOUT() {
return true
}
@ -70,7 +70,7 @@ func initKernel32Proc() {
return
}
// load related windows dll
// load related Windows dll
// https://docs.microsoft.com/en-us/windows/console/setconsolemode
kernel32 = syscall.NewLazyDLL("kernel32.dll")
@ -106,15 +106,15 @@ func tryEnableOnStdout() bool {
}
// Get the Windows Version and Build Number
var (
winVersion, _, buildNumber = windows.RtlGetNtVersionNumbers()
)
var winVersion, _, buildNumber = windows.RtlGetNtVersionNumbers()
// refer
// https://github.com/Delta456/box-cli-maker/blob/7b5a1ad8a016ce181e7d8b05e24b54ff60b4b38a/detect_windows.go#L30-L57
// https://github.com/gookit/color/issues/25#issuecomment-738727917
// detects the Color Level Supported on windows: cmd, powerShell
func detectSpecialTermColor(termVal string) (tl terminfo.ColorLevel, needVTP bool) {
//
// https://github.com/Delta456/box-cli-maker/blob/7b5a1ad8a016ce181e7d8b05e24b54ff60b4b38a/detect_windows.go#L30-L57
// https://github.com/gookit/color/issues/25#issuecomment-738727917
//
// detects the color level supported on Windows: cmd, powerShell
func detectSpecialTermColor(termVal string) (tl Level, needVTP bool) {
if os.Getenv("ConEmuANSI") == "ON" {
debugf("support True Color by ConEmuANSI=ON")
// ConEmuANSI is "ON" for generic ANSI support
@ -122,7 +122,7 @@ func detectSpecialTermColor(termVal string) (tl terminfo.ColorLevel, needVTP boo
// I am just assuming that people wouldn't have disabled it
// Even if it is not enabled then ConEmu will auto round off
// accordingly
return terminfo.ColorLevelMillions, false
return LevelRgb, false
}
// Before Windows 10 Build Number 10586, console never supported ANSI Colors
@ -130,33 +130,33 @@ func detectSpecialTermColor(termVal string) (tl terminfo.ColorLevel, needVTP boo
// Detect if using ANSICON on older systems
if os.Getenv("ANSICON") != "" {
conVersion := os.Getenv("ANSICON_VER")
// 8 bit Colors were only supported after v1.81 release
// 8-bit Colors were only supported after v1.81 release
if conVersion >= "181" {
return terminfo.ColorLevelHundreds, false
return Level256, false
}
return terminfo.ColorLevelBasic, false
return Level16, false
}
return terminfo.ColorLevelNone, false
return LevelNo, false
}
// True Color is not available before build 14931 so fallback to 8 bit color.
// True Color is not available before build 14931 so fallback to 8-bit color.
if buildNumber < 14931 {
return terminfo.ColorLevelHundreds, true
return Level256, true
}
// Windows 10 build 14931 is the first release that supports 16m/TrueColor
debugf("support True Color on windows version is >= build 14931")
return terminfo.ColorLevelMillions, true
return LevelRgb, true
}
/*************************************************************
* render full color code on windows(8,16,24bit color)
* render full color code on Windows(8,16,24bit color)
*************************************************************/
// docs https://docs.microsoft.com/zh-cn/windows/console/getconsolemode#parameters
const (
// equals to docs page's ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
// EnableVirtualTerminalProcessingMode equals to docs page's ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
EnableVirtualTerminalProcessingMode uint32 = 0x4
)
@ -166,9 +166,10 @@ const (
// doc https://docs.microsoft.com/zh-cn/windows/console/console-virtual-terminal-sequences#samples
//
// Usage:
// err := EnableVirtualTerminalProcessing(syscall.Stdout, true)
// // support print color text
// err = EnableVirtualTerminalProcessing(syscall.Stdout, false)
//
// err := EnableVirtualTerminalProcessing(syscall.Stdout, true)
// // support print color text
// err = EnableVirtualTerminalProcessing(syscall.Stdout, false)
func EnableVirtualTerminalProcessing(stream syscall.Handle, enable bool) error {
var mode uint32
// Check if it is currently in the terminal
@ -216,7 +217,7 @@ func EnableVirtualTerminalProcessing(stream syscall.Handle, enable bool) error {
// }
/*************************************************************
* render simple color code on windows
* render simple color code on Windows
*************************************************************/
// IsTty returns true if the given file descriptor is a terminal.
@ -224,20 +225,21 @@ func IsTty(fd uintptr) bool {
initKernel32Proc()
var st uint32
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
r, _, e := syscall.SyscallN(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
}
// IsTerminal returns true if the given file descriptor is a terminal.
//
// Usage:
// fd := os.Stdout.Fd()
// fd := uintptr(syscall.Stdout) // for windows
// IsTerminal(fd)
//
// fd := os.Stdout.Fd()
// fd := uintptr(syscall.Stdout) // for Windows
// IsTerminal(fd)
func IsTerminal(fd uintptr) bool {
initKernel32Proc()
var st uint32
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
r, _, e := syscall.SyscallN(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
}

25
vendor/github.com/gookit/color/index.html generated vendored Normal file
View file

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta charset="UTF-8">
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify/themes/vue.css">
<title>Color - A command-line color library with true color support, universal API methods and Windows support.</title>
</head>
<body>
<div id="app"></div>
<script>
window.$docsify = {
repo: 'gookit/color',
maxLevel: 3,
// 加载 _navbar.md
// loadNavbar: true,
loadNavbar: '_examples/navbar.md',
// 加载 _sidebar.md
// loadSidebar: true,
}
</script>
<script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></script>
</body>
</html>

View file

@ -1,122 +0,0 @@
package color
import "fmt"
/*************************************************************
* 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{Code: "32;45;3"}
// p.Print("message")
type Printer struct {
// NoColor disable color.
NoColor bool
// Code color code string. eg "32;45;3"
Code string
}
// NewPrinter instance
func NewPrinter(colorCode string) *Printer {
return &Printer{Code: colorCode}
}
// String returns color code string. eg: "32;45;3"
func (p *Printer) String() string {
// panic("implement me")
return p.Code
}
// 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{}) {
doPrintV2(p.String(), fmt.Sprint(a...))
}
// Printf format and rendering colored messages
func (p *Printer) Printf(format string, a ...interface{}) {
doPrintV2(p.String(), fmt.Sprintf(format, a...))
}
// Println rendering colored messages with newline
func (p *Printer) Println(a ...interface{}) {
doPrintlnV2(p.Code, a)
}
// IsEmpty color code
func (p *Printer) IsEmpty() bool {
return p.Code == ""
}
/*************************************************************
* SimplePrinter struct
*************************************************************/
// SimplePrinter use for quick use color print on inject to struct
type SimplePrinter struct{}
// Print message
func (s *SimplePrinter) Print(v ...interface{}) {
Print(v...)
}
// Printf message
func (s *SimplePrinter) Printf(format string, v ...interface{}) {
Printf(format, v...)
}
// Println message
func (s *SimplePrinter) Println(v ...interface{}) {
Println(v...)
}
// Infof message
func (s *SimplePrinter) Infof(format string, a ...interface{}) {
Info.Printf(format, a...)
}
// Infoln message
func (s *SimplePrinter) Infoln(a ...interface{}) {
Info.Println(a...)
}
// Warnf message
func (s *SimplePrinter) Warnf(format string, a ...interface{}) {
Warn.Printf(format, a...)
}
// Warnln message
func (s *SimplePrinter) Warnln(a ...interface{}) {
Warn.Println(a...)
}
// Errorf message
func (s *SimplePrinter) Errorf(format string, a ...interface{}) {
Error.Printf(format, a...)
}
// Errorln message
func (s *SimplePrinter) Errorln(a ...interface{}) {
Error.Println(a...)
}

View file

@ -1,109 +1,226 @@
package color
import "fmt"
/*************************************************************
* quick use color print message
* region Message Printer
*************************************************************/
// PrinterFace interface
type PrinterFace interface {
fmt.Stringer
Sprint(a ...any) string
Sprintf(format string, a ...any) string
Print(a ...any)
Printf(format string, a ...any)
Println(a ...any)
}
// Printer a generic color message printer.
//
// Usage:
//
// p := &Printer{Code: "32;45;3"}
// p.Print("message")
type Printer struct {
// NoColor disable color.
NoColor bool
// Code color code string. eg "32;45;3"
Code string
}
// NewPrinter instance
func NewPrinter(colorCode string) *Printer {
return &Printer{Code: colorCode}
}
// String returns color code string. eg: "32;45;3"
func (p *Printer) String() string {
// panic("implement me")
return p.Code
}
// Sprint returns rendering colored messages
func (p *Printer) Sprint(a ...any) string {
return RenderCode(p.String(), a...)
}
// Sprintf returns format and rendering colored messages
func (p *Printer) Sprintf(format string, a ...any) string {
return RenderString(p.String(), fmt.Sprintf(format, a...))
}
// Print rendering colored messages
func (p *Printer) Print(a ...any) {
doPrintV2(p.String(), fmt.Sprint(a...))
}
// Printf format and rendering colored messages
func (p *Printer) Printf(format string, a ...any) {
doPrintV2(p.String(), fmt.Sprintf(format, a...))
}
// Println rendering colored messages with newline
func (p *Printer) Println(a ...any) {
doPrintlnV2(p.Code, a)
}
// IsEmpty color code
func (p *Printer) IsEmpty() bool {
return p.Code == ""
}
/*************************************************************
* region SimplePrinter
*************************************************************/
// SimplePrinter use for quick use color print on inject to struct
type SimplePrinter struct{}
// Print message
func (s *SimplePrinter) Print(v ...any) { Print(v...) }
// Printf message
func (s *SimplePrinter) Printf(format string, v ...any) { Printf(format, v...) }
// Println message
func (s *SimplePrinter) Println(v ...any) {
Println(v...)
}
// Successf message
func (s *SimplePrinter) Successf(format string, a ...any) { Success.Printf(format, a...) }
// Successln message
func (s *SimplePrinter) Successln(a ...any) { Success.Println(a...) }
// Infof message
func (s *SimplePrinter) Infof(format string, a ...any) {
Info.Printf(format, a...)
}
// Infoln message
func (s *SimplePrinter) Infoln(a ...any) { Info.Println(a...) }
// Warnf message
func (s *SimplePrinter) Warnf(format string, a ...any) {
Warn.Printf(format, a...)
}
// Warnln message
func (s *SimplePrinter) Warnln(a ...any) { Warn.Println(a...) }
// Errorf message
func (s *SimplePrinter) Errorf(format string, a ...any) {
Error.Printf(format, a...)
}
// Errorln message
func (s *SimplePrinter) Errorln(a ...any) { Error.Println(a...) }
/*************************************************************
* region quick start
*************************************************************/
// Redp print message with Red color
func Redp(a ...interface{}) {
Red.Print(a...)
}
func Redp(a ...any) { Red.Print(a...) }
// Redf print message with Red color
func Redf(format string, a ...any) { Red.Printf(format, a...) }
// Redln print message line with Red color
func Redln(a ...interface{}) {
Red.Println(a...)
}
func Redln(a ...any) { Red.Println(a...) }
// Bluep print message with Blue color
func Bluep(a ...interface{}) {
Blue.Print(a...)
}
func Bluep(a ...any) { Blue.Print(a...) }
// Bluef print message with Blue color
func Bluef(format string, a ...any) { Blue.Printf(format, a...) }
// Blueln print message line with Blue color
func Blueln(a ...interface{}) {
Blue.Println(a...)
}
func Blueln(a ...any) { Blue.Println(a...) }
// Cyanp print message with Cyan color
func Cyanp(a ...interface{}) {
Cyan.Print(a...)
}
func Cyanp(a ...any) { Cyan.Print(a...) }
// Cyanf print message with Cyan color
func Cyanf(format string, a ...any) { Cyan.Printf(format, a...) }
// Cyanln print message line with Cyan color
func Cyanln(a ...interface{}) {
Cyan.Println(a...)
}
func Cyanln(a ...any) { Cyan.Println(a...) }
// Grayp print message with Gray color
func Grayp(a ...interface{}) {
Gray.Print(a...)
}
func Grayp(a ...any) { Gray.Print(a...) }
// Grayf print message with Gray color
func Grayf(format string, a ...any) { Gray.Printf(format, a...) }
// Grayln print message line with Gray color
func Grayln(a ...interface{}) {
Gray.Println(a...)
}
func Grayln(a ...any) { Gray.Println(a...) }
// Greenp print message with Green color
func Greenp(a ...interface{}) {
Green.Print(a...)
}
func Greenp(a ...any) { Green.Print(a...) }
// Greenf print message with Green color
func Greenf(format string, a ...any) { Green.Printf(format, a...) }
// Greenln print message line with Green color
func Greenln(a ...interface{}) {
Green.Println(a...)
}
func Greenln(a ...any) { Green.Println(a...) }
// Yellowp print message with Yellow color
func Yellowp(a ...interface{}) {
Yellow.Print(a...)
}
func Yellowp(a ...any) { Yellow.Print(a...) }
// Yellowf print message with Yellow color
func Yellowf(format string, a ...any) { Yellow.Printf(format, a...) }
// Yellowln print message line with Yellow color
func Yellowln(a ...interface{}) {
Yellow.Println(a...)
}
func Yellowln(a ...any) { Yellow.Println(a...) }
// Magentap print message with Magenta color
func Magentap(a ...interface{}) {
Magenta.Print(a...)
}
func Magentap(a ...any) { Magenta.Print(a...) }
// Magentaf print message with Magenta color
func Magentaf(format string, a ...any) { Magenta.Printf(format, a...) }
// Magentaln print message line with Magenta color
func Magentaln(a ...interface{}) {
Magenta.Println(a...)
}
func Magentaln(a ...any) { Magenta.Println(a...) }
/*************************************************************
* quick use style print message
*************************************************************/
// Infop print message with Info color
func Infop(a ...any) { Info.Print(a...) }
// Infof print message with Info style
func Infof(format string, a ...interface{}) {
Info.Printf(format, a...)
}
func Infof(format string, a ...any) { Info.Printf(format, a...) }
// Infoln print message with Info style
func Infoln(a ...interface{}) {
Info.Println(a...)
}
func Infoln(a ...any) { Info.Println(a...) }
// Successp print message with success color
func Successp(a ...any) { Success.Print(a...) }
// Successf print message with success style
func Successf(format string, a ...any) { Success.Printf(format, a...) }
// Successln print message with success style
func Successln(a ...any) { Success.Println(a...) }
// Errorp print message with Error color
func Errorp(a ...any) { Error.Print(a...) }
// Errorf print message with Error style
func Errorf(format string, a ...interface{}) {
Error.Printf(format, a...)
}
func Errorf(format string, a ...any) { Error.Printf(format, a...) }
// Errorln print message with Error style
func Errorln(a ...interface{}) {
Error.Println(a...)
}
func Errorln(a ...any) { Error.Println(a...) }
// Warnp print message with Warn color
func Warnp(a ...any) { Warn.Print(a...) }
// Warnf print message with Warn style
func Warnf(format string, a ...interface{}) {
Warn.Printf(format, a...)
}
func Warnf(format string, a ...any) { Warn.Printf(format, a...) }
// Warnln print message with Warn style
func Warnln(a ...interface{}) {
Warn.Println(a...)
}
func Warnln(a ...any) { Warn.Println(a...) }

View file

@ -12,85 +12,75 @@ import (
// Style a 16 color style. can add: fg color, bg color, color options
//
// Example:
// color.Style{color.FgGreen}.Print("message")
//
// color.Style{color.FgGreen}.Print("message")
type Style []Color
// New create a custom style
//
// Usage:
//
// color.New(color.FgGreen).Print("message")
// equals to:
// color.Style{color.FgGreen}.Print("message")
func New(colors ...Color) Style {
return colors
}
func New(colors ...Color) Style { return colors }
// Save to global styles map
func (s Style) Save(name string) {
AddStyle(name, s)
}
func (s Style) Save(name string) { AddStyle(name, s) }
// Add to global styles map
func (s *Style) Add(cs ...Color) {
*s = append(*s, cs...)
}
// Render render text
// Render colored text
//
// Usage:
// color.New(color.FgGreen).Render("text")
// color.New(color.FgGreen, color.BgBlack, color.OpBold).Render("text")
func (s Style) Render(a ...interface{}) string {
return RenderCode(s.String(), a...)
}
//
// color.New(color.FgGreen).Render("text")
// color.New(color.FgGreen, color.BgBlack, color.OpBold).Render("text")
func (s Style) Render(a ...any) string { return RenderCode(s.String(), a...) }
// Renderln render text line.
// Renderln render text with newline.
// like Println, will add spaces for each argument
//
// Usage:
// color.New(color.FgGreen).Renderln("text", "more")
// color.New(color.FgGreen, color.BgBlack, color.OpBold).Render("text", "more")
func (s Style) Renderln(a ...interface{}) string {
return RenderWithSpaces(s.String(), a...)
}
//
// color.New(color.FgGreen).Renderln("text", "more")
// color.New(color.FgGreen, color.BgBlack, color.OpBold).Render("text", "more")
func (s Style) Renderln(a ...any) string { return RenderWithSpaces(s.String(), a...) }
// Sprint is alias of the 'Render'
func (s Style) Sprint(a ...interface{}) string {
return RenderCode(s.String(), a...)
}
func (s Style) Sprint(a ...any) string { return RenderCode(s.String(), a...) }
// Sprintf format and render message.
func (s Style) Sprintf(format string, a ...interface{}) string {
func (s Style) Sprintf(format string, a ...any) string {
return RenderString(s.String(), fmt.Sprintf(format, a...))
}
// Print render and Print text
func (s Style) Print(a ...interface{}) {
func (s Style) Print(a ...any) {
doPrintV2(s.String(), fmt.Sprint(a...))
}
// Printf render and print text
func (s Style) Printf(format string, a ...interface{}) {
func (s Style) Printf(format string, a ...any) {
doPrintV2(s.Code(), fmt.Sprintf(format, a...))
}
// Println render and print text line
func (s Style) Println(a ...interface{}) {
func (s Style) Println(a ...any) {
doPrintlnV2(s.String(), a)
}
// Code convert to code string. returns like "32;45;3"
func (s Style) Code() string {
return s.String()
}
func (s Style) Code() string { return s.String() }
// String convert to code string. returns like "32;45;3"
func (s Style) String() string {
return Colors2code(s...)
}
func (s Style) String() string { return Colors2code(s...) }
// IsEmpty style
func (s Style) IsEmpty() bool {
return len(s) == 0
}
func (s Style) IsEmpty() bool { return len(s) == 0 }
/*************************************************************
* Theme(extended Style)
@ -110,27 +100,24 @@ func NewTheme(name string, style Style) *Theme {
}
// Save to themes map
func (t *Theme) Save() {
AddTheme(t.Name, t.Style)
}
func (t *Theme) Save() { AddTheme(t.Name, t.Style) }
// Tips use name as title, only apply style for name
func (t *Theme) Tips(format string, a ...interface{}) {
func (t *Theme) Tips(format string, a ...any) {
// only apply style for name
t.Print(strings.ToUpper(t.Name) + ": ")
Printf(format+"\n", a...)
prefix := RenderString(t.Code(), strings.ToUpper(t.Name)+": ")
Printf(prefix+format+"\n", a...)
}
// Prompt use name as title, and apply style for message
func (t *Theme) Prompt(format string, a ...interface{}) {
func (t *Theme) Prompt(format string, a ...any) {
title := strings.ToUpper(t.Name) + ":"
t.Println(title, fmt.Sprintf(format, a...))
}
// Block like Prompt, but will wrap a empty line
func (t *Theme) Block(format string, a ...interface{}) {
func (t *Theme) Block(format string, a ...any) {
title := strings.ToUpper(t.Name) + ":\n"
t.Println(title, fmt.Sprintf(format, a...))
}
@ -140,10 +127,11 @@ func (t *Theme) Block(format string, a ...interface{}) {
// internal themes(like bootstrap style)
// Usage:
// color.Info.Print("message")
// color.Info.Printf("a %s message", "test")
// color.Warn.Println("message")
// color.Error.Println("message")
//
// color.Info.Print("message")
// color.Info.Printf("a %s message", "test")
// color.Warn.Println("message")
// color.Error.Println("message")
var (
// Info color style
Info = &Theme{"info", Style{OpReset, FgGreen}}
@ -175,7 +163,8 @@ var (
// Themes internal defined themes.
// Usage:
// color.Themes["info"].Println("message")
//
// color.Themes["info"].Println("message")
var Themes = map[string]*Theme{
"info": Info,
"note": Note,
@ -201,9 +190,7 @@ func AddTheme(name string, style Style) {
}
// GetTheme get defined theme by name
func GetTheme(name string) *Theme {
return Themes[name]
}
func GetTheme(name string) *Theme { return Themes[name] }
/*************************************************************
* internal styles
@ -211,7 +198,8 @@ func GetTheme(name string) *Theme {
// Styles internal defined styles, like bootstrap styles.
// Usage:
// color.Styles["info"].Println("message")
//
// color.Styles["info"].Println("message")
var Styles = map[string]Style{
"info": {OpReset, FgGreen},
"note": {OpBold, FgLightCyan},
@ -237,9 +225,7 @@ var styleAliases = map[string]string{
}
// AddStyle add a style
func AddStyle(name string, s Style) {
Styles[name] = s
}
func AddStyle(name string, s Style) { Styles[name] = s }
// GetStyle get defined style by name
func GetStyle(name string) Style {
@ -270,7 +256,7 @@ func NewScheme(name string, styles map[string]Style) *Scheme {
return &Scheme{Name: name, Styles: styles}
}
// NewDefaultScheme create an defuault color Scheme
// NewDefaultScheme create a default color Scheme
func NewDefaultScheme(name string) *Scheme {
return NewScheme(name, map[string]Style{
"info": {OpReset, FgGreen},
@ -280,36 +266,34 @@ func NewDefaultScheme(name string) *Scheme {
}
// Style get by name
func (s *Scheme) Style(name string) Style {
return s.Styles[name]
}
func (s *Scheme) Style(name string) Style { return s.Styles[name] }
// Infof message print
func (s *Scheme) Infof(format string, a ...interface{}) {
func (s *Scheme) Infof(format string, a ...any) {
s.Styles["info"].Printf(format, a...)
}
// Infoln message print
func (s *Scheme) Infoln(v ...interface{}) {
func (s *Scheme) Infoln(v ...any) {
s.Styles["info"].Println(v...)
}
// Warnf message print
func (s *Scheme) Warnf(format string, a ...interface{}) {
func (s *Scheme) Warnf(format string, a ...any) {
s.Styles["warn"].Printf(format, a...)
}
// Warnln message print
func (s *Scheme) Warnln(v ...interface{}) {
func (s *Scheme) Warnln(v ...any) {
s.Styles["warn"].Println(v...)
}
// Errorf message print
func (s *Scheme) Errorf(format string, a ...interface{}) {
func (s *Scheme) Errorf(format string, a ...any) {
s.Styles["error"].Printf(format, a...)
}
// Errorln message print
func (s *Scheme) Errorln(v ...interface{}) {
func (s *Scheme) Errorln(v ...any) {
s.Styles["error"].Println(v...)
}

View file

@ -32,38 +32,31 @@ func ResetTerminal() error {
*************************************************************/
// Print render color tag and print messages
func Print(a ...interface{}) {
func Print(a ...any) {
Fprint(output, a...)
}
// Printf format and print messages
func Printf(format string, a ...interface{}) {
func Printf(format string, a ...any) {
Fprintf(output, format, a...)
}
// Println messages with new line
func Println(a ...interface{}) {
func Println(a ...any) {
Fprintln(output, a...)
}
// Fprint print rendered messages to writer
//
// Notice: will ignore print error
func Fprint(w io.Writer, a ...interface{}) {
func Fprint(w io.Writer, a ...any) {
_, err := fmt.Fprint(w, Render(a...))
saveInternalError(err)
// if isLikeInCmd {
// renderColorCodeOnCmd(func() {
// _, _ = fmt.Fprint(w, Render(a...))
// })
// } else {
// _, _ = fmt.Fprint(w, Render(a...))
// }
}
// Fprintf print format and rendered messages to writer.
// Notice: will ignore print error
func Fprintf(w io.Writer, format string, a ...interface{}) {
func Fprintf(w io.Writer, format string, a ...any) {
str := fmt.Sprintf(format, a...)
_, err := fmt.Fprint(w, ReplaceTag(str))
saveInternalError(err)
@ -71,53 +64,58 @@ func Fprintf(w io.Writer, format string, a ...interface{}) {
// Fprintln print rendered messages line to writer
// Notice: will ignore print error
func Fprintln(w io.Writer, a ...interface{}) {
str := formatArgsForPrintln(a)
func Fprintln(w io.Writer, a ...any) {
str := formatLikePrintln(a)
_, err := fmt.Fprintln(w, ReplaceTag(str))
saveInternalError(err)
}
// Lprint passes colored messages to a log.Logger for printing.
// Notice: should be goroutine safe
func Lprint(l *log.Logger, a ...interface{}) {
func Lprint(l *log.Logger, a ...any) {
l.Print(Render(a...))
}
// Render parse color tags, return rendered string.
//
// Usage:
//
// text := Render("<info>hello</> <cyan>world</>!")
// fmt.Println(text)
func Render(a ...interface{}) string {
func Render(a ...any) string {
if len(a) == 0 {
return ""
}
return ReplaceTag(fmt.Sprint(a...))
}
// Sprint parse color tags, return rendered string
func Sprint(a ...interface{}) string {
func Sprint(a ...any) string {
if len(a) == 0 {
return ""
}
return ReplaceTag(fmt.Sprint(a...))
}
// Sprintf format and return rendered string
func Sprintf(format string, a ...interface{}) string {
func Sprintf(format string, a ...any) string {
return ReplaceTag(fmt.Sprintf(format, a...))
}
// String alias of the ReplaceTag
func String(s string) string {
return ReplaceTag(s)
}
func String(s string) string { return ReplaceTag(s) }
// Text alias of the ReplaceTag
func Text(s string) string {
return ReplaceTag(s)
}
func Text(s string) string { return ReplaceTag(s) }
// Uint8sToInts convert []uint8 to []int
// func Uint8sToInts(u8s []uint8 ) []int {
// ints := make([]int, len(u8s))
// for i, u8 := range u8s {
// ints[i] = int(u8)
// }
// return ints
// }
/*************************************************************
* helper methods for print
@ -127,29 +125,26 @@ func Text(s string) string {
func doPrintV2(code, str string) {
_, err := fmt.Fprint(output, RenderString(code, str))
saveInternalError(err)
// if isLikeInCmd {
// renderColorCodeOnCmd(func() {
// _, _ = fmt.Fprint(output, RenderString(code, str))
// })
// } else {
// _, _ = fmt.Fprint(output, RenderString(code, str))
// }
}
// new implementation, support render full color code on pwsh.exe, cmd.exe
func doPrintlnV2(code string, args []interface{}) {
str := formatArgsForPrintln(args)
func doPrintlnV2(code string, args []any) {
str := formatLikePrintln(args)
_, err := fmt.Fprintln(output, RenderString(code, str))
saveInternalError(err)
}
// if use Println, will add spaces for each arg
func formatArgsForPrintln(args []interface{}) (message string) {
// use Println, will add spaces for each arg
func formatLikePrintln(args []any) (message string) {
if ln := len(args); ln == 0 {
message = ""
} else if ln == 1 {
message = fmt.Sprint(args[0])
// Single argument - avoid fmt.Sprint overhead
if str, ok := args[0].(string); ok {
message = str
} else {
message = fmt.Sprint(args[0])
}
} else {
message = fmt.Sprintln(args...)
// clear last "\n"
@ -167,14 +162,17 @@ func formatArgsForPrintln(args []interface{}) (message string) {
// return debugMode == "on"
// }
func debugf(f string, v ...interface{}) {
func debugf(f string, v ...any) {
if debugMode {
fmt.Print("COLOR_DEBUG: ")
fmt.Printf(f, v...)
fmt.Println()
fmt.Printf("COLOR_DEBUG: "+f+"\n", v...)
}
}
// equals: return ok ? val1 : val2
func isValidUint8(val int) bool {
return val >= 0 && val < 256
}
// equals: return ok ? val1 : val2
func compareVal(ok bool, val1, val2 uint8) uint8 {
if ok {
@ -183,6 +181,14 @@ func compareVal(ok bool, val1, val2 uint8) uint8 {
return val2
}
// equals: return ok ? val1 : val2
func compareF64(ok bool, val1, val2 float64) float64 {
if ok {
return val1
}
return val2
}
func saveInternalError(err error) {
if err != nil {
debugf("inner error: %s", err.Error())

4
vendor/modules.txt vendored
View file

@ -84,8 +84,8 @@ github.com/go-errors/errors
github.com/go-logfmt/logfmt
# github.com/google/go-cmp v0.7.0
## explicit; go 1.21
# github.com/gookit/color v1.4.2
## explicit; go 1.12
# github.com/gookit/color v1.6.0
## explicit; go 1.18
github.com/gookit/color
# github.com/hpcloud/tail v1.0.0
## explicit