rush_sync_server/commands/theme/
command.rs

1// =====================================================
2// FILE: src/commands/theme/command.rs - I18N VERSION
3// =====================================================
4
5use super::ThemeSystem;
6use crate::commands::command::Command;
7use crate::core::prelude::*;
8use std::future::Future;
9use std::pin::Pin;
10
11#[derive(Debug)]
12pub struct ThemeCommand {
13    theme_system: std::sync::Mutex<Option<ThemeSystem>>,
14}
15
16impl ThemeCommand {
17    pub fn new() -> Self {
18        Self {
19            theme_system: std::sync::Mutex::new(None),
20        }
21    }
22
23    fn get_or_init_theme_system(&self) -> Result<std::sync::MutexGuard<Option<ThemeSystem>>> {
24        let mut guard = self.theme_system.lock().unwrap_or_else(|poisoned| {
25            log::warn!("Recovered from poisoned mutex");
26            poisoned.into_inner()
27        });
28        if guard.is_none() {
29            *guard = Some(ThemeSystem::load()?);
30        }
31        Ok(guard)
32    }
33}
34
35impl Command for ThemeCommand {
36    fn name(&self) -> &'static str {
37        "theme"
38    }
39
40    fn description(&self) -> &'static str {
41        "Change application theme (live update without restart, loaded from TOML)"
42    }
43
44    fn matches(&self, command: &str) -> bool {
45        command.trim().to_lowercase().starts_with("theme")
46    }
47
48    fn execute_sync(&self, args: &[&str]) -> Result<String> {
49        log::info!("šŸŽØ ThemeCommand::execute_sync called with args: {:?}", args);
50
51        // Theme-System laden mit i18n Error-Handling
52        let mut guard = match self.get_or_init_theme_system() {
53            Ok(guard) => {
54                log::info!("āœ… ThemeSystem loaded successfully");
55                guard
56            }
57            Err(e) => {
58                log::error!("āŒ ThemeSystem load failed: {}", e);
59                return Ok(format!(
60                    "{} {}\n\nšŸ’” {}",
61                    get_command_translation("system.commands.theme.load_failed", &[&e.to_string()]),
62                    get_command_translation("system.commands.theme.no_themes_hint", &[]),
63                    get_command_translation("system.commands.theme.add_sections_hint", &[])
64                ));
65            }
66        };
67
68        let theme_system = guard.as_mut().unwrap();
69
70        match args.first() {
71            None => {
72                log::info!("šŸŽØ Calling theme_system.show_status()");
73                let result = theme_system.show_status_i18n();
74                log::info!("šŸŽØ show_status result: '{}'", result);
75                Ok(result)
76            }
77            Some(&"--help" | &"-h") => {
78                log::info!("šŸŽØ Calling create_help_text()");
79                let result = Self::create_help_text_i18n(theme_system);
80                log::info!(
81                    "šŸŽØ create_help_text result length: {} chars",
82                    result.chars().count()
83                );
84                Ok(result)
85            }
86            Some(&"debug") => match args.get(1) {
87                Some(&theme_name) => Ok(theme_system.debug_theme_details_i18n(theme_name)),
88                None => Ok(get_command_translation(
89                    "system.commands.theme.debug_missing_name",
90                    &[],
91                )),
92            },
93            Some(&"preview") => match args.get(1) {
94                Some(&theme_name) => theme_system.preview_theme_i18n(theme_name),
95                None => Ok(get_command_translation(
96                    "system.commands.theme.preview_missing_name",
97                    &[],
98                )),
99            },
100            Some(&theme_name) => {
101                log::info!("šŸŽØ Calling change_theme({})", theme_name);
102                theme_system.change_theme_i18n(theme_name)
103            }
104        }
105    }
106
107    fn execute_async<'a>(
108        &'a self,
109        args: &'a [&'a str],
110    ) -> Pin<Box<dyn Future<Output = Result<String>> + Send + 'a>> {
111        Box::pin(async move { self.execute_sync(args) })
112    }
113
114    fn supports_async(&self) -> bool {
115        true
116    }
117
118    fn priority(&self) -> u8 {
119        65
120    }
121}
122
123impl ThemeCommand {
124    fn create_help_text_i18n(theme_system: &ThemeSystem) -> String {
125        let available_themes = theme_system.get_available_names();
126
127        if available_themes.is_empty() {
128            return format!(
129                "{}\n\n{}",
130                get_command_translation("system.commands.theme.no_themes_available", &[]),
131                get_command_translation("system.commands.theme.how_to_add_themes", &[])
132            );
133        }
134
135        let themes_list = available_themes.join(", ");
136
137        format!(
138            "{}\n{}\n{}\n{}\n{}\n\n{}\n{}\n{}\n{}\n\n{}",
139            get_command_translation("system.commands.theme.help.header", &[]),
140            get_command_translation("system.commands.theme.help.show_themes", &[]),
141            get_command_translation("system.commands.theme.help.select_theme", &[&themes_list]),
142            get_command_translation("system.commands.theme.help.preview_theme", &[]),
143            get_command_translation("system.commands.theme.help.show_help", &[]),
144            get_command_translation("system.commands.theme.help.live_loaded", &[]),
145            get_command_translation("system.commands.theme.help.cursor_config", &[]),
146            get_command_translation("system.commands.theme.help.add_sections", &[]),
147            get_command_translation("system.commands.theme.help.live_changes", &[]),
148            get_command_translation("system.commands.theme.help.cursor_options", &[])
149        )
150    }
151}
152
153impl Default for ThemeCommand {
154    fn default() -> Self {
155        Self::new()
156    }
157}
158
159// =====================================================
160// ERWEITERTE THEMESYSTEM METHODEN MIT I18N
161// =====================================================
162
163impl ThemeSystem {
164    pub fn show_status_i18n(&self) -> String {
165        if self.themes.is_empty() {
166            return get_command_translation("system.commands.theme.no_themes_found", &[]);
167        }
168
169        let themes_list = self.themes.keys().cloned().collect::<Vec<_>>().join(", ");
170        get_command_translation(
171            "system.commands.theme.current_status",
172            &[&self.current_name.to_uppercase(), &themes_list],
173        )
174    }
175
176    pub fn change_theme_i18n(&mut self, theme_name: &str) -> Result<String> {
177        let theme_name_lower = theme_name.to_lowercase();
178
179        if !self.themes.contains_key(&theme_name_lower) {
180            return Ok(if self.themes.is_empty() {
181                get_command_translation("system.commands.theme.no_themes_found", &[])
182            } else {
183                let available = self.themes.keys().cloned().collect::<Vec<_>>().join(", ");
184                get_command_translation(
185                    "system.commands.theme.not_found",
186                    &[theme_name, &available],
187                )
188            });
189        }
190
191        self.current_name = theme_name_lower.clone();
192
193        // Log cursor details
194        if let Some(theme_def) = self.themes.get(&theme_name_lower) {
195            log::info!(
196                "šŸŽØ Theme '{}': input_cursor='{}' ({}), output_cursor='{}' ({}), prefix='{}'",
197                theme_name_lower.to_uppercase(),
198                theme_def.input_cursor,
199                theme_def.input_cursor_color,
200                theme_def.output_cursor,
201                theme_def.output_cursor_color,
202                theme_def.input_cursor_prefix
203            );
204        }
205
206        // Async save
207        let name_clone = theme_name_lower.clone();
208        let paths_clone = self.config_paths.clone();
209        tokio::spawn(async move {
210            if let Err(e) = Self::save_current_theme_to_config(&paths_clone, &name_clone).await {
211                log::error!("Failed to save theme: {}", e);
212            }
213        });
214
215        Ok(format!(
216            "__LIVE_THEME_UPDATE__{}__MESSAGE__{}",
217            theme_name_lower,
218            get_command_translation(
219                "system.commands.theme.changed_success",
220                &[&theme_name_lower.to_uppercase()]
221            )
222        ))
223    }
224
225    pub fn preview_theme_i18n(&self, theme_name: &str) -> Result<String> {
226        let theme_name_lower = theme_name.to_lowercase();
227
228        if let Some(theme_def) = self.themes.get(&theme_name_lower) {
229            Ok(get_command_translation(
230                "system.commands.theme.preview_details",
231                &[
232                    &theme_name_lower.to_uppercase(),
233                    &theme_def.input_text,
234                    &theme_def.input_bg,
235                    &theme_def.output_text,
236                    &theme_def.output_bg,
237                    &theme_def.input_cursor_prefix,
238                    &theme_def.input_cursor_color,
239                    &theme_def.input_cursor,
240                    &theme_def.output_cursor,
241                    &theme_def.output_cursor_color,
242                    &theme_name_lower,
243                ],
244            ))
245        } else {
246            let available = self.themes.keys().cloned().collect::<Vec<_>>().join(", ");
247            Ok(get_command_translation(
248                "system.commands.theme.not_found",
249                &[theme_name, &available],
250            ))
251        }
252    }
253
254    pub fn debug_theme_details_i18n(&self, theme_name: &str) -> String {
255        if let Some(theme_def) = self.themes.get(&theme_name.to_lowercase()) {
256            get_command_translation(
257                "system.commands.theme.debug_details",
258                &[
259                    &theme_name.to_uppercase(),
260                    &theme_def.input_text,
261                    &theme_def.input_bg,
262                    &theme_def.output_text,
263                    &theme_def.output_bg,
264                    &theme_def.input_cursor_prefix,
265                    &theme_def.input_cursor_color,
266                    &theme_def.input_cursor,
267                    &theme_def.output_cursor,
268                    &theme_def.output_cursor_color,
269                ],
270            )
271        } else {
272            get_command_translation("system.commands.theme.debug_not_found", &[theme_name])
273        }
274    }
275}