extension_host_proxy.rs

  1use std::path::{Path, PathBuf};
  2use std::sync::Arc;
  3
  4use anyhow::Result;
  5use fs::Fs;
  6use gpui::{App, Global, ReadGlobal, SharedString, Task};
  7use language::{BinaryStatus, LanguageMatcher, LanguageName, LoadedLanguage};
  8use lsp::LanguageServerName;
  9use parking_lot::RwLock;
 10
 11use crate::{Extension, SlashCommand};
 12
 13#[derive(Default)]
 14struct GlobalExtensionHostProxy(Arc<ExtensionHostProxy>);
 15
 16impl Global for GlobalExtensionHostProxy {}
 17
 18/// A proxy for interacting with the extension host.
 19///
 20/// This object implements each of the individual proxy types so that their
 21/// methods can be called directly on it.
 22#[derive(Default)]
 23pub struct ExtensionHostProxy {
 24    theme_proxy: RwLock<Option<Arc<dyn ExtensionThemeProxy>>>,
 25    grammar_proxy: RwLock<Option<Arc<dyn ExtensionGrammarProxy>>>,
 26    language_proxy: RwLock<Option<Arc<dyn ExtensionLanguageProxy>>>,
 27    language_server_proxy: RwLock<Option<Arc<dyn ExtensionLanguageServerProxy>>>,
 28    snippet_proxy: RwLock<Option<Arc<dyn ExtensionSnippetProxy>>>,
 29    slash_command_proxy: RwLock<Option<Arc<dyn ExtensionSlashCommandProxy>>>,
 30    context_server_proxy: RwLock<Option<Arc<dyn ExtensionContextServerProxy>>>,
 31    debug_adapter_provider_proxy: RwLock<Option<Arc<dyn ExtensionDebugAdapterProviderProxy>>>,
 32}
 33
 34impl ExtensionHostProxy {
 35    /// Returns the global [`ExtensionHostProxy`].
 36    pub fn global(cx: &App) -> Arc<Self> {
 37        GlobalExtensionHostProxy::global(cx).0.clone()
 38    }
 39
 40    /// Returns the global [`ExtensionHostProxy`].
 41    ///
 42    /// Inserts a default [`ExtensionHostProxy`] if one does not yet exist.
 43    pub fn default_global(cx: &mut App) -> Arc<Self> {
 44        cx.default_global::<GlobalExtensionHostProxy>().0.clone()
 45    }
 46
 47    pub fn new() -> Self {
 48        Self {
 49            theme_proxy: RwLock::default(),
 50            grammar_proxy: RwLock::default(),
 51            language_proxy: RwLock::default(),
 52            language_server_proxy: RwLock::default(),
 53            snippet_proxy: RwLock::default(),
 54            slash_command_proxy: RwLock::default(),
 55            context_server_proxy: RwLock::default(),
 56            debug_adapter_provider_proxy: RwLock::default(),
 57        }
 58    }
 59
 60    pub fn register_theme_proxy(&self, proxy: impl ExtensionThemeProxy) {
 61        self.theme_proxy.write().replace(Arc::new(proxy));
 62    }
 63
 64    pub fn register_grammar_proxy(&self, proxy: impl ExtensionGrammarProxy) {
 65        self.grammar_proxy.write().replace(Arc::new(proxy));
 66    }
 67
 68    pub fn register_language_proxy(&self, proxy: impl ExtensionLanguageProxy) {
 69        self.language_proxy.write().replace(Arc::new(proxy));
 70    }
 71
 72    pub fn register_language_server_proxy(&self, proxy: impl ExtensionLanguageServerProxy) {
 73        self.language_server_proxy.write().replace(Arc::new(proxy));
 74    }
 75
 76    pub fn register_snippet_proxy(&self, proxy: impl ExtensionSnippetProxy) {
 77        self.snippet_proxy.write().replace(Arc::new(proxy));
 78    }
 79
 80    pub fn register_slash_command_proxy(&self, proxy: impl ExtensionSlashCommandProxy) {
 81        self.slash_command_proxy.write().replace(Arc::new(proxy));
 82    }
 83
 84    pub fn register_context_server_proxy(&self, proxy: impl ExtensionContextServerProxy) {
 85        self.context_server_proxy.write().replace(Arc::new(proxy));
 86    }
 87
 88    pub fn register_debug_adapter_proxy(&self, proxy: impl ExtensionDebugAdapterProviderProxy) {
 89        self.debug_adapter_provider_proxy
 90            .write()
 91            .replace(Arc::new(proxy));
 92    }
 93}
 94
 95pub trait ExtensionThemeProxy: Send + Sync + 'static {
 96    fn set_extensions_loaded(&self);
 97
 98    fn list_theme_names(&self, theme_path: PathBuf, fs: Arc<dyn Fs>) -> Task<Result<Vec<String>>>;
 99
