rush_sync_server/commands/theme/
command.rs

1use super::ThemeSystem;
2use crate::commands::command::Command;
3use crate::core::prelude::*;
4use std::future::Future;
5use std::pin::Pin;
6
7#[derive(Debug)]
8pub struct ThemeCommand {
9    theme_system: std::sync::Mutex<Option<ThemeSystem>>,
10}
11
12impl ThemeCommand {
13    pub fn new() -> Self {
14        Self {
15            theme_system: std::sync::Mutex::new(None),
16        }
17    }
18
19    fn get_or_init_theme_system(&self) -> Result<std::sync::MutexGuard<Option<ThemeSystem>>> {
20        let mut guard = self.theme_system.lock().unwrap_or_else(|poisoned| {
21            log::warn!("Recovered from poisoned mutex");
22            poisoned.into_inner()
23        });
24        if guard.is_none() {
25            *guard = Some(ThemeSystem::load()?);
26        }
27        Ok(guard)
28    }
29}
30
31impl Command for ThemeCommand {
32    fn name(&self) -> &'static str {
33        "theme"
34    }
35
36    fn description(&self) -> &'static str {
37        "Change application theme (live update without restart, loaded from TOML)"
38    }
39
40    fn matches(&self, command: &str) -> bool {
41        command.trim().to_lowercase().starts_with("theme")
42    }
43
44    fn execute_sync(&self, args: &[&str]) -> Result<String> {
45        // ✅ DEBUG: Zeige was passiert
46        log::info!("🎨 ThemeCommand::execute_sync called with args: {:?}", args);
47
48        // ✅ SICHERER THEME-SYSTEM LOAD mit Fehlerbehandlung
49        let mut guard = match self.get_or_init_theme_system() {
50            Ok(guard) => {
51                log::info!("✅ ThemeSystem loaded successfully");
52                guard
53            }
54            Err(e) => {
55                log::error!("❌ ThemeSystem load failed: {}", e);
56                return Ok(format!("❌ Theme system failed to load: {}\n\n💡 Tip: Add [theme.dark] section to rush.toml", e));
57            }
58        };
59
60        let theme_system = guard.as_mut().unwrap();
61
62        match args.first() {
63            None => {
64                log::info!("🎨 Calling theme_system.show_status()");
65                let result = theme_system.show_status();
66                log::info!("🎨 show_status result: '{}'", result);
67                Ok(result)
68            }
69            Some(&"--help" | &"-h") => {
70                log::info!("🎨 Calling create_help_text()");
71                let result = Self::create_help_text(theme_system);
72                log::info!("🎨 create_help_text result length: {} chars", result.len());
73                // ✅ DEBUG: Zeige ersten Teil
74                log::info!(
75                    "🎨 create_help_text preview: '{}'",
76                    &result[..result.len().min(100)]
77                );
78                Ok(result)
79            }
80            Some(&"debug") => match args.get(1) {
81                Some(&theme_name) => Ok(theme_system.debug_theme_details(theme_name)),
82                None => Ok("❌ Theme name missing. Usage: theme debug <name>".to_string()),
83            },
84            Some(&"preview") => match args.get(1) {
85                Some(&theme_name) => theme_system.preview_theme(theme_name),
86                None => Ok("❌ Theme name missing. Usage: theme preview <name>".to_string()),
87            },
88            Some(&theme_name) => {
89                log::info!("🎨 Calling change_theme({})", theme_name);
90                theme_system.change_theme(theme_name)
91            }
92        }
93    }
94
95    fn execute_async<'a>(
96        &'a self,
97        args: &'a [&'a str],
98    ) -> Pin<Box<dyn Future<Output = Result<String>> + Send + 'a>> {
99        Box::pin(async move { self.execute_sync(args) })
100    }
101
102    fn supports_async(&self) -> bool {
103        true
104    }
105
106    fn priority(&self) -> u8 {
107        65
108    }
109}
110
111impl ThemeCommand {
112    fn create_help_text(theme_system: &ThemeSystem) -> String {
113        let available_themes = theme_system.get_available_names();
114
115        if available_themes.is_empty() {
116            return "❌ Keine Themes verfügbar!\n\n📝 Füge [theme.xyz] Sektionen zur rush.toml hinzu:\n\n[theme.mein_theme]\ninput_text = \"White\"\ninput_bg = \"Black\"\ncursor = \"Green\"\noutput_text = \"Gray\"\noutput_bg = \"Black\"\nprompt_text = \">> \"\nprompt_color = \"Cyan\"\noutput_cursor = \"BLOCK\"    # ✅ NEU!\noutput_color = \"LightGreen\" # ✅ NEU!".to_string();
117        }
118
119        let themes_list = available_themes.join(", ");
120
121        format!(
122            "🎨 TOML-Theme Commands (Live Update - Geladen aus rush.toml!):\n\
123            theme                Show available TOML-themes\n\
124            theme <name>         Select theme: {}\n\
125            theme preview <name> Preview theme colors + cursor config ✅ NEW!\n\
126            theme -h             Show this help\n\n\
127            ✨ Alle Themes werden LIVE aus [theme.*] Sektionen der rush.toml geladen!\n\
128            🎯 NEU: Cursor-Konfiguration per output_cursor + output_color!\n\
129            📁 Füge beliebige [theme.dein_name] Sektionen hinzu für neue Themes\n\
130            🔄 Änderungen werden sofort angewendet (kein Restart nötig)\n\n\
131            🎛️ Cursor-Optionen:\n\
132            • output_cursor: BLOCK, PIPE, UNDERSCORE\n\
133            • output_color: Jede unterstützte Farbe (White, Green, etc.)",
134            themes_list
135        )
136    }
137}
138
139impl Default for ThemeCommand {
140    fn default() -> Self {
141        Self::new()
142    }
143}