Skip to main content

ai_agent/utils/
theme.rs

1// Source: /data/home/swei/claudecode/openclaudecode/src/commands/theme/theme.tsx
2/**
3 * Theme definitions for the TUI
4 */
5use once_cell::sync::Lazy;
6
7/// Theme color type - can be RGB or ANSI
8#[derive(Debug, Clone, PartialEq)]
9pub enum ThemeColor {
10    Rgb(u8, u8, u8),
11    Ansi(AnsiColor),
12}
13
14impl ThemeColor {
15    pub fn to_ansi_string(&self) -> String {
16        match self {
17            ThemeColor::Ansi(color) => color.to_string(),
18            ThemeColor::Rgb(r, g, b) => format!("rgb({},{},{})", r, g, b),
19        }
20    }
21}
22
23#[derive(Debug, Clone, Copy, PartialEq)]
24pub enum AnsiColor {
25    Black,
26    Red,
27    Green,
28    Yellow,
29    Blue,
30    Magenta,
31    Cyan,
32    White,
33    BlackBright,
34    RedBright,
35    GreenBright,
36    YellowBright,
37    BlueBright,
38    MagentaBright,
39    CyanBright,
40    WhiteBright,
41}
42
43impl AnsiColor {
44    fn to_string(&self) -> String {
45        match self {
46            AnsiColor::Black => "ansi:black".to_string(),
47            AnsiColor::Red => "ansi:red".to_string(),
48            AnsiColor::Green => "ansi:green".to_string(),
49            AnsiColor::Yellow => "ansi:yellow".to_string(),
50            AnsiColor::Blue => "ansi:blue".to_string(),
51            AnsiColor::Magenta => "ansi:magenta".to_string(),
52            AnsiColor::Cyan => "ansi:cyan".to_string(),
53            AnsiColor::White => "ansi:white".to_string(),
54            AnsiColor::BlackBright => "ansi:blackBright".to_string(),
55            AnsiColor::RedBright => "ansi:redBright".to_string(),
56            AnsiColor::GreenBright => "ansi:greenBright".to_string(),
57            AnsiColor::YellowBright => "ansi:yellowBright".to_string(),
58            AnsiColor::BlueBright => "ansi:blueBright".to_string(),
59            AnsiColor::MagentaBright => "ansi:magentaBright".to_string(),
60            AnsiColor::CyanBright => "ansi:cyanBright".to_string(),
61            AnsiColor::WhiteBright => "ansi:whiteBright".to_string(),
62        }
63    }
64}
65
66/// Theme struct containing all color definitions
67#[derive(Debug, Clone, PartialEq)]
68pub struct Theme {
69    pub auto_accept: ThemeColor,
70    pub bash_border: ThemeColor,
71    pub claude: ThemeColor,
72    pub claude_shimmer: ThemeColor,
73    pub claude_blue_for_system_spinner: ThemeColor,
74    pub claude_blue_shimmer_for_system_spinner: ThemeColor,
75    pub permission: ThemeColor,
76    pub permission_shimmer: ThemeColor,
77    pub plan_mode: ThemeColor,
78    pub ide: ThemeColor,
79    pub prompt_border: ThemeColor,
80    pub prompt_border_shimmer: ThemeColor,
81    pub text: ThemeColor,
82    pub inverse_text: ThemeColor,
83    pub inactive: ThemeColor,
84    pub inactive_shimmer: ThemeColor,
85    pub subtle: ThemeColor,
86    pub suggestion: ThemeColor,
87    pub remember: ThemeColor,
88    pub background: ThemeColor,
89    // Semantic colors
90    pub success: ThemeColor,
91    pub error: ThemeColor,
92    pub warning: ThemeColor,
93    pub merged: ThemeColor,
94    pub warning_shimmer: ThemeColor,
95    // Diff colors
96    pub diff_added: ThemeColor,
97    pub diff_removed: ThemeColor,
98    pub diff_added_dimmed: ThemeColor,
99    pub diff_removed_dimmed: ThemeColor,
100    // Word-level diff highlighting
101    pub diff_added_word: ThemeColor,
102    pub diff_removed_word: ThemeColor,
103    // Agent colors
104    pub red_for_subagents_only: ThemeColor,
105    pub blue_for_subagents_only: ThemeColor,
106    pub green_for_subagents_only: ThemeColor,
107    pub yellow_for_subagents_only: ThemeColor,
108    pub purple_for_subagents_only: ThemeColor,
109    pub orange_for_subagents_only: ThemeColor,
110    pub pink_for_subagents_only: ThemeColor,
111    pub cyan_for_subagents_only: ThemeColor,
112    // Grove colors
113    pub professional_blue: ThemeColor,
114    // Chrome colors
115    pub chrome_yellow: ThemeColor,
116    // TUI V2 colors
117    pub clawd_body: ThemeColor,
118    pub clawd_background: ThemeColor,
119    pub user_message_background: ThemeColor,
120    pub user_message_background_hover: ThemeColor,
121    pub message_actions_background: ThemeColor,
122    pub selection_bg: ThemeColor,
123    pub bash_message_background_color: ThemeColor,
124    pub memory_background_color: ThemeColor,
125    pub rate_limit_fill: ThemeColor,
126    pub rate_limit_empty: ThemeColor,
127    pub fast_mode: ThemeColor,
128    pub fast_mode_shimmer: ThemeColor,
129    // Brief/assistant mode label colors
130    pub brief_label_you: ThemeColor,
131    pub brief_label_claude: ThemeColor,
132    // Rainbow colors for ultrathink keyword highlighting
133    pub rainbow_red: ThemeColor,
134    pub rainbow_orange: ThemeColor,
135    pub rainbow_yellow: ThemeColor,
136    pub rainbow_green: ThemeColor,
137    pub rainbow_blue: ThemeColor,
138    pub rainbow_indigo: ThemeColor,
139    pub rainbow_violet: ThemeColor,
140    pub rainbow_red_shimmer: ThemeColor,
141    pub rainbow_orange_shimmer: ThemeColor,
142    pub rainbow_yellow_shimmer: ThemeColor,
143    pub rainbow_green_shimmer: ThemeColor,
144    pub rainbow_blue_shimmer: ThemeColor,
145    pub rainbow_indigo_shimmer: ThemeColor,
146    pub rainbow_violet_shimmer: ThemeColor,
147}
148
149/// Helper to create RGB color
150fn rgb(r: u8, g: u8, b: u8) -> ThemeColor {
151    ThemeColor::Rgb(r, g, b)
152}
153
154/// Helper to create ANSI color
155fn ansi(color: AnsiColor) -> ThemeColor {
156    ThemeColor::Ansi(color)
157}
158
159/// Light theme using explicit RGB values to avoid inconsistencies
160/// from users' custom terminal ANSI color definitions
161pub static LIGHT_THEME: Lazy<Theme> = Lazy::new(|| Theme {
162    auto_accept: rgb(135, 0, 255),                     // Electric violet
163    bash_border: rgb(255, 0, 135),                     // Vibrant pink
164    claude: rgb(215, 119, 87),                         // Claude orange
165    claude_shimmer: rgb(245, 149, 117),                // Lighter claude orange for shimmer effect
166    claude_blue_for_system_spinner: rgb(87, 105, 247), // Medium blue for system spinner
167    claude_blue_shimmer_for_system_spinner: rgb(117, 135, 255), // Lighter blue for system spinner shimmer
168    permission: rgb(87, 105, 247),                              // Medium blue
169    permission_shimmer: rgb(137, 155, 255),                     // Lighter blue for shimmer effect
170    plan_mode: rgb(0, 102, 102),                                // Muted teal
171    ide: rgb(71, 130, 200),                                     // Muted blue
172    prompt_border: rgb(153, 153, 153),                          // Medium gray
173    prompt_border_shimmer: rgb(183, 183, 183),                  // Lighter gray for shimmer effect
174    text: rgb(0, 0, 0),                                         // Black
175    inverse_text: rgb(255, 255, 255),                           // White
176    inactive: rgb(102, 102, 102),                               // Dark gray
177    inactive_shimmer: rgb(142, 142, 142),                       // Lighter gray for shimmer effect
178    subtle: rgb(175, 175, 175),                                 // Light gray
179    suggestion: rgb(87, 105, 247),                              // Medium blue
180    remember: rgb(0, 0, 255),                                   // Blue
181    background: rgb(0, 153, 153),                               // Cyan
182    success: rgb(44, 122, 57),                                  // Green
183    error: rgb(171, 43, 63),                                    // Red
184    warning: rgb(150, 108, 30),                                 // Amber
185    merged: rgb(135, 0, 255), // Electric violet (matches autoAccept)
186    warning_shimmer: rgb(200, 158, 80), // Lighter amber for shimmer effect
187    diff_added: rgb(105, 219, 124), // Light green
188    diff_removed: rgb(255, 168, 180), // Light red
189    diff_added_dimmed: rgb(199, 225, 203), // Very light green
190    diff_removed_dimmed: rgb(253, 210, 216), // Very light red
191    diff_added_word: rgb(47, 157, 68), // Medium green
192    diff_removed_word: rgb(209, 69, 75), // Medium red
193    // Agent colors
194    red_for_subagents_only: rgb(220, 38, 38),     // Red 600
195    blue_for_subagents_only: rgb(37, 99, 235),    // Blue 600
196    green_for_subagents_only: rgb(22, 163, 74),   // Green 600
197    yellow_for_subagents_only: rgb(202, 138, 4),  // Yellow 600
198    purple_for_subagents_only: rgb(147, 51, 234), // Purple 600
199    orange_for_subagents_only: rgb(234, 88, 12),  // Orange 600
200    pink_for_subagents_only: rgb(219, 39, 119),   // Pink 600
201    cyan_for_subagents_only: rgb(8, 145, 178),    // Cyan 600
202    // Grove colors
203    professional_blue: rgb(106, 155, 204),
204    // Chrome colors
205    chrome_yellow: rgb(251, 188, 4), // Chrome yellow
206    // TUI V2 colors
207    clawd_body: rgb(215, 119, 87),
208    clawd_background: rgb(0, 0, 0),
209    user_message_background: rgb(240, 240, 240), // Slightly darker grey for optimal contrast
210    user_message_background_hover: rgb(252, 252, 252), // >=250 to quantize distinct from base at 256-color level
211    message_actions_background: rgb(232, 236, 244), // cool gray -- darker than userMsg 240 (visible on white), slight blue toward `suggestion`
212    selection_bg: rgb(180, 213, 255), // classic light-mode selection blue (macOS/VS Code-ish); dark fgs stay readable
213    bash_message_background_color: rgb(250, 245, 250),
214    memory_background_color: rgb(230, 245, 250),
215    rate_limit_fill: rgb(87, 105, 247),   // Medium blue
216    rate_limit_empty: rgb(39, 47, 111),   // Dark blue
217    fast_mode: rgb(255, 106, 0),          // Electric orange
218    fast_mode_shimmer: rgb(255, 150, 50), // Lighter orange for shimmer
219    // Brief/assistant mode
220    brief_label_you: rgb(37, 99, 235),     // Blue
221    brief_label_claude: rgb(215, 119, 87), // Brand orange
222    rainbow_red: rgb(235, 95, 87),
223    rainbow_orange: rgb(245, 139, 87),
224    rainbow_yellow: rgb(250, 195, 95),
225    rainbow_green: rgb(145, 200, 130),
226    rainbow_blue: rgb(130, 170, 220),
227    rainbow_indigo: rgb(155, 130, 200),
228    rainbow_violet: rgb(200, 130, 180),
229    rainbow_red_shimmer: rgb(250, 155, 147),
230    rainbow_orange_shimmer: rgb(255, 185, 137),
231    rainbow_yellow_shimmer: rgb(255, 225, 155),
232    rainbow_green_shimmer: rgb(185, 230, 180),
233    rainbow_blue_shimmer: rgb(180, 205, 240),
234    rainbow_indigo_shimmer: rgb(195, 180, 230),
235    rainbow_violet_shimmer: rgb(230, 180, 210),
236});
237
238/// Light ANSI theme using only the 16 standard ANSI colors
239/// for terminals without true color support
240pub static LIGHT_ANSI_THEME: Lazy<Theme> = Lazy::new(|| Theme {
241    auto_accept: ansi(AnsiColor::Magenta),
242    bash_border: ansi(AnsiColor::Magenta),
243    claude: ansi(AnsiColor::RedBright),
244    claude_shimmer: ansi(AnsiColor::YellowBright),
245    claude_blue_for_system_spinner: ansi(AnsiColor::Blue),
246    claude_blue_shimmer_for_system_spinner: ansi(AnsiColor::BlueBright),
247    permission: ansi(AnsiColor::Blue),
248    permission_shimmer: ansi(AnsiColor::BlueBright),
249    plan_mode: ansi(AnsiColor::Cyan),
250    ide: ansi(AnsiColor::BlueBright),
251    prompt_border: ansi(AnsiColor::White),
252    prompt_border_shimmer: ansi(AnsiColor::WhiteBright),
253    text: ansi(AnsiColor::Black),
254    inverse_text: ansi(AnsiColor::White),
255    inactive: ansi(AnsiColor::BlackBright),
256    inactive_shimmer: ansi(AnsiColor::White),
257    subtle: ansi(AnsiColor::BlackBright),
258    suggestion: ansi(AnsiColor::Blue),
259    remember: ansi(AnsiColor::Blue),
260    background: ansi(AnsiColor::Cyan),
261    success: ansi(AnsiColor::Green),
262    error: ansi(AnsiColor::Red),
263    warning: ansi(AnsiColor::Yellow),
264    merged: ansi(AnsiColor::Magenta),
265    warning_shimmer: ansi(AnsiColor::YellowBright),
266    diff_added: ansi(AnsiColor::Green),
267    diff_removed: ansi(AnsiColor::Red),
268    diff_added_dimmed: ansi(AnsiColor::Green),
269    diff_removed_dimmed: ansi(AnsiColor::Red),
270    diff_added_word: ansi(AnsiColor::GreenBright),
271    diff_removed_word: ansi(AnsiColor::RedBright),
272    // Agent colors
273    red_for_subagents_only: ansi(AnsiColor::Red),
274    blue_for_subagents_only: ansi(AnsiColor::Blue),
275    green_for_subagents_only: ansi(AnsiColor::Green),
276    yellow_for_subagents_only: ansi(AnsiColor::Yellow),
277    purple_for_subagents_only: ansi(AnsiColor::Magenta),
278    orange_for_subagents_only: ansi(AnsiColor::RedBright),
279    pink_for_subagents_only: ansi(AnsiColor::MagentaBright),
280    cyan_for_subagents_only: ansi(AnsiColor::Cyan),
281    // Grove colors
282    professional_blue: ansi(AnsiColor::BlueBright),
283    // Chrome colors
284    chrome_yellow: ansi(AnsiColor::Yellow),
285    // TUI V2 colors
286    clawd_body: ansi(AnsiColor::RedBright),
287    clawd_background: ansi(AnsiColor::Black),
288    user_message_background: ansi(AnsiColor::White),
289    user_message_background_hover: ansi(AnsiColor::WhiteBright),
290    message_actions_background: ansi(AnsiColor::White),
291    selection_bg: ansi(AnsiColor::Cyan),
292    bash_message_background_color: ansi(AnsiColor::WhiteBright),
293    memory_background_color: ansi(AnsiColor::White),
294    rate_limit_fill: ansi(AnsiColor::Yellow),
295    rate_limit_empty: ansi(AnsiColor::Black),
296    fast_mode: ansi(AnsiColor::Red),
297    fast_mode_shimmer: ansi(AnsiColor::RedBright),
298    brief_label_you: ansi(AnsiColor::Blue),
299    brief_label_claude: ansi(AnsiColor::RedBright),
300    rainbow_red: ansi(AnsiColor::Red),
301    rainbow_orange: ansi(AnsiColor::RedBright),
302    rainbow_yellow: ansi(AnsiColor::Yellow),
303    rainbow_green: ansi(AnsiColor::Green),
304    rainbow_blue: ansi(AnsiColor::Cyan),
305    rainbow_indigo: ansi(AnsiColor::Blue),
306    rainbow_violet: ansi(AnsiColor::Magenta),
307    rainbow_red_shimmer: ansi(AnsiColor::RedBright),
308    rainbow_orange_shimmer: ansi(AnsiColor::Yellow),
309    rainbow_yellow_shimmer: ansi(AnsiColor::YellowBright),
310    rainbow_green_shimmer: ansi(AnsiColor::GreenBright),
311    rainbow_blue_shimmer: ansi(AnsiColor::CyanBright),
312    rainbow_indigo_shimmer: ansi(AnsiColor::BlueBright),
313    rainbow_violet_shimmer: ansi(AnsiColor::MagentaBright),
314});
315
316/// Dark ANSI theme using only the 16 standard ANSI colors
317/// for terminals without true color support
318pub static DARK_ANSI_THEME: Lazy<Theme> = Lazy::new(|| Theme {
319    auto_accept: ansi(AnsiColor::MagentaBright),
320    bash_border: ansi(AnsiColor::MagentaBright),
321    claude: ansi(AnsiColor::RedBright),
322    claude_shimmer: ansi(AnsiColor::YellowBright),
323    claude_blue_for_system_spinner: ansi(AnsiColor::BlueBright),
324    claude_blue_shimmer_for_system_spinner: ansi(AnsiColor::BlueBright),
325    permission: ansi(AnsiColor::BlueBright),
326    permission_shimmer: ansi(AnsiColor::BlueBright),
327    plan_mode: ansi(AnsiColor::CyanBright),
328    ide: ansi(AnsiColor::Blue),
329    prompt_border: ansi(AnsiColor::White),
330    prompt_border_shimmer: ansi(AnsiColor::WhiteBright),
331    text: ansi(AnsiColor::WhiteBright),
332    inverse_text: ansi(AnsiColor::Black),
333    inactive: ansi(AnsiColor::White),
334    inactive_shimmer: ansi(AnsiColor::WhiteBright),
335    subtle: ansi(AnsiColor::White),
336    suggestion: ansi(AnsiColor::BlueBright),
337    remember: ansi(AnsiColor::BlueBright),
338    background: ansi(AnsiColor::CyanBright),
339    success: ansi(AnsiColor::GreenBright),
340    error: ansi(AnsiColor::RedBright),
341    warning: ansi(AnsiColor::YellowBright),
342    merged: ansi(AnsiColor::MagentaBright),
343    warning_shimmer: ansi(AnsiColor::YellowBright),
344    diff_added: ansi(AnsiColor::Green),
345    diff_removed: ansi(AnsiColor::Red),
346    diff_added_dimmed: ansi(AnsiColor::Green),
347    diff_removed_dimmed: ansi(AnsiColor::Red),
348    diff_added_word: ansi(AnsiColor::GreenBright),
349    diff_removed_word: ansi(AnsiColor::RedBright),
350    // Agent colors
351    red_for_subagents_only: ansi(AnsiColor::RedBright),
352    blue_for_subagents_only: ansi(AnsiColor::BlueBright),
353    green_for_subagents_only: ansi(AnsiColor::GreenBright),
354    yellow_for_subagents_only: ansi(AnsiColor::YellowBright),
355    purple_for_subagents_only: ansi(AnsiColor::MagentaBright),
356    orange_for_subagents_only: ansi(AnsiColor::RedBright),
357    pink_for_subagents_only: ansi(AnsiColor::MagentaBright),
358    cyan_for_subagents_only: ansi(AnsiColor::CyanBright),
359    // Grove colors
360    professional_blue: rgb(106, 155, 204),
361    // Chrome colors
362    chrome_yellow: ansi(AnsiColor::YellowBright),
363    // TUI V2 colors
364    clawd_body: ansi(AnsiColor::RedBright),
365    clawd_background: ansi(AnsiColor::Black),
366    user_message_background: ansi(AnsiColor::BlackBright),
367    user_message_background_hover: ansi(AnsiColor::White),
368    message_actions_background: ansi(AnsiColor::BlackBright),
369    selection_bg: ansi(AnsiColor::Blue),
370    bash_message_background_color: ansi(AnsiColor::Black),
371    memory_background_color: ansi(AnsiColor::BlackBright),
372    rate_limit_fill: ansi(AnsiColor::Yellow),
373    rate_limit_empty: ansi(AnsiColor::White),
374    fast_mode: ansi(AnsiColor::RedBright),
375    fast_mode_shimmer: ansi(AnsiColor::RedBright),
376    brief_label_you: ansi(AnsiColor::BlueBright),
377    brief_label_claude: ansi(AnsiColor::RedBright),
378    rainbow_red: ansi(AnsiColor::Red),
379    rainbow_orange: ansi(AnsiColor::RedBright),
380    rainbow_yellow: ansi(AnsiColor::Yellow),
381    rainbow_green: ansi(AnsiColor::Green),
382    rainbow_blue: ansi(AnsiColor::Cyan),
383    rainbow_indigo: ansi(AnsiColor::Blue),
384    rainbow_violet: ansi(AnsiColor::Magenta),
385    rainbow_red_shimmer: ansi(AnsiColor::RedBright),
386    rainbow_orange_shimmer: ansi(AnsiColor::Yellow),
387    rainbow_yellow_shimmer: ansi(AnsiColor::YellowBright),
388    rainbow_green_shimmer: ansi(AnsiColor::GreenBright),
389    rainbow_blue_shimmer: ansi(AnsiColor::CyanBright),
390    rainbow_indigo_shimmer: ansi(AnsiColor::BlueBright),
391    rainbow_violet_shimmer: ansi(AnsiColor::MagentaBright),
392});
393
394/// Light daltonized theme (color-blind friendly) using explicit RGB values
395/// to avoid inconsistencies from users' custom terminal ANSI color definitions
396pub static LIGHT_DALTONIZED_THEME: Lazy<Theme> = Lazy::new(|| Theme {
397    auto_accept: rgb(135, 0, 255),                     // Electric violet
398    bash_border: rgb(0, 102, 204),                     // Blue instead of pink
399    claude: rgb(255, 153, 51),                         // Orange adjusted for deuteranopia
400    claude_shimmer: rgb(255, 183, 101),                // Lighter orange for shimmer effect
401    claude_blue_for_system_spinner: rgb(51, 102, 255), // Bright blue for system spinner
402    claude_blue_shimmer_for_system_spinner: rgb(101, 152, 255), // Lighter bright blue for system spinner shimmer
403    permission: rgb(51, 102, 255),                              // Bright blue
404    permission_shimmer: rgb(101, 152, 255),                     // Lighter bright blue for shimmer
405    plan_mode: rgb(51, 102, 102), // Muted blue-gray (works for color-blind)
406    ide: rgb(71, 130, 200),       // Muted blue
407    prompt_border: rgb(153, 153, 153), // Medium gray
408    prompt_border_shimmer: rgb(183, 183, 183), // Lighter gray for shimmer
409    text: rgb(0, 0, 0),           // Black
410    inverse_text: rgb(255, 255, 255), // White
411    inactive: rgb(102, 102, 102), // Dark gray
412    inactive_shimmer: rgb(142, 142, 142), // Lighter gray for shimmer effect
413    subtle: rgb(175, 175, 175),   // Light gray
414    suggestion: rgb(51, 102, 255), // Bright blue
415    remember: rgb(51, 102, 255),  // Bright blue
416    background: rgb(0, 153, 153), // Cyan (color-blind friendly)
417    success: rgb(0, 102, 153),    // Blue instead of green for deuteranopia
418    error: rgb(204, 0, 0),        // Pure red for better distinction
419    warning: rgb(255, 153, 0),    // Orange adjusted for deuteranopia
420    merged: rgb(135, 0, 255),     // Electric violet (matches autoAccept)
421    warning_shimmer: rgb(255, 183, 50), // Lighter orange for shimmer
422    diff_added: rgb(153, 204, 255), // Light blue instead of green
423    diff_removed: rgb(255, 204, 204), // Light red
424    diff_added_dimmed: rgb(209, 231, 253), // Very light blue
425    diff_removed_dimmed: rgb(255, 233, 233), // Very light red
426    diff_added_word: rgb(51, 102, 204), // Medium blue (less intense than deep blue)
427    diff_removed_word: rgb(153, 51, 51), // Softer red (less intense than deep red)
428    // Agent colors (daltonism-friendly)
429    red_for_subagents_only: rgb(204, 0, 0),      // Pure red
430    blue_for_subagents_only: rgb(0, 102, 204),   // Pure blue
431    green_for_subagents_only: rgb(0, 204, 0),    // Pure green
432    yellow_for_subagents_only: rgb(255, 204, 0), // Golden yellow
433    purple_for_subagents_only: rgb(128, 0, 128), // True purple
434    orange_for_subagents_only: rgb(255, 128, 0), // True orange
435    pink_for_subagents_only: rgb(255, 102, 178), // Adjusted pink
436    cyan_for_subagents_only: rgb(0, 178, 178),   // Adjusted cyan
437    // Grove colors
438    professional_blue: rgb(106, 155, 204),
439    // Chrome colors
440    chrome_yellow: rgb(251, 188, 4), // Chrome yellow
441    // TUI V2 colors
442    clawd_body: rgb(215, 119, 87),
443    clawd_background: rgb(0, 0, 0),
444    user_message_background: rgb(220, 220, 220), // Slightly darker grey for optimal contrast
445    user_message_background_hover: rgb(232, 232, 232), // >=230 to quantize distinct from base at 256-color level
446    message_actions_background: rgb(210, 216, 226), // cool gray -- darker than userMsg 220, slight blue
447    selection_bg: rgb(180, 213, 255), // light selection blue; daltonized fgs are yellows/blues, both readable on light blue
448    bash_message_background_color: rgb(250, 245, 250),
449    memory_background_color: rgb(230, 245, 250),
450    rate_limit_fill: rgb(51, 102, 255),    // Bright blue
451    rate_limit_empty: rgb(23, 46, 114),    // Dark blue
452    fast_mode: rgb(255, 106, 0),           // Electric orange (color-blind safe)
453    fast_mode_shimmer: rgb(255, 150, 50),  // Lighter orange for shimmer
454    brief_label_you: rgb(37, 99, 235),     // Blue
455    brief_label_claude: rgb(255, 153, 51), // Orange adjusted for deuteranopia (matches claude)
456    rainbow_red: rgb(235, 95, 87),
457    rainbow_orange: rgb(245, 139, 87),
458    rainbow_yellow: rgb(250, 195, 95),
459    rainbow_green: rgb(145, 200, 130),
460    rainbow_blue: rgb(130, 170, 220),
461    rainbow_indigo: rgb(155, 130, 200),
462    rainbow_violet: rgb(200, 130, 180),
463    rainbow_red_shimmer: rgb(250, 155, 147),
464    rainbow_orange_shimmer: rgb(255, 185, 137),
465    rainbow_yellow_shimmer: rgb(255, 225, 155),
466    rainbow_green_shimmer: rgb(185, 230, 180),
467    rainbow_blue_shimmer: rgb(180, 205, 240),
468    rainbow_indigo_shimmer: rgb(195, 180, 230),
469    rainbow_violet_shimmer: rgb(230, 180, 210),
470});
471
472/// Dark theme using explicit RGB values to avoid inconsistencies
473/// from users' custom terminal ANSI color definitions
474pub static DARK_THEME: Lazy<Theme> = Lazy::new(|| Theme {
475    auto_accept: rgb(175, 135, 255),                    // Electric violet
476    bash_border: rgb(253, 93, 177),                     // Bright pink
477    claude: rgb(215, 119, 87),                          // Claude orange
478    claude_shimmer: rgb(235, 159, 127),                 // Lighter claude orange for shimmer effect
479    claude_blue_for_system_spinner: rgb(147, 165, 255), // Blue for system spinner
480    claude_blue_shimmer_for_system_spinner: rgb(177, 195, 255), // Lighter blue for system spinner shimmer
481    permission: rgb(177, 185, 249),                             // Light blue-purple
482    permission_shimmer: rgb(207, 215, 255),                     // Lighter blue-purple for shimmer
483    plan_mode: rgb(72, 150, 140),                               // Muted sage green
484    ide: rgb(71, 130, 200),                                     // Muted blue
485    prompt_border: rgb(136, 136, 136),                          // Medium gray
486    prompt_border_shimmer: rgb(166, 166, 166),                  // Lighter gray for shimmer
487    text: rgb(255, 255, 255),                                   // White
488    inverse_text: rgb(0, 0, 0),                                 // Black
489    inactive: rgb(153, 153, 153),                               // Light gray
490    inactive_shimmer: rgb(193, 193, 193),                       // Lighter gray for shimmer effect
491    subtle: rgb(80, 80, 80),                                    // Dark gray
492    suggestion: rgb(177, 185, 249),                             // Light blue-purple
493    remember: rgb(177, 185, 249),                               // Light blue-purple
494    background: rgb(0, 204, 204),                               // Bright cyan
495    success: rgb(78, 186, 101),                                 // Bright green
496    error: rgb(255, 107, 128),                                  // Bright red
497    warning: rgb(255, 193, 7),                                  // Bright amber
498    merged: rgb(175, 135, 255), // Electric violet (matches autoAccept)
499    warning_shimmer: rgb(255, 223, 57), // Lighter amber for shimmer
500    diff_added: rgb(34, 92, 43), // Dark green
501    diff_removed: rgb(122, 41, 54), // Dark red
502    diff_added_dimmed: rgb(71, 88, 74), // Very dark green
503    diff_removed_dimmed: rgb(105, 72, 77), // Very dark red
504    diff_added_word: rgb(56, 166, 96), // Medium green
505    diff_removed_word: rgb(179, 89, 107), // Softer red (less intense than bright red)
506    // Agent colors
507    red_for_subagents_only: rgb(220, 38, 38),     // Red 600
508    blue_for_subagents_only: rgb(37, 99, 235),    // Blue 600
509    green_for_subagents_only: rgb(22, 163, 74),   // Green 600
510    yellow_for_subagents_only: rgb(202, 138, 4),  // Yellow 600
511    purple_for_subagents_only: rgb(147, 51, 234), // Purple 600
512    orange_for_subagents_only: rgb(234, 88, 12),  // Orange 600
513    pink_for_subagents_only: rgb(219, 39, 119),   // Pink 600
514    cyan_for_subagents_only: rgb(8, 145, 178),    // Cyan 600
515    // Grove colors
516    professional_blue: rgb(106, 155, 204),
517    // Chrome colors
518    chrome_yellow: rgb(251, 188, 4), // Chrome yellow
519    // TUI V2 colors
520    clawd_body: rgb(215, 119, 87),
521    clawd_background: rgb(0, 0, 0),
522    user_message_background: rgb(55, 55, 55), // Lighter grey for better visual contrast
523    user_message_background_hover: rgb(70, 70, 70),
524    message_actions_background: rgb(44, 50, 62), // cool gray, slight blue
525    selection_bg: rgb(38, 79, 120), // classic dark-mode selection blue (VS Code dark default); light fgs stay readable
526    bash_message_background_color: rgb(65, 60, 65),
527    memory_background_color: rgb(55, 65, 70),
528    rate_limit_fill: rgb(177, 185, 249),   // Light blue-purple
529    rate_limit_empty: rgb(80, 83, 112),    // Medium blue-purple
530    fast_mode: rgb(255, 120, 20),          // Electric orange for dark bg
531    fast_mode_shimmer: rgb(255, 165, 70),  // Lighter orange for shimmer
532    brief_label_you: rgb(122, 180, 232),   // Light blue
533    brief_label_claude: rgb(215, 119, 87), // Brand orange
534    rainbow_red: rgb(235, 95, 87),
535    rainbow_orange: rgb(245, 139, 87),
536    rainbow_yellow: rgb(250, 195, 95),
537    rainbow_green: rgb(145, 200, 130),
538    rainbow_blue: rgb(130, 170, 220),
539    rainbow_indigo: rgb(155, 130, 200),
540    rainbow_violet: rgb(200, 130, 180),
541    rainbow_red_shimmer: rgb(250, 155, 147),
542    rainbow_orange_shimmer: rgb(255, 185, 137),
543    rainbow_yellow_shimmer: rgb(255, 225, 155),
544    rainbow_green_shimmer: rgb(185, 230, 180),
545    rainbow_blue_shimmer: rgb(180, 205, 240),
546    rainbow_indigo_shimmer: rgb(195, 180, 230),
547    rainbow_violet_shimmer: rgb(230, 180, 210),
548});
549
550/// Dark daltonized theme (color-blind friendly) using explicit RGB values
551/// to avoid inconsistencies from users' custom terminal ANSI color definitions
552pub static DARK_DALTONIZED_THEME: Lazy<Theme> = Lazy::new(|| Theme {
553    auto_accept: rgb(175, 135, 255),                    // Electric violet
554    bash_border: rgb(51, 153, 255),                     // Bright blue
555    claude: rgb(255, 153, 51),                          // Orange adjusted for deuteranopia
556    claude_shimmer: rgb(255, 183, 101),                 // Lighter orange for shimmer effect
557    claude_blue_for_system_spinner: rgb(153, 204, 255), // Light blue for system spinner
558    claude_blue_shimmer_for_system_spinner: rgb(183, 224, 255), // Lighter blue for system spinner shimmer
559    permission: rgb(153, 204, 255),                             // Light blue
560    permission_shimmer: rgb(183, 224, 255),                     // Lighter blue for shimmer
561    plan_mode: rgb(102, 153, 153), // Muted gray-teal (works for color-blind)
562    ide: rgb(71, 130, 200),        // Muted blue
563    prompt_border: rgb(136, 136, 136), // Medium gray
564    prompt_border_shimmer: rgb(166, 166, 166), // Lighter gray for shimmer
565    text: rgb(255, 255, 255),      // White
566    inverse_text: rgb(0, 0, 0),    // Black
567    inactive: rgb(153, 153, 153),  // Light gray
568    inactive_shimmer: rgb(193, 193, 193), // Lighter gray for shimmer effect
569    subtle: rgb(80, 80, 80),       // Dark gray
570    suggestion: rgb(153, 204, 255), // Light blue
571    remember: rgb(153, 204, 255),  // Light blue
572    background: rgb(0, 204, 204),  // Bright cyan (color-blind friendly)
573    success: rgb(51, 153, 255),    // Blue instead of green
574    error: rgb(255, 102, 102),     // Bright red
575    warning: rgb(255, 204, 0),     // Yellow-orange for deuteranopia
576    merged: rgb(175, 135, 255),    // Electric violet (matches autoAccept)
577    warning_shimmer: rgb(255, 234, 50), // Lighter yellow-orange for shimmer
578    diff_added: rgb(0, 68, 102),   // Dark blue
579    diff_removed: rgb(102, 0, 0),  // Dark red
580    diff_added_dimmed: rgb(62, 81, 91), // Dimmed blue
581    diff_removed_dimmed: rgb(62, 44, 44), // Dimmed red
582    diff_added_word: rgb(0, 119, 179), // Medium blue
583    diff_removed_word: rgb(179, 0, 0), // Medium red
584    // Agent colors (daltonism-friendly, dark mode)
585    red_for_subagents_only: rgb(255, 102, 102), // Bright red
586    blue_for_subagents_only: rgb(102, 178, 255), // Bright blue
587    green_for_subagents_only: rgb(102, 255, 102), // Bright green
588    yellow_for_subagents_only: rgb(255, 255, 102), // Bright yellow
589    purple_for_subagents_only: rgb(178, 102, 255), // Bright purple
590    orange_for_subagents_only: rgb(255, 178, 102), // Bright orange
591    pink_for_subagents_only: rgb(255, 153, 204), // Bright pink
592    cyan_for_subagents_only: rgb(102, 204, 204), // Bright cyan
593    // Grove colors
594    professional_blue: rgb(106, 155, 204),
595    // Chrome colors
596    chrome_yellow: rgb(251, 188, 4), // Chrome yellow
597    // TUI V2 colors
598    clawd_body: rgb(215, 119, 87),
599    clawd_background: rgb(0, 0, 0),
600    user_message_background: rgb(55, 55, 55), // Lighter grey for better visual contrast
601    user_message_background_hover: rgb(70, 70, 70),
602    message_actions_background: rgb(44, 50, 62), // cool gray, slight blue
603    selection_bg: rgb(38, 79, 120), // classic dark-mode selection blue (VS Code dark default); light fgs stay readable
604    bash_message_background_color: rgb(65, 60, 65),
605    memory_background_color: rgb(55, 65, 70),
606    rate_limit_fill: rgb(153, 204, 255),   // Light blue
607    rate_limit_empty: rgb(69, 92, 115),    // Dark blue
608    fast_mode: rgb(255, 120, 20),          // Electric orange for dark bg (color-blind safe)
609    fast_mode_shimmer: rgb(255, 165, 70),  // Lighter orange for shimmer
610    brief_label_you: rgb(122, 180, 232),   // Light blue
611    brief_label_claude: rgb(255, 153, 51), // Orange adjusted for deuteranopia (matches claude)
612    rainbow_red: rgb(235, 95, 87),
613    rainbow_orange: rgb(245, 139, 87),
614    rainbow_yellow: rgb(250, 195, 95),
615    rainbow_green: rgb(145, 200, 130),
616    rainbow_blue: rgb(130, 170, 220),
617    rainbow_indigo: rgb(155, 130, 200),
618    rainbow_violet: rgb(200, 130, 180),
619    rainbow_red_shimmer: rgb(250, 155, 147),
620    rainbow_orange_shimmer: rgb(255, 185, 137),
621    rainbow_yellow_shimmer: rgb(255, 225, 155),
622    rainbow_green_shimmer: rgb(185, 230, 180),
623    rainbow_blue_shimmer: rgb(180, 205, 240),
624    rainbow_indigo_shimmer: rgb(195, 180, 230),
625    rainbow_violet_shimmer: rgb(230, 180, 210),
626});
627
628/// Theme names
629pub const THEME_NAMES: &[&str] = &[
630    "dark",
631    "light",
632    "light-daltonized",
633    "dark-daltonized",
634    "light-ansi",
635    "dark-ansi",
636];
637
638/// Get theme by name
639pub fn get_theme(theme_name: &str) -> &'static Theme {
640    match theme_name {
641        "light" => &LIGHT_THEME,
642        "light-ansi" => &LIGHT_ANSI_THEME,
643        "dark-ansi" => &DARK_ANSI_THEME,
644        "light-daltonized" => &LIGHT_DALTONIZED_THEME,
645        "dark-daltonized" => &DARK_DALTONIZED_THEME,
646        _ => &DARK_THEME,
647    }
648}
649
650/// Converts a theme color to an ANSI escape sequence for use with asciichart.
651pub fn theme_color_to_ansi(theme_color: &str) -> String {
652    // Try to parse rgb(r, g, b) format
653    if let Some(caps) = regex::Regex::new(r"rgb\(\s?(\d+),\s?(\d+),\s?(\d+)\s?\)")
654        .ok()
655        .and_then(|r| r.captures(theme_color))
656    {
657        let r: u8 = caps[1].parse().unwrap_or(0);
658        let g: u8 = caps[2].parse().unwrap_or(0);
659        let b: u8 = caps[3].parse().unwrap_or(0);
660        // Convert to 256-color ANSI escape
661        if r == g && g == b {
662            // Grayscale
663            let gray = if r < 8 {
664                16
665            } else if r > 248 {
666                231
667            } else {
668                ((r as f64 - 8.0) / 10.0).floor() as u8 + 232
669            };
670            return format!("\x1b[38;5;{}m", gray);
671        }
672        // Color cube
673        let r_level = ((r as f64) / 51.0).round() as u8;
674        let g_level = ((g as f64) / 51.0).round() as u8;
675        let b_level = ((b as f64) / 51.0).round() as u8;
676        let color = 16 + r_level * 36 + g_level * 6 + b_level;
677        return format!("\x1b[38;5;{}m", color);
678    }
679    // Fallback to magenta if parsing fails
680    "\x1b[35m".to_string()
681}
682
683#[cfg(test)]
684mod tests {
685    use super::*;
686
687    #[test]
688    fn test_get_theme() {
689        // Theme retrieval works - just check they return the same pointer
690        let dark1 = get_theme("dark");
691        let dark2 = get_theme("dark");
692        assert!(std::ptr::eq(dark1, dark2));
693    }
694
695    #[test]
696    fn test_theme_color_to_ansi() {
697        // Black
698        let result = theme_color_to_ansi("rgb(0, 0, 0)");
699        assert!(result.contains("38;5;"));
700
701        // White
702        let result = theme_color_to_ansi("rgb(255, 255, 255)");
703        assert!(result.contains("38;5;"));
704
705        // Red
706        let result = theme_color_to_ansi("rgb(255, 0, 0)");
707        assert!(result.contains("38;5;"));
708    }
709}