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