pub mod builtin;
pub mod custom;
use std::path::Path;
use ratatui::style::Style;
use crate::syntax::HighlightKind;
#[derive(Debug, Clone)]
pub struct Theme {
pub name: String,
pub text: Style,
pub gutter: Style,
pub gutter_active: Style,
pub cursor_line: Style,
pub selection: Style,
pub status: Style,
pub status_mode: Style,
pub status_dirty: Style,
pub command: Style,
pub command_error: Style,
pub tab_active: Style,
pub tab_inactive: Style,
pub popup: Style,
pub popup_border: Style,
pub tree_directory: Style,
pub tree_file: Style,
pub search: Style,
pub search_active: Style,
pub syntax: SyntaxStyles,
}
#[derive(Debug, Clone, Copy)]
pub struct SyntaxStyles {
pub keyword: Style,
pub type_name: Style,
pub function: Style,
pub string: Style,
pub number: Style,
pub comment: Style,
pub constant: Style,
pub operator: Style,
pub punctuation: Style,
pub attribute: Style,
pub macro_call: Style,
pub heading: Style,
pub emphasis: Style,
pub link: Style,
}
impl SyntaxStyles {
#[must_use]
pub const fn style_for(&self, kind: HighlightKind) -> Style {
match kind {
HighlightKind::Keyword => self.keyword,
HighlightKind::Type => self.type_name,
HighlightKind::Function => self.function,
HighlightKind::String => self.string,
HighlightKind::Number => self.number,
HighlightKind::Comment => self.comment,
HighlightKind::Constant => self.constant,
HighlightKind::Operator => self.operator,
HighlightKind::Punctuation => self.punctuation,
HighlightKind::Attribute => self.attribute,
HighlightKind::Macro => self.macro_call,
HighlightKind::Heading => self.heading,
HighlightKind::Emphasis => self.emphasis,
HighlightKind::Link => self.link,
}
}
}
impl Default for Theme {
fn default() -> Self {
builtin::dark()
}
}
impl Theme {
#[must_use]
pub fn builtin(name: &str) -> Self {
match name.trim().to_ascii_lowercase().as_str() {
"light" => builtin::light(),
_ => builtin::dark(),
}
}
#[must_use]
pub fn load(name: &str, themes_dir: &Path) -> (Self, Option<String>) {
let path = themes_dir.join(format!("{name}.toml"));
if !path.is_file() {
return (Self::builtin(name), None);
}
match crate::filesystem::read_file(&path)
.and_then(|text| Ok(toml::from_str::<custom::CustomTheme>(&text)?))
{
Ok(spec) => (spec.build(name), None),
Err(error) => (Self::builtin(name), Some(format!("{path:?}: {error}"))),
}
}
}