1use std::collections::HashMap;
7
8use crate::style::Style;
9
10#[derive(Debug, Clone)]
16pub struct Theme {
17 pub styles: HashMap<String, Style>,
19 pub inherit: Option<Box<Theme>>,
21}
22
23impl Theme {
24 pub fn new() -> Self {
26 Self {
27 styles: HashMap::new(),
28 inherit: None,
29 }
30 }
31
32 pub fn with_inherit(inherit: Theme) -> Self {
34 Self {
35 styles: HashMap::new(),
36 inherit: Some(Box::new(inherit)),
37 }
38 }
39
40 pub fn get(&self, name: &str) -> Option<&Style> {
42 self.styles
43 .get(name)
44 .or_else(|| self.inherit.as_ref().and_then(|i| i.get(name)))
45 }
46
47 pub fn set(&mut self, name: impl Into<String>, style: Style) {
49 self.styles.insert(name.into(), style);
50 }
51
52 pub fn merge(&mut self, other: &Theme) {
54 for (name, style) in &other.styles {
55 self.styles
56 .entry(name.clone())
57 .or_insert_with(|| style.clone());
58 }
59 }
60}
61
62impl Default for Theme {
63 fn default() -> Self {
64 Self::new()
65 }
66}
67
68#[derive(Debug, Clone)]
75pub struct ThemeStack {
76 themes: Vec<Theme>,
77}
78
79impl Default for ThemeStack {
80 fn default() -> Self {
81 Self::new()
82 }
83}
84
85impl ThemeStack {
86 pub fn new() -> Self {
87 Self { themes: Vec::new() }
88 }
89
90 pub fn push(&mut self, theme: Theme) {
91 self.themes.push(theme);
92 }
93
94 pub fn pop(&mut self) -> Option<Theme> {
95 self.themes.pop()
96 }
97
98 pub fn get(&self, name: &str) -> Option<Style> {
100 for theme in self.themes.iter().rev() {
101 if let Some(s) = theme.get(name) {
102 return Some(s.clone());
103 }
104 }
105 None
106 }
107}
108
109pub mod names {
115 pub const REPR_NUMBER: &str = "repr.number";
117 pub const REPR_STR: &str = "repr.str";
118 pub const REPR_BOOL_TRUE: &str = "repr.bool_true";
119 pub const REPR_BOOL_FALSE: &str = "repr.bool_false";
120 pub const REPR_NONE: &str = "repr.none";
121 pub const REPR_URL: &str = "repr.url";
122 pub const REPR_PATH: &str = "repr.path";
123 pub const REPR_IPV4: &str = "repr.ipv4";
124 pub const REPR_IPV6: &str = "repr.ipv6";
125 pub const REPR_ELLIPSIS: &str = "repr.ellipsis";
126 pub const REPR_ATTRIB_NAME: &str = "repr.attrib_name";
127 pub const REPR_ATTRIB_VALUE: &str = "repr.attrib_value";
128 pub const REPR_TAG_NAME: &str = "repr.tag_name";
129 pub const REPR_TAG_CONTENTS: &str = "repr.tag_contents";
130 pub const REPR_TAG_PUNCTUATION: &str = "repr.tag_punctuation";
131 pub const REPR_BRACE: &str = "repr.brace";
132 pub const REPR_CALL: &str = "repr.call";
133 pub const REPR_COMMA: &str = "repr.comma";
134 pub const REPR_BOOL: &str = "repr.bool";
135 pub const REPR_ERROR: &str = "repr.error";
136
137 pub const TABLE_HEADER: &str = "table.header";
139 pub const TABLE_CELL: &str = "table.cell";
140 pub const TABLE_ROW: &str = "table.row";
141 pub const TABLE_FOOTER: &str = "table.footer";
142 pub const TABLE_TITLE: &str = "table.title";
143 pub const TABLE_CAPTION: &str = "table.caption";
144 pub const TABLE_BORDER: &str = "table.border";
145
146 pub const LOGGING_KEYWORD: &str = "logging.keyword";
148 pub const LOGGING_LEVEL_DEBUG: &str = "logging.level.debug";
149 pub const LOGGING_LEVEL_INFO: &str = "logging.level.info";
150 pub const LOGGING_LEVEL_WARNING: &str = "logging.level.warning";
151 pub const LOGGING_LEVEL_ERROR: &str = "logging.level.error";
152 pub const LOGGING_LEVEL_CRITICAL: &str = "logging.level.critical";
153 pub const LOGGING_LEVEL_NOTSET: &str = "logging.level.notset";
154
155 pub const TRACEBACK_BORDER: &str = "traceback.border";
157 pub const TRACEBACK_TITLE: &str = "traceback.title";
158 pub const TRACEBACK_ERROR: &str = "traceback.error";
159 pub const TRACEBACK_ERROR_MARK: &str = "traceback.error_mark";
160 pub const TRACEBACK_FILENAME: &str = "traceback.filename";
161 pub const TRACEBACK_LINE_NO: &str = "traceback.line_no";
162 pub const TRACEBACK_LOCALS_HEADER: &str = "traceback.locals_header";
163 pub const TRACEBACK_LOCALS_KEY: &str = "traceback.locals_key";
164 pub const TRACEBACK_LOCALS_VALUE: &str = "traceback.locals_value";
165 pub const TRACEBACK_EXC_TYPE: &str = "traceback.exc_type";
166 pub const TRACEBACK_EXC_VALUE: &str = "traceback.exc_value";
167
168 pub const RULE_LINE: &str = "rule.line";
170 pub const RULE_TEXT: &str = "rule.text";
171 pub const BAR_COMPLETE: &str = "bar.complete";
172 pub const BAR_FINISHED: &str = "bar.finished";
173 pub const BAR_PULSE: &str = "bar.pulse";
174 pub const BAR_REMAINING: &str = "bar.remaining";
175 pub const PROGRESS_DESCRIPTION: &str = "progress.description";
176 pub const PROGRESS_PERCENTAGE: &str = "progress.percentage";
177 pub const PROGRESS_REMAINING: &str = "progress.remaining";
178 pub const PROGRESS_ELAPSED: &str = "progress.elapsed";
179 pub const PROGRESS_DATA: &str = "progress.data";
180 pub const PROGRESS_DOWNLOAD: &str = "progress.download";
181 pub const PROGRESS_TRANSFER: &str = "progress.transfer";
182 pub const PROGRESS_FILESIZE: &str = "progress.filesize";
183 pub const PROGRESS_TOTAL: &str = "progress.total";
184 pub const TREE: &str = "tree";
185 pub const TREE_LINE: &str = "tree.line";
186 pub const MARKDOWN_H1: &str = "markdown.h1";
187 pub const MARKDOWN_H2: &str = "markdown.h2";
188 pub const MARKDOWN_CODE: &str = "markdown.code";
189 pub const MARKDOWN_LINK: &str = "markdown.link";
190 pub const MARKDOWN_ITEM: &str = "markdown.item";
191 pub const MARKDOWN_H3: &str = "markdown.h3";
192 pub const MARKDOWN_H4: &str = "markdown.h4";
193 pub const MARKDOWN_H5: &str = "markdown.h5";
194 pub const MARKDOWN_H6: &str = "markdown.h6";
195 pub const MARKDOWN_H7: &str = "markdown.h7";
196 pub const MARKDOWN_PARAGRAPH: &str = "markdown.paragraph";
197 pub const MARKDOWN_BLOCKQUOTE: &str = "markdown.blockquote";
198 pub const MARKDOWN_LIST: &str = "markdown.list";
199 pub const MARKDOWN_ITEM_BULLET: &str = "markdown.item.bullet";
200 pub const MARKDOWN_ITEM_NUMBER: &str = "markdown.item.number";
201 pub const MARKDOWN_TABLE: &str = "markdown.table";
202 pub const MARKDOWN_TABLE_HEADER: &str = "markdown.table.header";
203 pub const MARKDOWN_CODE_BLOCK: &str = "markdown.code.block";
204 pub const MARKDOWN_CODE_INLINE: &str = "markdown.code.inline";
205 pub const MARKDOWN_HR: &str = "markdown.hr";
206 pub const JSON_KEY: &str = "json.key";
207 pub const JSON_STR: &str = "json.str";
208 pub const JSON_NUMBER: &str = "json.number";
209 pub const JSON_BOOL: &str = "json.bool";
210 pub const JSON_NULL: &str = "json.null";
211 pub const JSON_BOOL_TRUE: &str = "json.bool_true";
212 pub const JSON_BOOL_FALSE: &str = "json.bool_false";
213 pub const JSON_BRACE: &str = "json.brace";
214
215 pub const STATUS_SPINNER: &str = "status.spinner";
217 pub const STATUS_MESSAGE: &str = "status.message";
218
219 pub const PROMPT: &str = "prompt";
221 pub const PROMPT_CHOICES: &str = "prompt.choices";
222 pub const PROMPT_DEFAULT: &str = "prompt.default";
223
224 pub const SYNTAX_COMMENT: &str = "syntax.comment";
226 pub const SYNTAX_KEYWORD: &str = "syntax.keyword";
227 pub const SYNTAX_STRING: &str = "syntax.string";
228 pub const SYNTAX_NUMBER: &str = "syntax.number";
229 pub const SYNTAX_FUNCTION: &str = "syntax.function";
230 pub const SYNTAX_TYPE: &str = "syntax.type";
231}
232
233pub fn default_theme() -> Theme {
235 let mut t = Theme::new();
236 use crate::color::Color;
237 use crate::style::Style;
238
239 t.set(
241 names::REPR_NUMBER,
242 Style::new().color(Color::parse("cyan").unwrap()).bold(true),
243 );
244 t.set(
245 names::REPR_STR,
246 Style::new().color(Color::parse("green").unwrap()),
247 );
248 t.set(
249 names::REPR_BOOL_TRUE,
250 Style::new()
251 .color(Color::parse("bright_green").unwrap())
252 .bold(true),
253 );
254 t.set(
255 names::REPR_BOOL_FALSE,
256 Style::new()
257 .color(Color::parse("bright_red").unwrap())
258 .bold(true),
259 );
260 t.set(
261 names::REPR_NONE,
262 Style::new()
263 .color(Color::parse("bright_yellow").unwrap())
264 .dim(true),
265 );
266 t.set(
267 names::REPR_URL,
268 Style::new()
269 .color(Color::parse("bright_blue").unwrap())
270 .underline(true),
271 );
272 t.set(
273 names::REPR_PATH,
274 Style::new().color(Color::parse("magenta").unwrap()),
275 );
276 t.set(
277 names::REPR_ATTRIB_NAME,
278 Style::new().color(Color::parse("bright_cyan").unwrap()),
279 );
280 t.set(
281 names::REPR_ATTRIB_VALUE,
282 Style::new().color(Color::parse("white").unwrap()),
283 );
284 t.set(
285 names::REPR_ELLIPSIS,
286 Style::new().dim(true).color(Color::parse("white").unwrap()),
287 );
288 t.set(
289 names::REPR_IPV4,
290 Style::new()
291 .color(Color::parse("bright_blue").unwrap())
292 .bold(true),
293 );
294 t.set(
295 names::REPR_IPV6,
296 Style::new()
297 .color(Color::parse("bright_magenta").unwrap())
298 .bold(true),
299 );
300 t.set(
301 names::REPR_TAG_NAME,
302 Style::new()
303 .color(Color::parse("bright_blue").unwrap())
304 .bold(true),
305 );
306 t.set(
307 names::REPR_TAG_CONTENTS,
308 Style::new().color(Color::parse("white").unwrap()),
309 );
310 t.set(
311 names::REPR_TAG_PUNCTUATION,
312 Style::new().color(Color::parse("bright_black").unwrap()),
313 );
314 t.set(
315 names::REPR_BRACE,
316 Style::new().color(Color::parse("bright_black").unwrap()),
317 );
318 t.set(
319 names::REPR_CALL,
320 Style::new().color(Color::parse("bright_cyan").unwrap()),
321 );
322 t.set(
323 names::REPR_COMMA,
324 Style::new().color(Color::parse("bright_black").unwrap()),
325 );
326 t.set(
327 names::REPR_BOOL,
328 Style::new()
329 .color(Color::parse("bright_yellow").unwrap())
330 .bold(true),
331 );
332 t.set(
333 names::REPR_ERROR,
334 Style::new()
335 .color(Color::parse("bright_red").unwrap())
336 .bold(true),
337 );
338
339 t.set(
341 names::TABLE_HEADER,
342 Style::new()
343 .bold(true)
344 .color(Color::parse("white").unwrap()),
345 );
346 t.set(names::TABLE_FOOTER, Style::new().bold(true));
347 t.set(names::TABLE_TITLE, Style::new().bold(true));
348 t.set(names::TABLE_CAPTION, Style::new().dim(true));
349 t.set(
350 names::TABLE_BORDER,
351 Style::new().color(Color::parse("bright_black").unwrap()),
352 );
353 t.set(
354 names::TABLE_CELL,
355 Style::new().color(Color::parse("white").unwrap()),
356 );
357 t.set(
358 names::TABLE_ROW,
359 Style::new().color(Color::parse("white").unwrap()),
360 );
361
362 t.set(
364 names::RULE_LINE,
365 Style::new().color(Color::parse("bright_black").unwrap()),
366 );
367 t.set(names::RULE_TEXT, Style::new().bold(true));
368
369 t.set(
371 names::TREE,
372 Style::new().color(Color::parse("white").unwrap()),
373 );
374 t.set(
375 names::TREE_LINE,
376 Style::new().color(Color::parse("bright_black").unwrap()),
377 );
378
379 t.set(
381 names::BAR_COMPLETE,
382 Style::new().color(Color::parse("green").unwrap()),
383 );
384 t.set(
385 names::BAR_FINISHED,
386 Style::new().color(Color::parse("bright_green").unwrap()),
387 );
388 t.set(
389 names::BAR_PULSE,
390 Style::new().color(Color::parse("bright_cyan").unwrap()),
391 );
392 t.set(
393 names::PROGRESS_DESCRIPTION,
394 Style::new().color(Color::parse("white").unwrap()),
395 );
396 t.set(
397 names::PROGRESS_PERCENTAGE,
398 Style::new().color(Color::parse("cyan").unwrap()),
399 );
400 t.set(
401 names::PROGRESS_REMAINING,
402 Style::new().color(Color::parse("bright_black").unwrap()),
403 );
404 t.set(
405 names::PROGRESS_ELAPSED,
406 Style::new().color(Color::parse("cyan").unwrap()),
407 );
408 t.set(
409 names::PROGRESS_DATA,
410 Style::new().color(Color::parse("bright_blue").unwrap()),
411 );
412 t.set(
413 names::PROGRESS_DOWNLOAD,
414 Style::new().color(Color::parse("bright_cyan").unwrap()),
415 );
416 t.set(
417 names::PROGRESS_TRANSFER,
418 Style::new().color(Color::parse("bright_magenta").unwrap()),
419 );
420 t.set(
421 names::PROGRESS_FILESIZE,
422 Style::new().color(Color::parse("bright_green").unwrap()),
423 );
424 t.set(
425 names::PROGRESS_TOTAL,
426 Style::new().color(Color::parse("bright_blue").unwrap()),
427 );
428 t.set(
429 names::BAR_REMAINING,
430 Style::new().color(Color::parse("bright_black").unwrap()),
431 );
432
433 t.set(
435 names::MARKDOWN_H1,
436 Style::new()
437 .bold(true)
438 .color(Color::parse("bright_cyan").unwrap()),
439 );
440 t.set(
441 names::MARKDOWN_H2,
442 Style::new().bold(true).color(Color::parse("cyan").unwrap()),
443 );
444 t.set(
445 names::MARKDOWN_CODE,
446 Style::new()
447 .color(Color::parse("bright_yellow").unwrap())
448 .bgcolor(Color::parse("black").unwrap()),
449 );
450 t.set(
451 names::MARKDOWN_LINK,
452 Style::new()
453 .color(Color::parse("bright_blue").unwrap())
454 .underline(true),
455 );
456 t.set(
457 names::MARKDOWN_H3,
458 Style::new()
459 .bold(true)
460 .color(Color::parse("yellow").unwrap()),
461 );
462 t.set(
463 names::MARKDOWN_H4,
464 Style::new()
465 .bold(true)
466 .color(Color::parse("green").unwrap()),
467 );
468 t.set(
469 names::MARKDOWN_H5,
470 Style::new().bold(true).color(Color::parse("blue").unwrap()),
471 );
472 t.set(
473 names::MARKDOWN_H6,
474 Style::new()
475 .bold(true)
476 .color(Color::parse("bright_black").unwrap()),
477 );
478 t.set(
479 names::MARKDOWN_H7,
480 Style::new()
481 .dim(true)
482 .color(Color::parse("bright_black").unwrap()),
483 );
484 t.set(
485 names::MARKDOWN_PARAGRAPH,
486 Style::new().color(Color::parse("white").unwrap()),
487 );
488 t.set(
489 names::MARKDOWN_BLOCKQUOTE,
490 Style::new().color(Color::parse("bright_black").unwrap()),
491 );
492 t.set(
493 names::MARKDOWN_LIST,
494 Style::new().color(Color::parse("white").unwrap()),
495 );
496 t.set(
497 names::MARKDOWN_ITEM,
498 Style::new().color(Color::parse("cyan").unwrap()),
499 );
500 t.set(
501 names::MARKDOWN_ITEM_BULLET,
502 Style::new().color(Color::parse("cyan").unwrap()),
503 );
504 t.set(
505 names::MARKDOWN_ITEM_NUMBER,
506 Style::new().color(Color::parse("cyan").unwrap()),
507 );
508 t.set(
509 names::MARKDOWN_TABLE,
510 Style::new().color(Color::parse("white").unwrap()),
511 );
512 t.set(
513 names::MARKDOWN_TABLE_HEADER,
514 Style::new()
515 .bold(true)
516 .color(Color::parse("white").unwrap()),
517 );
518 t.set(
519 names::MARKDOWN_CODE_BLOCK,
520 Style::new()
521 .color(Color::parse("bright_yellow").unwrap())
522 .bgcolor(Color::parse("black").unwrap()),
523 );
524 t.set(
525 names::MARKDOWN_CODE_INLINE,
526 Style::new().color(Color::parse("bright_yellow").unwrap()),
527 );
528 t.set(
529 names::MARKDOWN_HR,
530 Style::new().color(Color::parse("bright_black").unwrap()),
531 );
532
533 t.set(
535 names::JSON_KEY,
536 Style::new().color(Color::parse("cyan").unwrap()),
537 );
538 t.set(
539 names::JSON_STR,
540 Style::new().color(Color::parse("green").unwrap()),
541 );
542 t.set(
543 names::JSON_NUMBER,
544 Style::new()
545 .color(Color::parse("bright_blue").unwrap())
546 .bold(true),
547 );
548 t.set(
549 names::JSON_BOOL,
550 Style::new()
551 .color(Color::parse("bright_yellow").unwrap())
552 .bold(true),
553 );
554 t.set(
555 names::JSON_NULL,
556 Style::new()
557 .color(Color::parse("bright_red").unwrap())
558 .dim(true),
559 );
560 t.set(
561 names::JSON_BOOL_TRUE,
562 Style::new()
563 .color(Color::parse("bright_green").unwrap())
564 .bold(true),
565 );
566 t.set(
567 names::JSON_BOOL_FALSE,
568 Style::new()
569 .color(Color::parse("bright_red").unwrap())
570 .bold(true),
571 );
572 t.set(
573 names::JSON_BRACE,
574 Style::new().color(Color::parse("bright_black").unwrap()),
575 );
576
577 t.set(
579 names::TRACEBACK_BORDER,
580 Style::new().color(Color::parse("red").unwrap()),
581 );
582 t.set(names::TRACEBACK_TITLE, Style::new().bold(true));
583 t.set(
584 names::TRACEBACK_ERROR,
585 Style::new()
586 .color(Color::parse("bright_red").unwrap())
587 .bold(true),
588 );
589 t.set(
590 names::TRACEBACK_ERROR_MARK,
591 Style::new()
592 .color(Color::parse("bright_red").unwrap())
593 .bold(true),
594 );
595 t.set(
596 names::TRACEBACK_FILENAME,
597 Style::new().color(Color::parse("cyan").unwrap()),
598 );
599 t.set(
600 names::TRACEBACK_LINE_NO,
601 Style::new().color(Color::parse("bright_black").unwrap()),
602 );
603 t.set(names::TRACEBACK_LOCALS_HEADER, Style::new().bold(true));
604 t.set(
605 names::TRACEBACK_LOCALS_KEY,
606 Style::new().color(Color::parse("bright_cyan").unwrap()),
607 );
608 t.set(
609 names::TRACEBACK_LOCALS_VALUE,
610 Style::new().color(Color::parse("white").unwrap()),
611 );
612 t.set(
613 names::TRACEBACK_EXC_TYPE,
614 Style::new()
615 .color(Color::parse("bright_red").unwrap())
616 .bold(true),
617 );
618 t.set(
619 names::TRACEBACK_EXC_VALUE,
620 Style::new().color(Color::parse("white").unwrap()),
621 );
622
623 t.set(
625 names::LOGGING_KEYWORD,
626 Style::new()
627 .color(Color::parse("bright_yellow").unwrap())
628 .bold(true),
629 );
630 t.set(
631 names::LOGGING_LEVEL_NOTSET,
632 Style::new().dim(true).color(Color::parse("white").unwrap()),
633 );
634
635 t.set(
637 names::STATUS_SPINNER,
638 Style::new().color(Color::parse("bright_cyan").unwrap()),
639 );
640 t.set(
641 names::STATUS_MESSAGE,
642 Style::new().color(Color::parse("white").unwrap()),
643 );
644 t.set(
645 names::PROMPT,
646 Style::new().color(Color::parse("bright_cyan").unwrap()),
647 );
648 t.set(
649 names::PROMPT_CHOICES,
650 Style::new().color(Color::parse("cyan").unwrap()),
651 );
652 t.set(
653 names::PROMPT_DEFAULT,
654 Style::new().color(Color::parse("bright_black").unwrap()),
655 );
656
657 t
658}