use ratatui::style::Color;
#[derive(Clone, Debug, PartialEq)]
pub struct Theme {
pub name: &'static str,
pub status_bg: Color,
pub status_fg: Color,
pub status_mode_fg: Color,
pub status_cost_fg: Color,
pub status_dim_fg: Color,
pub input_border: Color,
pub input_prompt_fg: Color,
pub input_bash_fg: Color,
pub input_note_fg: Color,
pub input_command_fg: Color,
pub input_atfile_fg: Color,
pub user_bar: Color,
pub assistant_bar: Color,
pub system_bar: Color,
pub tool_call_icon: Color,
pub tool_ok_fg: Color,
pub tool_err_fg: Color,
pub code_fg: Color,
pub diff_add: Color,
pub diff_del: Color,
}
pub const DARK: Theme = Theme {
name: "dark",
status_bg: Color::DarkGray,
status_fg: Color::White,
status_mode_fg: Color::Green,
status_cost_fg: Color::Cyan,
status_dim_fg: Color::DarkGray,
input_border: Color::DarkGray,
input_prompt_fg: Color::Cyan,
input_bash_fg: Color::Yellow,
input_note_fg: Color::Green,
input_command_fg: Color::Magenta,
input_atfile_fg: Color::Cyan,
user_bar: Color::Blue,
assistant_bar: Color::Green,
system_bar: Color::DarkGray,
tool_call_icon: Color::Yellow,
tool_ok_fg: Color::Green,
tool_err_fg: Color::Red,
code_fg: Color::Cyan,
diff_add: Color::Green,
diff_del: Color::Red,
};
pub const LIGHT: Theme = Theme {
name: "light",
status_bg: Color::Gray,
status_fg: Color::Black,
status_mode_fg: Color::Blue,
status_cost_fg: Color::DarkGray,
status_dim_fg: Color::Gray,
input_border: Color::Gray,
input_prompt_fg: Color::Blue,
input_bash_fg: Color::Rgb(180, 100, 0),
input_note_fg: Color::Rgb(0, 120, 0),
input_command_fg: Color::Rgb(100, 0, 150),
input_atfile_fg: Color::Blue,
user_bar: Color::Blue,
assistant_bar: Color::Rgb(0, 130, 0),
system_bar: Color::Gray,
tool_call_icon: Color::Rgb(180, 100, 0),
tool_ok_fg: Color::Rgb(0, 130, 0),
tool_err_fg: Color::Red,
code_fg: Color::Blue,
diff_add: Color::Rgb(0, 130, 0),
diff_del: Color::Red,
};
pub const SOLARIZED: Theme = Theme {
name: "solarized",
status_bg: Color::Rgb(7, 54, 66),
status_fg: Color::Rgb(131, 148, 150),
status_mode_fg: Color::Rgb(38, 139, 210),
status_cost_fg: Color::Rgb(42, 161, 152),
status_dim_fg: Color::Rgb(88, 110, 117),
input_border: Color::Rgb(88, 110, 117),
input_prompt_fg: Color::Rgb(42, 161, 152),
input_bash_fg: Color::Rgb(181, 137, 0),
input_note_fg: Color::Rgb(133, 153, 0),
input_command_fg: Color::Rgb(108, 113, 196),
input_atfile_fg: Color::Rgb(42, 161, 152),
user_bar: Color::Rgb(38, 139, 210),
assistant_bar: Color::Rgb(133, 153, 0),
system_bar: Color::Rgb(88, 110, 117),
tool_call_icon: Color::Rgb(181, 137, 0),
tool_ok_fg: Color::Rgb(133, 153, 0),
tool_err_fg: Color::Rgb(220, 50, 47),
code_fg: Color::Rgb(42, 161, 152),
diff_add: Color::Rgb(133, 153, 0),
diff_del: Color::Rgb(220, 50, 47),
};
pub const ALL_THEMES: &[&Theme] = &[&DARK, &LIGHT, &SOLARIZED];
pub fn find_theme(name: &str) -> &'static Theme {
ALL_THEMES
.iter()
.copied()
.find(|t| t.name == name)
.unwrap_or(&DARK)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn dark_theme_has_expected_name() {
assert_eq!(DARK.name, "dark");
}
#[test]
fn find_theme_returns_dark_for_unknown() {
assert_eq!(find_theme("nope").name, "dark");
assert_eq!(find_theme("").name, "dark");
}
#[test]
fn all_themes_have_unique_names() {
let names: Vec<&str> = ALL_THEMES.iter().map(|t| t.name).collect();
let unique: std::collections::HashSet<&&str> = names.iter().collect();
assert_eq!(names.len(), unique.len(), "duplicate theme names");
}
#[test]
fn find_theme_returns_correct_theme() {
assert_eq!(find_theme("light").name, "light");
assert_eq!(find_theme("solarized").name, "solarized");
assert_eq!(find_theme("dark").name, "dark");
}
}