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;
 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    context_server_proxy: RwLock<Option<Arc<dyn ExtensionContextServerProxy>>>,
 33    debug_adapter_provider_proxy: RwLock<Option<Arc<dyn ExtensionDebugAdapterProviderProxy>>>,
 34    language_model_provider_proxy: RwLock<Option<Arc<dyn ExtensionLanguageModelProviderProxy>>>,
 35}
 36
 37impl ExtensionHostProxy {
 38    /// Returns the global [`ExtensionHostProxy`].
 39    pub fn global(cx: &App) -> Arc<Self> {
 40        GlobalExtensionHostProxy::global(cx).0.clone()
 41    }
 42
 43    /// Returns the global [`ExtensionHostProxy`].
 44    ///
 45    /// Inserts a default [`ExtensionHostProxy`] if one does not yet exist.
 46    pub fn default_global(cx: &mut App) -> Arc<Self> {
 47        cx.default_global::<GlobalExtensionHostProxy>().0.clone()
 48    }
 49
 50    pub fn new() -> Self {
 51        Self {
 52            theme_proxy: RwLock::default(),
 53            grammar_proxy: RwLock::default(),
 54            language_proxy: RwLock::default(),
 55            language_server_proxy: RwLock::default(),
 56            snippet_proxy: RwLock::default(),
 57            context_server_proxy: RwLock::default(),
 58            debug_adapter_provider_proxy: RwLock::default(),
 59            language_model_provider_proxy: RwLock::default(),
 60        }
 61    }
 62
 63    pub fn register_theme_proxy(&self, proxy: impl ExtensionThemeProxy) {
 64        self.theme_proxy.write().replace(Arc::new(proxy));
 65    }
 66
 67    pub fn register_grammar_proxy(&self, proxy: impl ExtensionGrammarProxy) {
 68        self.grammar_proxy.write().replace(Arc::new(proxy));
 69    }
 70
 71    pub fn register_language_proxy(&self, proxy: impl ExtensionLanguageProxy) {
 72        self.language_proxy.write().replace(Arc::new(proxy));
 73    }
 74
 75    pub fn register_language_server_proxy(&self, proxy: impl ExtensionLanguageServerProxy) {
 76        self.language_server_proxy.write().replace(Arc::new(proxy));
 77    }
 78
 79    pub fn register_snippet_proxy(&self, proxy: impl ExtensionSnippetProxy) {
 80        self.snippet_proxy.write().replace(Arc::new(proxy));
 81    }
 82
 83    pub fn register_context_server_proxy(&self, proxy: impl ExtensionContextServerProxy) {
 84        self.context_server_proxy.write().replace(Arc::new(proxy));
 85    }
 86
 87    pub fn register_debug_adapter_proxy(&self, proxy: impl ExtensionDebugAdapterProviderProxy) {
 88        self.debug_adapter_provider_proxy
 89            .write()
 90            .replace(Arc::new(proxy));
 91    }
 92
 93    pub fn register_language_model_provider_proxy(
 94        &self,
 95        proxy: impl ExtensionLanguageModelProviderProxy,
 96    ) {
 97        self.language_model_provider_proxy
 98            .write()
 99            .replace(Arc::new(proxy));
100    }
101}
102
103pub trait ExtensionThemeProxy: Send + Sync + 'static {
104    fn set_extensions_loaded(&self);
105
106    fn list_theme_names(&self, theme_path: PathBuf, fs: Arc<dyn Fs>) -> Task<Result<Vec<String>>>;
107
108    fn remove_user_themes(&self, themes: Vec<SharedString>);
109
110    fn load_user_theme(&self, theme_path: PathBuf, fs: Arc<dyn Fs>) -> Task<Result<()>>;
111
112    fn reload_current_theme(&self, cx: &mut App);
113
114    fn list_icon_theme_names(
115        &self,
116        icon_theme_path: PathBuf,
117        fs: Arc<dyn Fs>,
118    ) -> Task<Result<Vec<String>>>;
119
120    fn remove_icon_themes(&self, icon_themes: Vec<SharedString>);
121
122    fn load_icon_theme(
123        &self,
124        icon_theme_path: PathBuf,
125        icons_root_dir: PathBuf,
126        fs: Arc<dyn Fs>,
127    ) -> Task<Result<()>>;
128
129    fn reload_current_icon_theme(&self, cx: &mut App);
130}
131
132impl ExtensionThemeProxy for ExtensionHostProxy {
133    fn set_extensions_loaded(&self) {
134        let Some(proxy) = self.theme_proxy.read().clone() else {
135            return;
136        };
137
138        proxy.set_extensions_loaded()
139    }
140
141    fn list_theme_names(&self, theme_path: PathBuf, fs: Arc<dyn Fs>) -> Task<Result<Vec<String>>> {
142        let Some(proxy) = self.theme_proxy.read().clone() else {
143            return Task::ready(Ok(Vec::new()));
144        };
145
146        proxy.list_theme_names(theme_path, fs)
147    }
148
149    fn remove_user_themes(&self, themes: Vec<SharedString>) {
150        let Some(proxy) = self.theme_proxy.read().clone() else {
151            return;
152        };
153
154        proxy.remove_user_themes(themes)
155    }
156
157    fn load_user_theme(&self, theme_path: PathBuf, fs: Arc<dyn Fs>) -> Task<Result<()>> {
158        let Some(proxy) = self.theme_proxy.read().clone() else {
159            return Task::ready(Ok(()));
160        };
161
162        proxy.load_user_theme(theme_path, fs)
163    }
164
165    fn reload_current_theme(&self, cx: &mut App) {
166        let Some(proxy) = self.theme_proxy.read().clone() else {
167            return;
168        };
169
170        proxy.reload_current_theme(cx)
171    }
172
173    fn list_icon_theme_names(
174        &self,
175        icon_theme_path: PathBuf,
176        fs: Arc<dyn Fs>,
177    ) -> Task<Result<Vec<String>>> {
178        let Some(proxy) = self.theme_proxy.read().clone() else {
179            return Task::ready(Ok(Vec::new()));
180        };
181
182        proxy.list_icon_theme_names(icon_theme_path, fs)
183    }
184
185    fn remove_icon_themes(&self, icon_themes: Vec<SharedString>) {
186        let Some(proxy) = self.theme_proxy.read().clone() else {
187            return;
188        };
189
190        proxy.remove_icon_themes(icon_themes)
191    }
192
193    fn load_icon_theme(
194        &self,
195        icon_theme_path: PathBuf,
196        icons_root_dir: PathBuf,
197        fs: Arc<dyn Fs>,
198    ) -> Task<Result<()>> {
199        let Some(proxy) = self.theme_proxy.read().clone() else {
200            return Task::ready(Ok(()));
201        };
202
203        proxy.load_icon_theme(icon_theme_path, icons_root_dir, fs)
204    }
205
206    fn reload_current_icon_theme(&self, cx: &mut App) {
207        let Some(proxy) = self.theme_proxy.read().clone() else {
208            return;
209        };
210
211        proxy.reload_current_icon_theme(cx)
212    }
213}
214
215pub trait ExtensionGrammarProxy: Send + Sync + 'static {
216    fn register_grammars(&self, grammars: Vec<(Arc<str>, PathBuf)>);
217}
218
219impl ExtensionGrammarProxy for ExtensionHostProxy {
220    #[ztracing::instrument(skip_all)]
221    fn register_grammars(&self, grammars: Vec<(Arc<str>, PathBuf)>) {
222        let Some(proxy) = self.grammar_proxy.read().clone() else {
223            return;
224        };
225
226        proxy.register_grammars(grammars)
227    }
228}
229
230pub trait ExtensionLanguageProxy: Send + Sync + 'static {
231    fn register_language(
232        &self,
233        language: LanguageName,
234        grammar: Option<Arc<str>>,
235        matcher: LanguageMatcher,
236        hidden: bool,
237        load: Arc<dyn Fn() -> Result<LoadedLanguage> + Send + Sync + 'static>,
238    );
239
240    fn remove_languages(
241        &self,
242        languages_to_remove: &[LanguageName],
243        grammars_to_remove: &[Arc<str>],
244    );
245}
246
247impl ExtensionLanguageProxy for ExtensionHostProxy {
248    #[ztracing::instrument(skip_all, fields(lang = language.0.as_str()))]
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 ExtensionContextServerProxy: Send + Sync + 'static {
354    fn register_context_server(
355        &self,
356        extension: Arc<dyn Extension>,
357        server_id: Arc<str>,
358        cx: &mut App,
359    );
360
361    fn unregister_context_server(&self, server_id: Arc<str>, cx: &mut App);
362}
363
364impl ExtensionContextServerProxy for ExtensionHostProxy {
365    fn register_context_server(
366        &self,
367        extension: Arc<dyn Extension>,
368        server_id: Arc<str>,
369        cx: &mut App,
370    ) {
371        let Some(proxy) = self.context_server_proxy.read().clone() else {
372            return;
373        };
374
375        proxy.register_context_server(extension, server_id, cx)
376    }
377
378    fn unregister_context_server(&self, server_id: Arc<str>, cx: &mut App) {
379        let Some(proxy) = self.context_server_proxy.read().clone() else {
380            return;
381        };
382
383        proxy.unregister_context_server(server_id, cx)
384    }
385}
386
387pub trait ExtensionDebugAdapterProviderProxy: Send + Sync + 'static {
388    fn register_debug_adapter(
389        &self,
390        extension: Arc<dyn Extension>,
391        debug_adapter_name: Arc<str>,
392        schema_path: &Path,
393    );
394    fn register_debug_locator(&self, extension: Arc<dyn Extension>, locator_name: Arc<str>);
395    fn unregister_debug_adapter(&self, debug_adapter_name: Arc<str>);
396    fn unregister_debug_locator(&self, locator_name: Arc<str>);
397}
398
399impl ExtensionDebugAdapterProviderProxy for ExtensionHostProxy {
400    fn register_debug_adapter(
401        &self,
402        extension: Arc<dyn Extension>,
403        debug_adapter_name: Arc<str>,
404        schema_path: &Path,
405    ) {
406        let Some(proxy) = self.debug_adapter_provider_proxy.read().clone() else {
407            return;
408        };
409
410        proxy.register_debug_adapter(extension, debug_adapter_name, schema_path)
411    }
412
413    fn register_debug_locator(&self, extension: Arc<dyn Extension>, locator_name: Arc<str>) {
414        let Some(proxy) = self.debug_adapter_provider_proxy.read().clone() else {
415            return;
416        };
417
418        proxy.register_debug_locator(extension, locator_name)
419    }
420    fn unregister_debug_adapter(&self, debug_adapter_name: Arc<str>) {
421        let Some(proxy) = self.debug_adapter_provider_proxy.read().clone() else {
422            return;
423        };
424
425        proxy.unregister_debug_adapter(debug_adapter_name)
426    }
427    fn unregister_debug_locator(&self, locator_name: Arc<str>) {
428        let Some(proxy) = self.debug_adapter_provider_proxy.read().clone() else {
429            return;
430        };
431
432        proxy.unregister_debug_locator(locator_name)
433    }
434}
435
436pub trait ExtensionLanguageModelProviderProxy: Send + Sync + 'static {
437    fn register_language_model_provider(
438        &self,
439        provider_id: Arc<str>,
440        register_fn: LanguageModelProviderRegistration,
441        cx: &mut App,
442    );
443
444    fn unregister_language_model_provider(&self, provider_id: Arc<str>, cx: &mut App);
445}
446
447impl ExtensionLanguageModelProviderProxy for ExtensionHostProxy {
448    fn register_language_model_provider(
449        &self,
450        provider_id: Arc<str>,
451        register_fn: LanguageModelProviderRegistration,
452        cx: &mut App,
453    ) {
454        let Some(proxy) = self.language_model_provider_proxy.read().clone() else {
455            return;
456        };
457
458        proxy.register_language_model_provider(provider_id, register_fn, cx)
459    }
460
461    fn unregister_language_model_provider(&self, provider_id: Arc<str>, cx: &mut App) {
462        let Some(proxy) = self.language_model_provider_proxy.read().clone() else {
463            return;
464        };
465
466        proxy.unregister_language_model_provider(provider_id, cx)
467    }
468}