1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
|
/*
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.
*/
package color
import (
"fmt"
"io"
"os"
"regexp"
"strings"
"github.com/xo/terminfo"
)
// color render templates
//
// ESC 操作的表示:
//
// "\033"(Octal 8进制) = "\x1b"(Hexadecimal 16进制) = 27 (10进制)
const (
// 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"
)
// CodeExpr regex to clear color codes eg "\033[1;36mText\x1b[0m"
const CodeExpr = `\033\[[\d;?]+m`
var (
// Enable switch color render and display
//
// NOTICE:
// if ENV: NO_COLOR is not empty, will disable color render.
Enable = os.Getenv("NO_COLOR") == ""
// RenderTag render HTML tag on call color.Xprint, color.PrintX
RenderTag = true
// debug mode for development.
//
// set env:
// COLOR_DEBUG_MODE=on
// or:
// COLOR_DEBUG_MODE=on go run ./_examples/envcheck.go
debugMode = os.Getenv("COLOR_DEBUG_MODE") == "on"
// inner errors record on detect color level
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 False.
isLikeInCmd bool
// the color support level for current terminal
// 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 Get the currently supported color level
func TermColorLevel() Level {
return colorLevel
}
// SupportColor Whether the current environment supports color output
func SupportColor() bool {
return colorLevel > terminfo.ColorLevelNone
}
// 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 > terminfo.ColorLevelBasic
}
// SupportTrueColor Whether the current environment supports (RGB)True-color output
func SupportTrueColor() bool {
return colorLevel > terminfo.ColorLevelHundreds
}
/*************************************************************
* global settings
*************************************************************/
// Set console color attributes
func Set(colors ...Color) (int, error) {
code := Colors2code(colors...)
err := SetTerminal(code)
return 0, err
}
// Reset reset console color attributes
func Reset() (int, error) {
err := ResetTerminal()
return 0, err
}
// Disable disable color output
func Disable() bool {
oldVal := Enable
Enable = false
return oldVal
}
// NotRenderTag on call color.Xprint, color.PrintX
func NotRenderTag() {
RenderTag = false
}
// SetOutput set default colored text output
func SetOutput(w io.Writer) {
output = w
}
// ResetOutput reset output
func ResetOutput() {
output = os.Stdout
}
// ResetOptions reset all package option setting
func ResetOptions() {
RenderTag = true
Enable = true
output = os.Stdout
}
// ForceSetColorLevel force open color render
func ForceSetColorLevel(level terminfo.ColorLevel) terminfo.ColorLevel {
oldLevelVal := colorLevel
colorLevel = level
return oldLevelVal
}
// ForceColor force open color render
func ForceColor() terminfo.ColorLevel {
return ForceOpenColor()
}
// ForceOpenColor force open color render
func ForceOpenColor() terminfo.ColorLevel {
// TODO should set level to ?
return ForceSetColorLevel(terminfo.ColorLevelMillions)
}
// IsLikeInCmd check result
//
// Deprecated: please don't use
func IsLikeInCmd() bool {
return isLikeInCmd
}
// InnerErrs info
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 ...any) string {
var message string
if ln := len(args); ln == 0 {
return ""
}
message = fmt.Sprint(args...)
if len(code) == 0 {
return message
}
// disabled OR not support color
if !Enable || !SupportColor() {
return ClearCode(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 ...any) string {
msg := formatArgsForPrintln(args)
if len(code) == 0 {
return msg
}
// disabled OR not support color
if !Enable || !SupportColor() {
return ClearCode(msg)
}
return StartSet + code + "m" + msg + ResetSet
}
// RenderString render a string with color code.
//
// Usage:
//
// msg := RenderString("3;32;45", "a message")
func RenderString(code string, str string) string {
if len(code) == 0 || str == "" {
return str
}
// disabled OR not support color
if !Enable || !SupportColor() {
return ClearCode(str)
}
// return fmt.Sprintf(FullColorTpl, code, str)
return StartSet + code + "m" + str + ResetSet
}
// ClearCode clear color codes.
//
// eg:
//
// "\033[36;1mText\x1b[0m" -> "Text"
func ClearCode(str string) string {
if !strings.Contains(str, CodeSuffix) {
return str
}
return codeRegex.ReplaceAllString(str, "")
}
|