aboutsummaryrefslogtreecommitdiff
path: root/helix-view/src/theme.rs
diff options
context:
space:
mode:
authorBlaž Hrastnik2022-02-13 09:31:51 +0000
committerBlaž Hrastnik2022-02-13 09:31:51 +0000
commitbd549d8a20cce98e24c8653a4a86107c786cbaa3 (patch)
tree0780b58d41b6181e69023265cdb54517e2953778 /helix-view/src/theme.rs
parent7ad8eaaef0b292f4be6c66298cea40d2b928e172 (diff)
parent7083b98a388b30e0b61caac9bf6ccc1d79eadf81 (diff)
Merge remote-tracking branch 'origin/master' into debug
Diffstat (limited to 'helix-view/src/theme.rs')
-rw-r--r--helix-view/src/theme.rs136
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)
+ );
+ }
}