summaryrefslogtreecommitdiff
path: root/helix-view/src/theme.rs
diff options
context:
space:
mode:
Diffstat (limited to 'helix-view/src/theme.rs')
-rw-r--r--helix-view/src/theme.rs179
1 files changed, 179 insertions, 0 deletions
diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs
new file mode 100644
index 00000000..d61457d7
--- /dev/null
+++ b/helix-view/src/theme.rs
@@ -0,0 +1,179 @@
+use helix_core::hashmap;
+use std::collections::HashMap;
+
+#[cfg(feature = "term")]
+pub use tui::style::{Color, Style};
+
+// #[derive(Clone, Copy, PartialEq, Eq, Default, Hash)]
+// pub struct Color {
+// pub r: u8,
+// pub g: u8,
+// pub b: u8,
+// }
+
+// impl Color {
+// pub fn new(r: u8, g: u8, b: u8) -> Self {
+// Self { r, g, b }
+// }
+// }
+
+// #[cfg(feature = "term")]
+// impl Into<tui::style::Color> for Color {
+// fn into(self) -> tui::style::Color {
+// tui::style::Color::Rgb(self.r, self.g, self.b)
+// }
+// }
+
+// impl std::str::FromStr for Color {
+// type Err = ();
+
+// /// Tries to parse a string (`'#FFFFFF'` or `'FFFFFF'`) into RGB.
+// fn from_str(input: &str) -> Result<Self, Self::Err> {
+// let input = input.trim();
+// let input = match (input.chars().next(), input.len()) {
+// (Some('#'), 7) => &input[1..],
+// (_, 6) => input,
+// _ => return Err(()),
+// };
+
+// u32::from_str_radix(&input, 16)
+// .map(|s| Color {
+// r: ((s >> 16) & 0xFF) as u8,
+// g: ((s >> 8) & 0xFF) as u8,
+// b: (s & 0xFF) as u8,
+// })
+// .map_err(|_| ())
+// }
+// }
+
+// #[derive(Clone, Copy, PartialEq, Eq, Default, Hash)]
+// pub struct Style {
+// pub fg: Option<Color>,
+// pub bg: Option<Color>,
+// // TODO: modifiers (bold, underline, italic, etc)
+// }
+
+// impl Style {
+// pub fn fg(mut self, fg: Color) -> Self {
+// self.fg = Some(fg);
+// self
+// }
+
+// pub fn bg(mut self, bg: Color) -> Self {
+// self.bg = Some(bg);
+// self
+// }
+// }
+
+// #[cfg(feature = "term")]
+// impl Into<tui::style::Style> for Style {
+// fn into(self) -> tui::style::Style {
+// let style = tui::style::Style::default();
+
+// if let Some(fg) = self.fg {
+// style.fg(fg.into());
+// }
+
+// if let Some(bg) = self.bg {
+// style.bg(bg.into());
+// }
+
+// style
+// }
+// }
+
+/// Color theme for syntax highlighting.
+pub struct Theme {
+ scopes: Vec<String>,
+ mapping: HashMap<&'static str, Style>,
+}
+
+// let highlight_names: Vec<String> = [
+// "attribute",
+// "constant.builtin",
+// "constant",
+// "function.builtin",
+// "function.macro",
+// "function",
+// "keyword",
+// "operator",
+// "property",
+// "punctuation",
+// "comment",
+// "escape",
+// "label",
+// // "punctuation.bracket",
+// "punctuation.delimiter",
+// "string",
+// "string.special",
+// "tag",
+// "type",
+// "type.builtin",
+// "constructor",
+// "variable",
+// "variable.builtin",
+// "variable.parameter",
+// "path",
+// ];
+
+impl Default for Theme {
+ fn default() -> Self {
+ let mapping = hashmap! {
+ "attribute" => Style::default().fg(Color::Rgb(219, 191, 239)), // lilac
+ "keyword" => Style::default().fg(Color::Rgb(236, 205, 186)), // almond
+ "punctuation" => Style::default().fg(Color::Rgb(164, 160, 232)), // lavender
+ "punctuation.delimiter" => Style::default().fg(Color::Rgb(164, 160, 232)), // lavender
+ "operator" => Style::default().fg(Color::Rgb(219, 191, 239)), // lilac
+ "property" => Style::default().fg(Color::Rgb(164, 160, 232)), // lavender
+ "variable.parameter" => Style::default().fg(Color::Rgb(164, 160, 232)), // lavender
+ // TODO distinguish type from type.builtin?
+ "type" => Style::default().fg(Color::Rgb(255, 255, 255)), // white
+ "type.builtin" => Style::default().fg(Color::Rgb(255, 255, 255)), // white
+ "constructor" => Style::default().fg(Color::Rgb(219, 191, 239)), // lilac
+ "function" => Style::default().fg(Color::Rgb(255, 255, 255)), // white
+ "function.macro" => Style::default().fg(Color::Rgb(219, 191, 239)), // lilac
+ "comment" => Style::default().fg(Color::Rgb(105, 124, 129)), // sirocco
+ "variable.builtin" => Style::default().fg(Color::Rgb(159, 242, 143)), // mint
+ "constant" => Style::default().fg(Color::Rgb(255, 255, 255)), // white
+ "constant.builtin" => Style::default().fg(Color::Rgb(255, 255, 255)), // white
+ "string" => Style::default().fg(Color::Rgb(204, 204, 204)), // silver
+ "escape" => Style::default().fg(Color::Rgb(239, 186, 93)), // honey
+ // used for lifetimes
+ "label" => Style::default().fg(Color::Rgb(239, 186, 93)), // honey
+
+ // TODO: diferentiate number builtin
+ // TODO: diferentiate doc comment
+ // TODO: variable as lilac
+ // TODO: mod/use statements as white
+ // TODO: mod stuff as chamoise
+ // TODO: add "(scoped_identifier) @path" for std::mem::
+ //
+ // concat (ERROR) @syntax-error and "MISSING ;" selectors for errors
+
+ "module" => Style::default().fg(Color::Rgb(255, 0, 0)), // white
+ "variable" => Style::default().fg(Color::Rgb(255, 0, 0)), // white
+ "function.builtin" => Style::default().fg(Color::Rgb(255, 0, 0)), // white
+
+ "ui.background" => Style::default().bg(Color::Rgb(59, 34, 76)), // midnight
+ "ui.linenr" => Style::default().fg(Color::Rgb(90, 89, 119)), // comet
+ "ui.statusline" => Style::default().bg(Color::Rgb(40, 23, 51)), // revolver
+ };
+
+ let scopes = mapping.keys().map(ToString::to_string).collect();
+
+ Self { mapping, scopes }
+ }
+}
+
+impl Theme {
+ pub fn get(&self, scope: &str) -> Style {
+ self.mapping
+ .get(scope)
+ .copied()
+ .unwrap_or_else(|| Style::default().fg(Color::Rgb(0, 0, 255)))
+ }
+
+ pub fn scopes(&self) -> &[String] {
+ &self.scopes
+ }
+}