@@ -107,8 +107,33 @@ const (
107107 BgHiWhite
108108)
109109
110+ // 256-color support
111+ // Internal encoding for 256-color codes (used by escape_seq_parser.go):
112+ // Foreground 256-color: Fg256Start + colorIndex (1000-1255)
113+ // Background 256-color: Bg256Start + colorIndex (2000-2255)
114+ const (
115+ // Fg256Start is the base value for 256-color foreground colors.
116+ // Use Fg256Color(index) to create a 256-color foreground color.
117+ Fg256Start Color = 1000
118+ // Bg256Start is the base value for 256-color background colors.
119+ // Use Bg256Color(index) to create a 256-color background color.
120+ Bg256Start Color = 2000
121+ )
122+
110123// CSSClasses returns the CSS class names for the color.
111124func (c Color ) CSSClasses () string {
125+ // Check for 256-color and convert to RGB-based class
126+ if c >= Fg256Start && c < Fg256Start + 256 {
127+ colorIndex := int (c - Fg256Start )
128+ r , g , b := color256ToRGB (colorIndex )
129+ return fmt .Sprintf ("fg-256-%d-%d-%d" , r , g , b )
130+ }
131+ if c >= Bg256Start && c < Bg256Start + 256 {
132+ colorIndex := int (c - Bg256Start )
133+ r , g , b := color256ToRGB (colorIndex )
134+ return fmt .Sprintf ("bg-256-%d-%d-%d" , r , g , b )
135+ }
136+ // Existing behavior for standard colors
112137 if class , ok := colorCSSClassMap [c ]; ok {
113138 return class
114139 }
@@ -117,6 +142,17 @@ func (c Color) CSSClasses() string {
117142
118143// EscapeSeq returns the ANSI escape sequence for the color.
119144func (c Color ) EscapeSeq () string {
145+ // Check if it's a 256-color foreground (1000-1255)
146+ if c >= Fg256Start && c < Fg256Start + 256 {
147+ colorIndex := int (c - Fg256Start )
148+ return fmt .Sprintf ("%s38;5;%d%s" , EscapeStart , colorIndex , EscapeStop )
149+ }
150+ // Check if it's a 256-color background (2000-2255)
151+ if c >= Bg256Start && c < Bg256Start + 256 {
152+ colorIndex := int (c - Bg256Start )
153+ return fmt .Sprintf ("%s48;5;%d%s" , EscapeStart , colorIndex , EscapeStop )
154+ }
155+ // Regular color (existing behavior)
120156 return EscapeStart + strconv .Itoa (int (c )) + EscapeStop
121157}
122158
@@ -154,7 +190,8 @@ func (c Colors) CSSClasses() string {
154190
155191 var classes []string
156192 for _ , color := range c {
157- if class , ok := colorCSSClassMap [color ]; ok {
193+ class := color .CSSClasses ()
194+ if class != "" {
158195 classes = append (classes , class )
159196 }
160197 }
@@ -173,16 +210,32 @@ func (c Colors) EscapeSeq() string {
173210 colorsKey := fmt .Sprintf ("%#v" , c )
174211 escapeSeq , ok := colorsSeqMap .Load (colorsKey )
175212 if ! ok || escapeSeq == "" {
176- colorNums := make ([]string , len (c ))
177- for idx , color := range c {
178- colorNums [ idx ] = strconv . Itoa ( int (color ))
213+ codes := make ([]string , 0 , len (c ))
214+ for _ , color := range c {
215+ codes = append ( codes , c . colorToCode (color ))
179216 }
180- escapeSeq = EscapeStart + strings .Join (colorNums , ";" ) + EscapeStop
217+ escapeSeq = EscapeStart + strings .Join (codes , ";" ) + EscapeStop
181218 colorsSeqMap .Store (colorsKey , escapeSeq )
182219 }
183220 return escapeSeq .(string )
184221}
185222
223+ // colorToCode converts a Color to its escape sequence code string.
224+ func (c Colors ) colorToCode (color Color ) string {
225+ // Check if it's a 256-color foreground (1000-1255)
226+ if color >= Fg256Start && color < Fg256Start + 256 {
227+ colorIndex := int (color - Fg256Start )
228+ return fmt .Sprintf ("38;5;%d" , colorIndex )
229+ }
230+ // Check if it's a 256-color background (2000-2255)
231+ if color >= Bg256Start && color < Bg256Start + 256 {
232+ colorIndex := int (color - Bg256Start )
233+ return fmt .Sprintf ("48;5;%d" , colorIndex )
234+ }
235+ // Regular color
236+ return strconv .Itoa (int (color ))
237+ }
238+
186239// HTMLProperty returns the "class" attribute for the colors.
187240func (c Colors ) HTMLProperty () string {
188241 classes := c .CSSClasses ()
@@ -208,3 +261,81 @@ func colorize(s string, escapeSeq string) string {
208261 }
209262 return Escape (s , escapeSeq )
210263}
264+
265+ // Fg256Color returns a foreground 256-color Color value.
266+ // The index must be in the range 0-255.
267+ func Fg256Color (index int ) Color {
268+ if index < 0 || index > 255 {
269+ return Reset
270+ }
271+ return Fg256Start + Color (index )
272+ }
273+
274+ // Bg256Color returns a background 256-color Color value.
275+ // The index must be in the range 0-255.
276+ func Bg256Color (index int ) Color {
277+ if index < 0 || index > 255 {
278+ return Reset
279+ }
280+ return Bg256Start + Color (index )
281+ }
282+
283+ // Fg256RGB returns a foreground 256-color from RGB values in the 6x6x6 color cube.
284+ // Each RGB component must be in the range 0-5.
285+ // The resulting color index will be in the range 16-231.
286+ func Fg256RGB (r , g , b int ) Color {
287+ if r < 0 || r > 5 || g < 0 || g > 5 || b < 0 || b > 5 {
288+ return Reset
289+ }
290+ index := 16 + (r * 36 + g * 6 + b )
291+ return Fg256Color (index )
292+ }
293+
294+ // Bg256RGB returns a background 256-color from RGB values in the 6x6x6 color cube.
295+ // Each RGB component must be in the range 0-5.
296+ // The resulting color index will be in the range 16-231.
297+ func Bg256RGB (r , g , b int ) Color {
298+ if r < 0 || r > 5 || g < 0 || g > 5 || b < 0 || b > 5 {
299+ return Reset
300+ }
301+ index := 16 + (r * 36 + g * 6 + b )
302+ return Bg256Color (index )
303+ }
304+
305+ // color256ToRGB converts a 256-color index to RGB values.
306+ // Returns (r, g, b) values in the range 0-255.
307+ func color256ToRGB (index int ) (r , g , b int ) {
308+ if index < 16 {
309+ // Standard 16 colors - map to predefined RGB values
310+ standardColors := [16 ][3 ]int {
311+ {0 , 0 , 0 }, // 0: black
312+ {128 , 0 , 0 }, // 1: red
313+ {0 , 128 , 0 }, // 2: green
314+ {128 , 128 , 0 }, // 3: yellow
315+ {0 , 0 , 128 }, // 4: blue
316+ {128 , 0 , 128 }, // 5: magenta
317+ {0 , 128 , 128 }, // 6: cyan
318+ {192 , 192 , 192 }, // 7: light gray
319+ {128 , 128 , 128 }, // 8: dark gray
320+ {255 , 0 , 0 }, // 9: bright red
321+ {0 , 255 , 0 }, // 10: bright green
322+ {255 , 255 , 0 }, // 11: bright yellow
323+ {0 , 0 , 255 }, // 12: bright blue
324+ {255 , 0 , 255 }, // 13: bright magenta
325+ {0 , 255 , 255 }, // 14: bright cyan
326+ {255 , 255 , 255 }, // 15: white
327+ }
328+ return standardColors [index ][0 ], standardColors [index ][1 ], standardColors [index ][2 ]
329+ } else if index < 232 {
330+ // 216-color RGB cube (16-231)
331+ index -= 16
332+ r = (index / 36 ) * 51
333+ g = ((index / 6 ) % 6 ) * 51
334+ b = (index % 6 ) * 51
335+ } else {
336+ // 24 grayscale colors (232-255)
337+ gray := 8 + (index - 232 )* 10
338+ r , g , b = gray , gray , gray
339+ }
340+ return
341+ }
0 commit comments