use rnk::prelude::Color;
use std::sync::OnceLock;
enum TerminalThemeKind {
Dark,
Light,
NoColor,
}
#[derive(Clone, Copy, Debug)]
#[allow(dead_code)]
pub struct TerminalTheme {
pub text_primary: Color,
pub text_muted: Color,
pub text_subtle: Color,
pub accent_assistant: Color,
pub accent_user: Color,
pub accent_system: Color,
pub accent_primary: Color,
pub border: Color,
pub border_subtle: Color,
pub separator: Color,
pub surface: Color,
pub ok: Color,
pub warn: Color,
pub err: Color,
pub tool: Color,
pub tool_param: Color,
pub status_normal: Color,
pub status_bypass: Color,
pub status_plan: Color,
}
static THEME: OnceLock<TerminalTheme> = OnceLock::new();
pub fn current_theme() -> &'static TerminalTheme {
THEME.get_or_init(|| match detect_theme_kind() {
TerminalThemeKind::Light => light_theme(),
TerminalThemeKind::NoColor => no_color_theme(),
TerminalThemeKind::Dark => dark_theme(),
})
}
fn detect_theme_kind() -> TerminalThemeKind {
if std::env::var_os("NO_COLOR").is_some() {
return TerminalThemeKind::NoColor;
}
if let Ok(v) = std::env::var("SAGE_THEME") {
match v.to_ascii_lowercase().as_str() {
"light" => return TerminalThemeKind::Light,
"dark" => return TerminalThemeKind::Dark,
"none" | "no" | "off" => return TerminalThemeKind::NoColor,
_ => {}
}
}
if let Ok(cfgbg) = std::env::var("COLORFGBG") {
if let Some(bg) = cfgbg.rsplit(';').next().and_then(|s| s.parse::<u8>().ok()) {
if bg >= 7 {
return TerminalThemeKind::Light;
}
}
}
TerminalThemeKind::Light
}
fn dark_theme() -> TerminalTheme {
TerminalTheme {
text_primary: Color::Rgb(205, 214, 244), text_muted: Color::Rgb(108, 112, 134), text_subtle: Color::Rgb(88, 91, 112),
accent_assistant: Color::Rgb(137, 180, 250), accent_user: Color::Rgb(166, 227, 161), accent_system: Color::Rgb(203, 166, 247), accent_primary: Color::Rgb(137, 180, 250),
border: Color::Rgb(88, 91, 112), border_subtle: Color::Rgb(69, 71, 90), separator: Color::Rgb(69, 71, 90),
surface: Color::Rgb(49, 50, 68),
ok: Color::Rgb(166, 227, 161), warn: Color::Rgb(249, 226, 175), err: Color::Rgb(243, 139, 168),
tool: Color::Rgb(203, 166, 247), tool_param: Color::Rgb(166, 173, 200),
status_normal: Color::Rgb(249, 226, 175), status_bypass: Color::Rgb(243, 139, 168), status_plan: Color::Rgb(137, 180, 250), }
}
fn light_theme() -> TerminalTheme {
TerminalTheme {
text_primary: Color::Black,
text_muted: Color::Black,
text_subtle: Color::Black,
accent_assistant: Color::Rgb(30, 102, 245), accent_user: Color::Rgb(64, 160, 43), accent_system: Color::Rgb(136, 57, 239), accent_primary: Color::Black,
border: Color::Black,
border_subtle: Color::Black,
separator: Color::Black,
surface: Color::Black,
ok: Color::Black,
warn: Color::Black,
err: Color::Black,
tool: Color::Black,
tool_param: Color::Black,
status_normal: Color::Black,
status_bypass: Color::Black,
status_plan: Color::Black,
}
}
fn no_color_theme() -> TerminalTheme {
TerminalTheme {
text_primary: Color::White,
text_muted: Color::White,
text_subtle: Color::White,
accent_assistant: Color::White,
accent_user: Color::White,
accent_system: Color::White,
accent_primary: Color::White,
border: Color::White,
border_subtle: Color::White,
separator: Color::White,
surface: Color::White,
ok: Color::White,
warn: Color::White,
err: Color::White,
tool: Color::White,
tool_param: Color::White,
status_normal: Color::White,
status_bypass: Color::White,
status_plan: Color::White,
}
}