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    fn register_grammars(&self, grammars: Vec<(Arc<str>, PathBuf)>) {
227        let Some(proxy) = self.grammar_proxy.read().clone() else {
228            return;
229        };
230
231        proxy.register_grammars(grammars)
232    }
233}
234
235pub trait ExtensionLanguageProxy: Send + Sync + 'static {
236    fn register_language(
237        &self,
238        language: LanguageName,
239        grammar: Option<Arc<str>>,
240        matcher: LanguageMatcher,
241        hidden: bool,
242        load: Arc<dyn Fn() -> Result<LoadedLanguage> + Send + Sync + 'static>,
243    );
244
245    fn remove_languages(
246        &self,
247        languages_to_remove: &[LanguageName],
248        grammars_to_remove: &[Arc<str>],
249    );
250}
251
252impl ExtensionLanguageProxy for ExtensionHostProxy {
253    fn register_language(
254        &self,
255        language: LanguageName,
256        grammar: Option<Arc<str>>,
257        matcher: LanguageMatcher,
258        hidden: bool,
259        load: Arc<dyn Fn() -> Result<LoadedLanguage> + Send + Sync + 'static>,
260    ) {
261        let Some(proxy) = self.language_proxy.read().clone() else {
262            return;
263        };
264
265        proxy.register_language(language, grammar, matcher, hidden, load)
266    }
267
268    fn remove_languages(
269        &self,
270        languages_to_remove: &[LanguageName],
271        grammars_to_remove: &[Arc<str>],
272    ) {
273        let Some(proxy) = self.language_proxy.read().clone() else {
274            return;
275        };
276
277        proxy.remove_languages(languages_to_remove, grammars_to_remove)
278    }
279}
280
281pub trait ExtensionLanguageServerProxy: Send + Sync + 'static {
282    fn register_language_server(
283        &self,
284        extension: Arc<dyn Extension>,
285        language_server_id: LanguageServerName,
286        language: LanguageName,
287    );
288
289    fn remove_language_server(
290        &self,
291        language: &LanguageName,
292        language_server_id: &LanguageServerName,
293        cx: &mut App,
294    ) -> Task<Result<()>>;
295
296    fn update_language_server_status(
297        &self,
298        language_server_id: LanguageServerName,
299        status: BinaryStatus,
300    );
301}
302
303impl ExtensionLanguageServerProxy for ExtensionHostProxy {
304    fn register_language_server(
305        &self,
306        extension: Arc<dyn Extension>,
307        language_server_id: LanguageServerName,
308        language: LanguageName,
309    ) {
310        let Some(proxy) = self.language_server_proxy.read().clone() else {
311            return;
312        };
313
314        proxy.register_language_server(extension, language_server_id, language)
315    }
316
317    fn remove_language_server(
318        &self,
319        language: &LanguageName,
320        language_server_id: &LanguageServerName,
321        cx: &mut App,
322    ) -> Task<Result<()>> {
323        let Some(proxy) = self.language_server_proxy.read().clone() else {
324            return Task::ready(Ok(()));
325        };
326
327        proxy.remove_language_server(language, language_server_id, cx)
328    }
329
330    fn update_language_server_status(
331        &self,
332        language_server_id: LanguageServerName,
333        status: BinaryStatus,
334    ) {
335        let Some(proxy) = self.language_server_proxy.read().clone() else {
336            return;
337        };
338
339        proxy.update_language_server_status(language_server_id, status)
340    }
341}
342
343pub trait ExtensionSnippetProxy: Send + Sync + 'static {
344    fn register_snippet(&self, path: &PathBuf, snippet_contents: &str) -> Result<()>;
345}
346
347impl ExtensionSnippetProxy for ExtensionHostProxy {
348    fn register_snippet(&self, path: &PathBuf, snippet_contents: &str) -> Result<()> {
349        let Some(proxy) = self.snippet_proxy.read().clone() else {
350            return Ok(());
351        };
352
353        proxy.register_snippet(path, snippet_contents)
354    }
355}
356
357pub trait ExtensionSlashCommandProxy: Send + Sync + 'static {
358    fn register_slash_command(&self, extension: Arc<dyn Extension>, command: SlashCommand);
359
360    fn unregister_slash_command(&self, command_name: Arc<str>);
361}
362
363impl ExtensionSlashCommandProxy for ExtensionHostProxy {
364    fn register_slash_command(&self, extension: Arc<dyn Extension>, command: SlashCommand) {
365        let Some(proxy) = self.slash_command_proxy.read().clone() else {
366            return;
367        };
368
369        proxy.register_slash_command(extension, command)
370    }
371
372    fn unregister_slash_command(&self, command_name: Arc<str>) {
373        let Some(proxy) = self.slash_command_proxy.read().clone() else {
374            return;
375        };
376
377        proxy.unregister_slash_command(command_name)
378    }
379}
380
381pub trait ExtensionContextServerProxy: Send + Sync + 'static {
382    fn register_context_server(
383        &self,
384        extension: Arc<dyn Extension>,
385        server_id: Arc<str>,
386        cx: &mut App,
387    );
388
389    fn unregister_context_server(&self, server_id: Arc<str>, cx: &mut App);
390}
391
392impl ExtensionContextServerProxy for ExtensionHostProxy {
393    fn register_context_server(
394        &self,
395        extension: Arc<dyn Extension>,
396        server_id: Arc<str>,
397        cx: &mut App,
398    ) {
399        let Some(proxy) = self.context_server_proxy.read().clone() else {
400            return;
401        };
402
403        proxy.register_context_server(extension, server_id, cx)
404    }
405
406    fn unregister_context_server(&self, server_id: Arc<str>, cx: &mut App) {
407        let Some(proxy) = self.context_server_proxy.read().clone() else {
408            return;
409        };
410
411        proxy.unregister_context_server(server_id, cx)
412    }
413}
414
415pub trait ExtensionDebugAdapterProviderProxy: Send + Sync + 'static {
416    fn register_debug_adapter(
417        &self,
418        extension: Arc<dyn Extension>,
419        debug_adapter_name: Arc<str>,
420        schema_path: &Path,
421    );
422    fn register_debug_locator(&self, extension: Arc<dyn Extension>, locator_name: Arc<str>);
423    fn unregister_debug_adapter(&self, debug_adapter_name: Arc<str>);
424    fn unregister_debug_locator(&self, locator_name: Arc<str>);
425}
426
427impl ExtensionDebugAdapterProviderProxy for ExtensionHostProxy {
428    fn register_debug_adapter(
429        &self,
430        extension: Arc<dyn Extension>,
431        debug_adapter_name: Arc<str>,
432        schema_path: &Path,
433    ) {
434        let Some(proxy) = self.debug_adapter_provider_proxy.read().clone() else {
435            return;
436        };
437
438        proxy.register_debug_adapter(extension, debug_adapter_name, schema_path)
439    }
440
441    fn register_debug_locator(&self, extension: Arc<dyn Extension>, locator_name: Arc<str>) {
442        let Some(proxy) = self.debug_adapter_provider_proxy.read().clone() else {
443            return;
444        };
445
446        proxy.register_debug_locator(extension, locator_name)
447    }
448    fn unregister_debug_adapter(&self, debug_adapter_name: Arc<str>) {
449        let Some(proxy) = self.debug_adapter_provider_proxy.read().clone() else {
450            return;
451        };
452
453        proxy.unregister_debug_adapter(debug_adapter_name)
454    }
455    fn unregister_debug_locator(&self, locator_name: Arc<str>) {
456        let Some(proxy) = self.debug_adapter_provider_proxy.read().clone() else {
457            return;
458        };
459
460        proxy.unregister_debug_locator(locator_name)
461    }
462}
463
464pub trait ExtensionLanguageModelProviderProxy: Send + Sync + 'static {
465    fn register_language_model_provider(
466        &self,
467        provider_id: Arc<str>,
468        register_fn: LanguageModelProviderRegistration,
469        cx: &mut App,
470    );
471
472    fn unregister_language_model_provider(&self, provider_id: Arc<str>, cx: &mut App);
473}
474
475impl ExtensionLanguageModelProviderProxy for ExtensionHostProxy {
476    fn register_language_model_provider(
477        &self,
478        provider_id: Arc<str>,
479        register_fn: LanguageModelProviderRegistration,
480        cx: &mut App,
481    ) {
482        let Some(proxy) = self.language_model_provider_proxy.read().clone() else {
483            return;
484        };
485
486        proxy.register_language_model_provider(provider_id, register_fn, cx)
487    }
488
489    fn unregister_language_model_provider(&self, provider_id: Arc<str>, cx: &mut App) {
490        let Some(proxy) = self.language_model_provider_proxy.read().clone() else {
491            return;
492        };
493
494        proxy.unregister_language_model_provider(provider_id, cx)
495    }
496}