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