Skip to main content

pulldown_cmark_mdcat/
theme.rs

1// Copyright 2018-2020 Sebastian Wiesner <sebastian@swsnr.de>
2
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7//! Provide a colour theme for mdcat.
8
9use anstyle::{AnsiColor, Color, RgbColor, Style};
10
11/// A colour theme for mdcat.
12///
13/// All fields are public so themes can be fully customised, e.g. from a user config file.
14/// `h1_prefix_style` is a derived convenience (background-only padding matching `h1_text_style`'s
15/// background); use [`Theme::with_h1`] to keep the two in sync when changing the H1 background.
16#[derive(Debug, Clone, Hash, PartialEq, Eq)]
17pub struct Theme {
18    /// Style for HTML blocks.
19    pub html_block_style: Style,
20    /// Style for inline HTML.
21    pub inline_html_style: Style,
22    /// Style for code, unless the code is syntax-highlighted.
23    pub code_style: Style,
24    /// Style for links.
25    pub link_style: Style,
26    /// Color for image links (unless the image is rendered inline)
27    pub image_link_style: Style,
28    /// Color for rulers.
29    pub rule_color: Color,
30    /// Style for block quote borders (`│`).
31    pub quote_border_style: Style,
32    /// Style for H2 headings.
33    pub h2_style: Style,
34    /// Marker written before H2 heading text (default `"━━ "`).
35    pub h2_marker: String,
36    /// Style for H3 headings.
37    pub h3_style: Style,
38    /// Marker written before H3 heading text (default `"── "`).
39    pub h3_marker: String,
40    /// Style for H4 headings.
41    pub h4_style: Style,
42    /// Marker written before H4 heading text (default `"┄ "`).
43    pub h4_marker: String,
44    /// Style for H5 headings.
45    pub h5_style: Style,
46    /// Marker written before H5 heading text (default `"╌ "`).
47    pub h5_marker: String,
48    /// Style for H6 headings.
49    pub h6_style: Style,
50    /// Marker written before H6 heading text (default `"· "`).
51    pub h6_marker: String,
52    /// Style for footnote references and definitions.
53    pub footnote_style: Style,
54    /// Style for math expressions.
55    pub math_style: Style,
56    /// Style for `[!NOTE]` alerts.
57    pub alert_note_style: Style,
58    /// Icon and label written for `[!NOTE]` alerts (default `"ℹ NOTE"`).
59    pub alert_note_label: String,
60    /// Style for `[!TIP]` alerts.
61    pub alert_tip_style: Style,
62    /// Icon and label written for `[!TIP]` alerts (default `"◆ TIP"`).
63    pub alert_tip_label: String,
64    /// Style for `[!IMPORTANT]` alerts.
65    pub alert_important_style: Style,
66    /// Icon and label written for `[!IMPORTANT]` alerts (default `"★ IMPORTANT"`).
67    pub alert_important_label: String,
68    /// Style for `[!WARNING]` alerts.
69    pub alert_warning_style: Style,
70    /// Icon and label written for `[!WARNING]` alerts (default `"⚠ WARNING"`).
71    pub alert_warning_label: String,
72    /// Style for `[!CAUTION]` alerts.
73    pub alert_caution_style: Style,
74    /// Icon and label written for `[!CAUTION]` alerts (default `"✖ CAUTION"`).
75    pub alert_caution_label: String,
76    /// Background-colored padding space written before H1 text.
77    pub h1_prefix_style: Style,
78    /// Style for H1 heading text (fg + bg color).
79    pub h1_text_style: Style,
80}
81
82impl Theme {
83    /// Set the H1 style, keeping `h1_prefix_style`'s background in sync with `text_style`'s.
84    pub fn with_h1(mut self, text_style: Style) -> Self {
85        let bg = text_style.get_bg_color();
86        self.h1_prefix_style = Style::new().bg_color(bg).fg_color(bg);
87        self.h1_text_style = text_style;
88        self
89    }
90}
91
92/// Default heading markers and alert labels, shared by every built-in theme; only colors vary
93/// between themes.
94#[allow(clippy::type_complexity)]
95fn default_markers_and_labels() -> (
96    String,
97    String,
98    String,
99    String,
100    String,
101    String,
102    String,
103    String,
104    String,
105    String,
106) {
107    (
108        "━━ ".to_string(),
109        "── ".to_string(),
110        "┄ ".to_string(),
111        "╌ ".to_string(),
112        "· ".to_string(),
113        "ℹ NOTE".to_string(),
114        "◆ TIP".to_string(),
115        "★ IMPORTANT".to_string(),
116        "⚠ WARNING".to_string(),
117        "✖ CAUTION".to_string(),
118    )
119}
120
121fn rgb(r: u8, g: u8, b: u8) -> Color {
122    RgbColor(r, g, b).into()
123}
124
125fn h1(bg: Color, fg: Color) -> (Style, Style) {
126    (
127        Style::new().bg_color(Some(bg)).fg_color(Some(bg)),
128        Style::new().bg_color(Some(bg)).fg_color(Some(fg)).bold(),
129    )
130}
131
132impl Theme {
133    /// A theme for dark terminal backgrounds (the default).
134    pub fn dark() -> Self {
135        let (h1_prefix_style, h1_text_style) = (
136            Style::new()
137                .bg_color(Some(AnsiColor::BrightBlue.into()))
138                .fg_color(Some(AnsiColor::BrightBlue.into())),
139            Style::new()
140                .bg_color(Some(AnsiColor::BrightBlue.into()))
141                .fg_color(Some(AnsiColor::BrightWhite.into()))
142                .bold(),
143        );
144        let (
145            h2_marker,
146            h3_marker,
147            h4_marker,
148            h5_marker,
149            h6_marker,
150            alert_note_label,
151            alert_tip_label,
152            alert_important_label,
153            alert_warning_label,
154            alert_caution_label,
155        ) = default_markers_and_labels();
156        Self {
157            html_block_style: Style::new().fg_color(Some(AnsiColor::Green.into())),
158            inline_html_style: Style::new().fg_color(Some(AnsiColor::Green.into())),
159            code_style: Style::new().fg_color(Some(AnsiColor::Yellow.into())),
160            link_style: Style::new().fg_color(Some(AnsiColor::Blue.into())),
161            image_link_style: Style::new().fg_color(Some(AnsiColor::Magenta.into())),
162            rule_color: AnsiColor::Green.into(),
163            quote_border_style: Style::new().fg_color(Some(AnsiColor::Cyan.into())),
164            h2_style: Style::new().fg_color(Some(AnsiColor::Blue.into())).bold(),
165            h3_style: Style::new().fg_color(Some(AnsiColor::Cyan.into())).bold(),
166            h4_style: Style::new().fg_color(Some(AnsiColor::Green.into())).bold(),
167            h5_style: Style::new().fg_color(Some(AnsiColor::Yellow.into())).bold(),
168            h6_style: Style::new()
169                .fg_color(Some(AnsiColor::Magenta.into()))
170                .bold(),
171            footnote_style: Style::new().fg_color(Some(AnsiColor::Cyan.into())),
172            math_style: Style::new().fg_color(Some(AnsiColor::Yellow.into())),
173            alert_note_style: Style::new()
174                .fg_color(Some(AnsiColor::BrightBlue.into()))
175                .bold(),
176            alert_tip_style: Style::new()
177                .fg_color(Some(AnsiColor::BrightGreen.into()))
178                .bold(),
179            alert_important_style: Style::new()
180                .fg_color(Some(AnsiColor::BrightMagenta.into()))
181                .bold(),
182            alert_warning_style: Style::new()
183                .fg_color(Some(AnsiColor::BrightYellow.into()))
184                .bold(),
185            alert_caution_style: Style::new()
186                .fg_color(Some(AnsiColor::BrightRed.into()))
187                .bold(),
188            h2_marker,
189            h3_marker,
190            h4_marker,
191            h5_marker,
192            h6_marker,
193            alert_note_label,
194            alert_tip_label,
195            alert_important_label,
196            alert_warning_label,
197            alert_caution_label,
198            h1_prefix_style,
199            h1_text_style,
200        }
201    }
202
203    /// A theme for light terminal backgrounds.
204    pub fn light() -> Self {
205        let (h1_prefix_style, h1_text_style) = (
206            Style::new()
207                .bg_color(Some(AnsiColor::BrightCyan.into()))
208                .fg_color(Some(AnsiColor::BrightCyan.into())),
209            Style::new()
210                .bg_color(Some(AnsiColor::BrightCyan.into()))
211                .fg_color(Some(AnsiColor::Black.into()))
212                .bold(),
213        );
214        let (
215            h2_marker,
216            h3_marker,
217            h4_marker,
218            h5_marker,
219            h6_marker,
220            alert_note_label,
221            alert_tip_label,
222            alert_important_label,
223            alert_warning_label,
224            alert_caution_label,
225        ) = default_markers_and_labels();
226        Self {
227            html_block_style: Style::new().fg_color(Some(AnsiColor::Green.into())),
228            inline_html_style: Style::new().fg_color(Some(AnsiColor::Green.into())),
229            code_style: Style::new().fg_color(Some(AnsiColor::Blue.into())),
230            link_style: Style::new().fg_color(Some(AnsiColor::Blue.into())),
231            image_link_style: Style::new().fg_color(Some(AnsiColor::Magenta.into())),
232            rule_color: AnsiColor::Green.into(),
233            quote_border_style: Style::new().fg_color(Some(AnsiColor::Cyan.into())),
234            h2_style: Style::new()
235                .fg_color(Some(AnsiColor::Magenta.into()))
236                .bold(),
237            h3_style: Style::new().fg_color(Some(AnsiColor::Blue.into())).bold(),
238            h4_style: Style::new().fg_color(Some(AnsiColor::Cyan.into())).bold(),
239            h5_style: Style::new().fg_color(Some(AnsiColor::Green.into())).bold(),
240            h6_style: Style::new().fg_color(Some(AnsiColor::Red.into())).bold(),
241            footnote_style: Style::new().fg_color(Some(AnsiColor::Cyan.into())),
242            math_style: Style::new().fg_color(Some(AnsiColor::Blue.into())),
243            alert_note_style: Style::new().fg_color(Some(AnsiColor::Blue.into())).bold(),
244            alert_tip_style: Style::new().fg_color(Some(AnsiColor::Green.into())).bold(),
245            alert_important_style: Style::new()
246                .fg_color(Some(AnsiColor::Magenta.into()))
247                .bold(),
248            alert_warning_style: Style::new().fg_color(Some(AnsiColor::Red.into())).bold(),
249            alert_caution_style: Style::new()
250                .fg_color(Some(AnsiColor::BrightRed.into()))
251                .bold(),
252            h2_marker,
253            h3_marker,
254            h4_marker,
255            h5_marker,
256            h6_marker,
257            alert_note_label,
258            alert_tip_label,
259            alert_important_label,
260            alert_warning_label,
261            alert_caution_label,
262            h1_prefix_style,
263            h1_text_style,
264        }
265    }
266
267    /// Catppuccin Mocha (dark).
268    pub fn catppuccin_mocha() -> Self {
269        let (h1_prefix_style, h1_text_style) = h1(rgb(203, 166, 247), rgb(17, 17, 27));
270        let (
271            h2_marker,
272            h3_marker,
273            h4_marker,
274            h5_marker,
275            h6_marker,
276            alert_note_label,
277            alert_tip_label,
278            alert_important_label,
279            alert_warning_label,
280            alert_caution_label,
281        ) = default_markers_and_labels();
282        Self {
283            html_block_style: Style::new().fg_color(Some(rgb(250, 179, 135))),
284            inline_html_style: Style::new().fg_color(Some(rgb(250, 179, 135))),
285            code_style: Style::new().fg_color(Some(rgb(137, 220, 235))),
286            link_style: Style::new().fg_color(Some(rgb(137, 180, 250))),
287            image_link_style: Style::new().fg_color(Some(rgb(245, 194, 231))),
288            rule_color: rgb(148, 226, 213),
289            quote_border_style: Style::new().fg_color(Some(rgb(108, 112, 134))),
290            h2_style: Style::new().fg_color(Some(rgb(203, 166, 247))).bold(),
291            h3_style: Style::new().fg_color(Some(rgb(137, 180, 250))).bold(),
292            h4_style: Style::new().fg_color(Some(rgb(137, 220, 235))).bold(),
293            h5_style: Style::new().fg_color(Some(rgb(166, 227, 161))).bold(),
294            h6_style: Style::new().fg_color(Some(rgb(250, 179, 135))).bold(),
295            footnote_style: Style::new().fg_color(Some(rgb(108, 112, 134))),
296            math_style: Style::new().fg_color(Some(rgb(137, 220, 235))),
297            alert_note_style: Style::new().fg_color(Some(rgb(116, 199, 236))).bold(),
298            alert_tip_style: Style::new().fg_color(Some(rgb(166, 227, 161))).bold(),
299            alert_important_style: Style::new().fg_color(Some(rgb(203, 166, 247))).bold(),
300            alert_warning_style: Style::new().fg_color(Some(rgb(249, 226, 175))).bold(),
301            alert_caution_style: Style::new().fg_color(Some(rgb(243, 139, 168))).bold(),
302            h2_marker,
303            h3_marker,
304            h4_marker,
305            h5_marker,
306            h6_marker,
307            alert_note_label,
308            alert_tip_label,
309            alert_important_label,
310            alert_warning_label,
311            alert_caution_label,
312            h1_prefix_style,
313            h1_text_style,
314        }
315    }
316
317    /// Catppuccin Latte (light).
318    pub fn catppuccin_latte() -> Self {
319        let (h1_prefix_style, h1_text_style) = h1(rgb(136, 57, 239), rgb(239, 241, 245));
320        let (
321            h2_marker,
322            h3_marker,
323            h4_marker,
324            h5_marker,
325            h6_marker,
326            alert_note_label,
327            alert_tip_label,
328            alert_important_label,
329            alert_warning_label,
330            alert_caution_label,
331        ) = default_markers_and_labels();
332        Self {
333            html_block_style: Style::new().fg_color(Some(rgb(254, 100, 11))),
334            inline_html_style: Style::new().fg_color(Some(rgb(254, 100, 11))),
335            code_style: Style::new().fg_color(Some(rgb(4, 165, 229))),
336            link_style: Style::new().fg_color(Some(rgb(30, 102, 245))),
337            image_link_style: Style::new().fg_color(Some(rgb(234, 118, 203))),
338            rule_color: rgb(23, 146, 153),
339            quote_border_style: Style::new().fg_color(Some(rgb(124, 127, 147))),
340            h2_style: Style::new().fg_color(Some(rgb(136, 57, 239))).bold(),
341            h3_style: Style::new().fg_color(Some(rgb(30, 102, 245))).bold(),
342            h4_style: Style::new().fg_color(Some(rgb(23, 146, 153))).bold(),
343            h5_style: Style::new().fg_color(Some(rgb(64, 160, 43))).bold(),
344            h6_style: Style::new().fg_color(Some(rgb(254, 100, 11))).bold(),
345            footnote_style: Style::new().fg_color(Some(rgb(124, 127, 147))),
346            math_style: Style::new().fg_color(Some(rgb(4, 165, 229))),
347            alert_note_style: Style::new().fg_color(Some(rgb(32, 159, 181))).bold(),
348            alert_tip_style: Style::new().fg_color(Some(rgb(64, 160, 43))).bold(),
349            alert_important_style: Style::new().fg_color(Some(rgb(136, 57, 239))).bold(),
350            alert_warning_style: Style::new().fg_color(Some(rgb(223, 142, 29))).bold(),
351            alert_caution_style: Style::new().fg_color(Some(rgb(210, 15, 57))).bold(),
352            h2_marker,
353            h3_marker,
354            h4_marker,
355            h5_marker,
356            h6_marker,
357            alert_note_label,
358            alert_tip_label,
359            alert_important_label,
360            alert_warning_label,
361            alert_caution_label,
362            h1_prefix_style,
363            h1_text_style,
364        }
365    }
366
367    /// Gruvbox Dark.
368    pub fn gruvbox_dark() -> Self {
369        let (h1_prefix_style, h1_text_style) = h1(rgb(250, 189, 47), rgb(40, 40, 40));
370        let (
371            h2_marker,
372            h3_marker,
373            h4_marker,
374            h5_marker,
375            h6_marker,
376            alert_note_label,
377            alert_tip_label,
378            alert_important_label,
379            alert_warning_label,
380            alert_caution_label,
381        ) = default_markers_and_labels();
382        Self {
383            html_block_style: Style::new().fg_color(Some(rgb(214, 93, 14))),
384            inline_html_style: Style::new().fg_color(Some(rgb(214, 93, 14))),
385            code_style: Style::new().fg_color(Some(rgb(131, 165, 152))),
386            link_style: Style::new().fg_color(Some(rgb(131, 165, 152))),
387            image_link_style: Style::new().fg_color(Some(rgb(211, 134, 155))),
388            rule_color: rgb(184, 187, 38),
389            quote_border_style: Style::new().fg_color(Some(rgb(142, 192, 124))),
390            h2_style: Style::new().fg_color(Some(rgb(250, 189, 47))).bold(),
391            h3_style: Style::new().fg_color(Some(rgb(131, 165, 152))).bold(),
392            h4_style: Style::new().fg_color(Some(rgb(142, 192, 124))).bold(),
393            h5_style: Style::new().fg_color(Some(rgb(211, 134, 155))).bold(),
394            h6_style: Style::new().fg_color(Some(rgb(254, 128, 25))).bold(),
395            footnote_style: Style::new().fg_color(Some(rgb(146, 131, 116))),
396            math_style: Style::new().fg_color(Some(rgb(131, 165, 152))),
397            alert_note_style: Style::new().fg_color(Some(rgb(131, 165, 152))).bold(),
398            alert_tip_style: Style::new().fg_color(Some(rgb(184, 187, 38))).bold(),
399            alert_important_style: Style::new().fg_color(Some(rgb(211, 134, 155))).bold(),
400            alert_warning_style: Style::new().fg_color(Some(rgb(254, 128, 25))).bold(),
401            alert_caution_style: Style::new().fg_color(Some(rgb(251, 73, 52))).bold(),
402            h2_marker,
403            h3_marker,
404            h4_marker,
405            h5_marker,
406            h6_marker,
407            alert_note_label,
408            alert_tip_label,
409            alert_important_label,
410            alert_warning_label,
411            alert_caution_label,
412            h1_prefix_style,
413            h1_text_style,
414        }
415    }
416
417    /// Gruvbox Light.
418    pub fn gruvbox_light() -> Self {
419        let (h1_prefix_style, h1_text_style) = h1(rgb(181, 118, 20), rgb(251, 241, 199));
420        let (
421            h2_marker,
422            h3_marker,
423            h4_marker,
424            h5_marker,
425            h6_marker,
426            alert_note_label,
427            alert_tip_label,
428            alert_important_label,
429            alert_warning_label,
430            alert_caution_label,
431        ) = default_markers_and_labels();
432        Self {
433            html_block_style: Style::new().fg_color(Some(rgb(175, 58, 3))),
434            inline_html_style: Style::new().fg_color(Some(rgb(175, 58, 3))),
435            code_style: Style::new().fg_color(Some(rgb(7, 102, 120))),
436            link_style: Style::new().fg_color(Some(rgb(7, 102, 120))),
437            image_link_style: Style::new().fg_color(Some(rgb(143, 63, 113))),
438            rule_color: rgb(66, 123, 88),
439            quote_border_style: Style::new().fg_color(Some(rgb(66, 123, 88))),
440            h2_style: Style::new().fg_color(Some(rgb(181, 118, 20))).bold(),
441            h3_style: Style::new().fg_color(Some(rgb(7, 102, 120))).bold(),
442            h4_style: Style::new().fg_color(Some(rgb(66, 123, 88))).bold(),
443            h5_style: Style::new().fg_color(Some(rgb(143, 63, 113))).bold(),
444            h6_style: Style::new().fg_color(Some(rgb(175, 58, 3))).bold(),
445            footnote_style: Style::new().fg_color(Some(rgb(124, 111, 100))),
446            math_style: Style::new().fg_color(Some(rgb(7, 102, 120))),
447            alert_note_style: Style::new().fg_color(Some(rgb(7, 102, 120))).bold(),
448            alert_tip_style: Style::new().fg_color(Some(rgb(121, 116, 14))).bold(),
449            alert_important_style: Style::new().fg_color(Some(rgb(143, 63, 113))).bold(),
450            alert_warning_style: Style::new().fg_color(Some(rgb(181, 118, 20))).bold(),
451            alert_caution_style: Style::new().fg_color(Some(rgb(157, 0, 6))).bold(),
452            h2_marker,
453            h3_marker,
454            h4_marker,
455            h5_marker,
456            h6_marker,
457            alert_note_label,
458            alert_tip_label,
459            alert_important_label,
460            alert_warning_label,
461            alert_caution_label,
462            h1_prefix_style,
463            h1_text_style,
464        }
465    }
466
467    /// Dracula.
468    pub fn dracula() -> Self {
469        let (h1_prefix_style, h1_text_style) = h1(rgb(189, 147, 249), rgb(40, 42, 54));
470        let (
471            h2_marker,
472            h3_marker,
473            h4_marker,
474            h5_marker,
475            h6_marker,
476            alert_note_label,
477            alert_tip_label,
478            alert_important_label,
479            alert_warning_label,
480            alert_caution_label,
481        ) = default_markers_and_labels();
482        Self {
483            html_block_style: Style::new().fg_color(Some(rgb(255, 184, 108))),
484            inline_html_style: Style::new().fg_color(Some(rgb(255, 184, 108))),
485            code_style: Style::new().fg_color(Some(rgb(241, 250, 140))),
486            link_style: Style::new().fg_color(Some(rgb(139, 233, 253))),
487            image_link_style: Style::new().fg_color(Some(rgb(255, 121, 198))),
488            rule_color: rgb(80, 250, 123),
489            quote_border_style: Style::new().fg_color(Some(rgb(98, 114, 164))),
490            h2_style: Style::new().fg_color(Some(rgb(189, 147, 249))).bold(),
491            h3_style: Style::new().fg_color(Some(rgb(139, 233, 253))).bold(),
492            h4_style: Style::new().fg_color(Some(rgb(80, 250, 123))).bold(),
493            h5_style: Style::new().fg_color(Some(rgb(255, 121, 198))).bold(),
494            h6_style: Style::new().fg_color(Some(rgb(255, 184, 108))).bold(),
495            footnote_style: Style::new().fg_color(Some(rgb(98, 114, 164))),
496            math_style: Style::new().fg_color(Some(rgb(241, 250, 140))),
497            alert_note_style: Style::new().fg_color(Some(rgb(139, 233, 253))).bold(),
498            alert_tip_style: Style::new().fg_color(Some(rgb(80, 250, 123))).bold(),
499            alert_important_style: Style::new().fg_color(Some(rgb(255, 121, 198))).bold(),
500            alert_warning_style: Style::new().fg_color(Some(rgb(255, 184, 108))).bold(),
501            alert_caution_style: Style::new().fg_color(Some(rgb(255, 85, 85))).bold(),
502            h2_marker,
503            h3_marker,
504            h4_marker,
505            h5_marker,
506            h6_marker,
507            alert_note_label,
508            alert_tip_label,
509            alert_important_label,
510            alert_warning_label,
511            alert_caution_label,
512            h1_prefix_style,
513            h1_text_style,
514        }
515    }
516
517    /// Nord.
518    pub fn nord() -> Self {
519        let (h1_prefix_style, h1_text_style) = h1(rgb(94, 129, 172), rgb(236, 239, 244));
520        let (
521            h2_marker,
522            h3_marker,
523            h4_marker,
524            h5_marker,
525            h6_marker,
526            alert_note_label,
527            alert_tip_label,
528            alert_important_label,
529            alert_warning_label,
530            alert_caution_label,
531        ) = default_markers_and_labels();
532        Self {
533            html_block_style: Style::new().fg_color(Some(rgb(208, 135, 112))),
534            inline_html_style: Style::new().fg_color(Some(rgb(208, 135, 112))),
535            code_style: Style::new().fg_color(Some(rgb(143, 188, 187))),
536            link_style: Style::new().fg_color(Some(rgb(136, 192, 208))),
537            image_link_style: Style::new().fg_color(Some(rgb(180, 142, 173))),
538            rule_color: rgb(136, 192, 208),
539            quote_border_style: Style::new().fg_color(Some(rgb(76, 86, 106))),
540            h2_style: Style::new().fg_color(Some(rgb(94, 129, 172))).bold(),
541            h3_style: Style::new().fg_color(Some(rgb(129, 161, 193))).bold(),
542            h4_style: Style::new().fg_color(Some(rgb(136, 192, 208))).bold(),
543            h5_style: Style::new().fg_color(Some(rgb(163, 190, 140))).bold(),
544            h6_style: Style::new().fg_color(Some(rgb(235, 203, 139))).bold(),
545            footnote_style: Style::new().fg_color(Some(rgb(76, 86, 106))),
546            math_style: Style::new().fg_color(Some(rgb(143, 188, 187))),
547            alert_note_style: Style::new().fg_color(Some(rgb(143, 188, 187))).bold(),
548            alert_tip_style: Style::new().fg_color(Some(rgb(163, 190, 140))).bold(),
549            alert_important_style: Style::new().fg_color(Some(rgb(180, 142, 173))).bold(),
550            alert_warning_style: Style::new().fg_color(Some(rgb(235, 203, 139))).bold(),
551            alert_caution_style: Style::new().fg_color(Some(rgb(191, 97, 106))).bold(),
552            h2_marker,
553            h3_marker,
554            h4_marker,
555            h5_marker,
556            h6_marker,
557            alert_note_label,
558            alert_tip_label,
559            alert_important_label,
560            alert_warning_label,
561            alert_caution_label,
562            h1_prefix_style,
563            h1_text_style,
564        }
565    }
566
567    /// Solarized Dark.
568    pub fn solarized_dark() -> Self {
569        let (h1_prefix_style, h1_text_style) = h1(rgb(38, 139, 210), rgb(0, 43, 54));
570        let (
571            h2_marker,
572            h3_marker,
573            h4_marker,
574            h5_marker,
575            h6_marker,
576            alert_note_label,
577            alert_tip_label,
578            alert_important_label,
579            alert_warning_label,
580            alert_caution_label,
581        ) = default_markers_and_labels();
582        Self {
583            html_block_style: Style::new().fg_color(Some(rgb(203, 75, 22))),
584            inline_html_style: Style::new().fg_color(Some(rgb(203, 75, 22))),
585            code_style: Style::new().fg_color(Some(rgb(42, 161, 152))),
586            link_style: Style::new().fg_color(Some(rgb(38, 139, 210))),
587            image_link_style: Style::new().fg_color(Some(rgb(211, 54, 130))),
588            rule_color: rgb(42, 161, 152),
589            quote_border_style: Style::new().fg_color(Some(rgb(88, 110, 117))),
590            h2_style: Style::new().fg_color(Some(rgb(38, 139, 210))).bold(),
591            h3_style: Style::new().fg_color(Some(rgb(42, 161, 152))).bold(),
592            h4_style: Style::new().fg_color(Some(rgb(133, 153, 0))).bold(),
593            h5_style: Style::new().fg_color(Some(rgb(211, 54, 130))).bold(),
594            h6_style: Style::new().fg_color(Some(rgb(203, 75, 22))).bold(),
595            footnote_style: Style::new().fg_color(Some(rgb(88, 110, 117))),
596            math_style: Style::new().fg_color(Some(rgb(42, 161, 152))),
597            alert_note_style: Style::new().fg_color(Some(rgb(108, 113, 196))).bold(),
598            alert_tip_style: Style::new().fg_color(Some(rgb(133, 153, 0))).bold(),
599            alert_important_style: Style::new().fg_color(Some(rgb(211, 54, 130))).bold(),
600            alert_warning_style: Style::new().fg_color(Some(rgb(181, 137, 0))).bold(),
601            alert_caution_style: Style::new().fg_color(Some(rgb(220, 50, 47))).bold(),
602            h2_marker,
603            h3_marker,
604            h4_marker,
605            h5_marker,
606            h6_marker,
607            alert_note_label,
608            alert_tip_label,
609            alert_important_label,
610            alert_warning_label,
611            alert_caution_label,
612            h1_prefix_style,
613            h1_text_style,
614        }
615    }
616
617    /// Solarized Light.
618    pub fn solarized_light() -> Self {
619        let (h1_prefix_style, h1_text_style) = h1(rgb(38, 139, 210), rgb(253, 246, 227));
620        Self {
621            h1_prefix_style,
622            h1_text_style,
623            ..Self::solarized_dark()
624        }
625    }
626}
627
628impl Default for Theme {
629    fn default() -> Self {
630        Self::dark()
631    }
632}
633
634/// Combine styles.
635pub trait CombineStyle {
636    /// Put this style on top of the other style.
637    ///
638    /// Return a new style which falls back to the `other` style for all style attributes not
639    /// specified in this style.
640    fn on_top_of(self, other: &Self) -> Self;
641}
642
643impl CombineStyle for Style {
644    /// Put this style on top of the `other` style.
645    fn on_top_of(self, other: &Style) -> Style {
646        Style::new()
647            .fg_color(self.get_fg_color().or(other.get_fg_color()))
648            .bg_color(self.get_bg_color().or(other.get_bg_color()))
649            .effects(other.get_effects() | self.get_effects())
650            .underline_color(self.get_underline_color().or(other.get_underline_color()))
651    }
652}