Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-view/src/theme.rs')
-rw-r--r--helix-view/src/theme.rs229
1 files changed, 16 insertions, 213 deletions
diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs
index 173a40f3..fca47413 100644
--- a/helix-view/src/theme.rs
+++ b/helix-view/src/theme.rs
@@ -5,7 +5,7 @@ use std::{
};
use anyhow::{anyhow, Result};
-use helix_core::{hashmap, syntax::Highlight};
+use helix_core::hashmap;
use helix_loader::merge_toml_values;
use log::warn;
use once_cell::sync::Lazy;
@@ -35,75 +35,6 @@ pub static BASE16_DEFAULT_THEME: Lazy<Theme> = Lazy::new(|| Theme {
..Theme::from(BASE16_DEFAULT_THEME_DATA.clone())
});
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum Mode {
- Dark,
- Light,
-}
-
-#[cfg(feature = "term")]
-impl From<termina::escape::csi::ThemeMode> for Mode {
- fn from(mode: termina::escape::csi::ThemeMode) -> Self {
- match mode {
- termina::escape::csi::ThemeMode::Dark => Self::Dark,
- termina::escape::csi::ThemeMode::Light => Self::Light,
- }
- }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct Config {
- light: String,
- dark: String,
- /// A theme to choose when the terminal did not declare either light or dark mode.
- /// When not specified the dark theme is preferred.
- fallback: Option<String>,
-}
-
-impl Config {
- pub fn choose(&self, preference: Option<Mode>) -> &str {
- match preference {
- Some(Mode::Light) => &self.light,
- Some(Mode::Dark) => &self.dark,
- None => self.fallback.as_ref().unwrap_or(&self.dark),
- }
- }
-}
-
-impl<'de> Deserialize<'de> for Config {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: serde::Deserializer<'de>,
- {
- #[derive(Deserialize)]
- #[serde(untagged, deny_unknown_fields, rename_all = "kebab-case")]
- enum InnerConfig {
- Constant(String),
- Adaptive {
- dark: String,
- light: String,
- fallback: Option<String>,
- },
- }
-
- let inner = InnerConfig::deserialize(deserializer)?;
-
- let (light, dark, fallback) = match inner {
- InnerConfig::Constant(theme) => (theme.clone(), theme.clone(), None),
- InnerConfig::Adaptive {
- light,
- dark,
- fallback,
- } => (light, dark, fallback),
- };
-
- Ok(Self {
- light,
- dark,
- fallback,
- })
- }
-}
#[derive(Clone, Debug)]
pub struct Loader {
/// Theme directories to search from highest to lowest priority
@@ -296,7 +227,6 @@ pub struct Theme {
// tree-sitter highlight styles are stored in a Vec to optimize lookups
scopes: Vec<String>,
highlights: Vec<Style>,
- rainbow_length: usize,
}
impl From<Value> for Theme {
@@ -323,20 +253,12 @@ impl<'de> Deserialize<'de> for Theme {
}
}
-#[allow(clippy::type_complexity)]
fn build_theme_values(
mut values: Map<String, Value>,
-) -> (
- HashMap<String, Style>,
- Vec<String>,
- Vec<Style>,
- usize,
- Vec<String>,
-) {
+) -> (HashMap<String, Style>, Vec<String>, Vec<Style>, Vec<String>) {
let mut styles = HashMap::new();
let mut scopes = Vec::new();
let mut highlights = Vec::new();
- let mut rainbow_length = 0;
let mut warnings = Vec::new();
@@ -355,27 +277,6 @@ fn build_theme_values(
styles.reserve(values.len());
scopes.reserve(values.len());
highlights.reserve(values.len());
-
- for (i, style) in values
- .remove("rainbow")
- .and_then(|value| match palette.parse_style_array(value) {
- Ok(styles) => Some(styles),
- Err(err) => {
- warnings.push(err);
- None
- }
- })
- .unwrap_or_else(default_rainbow)
- .into_iter()
- .enumerate()
- {
- let name = format!("rainbow.{i}");
- styles.insert(name.clone(), style);
- scopes.push(name);
- highlights.push(style);
- rainbow_length += 1;
- }
-
for (name, style_value) in values {
let mut style = Style::default();
if let Err(err) = palette.parse_style(&mut style, style_value) {
@@ -388,51 +289,18 @@ fn build_theme_values(
highlights.push(style);
}
- (styles, scopes, highlights, rainbow_length, warnings)
+ (styles, scopes, highlights, warnings)
}
-fn default_rainbow() -> Vec<Style> {
- vec![
- Style::default().fg(Color::Red),
- Style::default().fg(Color::Yellow),
- Style::default().fg(Color::Green),
- Style::default().fg(Color::Blue),
- Style::default().fg(Color::Cyan),
- Style::default().fg(Color::Magenta),
- ]
-}
impl Theme {
- /// To allow `Highlight` to represent arbitrary RGB colors without turning it into an enum,
- /// we interpret the last 256^3 numbers as RGB.
- const RGB_START: u32 = (u32::MAX << (8 + 8 + 8)) - 1 - (u32::MAX - Highlight::MAX);
-
- /// Interpret a Highlight with the RGB foreground
- fn decode_rgb_highlight(highlight: Highlight) -> Option<(u8, u8, u8)> {
- (highlight.get() > Self::RGB_START).then(|| {
- let [b, g, r, ..] = (highlight.get() + 1).to_le_bytes();
- (r, g, b)
- })
- }
-
- /// Create a Highlight that represents an RGB color
- pub fn rgb_highlight(r: u8, g: u8, b: u8) -> Highlight {
- // -1 because highlight is "non-max": u32::MAX is reserved for the null pointer
- // optimization.
- Highlight::new(u32::from_le_bytes([b, g, r, u8::MAX]) - 1)
- }
-
#[inline]
- pub fn highlight(&self, highlight: Highlight) -> Style {
- if let Some((red, green, blue)) = Self::decode_rgb_highlight(highlight) {
- Style::new().fg(Color::Rgb(red, green, blue))
- } else {
- self.highlights[highlight.idx()]
- }
+ pub fn highlight(&self, index: usize) -> Style {
+ self.highlights[index]
}
#[inline]
- pub fn scope(&self, highlight: Highlight) -> &str {
- &self.scopes[highlight.idx()]
+ pub fn scope(&self, index: usize) -> &str {
+ &self.scopes[index]
}
pub fn name(&self) -> &str {
@@ -463,16 +331,13 @@ impl Theme {
&self.scopes
}
- pub fn find_highlight_exact(&self, scope: &str) -> Option<Highlight> {
- self.scopes()
- .iter()
- .position(|s| s == scope)
- .map(|idx| Highlight::new(idx as u32))
+ pub fn find_scope_index_exact(&self, scope: &str) -> Option<usize> {
+ self.scopes().iter().position(|s| s == scope)
}
- pub fn find_highlight(&self, mut scope: &str) -> Option<Highlight> {
+ pub fn find_scope_index(&self, mut scope: &str) -> Option<usize> {
loop {
- if let Some(highlight) = self.find_highlight_exact(scope) {
+ if let Some(highlight) = self.find_scope_index_exact(scope) {
return Some(highlight);
}
if let Some(new_end) = scope.rfind('.') {
@@ -491,10 +356,6 @@ impl Theme {
})
}
- pub fn rainbow_length(&self) -> usize {
- self.rainbow_length
- }
-
fn from_toml(value: Value) -> (Self, Vec<String>) {
if let Value::Table(table) = value {
Theme::from_keys(table)
@@ -505,14 +366,12 @@ impl Theme {
}
fn from_keys(toml_keys: Map<String, Value>) -> (Self, Vec<String>) {
- let (styles, scopes, highlights, rainbow_length, load_errors) =
- build_theme_values(toml_keys);
+ let (styles, scopes, highlights, load_errors) = build_theme_values(toml_keys);
let theme = Self {
styles,
scopes,
highlights,
- rainbow_length,
..Default::default()
};
(theme, load_errors)
@@ -641,7 +500,10 @@ impl ThemePalette {
let modifiers = value.as_array().ok_or("Modifiers should be an array")?;
for modifier in modifiers {
- if modifier.as_str() == Some("underlined") {
+ if modifier
+ .as_str()
+ .map_or(false, |modifier| modifier == "underlined")
+ {
*style = style.underline_style(UnderlineStyle::Line);
} else {
*style = style.add_modifier(Self::parse_modifier(modifier)?);
@@ -656,21 +518,6 @@ impl ThemePalette {
}
Ok(())
}
-
- fn parse_style_array(&self, value: Value) -> Result<Vec<Style>, String> {
- let mut styles = Vec::new();
-
- for v in value
- .as_array()
- .ok_or_else(|| format!("Could not parse value as an array: '{value}'"))?
- {
- let mut style = Style::default();
- self.parse_style(&mut style, v.clone())?;
- styles.push(style);
- }
-
- Ok(styles)
- }
}
impl TryFrom<Value> for ThemePalette {
@@ -745,48 +592,4 @@ mod tests {
.add_modifier(Modifier::BOLD)
);
}
-
- // tests for parsing an RGB `Highlight`
-
- #[test]
- fn convert_to_and_from() {
- let (r, g, b) = (0xFF, 0xFE, 0xFA);
- let highlight = Theme::rgb_highlight(r, g, b);
- assert_eq!(Theme::decode_rgb_highlight(highlight), Some((r, g, b)));
- }
-
- /// make sure we can store all the colors at the end
- #[test]
- fn full_numeric_range() {
- assert_eq!(Highlight::MAX - Theme::RGB_START, 256_u32.pow(3));
- }
-
- #[test]
- fn retrieve_color() {
- // color in the middle
- let (r, g, b) = (0x14, 0xAA, 0xF7);
- assert_eq!(
- Theme::default().highlight(Theme::rgb_highlight(r, g, b)),
- Style::new().fg(Color::Rgb(r, g, b))
- );
- // pure black
- let (r, g, b) = (0x00, 0x00, 0x00);
- assert_eq!(
- Theme::default().highlight(Theme::rgb_highlight(r, g, b)),
- Style::new().fg(Color::Rgb(r, g, b))
- );
- // pure white
- let (r, g, b) = (0xff, 0xff, 0xff);
- assert_eq!(
- Theme::default().highlight(Theme::rgb_highlight(r, g, b)),
- Style::new().fg(Color::Rgb(r, g, b))
- );
- }
-
- #[test]
- #[should_panic(expected = "index out of bounds: the len is 0 but the index is 4278190078")]
- fn out_of_bounds() {
- let highlight = Highlight::new(Theme::rgb_highlight(0, 0, 0).get() - 1);
- Theme::default().highlight(highlight);
- }
}