Skip to main content

supercode_harness/tui/
theme.rs

1//! P5-4 (§3.1 `capabilities.tui.theme`, D8 "themes"): the SEMANTIC theme
2//! choice — which of the built-in named roles (accent, dim, error, …) a
3//! renderer should map to actual terminal colors. Deliberately carries no
4//! `ratatui::style::Color` (or any other terminal-library type) so this
5//! stays part of the terminal-free view-model core; `crates/cli`'s
6//! render layer owns the actual RGB/ANSI mapping.
7
8/// A built-in theme name. `Dark` is the default (matches
9/// `Config::tui_theme`'s `"dark"` default).
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
11pub enum Theme {
12    /// Default — matches most terminals' dark-background convention.
13    #[default]
14    Dark,
15    /// Light-background terminal.
16    Light,
17}
18
19impl Theme {
20    /// Parse `capabilities.tui.theme`'s string value. Unknown values fall
21    /// back to [`Theme::Dark`] rather than erroring — a themed cosmetic
22    /// setting is never worth refusing to start the TUI over.
23    pub fn parse(s: &str) -> Self {
24        match s.to_ascii_lowercase().as_str() {
25            "light" => Theme::Light,
26            _ => Theme::Dark,
27        }
28    }
29
30    /// The toggle [`crate::tui::Action::ToggleTheme`] cycles to.
31    pub fn toggled(self) -> Self {
32        match self {
33            Theme::Dark => Theme::Light,
34            Theme::Light => Theme::Dark,
35        }
36    }
37
38    /// A short, human-readable name for the status line.
39    pub fn label(self) -> &'static str {
40        match self {
41            Theme::Dark => "dark",
42            Theme::Light => "light",
43        }
44    }
45}
46
47#[cfg(test)]
48mod tests {
49    use super::*;
50
51    #[test]
52    fn parse_known_and_unknown() {
53        assert_eq!(Theme::parse("light"), Theme::Light);
54        assert_eq!(Theme::parse("LIGHT"), Theme::Light);
55        assert_eq!(Theme::parse("dark"), Theme::Dark);
56        assert_eq!(Theme::parse("bogus"), Theme::Dark);
57        assert_eq!(Theme::parse(""), Theme::Dark);
58    }
59
60    #[test]
61    fn toggle_round_trips() {
62        assert_eq!(Theme::Dark.toggled(), Theme::Light);
63        assert_eq!(Theme::Light.toggled(), Theme::Dark);
64        assert_eq!(Theme::Dark.toggled().toggled(), Theme::Dark);
65    }
66
67    #[test]
68    fn default_is_dark() {
69        assert_eq!(Theme::default(), Theme::Dark);
70    }
71}