1use crate::renderer::HIGHLIGHT_NAMES;
2use crate::Error;
3use std::collections::HashMap;
4use std::convert::From;
5use toml::value::Table;
6use toml::Value;
7
8pub(crate) struct Style {
9 pub color: String,
10 pub is_bold: bool,
11 pub is_italic: bool,
12}
13
14impl From<&String> for Style {
15 fn from(color: &String) -> Self {
16 Style {
17 color: color.clone(),
18 is_bold: false,
19 is_italic: false,
20 }
21 }
22}
23
24pub struct Theme {
26 pub(crate) style_map: HashMap<usize, Style>,
27 pub(crate) foreground: Style,
28 pub(crate) background: Style,
29}
30
31impl Theme {
32 pub fn from_helix(data: &str) -> Result<Self, Error> {
40 let root = match data.parse::<toml::Value>()? {
41 Value::Table(table) => table,
42 _ => return Err(Error::InvalidTheme),
43 };
44
45 let palette = root.get("palette").ok_or(Error::InvalidTheme)?;
46
47 let referenced_color = |table: &Table, name: &str| -> Result<Style, Error> {
48 if let Some(Value::String(reference)) = table.get(name) {
49 if let Some(Value::String(color)) = palette.get(reference) {
50 return Ok(Style::from(color));
51 }
52 }
53
54 Err(Error::InvalidColorReference(name.to_string()))
55 };
56
57 let fg_color = |name: &str| -> Result<Option<Style>, Error> {
58 if let Some(value) = root.get(name) {
59 match value {
60 Value::String(reference) => {
61 if let Some(Value::String(color)) = palette.get(reference) {
62 return Ok(Some(Style::from(color)));
63 }
64 }
65 Value::Table(table) => {
66 let mut style = referenced_color(table, "fg")?;
67
68 if let Some(Value::Array(modifiers)) = table.get("modifiers") {
69 for modifier in modifiers {
70 if let Value::String(modifier) = modifier {
71 if modifier == "italic" {
72 style.is_italic = true;
73 } else if modifier == "bold" {
74 style.is_bold = true;
75 }
76 }
77 }
78 }
79
80 return Ok(Some(style));
81 }
82 _ => {}
83 }
84 }
85
86 Ok(None)
87 };
88
89 let mut style_map = HashMap::default();
90
91 for (index, name) in HIGHLIGHT_NAMES.iter().enumerate() {
92 if let Some(style) = fg_color(*name)? {
93 style_map.insert(index, style);
94 }
95 }
96
97 let background = match root.get("ui.background") {
98 Some(Value::Table(table)) => referenced_color(table, "bg")?,
99 _ => Style::from(&"#000".to_string()),
100 };
101
102 let foreground = fg_color("ui.text")?.unwrap_or_else(|| Style::from(&"#fff".to_string()));
103
104 Ok(Self {
105 style_map,
106 foreground,
107 background,
108 })
109 }
110}