Skip to content

Commit 9736538

Browse files
authored
Add zellij template with .rgbs color format support (#91)
Add a zellij.kdl theme template that uses space-separated RGB values for KDL color syntax (e.g., '255 128 0'). Introduce {key.rgbs} variable format that converts hex colors to space-separated decimal RGB, alongside the existing comma-separated {key.rgb} format. - Add HexToRGBSpaceString() to internal/color/convert.go - Add {key.rgbs} handler to internal/template/engine.go - Add templates/zellij.kdl for Zellij terminal multiplexer theming
1 parent f851a15 commit 9736538

3 files changed

Lines changed: 138 additions & 2 deletions

File tree

internal/color/convert.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,13 @@ func HexToRGBString(hex string) string {
147147
return fmt.Sprintf("%d,%d,%d", clampByte(rgb.R), clampByte(rgb.G), clampByte(rgb.B))
148148
}
149149

150+
// HexToRGBSpaceString converts a hex color to an "r g b" space-separated decimal string.
151+
// Used by KDL-based configs like Zellij.
152+
func HexToRGBSpaceString(hex string) string {
153+
rgb := HexToRGB(hex)
154+
return fmt.Sprintf("%d %d %d", clampByte(rgb.R), clampByte(rgb.G), clampByte(rgb.B))
155+
}
156+
150157
// HexToRGBA converts a hex color to an "rgba(r, g, b, a)" string.
151158
func HexToRGBA(hex string, alpha float64) string {
152159
rgb := HexToRGB(hex)

internal/template/engine.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
// - {key} -> value
1313
// - {key.strip} -> value without '#' prefix
1414
// - {key.rgb} -> "r,g,b" decimal
15+
// - {key.rgbs} -> "r g b" space-separated decimal
1516
// - {key.rgba} -> "rgba(r, g, b, 1.0)"
1617
// - {key.rgba:0.5} -> "rgba(r, g, b, 0.5)"
1718
// - {key.yaru} -> Yaru icon theme name based on hue
@@ -31,6 +32,14 @@ func ReplaceVariable(content, key, value string) string {
3132
content = strings.ReplaceAll(content, "{"+key+".rgb}", value)
3233
}
3334

35+
// Replace {key.rgbs} (converts hex to space-separated decimal RGB: r g b)
36+
if strings.HasPrefix(value, "#") {
37+
rgbsValue := color.HexToRGBSpaceString(value)
38+
content = strings.ReplaceAll(content, "{"+key+".rgbs}", rgbsValue)
39+
} else {
40+
content = strings.ReplaceAll(content, "{"+key+".rgbs}", value)
41+
}
42+
3443
// Replace {key.rgba} and {key.rgba:N} (converts hex to rgba format)
3544
rgbaPattern := regexp.MustCompile(fmt.Sprintf(`\{%s\.rgba(?::(\d*\.?\d+))?\}`, regexp.QuoteMeta(key)))
3645
if strings.HasPrefix(value, "#") {
@@ -59,7 +68,7 @@ func ReplaceVariable(content, key, value string) string {
5968

6069
// ProcessTemplate replaces all variables in template content and returns the
6170
// processed result. Each variable is substituted using ReplaceVariable which
62-
// handles {key}, {key.strip}, {key.rgb}, {key.rgba}, and {key.yaru} variants.
71+
// handles {key}, {key.strip}, {key.rgb}, {key.rgbs}, {key.rgba}, and {key.yaru} variants.
6372
func ProcessTemplate(templateContent string, variables map[string]string) string {
6473
result := templateContent
6574
for key, value := range variables {
@@ -68,7 +77,7 @@ func ProcessTemplate(templateContent string, variables map[string]string) string
6877
return result
6978
}
7079

71-
// variablePattern matches {key}, {key.strip}, {key.rgb}, {key.rgba}, {key.rgba:N}, and {key.yaru}.
80+
// variablePattern matches {key}, {key.strip}, {key.rgb}, {key.rgbs}, {key.rgba}, {key.rgba:N}, and {key.yaru}.
7281
var variablePattern = regexp.MustCompile(`\{(\w+)(?:\.\w+(?::[^}]*)?)?\}`)
7382

7483
// ExtractVariableNames returns the deduplicated set of base variable names

templates/zellij.kdl

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
themes {
2+
current {
3+
text_unselected {
4+
base {foreground.rgbs}
5+
background {bright_black.rgbs}
6+
emphasis_0 {orange.rgbs}
7+
emphasis_1 {bright_cyan.rgbs}
8+
emphasis_2 {bright_green.rgbs}
9+
emphasis_3 {bright_magenta.rgbs}
10+
}
11+
text_selected {
12+
base {foreground.rgbs}
13+
background {bright_black.rgbs}
14+
emphasis_0 {orange.rgbs}
15+
emphasis_1 {bright_cyan.rgbs}
16+
emphasis_2 {bright_green.rgbs}
17+
emphasis_3 {bright_magenta.rgbs}
18+
}
19+
ribbon_selected {
20+
base {bright_black.rgbs}
21+
background {bright_green.rgbs}
22+
emphasis_0 {bright_red.rgbs}
23+
emphasis_1 {orange.rgbs}
24+
emphasis_2 {bright_magenta.rgbs}
25+
emphasis_3 {bright_blue.rgbs}
26+
}
27+
ribbon_unselected {
28+
base {bright_black.rgbs}
29+
background {foreground.rgbs}
30+
emphasis_0 {bright_red.rgbs}
31+
emphasis_1 {foreground.rgbs}
32+
emphasis_2 {bright_blue.rgbs}
33+
emphasis_3 {bright_magenta.rgbs}
34+
}
35+
table_title {
36+
base {bright_green.rgbs}
37+
background 0
38+
emphasis_0 {orange.rgbs}
39+
emphasis_1 {bright_cyan.rgbs}
40+
emphasis_2 {bright_green.rgbs}
41+
emphasis_3 {bright_magenta.rgbs}
42+
}
43+
table_cell_selected {
44+
base {foreground.rgbs}
45+
background {bright_black.rgbs}
46+
emphasis_0 {orange.rgbs}
47+
emphasis_1 {bright_cyan.rgbs}
48+
emphasis_2 {bright_green.rgbs}
49+
emphasis_3 {bright_magenta.rgbs}
50+
}
51+
table_cell_unselected {
52+
base {foreground.rgbs}
53+
background {bright_black.rgbs}
54+
emphasis_0 {orange.rgbs}
55+
emphasis_1 {bright_cyan.rgbs}
56+
emphasis_2 {bright_green.rgbs}
57+
emphasis_3 {bright_magenta.rgbs}
58+
}
59+
list_selected {
60+
base {foreground.rgbs}
61+
background {bright_black.rgbs}
62+
emphasis_0 {orange.rgbs}
63+
emphasis_1 {bright_cyan.rgbs}
64+
emphasis_2 {bright_green.rgbs}
65+
emphasis_3 {bright_magenta.rgbs}
66+
}
67+
list_unselected {
68+
base {foreground.rgbs}
69+
background {bright_black.rgbs}
70+
emphasis_0 {orange.rgbs}
71+
emphasis_1 {bright_cyan.rgbs}
72+
emphasis_2 {bright_green.rgbs}
73+
emphasis_3 {bright_magenta.rgbs}
74+
}
75+
frame_selected {
76+
base {bright_green.rgbs}
77+
background 0
78+
emphasis_0 {orange.rgbs}
79+
emphasis_1 {bright_cyan.rgbs}
80+
emphasis_2 {bright_magenta.rgbs}
81+
emphasis_3 0
82+
}
83+
frame_highlight {
84+
base {orange.rgbs}
85+
background 0
86+
emphasis_0 {bright_magenta.rgbs}
87+
emphasis_1 {orange.rgbs}
88+
emphasis_2 {orange.rgbs}
89+
emphasis_3 {orange.rgbs}
90+
}
91+
exit_code_success {
92+
base {bright_green.rgbs}
93+
background 0
94+
emphasis_0 {bright_cyan.rgbs}
95+
emphasis_1 {bright_black.rgbs}
96+
emphasis_2 {bright_magenta.rgbs}
97+
emphasis_3 {bright_blue.rgbs}
98+
}
99+
exit_code_error {
100+
base {bright_red.rgbs}
101+
background 0
102+
emphasis_0 {yellow.rgbs}
103+
emphasis_1 0
104+
emphasis_2 0
105+
emphasis_3 0
106+
}
107+
multiplayer_user_colors {
108+
player_1 {bright_magenta.rgbs}
109+
player_2 {bright_blue.rgbs}
110+
player_3 0
111+
player_4 {yellow.rgbs}
112+
player_5 {bright_cyan.rgbs}
113+
player_6 0
114+
player_7 {bright_red.rgbs}
115+
player_8 0
116+
player_9 0
117+
player_10 0
118+
}
119+
}
120+
}

0 commit comments

Comments
 (0)