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}