1package color
2
3import (
4	"fmt"
5	"strconv"
6	"strings"
7)
8
9/*
10from wikipedia, 256 color:
11   ESC[ … 38;5;<n> … m选择前景色
12   ESC[ … 48;5;<n> … m选择背景色
13     0-  7:标准颜色(同 ESC[30–37m)
14     8- 15:高强度颜色(同 ESC[90–97m)
15    16-231:6 × 6 × 6 立方(216色): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
16   232-255:从黑到白的24阶灰度色
17*/
18
19// tpl for 8 bit 256 color(`2^8`)
20//
21// format:
22// 	ESC[ … 38;5;<n> … m // 选择前景色
23//  ESC[ … 48;5;<n> … m // 选择背景色
24//
25// example:
26//  fg "\x1b[38;5;242m"
27//  bg "\x1b[48;5;208m"
28//  both "\x1b[38;5;242;48;5;208m"
29//
30// links:
31// 	https://zh.wikipedia.org/wiki/ANSI%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97#8
32const (
33	TplFg256 = "38;5;%d"
34	TplBg256 = "48;5;%d"
35	Fg256Pfx = "38;5;"
36	Bg256Pfx = "48;5;"
37)
38
39/*************************************************************
40 * 8bit(256) Color: Bit8Color Color256
41 *************************************************************/
42
43// Color256 256 color (8 bit), uint8 range at 0 - 255
44//
45// 颜色值使用10进制和16进制都可 0x98 = 152
46//
47// The color consists of two uint8:
48// 	0: color value
49// 	1: color type; Fg=0, Bg=1, >1: unset value
50//
51// example:
52// 	fg color: [152, 0]
53//  bg color: [152, 1]
54//
55// NOTICE: now support 256 color on windows CMD, PowerShell
56// lint warn - Name starts with package name
57type Color256 [2]uint8
58type Bit8Color = Color256 // alias
59
60var emptyC256 = Color256{1: 99}
61
62// Bit8 create a color256
63func Bit8(val uint8, isBg ...bool) Color256 {
64	return C256(val, isBg...)
65}
66
67// C256 create a color256
68func C256(val uint8, isBg ...bool) Color256 {
69	bc := Color256{val}
70
71	// mark is bg color
72	if len(isBg) > 0 && isBg[0] {
73		bc[1] = AsBg
74	}
75
76	return bc
77}
78
79// Set terminal by 256 color code
80func (c Color256) Set() error {
81	return SetTerminal(c.String())
82}
83
84// Reset terminal. alias of the ResetTerminal()
85func (c Color256) Reset() error {
86	return ResetTerminal()
87}
88
89// Print print message
90func (c Color256) Print(a ...interface{}) {
91	doPrintV2(c.String(), fmt.Sprint(a...))
92}
93
94// Printf format and print message
95func (c Color256) Printf(format string, a ...interface{}) {
96	doPrintV2(c.String(), fmt.Sprintf(format, a...))
97}
98
99// Println print message with newline
100func (c Color256) Println(a ...interface{}) {
101	doPrintlnV2(c.String(), a)
102}
103
104// Sprint returns rendered message
105func (c Color256) Sprint(a ...interface{}) string {
106	return RenderCode(c.String(), a...)
107}
108
109// Sprintf returns format and rendered message
110func (c Color256) Sprintf(format string, a ...interface{}) string {
111	return RenderString(c.String(), fmt.Sprintf(format, a...))
112}
113
114// C16 convert color-256 to 16 color.
115func (c Color256) C16() Color {
116	return c.Basic()
117}
118
119// Basic convert color-256 to basic 16 color.
120func (c Color256) Basic() Color {
121	return Color(c[0]) // TODO
122}
123
124// RGB convert color-256 to RGB color.
125func (c Color256) RGB() RGBColor {
126	return RGBFromSlice(C256ToRgb(c[0]), c[1] == AsBg)
127}
128
129// RGBColor convert color-256 to RGB color.
130func (c Color256) RGBColor() RGBColor {
131	return c.RGB()
132}
133
134// Value return color value
135func (c Color256) Value() uint8 {
136	return c[0]
137}
138
139// Code convert to color code string. eg: "12"
140func (c Color256) Code() string {
141	return strconv.Itoa(int(c[0]))
142}
143
144// FullCode convert to color code string with prefix. eg: "38;5;12"
145func (c Color256) FullCode() string {
146	return c.String()
147}
148
149// String convert to color code string with prefix. eg: "38;5;12"
150func (c Color256) String() string {
151	if c[1] == AsFg { // 0 is Fg
152		// return fmt.Sprintf(TplFg256, c[0])
153		return Fg256Pfx + strconv.Itoa(int(c[0]))
154	}
155
156	if c[1] == AsBg { // 1 is Bg
157		// return fmt.Sprintf(TplBg256, c[0])
158		return Bg256Pfx + strconv.Itoa(int(c[0]))
159	}
160
161	return "" // empty
162}
163
164// IsFg color
165func (c Color256) IsFg() bool {
166	return c[1] == AsFg
167}
168
169// ToFg 256 color
170func (c Color256) ToFg() Color256 {
171	c[1] = AsFg
172	return c
173}
174
175// IsBg color
176func (c Color256) IsBg() bool {
177	return c[1] == AsBg
178}
179
180// ToBg 256 color
181func (c Color256) ToBg() Color256 {
182	c[1] = AsBg
183	return c
184}
185
186// IsEmpty value
187func (c Color256) IsEmpty() bool {
188	return c[1] > 1
189}
190
191/*************************************************************
192 * 8bit(256) Style
193 *************************************************************/
194
195// Style256 definition
196//
197// 前/背景色
198// 都是由两位uint8组成, 第一位是色彩值;
199// 第二位与 Bit8Color 不一样的是,在这里表示是否设置了值 0 未设置 !=0 已设置
200type Style256 struct {
201	// p Printer
202
203	// Name of the style
204	Name string
205	// color options of the style
206	opts Opts
207	// fg and bg color
208	fg, bg Color256
209}
210
211// S256 create a color256 style
212// Usage:
213// 	s := color.S256()
214// 	s := color.S256(132) // fg
215// 	s := color.S256(132, 203) // fg and bg
216func S256(fgAndBg ...uint8) *Style256 {
217	s := &Style256{}
218	vl := len(fgAndBg)
219	if vl > 0 { // with fg
220		s.fg = Color256{fgAndBg[0], 1}
221
222		if vl > 1 { // and with bg
223			s.bg = Color256{fgAndBg[1], 1}
224		}
225	}
226
227	return s
228}
229
230// Set fg and bg color value, can also with color options
231func (s *Style256) Set(fgVal, bgVal uint8, opts ...Color) *Style256 {
232	s.fg = Color256{fgVal, 1}
233	s.bg = Color256{bgVal, 1}
234	s.opts.Add(opts...)
235	return s
236}
237
238// SetBg set bg color value
239func (s *Style256) SetBg(bgVal uint8) *Style256 {
240	s.bg = Color256{bgVal, 1}
241	return s
242}
243
244// SetFg set fg color value
245func (s *Style256) SetFg(fgVal uint8) *Style256 {
246	s.fg = Color256{fgVal, 1}
247	return s
248}
249
250// SetOpts set options
251func (s *Style256) SetOpts(opts Opts) *Style256 {
252	s.opts = opts
253	return s
254}
255
256// AddOpts add options
257func (s *Style256) AddOpts(opts ...Color) *Style256 {
258	s.opts.Add(opts...)
259	return s
260}
261
262// Print message
263func (s *Style256) Print(a ...interface{}) {
264	doPrintV2(s.String(), fmt.Sprint(a...))
265}
266
267// Printf format and print message
268func (s *Style256) Printf(format string, a ...interface{}) {
269	doPrintV2(s.String(), fmt.Sprintf(format, a...))
270}
271
272// Println print message with newline
273func (s *Style256) Println(a ...interface{}) {
274	doPrintlnV2(s.String(), a)
275}
276
277// Sprint returns rendered message
278func (s *Style256) Sprint(a ...interface{}) string {
279	return RenderCode(s.Code(), a...)
280}
281
282// Sprintf returns format and rendered message
283func (s *Style256) Sprintf(format string, a ...interface{}) string {
284	return RenderString(s.Code(), fmt.Sprintf(format, a...))
285}
286
287// Code convert to color code string
288func (s *Style256) Code() string {
289	return s.String()
290}
291
292// String convert to color code string
293func (s *Style256) String() string {
294	var ss []string
295	if s.fg[1] > 0 {
296		ss = append(ss, fmt.Sprintf(TplFg256, s.fg[0]))
297	}
298
299	if s.bg[1] > 0 {
300		ss = append(ss, fmt.Sprintf(TplBg256, s.bg[0]))
301	}
302
303	if s.opts.IsValid() {
304		ss = append(ss, s.opts.String())
305	}
306
307	return strings.Join(ss, ";")
308}
309