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