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