wit.rs

  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}