1use crate::color::Color;
2
3mod vscode;
4
5use serde::{Deserialize, Serialize};
6pub use vscode::parse_vscode_theme;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct Theme {
10 #[allow(dead_code)]
11 pub name: String,
12 pub style: Style,
13 pub gutter_style: Style,
14 pub status_line_style: StatusLineStyle,
15 pub token_styles: Vec<TokenStyle>,
16 pub selection_style: Option<Style>,
17}
18
19impl Theme {
20 #[must_use]
21 pub fn get_style(&self, scope: &str) -> Option<Style> {
22 self.token_styles.iter().find_map(|token_style| {
23 if token_style.scope.contains(&scope.to_string()) {
24 Some(token_style.style.clone())
25 } else {
26 None
27 }
28 })
29 }
30
31 #[allow(dead_code)]
32 #[must_use]
33 pub fn get_selection_background(&self) -> Color {
34 self.selection_style
35 .as_ref()
36 .and_then(|s| s.background)
37 .unwrap_or(Color::Rgb {
38 r: 255,
39 g: 255,
40 b: 255,
41 })
42 }
43}
44
45impl Default for Theme {
46 fn default() -> Self {
47 Self {
48 name: "default".to_string(),
49 style: Style {
50 foreground: Some(Color::Rgb {
51 r: 255,
52 g: 255,
53 b: 255,
54 }),
55 background: Some(Color::Rgb { r: 0, g: 0, b: 0 }),
56 bold: false,
57 italic: false,
58 },
59 gutter_style: Style::default(),
60 status_line_style: StatusLineStyle::default(),
61 token_styles: vec![],
62 selection_style: None,
63 }
64 }
65}
66
67#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct TokenStyle {
69 pub name: Option<String>,
70 pub scope: Vec<String>,
71 pub style: Style,
72}
73
74#[derive(Debug, Default, Clone, Serialize, Deserialize)]
75pub struct StatusLineStyle {
76 pub outer_style: Style,
77 pub outer_chars: [char; 4],
78 pub inner_style: Style,
79}
80
81#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
82pub struct Style {
83 pub foreground: Option<Color>,
84 pub background: Option<Color>,
85 pub bold: bool,
86 pub italic: bool,
87}
88
89impl Style {
90 #[allow(dead_code)]
91 #[must_use]
92 pub fn fallback_background(&self, fallback_background: &Style) -> Style {
93 let background = self
94 .background
95 .or(fallback_background.background)
96 .or(Some(Color::Rgb { r: 0, g: 0, b: 0 }));
97 self.with_background(background)
98 }
99
100 #[allow(dead_code)]
101 #[must_use]
102 pub fn with_background(&self, background: Option<Color>) -> Style {
103 Style {
104 background,
105 ..(*self)
106 }
107 }
108
109 #[allow(dead_code)]
110 #[must_use]
111 pub fn inverted(&self) -> Style {
112 Style {
113 foreground: self.background,
114 background: self.foreground,
115 bold: self.bold,
116 italic: self.italic,
117 }
118 }
119}