1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4use crate::{Syntax, color::Color, highlight_specs};
5
6#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
7#[allow(missing_docs)]
9pub struct Base16 {
10 pub colors: [Color; 16],
11}
12
13impl Base16 {
14 #[must_use]
15 pub fn from_hex(hex: [u32; 16]) -> Self {
24 let mut colors = [Color::BLACK; 16];
25 for (i, &h) in hex.iter().enumerate() {
26 colors[i] = Color::from(h);
27 }
28 Self { colors }
29 }
30}
31
32#[derive(Clone, Debug, Serialize, Deserialize)]
34pub struct Theme {
35 pub base: Base16,
37
38 #[allow(missing_docs)]
39 pub syntax_specific: HashMap<Syntax, SyntaxTheme>,
40}
41impl Theme {
42 #[must_use]
43 #[allow(missing_docs)]
44 pub fn from_base16(base: Base16) -> Self {
45 let mut syntax_specific = HashMap::new();
46
47 for (syntax, spec) in highlight_specs::all_specs() {
48 let theme = SyntaxTheme::from_base16_and_spec(base, spec);
49 syntax_specific.insert(syntax, theme);
50 }
51
52 Self {
53 base,
54 syntax_specific,
55 }
56 }
57}
58
59impl Default for Theme {
60 fn default() -> Self {
61 Self::from_base16(Base16::default())
62 }
63}
64
65impl Default for Base16 {
66 fn default() -> Self {
67 Self {
68 colors: [
69 Color {
70 r: 0.067,
71 g: 0.071,
72 b: 0.114,
73 a: 1.0,
74 },
75 Color {
76 r: 0.102,
77 g: 0.106,
78 b: 0.165,
79 a: 1.0,
80 },
81 Color {
82 r: 0.129,
83 g: 0.133,
84 b: 0.204,
85 a: 1.0,
86 },
87 Color {
88 r: 0.157,
89 g: 0.173,
90 b: 0.204,
91 a: 1.0,
92 },
93 Color {
94 r: 0.290,
95 g: 0.314,
96 b: 0.341,
97 a: 1.0,
98 },
99 Color {
100 r: 0.627,
101 g: 0.659,
102 b: 0.804,
103 a: 1.0,
104 },
105 Color {
106 r: 0.627,
107 g: 0.659,
108 b: 0.804,
109 a: 1.0,
110 },
111 Color {
112 r: 0.627,
113 g: 0.659,
114 b: 0.804,
115 a: 1.0,
116 },
117 Color {
118 r: 0.933,
119 g: 0.427,
120 b: 0.522,
121 a: 1.0,
122 },
123 Color {
124 r: 0.965,
125 g: 0.584,
126 b: 0.357,
127 a: 1.0,
128 },
129 Color {
130 r: 0.843,
131 g: 0.651,
132 b: 0.373,
133 a: 1.0,
134 },
135 Color {
136 r: 0.584,
137 g: 0.773,
138 b: 0.380,
139 a: 1.0,
140 },
141 Color {
142 r: 0.220,
143 g: 0.659,
144 b: 0.616,
145 a: 1.0,
146 },
147 Color {
148 r: 0.443,
149 g: 0.600,
150 b: 0.933,
151 a: 1.0,
152 },
153 Color {
154 r: 0.643,
155 g: 0.522,
156 b: 0.867,
157 a: 1.0,
158 },
159 Color {
160 r: 0.467,
161 g: 0.204,
162 b: 0.251,
163 a: 1.0,
164 },
165 ],
166 }
167 }
168}
169pub struct HighlightSpec {
171 pub names: Vec<String>,
173 pub indices: Vec<usize>,
175}
176#[allow(missing_docs)]
177impl HighlightSpec {
178 pub fn new(names: Vec<&str>, indices: Vec<usize>) -> Self {
179 Self {
180 indices,
181 names: names
182 .iter()
183 .map(std::string::ToString::to_string)
184 .collect::<Vec<String>>(),
185 }
186 }
187}
188
189#[derive(Debug, Clone, Serialize, Deserialize)]
190pub struct SyntaxTheme {
192 pub highlight_names: Vec<String>,
194 pub highlight_colors: Vec<Color>,
196 #[allow(missing_docs)]
197 pub default_color: Color,
198}
199
200#[allow(missing_docs)]
201impl SyntaxTheme {
202 #[must_use]
203 pub fn from_base16_and_spec(base: Base16, spec: HighlightSpec) -> Self {
204 let mut colors = Vec::with_capacity(spec.indices.len());
205
206 for idx in &spec.indices {
207 colors.push(base.colors[*idx]);
208 }
209
210 Self {
211 highlight_names: spec.names,
212 highlight_colors: colors,
213 default_color: base.colors[5],
214 }
215 }
216
217 #[must_use]
218 pub fn color_for_name(&self, name: &str) -> Option<Color> {
219 self.highlight_names
220 .iter()
221 .position(|n| n == name)
222 .and_then(|idx| self.highlight_colors.get(idx).copied())
223 }
224}