aboutsummaryrefslogtreecommitdiff
path: root/src/config
diff options
context:
space:
mode:
Diffstat (limited to 'src/config')
-rw-r--r--src/config/io.rs16
-rw-r--r--src/config/theme.rs98
2 files changed, 114 insertions, 0 deletions
diff --git a/src/config/io.rs b/src/config/io.rs
index b6a70427..7ed82395 100644
--- a/src/config/io.rs
+++ b/src/config/io.rs
@@ -341,6 +341,8 @@ fn load_live_config_from_str(content: &str) -> Result<LoadedConfig, Vec<String>>
|section| config.remote = section,
);
+ diagnostics.extend(config.theme.diagnostics());
+
Ok(LoadedConfig {
config,
diagnostics,
@@ -864,6 +866,20 @@ resume_agents_on_restore = true
}
#[test]
+ fn load_live_config_warns_about_unknown_theme_names() {
+ let loaded = load_live_config_from_str(
+ r#"
+[theme]
+name = "catppucin"
+"#,
+ )
+ .unwrap();
+
+ assert_eq!(loaded.diagnostics.len(), 1);
+ assert!(loaded.diagnostics[0].contains("theme.name = \"catppucin\""));
+ }
+
+ #[test]
fn load_live_config_warns_about_unknown_top_level_sections() {
let loaded = load_live_config_from_str(
r#"
diff --git a/src/config/theme.rs b/src/config/theme.rs
index e98c9dfb..e89fe99c 100644
--- a/src/config/theme.rs
+++ b/src/config/theme.rs
@@ -1,6 +1,51 @@
use serde::Deserialize;
use tracing::warn;
+pub const THEME_NAMES: &[&str] = &[
+ "catppuccin",
+ "catppuccin-latte",
+ "terminal",
+ "tokyo-night",
+ "tokyo-night-day",
+ "dracula",
+ "nord",
+ "gruvbox",
+ "gruvbox-light",
+ "one-dark",
+ "one-light",
+ "solarized",
+ "solarized-light",
+ "kanagawa",
+ "kanagawa-lotus",
+ "rose-pine",
+ "rose-pine-dawn",
+ "vesper",
+];
+
+pub(crate) fn canonical_theme_name(name: &str) -> Option<&'static str> {
+ match name.to_lowercase().replace([' ', '_'], "-").as_str() {
+ "catppuccin" | "catppuccin-mocha" => Some("catppuccin"),
+ "catppuccin-latte" | "latte" | "light" => Some("catppuccin-latte"),
+ "terminal" => Some("terminal"),
+ "tokyo-night" | "tokyonight" => Some("tokyo-night"),
+ "tokyo-night-day" | "tokyo-day" | "tokyonight-day" => Some("tokyo-night-day"),
+ "dracula" => Some("dracula"),
+ "nord" => Some("nord"),
+ "gruvbox" | "gruvbox-dark" => Some("gruvbox"),
+ "gruvbox-light" => Some("gruvbox-light"),
+ "one-dark" | "onedark" => Some("one-dark"),
+ "one-light" | "onelight" => Some("one-light"),
+ "solarized" | "solarized-dark" => Some("solarized"),
+ "solarized-light" => Some("solarized-light"),
+ "kanagawa" => Some("kanagawa"),
+ "kanagawa-lotus" | "lotus" => Some("kanagawa-lotus"),
+ "rose-pine" | "rosepine" => Some("rose-pine"),
+ "rose-pine-dawn" | "rosepine-dawn" | "dawn" => Some("rose-pine-dawn"),
+ "vesper" => Some("vesper"),
+ _ => None,
+ }
+}
+
/// Theme configuration: pick a built-in or override individual tokens.
///
/// ```toml
@@ -26,6 +71,31 @@ pub struct ThemeConfig {
pub custom: Option<CustomThemeColors>,
}
+impl ThemeConfig {
+ pub(crate) fn diagnostics(&self) -> Vec<String> {
+ let valid = THEME_NAMES.join(", ");
+ [
+ ("theme.name", self.name.as_deref(), "catppuccin"),
+ ("theme.dark_name", self.dark_name.as_deref(), "catppuccin"),
+ (
+ "theme.light_name",
+ self.light_name.as_deref(),
+ "catppuccin-latte",
+ ),
+ ]
+ .into_iter()
+ .filter_map(|(field, value, fallback)| {
+ let value = value?;
+ canonical_theme_name(value).is_none().then(|| {
+ format!(
+ "unknown theme name {field} = {value:?}; using {fallback:?}; valid themes: {valid}"
+ )
+ })
+ })
+ .collect()
+ }
+}
+
/// Per-token color overrides. All fields optional — only set what you want to change.
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(default)]
@@ -133,6 +203,34 @@ name = "dracula"
}
#[test]
+ fn unknown_theme_names_are_diagnosed() {
+ let config: Config = toml::from_str(
+ r#"
+[theme]
+name = "catppucin"
+dark_name = "tokio-night"
+light_name = "lattee"
+"#,
+ )
+ .unwrap();
+
+ let diagnostics = config.theme.diagnostics();
+ assert_eq!(diagnostics.len(), 3);
+ assert!(diagnostics[0].contains("theme.name = \"catppucin\""));
+ assert!(diagnostics[0].contains("using \"catppuccin\""));
+ assert!(diagnostics[1].contains("theme.dark_name = \"tokio-night\""));
+ assert!(diagnostics[2].contains("theme.light_name = \"lattee\""));
+ assert!(diagnostics[2].contains("using \"catppuccin-latte\""));
+ }
+
+ #[test]
+ fn theme_name_aliases_are_valid() {
+ for name in ["catppuccin-mocha", "tokyonight", "gruvbox-dark", "dawn"] {
+ assert!(canonical_theme_name(name).is_some(), "alias: {name}");
+ }
+ }
+
+ #[test]
fn parse_color_accepts_reset_aliases() {
use ratatui::style::Color;