use demand::Theme;
use crate::config::Settings;
pub fn get_theme() -> Theme {
let settings = Settings::get();
select_theme(
console::colors_enabled_stderr(),
&settings.color_theme,
detect_light_background(),
)
}
fn select_theme(colors_enabled: bool, color_theme: &str, light_background: bool) -> Theme {
if !colors_enabled {
return Theme::new();
}
let auto = || {
if light_background {
Theme::base16()
} else {
Theme::charm()
}
};
match color_theme.to_lowercase().as_str() {
"auto" | "default" | "" => auto(),
"charm" => Theme::charm(),
"base16" => Theme::base16(),
"catppuccin" => Theme::catppuccin(),
"dracula" => Theme::dracula(),
other => {
warn!("Unknown color theme '{}', using default", other);
auto()
}
}
}
fn detect_light_background() -> bool {
std::env::var("COLORFGBG")
.ok()
.as_deref()
.map(colorfgbg_is_light)
.unwrap_or(false)
}
fn colorfgbg_is_light(value: &str) -> bool {
value
.rsplit(';')
.next()
.and_then(|bg| bg.trim().parse::<u8>().ok())
.map(|bg| bg == 7 || (10..=15).contains(&bg))
.unwrap_or(false)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn colors_disabled_returns_unstyled_theme() {
for theme in [
"default",
"charm",
"base16",
"catppuccin",
"dracula",
"auto",
"bogus",
] {
let t = select_theme(false, theme, false);
let plain = Theme::new();
assert_eq!(t.title.fg(), plain.title.fg(), "theme={theme}");
assert_eq!(
t.selected_option.fg(),
plain.selected_option.fg(),
"theme={theme}"
);
assert_eq!(
t.unselected_option.fg(),
plain.unselected_option.fg(),
"theme={theme}"
);
}
}
#[test]
fn explicit_theme_is_applied_when_colors_enabled() {
let base16 = select_theme(true, "base16", false);
assert_eq!(base16.title.fg(), Theme::base16().title.fg());
assert!(base16.title.fg().is_some());
let charm = select_theme(true, "charm", true );
assert_eq!(charm.title.fg(), Theme::charm().title.fg());
}
#[test]
fn auto_picks_base16_on_light_and_charm_on_dark() {
for theme in ["auto", "default", ""] {
let light = select_theme(true, theme, true);
assert_eq!(
light.title.fg(),
Theme::base16().title.fg(),
"theme={theme}"
);
let dark = select_theme(true, theme, false);
assert_eq!(dark.title.fg(), Theme::charm().title.fg(), "theme={theme}");
}
}
#[test]
fn unknown_theme_falls_back_to_auto() {
assert_eq!(
select_theme(true, "bogus", true).title.fg(),
Theme::base16().title.fg()
);
assert_eq!(
select_theme(true, "bogus", false).title.fg(),
Theme::charm().title.fg()
);
}
#[test]
fn colorfgbg_light_detection() {
assert!(colorfgbg_is_light("0;15"));
assert!(colorfgbg_is_light("0;7"));
assert!(colorfgbg_is_light("0;default;15"));
assert!(colorfgbg_is_light(" 0 ; 15 "));
assert!(!colorfgbg_is_light("15;0"));
assert!(!colorfgbg_is_light("7;0"));
assert!(!colorfgbg_is_light("15;8"));
assert!(!colorfgbg_is_light(""));
assert!(!colorfgbg_is_light("foo"));
assert!(!colorfgbg_is_light("0;default"));
}
}