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 if !allow_unreleased_version {
87 Err(anyhow!(
88 "unreleased versions of the extension API can only be used on development builds of Zed"
89 ))?;
90 }
91
92 Ok(())
93}
94
95pub enum Extension {
96 V0_6_0(since_v0_6_0::Extension),
97 V0_5_0(since_v0_5_0::Extension),
98 V0_4_0(since_v0_4_0::Extension),
99 V0_3_0(since_v0_3_0::Extension),
100 V0_2_0(since_v0_2_0::Extension),
101 V0_1_0(since_v0_1_0::Extension),
102 V0_0_6(since_v0_0_6::Extension),
103 V0_0_4(since_v0_0_4::Extension),
104 V0_0_1(since_v0_0_1::Extension),
105}
106
107impl Extension {
108 pub async fn instantiate_async(
109 store: &mut Store<WasmState>,
110 release_channel: ReleaseChannel,
111 version: SemanticVersion,
112 component: &Component,
113 ) -> Result<Self> {
114 // Note: The release channel can be used to stage a new version of the extension API.
115 let _ = release_channel;
116
117 if version >= latest::MIN_VERSION {
118 authorize_access_to_unreleased_wasm_api_version(release_channel)?;
119
120 let extension =
121 latest::Extension::instantiate_async(store, component, latest::linker())
122 .await
123 .context("failed to instantiate wasm extension")?;
124 Ok(Self::V0_6_0(extension))
125 } else if version >= since_v0_5_0::MIN_VERSION {
126 let extension = since_v0_5_0::Extension::instantiate_async(
127 store,
128 component,
129 since_v0_5_0::linker(),
130 )
131 .await
132 .context("failed to instantiate wasm extension")?;
133 Ok(Self::V0_5_0(extension))
134 } else if version >= since_v0_4_0::MIN_VERSION {
135 let extension = since_v0_4_0::Extension::instantiate_async(
136 store,
137 component,
138 since_v0_4_0::linker(),
139 )
140 .await
141 .context("failed to instantiate wasm extension")?;
142 Ok(Self::V0_4_0(extension))
143 } else if version >= since_v0_3_0::MIN_VERSION {
144 let extension = since_v0_3_0::Extension::instantiate_async(
145 store,
146 component,
147 since_v0_3_0::linker(),
148 )
149 .await
150 .context("failed to instantiate wasm extension")?;
151 Ok(Self::V0_3_0(extension))
152 } else if version >= since_v0_2_0::MIN_VERSION {
153 let extension = since_v0_2_0::Extension::instantiate_async(
154 store,
155 component,
156 since_v0_2_0::linker(),
157 )
158 .await
159 .context("failed to instantiate wasm extension")?;
160 Ok(Self::V0_2_0(extension))
161 } else if version >= since_v0_1_0::MIN_VERSION {
162 let extension = since_v0_1_0::Extension::instantiate_async(
163 store,
164 component,
165 since_v0_1_0::linker(),
166 )
167 .await
168 .context("failed to instantiate wasm extension")?;
169 Ok(Self::V0_1_0(extension))
170 } else if version >= since_v0_0_6::MIN_VERSION {
171 let extension = since_v0_0_6::Extension::instantiate_async(
172 store,
173 component,
174 since_v0_0_6::linker(),
175 )
176 .await
177 .context("failed to instantiate wasm extension")?;
178 Ok(Self::V0_0_6(extension))
179 } else if version >= since_v0_0_4::MIN_VERSION {
180 let extension = since_v0_0_4::Extension::instantiate_async(
181 store,
182 component,
183 since_v0_0_4::linker(),
184 )
185 .await
186 .context("failed to instantiate wasm extension")?;
187 Ok(Self::V0_0_4(extension))
188 } else {
189 let extension = since_v0_0_1::Extension::instantiate_async(
190 store,
191 component,
192 since_v0_0_1::linker(),
193 )
194 .await
195 .context("failed to instantiate wasm extension")?;
196 Ok(Self::V0_0_1(extension))
197 }
198 }
199
200 pub async fn call_init_extension(&self, store: &mut Store<WasmState>) -> Result<()> {
201 match self {
202 Extension::V0_6_0(ext) => ext.call_init_extension(store).await,
203 Extension::V0_5_0(ext) => ext.call_init_extension(store).await,
204 Extension::V0_4_0(ext) => ext.call_init_extension(store).await,
205 Extension::V0_3_0(ext) => ext.call_init_extension(store).await,
206 Extension::V0_2_0(ext) => ext.call_init_extension(store).await,
207 Extension::V0_1_0(ext) => ext.call_init_extension(store).await,
208 Extension::V0_0_6(ext) => ext.call_init_extension(store).await,
209 Extension::V0_0_4(ext) => ext.call_init_extension(store).await,
210 Extension::V0_0_1(ext) => ext.call_init_extension(store).await,
211 }
212 }
213
214 pub async fn call_language_server_command(
215 &self,
216 store: &mut Store<WasmState>,
217 language_server_id: &LanguageServerName,
218 language_name: &LanguageName,
219 resource: Resource<Arc<dyn WorktreeDelegate>>,
220 ) -> Result<Result<Command, String>> {
221 match self {
222 Extension::V0_6_0(ext) => {
223 ext.call_language_server_command(store, &language_server_id.0, resource)
224 .await
225 }
226 Extension::V0_5_0(ext) => {
227 ext.call_language_server_command(store, &language_server_id.0, resource)
228 .await
229 }
230 Extension::V0_4_0(ext) => {
231 ext.call_language_server_command(store, &language_server_id.0, resource)
232 .await
233 }
234 Extension::V0_3_0(ext) => {
235 ext.call_language_server_command(store, &language_server_id.0, resource)
236 .await
237 }
238 Extension::V0_2_0(ext) => Ok(ext
239 .call_language_server_command(store, &language_server_id.0, resource)
240 .await?
241 .map(|command| command.into())),
242 Extension::V0_1_0(ext) => Ok(ext
243 .call_language_server_command(store, &language_server_id.0, resource)
244 .await?
245 .map(|command| command.into())),
246 Extension::V0_0_6(ext) => Ok(ext
247 .call_language_server_command(store, &language_server_id.0, resource)
248 .await?
249 .map(|command| command.into())),
250 Extension::V0_0_4(ext) => Ok(ext
251 .call_language_server_command(
252 store,
253 &LanguageServerConfig {
254 name: language_server_id.0.to_string(),
255 language_name: language_name.to_string(),
256 },
257 resource,
258 )
259 .await?
260 .map(|command| command.into())),
261 Extension::V0_0_1(ext) => Ok(ext
262 .call_language_server_command(
263 store,
264 &LanguageServerConfig {
265 name: language_server_id.0.to_string(),
266 language_name: language_name.to_string(),
267 }
268 .into(),
269 resource,
270 )
271 .await?
272 .map(|command| command.into())),
273 }
274 }
275
276 pub async fn call_language_server_initialization_options(
277 &self,
278 store: &mut Store<WasmState>,
279 language_server_id: &LanguageServerName,
280 language_name: &LanguageName,
281 resource: Resource<Arc<dyn WorktreeDelegate>>,
282 ) -> Result<Result<Option<String>, String>> {
283 match self {
284 Extension::V0_6_0(ext) => {
285 ext.call_language_server_initialization_options(
286 store,
287 &language_server_id.0,
288 resource,
289 )
290 .await
291 }
292 Extension::V0_5_0(ext) => {
293 ext.call_language_server_initialization_options(
294 store,
295 &language_server_id.0,
296 resource,
297 )
298 .await
299 }
300 Extension::V0_4_0(ext) => {
301 ext.call_language_server_initialization_options(
302 store,
303 &language_server_id.0,
304 resource,
305 )
306 .await
307 }
308 Extension::V0_3_0(ext) => {
309 ext.call_language_server_initialization_options(
310 store,
311 &language_server_id.0,
312 resource,
313 )
314 .await
315 }
316 Extension::V0_2_0(ext) => {
317 ext.call_language_server_initialization_options(
318 store,
319 &language_server_id.0,
320 resource,
321 )
322 .await
323 }
324 Extension::V0_1_0(ext) => {
325 ext.call_language_server_initialization_options(
326 store,
327 &language_server_id.0,
328 resource,
329 )
330 .await
331 }
332 Extension::V0_0_6(ext) => {
333 ext.call_language_server_initialization_options(
334 store,
335 &language_server_id.0,
336 resource,
337 )
338 .await
339 }
340 Extension::V0_0_4(ext) => {
341 ext.call_language_server_initialization_options(
342 store,
343 &LanguageServerConfig {
344 name: language_server_id.0.to_string(),
345 language_name: language_name.to_string(),
346 },
347 resource,
348 )
349 .await
350 }
351 Extension::V0_0_1(ext) => {
352 ext.call_language_server_initialization_options(
353 store,
354 &LanguageServerConfig {
355 name: language_server_id.0.to_string(),
356 language_name: language_name.to_string(),
357 }
358 .into(),
359 resource,
360 )
361 .await
362 }
363 }
364 }
365
366 pub async fn call_language_server_workspace_configuration(
367 &self,
368 store: &mut Store<WasmState>,
369 language_server_id: &LanguageServerName,
370 resource: Resource<Arc<dyn WorktreeDelegate>>,
371 ) -> Result<Result<Option<String>, String>> {
372 match self {
373 Extension::V0_6_0(ext) => {
374 ext.call_language_server_workspace_configuration(
375 store,
376 &language_server_id.0,
377 resource,
378 )
379 .await
380 }
381 Extension::V0_5_0(ext) => {
382 ext.call_language_server_workspace_configuration(
383 store,
384 &language_server_id.0,
385 resource,
386 )
387 .await
388 }
389 Extension::V0_4_0(ext) => {
390 ext.call_language_server_workspace_configuration(
391 store,
392 &language_server_id.0,
393 resource,
394 )
395 .await
396 }
397 Extension::V0_3_0(ext) => {
398 ext.call_language_server_workspace_configuration(
399 store,
400 &language_server_id.0,
401 resource,
402 )
403 .await
404 }
405 Extension::V0_2_0(ext) => {
406 ext.call_language_server_workspace_configuration(
407 store,
408 &language_server_id.0,
409 resource,
410 )
411 .await
412 }
413 Extension::V0_1_0(ext) => {
414 ext.call_language_server_workspace_configuration(
415 store,
416 &language_server_id.0,
417 resource,
418 )
419 .await
420 }
421 Extension::V0_0_6(ext) => {
422 ext.call_language_server_workspace_configuration(
423 store,
424 &language_server_id.0,
425 resource,
426 )
427 .await
428 }
429 Extension::V0_0_4(_) | Extension::V0_0_1(_) => Ok(Ok(None)),
430 }
431 }
432
433 pub async fn call_language_server_additional_initialization_options(
434 &self,
435 store: &mut Store<WasmState>,
436 language_server_id: &LanguageServerName,
437 target_language_server_id: &LanguageServerName,
438 resource: Resource<Arc<dyn WorktreeDelegate>>,
439 ) -> Result<Result<Option<String>, String>> {
440 match self {
441 Extension::V0_6_0(ext) => {
442 ext.call_language_server_additional_initialization_options(
443 store,
444 &language_server_id.0,
445 &target_language_server_id.0,
446 resource,
447 )
448 .await
449 }
450 Extension::V0_5_0(ext) => {
451 ext.call_language_server_additional_initialization_options(
452 store,
453 &language_server_id.0,
454 &target_language_server_id.0,
455 resource,
456 )
457 .await
458 }
459 Extension::V0_4_0(ext) => {
460 ext.call_language_server_additional_initialization_options(
461 store,
462 &language_server_id.0,
463 &target_language_server_id.0,
464 resource,
465 )
466 .await
467 }
468 Extension::V0_3_0(_)
469 | Extension::V0_2_0(_)
470 | Extension::V0_1_0(_)
471 | Extension::V0_0_6(_)
472 | Extension::V0_0_4(_)
473 | Extension::V0_0_1(_) => Ok(Ok(None)),
474 }
475 }
476
477 pub async fn call_language_server_additional_workspace_configuration(
478 &self,
479 store: &mut Store<WasmState>,
480 language_server_id: &LanguageServerName,
481 target_language_server_id: &LanguageServerName,
482 resource: Resource<Arc<dyn WorktreeDelegate>>,
483 ) -> Result<Result<Option<String>, String>> {
484 match self {
485 Extension::V0_6_0(ext) => {
486 ext.call_language_server_additional_workspace_configuration(
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_workspace_configuration(
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_workspace_configuration(
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_labels_for_completions(
522 &self,
523 store: &mut Store<WasmState>,
524 language_server_id: &LanguageServerName,
525 completions: Vec<latest::Completion>,
526 ) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
527 match self {
528 Extension::V0_6_0(ext) => {
529 ext.call_labels_for_completions(store, &language_server_id.0, &completions)
530 .await
531 }
532 Extension::V0_5_0(ext) => Ok(ext
533 .call_labels_for_completions(
534 store,
535 &language_server_id.0,
536 &completions.into_iter().collect::<Vec<_>>(),
537 )
538 .await?
539 .map(|labels| {
540 labels
541 .into_iter()
542 .map(|label| label.map(Into::into))
543 .collect()
544 })),
545 Extension::V0_4_0(ext) => Ok(ext
546 .call_labels_for_completions(
547 store,
548 &language_server_id.0,
549 &completions.into_iter().collect::<Vec<_>>(),
550 )
551 .await?
552 .map(|labels| {
553 labels
554 .into_iter()
555 .map(|label| label.map(Into::into))
556 .collect()
557 })),
558 Extension::V0_3_0(ext) => Ok(ext
559 .call_labels_for_completions(
560 store,
561 &language_server_id.0,
562 &completions.into_iter().collect::<Vec<_>>(),
563 )
564 .await?
565 .map(|labels| {
566 labels
567 .into_iter()
568 .map(|label| label.map(Into::into))
569 .collect()
570 })),
571 Extension::V0_2_0(ext) => Ok(ext
572 .call_labels_for_completions(
573 store,
574 &language_server_id.0,
575 &completions.into_iter().collect::<Vec<_>>(),
576 )
577 .await?
578 .map(|labels| {
579 labels
580 .into_iter()
581 .map(|label| label.map(Into::into))
582 .collect()
583 })),
584 Extension::V0_1_0(ext) => Ok(ext
585 .call_labels_for_completions(
586 store,
587 &language_server_id.0,
588 &completions.into_iter().map(Into::into).collect::<Vec<_>>(),
589 )
590 .await?
591 .map(|labels| {
592 labels
593 .into_iter()
594 .map(|label| label.map(Into::into))
595 .collect()
596 })),
597 Extension::V0_0_6(ext) => Ok(ext
598 .call_labels_for_completions(
599 store,
600 &language_server_id.0,
601 &completions.into_iter().map(Into::into).collect::<Vec<_>>(),
602 )
603 .await?
604 .map(|labels| {
605 labels
606 .into_iter()
607 .map(|label| label.map(Into::into))
608 .collect()
609 })),
610 Extension::V0_0_1(_) | Extension::V0_0_4(_) => Ok(Ok(Vec::new())),
611 }
612 }
613
614 pub async fn call_labels_for_symbols(
615 &self,
616 store: &mut Store<WasmState>,
617 language_server_id: &LanguageServerName,
618 symbols: Vec<latest::Symbol>,
619 ) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
620 match self {
621 Extension::V0_6_0(ext) => {
622 ext.call_labels_for_symbols(store, &language_server_id.0, &symbols)
623 .await
624 }
625 Extension::V0_5_0(ext) => Ok(ext
626 .call_labels_for_symbols(
627 store,
628 &language_server_id.0,
629 &symbols.into_iter().collect::<Vec<_>>(),
630 )
631 .await?
632 .map(|labels| {
633 labels
634 .into_iter()
635 .map(|label| label.map(Into::into))
636 .collect()
637 })),
638 Extension::V0_4_0(ext) => Ok(ext
639 .call_labels_for_symbols(
640 store,
641 &language_server_id.0,
642 &symbols.into_iter().collect::<Vec<_>>(),
643 )
644 .await?
645 .map(|labels| {
646 labels
647 .into_iter()
648 .map(|label| label.map(Into::into))
649 .collect()
650 })),
651 Extension::V0_3_0(ext) => Ok(ext
652 .call_labels_for_symbols(
653 store,
654 &language_server_id.0,
655 &symbols.into_iter().collect::<Vec<_>>(),
656 )
657 .await?
658 .map(|labels| {
659 labels
660 .into_iter()
661 .map(|label| label.map(Into::into))
662 .collect()
663 })),
664 Extension::V0_2_0(ext) => Ok(ext
665 .call_labels_for_symbols(
666 store,
667 &language_server_id.0,
668 &symbols.into_iter().collect::<Vec<_>>(),
669 )
670 .await?
671 .map(|labels| {
672 labels
673 .into_iter()
674 .map(|label| label.map(Into::into))
675 .collect()
676 })),
677 Extension::V0_1_0(ext) => Ok(ext
678 .call_labels_for_symbols(
679 store,
680 &language_server_id.0,
681 &symbols.into_iter().map(Into::into).collect::<Vec<_>>(),
682 )
683 .await?
684 .map(|labels| {
685 labels
686 .into_iter()
687 .map(|label| label.map(Into::into))
688 .collect()
689 })),
690 Extension::V0_0_6(ext) => Ok(ext
691 .call_labels_for_symbols(
692 store,
693 &language_server_id.0,
694 &symbols.into_iter().map(Into::into).collect::<Vec<_>>(),
695 )
696 .await?
697 .map(|labels| {
698 labels
699 .into_iter()
700 .map(|label| label.map(Into::into))
701 .collect()
702 })),
703 Extension::V0_0_1(_) | Extension::V0_0_4(_) => Ok(Ok(Vec::new())),
704 }
705 }
706
707 pub async fn call_complete_slash_command_argument(
708 &self,
709 store: &mut Store<WasmState>,
710 command: &SlashCommand,
711 arguments: &[String],
712 ) -> Result<Result<Vec<SlashCommandArgumentCompletion>, String>> {
713 match self {
714 Extension::V0_6_0(ext) => {
715 ext.call_complete_slash_command_argument(store, command, arguments)
716 .await
717 }
718 Extension::V0_5_0(ext) => {
719 ext.call_complete_slash_command_argument(store, command, arguments)
720 .await
721 }
722 Extension::V0_4_0(ext) => {
723 ext.call_complete_slash_command_argument(store, command, arguments)
724 .await
725 }
726 Extension::V0_3_0(ext) => {
727 ext.call_complete_slash_command_argument(store, command, arguments)
728 .await
729 }
730 Extension::V0_2_0(ext) => {
731 ext.call_complete_slash_command_argument(store, command, arguments)
732 .await
733 }
734 Extension::V0_1_0(ext) => {
735 ext.call_complete_slash_command_argument(store, command, arguments)
736 .await
737 }
738 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
739 Ok(Ok(Vec::new()))
740 }
741 }
742 }
743
744 pub async fn call_run_slash_command(
745 &self,
746 store: &mut Store<WasmState>,
747 command: &SlashCommand,
748 arguments: &[String],
749 resource: Option<Resource<Arc<dyn WorktreeDelegate>>>,
750 ) -> Result<Result<SlashCommandOutput, String>> {
751 match self {
752 Extension::V0_6_0(ext) => {
753 ext.call_run_slash_command(store, command, arguments, resource)
754 .await
755 }
756 Extension::V0_5_0(ext) => {
757 ext.call_run_slash_command(store, command, arguments, resource)
758 .await
759 }
760 Extension::V0_4_0(ext) => {
761 ext.call_run_slash_command(store, command, arguments, resource)
762 .await
763 }
764 Extension::V0_3_0(ext) => {
765 ext.call_run_slash_command(store, command, arguments, resource)
766 .await
767 }
768 Extension::V0_2_0(ext) => {
769 ext.call_run_slash_command(store, command, arguments, resource)
770 .await
771 }
772 Extension::V0_1_0(ext) => {
773 ext.call_run_slash_command(store, command, arguments, resource)
774 .await
775 }
776 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
777 Err(anyhow!("`run_slash_command` not available prior to v0.1.0"))
778 }
779 }
780 }
781
782 pub async fn call_context_server_command(
783 &self,
784 store: &mut Store<WasmState>,
785 context_server_id: Arc<str>,
786 project: Resource<ExtensionProject>,
787 ) -> Result<Result<Command, String>> {
788 match self {
789 Extension::V0_6_0(ext) => {
790 ext.call_context_server_command(store, &context_server_id, project)
791 .await
792 }
793 Extension::V0_5_0(ext) => {
794 ext.call_context_server_command(store, &context_server_id, project)
795 .await
796 }
797 Extension::V0_4_0(ext) => {
798 ext.call_context_server_command(store, &context_server_id, project)
799 .await
800 }
801 Extension::V0_3_0(ext) => {
802 ext.call_context_server_command(store, &context_server_id, project)
803 .await
804 }
805 Extension::V0_2_0(ext) => Ok(ext
806 .call_context_server_command(store, &context_server_id, project)
807 .await?
808 .map(Into::into)),
809 Extension::V0_0_1(_)
810 | Extension::V0_0_4(_)
811 | Extension::V0_0_6(_)
812 | Extension::V0_1_0(_) => Err(anyhow!(
813 "`context_server_command` not available prior to v0.2.0"
814 )),
815 }
816 }
817
818 pub async fn call_context_server_configuration(
819 &self,
820 store: &mut Store<WasmState>,
821 context_server_id: Arc<str>,
822 project: Resource<ExtensionProject>,
823 ) -> Result<Result<Option<ContextServerConfiguration>, String>> {
824 match self {
825 Extension::V0_6_0(ext) => {
826 ext.call_context_server_configuration(store, &context_server_id, project)
827 .await
828 }
829 Extension::V0_5_0(ext) => {
830 ext.call_context_server_configuration(store, &context_server_id, project)
831 .await
832 }
833 Extension::V0_0_1(_)
834 | Extension::V0_0_4(_)
835 | Extension::V0_0_6(_)
836 | Extension::V0_1_0(_)
837 | Extension::V0_2_0(_)
838 | Extension::V0_3_0(_)
839 | Extension::V0_4_0(_) => Err(anyhow!(
840 "`context_server_configuration` not available prior to v0.5.0"
841 )),
842 }
843 }
844
845 pub async fn call_suggest_docs_packages(
846 &self,
847 store: &mut Store<WasmState>,
848 provider: &str,
849 ) -> Result<Result<Vec<String>, String>> {
850 match self {
851 Extension::V0_6_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
852 Extension::V0_5_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
853 Extension::V0_4_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
854 Extension::V0_3_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
855 Extension::V0_2_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
856 Extension::V0_1_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
857 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => Err(anyhow!(
858 "`suggest_docs_packages` not available prior to v0.1.0"
859 )),
860 }
861 }
862
863 pub async fn call_index_docs(
864 &self,
865 store: &mut Store<WasmState>,
866 provider: &str,
867 package_name: &str,
868 kv_store: Resource<Arc<dyn KeyValueStoreDelegate>>,
869 ) -> Result<Result<(), String>> {
870 match self {
871 Extension::V0_6_0(ext) => {
872 ext.call_index_docs(store, provider, package_name, kv_store)
873 .await
874 }
875 Extension::V0_5_0(ext) => {
876 ext.call_index_docs(store, provider, package_name, kv_store)
877 .await
878 }
879 Extension::V0_4_0(ext) => {
880 ext.call_index_docs(store, provider, package_name, kv_store)
881 .await
882 }
883 Extension::V0_3_0(ext) => {
884 ext.call_index_docs(store, provider, package_name, kv_store)
885 .await
886 }
887 Extension::V0_2_0(ext) => {
888 ext.call_index_docs(store, provider, package_name, kv_store)
889 .await
890 }
891 Extension::V0_1_0(ext) => {
892 ext.call_index_docs(store, provider, package_name, kv_store)
893 .await
894 }
895 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
896 Err(anyhow!("`index_docs` not available prior to v0.1.0"))
897 }
898 }
899 }
900 pub async fn call_get_dap_binary(
901 &self,
902 store: &mut Store<WasmState>,
903 adapter_name: Arc<str>,
904 task: DebugTaskDefinition,
905 user_installed_path: Option<PathBuf>,
906 resource: Resource<Arc<dyn WorktreeDelegate>>,
907 ) -> Result<Result<DebugAdapterBinary, String>> {
908 match self {
909 Extension::V0_6_0(ext) => {
910 let dap_binary = ext
911 .call_get_dap_binary(
912 store,
913 &adapter_name,
914 &task.try_into()?,
915 user_installed_path.as_ref().and_then(|p| p.to_str()),
916 resource,
917 )
918 .await?
919 .map_err(|e| anyhow!("{e:?}"))?;
920
921 Ok(Ok(dap_binary))
922 }
923 _ => Err(anyhow!("`get_dap_binary` not available prior to v0.6.0")),
924 }
925 }
926}
927
928trait ToWasmtimeResult<T> {
929 fn to_wasmtime_result(self) -> wasmtime::Result<Result<T, String>>;
930}
931
932impl<T> ToWasmtimeResult<T> for Result<T> {
933 fn to_wasmtime_result(self) -> wasmtime::Result<Result<T, String>> {
934 Ok(self.map_err(|error| format!("{error:?}")))
935 }
936}