use std::sync::{PoisonError, RwLock};
use crate::style::{Style, parse_rgb as hex};
use crate::trace_printer::TraceTheme;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Theme {
red: (u8, u8, u8),
peach: (u8, u8, u8),
yellow: (u8, u8, u8),
teal: (u8, u8, u8),
sky: (u8, u8, u8),
blue: (u8, u8, u8),
mauve: (u8, u8, u8),
overlay1: (u8, u8, u8),
overlay0: (u8, u8, u8),
}
const _: () = assert!(
std::mem::size_of::<Theme>() <= 32,
"Theme is cloned on every get_theme(); keep it a small palette",
);
impl Theme {
pub const CATPPUCCIN_MOCHA: Self = Self {
red: hex("#f38ba8"),
peach: hex("#fab387"),
yellow: hex("#f9e2af"),
teal: hex("#94e2d5"),
sky: hex("#89dceb"),
blue: hex("#89b4fa"),
mauve: hex("#cba6f7"),
overlay1: hex("#7f849c"),
overlay0: hex("#6c7086"),
};
pub const CATPPUCCIN_MACCHIATO: Self = Self {
red: hex("#ed8796"),
peach: hex("#f5a97f"),
yellow: hex("#eed49f"),
teal: hex("#8bd5ca"),
sky: hex("#91d7e3"),
blue: hex("#8aadf4"),
mauve: hex("#c6a0f6"),
overlay1: hex("#8087a2"),
overlay0: hex("#6e738d"),
};
pub const CATPPUCCIN_FRAPPE: Self = Self {
red: hex("#e78284"),
peach: hex("#ef9f76"),
yellow: hex("#e5c890"),
teal: hex("#81c8be"),
sky: hex("#99d1db"),
blue: hex("#8caaee"),
mauve: hex("#ca9ee6"),
overlay1: hex("#838ba7"),
overlay0: hex("#737994"),
};
pub const CATPPUCCIN_LATTE: Self = Self {
red: hex("#d20f39"),
peach: hex("#fe640b"),
yellow: hex("#df8e1d"),
teal: hex("#179299"),
sky: hex("#04a5e5"),
blue: hex("#1e66f5"),
mauve: hex("#8839ef"),
overlay1: hex("#8c8fa1"),
overlay0: hex("#9ca0b0"),
};
pub const DRACULA: Self = Self {
red: hex("#ff5555"),
peach: hex("#ffb86c"),
yellow: hex("#f1fa8c"),
teal: hex("#8be9fd"),
sky: hex("#8be9fd"),
blue: hex("#bd93f9"),
mauve: hex("#bd93f9"),
overlay1: hex("#6272a4"),
overlay0: hex("#6272a4"),
};
pub const NORD: Self = Self {
red: hex("#bf616a"),
peach: hex("#d08770"),
yellow: hex("#ebcb8b"),
teal: hex("#8fbcbb"),
sky: hex("#88c0d0"),
blue: hex("#81a1c1"),
mauve: hex("#b48ead"),
overlay1: hex("#4c566a"),
overlay0: hex("#4c566a"),
};
pub const DEFAULT: Self = Self::CATPPUCCIN_MOCHA;
#[must_use]
pub const fn frame_number(&self) -> Style {
Style::from_rgb(self.overlay1)
}
#[must_use]
pub const fn function_name(&self) -> Style {
Style::from_rgb(self.red)
}
#[must_use]
pub const fn function_hash(&self) -> Style {
Style::from_rgb(self.overlay0)
}
#[must_use]
pub const fn file_path(&self) -> Style {
Style::from_rgb(self.mauve)
}
#[must_use]
pub const fn line_number(&self) -> Style {
Style::from_rgb(self.peach)
}
#[must_use]
pub const fn separator(&self) -> Style {
Style::from_rgb(self.overlay0)
}
#[must_use]
pub const fn fields(&self) -> Style {
Style::from_rgb(self.sky)
}
#[must_use]
pub const fn header(&self) -> Style {
Style::from_rgb(self.mauve)
}
#[must_use]
pub const fn frames_hidden(&self) -> Style {
Style::from_rgb(self.teal)
}
#[must_use]
pub const fn error_title(&self) -> Style {
Style::from_rgb(self.red).bold()
}
#[must_use]
pub const fn error_code(&self) -> Style {
Style::from_rgb(self.blue)
}
#[must_use]
pub const fn delimiter(&self) -> Style {
Style::from_rgb(self.overlay0)
}
#[must_use]
pub const fn cause(&self) -> Style {
Style::from_rgb(self.yellow)
}
#[must_use]
pub const fn help(&self) -> Style {
Style::from_rgb(self.teal)
}
#[must_use]
pub const fn panic_message(&self) -> Style {
Style::from_rgb(self.sky)
}
#[must_use]
pub const fn panic_location(&self) -> Style {
Style::from_rgb(self.mauve)
}
#[must_use]
pub const fn hint(&self) -> Style {
Style::from_rgb(self.overlay0)
}
#[must_use]
pub const fn trace(&self) -> TraceTheme {
TraceTheme {
frame_number: self.frame_number(),
function_name: self.function_name(),
function_hash: self.function_hash(),
file_path: self.file_path(),
line_number: self.line_number(),
separator: self.separator(),
fields: self.fields(),
header: self.header(),
frames_hidden: self.frames_hidden(),
}
}
}
static THEME: RwLock<Theme> = RwLock::new(Theme::DEFAULT);
#[inline]
pub fn set_theme(theme: Theme) {
*THEME.write().unwrap_or_else(PoisonError::into_inner) = theme;
}
#[must_use]
#[inline]
pub fn get_theme() -> Theme {
THEME.read().unwrap_or_else(PoisonError::into_inner).clone()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn set_get_theme_roundtrips() {
let original = get_theme();
set_theme(Theme::DRACULA);
assert_eq!(get_theme(), Theme::DRACULA);
set_theme(Theme::NORD);
assert_eq!(get_theme(), Theme::NORD);
set_theme(original);
}
}