diff --git a/helix-view/src/graphics.rs b/helix-view/src/graphics.rs index ed530533..9a7a86c3 100644 --- a/helix-view/src/graphics.rs +++ b/helix-view/src/graphics.rs @@ -1,5 +1,8 @@ use bitflags::bitflags; -use std::cmp::{max, min}; +use std::{ + cmp::{max, min}, + str::FromStr, +}; #[derive(Debug, Clone, Copy, PartialEq)] /// UNSTABLE @@ -237,6 +240,25 @@ bitflags! { } } +impl FromStr for Modifier { + type Err = &'static str; + + fn from_str(modifier: &str) -> Result { + match modifier { + "bold" => Ok(Self::BOLD), + "dim" => Ok(Self::DIM), + "italic" => Ok(Self::ITALIC), + "underlined" => Ok(Self::UNDERLINED), + "slow_blink" => Ok(Self::SLOW_BLINK), + "rapid_blink" => Ok(Self::RAPID_BLINK), + "reversed" => Ok(Self::REVERSED), + "hidden" => Ok(Self::HIDDEN), + "crossed_out" => Ok(Self::CROSSED_OUT), + _ => Err("Invalid modifier"), + } + } +} + /// Style let you control the main characteristics of the displayed elements. /// /// ```rust diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index 756e34f6..74b817d0 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -1,5 +1,6 @@ use std::{ collections::HashMap, + convert::TryFrom, path::{Path, PathBuf}, }; @@ -11,8 +12,6 @@ use toml::Value; pub use crate::graphics::{Color, Modifier, Style}; -/// Color theme for syntax highlighting. - pub static DEFAULT_THEME: Lazy = Lazy::new(|| { toml::from_slice(include_bytes!("../../theme.toml")).expect("Failed to parse default theme") }); @@ -54,22 +53,10 @@ impl Loader { .map(|entries| { entries .filter_map(|entry| { - if let Ok(entry) = entry { - let path = entry.path(); - if let Some(ext) = path.extension() { - if ext != "toml" { - return None; - } - return Some( - entry - .file_name() - .to_string_lossy() - .trim_end_matches(".toml") - .to_owned(), - ); - } - } - None + let entry = entry.ok()?; + let path = entry.path(); + (path.extension()? == "toml") + .then(|| path.file_stem().unwrap().to_string_lossy().into_owned()) }) .collect() }) @@ -103,13 +90,23 @@ impl<'de> Deserialize<'de> for Theme { let mut styles = HashMap::new(); if let Ok(mut colors) = HashMap::::deserialize(deserializer) { - let palette = parse_palette(colors.remove("palette")); - // scopes.reserve(colors.len()); + // TODO: alert user of parsing failures in editor + let palette = colors + .remove("palette") + .map(|value| { + ThemePalette::try_from(value).unwrap_or_else(|err| { + warn!("{}", err); + ThemePalette::default() + }) + }) + .unwrap_or_default(); + styles.reserve(colors.len()); for (name, style_value) in colors { let mut style = Style::default(); - parse_style(&mut style, style_value, &palette); - // scopes.push(name); + if let Err(err) = palette.parse_style(&mut style, style_value) { + warn!("{}", err); + } styles.insert(name, style); } } @@ -119,121 +116,120 @@ impl<'de> Deserialize<'de> for Theme { } } -fn parse_palette(value: Option) -> HashMap { - match value { - Some(Value::Table(entries)) => entries, - _ => return HashMap::default(), +impl Theme { + pub fn get(&self, scope: &str) -> Style { + self.try_get(scope) + .unwrap_or_else(|| Style::default().fg(Color::Rgb(0, 0, 255))) } - .into_iter() - .filter_map(|(name, value)| { - let color = parse_color(value, &HashMap::default())?; - Some((name, color)) - }) - .collect() -} -fn parse_style(style: &mut Style, value: Value, palette: &HashMap) { - //TODO: alert user of parsing failures - if let Value::Table(entries) = value { - for (name, value) in entries { - match name.as_str() { - "fg" => { - if let Some(color) = parse_color(value, palette) { - *style = style.fg(color); - } - } - "bg" => { - if let Some(color) = parse_color(value, palette) { - *style = style.bg(color); - } - } - "modifiers" => { - if let Value::Array(arr) = value { - for modifier in arr.iter().filter_map(parse_modifier) { - *style = style.add_modifier(modifier); - } - } - } - _ => (), - } - } - } else if let Some(color) = parse_color(value, palette) { - *style = style.fg(color); + pub fn try_get(&self, scope: &str) -> Option