1use anstyle::{AnsiColor, Color, RgbColor, Style};
10
11#[derive(Debug, Clone)]
13pub struct Theme {
14 pub(crate) html_block_style: Style,
16 pub(crate) inline_html_style: Style,
18 pub(crate) code_style: Style,
20 pub(crate) link_style: Style,
22 pub(crate) image_link_style: Style,
24 pub(crate) rule_color: Color,
26 pub(crate) quote_border_style: Style,
28 pub(crate) h2_style: Style,
30 pub(crate) h3_style: Style,
32 pub(crate) h4_style: Style,
34 pub(crate) h5_style: Style,
36 pub(crate) h6_style: Style,
38 pub(crate) footnote_style: Style,
40 pub(crate) math_style: Style,
42 pub(crate) alert_note_style: Style,
44 pub(crate) alert_tip_style: Style,
46 pub(crate) alert_important_style: Style,
48 pub(crate) alert_warning_style: Style,
50 pub(crate) alert_caution_style: Style,
52 pub(crate) h1_prefix_style: Style,
54 pub(crate) h1_text_style: Style,
56}
57
58fn rgb(r: u8, g: u8, b: u8) -> Color {
59 RgbColor(r, g, b).into()
60}
61
62fn h1(bg: Color, fg: Color) -> (Style, Style) {
63 (
64 Style::new().bg_color(Some(bg)).fg_color(Some(bg)),
65 Style::new().bg_color(Some(bg)).fg_color(Some(fg)).bold(),
66 )
67}
68
69impl Theme {
70 pub fn dark() -> Self {
72 let (h1_prefix_style, h1_text_style) = (
73 Style::new()
74 .bg_color(Some(AnsiColor::BrightBlue.into()))
75 .fg_color(Some(AnsiColor::BrightBlue.into())),
76 Style::new()
77 .bg_color(Some(AnsiColor::BrightBlue.into()))
78 .fg_color(Some(AnsiColor::BrightWhite.into()))
79 .bold(),
80 );
81 Self {
82 html_block_style: Style::new().fg_color(Some(AnsiColor::Green.into())),
83 inline_html_style: Style::new().fg_color(Some(AnsiColor::Green.into())),
84 code_style: Style::new().fg_color(Some(AnsiColor::Yellow.into())),
85 link_style: Style::new().fg_color(Some(AnsiColor::Blue.into())),
86 image_link_style: Style::new().fg_color(Some(AnsiColor::Magenta.into())),
87 rule_color: AnsiColor::Green.into(),
88 quote_border_style: Style::new().fg_color(Some(AnsiColor::Cyan.into())),
89 h2_style: Style::new().fg_color(Some(AnsiColor::Blue.into())).bold(),
90 h3_style: Style::new().fg_color(Some(AnsiColor::Cyan.into())).bold(),
91 h4_style: Style::new().fg_color(Some(AnsiColor::Green.into())).bold(),
92 h5_style: Style::new().fg_color(Some(AnsiColor::Yellow.into())).bold(),
93 h6_style: Style::new()
94 .fg_color(Some(AnsiColor::Magenta.into()))
95 .bold(),
96 footnote_style: Style::new().fg_color(Some(AnsiColor::Cyan.into())),
97 math_style: Style::new().fg_color(Some(AnsiColor::Yellow.into())),
98 alert_note_style: Style::new()
99 .fg_color(Some(AnsiColor::BrightBlue.into()))
100 .bold(),
101 alert_tip_style: Style::new()
102 .fg_color(Some(AnsiColor::BrightGreen.into()))
103 .bold(),
104 alert_important_style: Style::new()
105 .fg_color(Some(AnsiColor::BrightMagenta.into()))
106 .bold(),
107 alert_warning_style: Style::new()
108 .fg_color(Some(AnsiColor::BrightYellow.into()))
109 .bold(),
110 alert_caution_style: Style::new()
111 .fg_color(Some(AnsiColor::BrightRed.into()))
112 .bold(),
113 h1_prefix_style,
114 h1_text_style,
115 }
116 }
117
118 pub fn light() -> Self {
120 let (h1_prefix_style, h1_text_style) = (
121 Style::new()
122 .bg_color(Some(AnsiColor::BrightCyan.into()))
123 .fg_color(Some(AnsiColor::BrightCyan.into())),
124 Style::new()
125 .bg_color(Some(AnsiColor::BrightCyan.into()))
126 .fg_color(Some(AnsiColor::Black.into()))
127 .bold(),
128 );
129 Self {
130 html_block_style: Style::new().fg_color(Some(AnsiColor::Green.into())),
131 inline_html_style: Style::new().fg_color(Some(AnsiColor::Green.into())),
132 code_style: Style::new().fg_color(Some(AnsiColor::Blue.into())),
133 link_style: Style::new().fg_color(Some(AnsiColor::Blue.into())),
134 image_link_style: Style::new().fg_color(Some(AnsiColor::Magenta.into())),
135 rule_color: AnsiColor::Green.into(),
136 quote_border_style: Style::new().fg_color(Some(AnsiColor::Cyan.into())),
137 h2_style: Style::new()
138 .fg_color(Some(AnsiColor::Magenta.into()))
139 .bold(),
140 h3_style: Style::new().fg_color(Some(AnsiColor::Blue.into())).bold(),
141 h4_style: Style::new().fg_color(Some(AnsiColor::Cyan.into())).bold(),
142 h5_style: Style::new().fg_color(Some(AnsiColor::Green.into())).bold(),
143 h6_style: Style::new().fg_color(Some(AnsiColor::Red.into())).bold(),
144 footnote_style: Style::new().fg_color(Some(AnsiColor::Cyan.into())),
145 math_style: Style::new().fg_color(Some(AnsiColor::Blue.into())),
146 alert_note_style: Style::new().fg_color(Some(AnsiColor::Blue.into())).bold(),
147 alert_tip_style: Style::new().fg_color(Some(AnsiColor::Green.into())).bold(),
148 alert_important_style: Style::new()
149 .fg_color(Some(AnsiColor::Magenta.into()))
150 .bold(),
151 alert_warning_style: Style::new().fg_color(Some(AnsiColor::Red.into())).bold(),
152 alert_caution_style: Style::new()
153 .fg_color(Some(AnsiColor::BrightRed.into()))
154 .bold(),
155 h1_prefix_style,
156 h1_text_style,
157 }
158 }
159
160 pub fn catppuccin_mocha() -> Self {
162 let (h1_prefix_style, h1_text_style) = h1(rgb(203, 166, 247), rgb(17, 17, 27));
163 Self {
164 html_block_style: Style::new().fg_color(Some(rgb(250, 179, 135))),
165 inline_html_style: Style::new().fg_color(Some(rgb(250, 179, 135))),
166 code_style: Style::new().fg_color(Some(rgb(137, 220, 235))),
167 link_style: Style::new().fg_color(Some(rgb(137, 180, 250))),
168 image_link_style: Style::new().fg_color(Some(rgb(245, 194, 231))),
169 rule_color: rgb(148, 226, 213),
170 quote_border_style: Style::new().fg_color(Some(rgb(108, 112, 134))),
171 h2_style: Style::new().fg_color(Some(rgb(203, 166, 247))).bold(),
172 h3_style: Style::new().fg_color(Some(rgb(137, 180, 250))).bold(),
173 h4_style: Style::new().fg_color(Some(rgb(137, 220, 235))).bold(),
174 h5_style: Style::new().fg_color(Some(rgb(166, 227, 161))).bold(),
175 h6_style: Style::new().fg_color(Some(rgb(250, 179, 135))).bold(),
176 footnote_style: Style::new().fg_color(Some(rgb(108, 112, 134))),
177 math_style: Style::new().fg_color(Some(rgb(137, 220, 235))),
178 alert_note_style: Style::new().fg_color(Some(rgb(116, 199, 236))).bold(),
179 alert_tip_style: Style::new().fg_color(Some(rgb(166, 227, 161))).bold(),
180 alert_important_style: Style::new().fg_color(Some(rgb(203, 166, 247))).bold(),
181 alert_warning_style: Style::new().fg_color(Some(rgb(249, 226, 175))).bold(),
182 alert_caution_style: Style::new().fg_color(Some(rgb(243, 139, 168))).bold(),
183 h1_prefix_style,
184 h1_text_style,
185 }
186 }
187
188 pub fn catppuccin_latte() -> Self {
190 let (h1_prefix_style, h1_text_style) = h1(rgb(136, 57, 239), rgb(239, 241, 245));
191 Self {
192 html_block_style: Style::new().fg_color(Some(rgb(254, 100, 11))),
193 inline_html_style: Style::new().fg_color(Some(rgb(254, 100, 11))),
194 code_style: Style::new().fg_color(Some(rgb(4, 165, 229))),
195 link_style: Style::new().fg_color(Some(rgb(30, 102, 245))),
196 image_link_style: Style::new().fg_color(Some(rgb(234, 118, 203))),
197 rule_color: rgb(23, 146, 153),
198 quote_border_style: Style::new().fg_color(Some(rgb(124, 127, 147))),
199 h2_style: Style::new().fg_color(Some(rgb(136, 57, 239))).bold(),
200 h3_style: Style::new().fg_color(Some(rgb(30, 102, 245))).bold(),
201 h4_style: Style::new().fg_color(Some(rgb(23, 146, 153))).bold(),
202 h5_style: Style::new().fg_color(Some(rgb(64, 160, 43))).bold(),
203 h6_style: Style::new().fg_color(Some(rgb(254, 100, 11))).bold(),
204 footnote_style: Style::new().fg_color(Some(rgb(124, 127, 147))),
205 math_style: Style::new().fg_color(Some(rgb(4, 165, 229))),
206 alert_note_style: Style::new().fg_color(Some(rgb(32, 159, 181))).bold(),
207 alert_tip_style: Style::new().fg_color(Some(rgb(64, 160, 43))).bold(),
208 alert_important_style: Style::new().fg_color(Some(rgb(136, 57, 239))).bold(),
209 alert_warning_style: Style::new().fg_color(Some(rgb(223, 142, 29))).bold(),
210 alert_caution_style: Style::new().fg_color(Some(rgb(210, 15, 57))).bold(),
211 h1_prefix_style,
212 h1_text_style,
213 }
214 }
215
216 pub fn gruvbox_dark() -> Self {
218 let (h1_prefix_style, h1_text_style) = h1(rgb(250, 189, 47), rgb(40, 40, 40));
219 Self {
220 html_block_style: Style::new().fg_color(Some(rgb(214, 93, 14))),
221 inline_html_style: Style::new().fg_color(Some(rgb(214, 93, 14))),
222 code_style: Style::new().fg_color(Some(rgb(131, 165, 152))),
223 link_style: Style::new().fg_color(Some(rgb(131, 165, 152))),
224 image_link_style: Style::new().fg_color(Some(rgb(211, 134, 155))),
225 rule_color: rgb(184, 187, 38),
226 quote_border_style: Style::new().fg_color(Some(rgb(142, 192, 124))),
227 h2_style: Style::new().fg_color(Some(rgb(250, 189, 47))).bold(),
228 h3_style: Style::new().fg_color(Some(rgb(131, 165, 152))).bold(),
229 h4_style: Style::new().fg_color(Some(rgb(142, 192, 124))).bold(),
230 h5_style: Style::new().fg_color(Some(rgb(211, 134, 155))).bold(),
231 h6_style: Style::new().fg_color(Some(rgb(254, 128, 25))).bold(),
232 footnote_style: Style::new().fg_color(Some(rgb(146, 131, 116))),
233 math_style: Style::new().fg_color(Some(rgb(131, 165, 152))),
234 alert_note_style: Style::new().fg_color(Some(rgb(131, 165, 152))).bold(),
235 alert_tip_style: Style::new().fg_color(Some(rgb(184, 187, 38))).bold(),
236 alert_important_style: Style::new().fg_color(Some(rgb(211, 134, 155))).bold(),
237 alert_warning_style: Style::new().fg_color(Some(rgb(254, 128, 25))).bold(),
238 alert_caution_style: Style::new().fg_color(Some(rgb(251, 73, 52))).bold(),
239 h1_prefix_style,
240 h1_text_style,
241 }
242 }
243
244 pub fn gruvbox_light() -> Self {
246 let (h1_prefix_style, h1_text_style) = h1(rgb(181, 118, 20), rgb(251, 241, 199));
247 Self {
248 html_block_style: Style::new().fg_color(Some(rgb(175, 58, 3))),
249 inline_html_style: Style::new().fg_color(Some(rgb(175, 58, 3))),
250 code_style: Style::new().fg_color(Some(rgb(7, 102, 120))),
251 link_style: Style::new().fg_color(Some(rgb(7, 102, 120))),
252 image_link_style: Style::new().fg_color(Some(rgb(143, 63, 113))),
253 rule_color: rgb(66, 123, 88),
254 quote_border_style: Style::new().fg_color(Some(rgb(66, 123, 88))),
255 h2_style: Style::new().fg_color(Some(rgb(181, 118, 20))).bold(),
256 h3_style: Style::new().fg_color(Some(rgb(7, 102, 120))).bold(),
257 h4_style: Style::new().fg_color(Some(rgb(66, 123, 88))).bold(),
258 h5_style: Style::new().fg_color(Some(rgb(143, 63, 113))).bold(),
259 h6_style: Style::new().fg_color(Some(rgb(175, 58, 3))).bold(),
260 footnote_style: Style::new().fg_color(Some(rgb(124, 111, 100))),
261 math_style: Style::new().fg_color(Some(rgb(7, 102, 120))),
262 alert_note_style: Style::new().fg_color(Some(rgb(7, 102, 120))).bold(),
263 alert_tip_style: Style::new().fg_color(Some(rgb(121, 116, 14))).bold(),
264 alert_important_style: Style::new().fg_color(Some(rgb(143, 63, 113))).bold(),
265 alert_warning_style: Style::new().fg_color(Some(rgb(181, 118, 20))).bold(),
266 alert_caution_style: Style::new().fg_color(Some(rgb(157, 0, 6))).bold(),
267 h1_prefix_style,
268 h1_text_style,
269 }
270 }
271
272 pub fn dracula() -> Self {
274 let (h1_prefix_style, h1_text_style) = h1(rgb(189, 147, 249), rgb(40, 42, 54));
275 Self {
276 html_block_style: Style::new().fg_color(Some(rgb(255, 184, 108))),
277 inline_html_style: Style::new().fg_color(Some(rgb(255, 184, 108))),
278 code_style: Style::new().fg_color(Some(rgb(241, 250, 140))),
279 link_style: Style::new().fg_color(Some(rgb(139, 233, 253))),
280 image_link_style: Style::new().fg_color(Some(rgb(255, 121, 198))),
281 rule_color: rgb(80, 250, 123),
282 quote_border_style: Style::new().fg_color(Some(rgb(98, 114, 164))),
283 h2_style: Style::new().fg_color(Some(rgb(189, 147, 249))).bold(),
284 h3_style: Style::new().fg_color(Some(rgb(139, 233, 253))).bold(),
285 h4_style: Style::new().fg_color(Some(rgb(80, 250, 123))).bold(),
286 h5_style: Style::new().fg_color(Some(rgb(255, 121, 198))).bold(),
287 h6_style: Style::new().fg_color(Some(rgb(255, 184, 108))).bold(),
288 footnote_style: Style::new().fg_color(Some(rgb(98, 114, 164))),
289 math_style: Style::new().fg_color(Some(rgb(241, 250, 140))),
290 alert_note_style: Style::new().fg_color(Some(rgb(139, 233, 253))).bold(),
291 alert_tip_style: Style::new().fg_color(Some(rgb(80, 250, 123))).bold(),
292 alert_important_style: Style::new().fg_color(Some(rgb(255, 121, 198))).bold(),
293 alert_warning_style: Style::new().fg_color(Some(rgb(255, 184, 108))).bold(),
294 alert_caution_style: Style::new().fg_color(Some(rgb(255, 85, 85))).bold(),
295 h1_prefix_style,
296 h1_text_style,
297 }
298 }
299
300 pub fn nord() -> Self {
302 let (h1_prefix_style, h1_text_style) = h1(rgb(94, 129, 172), rgb(236, 239, 244));
303 Self {
304 html_block_style: Style::new().fg_color(Some(rgb(208, 135, 112))),
305 inline_html_style: Style::new().fg_color(Some(rgb(208, 135, 112))),
306 code_style: Style::new().fg_color(Some(rgb(143, 188, 187))),
307 link_style: Style::new().fg_color(Some(rgb(136, 192, 208))),
308 image_link_style: Style::new().fg_color(Some(rgb(180, 142, 173))),
309 rule_color: rgb(136, 192, 208),
310 quote_border_style: Style::new().fg_color(Some(rgb(76, 86, 106))),
311 h2_style: Style::new().fg_color(Some(rgb(94, 129, 172))).bold(),
312 h3_style: Style::new().fg_color(Some(rgb(129, 161, 193))).bold(),
313 h4_style: Style::new().fg_color(Some(rgb(136, 192, 208))).bold(),
314 h5_style: Style::new().fg_color(Some(rgb(163, 190, 140))).bold(),
315 h6_style: Style::new().fg_color(Some(rgb(235, 203, 139))).bold(),
316 footnote_style: Style::new().fg_color(Some(rgb(76, 86, 106))),
317 math_style: Style::new().fg_color(Some(rgb(143, 188, 187))),
318 alert_note_style: Style::new().fg_color(Some(rgb(143, 188, 187))).bold(),
319 alert_tip_style: Style::new().fg_color(Some(rgb(163, 190, 140))).bold(),
320 alert_important_style: Style::new().fg_color(Some(rgb(180, 142, 173))).bold(),
321 alert_warning_style: Style::new().fg_color(Some(rgb(235, 203, 139))).bold(),
322 alert_caution_style: Style::new().fg_color(Some(rgb(191, 97, 106))).bold(),
323 h1_prefix_style,
324 h1_text_style,
325 }
326 }
327
328 pub fn solarized_dark() -> Self {
330 let (h1_prefix_style, h1_text_style) = h1(rgb(38, 139, 210), rgb(0, 43, 54));
331 Self {
332 html_block_style: Style::new().fg_color(Some(rgb(203, 75, 22))),
333 inline_html_style: Style::new().fg_color(Some(rgb(203, 75, 22))),
334 code_style: Style::new().fg_color(Some(rgb(42, 161, 152))),
335 link_style: Style::new().fg_color(Some(rgb(38, 139, 210))),
336 image_link_style: Style::new().fg_color(Some(rgb(211, 54, 130))),
337 rule_color: rgb(42, 161, 152),
338 quote_border_style: Style::new().fg_color(Some(rgb(88, 110, 117))),
339 h2_style: Style::new().fg_color(Some(rgb(38, 139, 210))).bold(),
340 h3_style: Style::new().fg_color(Some(rgb(42, 161, 152))).bold(),
341 h4_style: Style::new().fg_color(Some(rgb(133, 153, 0))).bold(),
342 h5_style: Style::new().fg_color(Some(rgb(211, 54, 130))).bold(),
343 h6_style: Style::new().fg_color(Some(rgb(203, 75, 22))).bold(),
344 footnote_style: Style::new().fg_color(Some(rgb(88, 110, 117))),
345 math_style: Style::new().fg_color(Some(rgb(42, 161, 152))),
346 alert_note_style: Style::new().fg_color(Some(rgb(108, 113, 196))).bold(),
347 alert_tip_style: Style::new().fg_color(Some(rgb(133, 153, 0))).bold(),
348 alert_important_style: Style::new().fg_color(Some(rgb(211, 54, 130))).bold(),
349 alert_warning_style: Style::new().fg_color(Some(rgb(181, 137, 0))).bold(),
350 alert_caution_style: Style::new().fg_color(Some(rgb(220, 50, 47))).bold(),
351 h1_prefix_style,
352 h1_text_style,
353 }
354 }
355
356 pub fn solarized_light() -> Self {
358 let (h1_prefix_style, h1_text_style) = h1(rgb(38, 139, 210), rgb(253, 246, 227));
359 Self {
360 h1_prefix_style,
361 h1_text_style,
362 ..Self::solarized_dark()
363 }
364 }
365}
366
367impl Default for Theme {
368 fn default() -> Self {
369 Self::dark()
370 }
371}
372
373pub trait CombineStyle {
375 fn on_top_of(self, other: &Self) -> Self;
380}
381
382impl CombineStyle for Style {
383 fn on_top_of(self, other: &Style) -> Style {
385 Style::new()
386 .fg_color(self.get_fg_color().or(other.get_fg_color()))
387 .bg_color(self.get_bg_color().or(other.get_bg_color()))
388 .effects(other.get_effects() | self.get_effects())
389 .underline_color(self.get_underline_color().or(other.get_underline_color()))
390 }
391}