1mod since_v0_0_1;
2mod since_v0_0_4;
3mod since_v0_0_6;
4mod since_v0_1_0;
5mod since_v0_2_0;
6mod since_v0_3_0;
7mod since_v0_4_0;
8mod since_v0_5_0;
9mod since_v0_6_0;
10mod since_v0_8_0;
11use dap::DebugRequest;
12use extension::{DebugTaskDefinition, KeyValueStoreDelegate, WorktreeDelegate};
13use gpui::BackgroundExecutor;
14use language::LanguageName;
15use lsp::LanguageServerName;
16use release_channel::ReleaseChannel;
17use task::{DebugScenario, SpawnInTerminal, TaskTemplate, ZedDebugConfig};
18
19use crate::wasm_host::wit::since_v0_6_0::dap::StartDebuggingRequestArgumentsRequest;
20
21use super::{WasmState, wasm_engine};
22use anyhow::{Context as _, Result, anyhow};
23use semver::Version;
24use since_v0_8_0 as latest;
25use std::{ops::RangeInclusive, path::PathBuf, sync::Arc};
26use wasmtime::{
27 Store,
28 component::{Component, Linker, Resource},
29};
30
31#[cfg(test)]
32pub use latest::CodeLabelSpanLiteral;
33pub use latest::{
34 CodeLabel, CodeLabelSpan, Command, DebugAdapterBinary, ExtensionProject, Range, SlashCommand,
35 zed::extension::context_server::ContextServerConfiguration,
36 zed::extension::lsp::{
37 Completion, CompletionKind, CompletionLabelDetails, InsertTextFormat, Symbol, SymbolKind,
38 },
39 zed::extension::slash_command::{SlashCommandArgumentCompletion, SlashCommandOutput},
40};
41pub use since_v0_0_4::LanguageServerConfig;
42
43pub fn new_linker(
44 executor: &BackgroundExecutor,
45 f: impl Fn(&mut Linker<WasmState>, fn(&mut WasmState) -> &mut WasmState) -> Result<()>,
46) -> Linker<WasmState> {
47 let mut linker = Linker::new(&wasm_engine(executor));
48 wasmtime_wasi::add_to_linker_async(&mut linker).unwrap();
49 f(&mut linker, wasi_view).unwrap();
50 linker
51}
52
53fn wasi_view(state: &mut WasmState) -> &mut WasmState {
54 state
55}
56
57/// Returns whether the given Wasm API version is supported by the Wasm host.
58pub fn is_supported_wasm_api_version(release_channel: ReleaseChannel, version: Version) -> bool {
59 wasm_api_version_range(release_channel).contains(&version)
60}
61
62/// Returns the Wasm API version range that is supported by the Wasm host.
63#[inline(always)]
64pub fn wasm_api_version_range(release_channel: ReleaseChannel) -> RangeInclusive<Version> {
65 // Note: The release channel can be used to stage a new version of the extension API.
66 let _ = release_channel;
67
68 let max_version = match release_channel {
69 ReleaseChannel::Dev | ReleaseChannel::Nightly => latest::MAX_VERSION,
70 ReleaseChannel::Stable | ReleaseChannel::Preview => since_v0_6_0::MAX_VERSION,
71 };
72
73 since_v0_0_1::MIN_VERSION..=max_version
74}
75
76/// Authorizes access to use unreleased versions of the Wasm API, based on the provided [`ReleaseChannel`].
77///
78/// Note: If there isn't currently an unreleased Wasm API version this function may be unused. Don't delete it!
79pub fn authorize_access_to_unreleased_wasm_api_version(
80 release_channel: ReleaseChannel,
81) -> Result<()> {
82 let allow_unreleased_version = match release_channel {
83 ReleaseChannel::Dev | ReleaseChannel::Nightly => true,
84 ReleaseChannel::Stable | ReleaseChannel::Preview => {
85 // We always allow the latest in tests so that the extension tests pass on release branches.
86 cfg!(any(test, feature = "test-support"))
87 }
88 };
89
90 anyhow::ensure!(
91 allow_unreleased_version,
92 "unreleased versions of the extension API can only be used on development builds of Zed"
93 );
94
95 Ok(())
96}
97
98pub enum Extension {
99 V0_8_0(since_v0_8_0::Extension),
100 V0_6_0(since_v0_6_0::Extension),
101 V0_5_0(since_v0_5_0::Extension),
102 V0_4_0(since_v0_4_0::Extension),
103 V0_3_0(since_v0_3_0::Extension),
104 V0_2_0(since_v0_2_0::Extension),
105 V0_1_0(since_v0_1_0::Extension),
106 V0_0_6(since_v0_0_6::Extension),
107 V0_0_4(since_v0_0_4::Extension),
108 V0_0_1(since_v0_0_1::Extension),
109}
110
111impl Extension {
112 pub async fn instantiate_async(
113 executor: &BackgroundExecutor,
114 store: &mut Store<WasmState>,
115 release_channel: ReleaseChannel,
116 version: Version,
117 component: &Component,
118 ) -> Result<Self> {
119 // Note: The release channel can be used to stage a new version of the extension API.
120 let _ = release_channel;
121
122 if version >= latest::MIN_VERSION {
123 authorize_access_to_unreleased_wasm_api_version(release_channel)?;
124
125 let extension =
126 latest::Extension::instantiate_async(store, component, latest::linker(executor))
127 .await
128 .context("failed to instantiate wasm extension")?;
129 Ok(Self::V0_8_0(extension))
130 } else if version >= since_v0_6_0::MIN_VERSION {
131 let extension = since_v0_6_0::Extension::instantiate_async(
132 store,
133 component,
134 since_v0_6_0::linker(executor),
135 )
136 .await
137 .context("failed to instantiate wasm extension")?;
138 Ok(Self::V0_6_0(extension))
139 } else if version >= since_v0_5_0::MIN_VERSION {
140 let extension = since_v0_5_0::Extension::instantiate_async(
141 store,
142 component,
143 since_v0_5_0::linker(executor),
144 )
145 .await
146 .context("failed to instantiate wasm extension")?;
147 Ok(Self::V0_5_0(extension))
148 } else if version >= since_v0_4_0::MIN_VERSION {
149 let extension = since_v0_4_0::Extension::instantiate_async(
150 store,
151 component,
152 since_v0_4_0::linker(executor),
153 )
154 .await
155 .context("failed to instantiate wasm extension")?;
156 Ok(Self::V0_4_0(extension))
157 } else if version >= since_v0_3_0::MIN_VERSION {
158 let extension = since_v0_3_0::Extension::instantiate_async(
159 store,
160 component,
161 since_v0_3_0::linker(executor),
162 )
163 .await
164 .context("failed to instantiate wasm extension")?;
165 Ok(Self::V0_3_0(extension))
166 } else if version >= since_v0_2_0::MIN_VERSION {
167 let extension = since_v0_2_0::Extension::instantiate_async(
168 store,
169 component,
170 since_v0_2_0::linker(executor),
171 )
172 .await
173 .context("failed to instantiate wasm extension")?;
174 Ok(Self::V0_2_0(extension))
175 } else if version >= since_v0_1_0::MIN_VERSION {
176 let extension = since_v0_1_0::Extension::instantiate_async(
177 store,
178 component,
179 since_v0_1_0::linker(executor),
180 )
181 .await
182 .context("failed to instantiate wasm extension")?;
183 Ok(Self::V0_1_0(extension))
184 } else if version >= since_v0_0_6::MIN_VERSION {
185 let extension = since_v0_0_6::Extension::instantiate_async(
186 store,
187 component,
188 since_v0_0_6::linker(executor),
189 )
190 .await
191 .context("failed to instantiate wasm extension")?;
192 Ok(Self::V0_0_6(extension))
193 } else if version >= since_v0_0_4::MIN_VERSION {
194 let extension = since_v0_0_4::Extension::instantiate_async(
195 store,
196 component,
197 since_v0_0_4::linker(executor),
198 )
199 .await
200 .context("failed to instantiate wasm extension")?;
201 Ok(Self::V0_0_4(extension))
202 } else {
203 let extension = since_v0_0_1::Extension::instantiate_async(
204 store,
205 component,
206 since_v0_0_1::linker(executor),
207 )
208 .await
209 .context("failed to instantiate wasm extension")?;
210 Ok(Self::V0_0_1(extension))
211 }
212 }
213
214 pub async fn call_init_extension(&self, store: &mut Store<WasmState>) -> Result<()> {
215 match self {
216 Extension::V0_8_0(ext) => ext.call_init_extension(store).await,
217 Extension::V0_6_0(ext) => ext.call_init_extension(store).await,
218 Extension::V0_5_0(ext) => ext.call_init_extension(store).await,
219 Extension::V0_4_0(ext) => ext.call_init_extension(store).await,
220 Extension::V0_3_0(ext) => ext.call_init_extension(store).await,
221 Extension::V0_2_0(ext) => ext.call_init_extension(store).await,
222 Extension::V0_1_0(ext) => ext.call_init_extension(store).await,
223 Extension::V0_0_6(ext) => ext.call_init_extension(store).await,
224 Extension::V0_0_4(ext) => ext.call_init_extension(store).await,
225 Extension::V0_0_1(ext) => ext.call_init_extension(store).await,
226 }
227 }
228
229 pub async fn call_language_server_command(
230 &self,
231 store: &mut Store<WasmState>,
232 language_server_id: &LanguageServerName,
233 language_name: &LanguageName,
234 resource: Resource<Arc<dyn WorktreeDelegate>>,
235 ) -> Result<Result<Command, String>> {
236 match self {
237 Extension::V0_8_0(ext) => {
238 ext.call_language_server_command(store, &language_server_id.0, resource)
239 .await
240 }
241 Extension::V0_6_0(ext) => {
242 ext.call_language_server_command(store, &language_server_id.0, resource)
243 .await
244 }
245 Extension::V0_5_0(ext) => {
246 ext.call_language_server_command(store, &language_server_id.0, resource)
247 .await
248 }
249 Extension::V0_4_0(ext) => {
250 ext.call_language_server_command(store, &language_server_id.0, resource)
251 .await
252 }
253 Extension::V0_3_0(ext) => {
254 ext.call_language_server_command(store, &language_server_id.0, resource)
255 .await
256 }
257 Extension::V0_2_0(ext) => Ok(ext
258 .call_language_server_command(store, &language_server_id.0, resource)
259 .await?
260 .map(|command| command.into())),
261 Extension::V0_1_0(ext) => Ok(ext
262 .call_language_server_command(store, &language_server_id.0, resource)
263 .await?
264 .map(|command| command.into())),
265 Extension::V0_0_6(ext) => Ok(ext
266 .call_language_server_command(store, &language_server_id.0, resource)
267 .await?
268 .map(|command| command.into())),
269 Extension::V0_0_4(ext) => Ok(ext
270 .call_language_server_command(
271 store,
272 &LanguageServerConfig {
273 name: language_server_id.0.to_string(),
274 language_name: language_name.to_string(),
275 },
276 resource,
277 )
278 .await?
279 .map(|command| command.into())),
280 Extension::V0_0_1(ext) => Ok(ext
281 .call_language_server_command(
282 store,
283 &LanguageServerConfig {
284 name: language_server_id.0.to_string(),
285 language_name: language_name.to_string(),
286 }
287 .into(),
288 resource,
289 )
290 .await?
291 .map(|command| command.into())),
292 }
293 }
294
295 pub async fn call_language_server_initialization_options(
296 &self,
297 store: &mut Store<WasmState>,
298 language_server_id: &LanguageServerName,
299 language_name: &LanguageName,
300 resource: Resource<Arc<dyn WorktreeDelegate>>,
301 ) -> Result<Result<Option<String>, String>> {
302 match self {
303 Extension::V0_8_0(ext) => {
304 ext.call_language_server_initialization_options(
305 store,
306 &language_server_id.0,
307 resource,
308 )
309 .await
310 }
311 Extension::V0_6_0(ext) => {
312 ext.call_language_server_initialization_options(
313 store,
314 &language_server_id.0,
315 resource,
316 )
317 .await
318 }
319 Extension::V0_5_0(ext) => {
320 ext.call_language_server_initialization_options(
321 store,
322 &language_server_id.0,
323 resource,
324 )
325 .await
326 }
327 Extension::V0_4_0(ext) => {
328 ext.call_language_server_initialization_options(
329 store,
330 &language_server_id.0,
331 resource,
332 )
333 .await
334 }
335 Extension::V0_3_0(ext) => {
336 ext.call_language_server_initialization_options(
337 store,
338 &language_server_id.0,
339 resource,
340 )
341 .await
342 }
343 Extension::V0_2_0(ext) => {
344 ext.call_language_server_initialization_options(
345 store,
346 &language_server_id.0,
347 resource,
348 )
349 .await
350 }
351 Extension::V0_1_0(ext) => {
352 ext.call_language_server_initialization_options(
353 store,
354 &language_server_id.0,
355 resource,
356 )
357 .await
358 }
359 Extension::V0_0_6(ext) => {
360 ext.call_language_server_initialization_options(
361 store,
362 &language_server_id.0,
363 resource,
364 )
365 .await
366 }
367 Extension::V0_0_4(ext) => {
368 ext.call_language_server_initialization_options(
369 store,
370 &LanguageServerConfig {
371 name: language_server_id.0.to_string(),
372 language_name: language_name.to_string(),
373 },
374 resource,
375 )
376 .await
377 }
378 Extension::V0_0_1(ext) => {
379 ext.call_language_server_initialization_options(
380 store,
381 &LanguageServerConfig {
382 name: language_server_id.0.to_string(),
383 language_name: language_name.to_string(),
384 }
385 .into(),
386 resource,
387 )
388 .await
389 }
390 }
391 }
392
393 pub async fn call_language_server_workspace_configuration(
394 &self,
395 store: &mut Store<WasmState>,
396 language_server_id: &LanguageServerName,
397 resource: Resource<Arc<dyn WorktreeDelegate>>,
398 ) -> Result<Result<Option<String>, String>> {
399 match self {
400 Extension::V0_8_0(ext) => {
401 ext.call_language_server_workspace_configuration(
402 store,
403 &language_server_id.0,
404 resource,
405 )
406 .await
407 }
408 Extension::V0_6_0(ext) => {
409 ext.call_language_server_workspace_configuration(
410 store,
411 &language_server_id.0,
412 resource,
413 )
414 .await
415 }
416 Extension::V0_5_0(ext) => {
417 ext.call_language_server_workspace_configuration(
418 store,
419 &language_server_id.0,
420 resource,
421 )
422 .await
423 }
424 Extension::V0_4_0(ext) => {
425 ext.call_language_server_workspace_configuration(
426 store,
427 &language_server_id.0,
428 resource,
429 )
430 .await
431 }
432 Extension::V0_3_0(ext) => {
433 ext.call_language_server_workspace_configuration(
434 store,
435 &language_server_id.0,
436 resource,
437 )
438 .await
439 }
440 Extension::V0_2_0(ext) => {
441 ext.call_language_server_workspace_configuration(
442 store,
443 &language_server_id.0,
444 resource,
445 )
446 .await
447 }
448 Extension::V0_1_0(ext) => {
449 ext.call_language_server_workspace_configuration(
450 store,
451 &language_server_id.0,
452 resource,
453 )
454 .await
455 }
456 Extension::V0_0_6(ext) => {
457 ext.call_language_server_workspace_configuration(
458 store,
459 &language_server_id.0,
460 resource,
461 )
462 .await
463 }
464 Extension::V0_0_4(_) | Extension::V0_0_1(_) => Ok(Ok(None)),
465 }
466 }
467
468 pub async fn call_language_server_additional_initialization_options(
469 &self,
470 store: &mut Store<WasmState>,
471 language_server_id: &LanguageServerName,
472 target_language_server_id: &LanguageServerName,
473 resource: Resource<Arc<dyn WorktreeDelegate>>,
474 ) -> Result<Result<Option<String>, String>> {
475 match self {
476 Extension::V0_8_0(ext) => {
477 ext.call_language_server_additional_initialization_options(
478 store,
479 &language_server_id.0,
480 &target_language_server_id.0,
481 resource,
482 )
483 .await
484 }
485 Extension::V0_6_0(ext) => {
486 ext.call_language_server_additional_initialization_options(
487 store,
488 &language_server_id.0,
489 &target_language_server_id.0,
490 resource,
491 )
492 .await
493 }
494 Extension::V0_5_0(ext) => {
495 ext.call_language_server_additional_initialization_options(
496 store,
497 &language_server_id.0,
498 &target_language_server_id.0,
499 resource,
500 )
501 .await
502 }
503 Extension::V0_4_0(ext) => {
504 ext.call_language_server_additional_initialization_options(
505 store,
506 &language_server_id.0,
507 &target_language_server_id.0,
508 resource,
509 )
510 .await
511 }
512 Extension::V0_3_0(_)
513 | Extension::V0_2_0(_)
514 | Extension::V0_1_0(_)
515 | Extension::V0_0_6(_)
516 | Extension::V0_0_4(_)
517 | Extension::V0_0_1(_) => Ok(Ok(None)),
518 }
519 }
520
521 pub async fn call_language_server_additional_workspace_configuration(
522 &self,
523 store: &mut Store<WasmState>,
524 language_server_id: &LanguageServerName,
525 target_language_server_id: &LanguageServerName,
526 resource: Resource<Arc<dyn WorktreeDelegate>>,
527 ) -> Result<Result<Option<String>, String>> {
528 match self {
529 Extension::V0_8_0(ext) => {
530 ext.call_language_server_additional_workspace_configuration(
531 store,
532 &language_server_id.0,
533 &target_language_server_id.0,
534 resource,
535 )
536 .await
537 }
538 Extension::V0_6_0(ext) => {
539 ext.call_language_server_additional_workspace_configuration(
540 store,
541 &language_server_id.0,
542 &target_language_server_id.0,
543 resource,
544 )
545 .await
546 }
547 Extension::V0_5_0(ext) => {
548 ext.call_language_server_additional_workspace_configuration(
549 store,
550 &language_server_id.0,
551 &target_language_server_id.0,
552 resource,
553 )
554 .await
555 }
556 Extension::V0_4_0(ext) => {
557 ext.call_language_server_additional_workspace_configuration(
558 store,
559 &language_server_id.0,
560 &target_language_server_id.0,
561 resource,
562 )
563 .await
564 }
565 Extension::V0_3_0(_)
566 | Extension::V0_2_0(_)
567 | Extension::V0_1_0(_)
568 | Extension::V0_0_6(_)
569 | Extension::V0_0_4(_)
570 | Extension::V0_0_1(_) => Ok(Ok(None)),
571 }
572 }
573
574 pub async fn call_labels_for_completions(
575 &self,
576 store: &mut Store<WasmState>,
577 language_server_id: &LanguageServerName,
578 completions: Vec<latest::Completion>,
579 ) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
580 match self {
581 Extension::V0_8_0(ext) => {
582 ext.call_labels_for_completions(store, &language_server_id.0, &completions)
583 .await
584 }
585 Extension::V0_6_0(ext) => Ok(ext
586 .call_labels_for_completions(
587 store,
588 &language_server_id.0,
589 &completions.into_iter().collect::<Vec<_>>(),
590 )
591 .await?
592 .map(|labels| {
593 labels
594 .into_iter()
595 .map(|label| label.map(Into::into))
596 .collect()
597 })),
598 Extension::V0_5_0(ext) => Ok(ext
599 .call_labels_for_completions(
600 store,
601 &language_server_id.0,
602 &completions.into_iter().collect::<Vec<_>>(),
603 )
604 .await?
605 .map(|labels| {
606 labels
607 .into_iter()
608 .map(|label| label.map(Into::into))
609 .collect()
610 })),
611 Extension::V0_4_0(ext) => Ok(ext
612 .call_labels_for_completions(
613 store,
614 &language_server_id.0,
615 &completions.into_iter().collect::<Vec<_>>(),
616 )
617 .await?
618 .map(|labels| {
619 labels
620 .into_iter()
621 .map(|label| label.map(Into::into))
622 .collect()
623 })),
624 Extension::V0_3_0(ext) => Ok(ext
625 .call_labels_for_completions(
626 store,
627 &language_server_id.0,
628 &completions.into_iter().collect::<Vec<_>>(),
629 )
630 .await?
631 .map(|labels| {
632 labels
633 .into_iter()
634 .map(|label| label.map(Into::into))
635 .collect()
636 })),
637 Extension::V0_2_0(ext) => Ok(ext
638 .call_labels_for_completions(
639 store,
640 &language_server_id.0,
641 &completions.into_iter().collect::<Vec<_>>(),
642 )
643 .await?
644 .map(|labels| {
645 labels
646 .into_iter()
647 .map(|label| label.map(Into::into))
648 .collect()
649 })),
650 Extension::V0_1_0(ext) => Ok(ext
651 .call_labels_for_completions(
652 store,
653 &language_server_id.0,
654 &completions.into_iter().map(Into::into).collect::<Vec<_>>(),
655 )
656 .await?
657 .map(|labels| {
658 labels
659 .into_iter()
660 .map(|label| label.map(Into::into))
661 .collect()
662 })),
663 Extension::V0_0_6(ext) => Ok(ext
664 .call_labels_for_completions(
665 store,
666 &language_server_id.0,
667 &completions.into_iter().map(Into::into).collect::<Vec<_>>(),
668 )
669 .await?
670 .map(|labels| {
671 labels
672 .into_iter()
673 .map(|label| label.map(Into::into))
674 .collect()
675 })),
676 Extension::V0_0_1(_) | Extension::V0_0_4(_) => Ok(Ok(Vec::new())),
677 }
678 }
679
680 pub async fn call_labels_for_symbols(
681 &self,
682 store: &mut Store<WasmState>,
683 language_server_id: &LanguageServerName,
684 symbols: Vec<latest::Symbol>,
685 ) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
686 match self {
687 Extension::V0_8_0(ext) => {
688 ext.call_labels_for_symbols(store, &language_server_id.0, &symbols)
689 .await
690 }
691 Extension::V0_6_0(ext) => Ok(ext
692 .call_labels_for_symbols(
693 store,
694 &language_server_id.0,
695 &symbols.into_iter().collect::<Vec<_>>(),
696 )
697 .await?
698 .map(|labels| {
699 labels
700 .into_iter()
701 .map(|label| label.map(Into::into))
702 .collect()
703 })),
704 Extension::V0_5_0(ext) => Ok(ext
705 .call_labels_for_symbols(
706 store,
707 &language_server_id.0,
708 &symbols.into_iter().collect::<Vec<_>>(),
709 )
710 .await?
711 .map(|labels| {
712 labels
713 .into_iter()
714 .map(|label| label.map(Into::into))
715 .collect()
716 })),
717 Extension::V0_4_0(ext) => Ok(ext
718 .call_labels_for_symbols(
719 store,
720 &language_server_id.0,
721 &symbols.into_iter().collect::<Vec<_>>(),
722 )
723 .await?
724 .map(|labels| {
725 labels
726 .into_iter()
727 .map(|label| label.map(Into::into))
728 .collect()
729 })),
730 Extension::V0_3_0(ext) => Ok(ext
731 .call_labels_for_symbols(
732 store,
733 &language_server_id.0,
734 &symbols.into_iter().collect::<Vec<_>>(),
735 )
736 .await?
737 .map(|labels| {
738 labels
739 .into_iter()
740 .map(|label| label.map(Into::into))
741 .collect()
742 })),
743 Extension::V0_2_0(ext) => Ok(ext
744 .call_labels_for_symbols(
745 store,
746 &language_server_id.0,
747 &symbols.into_iter().collect::<Vec<_>>(),
748 )
749 .await?
750 .map(|labels| {
751 labels
752 .into_iter()
753 .map(|label| label.map(Into::into))
754 .collect()
755 })),
756 Extension::V0_1_0(ext) => Ok(ext
757 .call_labels_for_symbols(
758 store,
759 &language_server_id.0,
760 &symbols.into_iter().map(Into::into).collect::<Vec<_>>(),
761 )
762 .await?
763 .map(|labels| {
764 labels
765 .into_iter()
766 .map(|label| label.map(Into::into))
767 .collect()
768 })),
769 Extension::V0_0_6(ext) => Ok(ext
770 .call_labels_for_symbols(
771 store,
772 &language_server_id.0,
773 &symbols.into_iter().map(Into::into).collect::<Vec<_>>(),
774 )
775 .await?
776 .map(|labels| {
777 labels
778 .into_iter()
779 .map(|label| label.map(Into::into))
780 .collect()
781 })),
782 Extension::V0_0_1(_) | Extension::V0_0_4(_) => Ok(Ok(Vec::new())),
783 }
784 }
785
786 pub async fn call_complete_slash_command_argument(
787 &self,
788 store: &mut Store<WasmState>,
789 command: &SlashCommand,
790 arguments: &[String],
791 ) -> Result<Result<Vec<SlashCommandArgumentCompletion>, String>> {
792 match self {
793 Extension::V0_8_0(ext) => {
794 ext.call_complete_slash_command_argument(store, command, arguments)
795 .await
796 }
797 Extension::V0_6_0(ext) => {
798 ext.call_complete_slash_command_argument(store, command, arguments)
799 .await
800 }
801 Extension::V0_5_0(ext) => {
802 ext.call_complete_slash_command_argument(store, command, arguments)
803 .await
804 }
805 Extension::V0_4_0(ext) => {
806 ext.call_complete_slash_command_argument(store, command, arguments)
807 .await
808 }
809 Extension::V0_3_0(ext) => {
810 ext.call_complete_slash_command_argument(store, command, arguments)
811 .await
812 }
813 Extension::V0_2_0(ext) => {
814 ext.call_complete_slash_command_argument(store, command, arguments)
815 .await
816 }
817 Extension::V0_1_0(ext) => {
818 ext.call_complete_slash_command_argument(store, command, arguments)
819 .await
820 }
821 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
822 Ok(Ok(Vec::new()))
823 }
824 }
825 }
826
827 pub async fn call_run_slash_command(
828 &self,
829 store: &mut Store<WasmState>,
830 command: &SlashCommand,
831 arguments: &[String],
832 resource: Option<Resource<Arc<dyn WorktreeDelegate>>>,
833 ) -> Result<Result<SlashCommandOutput, String>> {
834 match self {
835 Extension::V0_8_0(ext) => {
836 ext.call_run_slash_command(store, command, arguments, resource)
837 .await
838 }
839 Extension::V0_6_0(ext) => {
840 ext.call_run_slash_command(store, command, arguments, resource)
841 .await
842 }
843 Extension::V0_5_0(ext) => {
844 ext.call_run_slash_command(store, command, arguments, resource)
845 .await
846 }
847 Extension::V0_4_0(ext) => {
848 ext.call_run_slash_command(store, command, arguments, resource)
849 .await
850 }
851 Extension::V0_3_0(ext) => {
852 ext.call_run_slash_command(store, command, arguments, resource)
853 .await
854 }
855 Extension::V0_2_0(ext) => {
856 ext.call_run_slash_command(store, command, arguments, resource)
857 .await
858 }
859 Extension::V0_1_0(ext) => {
860 ext.call_run_slash_command(store, command, arguments, resource)
861 .await
862 }
863 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
864 anyhow::bail!("`run_slash_command` not available prior to v0.1.0");
865 }
866 }
867 }
868
869 pub async fn call_context_server_command(
870 &self,
871 store: &mut Store<WasmState>,
872 context_server_id: Arc<str>,
873 project: Resource<ExtensionProject>,
874 ) -> Result<Result<Command, String>> {
875 match self {
876 Extension::V0_8_0(ext) => {
877 ext.call_context_server_command(store, &context_server_id, project)
878 .await
879 }
880 Extension::V0_6_0(ext) => {
881 ext.call_context_server_command(store, &context_server_id, project)
882 .await
883 }
884 Extension::V0_5_0(ext) => {
885 ext.call_context_server_command(store, &context_server_id, project)
886 .await
887 }
888 Extension::V0_4_0(ext) => {
889 ext.call_context_server_command(store, &context_server_id, project)
890 .await
891 }
892 Extension::V0_3_0(ext) => {
893 ext.call_context_server_command(store, &context_server_id, project)
894 .await
895 }
896 Extension::V0_2_0(ext) => Ok(ext
897 .call_context_server_command(store, &context_server_id, project)
898 .await?
899 .map(Into::into)),
900 Extension::V0_0_1(_)
901 | Extension::V0_0_4(_)
902 | Extension::V0_0_6(_)
903 | Extension::V0_1_0(_) => {
904 anyhow::bail!("`context_server_command` not available prior to v0.2.0");
905 }
906 }
907 }
908
909 pub async fn call_context_server_configuration(
910 &self,
911 store: &mut Store<WasmState>,
912 context_server_id: Arc<str>,
913 project: Resource<ExtensionProject>,
914 ) -> Result<Result<Option<ContextServerConfiguration>, String>> {
915 match self {
916 Extension::V0_8_0(ext) => {
917 ext.call_context_server_configuration(store, &context_server_id, project)
918 .await
919 }
920 Extension::V0_6_0(ext) => {
921 ext.call_context_server_configuration(store, &context_server_id, project)
922 .await
923 }
924 Extension::V0_5_0(ext) => {
925 ext.call_context_server_configuration(store, &context_server_id, project)
926 .await
927 }
928 Extension::V0_0_1(_)
929 | Extension::V0_0_4(_)
930 | Extension::V0_0_6(_)
931 | Extension::V0_1_0(_)
932 | Extension::V0_2_0(_)
933 | Extension::V0_3_0(_)
934 | Extension::V0_4_0(_) => {
935 anyhow::bail!("`context_server_configuration` not available prior to v0.5.0");
936 }
937 }
938 }
939
940 pub async fn call_suggest_docs_packages(
941 &self,
942 store: &mut Store<WasmState>,
943 provider: &str,
944 ) -> Result<Result<Vec<String>, String>> {
945 match self {
946 Extension::V0_8_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
947 Extension::V0_6_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
948 Extension::V0_5_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
949 Extension::V0_4_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
950 Extension::V0_3_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
951 Extension::V0_2_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
952 Extension::V0_1_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
953 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
954 anyhow::bail!("`suggest_docs_packages` not available prior to v0.1.0");
955 }
956 }
957 }
958
959 pub async fn call_index_docs(
960 &self,
961 store: &mut Store<WasmState>,
962 provider: &str,
963 package_name: &str,
964 kv_store: Resource<Arc<dyn KeyValueStoreDelegate>>,
965 ) -> Result<Result<(), String>> {
966 match self {
967 Extension::V0_8_0(ext) => {
968 ext.call_index_docs(store, provider, package_name, kv_store)
969 .await
970 }
971 Extension::V0_6_0(ext) => {
972 ext.call_index_docs(store, provider, package_name, kv_store)
973 .await
974 }
975 Extension::V0_5_0(ext) => {
976 ext.call_index_docs(store, provider, package_name, kv_store)
977 .await
978 }
979 Extension::V0_4_0(ext) => {
980 ext.call_index_docs(store, provider, package_name, kv_store)
981 .await
982 }
983 Extension::V0_3_0(ext) => {
984 ext.call_index_docs(store, provider, package_name, kv_store)
985 .await
986 }
987 Extension::V0_2_0(ext) => {
988 ext.call_index_docs(store, provider, package_name, kv_store)
989 .await
990 }
991 Extension::V0_1_0(ext) => {
992 ext.call_index_docs(store, provider, package_name, kv_store)
993 .await
994 }
995 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
996 anyhow::bail!("`index_docs` not available prior to v0.1.0");
997 }
998 }
999 }
1000
1001 pub async fn call_get_dap_binary(
1002 &self,
1003 store: &mut Store<WasmState>,
1004 adapter_name: Arc<str>,
1005 task: DebugTaskDefinition,
1006 user_installed_path: Option<PathBuf>,
1007 resource: Resource<Arc<dyn WorktreeDelegate>>,
1008 ) -> Result<Result<DebugAdapterBinary, String>> {
1009 match self {
1010 Extension::V0_6_0(ext) => {
1011 let dap_binary = ext
1012 .call_get_dap_binary(
1013 store,
1014 &adapter_name,
1015 &task.try_into()?,
1016 user_installed_path.as_ref().and_then(|p| p.to_str()),
1017 resource,
1018 )
1019 .await?
1020 .map_err(|e| anyhow!("{e:?}"))?;
1021
1022 Ok(Ok(dap_binary))
1023 }
1024 _ => anyhow::bail!("`get_dap_binary` not available prior to v0.6.0"),
1025 }
1026 }
1027
1028 pub async fn call_dap_request_kind(
1029 &self,
1030 store: &mut Store<WasmState>,
1031 adapter_name: Arc<str>,
1032 config: serde_json::Value,
1033 ) -> Result<Result<StartDebuggingRequestArgumentsRequest, String>> {
1034 match self {
1035 Extension::V0_6_0(ext) => {
1036 let config =
1037 serde_json::to_string(&config).context("Adapter config is not a valid JSON")?;
1038 let dap_binary = ext
1039 .call_dap_request_kind(store, &adapter_name, &config)
1040 .await?
1041 .map_err(|e| anyhow!("{e:?}"))?;
1042
1043 Ok(Ok(dap_binary))
1044 }
1045 _ => anyhow::bail!("`dap_request_kind` not available prior to v0.6.0"),
1046 }
1047 }
1048
1049 pub async fn call_dap_config_to_scenario(
1050 &self,
1051 store: &mut Store<WasmState>,
1052 config: ZedDebugConfig,
1053 ) -> Result<Result<DebugScenario, String>> {
1054 match self {
1055 Extension::V0_6_0(ext) => {
1056 let config = config.into();
1057 let dap_binary = ext
1058 .call_dap_config_to_scenario(store, &config)
1059 .await?
1060 .map_err(|e| anyhow!("{e:?}"))?;
1061
1062 Ok(Ok(dap_binary.try_into()?))
1063 }
1064 _ => anyhow::bail!("`dap_config_to_scenario` not available prior to v0.6.0"),
1065 }
1066 }
1067
1068 pub async fn call_dap_locator_create_scenario(
1069 &self,
1070 store: &mut Store<WasmState>,
1071 locator_name: String,
1072 build_config_template: TaskTemplate,
1073 resolved_label: String,
1074 debug_adapter_name: String,
1075 ) -> Result<Option<DebugScenario>> {
1076 match self {
1077 Extension::V0_6_0(ext) => {
1078 let build_config_template = build_config_template.into();
1079 let dap_binary = ext
1080 .call_dap_locator_create_scenario(
1081 store,
1082 &locator_name,
1083 &build_config_template,
1084 &resolved_label,
1085 &debug_adapter_name,
1086 )
1087 .await?;
1088
1089 Ok(dap_binary.map(TryInto::try_into).transpose()?)
1090 }
1091 _ => anyhow::bail!("`dap_locator_create_scenario` not available prior to v0.6.0"),
1092 }
1093 }
1094
1095 pub async fn call_run_dap_locator(
1096 &self,
1097 store: &mut Store<WasmState>,
1098 locator_name: String,
1099 resolved_build_task: SpawnInTerminal,
1100 ) -> Result<Result<DebugRequest, String>> {
1101 match self {
1102 Extension::V0_6_0(ext) => {
1103 let build_config_template = resolved_build_task.try_into()?;
1104 let dap_request = ext
1105 .call_run_dap_locator(store, &locator_name, &build_config_template)
1106 .await?
1107 .map_err(|e| anyhow!("{e:?}"))?;
1108
1109 Ok(Ok(dap_request.into()))
1110 }
1111 _ => anyhow::bail!("`dap_locator_create_scenario` not available prior to v0.6.0"),
1112 }
1113 }
1114}
1115
1116trait ToWasmtimeResult<T> {
1117 fn to_wasmtime_result(self) -> wasmtime::Result<Result<T, String>>;
1118}
1119
1120impl<T> ToWasmtimeResult<T> for Result<T> {
1121 fn to_wasmtime_result(self) -> wasmtime::Result<Result<T, String>> {
1122 Ok(self.map_err(|error| format!("{error:?}")))
1123 }
1124}