use ratatui::style::Color;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ThemeMode {
Dark,
Light,
Auto,
}
#[derive(Debug, Clone)]
pub struct Theme {
pub selection_bg: Color,
pub file_header_bg: Color,
pub added_line_bg: Color,
pub removed_line_bg: Color,
pub added_emphasis_bg: Color, pub removed_emphasis_bg: Color, pub file_header_fg: Color,
pub context_fg: Color,
pub context_bg: Color,
pub gutter_fg: Color,
pub help_text_fg: Color,
pub help_section_fg: Color, pub help_key_fg: Color, pub help_dismiss_fg: Color, pub help_overlay_bg: Color,
pub tree_highlight_fg: Color,
pub tree_highlight_bg: Color,
pub tree_group_fg: Color,
pub search_match_fg: Color,
pub search_match_bg: Color,
pub md_inline_code_fg: Color,
pub md_heading_h1_fg: Color,
pub md_heading_h2_fg: Color,
pub md_heading_h3_fg: Color,
pub md_heading_h4_fg: Color,
pub md_heading_h5_fg: Color,
pub md_heading_h6_fg: Color,
pub md_list_bullet_fg: Color,
pub md_code_block_fg: Color,
pub md_code_block_delim_fg: Color,
pub md_blockquote_fg: Color,
pub md_link_fg: Color,
pub md_rule_fg: Color,
pub syntect_theme: &'static str,
}
impl Theme {
pub fn dark() -> Self {
Self {
selection_bg: Color::Rgb(40, 40, 60),
file_header_bg: Color::Rgb(30, 30, 40),
added_line_bg: Color::Rgb(0, 40, 0),
removed_line_bg: Color::Rgb(40, 0, 0),
added_emphasis_bg: Color::Rgb(0, 80, 0),
removed_emphasis_bg: Color::Rgb(80, 0, 0),
file_header_fg: Color::White,
context_fg: Color::Reset,
context_bg: Color::Reset,
gutter_fg: Color::DarkGray,
help_text_fg: Color::White,
help_section_fg: Color::Cyan,
help_key_fg: Color::Yellow,
help_dismiss_fg: Color::DarkGray,
help_overlay_bg: Color::Black,
tree_highlight_fg: Color::Black,
tree_highlight_bg: Color::Cyan,
tree_group_fg: Color::Cyan,
search_match_fg: Color::Black,
search_match_bg: Color::Yellow,
md_inline_code_fg: Color::Yellow,
md_heading_h1_fg: Color::Magenta,
md_heading_h2_fg: Color::Cyan,
md_heading_h3_fg: Color::Green,
md_heading_h4_fg: Color::Yellow,
md_heading_h5_fg: Color::Blue,
md_heading_h6_fg: Color::Red,
md_list_bullet_fg: Color::Cyan,
md_code_block_fg: Color::Green,
md_code_block_delim_fg: Color::DarkGray,
md_blockquote_fg: Color::DarkGray,
md_link_fg: Color::Blue,
md_rule_fg: Color::DarkGray,
syntect_theme: "base16-ocean.dark",
}
}
pub fn light() -> Self {
Self {
selection_bg: Color::Rgb(210, 210, 230),
file_header_bg: Color::Rgb(220, 220, 235),
added_line_bg: Color::Rgb(210, 255, 210),
removed_line_bg: Color::Rgb(255, 210, 210),
added_emphasis_bg: Color::Rgb(170, 240, 170),
removed_emphasis_bg: Color::Rgb(240, 170, 170),
file_header_fg: Color::Black,
context_fg: Color::Reset,
context_bg: Color::Reset,
gutter_fg: Color::Gray,
help_text_fg: Color::Black,
help_section_fg: Color::Blue,
help_key_fg: Color::Red,
help_dismiss_fg: Color::Gray,
help_overlay_bg: Color::White,
tree_highlight_fg: Color::White,
tree_highlight_bg: Color::Blue,
tree_group_fg: Color::Blue,
search_match_fg: Color::Black,
search_match_bg: Color::Yellow,
md_inline_code_fg: Color::Rgb(180, 80, 0),
md_heading_h1_fg: Color::Rgb(160, 0, 160),
md_heading_h2_fg: Color::Rgb(0, 130, 150),
md_heading_h3_fg: Color::Rgb(0, 130, 0),
md_heading_h4_fg: Color::Rgb(180, 80, 0),
md_heading_h5_fg: Color::Blue,
md_heading_h6_fg: Color::Red,
md_list_bullet_fg: Color::Rgb(0, 130, 150),
md_code_block_fg: Color::Rgb(0, 130, 0),
md_code_block_delim_fg: Color::Gray,
md_blockquote_fg: Color::Gray,
md_link_fg: Color::Blue,
md_rule_fg: Color::Gray,
syntect_theme: "base16-ocean.light",
}
}
pub fn from_mode(mode: ThemeMode) -> Self {
match mode {
ThemeMode::Dark => Self::dark(),
ThemeMode::Light => Self::light(),
ThemeMode::Auto => {
if detect_light_background() {
Self::light()
} else {
Self::dark()
}
}
}
}
}
fn detect_light_background() -> bool {
use std::io::IsTerminal;
if !std::io::stdin().is_terminal() || !std::io::stdout().is_terminal() {
return false;
}
if std::env::var("CI").is_ok() || std::env::var("TERM").as_deref() == Ok("dumb") {
return false;
}
if let Ok(luma) = terminal_light::luma() {
return luma > 0.6;
}
if let Ok(val) = std::env::var("COLORFGBG") {
if let Some(bg) = val.rsplit(';').next().and_then(|s| s.parse::<u8>().ok()) {
return bg >= 7;
}
}
false
}