diff options
Diffstat (limited to 'helix-view/src/theme.rs')
-rw-r--r-- | helix-view/src/theme.rs | 136 |
1 files changed, 90 insertions, 46 deletions
diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index 757316bd..00c1bbbd 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -15,6 +15,10 @@ pub use crate::graphics::{Color, Modifier, Style}; pub static DEFAULT_THEME: Lazy<Theme> = Lazy::new(|| { toml::from_slice(include_bytes!("../../theme.toml")).expect("Failed to parse default theme") }); +pub static BASE16_DEFAULT_THEME: Lazy<Theme> = Lazy::new(|| { + toml::from_slice(include_bytes!("../../base16_theme.toml")) + .expect("Failed to parse base 16 default theme") +}); #[derive(Clone, Debug)] pub struct Loader { @@ -35,6 +39,9 @@ impl Loader { if name == "default" { return Ok(self.default()); } + if name == "base16_default" { + return Ok(self.base16_default()); + } let filename = format!("{}.toml", name); let user_path = self.user_dir.join(&filename); @@ -74,12 +81,20 @@ impl Loader { pub fn default(&self) -> Theme { DEFAULT_THEME.clone() } + + /// Returns the alternative 16-color default theme + pub fn base16_default(&self) -> Theme { + BASE16_DEFAULT_THEME.clone() + } } #[derive(Clone, Debug)] pub struct Theme { - scopes: Vec<String>, + // UI styles are stored in a HashMap styles: HashMap<String, Style>, + // tree-sitter highlight styles are stored in a Vec to optimize lookups + scopes: Vec<String>, + highlights: Vec<Style>, } impl<'de> Deserialize<'de> for Theme { @@ -88,6 +103,8 @@ impl<'de> Deserialize<'de> for Theme { D: Deserializer<'de>, { let mut styles = HashMap::new(); + let mut scopes = Vec::new(); + let mut highlights = Vec::new(); if let Ok(mut colors) = HashMap::<String, Value>::deserialize(deserializer) { // TODO: alert user of parsing failures in editor @@ -102,24 +119,38 @@ impl<'de> Deserialize<'de> for Theme { .unwrap_or_default(); styles.reserve(colors.len()); + scopes.reserve(colors.len()); + highlights.reserve(colors.len()); + for (name, style_value) in colors { let mut style = Style::default(); if let Err(err) = palette.parse_style(&mut style, style_value) { warn!("{}", err); } - styles.insert(name, style); + + // these are used both as UI and as highlights + styles.insert(name.clone(), style); + scopes.push(name); + highlights.push(style); } } - let scopes = styles.keys().map(ToString::to_string).collect(); - Ok(Self { scopes, styles }) + Ok(Self { + scopes, + styles, + highlights, + }) } } impl Theme { + #[inline] + pub fn highlight(&self, index: usize) -> Style { + self.highlights[index] + } + pub fn get(&self, scope: &str) -> Style { - self.try_get(scope) - .unwrap_or_else(|| Style::default().fg(Color::Rgb(0, 0, 255))) + self.try_get(scope).unwrap_or_default() } pub fn try_get(&self, scope: &str) -> Option<Style> { @@ -134,6 +165,14 @@ impl Theme { pub fn find_scope_index(&self, scope: &str) -> Option<usize> { self.scopes().iter().position(|s| s == scope) } + + pub fn is_16_color(&self) -> bool { + self.styles.iter().all(|(_, style)| { + [style.fg, style.bg] + .into_iter() + .all(|color| !matches!(color, Some(Color::Rgb(..)))) + }) + } } struct ThemePalette { @@ -257,53 +296,58 @@ impl TryFrom<Value> for ThemePalette { } } -#[test] -fn test_parse_style_string() { - let fg = Value::String("#ffffff".to_string()); +#[cfg(test)] +mod tests { + use super::*; - let mut style = Style::default(); - let palette = ThemePalette::default(); - palette.parse_style(&mut style, fg).unwrap(); + #[test] + fn test_parse_style_string() { + let fg = Value::String("#ffffff".to_string()); - assert_eq!(style, Style::default().fg(Color::Rgb(255, 255, 255))); -} + let mut style = Style::default(); + let palette = ThemePalette::default(); + palette.parse_style(&mut style, fg).unwrap(); -#[test] -fn test_palette() { - use helix_core::hashmap; - let fg = Value::String("my_color".to_string()); + assert_eq!(style, Style::default().fg(Color::Rgb(255, 255, 255))); + } - let mut style = Style::default(); - let palette = - ThemePalette::new(hashmap! { "my_color".to_string() => Color::Rgb(255, 255, 255) }); - palette.parse_style(&mut style, fg).unwrap(); + #[test] + fn test_palette() { + use helix_core::hashmap; + let fg = Value::String("my_color".to_string()); - assert_eq!(style, Style::default().fg(Color::Rgb(255, 255, 255))); -} + let mut style = Style::default(); + let palette = + ThemePalette::new(hashmap! { "my_color".to_string() => Color::Rgb(255, 255, 255) }); + palette.parse_style(&mut style, fg).unwrap(); -#[test] -fn test_parse_style_table() { - let table = toml::toml! { - "keyword" = { - fg = "#ffffff", - bg = "#000000", - modifiers = ["bold"], - } - }; + assert_eq!(style, Style::default().fg(Color::Rgb(255, 255, 255))); + } - let mut style = Style::default(); - let palette = ThemePalette::default(); - if let Value::Table(entries) = table { - for (_name, value) in entries { - palette.parse_style(&mut style, value).unwrap(); + #[test] + fn test_parse_style_table() { + let table = toml::toml! { + "keyword" = { + fg = "#ffffff", + bg = "#000000", + modifiers = ["bold"], + } + }; + + let mut style = Style::default(); + let palette = ThemePalette::default(); + if let Value::Table(entries) = table { + for (_name, value) in entries { + palette.parse_style(&mut style, value).unwrap(); + } } - } - assert_eq!( - style, - Style::default() - .fg(Color::Rgb(255, 255, 255)) - .bg(Color::Rgb(0, 0, 0)) - .add_modifier(Modifier::BOLD) - ); + assert_eq!( + style, + Style::default() + .fg(Color::Rgb(255, 255, 255)) + .bg(Color::Rgb(0, 0, 0)) + .add_modifier(Modifier::BOLD) + ); + } } |