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