100    fn remove_user_themes(&self, themes: Vec<SharedString>);
101
102    fn load_user_theme(&self, theme_path: PathBuf, fs: Arc<dyn Fs>) -> Task<Result<()>>;
103
104    fn reload_current_theme(&self, cx: &mut App);
105
106    fn list_icon_theme_names(
107        &self,
108        icon_theme_path: PathBuf,
109        fs: Arc<dyn Fs>,
110    ) -> Task<Result<Vec<String>>>;
111
112    fn remove_icon_themes(&self, icon_themes: Vec<SharedString>);
113
114    fn load_icon_theme(
115        &self,
116        icon_theme_path: PathBuf,
117        icons_root_dir: PathBuf,
118        fs: Arc<dyn Fs>,
119    ) -> Task<Result<()>>;
120
121    fn reload_current_icon_theme(&self, cx: &mut App);
122}
123
124impl ExtensionThemeProxy for ExtensionHostProxy {
125    fn set_extensions_loaded(&self) {
126        let Some(proxy) = self.theme_proxy.read().clone() else {
127            return;
128        };
129
130        proxy.set_extensions_loaded()
131    }
132
133    fn list_theme_names(&self, theme_path: PathBuf, fs: Arc<dyn Fs>) -> Task<Result<Vec<String>>> {
134        let Some(proxy) = self.theme_proxy.read().clone() else {
135            return Task::ready(Ok(Vec::new()));
136        };
137
138        proxy.list_theme_names(theme_path, fs)
139    }
140
141    fn remove_user_themes(&self, themes: Vec<SharedString>) {
142        let Some(proxy) = self.theme_proxy.read().clone() else {
143            return;
144        };
145
146        proxy.remove_user_themes(themes)
147    }
148
149    fn load_user_theme(&self, theme_path: PathBuf, fs: Arc<dyn Fs>) -> Task<Result<()>> {
150        let Some(proxy) = self.theme_proxy.read().clone() else {
151            return Task::ready(Ok(()));
152        };
153
154        proxy.load_user_theme(theme_path, fs)
155    }
156
157    fn reload_current_theme(&self, cx: &mut App) {
158        let Some(proxy) = self.theme_proxy.read().clone() else {
159            return;
160        };
161
162        proxy.reload_current_theme(cx)
163    }
164
165    fn list_icon_theme_names(
166        &self,
167        icon_theme_path: PathBuf,
168        fs: Arc<dyn Fs>,
169    ) -> Task<Result<Vec<String>>> {
170        let Some(proxy) = self.theme_proxy.read().clone() else {
171            return Task::ready(Ok(Vec::new()));
172        };
173
174        proxy.list_icon_theme_names(icon_theme_path, fs)
175    }
176
177    fn remove_icon_themes(&self, icon_themes: Vec<SharedString>) {
178        let Some(proxy) = self.theme_proxy.read().clone() else {
179            return;
180        };
181
182        proxy.remove_icon_themes(icon_themes)
183    }
184
185    fn load_icon_theme(
186        &self,
187        icon_theme_path: PathBuf,
188        icons_root_dir: PathBuf,
189        fs: Arc<dyn Fs>,
190    ) -> Task<Result<()>> {
191        let Some(proxy) = self.theme_proxy.read().clone() else {
192            return Task::ready(Ok(()));
193        };
194
195        proxy.load_icon_theme(icon_theme_path, icons_root_dir, fs)
196    }
197
198    fn reload_current_icon_theme(&self, cx: &mut App) {
199        let Some(proxy) = self.theme_proxy.read().clone() else {
200            return;
201        };
202
203        proxy.reload_current_icon_theme(cx)
204    }
205}
206
207pub trait ExtensionGrammarProxy: Send + Sync + 'static {
208    fn register_grammars(&self, grammars: Vec<(Arc<str>, PathBuf)>);
209}
210
211impl ExtensionGrammarProxy for ExtensionHostProxy {
212    fn register_grammars(&self, grammars: Vec<(Arc<str>, PathBuf)>) {
213        let Some(proxy) = self.grammar_proxy.read().clone() else {
214            return;
215        };
216
217        proxy.register_grammars(grammars)
218    }
219}
220
221pub trait ExtensionLanguageProxy: Send + Sync + 'static {
222    fn register_language(
223        &self,
224        language: LanguageName,
225        grammar: Option<Arc<str>>,
226        matcher: LanguageMatcher,
227        hidden: bool,
228        load: Arc<dyn Fn() -> Result<LoadedLanguage> + Send + Sync + 'static>,
229    );
230
231    fn remove_languages(
232        &self,
233        languages_to_remove: &[LanguageName],
234        grammars_to_remove: &[Arc<str>],
235    );
236}
237
238impl ExtensionLanguageProxy for ExtensionHostProxy {
239    fn register_language(
240        &self,
241        language: LanguageName,
242        grammar: Option<Arc<str>>,
243        matcher: LanguageMatcher,
244        hidden: bool,
245        load: Arc<dyn Fn() -> Result<LoadedLanguage> + Send + Sync + 'static>,
246    ) {
247        let Some(proxy) = self.language_proxy.read().clone() else {
248            return;
249        };
250
251        proxy.register_language(language, grammar, matcher, hidden, load)
252    }
253
254    fn remove_languages(
255        &self,
256        languages_to_remove: &[LanguageName],
257        grammars_to_remove: &[Arc<str>],
258    ) {
259        let Some(proxy) = self.language_proxy.read().clone() else {
260            return;
261        };
262
263        proxy.remove_languages(languages_to_remove, grammars_to_remove)
264    }
265}
266
267pub trait ExtensionLanguageServerProxy: Send + Sync + 'static {
268    fn register_language_server(
269        &self,
270        extension: Arc<dyn Extension>,
271        language_server_id: LanguageServerName,
272        language: LanguageName,
273    );
274
275    fn remove_language_server(
276        &self,
277        language: &LanguageName,
278        language_server_id: &LanguageServerName,
279        cx: &mut App,
280    ) -> Task<Result<()>>;
281
282    fn update_language_server_status(
283        &self,
284        language_server_id: LanguageServerName,
285        status: BinaryStatus,
286    );
287}
288
289impl ExtensionLanguageServerProxy for ExtensionHostProxy {
290    fn register_language_server(
291        &self,
292        extension: Arc<dyn Extension>,
293        language_server_id: LanguageServerName,
294        language: LanguageName,
295    ) {
296        let Some(proxy) = self.language_server_proxy.read().clone() else {
297            return;
298        };
299
300        proxy.register_language_server(extension, language_server_id, language)
301    }
302
303    fn remove_language_server(
304        &self,
305        language: &LanguageName,
306        language_server_id: &LanguageServerName,
307        cx: &mut App,
308    ) -> Task<Result<()>> {
309        let Some(proxy) = self.language_server_proxy.read().clone() else {
310            return Task::ready(Ok(()));
311        };
312
313        proxy.remove_language_server(language, language_server_id, cx)
314    }
315
316    fn update_language_server_status(
317        &self,
318        language_server_id: LanguageServerName,
319        status: BinaryStatus,
320    ) {
321        let Some(proxy) = self.language_server_proxy.read().clone() else {
322            return;
323        };
324
325        proxy.update_language_server_status(language_server_id, status)
326    }
327}
328
329pub trait ExtensionSnippetProxy: Send + Sync + 'static {
330    fn register_snippet(&self, path: &PathBuf, snippet_contents: &str) -> Result<()>;
331}
332
333impl ExtensionSnippetProxy for ExtensionHostProxy {
334    fn register_snippet(&self, path: &PathBuf, snippet_contents: &str) -> Result<()> {
335        let Some(proxy) = self.snippet_proxy.read().clone() else {
336            return Ok(());
337        };
338
339        proxy.register_snippet(path, snippet_contents)
340    }
341}
342
343pub trait ExtensionSlashCommandProxy: Send + Sync + 'static {
344    fn register_slash_command(&self, extension: Arc<dyn Extension>, command: SlashCommand);
345
346    fn unregister_slash_command(&self, command_name: Arc<str>);
347}
348
349impl ExtensionSlashCommandProxy for ExtensionHostProxy {
350    fn register_slash_command(&self, extension: Arc<dyn Extension>, command: SlashCommand) {
351        let Some(proxy) = self.slash_command_proxy.read().clone() else {
352            return;
353        };
354
355        proxy.register_slash_command(extension, command)
356    }
357
358    fn unregister_slash_command(&self, command_name: Arc<str>) {
359        let Some(proxy) = self.slash_command_proxy.read().clone() else {
360            return;
361        };
362
363        proxy.unregister_slash_command(command_name)
364    }
365}
366
367pub trait ExtensionContextServerProxy: Send + Sync + 'static {
368    fn register_context_server(
369        &self,
370        extension: Arc<dyn Extension>,
371        server_id: Arc<str>,
372        cx: &mut App,
373    );
374
375    fn unregister_context_server(&self, server_id: Arc<str>, cx: &mut App);
376}
377
378impl ExtensionContextServerProxy for ExtensionHostProxy {
379    fn register_context_server(
380        &self,
381        extension: Arc<dyn Extension>,
382        server_id: Arc<str>,
383        cx: &mut App,
384    ) {
385        let Some(proxy) = self.context_server_proxy.read().clone() else {
386            return;
387        };
388
389        proxy.register_context_server(extension, server_id, cx)
390    }
391
392    fn unregister_context_server(&self, server_id: Arc<str>, cx: &mut App) {
393        let Some(proxy) = self.context_server_proxy.read().clone() else {
394            return;
395        };
396
397        proxy.unregister_context_server(server_id, cx)
398    }
399}
400
401pub trait ExtensionDebugAdapterProviderProxy: Send + Sync + 'static {
402    fn register_debug_adapter(
403        &self,
404        extension: Arc<dyn Extension>,
405        debug_adapter_name: Arc<str>,
406        schema_path: &Path,
407    );
408    fn register_debug_locator(&self, extension: Arc<dyn Extension>, locator_name: Arc<str>);
409    fn unregister_debug_adapter(&self, debug_adapter_name: Arc<str>);
410    fn unregister_debug_locator(&self, locator_name: Arc<str>);
411}
412
413impl ExtensionDebugAdapterProviderProxy for ExtensionHostProxy {
414    fn register_debug_adapter(
415        &self,
416        extension: Arc<dyn Extension>,
417        debug_adapter_name: Arc<str>,
418        schema_path: &Path,
419    ) {
420        let Some(proxy) = self.debug_adapter_provider_proxy.read().clone() else {
421            return;
422        };
423
424        proxy.register_debug_adapter(extension, debug_adapter_name, schema_path)
425    }
426
427    fn register_debug_locator(&self, extension: Arc<dyn Extension>, locator_name: Arc<str>) {
428        let Some(proxy) = self.debug_adapter_provider_proxy.read().clone() else {
429            return;
430        };
431
432        proxy.register_debug_locator(extension, locator_name)
433    }
434    fn unregister_debug_adapter(&self, debug_adapter_name: Arc<str>) {
435        let Some(proxy) = self.debug_adapter_provider_proxy.read().clone() else {
436            return;
437        };
438
439        proxy.unregister_debug_adapter(debug_adapter_name)
440    }
441    fn unregister_debug_locator(&self, locator_name: Arc<str>) {
442        let Some(proxy) = self.debug_adapter_provider_proxy.read().clone() else {
443            return;
444        };
445
446        proxy.unregister_debug_locator(locator_name)
447    }
448}