Skip to main content

fresh_core/
services.rs

1use std::collections::HashMap;
2
3/// Trait for the editor to provide services to the plugin runtime
4/// without the runtime depending directly on UI or complex system logic.
5pub trait PluginServiceBridge: Send + Sync + 'static {
6    /// Support downcasting for tests
7    fn as_any(&self) -> &dyn std::any::Any;
8
9    /// Translate a string for a plugin
10    fn translate(&self, plugin_name: &str, key: &str, args: &HashMap<String, String>) -> String;
11
12    /// Get the current locale
13    fn current_locale(&self) -> String;
14
15    /// Update the current JavaScript execution state (for debugging/signal handlers)
16    fn set_js_execution_state(&self, state: String);
17
18    /// Clear the JavaScript execution state
19    fn clear_js_execution_state(&self);
20
21    /// Get the JSON schema for themes
22    fn get_theme_schema(&self) -> serde_json::Value;
23
24    /// Get a list of builtin theme names
25    fn get_builtin_themes(&self) -> serde_json::Value;
26
27    /// Full theme registry (builtins + user + packages + bundles) as a JSON
28    /// object keyed by canonical registry key. Each value is the parsed theme
29    /// with `_key` / `_pack` metadata fields (see `ThemeRegistry::to_json_map`).
30    fn get_all_themes(&self) -> serde_json::Value;
31
32    /// Register custom i18n strings for a plugin
33    fn register_plugin_strings(
34        &self,
35        _plugin_name: &str,
36        _strings: HashMap<String, HashMap<String, String>>,
37    ) {
38    }
39
40    /// Unregister custom i18n strings for a plugin
41    fn unregister_plugin_strings(&self, _plugin_name: &str) {}
42
43    /// Register a plugin command
44    fn register_command(&self, command: crate::command::Command);
45
46    /// Unregister a command by name
47    fn unregister_command(&self, name: &str);
48
49    /// Unregister all commands with a given prefix
50    fn unregister_commands_by_prefix(&self, prefix: &str);
51
52    /// Unregister all commands registered by a specific plugin
53    fn unregister_commands_by_plugin(&self, plugin_name: &str);
54
55    /// Get the plugins directory path
56    fn plugins_dir(&self) -> std::path::PathBuf;
57
58    /// Get the config directory path
59    fn config_dir(&self) -> std::path::PathBuf;
60
61    /// Get the persistent data directory path (DirectoryContext::data_dir).
62    /// Used for long-lived plugin state such as review-diff comment history.
63    fn data_dir(&self) -> std::path::PathBuf;
64
65    /// Directory holding terminal scrollback backing files for the given
66    /// working directory (project root / worktree). Each root gets its own
67    /// subdir, so Universal Search's terminal scope can stay scoped to the
68    /// active project. Default falls back to the shared `terminals` root
69    /// (covers all roots); the editor bridge overrides with the per-root
70    /// subdir (`DirectoryContext::terminal_dir_for`).
71    fn terminal_dir(&self, working_dir: &std::path::Path) -> std::path::PathBuf {
72        let _ = working_dir;
73        self.data_dir().join("terminals")
74    }
75
76    /// Per-working-directory data root for plugin state that should be scoped
77    /// to a single project root / worktree (e.g. `<data_dir>/workdirs/
78    /// <encoded-cwd>/`). Default falls back to the shared parent; the editor
79    /// bridge overrides with the per-root subdir
80    /// (`DirectoryContext::working_data_dir_for`).
81    fn working_data_dir(&self, working_dir: &std::path::Path) -> std::path::PathBuf {
82        let _ = working_dir;
83        self.data_dir().join("workdirs")
84    }
85
86    /// Get theme data (JSON) by name from the in-memory cache.
87    fn get_theme_data(&self, _name: &str) -> Option<serde_json::Value> {
88        None
89    }
90
91    /// Save a theme file to the user themes directory.
92    /// Returns the path where the file was written.
93    fn save_theme_file(&self, _name: &str, _content: &str) -> Result<String, String> {
94        Err("not implemented".to_string())
95    }
96
97    /// Check if a user theme file exists (for overwrite confirmation).
98    fn theme_file_exists(&self, _name: &str) -> bool {
99        false
100    }
101}
102
103/// A no-op implementation of the service bridge for testing
104pub struct NoopServiceBridge;
105
106impl PluginServiceBridge for NoopServiceBridge {
107    fn as_any(&self) -> &dyn std::any::Any {
108        self
109    }
110    fn translate(&self, _plugin_name: &str, key: &str, _args: &HashMap<String, String>) -> String {
111        key.to_string()
112    }
113    fn current_locale(&self) -> String {
114        "en".to_string()
115    }
116    fn set_js_execution_state(&self, _state: String) {}
117    fn clear_js_execution_state(&self) {}
118    fn get_theme_schema(&self) -> serde_json::Value {
119        serde_json::Value::Null
120    }
121    fn get_builtin_themes(&self) -> serde_json::Value {
122        serde_json::Value::Null
123    }
124    fn get_all_themes(&self) -> serde_json::Value {
125        serde_json::Value::Null
126    }
127    fn register_plugin_strings(
128        &self,
129        _plugin_name: &str,
130        _strings: HashMap<String, HashMap<String, String>>,
131    ) {
132    }
133    fn unregister_plugin_strings(&self, _plugin_name: &str) {}
134    fn register_command(&self, _command: crate::command::Command) {}
135    fn unregister_command(&self, _name: &str) {}
136    fn unregister_commands_by_prefix(&self, _prefix: &str) {}
137    fn unregister_commands_by_plugin(&self, _plugin_name: &str) {}
138    fn plugins_dir(&self) -> std::path::PathBuf {
139        std::path::PathBuf::from("/tmp/plugins")
140    }
141    fn config_dir(&self) -> std::path::PathBuf {
142        std::path::PathBuf::from("/tmp/config")
143    }
144    fn data_dir(&self) -> std::path::PathBuf {
145        std::path::PathBuf::from("/tmp/data")
146    }
147}