ricecoder_ide/themes/
mod.rs

1//! IDE Theme System
2//!
3//! This module provides theme management for the IDE, re-exporting theme types from ricecoder-tui
4//! and providing IDE-specific theme manager wrapper functionality.
5//!
6//! # Architecture
7//!
8//! The IDE theme system is built on top of the TUI theme system, providing:
9//! - Re-exported theme types (Color, Theme, ThemeManager)
10//! - IDE-specific theme manager wrapper
11//! - Integration with IDE configuration
12//! - Theme persistence through ricecoder-storage
13//!
14//! # Example
15//!
16//! ```ignore
17//! use ricecoder_ide::themes::{IdeThemeManager, Color, Theme};
18//!
19//! // Create IDE theme manager
20//! let theme_manager = IdeThemeManager::new();
21//!
22//! // Switch to a theme
23//! theme_manager.switch_by_name("dracula")?;
24//!
25//! // Get current theme
26//! let current = theme_manager.current()?;
27//! println!("Current theme: {}", current.name);
28//! ```
29
30pub mod integration;
31
32use anyhow::Result;
33use std::path::Path;
34
35// Re-export theme types from ricecoder-tui
36pub use ricecoder_tui::style::{Color, ColorSupport, Theme};
37pub use ricecoder_tui::theme::ThemeManager;
38pub use ricecoder_tui::theme_loader::ThemeLoader;
39pub use ricecoder_tui::theme_registry::ThemeRegistry;
40pub use ricecoder_tui::theme_reset::ThemeResetManager;
41
42// Re-export integration types
43pub use integration::{IdeThemeConfig, IdeThemeIntegration};
44
45/// IDE-specific theme manager wrapper
46///
47/// Provides IDE-specific functionality on top of the base ThemeManager,
48/// including integration with IDE configuration and storage.
49#[derive(Clone, Debug)]
50pub struct IdeThemeManager {
51    /// Underlying theme manager from ricecoder-tui
52    inner: ThemeManager,
53}
54
55impl IdeThemeManager {
56    /// Create a new IDE theme manager with default theme
57    pub fn new() -> Self {
58        Self {
59            inner: ThemeManager::new(),
60        }
61    }
62
63    /// Create an IDE theme manager with a specific theme
64    pub fn with_theme(theme: Theme) -> Self {
65        Self {
66            inner: ThemeManager::with_theme(theme),
67        }
68    }
69
70    /// Create an IDE theme manager with a custom registry
71    pub fn with_registry(registry: ThemeRegistry) -> Self {
72        Self {
73            inner: ThemeManager::with_registry(registry),
74        }
75    }
76
77    /// Get the current theme
78    pub fn current(&self) -> Result<Theme> {
79        self.inner.current()
80    }
81
82    /// Switch to a theme by name
83    pub fn switch_by_name(&self, name: &str) -> Result<()> {
84        self.inner.switch_by_name(name)
85    }
86
87    /// Switch to a specific theme
88    pub fn switch_to(&self, theme: Theme) -> Result<()> {
89        self.inner.switch_to(theme)
90    }
91
92    /// Get all available theme names
93    pub fn available_themes(&self) -> Vec<&'static str> {
94        self.inner.available_themes()
95    }
96
97    /// Get the current theme name
98    pub fn current_name(&self) -> Result<String> {
99        self.inner.current_name()
100    }
101
102    /// Load a custom theme from a file
103    pub fn load_custom_theme(&self, path: &Path) -> Result<()> {
104        self.inner.load_custom_theme(path)
105    }
106
107    /// Load all custom themes from a directory
108    pub fn load_custom_themes_from_directory(&self, dir: &Path) -> Result<Vec<Theme>> {
109        self.inner.load_custom_themes_from_directory(dir)
110    }
111
112    /// Load all custom themes from a directory and register them
113    pub fn load_and_register_custom_themes(&self, dir: &Path) -> Result<Vec<String>> {
114        self.inner.load_and_register_custom_themes(dir)
115    }
116
117    /// Save current theme as a custom theme
118    pub fn save_custom_theme(&self, path: &Path) -> Result<()> {
119        self.inner.save_custom_theme(path)
120    }
121
122    /// Save a specific theme as a custom theme
123    pub fn save_theme_as_custom(&self, theme: &Theme, path: &Path) -> Result<()> {
124        self.inner.save_theme_as_custom(theme, path)
125    }
126
127    /// Delete a custom theme file and unregister it
128    pub fn delete_custom_theme(&self, name: &str, path: &Path) -> Result<()> {
129        self.inner.delete_custom_theme(name, path)
130    }
131
132    /// Get the default custom themes directory
133    pub fn custom_themes_directory() -> Result<std::path::PathBuf> {
134        ThemeManager::custom_themes_directory()
135    }
136
137    /// Get the theme registry
138    pub fn registry(&self) -> &ThemeRegistry {
139        self.inner.registry()
140    }
141
142    /// List all available themes (built-in and custom)
143    pub fn list_all_themes(&self) -> Result<Vec<String>> {
144        self.inner.list_all_themes()
145    }
146
147    /// List all built-in themes
148    pub fn list_builtin_themes(&self) -> Vec<String> {
149        self.inner.list_builtin_themes()
150    }
151
152    /// List all custom themes
153    pub fn list_custom_themes(&self) -> Result<Vec<String>> {
154        self.inner.list_custom_themes()
155    }
156
157    /// Register a custom theme in the registry
158    pub fn register_theme(&self, theme: Theme) -> Result<()> {
159        self.inner.register_theme(theme)
160    }
161
162    /// Unregister a custom theme from the registry
163    pub fn unregister_theme(&self, name: &str) -> Result<()> {
164        self.inner.unregister_theme(name)
165    }
166
167    /// Check if a theme exists
168    pub fn theme_exists(&self, name: &str) -> bool {
169        self.inner.theme_exists(name)
170    }
171
172    /// Check if a theme is built-in
173    pub fn is_builtin_theme(&self, name: &str) -> bool {
174        self.inner.is_builtin_theme(name)
175    }
176
177    /// Check if a theme is custom
178    pub fn is_custom_theme(&self, name: &str) -> Result<bool> {
179        self.inner.is_custom_theme(name)
180    }
181
182    /// Get the number of built-in themes
183    pub fn builtin_theme_count(&self) -> usize {
184        self.inner.builtin_theme_count()
185    }
186
187    /// Get the number of custom themes
188    pub fn custom_theme_count(&self) -> Result<usize> {
189        self.inner.custom_theme_count()
190    }
191
192    /// Reset all colors in the current theme to their default values
193    pub fn reset_colors(&self) -> Result<()> {
194        self.inner.reset_colors()
195    }
196
197    /// Reset the current theme to its built-in default
198    pub fn reset_theme(&self) -> Result<()> {
199        self.inner.reset_theme()
200    }
201
202    /// Reset a specific color field in the current theme to its default value
203    pub fn reset_color(&self, color_name: &str) -> Result<()> {
204        self.inner.reset_color(color_name)
205    }
206
207    /// Get the default color value for a specific color field in the current theme
208    pub fn get_default_color(&self, color_name: &str) -> Result<Color> {
209        self.inner.get_default_color(color_name)
210    }
211
212    /// Get the theme reset manager
213    pub fn reset_manager(&self) -> &ThemeResetManager {
214        self.inner.reset_manager()
215    }
216
217    /// Register a listener for theme changes
218    pub fn on_theme_changed<F>(&self, listener: F) -> Result<()>
219    where
220        F: Fn(&Theme) + Send + 'static,
221    {
222        self.inner.on_theme_changed(listener)
223    }
224
225    /// Get the underlying theme manager
226    pub fn inner(&self) -> &ThemeManager {
227        &self.inner
228    }
229}
230
231impl Default for IdeThemeManager {
232    fn default() -> Self {
233        Self::new()
234    }
235}
236
237#[cfg(test)]
238mod tests {
239    use super::*;
240
241    #[test]
242    fn test_ide_theme_manager_creation() {
243        let manager = IdeThemeManager::new();
244        assert_eq!(manager.current().unwrap().name, "dark");
245    }
246
247    #[test]
248    fn test_ide_theme_manager_with_theme() {
249        let theme = Theme::light();
250        let manager = IdeThemeManager::with_theme(theme);
251        assert_eq!(manager.current().unwrap().name, "light");
252    }
253
254    #[test]
255    fn test_ide_switch_by_name() {
256        let manager = IdeThemeManager::new();
257        manager.switch_by_name("dracula").unwrap();
258        assert_eq!(manager.current().unwrap().name, "dracula");
259    }
260
261    #[test]
262    fn test_ide_available_themes() {
263        let manager = IdeThemeManager::new();
264        let themes = manager.available_themes();
265        assert_eq!(themes.len(), 6);
266        assert!(themes.contains(&"dark"));
267        assert!(themes.contains(&"light"));
268        assert!(themes.contains(&"dracula"));
269        assert!(themes.contains(&"monokai"));
270        assert!(themes.contains(&"nord"));
271        assert!(themes.contains(&"high-contrast"));
272    }
273
274    #[test]
275    fn test_ide_current_name() {
276        let manager = IdeThemeManager::new();
277        assert_eq!(manager.current_name().unwrap(), "dark");
278
279        manager.switch_by_name("nord").unwrap();
280        assert_eq!(manager.current_name().unwrap(), "nord");
281    }
282
283    #[test]
284    fn test_ide_theme_exists() {
285        let manager = IdeThemeManager::new();
286        assert!(manager.theme_exists("dark"));
287        assert!(manager.theme_exists("light"));
288        assert!(!manager.theme_exists("nonexistent"));
289    }
290
291    #[test]
292    fn test_ide_is_builtin_theme() {
293        let manager = IdeThemeManager::new();
294        assert!(manager.is_builtin_theme("dark"));
295        assert!(manager.is_builtin_theme("light"));
296        assert!(!manager.is_builtin_theme("nonexistent"));
297    }
298
299    #[test]
300    fn test_ide_builtin_theme_count() {
301        let manager = IdeThemeManager::new();
302        assert_eq!(manager.builtin_theme_count(), 6);
303    }
304
305    #[test]
306    fn test_ide_reset_colors() {
307        let manager = IdeThemeManager::new();
308        let original_primary = manager.current().unwrap().primary;
309
310        // Reset colors (should restore to defaults)
311        manager.reset_colors().unwrap();
312
313        // Verify reset
314        assert_eq!(manager.current().unwrap().primary, original_primary);
315    }
316
317    #[test]
318    fn test_ide_reset_theme() {
319        let manager = IdeThemeManager::new();
320        manager.switch_by_name("light").unwrap();
321
322        let original_theme = Theme::light();
323
324        // Reset theme
325        manager.reset_theme().unwrap();
326
327        // Verify reset
328        let reset = manager.current().unwrap();
329        assert_eq!(reset.primary, original_theme.primary);
330        assert_eq!(reset.background, original_theme.background);
331    }
332
333    #[test]
334    fn test_ide_default() {
335        let manager = IdeThemeManager::default();
336        assert_eq!(manager.current().unwrap().name, "dark");
337    }
338}