Skip to content

Commit efc6d3f

Browse files
committed
refactor: update and refactor the color tag parse logic
1 parent daca06f commit efc6d3f

File tree

3 files changed

+201
-38
lines changed

3 files changed

+201
-38
lines changed

color_tag.go

+172-38
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,11 @@ var (
3838
* internal defined color tags
3939
*************************************************************/
4040

41-
// There are internal defined color tags
42-
// Usage: <tag>content text</>
41+
// There are internal defined fg color tags
42+
//
43+
// Usage:
44+
// <tag>content text</>
45+
//
4346
// @notice 加 0 在前面是为了防止之前的影响到现在的设置
4447
var colorTags = map[string]string{
4548
// basic tags
@@ -72,7 +75,9 @@ var colorTags = map[string]string{
7275
"magenta": "0;35",
7376
"mga": "0;35", // short name
7477
"magentaB": "1;35", // with bold
78+
"magenta1": "1;35",
7579
"mgb": "1;35",
80+
"mga1": "1;35",
7681
"mgaB": "1;35",
7782

7883
// light/hi tags
@@ -90,7 +95,7 @@ var colorTags = map[string]string{
9095
"light_magenta": "0;95",
9196
"hiMagenta": "0;95",
9297
"hi_magenta": "0;95",
93-
"lightMagentaB": "1;95", // with bold
98+
"lightMagenta1": "1;95", // with bold
9499
"hiMagentaB": "1;95", // with bold
95100
"hi_magenta_b": "1;95",
96101
"lightRed": "0;91",
@@ -127,9 +132,14 @@ var colorTags = map[string]string{
127132
// option
128133
"bold": "1",
129134
"b": "1",
135+
"italic": "3",
136+
"i": "3", // italic
130137
"underscore": "4",
131138
"us": "4", // short name for 'underscore'
139+
"blink": "5",
140+
"fb": "6", // fast blink
132141
"reverse": "7",
142+
"st": "9", // strikethrough
133143

134144
// alert tags, like bootstrap's alert
135145
"suc": "1;32", // same "green" and "bold"
@@ -146,12 +156,141 @@ var colorTags = map[string]string{
146156
"error": "97;41", // fg light white; bg red
147157
}
148158

159+
/*************************************************************
160+
* internal defined tag attributes
161+
*************************************************************/
162+
163+
// built-in attributes for fg,bg 16-colors and op codes.
164+
var (
165+
attrFgs = map[string]string{
166+
// basic colors
167+
168+
"black": FgBlack.Code(),
169+
"red": "31",
170+
"green": "32",
171+
"brown": "33", // #A52A2A
172+
"yellow": "33",
173+
"ylw": "33",
174+
"blue": "34",
175+
"cyan": "36",
176+
"magenta": "35",
177+
"mga": "35",
178+
"white": FgWhite.Code(),
179+
"default": "39", // no color
180+
"normal": "39", // no color
181+
182+
// light/hi colors
183+
184+
"darkGray": FgDarkGray.Code(),
185+
"dark_gray": "90",
186+
"gray": "90",
187+
"lightYellow": "93",
188+
"light_yellow": "93",
189+
"hiYellow": "93",
190+
"hi_yellow": "93",
191+
"lightMagenta": "95",
192+
"light_magenta": "95",
193+
"hiMagenta": "95",
194+
"hi_magenta": "95",
195+
"hi_mga": "95",
196+
"lightRed": "91",
197+
"light_red": "91",
198+
"hiRed": "91",
199+
"hi_red": "91",
200+
"lightGreen": "92",
201+
"light_green": "92",
202+
"hiGreen": "92",
203+
"hi_green": "92",
204+
"lightBlue": "94",
205+
"light_blue": "94",
206+
"hiBlue": "94",
207+
"hi_blue": "94",
208+
"lightCyan": "96",
209+
"light_cyan": "96",
210+
"hiCyan": "96",
211+
"hi_cyan": "96",
212+
"lightWhite": "97",
213+
"light_white": "97",
214+
}
215+
216+
attrBgs = map[string]string{
217+
// basic colors
218+
219+
"black": BgBlack.Code(),
220+
"red": "41",
221+
"green": "42",
222+
"brown": "43", // #A52A2A
223+
"yellow": "43",
224+
"ylw": "43",
225+
"blue": "44",
226+
"cyan": "46",
227+
"magenta": "45",
228+
"mga": "45",
229+
"white": FgWhite.Code(),
230+
"default": "49", // no color
231+
"normal": "49", // no color
232+
233+
// light/hi colors
234+
235+
"darkGray": BgDarkGray.Code(),
236+
"dark_gray": "100",
237+
"gray": "100",
238+
"lightYellow": "103",
239+
"light_yellow": "103",
240+
"hiYellow": "103",
241+
"hi_yellow": "103",
242+
"lightMagenta": "105",
243+
"light_magenta": "105",
244+
"hiMagenta": "105",
245+
"hi_magenta": "105",
246+
"hi_mga": "105",
247+
"lightRed": "101",
248+
"light_red": "101",
249+
"hiRed": "101",
250+
"hi_red": "101",
251+
"lightGreen": "102",
252+
"light_green": "102",
253+
"hiGreen": "102",
254+
"hi_green": "102",
255+
"lightBlue": "104",
256+
"light_blue": "104",
257+
"hiBlue": "104",
258+
"hi_blue": "104",
259+
"lightCyan": "106",
260+
"light_cyan": "106",
261+
"hiCyan": "106",
262+
"hi_cyan": "106",
263+
"lightWhite": BgLightWhite.Code(),
264+
"light_white": "107",
265+
}
266+
267+
attrOpts = map[string]string{
268+
"reset": OpReset.Code(),
269+
"bold": OpBold.Code(),
270+
"b": OpBold.Code(),
271+
"fuzzy": OpFuzzy.Code(),
272+
"italic": OpItalic.Code(),
273+
"i": OpItalic.Code(),
274+
"underscore": OpUnderscore.Code(),
275+
"us": OpUnderscore.Code(),
276+
"u": OpUnderscore.Code(),
277+
"blink": OpBlink.Code(),
278+
"fastblink": OpFastBlink.Code(),
279+
"fb": OpFastBlink.Code(),
280+
"reverse": OpReverse.Code(),
281+
"concealed": OpConcealed.Code(),
282+
"strikethrough": OpStrikethrough.Code(),
283+
"st": OpStrikethrough.Code(),
284+
}
285+
)
286+
149287
/*************************************************************
150288
* parse color tags
151289
*************************************************************/
152290

153291
var (
154292
tagParser = TagParser{}
293+
// regex for match color 256 code
155294
rxNumStr = regexp.MustCompile("^[0-9]{1,3}$")
156295
rxHexCode = regexp.MustCompile("^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$")
157296
)
@@ -182,11 +321,18 @@ func (tp *TagParser) ParseByEnv(str string) string {
182321
if !Enable || !SupportColor() {
183322
return ClearTag(str)
184323
}
185-
186324
return tp.Parse(str)
187325
}
188326

189327
// Parse parse given string, replace color tag and return rendered string
328+
//
329+
// Use built in tags:
330+
// <TAG_NAME>CONTENT</>
331+
// // e.g: `<info>message</>`
332+
//
333+
// Custom tag attributes:
334+
// `<fg=VALUE;bg=VALUE;op=VALUES>CONTENT</>`
335+
// // e.g: `<fg=167;bg=232>wel</>`
190336
func (tp *TagParser) Parse(str string) string {
191337
// not contains color tag
192338
if !strings.Contains(str, "</>") {
@@ -198,14 +344,15 @@ func (tp *TagParser) Parse(str string) string {
198344

199345
// item: 0 full text 1 tag name 2 tag content
200346
for _, item := range matched {
201-
full, tag, content := item[0], item[1], item[2]
347+
full, tag, body := item[0], item[1], item[2]
202348

203-
// use defined tag name: "<info>content</>" -> tag: "info"
349+
// use defined color tag name: "<info>content</>" -> tag: "info"
204350
if !strings.ContainsRune(tag, '=') {
205-
code := colorTags[tag]
206-
if len(code) > 0 {
207-
now := RenderString(code, content)
208-
// old := WrapTag(content, tag) is equals to var 'full'
351+
if code := colorTags[tag]; len(code) > 0 {
352+
str = strings.Replace(str, full, RenderString(code, body), 1)
353+
} else if code, ok := namedRgbMap[tag]; ok {
354+
code = strings.Replace(code, ",", ";", -1)
355+
now := RenderString(FgRGBPfx+code, body)
209356
str = strings.Replace(str, full, now, 1)
210357
}
211358
continue
@@ -214,18 +361,13 @@ func (tp *TagParser) Parse(str string) string {
214361
// custom color in tag
215362
// - basic: "fg=white;bg=blue;op=bold"
216363
if code := ParseCodeFromAttr(tag); len(code) > 0 {
217-
now := RenderString(code, content)
218-
str = strings.Replace(str, full, now, 1)
364+
str = strings.Replace(str, full, RenderString(code, body), 1)
219365
}
220366
}
221367

222368
return str
223369
}
224370

225-
// func (tp *TagParser) ParseAttr(attr string) (code string) {
226-
// return
227-
// }
228-
229371
// ReplaceTag parse string, replace color tag and return rendered string
230372
func ReplaceTag(str string) string {
231373
return tagParser.ParseByEnv(str)
@@ -236,17 +378,20 @@ func ReplaceTag(str string) string {
236378
// attr format:
237379
// // VALUE please see var: FgColors, BgColors, AllOptions
238380
// "fg=VALUE;bg=VALUE;op=VALUE"
381+
//
239382
// 16 color:
240383
// "fg=yellow"
241384
// "bg=red"
242-
// "op=bold,underscore" option is allow multi value
385+
// "op=bold,underscore" // option is allow multi value
243386
// "fg=white;bg=blue;op=bold"
244387
// "fg=white;op=bold,underscore"
388+
//
245389
// 256 color:
246390
// "fg=167"
247391
// "fg=167;bg=23"
248392
// "fg=167;bg=23;op=bold"
249-
// true color:
393+
//
394+
// True color:
250395
// // hex
251396
// "fg=fc1cac"
252397
// "fg=fc1cac;bg=c2c3c4"
@@ -270,31 +415,27 @@ func ParseCodeFromAttr(attr string) (code string) {
270415
pos, val := item[1], item[2]
271416
switch pos {
272417
case "fg":
273-
if c, ok := FgColors[val]; ok { // basic
274-
codes = append(codes, c.String())
275-
} else if c, ok := ExFgColors[val]; ok { // extra
276-
codes = append(codes, c.String())
418+
if code, ok := attrFgs[val]; ok { // attr fg
419+
codes = append(codes, code)
277420
} else if code := rgbHex256toCode(val, false); code != "" {
278421
codes = append(codes, code)
279422
}
280423
case "bg":
281-
if c, ok := BgColors[val]; ok { // basic bg
282-
codes = append(codes, c.String())
283-
} else if c, ok := ExBgColors[val]; ok { // extra bg
284-
codes = append(codes, c.String())
424+
if code, ok := attrBgs[val]; ok { // attr bg
425+
codes = append(codes, code)
285426
} else if code := rgbHex256toCode(val, true); code != "" {
286427
codes = append(codes, code)
287428
}
288429
case "op": // options allow multi value
289430
if strings.Contains(val, ",") {
290431
ns := strings.Split(val, ",")
291432
for _, n := range ns {
292-
if c, ok := AllOptions[n]; ok {
293-
codes = append(codes, c.String())
433+
if code, ok := attrOpts[n]; ok { // attr ops
434+
codes = append(codes, code)
294435
}
295436
}
296-
} else if c, ok := AllOptions[val]; ok {
297-
codes = append(codes, c.String())
437+
} else if code, ok := attrOpts[val]; ok {
438+
codes = append(codes, code)
298439
}
299440
}
300441
}
@@ -327,7 +468,6 @@ func ClearTag(s string) string {
327468
if !strings.Contains(s, "</>") {
328469
return s
329470
}
330-
331471
return stripRegex.ReplaceAllString(s, "")
332472
}
333473

@@ -350,7 +490,6 @@ func WrapTag(s string, tag string) string {
350490
if s == "" || tag == "" {
351491
return s
352492
}
353-
354493
return fmt.Sprintf("<%s>%s</>", tag, s)
355494
}
356495

@@ -410,12 +549,7 @@ func (tg Tag) Println(a ...interface{}) {
410549

411550
// Sprint render messages
412551
func (tg Tag) Sprint(a ...interface{}) string {
413-
name := string(tg)
414-
// if stl := GetStyle(name); !stl.IsEmpty() {
415-
// return stl.Render(args...)
416-
// }
417-
418-
return RenderCode(GetTagCode(name), a...)
552+
return RenderCode(GetTagCode(string(tg)), a...)
419553
}
420554

421555
// Sprintf format and render messages

color_tag_test.go

+20
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package color
22

33
import (
4+
"fmt"
45
"log"
56
"testing"
67

@@ -62,18 +63,34 @@ def <info>info text
6263
is.Equal("", s)
6364
}
6465

66+
func TestTagParser_Parse_c16_opt(t *testing.T) {
67+
s := tagParser.Parse("<fg=mga;op=i>msg</>")
68+
69+
fmt.Println(s)
70+
assert.Equal(t, "\x1b[35;3mmsg\x1b[0m", s)
71+
}
72+
73+
func TestTagParser_Parse_named_rgb_code(t *testing.T) {
74+
s := tagParser.Parse("<deepskyblue>deepskyblue style msg</>")
75+
76+
fmt.Println(s)
77+
assert.Equal(t, "\x1b[38;2;0;191;255mdeepskyblue style msg\x1b[0m", s)
78+
}
79+
6580
func TestTagParser_Parse_hex_rgb_c256(t *testing.T) {
6681
is := assert.New(t)
6782
p := NewTagParser()
6883

6984
s := "custom tag: <fg=e7b2a1>hello, welcome</>"
7085
r := p.Parse(s)
86+
fmt.Println(r)
7187
is.NotContains(r, "<")
7288
is.NotContains(r, ">")
7389
is.Equal("custom tag: \x1B[38;2;231;178;161mhello, welcome\x1B[0m", r)
7490

7591
s = "custom tag: <fg=e7b2a1;bg=176;op=bold>hello, welcome</>"
7692
r = p.Parse(s)
93+
fmt.Println(r)
7794
is.NotContains(r, "<")
7895
is.NotContains(r, ">")
7996
is.Equal("custom tag: \x1b[38;2;231;178;161;48;5;176;1mhello, welcome\x1b[0m", r)
@@ -85,6 +102,9 @@ func TestParseCodeFromAttr_basic(t *testing.T) {
85102
s := ParseCodeFromAttr("=")
86103
is.Equal("", s)
87104

105+
s = ParseCodeFromAttr("no attr")
106+
is.Equal("", s)
107+
88108
s = ParseCodeFromAttr("fg=lightRed;bg=lightRed;op=bold,blink")
89109
is.Equal("91;101;1;5", s)
90110

0 commit comments

Comments
 (0)