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