diff --git a/docs/user-guide/05-themes.md b/docs/user-guide/05-themes.md index 40b43280..2785c343 100644 --- a/docs/user-guide/05-themes.md +++ b/docs/user-guide/05-themes.md @@ -71,4 +71,5 @@ match_fg = "#ff0000" ### Colors ANSI: `"red"`, `"bright-blue"`, `"white"` -Hex: `"#ff0000"`, `"#1e1e2e"` +Hex: `"#ff0000"`, `"#1e1e2e"` +Terminal default: `"none"` (also `"default"` / `"reset"`) — leaves the element uncolored, e.g. `background = "none"` keeps a transparent background. diff --git a/television/config/themes.rs b/television/config/themes.rs index f8b483df..74a8a036 100644 --- a/television/config/themes.rs +++ b/television/config/themes.rs @@ -16,6 +16,11 @@ pub mod builtin; pub enum Color { Ansi(ANSIColor), Rgb(RGBColor), + /// The terminal's default color, leaving the underlying cell untouched. + /// + /// This is useful to keep a transparent background or to fall back to the + /// terminal's default foreground for a given element. + Reset, } impl Color { @@ -24,6 +29,7 @@ impl Color { RGBColor::from_str(s).map(Self::Rgb) } else { match s.to_lowercase().as_str() { + "none" | "default" | "reset" => Some(Self::Reset), "black" => Some(Self::Ansi(ANSIColor::Black)), "red" => Some(Self::Ansi(ANSIColor::Red)), "green" => Some(Self::Ansi(ANSIColor::Green)), @@ -476,6 +482,7 @@ impl Into for &Color { match self { Color::Ansi(ansi) => ansi.into(), Color::Rgb(rgb) => rgb.into(), + Color::Reset => RatatuiColor::Reset, } } } @@ -810,6 +817,58 @@ mod tests { } } + #[test] + fn test_color_from_str_none_is_reset() { + for value in ["none", "None", "NONE", "default", "reset"] { + assert_eq!(Color::from_str(value), Some(Color::Reset)); + } + } + + #[test] + fn test_reset_color_maps_to_ratatui_reset() { + let color = Color::Reset; + let ratatui_color: RatatuiColor = (&color).into(); + assert_eq!(ratatui_color, RatatuiColor::Reset); + } + + #[test] + fn test_theme_deserialization_none_background() { + let theme_content = r##" + background = "none" + border_fg = "black" + text_fg = "white" + dimmed_text_fg = "bright-black" + input_text_fg = "bright-white" + result_count_fg = "bright-white" + result_name_fg = "bright-white" + result_line_number_fg = "bright-white" + result_value_fg = "bright-white" + selection_bg = "bright-white" + selection_fg = "bright-white" + match_fg = "bright-white" + preview_title_fg = "bright-white" + channel_mode_fg = "bright-white" + channel_mode_bg = "bright-black" + remote_control_mode_fg = "bright-white" + remote_control_mode_bg = "bright-black" + "##; + let theme: Theme = toml::from_str(theme_content).unwrap(); + assert_eq!(theme.background, Some(Color::Reset)); + } + + #[test] + fn test_theme_override_with_none() { + let base_theme = create_test_theme(); + let overrides = crate::config::ui::ThemeOverrides { + background: Some("none".to_string()), + ..Default::default() + }; + + let merged_theme = + base_theme.merge_with_overrides(&overrides).unwrap(); + assert_eq!(merged_theme.background, Some(Color::Reset)); + } + #[test] fn test_theme_deserialization_fallback_channel_mode_bg() { let theme_content = r##"