1package cellbuf
2
3import (
4 "bytes"
5 "image/color"
6
7 "github.com/charmbracelet/x/ansi"
8)
9
10// ReadStyle reads a Select Graphic Rendition (SGR) escape sequences from a
11// list of parameters.
12func ReadStyle(params ansi.Params, pen *Style) {
13 if len(params) == 0 {
14 pen.Reset()
15 return
16 }
17
18 for i := 0; i < len(params); i++ {
19 param, hasMore, _ := params.Param(i, 0)
20 switch param {
21 case 0: // Reset
22 pen.Reset()
23 case 1: // Bold
24 pen.Bold(true)
25 case 2: // Dim/Faint
26 pen.Faint(true)
27 case 3: // Italic
28 pen.Italic(true)
29 case 4: // Underline
30 nextParam, _, ok := params.Param(i+1, 0)
31 if hasMore && ok { // Only accept subparameters i.e. separated by ":"
32 switch nextParam {
33 case 0, 1, 2, 3, 4, 5:
34 i++
35 switch nextParam {
36 case 0: // No Underline
37 pen.UnderlineStyle(NoUnderline)
38 case 1: // Single Underline
39 pen.UnderlineStyle(SingleUnderline)
40 case 2: // Double Underline
41 pen.UnderlineStyle(DoubleUnderline)
42 case 3: // Curly Underline
43 pen.UnderlineStyle(CurlyUnderline)
44 case 4: // Dotted Underline
45 pen.UnderlineStyle(DottedUnderline)
46 case 5: // Dashed Underline
47 pen.UnderlineStyle(DashedUnderline)
48 }
49 }
50 } else {
51 // Single Underline
52 pen.Underline(true)
53 }
54 case 5: // Slow Blink
55 pen.SlowBlink(true)
56 case 6: // Rapid Blink
57 pen.RapidBlink(true)
58 case 7: // Reverse
59 pen.Reverse(true)
60 case 8: // Conceal
61 pen.Conceal(true)
62 case 9: // Crossed-out/Strikethrough
63 pen.Strikethrough(true)
64 case 22: // Normal Intensity (not bold or faint)
65 pen.Bold(false).Faint(false)
66 case 23: // Not italic, not Fraktur
67 pen.Italic(false)
68 case 24: // Not underlined
69 pen.Underline(false)
70 case 25: // Blink off
71 pen.SlowBlink(false).RapidBlink(false)
72 case 27: // Positive (not reverse)
73 pen.Reverse(false)
74 case 28: // Reveal
75 pen.Conceal(false)
76 case 29: // Not crossed out
77 pen.Strikethrough(false)
78 case 30, 31, 32, 33, 34, 35, 36, 37: // Set foreground
79 pen.Foreground(ansi.Black + ansi.BasicColor(param-30)) //nolint:gosec
80 case 38: // Set foreground 256 or truecolor
81 var c color.Color
82 n := ReadStyleColor(params[i:], &c)
83 if n > 0 {
84 pen.Foreground(c)
85 i += n - 1
86 }
87 case 39: // Default foreground
88 pen.Foreground(nil)
89 case 40, 41, 42, 43, 44, 45, 46, 47: // Set background
90 pen.Background(ansi.Black + ansi.BasicColor(param-40)) //nolint:gosec
91 case 48: // Set background 256 or truecolor
92 var c color.Color
93 n := ReadStyleColor(params[i:], &c)
94 if n > 0 {
95 pen.Background(c)
96 i += n - 1
97 }
98 case 49: // Default Background
99 pen.Background(nil)
100 case 58: // Set underline color
101 var c color.Color
102 n := ReadStyleColor(params[i:], &c)
103 if n > 0 {
104 pen.UnderlineColor(c)
105 i += n - 1
106 }
107 case 59: // Default underline color
108 pen.UnderlineColor(nil)
109 case 90, 91, 92, 93, 94, 95, 96, 97: // Set bright foreground
110 pen.Foreground(ansi.BrightBlack + ansi.BasicColor(param-90)) //nolint:gosec
111 case 100, 101, 102, 103, 104, 105, 106, 107: // Set bright background
112 pen.Background(ansi.BrightBlack + ansi.BasicColor(param-100)) //nolint:gosec
113 }
114 }
115}
116
117// ReadLink reads a hyperlink escape sequence from a data buffer.
118func ReadLink(p []byte, link *Link) {
119 params := bytes.Split(p, []byte{';'})
120 if len(params) != 3 {
121 return
122 }
123 link.Params = string(params[1])
124 link.URL = string(params[2])
125}
126
127// ReadStyleColor reads a color from a list of parameters.
128// See [ansi.ReadStyleColor] for more information.
129func ReadStyleColor(params ansi.Params, c *color.Color) int {
130 return ansi.ReadStyleColor(params, c)
131}