Skip to content

Commit 90b3c2a

Browse files
committed
demo
1 parent bc95ab4 commit 90b3c2a

File tree

6 files changed

+447
-11
lines changed

6 files changed

+447
-11
lines changed

cmd/demo-colors/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# 256-Color Palette Demo
2+
3+
This demo showcases the 256-color ANSI palette support in go-pretty.
4+
5+
## Usage
6+
7+
```bash
8+
go run ./cmd/demo-colors
9+
```
10+
11+
## Screenshot
12+
13+
![256-Color Palette Demo](demo.png)

cmd/demo-colors/demo.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/jedib0t/go-pretty/v6/table"
7+
"github.com/jedib0t/go-pretty/v6/text"
8+
)
9+
10+
func main() {
11+
tw := table.NewWriter()
12+
tw.AppendRows([]table.Row{
13+
{renderGrid(false)},
14+
{renderGrid(true)},
15+
})
16+
tw.SetTitle("256-Color Palette")
17+
tw.SetStyle(table.StyleLight)
18+
tw.Style().Options.SeparateRows = true
19+
tw.Style().Title.Align = text.AlignCenter
20+
fmt.Println(tw.Render())
21+
}
22+
23+
func alignCode(code int) string {
24+
return " " + text.AlignRight.Apply(fmt.Sprint(code), 3) + " "
25+
}
26+
27+
func blankTable() table.Writer {
28+
tw := table.NewWriter()
29+
tw.SetStyle(table.StyleLight)
30+
style := tw.Style()
31+
style.Box.PaddingLeft = ""
32+
style.Box.PaddingRight = ""
33+
style.Options.DrawBorder = false
34+
style.Options.SeparateRows = false
35+
style.Options.SeparateColumns = false
36+
return tw
37+
}
38+
39+
func buildRow(start, end int, isBackground bool) table.Row {
40+
row := make(table.Row, 0, end-start)
41+
for i := start; i < end; i++ {
42+
row = append(row, cellValue(i, isBackground))
43+
}
44+
return row
45+
}
46+
47+
func cellValue(code int, isBackground bool) string {
48+
if isBackground {
49+
return text.Colors{text.Bg256Color(code), text.FgBlack}.Sprint(alignCode(code))
50+
}
51+
return text.Colors{text.BgBlack, text.Fg256Color(code)}.Sprint(alignCode(code))
52+
}
53+
54+
func renderGrid(isBackground bool) string {
55+
tw := table.NewWriter()
56+
tw.SetIndexColumn(1)
57+
title := "Foreground Colors"
58+
if isBackground {
59+
title = "Background Colors"
60+
}
61+
tw.SetTitle(text.Underline.Sprint(title) + "\n")
62+
tw.SetStyle(table.StyleLight)
63+
style := tw.Style()
64+
style.Box.PaddingLeft = ""
65+
style.Box.PaddingRight = ""
66+
style.Options.DrawBorder = false
67+
style.Options.SeparateRows = false
68+
style.Options.SeparateColumns = false
69+
style.Title.Align = text.AlignCenter
70+
tw.SetColumnConfigs([]table.ColumnConfig{
71+
{Number: 1, Align: text.AlignCenter},
72+
})
73+
74+
// Standard 16 colors (0-15)
75+
row16 := blankTable()
76+
row16.AppendRow(buildRow(0, 16, isBackground))
77+
tw.AppendRows([]table.Row{{row16.Render()}, {""}})
78+
79+
// RGB cube colors (16-231) - 216 colors in 6 blocks of 36
80+
row216 := blankTable()
81+
blockRow := make(table.Row, 0)
82+
for block := 0; block < 6; block++ {
83+
blockStart := 16 + 36*block
84+
blockTable := blankTable()
85+
colors := buildRow(blockStart, blockStart+36, isBackground)
86+
for i := 0; i < len(colors); i += 6 {
87+
end := i + 6
88+
if end > len(colors) {
89+
end = len(colors)
90+
}
91+
blockTable.AppendRow(colors[i:end])
92+
}
93+
blockRow = append(blockRow, blockTable.Render())
94+
if len(blockRow) == 3 {
95+
row216.AppendRow(blockRow)
96+
blockRow = make(table.Row, 0)
97+
}
98+
}
99+
if len(blockRow) > 0 {
100+
row216.AppendRow(blockRow)
101+
}
102+
tw.AppendRows([]table.Row{{row216.Render()}, {""}})
103+
104+
// Grayscale colors (232-255) - 24 colors
105+
rowGrayscale := blankTable()
106+
colors := buildRow(232, 256, isBackground)
107+
for i := 0; i < len(colors); i += 12 {
108+
end := i + 12
109+
if end > len(colors) {
110+
end = len(colors)
111+
}
112+
rowGrayscale.AppendRow(colors[i:end])
113+
}
114+
tw.AppendRows([]table.Row{{rowGrayscale.Render()}})
115+
116+
return tw.Render()
117+
}

cmd/demo-colors/demo.png

444 KB
Loading

text/color.go

Lines changed: 136 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
111124
func (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.
119144
func (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.
187240
func (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

Comments
 (0)