1use crate::{
4 color_choice::ColorLevel,
5 role::StyleRole,
6 style::{AnsiColor, Style},
7};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub struct Theme {
14 styles: [Style; StyleRole::COUNT],
15}
16
17impl Default for Theme {
18 fn default() -> Self {
19 Self::dark()
20 }
21}
22
23impl Theme {
24 pub const NAMES: &'static [&'static str] = &[
26 "dark",
27 "light",
28 "monochrome",
29 "ansi16",
30 "gruvbox",
31 "nord",
32 "dracula",
33 "solarized-dark",
34 "solarized-light",
35 "one-dark",
36 "catppuccin",
37 "tokyo-night",
38 "monokai",
39 "ayu-dark",
40 ];
41
42 pub fn by_name(name: &str) -> Option<Self> {
44 let normalized = name.trim().to_ascii_lowercase().replace('_', "-");
45 match normalized.as_str() {
46 "default" | "dark" => Some(Self::dark()),
47 "light" => Some(Self::light()),
48 "monochrome" | "mono" | "plain" => Some(Self::monochrome()),
49 "ansi16" | "ansi" => Some(Self::ansi16()),
50 "gruvbox" => Some(Self::gruvbox()),
51 "nord" => Some(Self::nord()),
52 "dracula" => Some(Self::dracula()),
53 "solarized-dark" => Some(Self::solarized_dark()),
54 "solarized-light" => Some(Self::solarized_light()),
55 "one-dark" | "onedark" => Some(Self::one_dark()),
56 "catppuccin" | "catppuccin-mocha" => Some(Self::catppuccin_mocha()),
57 "tokyo-night" | "tokyonight" => Some(Self::tokyo_night()),
58 "monokai" => Some(Self::monokai()),
59 "ayu" | "ayu-dark" => Some(Self::ayu_dark()),
60 _ => None,
61 }
62 }
63
64 pub const fn empty() -> Self {
66 Self { styles: [Style::new(); StyleRole::COUNT] }
67 }
68
69 pub fn dark() -> Self {
74 Self::empty()
75 .with(StyleRole::Type, Style::new().bold().fg_rgb(224, 138, 90))
76 .with(StyleRole::Field, Style::new().fg_rgb(110, 180, 235))
77 .with(StyleRole::Variant, Style::new().bold().fg_rgb(180, 145, 225))
78 .with(StyleRole::Key, Style::new().fg_rgb(105, 205, 195))
79 .with(StyleRole::String, Style::new().fg_rgb(142, 198, 128))
80 .with(StyleRole::Number, Style::new().fg_rgb(235, 190, 95))
81 .with(StyleRole::Boolean, Style::new().fg_rgb(195, 135, 185))
82 .with(StyleRole::Null, Style::new().dimmed().fg_rgb(140, 145, 155))
83 .with(StyleRole::Punctuation, Style::new().dimmed().fg_rgb(115, 120, 130))
84 .with(StyleRole::Index, Style::new().fg_rgb(115, 185, 195))
85 .with(StyleRole::Metadata, Style::new().dimmed().fg_rgb(130, 135, 145))
86 .with(StyleRole::Sensitive, Style::new().bold().fg_rgb(235, 95, 95))
87 .with(StyleRole::Truncated, Style::new().italic().fg_rgb(225, 180, 75))
88 .with(StyleRole::Error, Style::new().bold().fg_rgb(240, 85, 85))
89 .with(StyleRole::Muted, Style::new().dimmed().fg_rgb(120, 125, 135))
90 }
91
92 pub fn light() -> Self {
94 Self::empty()
95 .with(StyleRole::Type, Style::new().bold().fg_rgb(175, 75, 25))
96 .with(StyleRole::Field, Style::new().fg_rgb(30, 95, 160))
97 .with(StyleRole::Variant, Style::new().bold().fg_rgb(115, 45, 150))
98 .with(StyleRole::Key, Style::new().fg_rgb(20, 115, 120))
99 .with(StyleRole::String, Style::new().fg_rgb(35, 125, 55))
100 .with(StyleRole::Number, Style::new().fg_rgb(165, 105, 15))
101 .with(StyleRole::Boolean, Style::new().fg_rgb(140, 35, 105))
102 .with(StyleRole::Null, Style::new().dimmed().fg_rgb(110, 115, 125))
103 .with(StyleRole::Punctuation, Style::new().fg_rgb(120, 125, 135))
104 .with(StyleRole::Index, Style::new().fg_rgb(40, 105, 135))
105 .with(StyleRole::Metadata, Style::new().dimmed().fg_rgb(105, 110, 120))
106 .with(StyleRole::Sensitive, Style::new().bold().fg_rgb(185, 30, 30))
107 .with(StyleRole::Truncated, Style::new().italic().fg_rgb(155, 95, 20))
108 .with(StyleRole::Error, Style::new().bold().fg_rgb(195, 20, 20))
109 .with(StyleRole::Muted, Style::new().dimmed().fg_rgb(110, 115, 125))
110 }
111
112 pub fn monochrome() -> Self {
114 Self::empty()
115 .with(StyleRole::Type, Style::new().bold())
116 .with(StyleRole::Field, Style::new())
117 .with(StyleRole::Variant, Style::new().bold().underline())
118 .with(StyleRole::Key, Style::new().underline())
119 .with(StyleRole::String, Style::new())
120 .with(StyleRole::Number, Style::new().bold())
121 .with(StyleRole::Boolean, Style::new().bold())
122 .with(StyleRole::Null, Style::new().dimmed().italic())
123 .with(StyleRole::Punctuation, Style::new().dimmed())
124 .with(StyleRole::Index, Style::new().dimmed())
125 .with(StyleRole::Metadata, Style::new().dimmed())
126 .with(StyleRole::Sensitive, Style::new().bold().underline())
127 .with(StyleRole::Truncated, Style::new().dimmed().italic())
128 .with(StyleRole::Error, Style::new().bold().underline())
129 .with(StyleRole::Muted, Style::new().dimmed())
130 }
131
132 pub fn ansi16() -> Self {
134 Self::empty()
135 .with(StyleRole::Type, Style::new().bold().fg_ansi(AnsiColor::Yellow))
136 .with(StyleRole::Field, Style::new().fg_ansi(AnsiColor::Cyan))
137 .with(StyleRole::Variant, Style::new().bold().fg_ansi(AnsiColor::Magenta))
138 .with(StyleRole::Key, Style::new().fg_ansi(AnsiColor::Cyan))
139 .with(StyleRole::String, Style::new().fg_ansi(AnsiColor::Green))
140 .with(StyleRole::Number, Style::new().fg_ansi(AnsiColor::Yellow))
141 .with(StyleRole::Boolean, Style::new().fg_ansi(AnsiColor::Magenta))
142 .with(StyleRole::Null, Style::new().fg_ansi(AnsiColor::BrightBlack))
143 .with(StyleRole::Punctuation, Style::new().fg_ansi(AnsiColor::BrightBlack))
144 .with(StyleRole::Index, Style::new().fg_ansi(AnsiColor::Cyan))
145 .with(StyleRole::Metadata, Style::new().fg_ansi(AnsiColor::BrightBlack))
146 .with(StyleRole::Sensitive, Style::new().bold().fg_ansi(AnsiColor::BrightRed))
147 .with(StyleRole::Truncated, Style::new().fg_ansi(AnsiColor::Yellow))
148 .with(StyleRole::Error, Style::new().bold().fg_ansi(AnsiColor::Red))
149 .with(StyleRole::Muted, Style::new().fg_ansi(AnsiColor::BrightBlack))
150 }
151
152 pub fn gruvbox() -> Self {
154 Self::empty()
155 .with(StyleRole::Type, Style::new().bold().fg_rgb(254, 128, 25))
156 .with(StyleRole::Field, Style::new().fg_rgb(131, 165, 152))
157 .with(StyleRole::Variant, Style::new().bold().fg_rgb(211, 134, 155))
158 .with(StyleRole::Key, Style::new().fg_rgb(142, 192, 124))
159 .with(StyleRole::String, Style::new().fg_rgb(184, 187, 38))
160 .with(StyleRole::Number, Style::new().fg_rgb(250, 189, 47))
161 .with(StyleRole::Boolean, Style::new().fg_rgb(211, 134, 155))
162 .with(StyleRole::Null, Style::new().dimmed().fg_rgb(146, 131, 116))
163 .with(StyleRole::Punctuation, Style::new().dimmed().fg_rgb(146, 131, 116))
164 .with(StyleRole::Index, Style::new().fg_rgb(142, 192, 124))
165 .with(StyleRole::Metadata, Style::new().dimmed().fg_rgb(146, 131, 116))
166 .with(StyleRole::Sensitive, Style::new().bold().fg_rgb(251, 73, 52))
167 .with(StyleRole::Truncated, Style::new().italic().fg_rgb(250, 189, 47))
168 .with(StyleRole::Error, Style::new().bold().fg_rgb(251, 73, 52))
169 .with(StyleRole::Muted, Style::new().dimmed().fg_rgb(102, 92, 84))
170 }
171
172 pub fn nord() -> Self {
174 Self::empty()
175 .with(StyleRole::Type, Style::new().bold().fg_rgb(208, 135, 112))
176 .with(StyleRole::Field, Style::new().fg_rgb(136, 192, 208))
177 .with(StyleRole::Variant, Style::new().bold().fg_rgb(180, 142, 173))
178 .with(StyleRole::Key, Style::new().fg_rgb(129, 161, 193))
179 .with(StyleRole::String, Style::new().fg_rgb(163, 190, 140))
180 .with(StyleRole::Number, Style::new().fg_rgb(235, 203, 139))
181 .with(StyleRole::Boolean, Style::new().fg_rgb(180, 142, 173))
182 .with(StyleRole::Null, Style::new().dimmed().fg_rgb(147, 156, 172))
183 .with(StyleRole::Punctuation, Style::new().dimmed().fg_rgb(97, 110, 136))
184 .with(StyleRole::Index, Style::new().fg_rgb(136, 192, 208))
185 .with(StyleRole::Metadata, Style::new().dimmed().fg_rgb(108, 120, 144))
186 .with(StyleRole::Sensitive, Style::new().bold().fg_rgb(191, 97, 106))
187 .with(StyleRole::Truncated, Style::new().italic().fg_rgb(235, 203, 139))
188 .with(StyleRole::Error, Style::new().bold().fg_rgb(191, 97, 106))
189 .with(StyleRole::Muted, Style::new().dimmed().fg_rgb(76, 86, 106))
190 }
191
192 pub fn dracula() -> Self {
194 Self::empty()
195 .with(StyleRole::Type, Style::new().bold().fg_rgb(255, 184, 108))
196 .with(StyleRole::Field, Style::new().fg_rgb(139, 233, 253))
197 .with(StyleRole::Variant, Style::new().bold().fg_rgb(189, 147, 249))
198 .with(StyleRole::Key, Style::new().fg_rgb(139, 233, 253))
199 .with(StyleRole::String, Style::new().fg_rgb(80, 250, 123))
200 .with(StyleRole::Number, Style::new().fg_rgb(241, 250, 140))
201 .with(StyleRole::Boolean, Style::new().fg_rgb(255, 121, 198))
202 .with(StyleRole::Null, Style::new().dimmed().fg_rgb(98, 114, 164))
203 .with(StyleRole::Punctuation, Style::new().dimmed().fg_rgb(98, 114, 164))
204 .with(StyleRole::Index, Style::new().fg_rgb(139, 233, 253))
205 .with(StyleRole::Metadata, Style::new().dimmed().fg_rgb(98, 114, 164))
206 .with(StyleRole::Sensitive, Style::new().bold().fg_rgb(255, 85, 85))
207 .with(StyleRole::Truncated, Style::new().italic().fg_rgb(241, 250, 140))
208 .with(StyleRole::Error, Style::new().bold().fg_rgb(255, 85, 85))
209 .with(StyleRole::Muted, Style::new().dimmed().fg_rgb(98, 114, 164))
210 }
211
212 pub fn solarized_dark() -> Self {
214 Self::empty()
215 .with(StyleRole::Type, Style::new().bold().fg_rgb(203, 75, 22))
216 .with(StyleRole::Field, Style::new().fg_rgb(38, 139, 210))
217 .with(StyleRole::Variant, Style::new().bold().fg_rgb(108, 113, 196))
218 .with(StyleRole::Key, Style::new().fg_rgb(42, 161, 152))
219 .with(StyleRole::String, Style::new().fg_rgb(133, 153, 0))
220 .with(StyleRole::Number, Style::new().fg_rgb(181, 137, 0))
221 .with(StyleRole::Boolean, Style::new().fg_rgb(211, 54, 130))
222 .with(StyleRole::Null, Style::new().dimmed().fg_rgb(101, 123, 131))
223 .with(StyleRole::Punctuation, Style::new().dimmed().fg_rgb(88, 110, 117))
224 .with(StyleRole::Index, Style::new().fg_rgb(42, 161, 152))
225 .with(StyleRole::Metadata, Style::new().dimmed().fg_rgb(88, 110, 117))
226 .with(StyleRole::Sensitive, Style::new().bold().fg_rgb(220, 50, 47))
227 .with(StyleRole::Truncated, Style::new().italic().fg_rgb(181, 137, 0))
228 .with(StyleRole::Error, Style::new().bold().fg_rgb(220, 50, 47))
229 .with(StyleRole::Muted, Style::new().dimmed().fg_rgb(88, 110, 117))
230 }
231
232 pub fn solarized_light() -> Self {
234 Self::empty()
235 .with(StyleRole::Type, Style::new().bold().fg_rgb(203, 75, 22))
236 .with(StyleRole::Field, Style::new().fg_rgb(38, 139, 210))
237 .with(StyleRole::Variant, Style::new().bold().fg_rgb(108, 113, 196))
238 .with(StyleRole::Key, Style::new().fg_rgb(42, 161, 152))
239 .with(StyleRole::String, Style::new().fg_rgb(133, 153, 0))
240 .with(StyleRole::Number, Style::new().fg_rgb(181, 137, 0))
241 .with(StyleRole::Boolean, Style::new().fg_rgb(211, 54, 130))
242 .with(StyleRole::Null, Style::new().dimmed().fg_rgb(147, 161, 161))
243 .with(StyleRole::Punctuation, Style::new().fg_rgb(101, 123, 131))
244 .with(StyleRole::Index, Style::new().fg_rgb(42, 161, 152))
245 .with(StyleRole::Metadata, Style::new().dimmed().fg_rgb(131, 148, 150))
246 .with(StyleRole::Sensitive, Style::new().bold().fg_rgb(220, 50, 47))
247 .with(StyleRole::Truncated, Style::new().italic().fg_rgb(181, 137, 0))
248 .with(StyleRole::Error, Style::new().bold().fg_rgb(220, 50, 47))
249 .with(StyleRole::Muted, Style::new().dimmed().fg_rgb(147, 161, 161))
250 }
251
252 pub fn one_dark() -> Self {
254 Self::empty()
255 .with(StyleRole::Type, Style::new().bold().fg_rgb(229, 192, 123))
256 .with(StyleRole::Field, Style::new().fg_rgb(97, 175, 239))
257 .with(StyleRole::Variant, Style::new().bold().fg_rgb(198, 120, 221))
258 .with(StyleRole::Key, Style::new().fg_rgb(86, 182, 194))
259 .with(StyleRole::String, Style::new().fg_rgb(152, 195, 121))
260 .with(StyleRole::Number, Style::new().fg_rgb(209, 154, 102))
261 .with(StyleRole::Boolean, Style::new().fg_rgb(198, 120, 221))
262 .with(StyleRole::Null, Style::new().dimmed().fg_rgb(120, 128, 142))
263 .with(StyleRole::Punctuation, Style::new().dimmed().fg_rgb(92, 99, 112))
264 .with(StyleRole::Index, Style::new().fg_rgb(86, 182, 194))
265 .with(StyleRole::Metadata, Style::new().dimmed().fg_rgb(92, 99, 112))
266 .with(StyleRole::Sensitive, Style::new().bold().fg_rgb(224, 108, 117))
267 .with(StyleRole::Truncated, Style::new().italic().fg_rgb(229, 192, 123))
268 .with(StyleRole::Error, Style::new().bold().fg_rgb(224, 108, 117))
269 .with(StyleRole::Muted, Style::new().dimmed().fg_rgb(92, 99, 112))
270 }
271
272 pub fn catppuccin_mocha() -> Self {
274 Self::empty()
275 .with(StyleRole::Type, Style::new().bold().fg_rgb(250, 179, 135))
276 .with(StyleRole::Field, Style::new().fg_rgb(137, 180, 250))
277 .with(StyleRole::Variant, Style::new().bold().fg_rgb(203, 166, 247))
278 .with(StyleRole::Key, Style::new().fg_rgb(148, 226, 213))
279 .with(StyleRole::String, Style::new().fg_rgb(166, 227, 161))
280 .with(StyleRole::Number, Style::new().fg_rgb(249, 226, 175))
281 .with(StyleRole::Boolean, Style::new().fg_rgb(245, 194, 231))
282 .with(StyleRole::Null, Style::new().dimmed().fg_rgb(147, 153, 178))
283 .with(StyleRole::Punctuation, Style::new().dimmed().fg_rgb(108, 112, 134))
284 .with(StyleRole::Index, Style::new().fg_rgb(137, 220, 235))
285 .with(StyleRole::Metadata, Style::new().dimmed().fg_rgb(166, 173, 200))
286 .with(StyleRole::Sensitive, Style::new().bold().fg_rgb(243, 139, 168))
287 .with(StyleRole::Truncated, Style::new().italic().fg_rgb(249, 226, 175))
288 .with(StyleRole::Error, Style::new().bold().fg_rgb(243, 139, 168))
289 .with(StyleRole::Muted, Style::new().dimmed().fg_rgb(88, 91, 112))
290 }
291
292 pub fn catppuccin() -> Self {
294 Self::catppuccin_mocha()
295 }
296
297 pub fn tokyo_night() -> Self {
299 Self::empty()
300 .with(StyleRole::Type, Style::new().bold().fg_rgb(255, 158, 100))
301 .with(StyleRole::Field, Style::new().fg_rgb(122, 162, 247))
302 .with(StyleRole::Variant, Style::new().bold().fg_rgb(187, 154, 247))
303 .with(StyleRole::Key, Style::new().fg_rgb(125, 207, 255))
304 .with(StyleRole::String, Style::new().fg_rgb(158, 206, 106))
305 .with(StyleRole::Number, Style::new().fg_rgb(224, 175, 104))
306 .with(StyleRole::Boolean, Style::new().fg_rgb(187, 154, 247))
307 .with(StyleRole::Null, Style::new().dimmed().fg_rgb(120, 124, 153))
308 .with(StyleRole::Punctuation, Style::new().dimmed().fg_rgb(86, 95, 137))
309 .with(StyleRole::Index, Style::new().fg_rgb(125, 207, 255))
310 .with(StyleRole::Metadata, Style::new().dimmed().fg_rgb(86, 95, 137))
311 .with(StyleRole::Sensitive, Style::new().bold().fg_rgb(247, 118, 142))
312 .with(StyleRole::Truncated, Style::new().italic().fg_rgb(224, 175, 104))
313 .with(StyleRole::Error, Style::new().bold().fg_rgb(247, 118, 142))
314 .with(StyleRole::Muted, Style::new().dimmed().fg_rgb(86, 95, 137))
315 }
316
317 pub fn monokai() -> Self {
319 Self::empty()
320 .with(StyleRole::Type, Style::new().bold().fg_rgb(253, 151, 31))
321 .with(StyleRole::Field, Style::new().fg_rgb(102, 217, 239))
322 .with(StyleRole::Variant, Style::new().bold().fg_rgb(174, 129, 255))
323 .with(StyleRole::Key, Style::new().fg_rgb(102, 217, 239))
324 .with(StyleRole::String, Style::new().fg_rgb(166, 226, 46))
325 .with(StyleRole::Number, Style::new().fg_rgb(230, 219, 116))
326 .with(StyleRole::Boolean, Style::new().fg_rgb(249, 38, 114))
327 .with(StyleRole::Null, Style::new().dimmed().fg_rgb(140, 138, 125))
328 .with(StyleRole::Punctuation, Style::new().dimmed().fg_rgb(117, 113, 94))
329 .with(StyleRole::Index, Style::new().fg_rgb(102, 217, 239))
330 .with(StyleRole::Metadata, Style::new().dimmed().fg_rgb(117, 113, 94))
331 .with(StyleRole::Sensitive, Style::new().bold().fg_rgb(249, 38, 114))
332 .with(StyleRole::Truncated, Style::new().italic().fg_rgb(230, 219, 116))
333 .with(StyleRole::Error, Style::new().bold().fg_rgb(249, 38, 114))
334 .with(StyleRole::Muted, Style::new().dimmed().fg_rgb(117, 113, 94))
335 }
336
337 pub fn ayu_dark() -> Self {
339 Self::empty()
340 .with(StyleRole::Type, Style::new().bold().fg_rgb(255, 153, 64))
341 .with(StyleRole::Field, Style::new().fg_rgb(54, 163, 217))
342 .with(StyleRole::Variant, Style::new().bold().fg_rgb(212, 191, 255))
343 .with(StyleRole::Key, Style::new().fg_rgb(149, 230, 203))
344 .with(StyleRole::String, Style::new().fg_rgb(184, 204, 82))
345 .with(StyleRole::Number, Style::new().fg_rgb(231, 197, 71))
346 .with(StyleRole::Boolean, Style::new().fg_rgb(212, 191, 255))
347 .with(StyleRole::Null, Style::new().dimmed().fg_rgb(120, 126, 135))
348 .with(StyleRole::Punctuation, Style::new().dimmed().fg_rgb(92, 103, 115))
349 .with(StyleRole::Index, Style::new().fg_rgb(95, 180, 210))
350 .with(StyleRole::Metadata, Style::new().dimmed().fg_rgb(92, 103, 115))
351 .with(StyleRole::Sensitive, Style::new().bold().fg_rgb(240, 113, 120))
352 .with(StyleRole::Truncated, Style::new().italic().fg_rgb(231, 197, 71))
353 .with(StyleRole::Error, Style::new().bold().fg_rgb(240, 113, 120))
354 .with(StyleRole::Muted, Style::new().dimmed().fg_rgb(92, 103, 115))
355 }
356
357 pub const fn with(mut self, role: StyleRole, style: Style) -> Self {
359 self.styles[role.index()] = style;
360 self
361 }
362
363 #[inline]
365 pub const fn style(&self, role: StyleRole) -> Style {
366 self.styles[role.index()]
367 }
368
369 pub fn adapt_to(self, level: ColorLevel) -> Self {
371 match level {
372 ColorLevel::Auto => {
373 let detected = ColorLevel::detect();
374 if detected == ColorLevel::Auto { self } else { self.adapt_to(detected) }
375 }
376 ColorLevel::Truecolor => self,
377 ColorLevel::Ansi256 => self.to_ansi256(),
378 ColorLevel::Ansi16 => self.to_ansi16(),
379 ColorLevel::None => self.to_monochrome(),
380 }
381 }
382
383 pub fn to_ansi256(self) -> Self {
385 let mut new_theme = self;
386 let mut i = 0;
387 while i < StyleRole::COUNT {
388 new_theme.styles[i] = new_theme.styles[i].to_ansi256();
389 i += 1;
390 }
391 new_theme
392 }
393
394 pub fn to_ansi16(self) -> Self {
396 let mut new_theme = self;
397 let mut i = 0;
398 while i < StyleRole::COUNT {
399 new_theme.styles[i] = new_theme.styles[i].to_ansi16();
400 i += 1;
401 }
402 new_theme
403 }
404
405 pub fn to_monochrome(self) -> Self {
407 let mut new_theme = self;
408 let mut i = 0;
409 while i < StyleRole::COUNT {
410 new_theme.styles[i] = new_theme.styles[i].to_monochrome();
411 i += 1;
412 }
413 new_theme
414 }
415
416 pub fn is_plain(&self) -> bool {
418 self.styles.iter().all(|s| s.is_plain())
419 }
420}