Skip to main content

holodeck_simctl_core/models/
theme_name.rs

1use serde::{Deserialize, Serialize};
2
3/// Which built-in TUI color theme to use. The actual colors live in
4/// `holodeck-tui::theme` (a rendering concern) — this is just the selector,
5/// kept in Core alongside the rest of `Config` so it round-trips through
6/// `~/.config/holodeck/config.json` like `videoCodec`/`screenshotType`.
7#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
8#[serde(rename_all = "kebab-case")]
9pub enum ThemeName {
10    /// The [Default+](https://github.com/otaviocc/default-plus) colorscheme.
11    #[default]
12    DefaultPlus,
13    /// The terminal's own 16-color scheme — correct on a background whose
14    /// depth/appearance nothing has detected, at the cost of not matching
15    /// any specific palette exactly on every terminal.
16    Ansi,
17    /// [Tokyo Night](https://github.com/folke/tokyonight.nvim).
18    TokyoNight,
19    /// [Nord](https://www.nordtheme.com).
20    Nord,
21    /// [Dracula](https://draculatheme.com).
22    Dracula,
23    /// [Gruvbox](https://github.com/morhetz/gruvbox) dark.
24    Gruvbox,
25    /// [Catppuccin](https://catppuccin.com) Mocha.
26    CatppuccinMocha,
27    /// [Solarized](https://ethanschoonover.com/solarized/) Dark.
28    SolarizedDark,
29}
30
31impl ThemeName {
32    pub const ALL: [ThemeName; 8] = [
33        ThemeName::DefaultPlus,
34        ThemeName::Ansi,
35        ThemeName::TokyoNight,
36        ThemeName::Nord,
37        ThemeName::Dracula,
38        ThemeName::Gruvbox,
39        ThemeName::CatppuccinMocha,
40        ThemeName::SolarizedDark,
41    ];
42
43    pub fn raw_value(self) -> &'static str {
44        match self {
45            ThemeName::DefaultPlus => "default-plus",
46            ThemeName::Ansi => "ansi",
47            ThemeName::TokyoNight => "tokyo-night",
48            ThemeName::Nord => "nord",
49            ThemeName::Dracula => "dracula",
50            ThemeName::Gruvbox => "gruvbox",
51            ThemeName::CatppuccinMocha => "catppuccin-mocha",
52            ThemeName::SolarizedDark => "solarized-dark",
53        }
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60
61    #[test]
62    fn default_is_default_plus() {
63        assert_eq!(ThemeName::default(), ThemeName::DefaultPlus);
64    }
65
66    #[test]
67    fn serializes_as_kebab_case() {
68        assert_eq!(serde_json::to_string(&ThemeName::DefaultPlus).unwrap(), "\"default-plus\"");
69        assert_eq!(serde_json::to_string(&ThemeName::Ansi).unwrap(), "\"ansi\"");
70        assert_eq!(serde_json::to_string(&ThemeName::TokyoNight).unwrap(), "\"tokyo-night\"");
71        assert_eq!(serde_json::to_string(&ThemeName::Nord).unwrap(), "\"nord\"");
72        assert_eq!(serde_json::to_string(&ThemeName::Dracula).unwrap(), "\"dracula\"");
73        assert_eq!(serde_json::to_string(&ThemeName::Gruvbox).unwrap(), "\"gruvbox\"");
74        assert_eq!(serde_json::to_string(&ThemeName::CatppuccinMocha).unwrap(), "\"catppuccin-mocha\"");
75        assert_eq!(serde_json::to_string(&ThemeName::SolarizedDark).unwrap(), "\"solarized-dark\"");
76    }
77
78    #[test]
79    fn raw_value_round_trips_through_json_for_every_variant() {
80        for name in ThemeName::ALL {
81            let json = serde_json::to_string(&name).unwrap();
82            assert_eq!(json, format!("\"{}\"", name.raw_value()));
83            let parsed: ThemeName = serde_json::from_str(&json).unwrap();
84            assert_eq!(parsed, name);
85        }
86    }
87}