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::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_additional_initialization_options(
 469        &self,
 470        store: &mut Store<WasmState>,
 471        language_server_id: &LanguageServerName,
 472        target_language_server_id: &LanguageServerName,
 473        resource: Resource<Arc<dyn WorktreeDelegate>>,
 474    ) -> Result<Result<Option<String>, String>> {
 475        match self {
 476            Extension::V0_8_0(ext) => {
 477                ext.call_language_server_additional_initialization_options(
 478                    store,
 479                    &language_server_id.0,
 480                    &target_language_server_id.0,
 481                    resource,
 482                )
 483                .await
 484            }
 485            Extension::V0_6_0(ext) => {
 486                ext.call_language_server_additional_initialization_options(
 487                    store,
 488                    &language_server_id.0,
 489                    &target_language_server_id.0,
 490                    resource,
 491                )
 492                .await
 493            }
 494            Extension::V0_5_0(ext) => {
 495                ext.call_language_server_additional_initialization_options(
 496                    store,
 497                    &language_server_id.0,
 498                    &target_language_server_id.0,
 499                    resource,
 500                )
 501                .await
 502            }
 503            Extension::V0_4_0(ext) => {
 504                ext.call_language_server_additional_initialization_options(
 505                    store,
 506                    &language_server_id.0,
 507                    &target_language_server_id.0,
 508                    resource,
 509                )
 510                .await
 511            }
 512            Extension::V0_3_0(_)
 513            | Extension::V0_2_0(_)
 514            | Extension::V0_1_0(_)
 515            | Extension::V0_0_6(_)
 516            | Extension::V0_0_4(_)
 517            | Extension::V0_0_1(_) => Ok(Ok(None)),
 518        }
 519    }
 520
 521    pub async fn call_language_server_additional_workspace_configuration(
 522        &self,
 523        store: &mut Store<WasmState>,
 524        language_server_id: &LanguageServerName,
 525        target_language_server_id: &LanguageServerName,
 526        resource: Resource<Arc<dyn WorktreeDelegate>>,
 527    ) -> Result<Result<Option<String>, String>> {
 528        match self {
 529            Extension::V0_8_0(ext) => {
 530                ext.call_language_server_additional_workspace_configuration(
 531                    store,
 532                    &language_server_id.0,
 533                    &target_language_server_id.0,
 534                    resource,
 535                )
 536                .await
 537            }
 538            Extension::V0_6_0(ext) => {
 539                ext.call_language_server_additional_workspace_configuration(
 540                    store,
 541                    &language_server_id.0,
 542                    &target_language_server_id.0,
 543                    resource,
 544                )
 545                .await
 546            }
 547            Extension::V0_5_0(ext) => {
 548                ext.call_language_server_additional_workspace_configuration(
 549                    store,
 550                    &language_server_id.0,
 551                    &target_language_server_id.0,
 552                    resource,
 553                )
 554                .await
 555            }
 556            Extension::V0_4_0(ext) => {
 557                ext.call_language_server_additional_workspace_configuration(
 558                    store,
 559                    &language_server_id.0,
 560                    &target_language_server_id.0,
 561                    resource,
 562                )
 563                .await
 564            }
 565            Extension::V0_3_0(_)
 566            | Extension::V0_2_0(_)
 567            | Extension::V0_1_0(_)
 568            | Extension::V0_0_6(_)
 569            | Extension::V0_0_4(_)
 570            | Extension::V0_0_1(_) => Ok(Ok(None)),
 571        }
 572    }
 573
 574    pub async fn call_labels_for_completions(
 575        &self,
 576        store: &mut Store<WasmState>,
 577        language_server_id: &LanguageServerName,
 578        completions: Vec<latest::Completion>,
 579    ) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
 580        match self {
 581            Extension::V0_8_0(ext) => {
 582                ext.call_labels_for_completions(store, &language_server_id.0, &completions)
 583                    .await
 584            }
 585            Extension::V0_6_0(ext) => Ok(ext
 586                .call_labels_for_completions(
 587                    store,
 588                    &language_server_id.0,
 589                    &completions.into_iter().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_5_0(ext) => Ok(ext
 599                .call_labels_for_completions(
 600                    store,
 601                    &language_server_id.0,
 602                    &completions.into_iter().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_4_0(ext) => Ok(ext
 612                .call_labels_for_completions(
 613                    store,
 614                    &language_server_id.0,
 615                    &completions.into_iter().collect::<Vec<_>>(),
 616                )
 617                .await?
 618                .map(|labels| {
 619                    labels
 620                        .into_iter()
 621                        .map(|label| label.map(Into::into))
 622                        .collect()
 623                })),
 624            Extension::V0_3_0(ext) => Ok(ext
 625                .call_labels_for_completions(
 626                    store,
 627                    &language_server_id.0,
 628                    &completions.into_iter().collect::<Vec<_>>(),
 629                )
 630                .await?
 631                .map(|labels| {
 632                    labels
 633                        .into_iter()
 634                        .map(|label| label.map(Into::into))
 635                        .collect()
 636                })),
 637            Extension::V0_2_0(ext) => Ok(ext
 638                .call_labels_for_completions(
 639                    store,
 640                    &language_server_id.0,
 641                    &completions.into_iter().collect::<Vec<_>>(),
 642                )
 643                .await?
 644                .map(|labels| {
 645                    labels
 646                        .into_iter()
 647                        .map(|label| label.map(Into::into))
 648                        .collect()
 649                })),
 650            Extension::V0_1_0(ext) => Ok(ext
 651                .call_labels_for_completions(
 652                    store,
 653                    &language_server_id.0,
 654                    &completions.into_iter().map(Into::into).collect::<Vec<_>>(),
 655                )
 656                .await?
 657                .map(|labels| {
 658                    labels
 659                        .into_iter()
 660                        .map(|label| label.map(Into::into))
 661                        .collect()
 662                })),
 663            Extension::V0_0_6(ext) => Ok(ext
 664                .call_labels_for_completions(
 665                    store,
 666                    &language_server_id.0,
 667                    &completions.into_iter().map(Into::into).collect::<Vec<_>>(),
 668                )
 669                .await?
 670                .map(|labels| {
 671                    labels
 672                        .into_iter()
 673                        .map(|label| label.map(Into::into))
 674                        .collect()
 675                })),
 676            Extension::V0_0_1(_) | Extension::V0_0_4(_) => Ok(Ok(Vec::new())),
 677        }
 678    }
 679
 680    pub async fn call_labels_for_symbols(
 681        &self,
 682        store: &mut Store<WasmState>,
 683        language_server_id: &LanguageServerName,
 684        symbols: Vec<latest::Symbol>,
 685    ) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
 686        match self {
 687            Extension::V0_8_0(ext) => {
 688                ext.call_labels_for_symbols(store, &language_server_id.0, &symbols)
 689                    .await
 690            }
 691            Extension::V0_6_0(ext) => Ok(ext
 692                .call_labels_for_symbols(
 693                    store,
 694                    &language_server_id.0,
 695                    &symbols.into_iter().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_5_0(ext) => Ok(ext
 705                .call_labels_for_symbols(
 706                    store,
 707                    &language_server_id.0,
 708                    &symbols.into_iter().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_4_0(ext) => Ok(ext
 718                .call_labels_for_symbols(
 719                    store,
 720                    &language_server_id.0,
 721                    &symbols.into_iter().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_3_0(ext) => Ok(ext
 731                .call_labels_for_symbols(
 732                    store,
 733                    &language_server_id.0,
 734                    &symbols.into_iter().collect::<Vec<_>>(),
 735                )
 736                .await?
 737                .map(|labels| {
 738                    labels
 739                        .into_iter()
 740                        .map(|label| label.map(Into::into))
 741                        .collect()
 742                })),
 743            Extension::V0_2_0(ext) => Ok(ext
 744                .call_labels_for_symbols(
 745                    store,
 746                    &language_server_id.0,
 747                    &symbols.into_iter().collect::<Vec<_>>(),
 748                )
 749                .await?
 750                .map(|labels| {
 751                    labels
 752                        .into_iter()
 753                        .map(|label| label.map(Into::into))
 754                        .collect()
 755                })),
 756            Extension::V0_1_0(ext) => Ok(ext
 757                .call_labels_for_symbols(
 758                    store,
 759                    &language_server_id.0,
 760                    &symbols.into_iter().map(Into::into).collect::<Vec<_>>(),
 761                )
 762                .await?
 763                .map(|labels| {
 764                    labels
 765                        .into_iter()
 766                        .map(|label| label.map(Into::into))
 767                        .collect()
 768                })),
 769            Extension::V0_0_6(ext) => Ok(ext
 770                .call_labels_for_symbols(
 771                    store,
 772                    &language_server_id.0,
 773                    &symbols.into_iter().map(Into::into).collect::<Vec<_>>(),
 774                )
 775                .await?
 776                .map(|labels| {
 777                    labels
 778                        .into_iter()
 779                        .map(|label| label.map(Into::into))
 780                        .collect()
 781                })),
 782            Extension::V0_0_1(_) | Extension::V0_0_4(_) => Ok(Ok(Vec::new())),
 783        }
 784    }
 785
 786    pub async fn call_complete_slash_command_argument(
 787        &self,
 788        store: &mut Store<WasmState>,
 789        command: &SlashCommand,
 790        arguments: &[String],
 791    ) -> Result<Result<Vec<SlashCommandArgumentCompletion>, String>> {
 792        match self {
 793            Extension::V0_8_0(ext) => {
 794                ext.call_complete_slash_command_argument(store, command, arguments)
 795                    .await
 796            }
 797            Extension::V0_6_0(ext) => {
 798                ext.call_complete_slash_command_argument(store, command, arguments)
 799                    .await
 800            }
 801            Extension::V0_5_0(ext) => {
 802                ext.call_complete_slash_command_argument(store, command, arguments)
 803                    .await
 804            }
 805            Extension::V0_4_0(ext) => {
 806                ext.call_complete_slash_command_argument(store, command, arguments)
 807                    .await
 808            }
 809            Extension::V0_3_0(ext) => {
 810                ext.call_complete_slash_command_argument(store, command, arguments)
 811                    .await
 812            }
 813            Extension::V0_2_0(ext) => {
 814                ext.call_complete_slash_command_argument(store, command, arguments)
 815                    .await
 816            }
 817            Extension::V0_1_0(ext) => {
 818                ext.call_complete_slash_command_argument(store, command, arguments)
 819                    .await
 820            }
 821            Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
 822                Ok(Ok(Vec::new()))
 823            }
 824        }
 825    }
 826
 827    pub async fn call_run_slash_command(
 828        &self,
 829        store: &mut Store<WasmState>,
 830        command: &SlashCommand,
 831        arguments: &[String],
 832        resource: Option<Resource<Arc<dyn WorktreeDelegate>>>,
 833    ) -> Result<Result<SlashCommandOutput, String>> {
 834        match self {
 835            Extension::V0_8_0(ext) => {
 836                ext.call_run_slash_command(store, command, arguments, resource)
 837                    .await
 838            }
 839            Extension::V0_6_0(ext) => {
 840                ext.call_run_slash_command(store, command, arguments, resource)
 841                    .await
 842            }
 843            Extension::V0_5_0(ext) => {
 844                ext.call_run_slash_command(store, command, arguments, resource)
 845                    .await
 846            }
 847            Extension::V0_4_0(ext) => {
 848                ext.call_run_slash_command(store, command, arguments, resource)
 849                    .await
 850            }
 851            Extension::V0_3_0(ext) => {
 852                ext.call_run_slash_command(store, command, arguments, resource)
 853                    .await
 854            }
 855            Extension::V0_2_0(ext) => {
 856                ext.call_run_slash_command(store, command, arguments, resource)
 857                    .await
 858            }
 859            Extension::V0_1_0(ext) => {
 860                ext.call_run_slash_command(store, command, arguments, resource)
 861                    .await
 862            }
 863            Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
 864                anyhow::bail!("`run_slash_command` not available prior to v0.1.0");
 865            }
 866        }
 867    }
 868
 869    pub async fn call_context_server_command(
 870        &self,
 871        store: &mut Store<WasmState>,
 872        context_server_id: Arc<str>,
 873        project: Resource<ExtensionProject>,
 874    ) -> Result<Result<Command, String>> {
 875        match self {
 876            Extension::V0_8_0(ext) => {
 877                ext.call_context_server_command(store, &context_server_id, project)
 878                    .await
 879            }
 880            Extension::V0_6_0(ext) => {
 881                ext.call_context_server_command(store, &context_server_id, project)
 882                    .await
 883            }
 884            Extension::V0_5_0(ext) => {
 885                ext.call_context_server_command(store, &context_server_id, project)
 886                    .await
 887            }
 888            Extension::V0_4_0(ext) => {
 889                ext.call_context_server_command(store, &context_server_id, project)
 890                    .await
 891            }
 892            Extension::V0_3_0(ext) => {
 893                ext.call_context_server_command(store, &context_server_id, project)
 894                    .await
 895            }
 896            Extension::V0_2_0(ext) => Ok(ext
 897                .call_context_server_command(store, &context_server_id, project)
 898                .await?
 899                .map(Into::into)),
 900            Extension::V0_0_1(_)
 901            | Extension::V0_0_4(_)
 902            | Extension::V0_0_6(_)
 903            | Extension::V0_1_0(_) => {
 904                anyhow::bail!("`context_server_command` not available prior to v0.2.0");
 905            }
 906        }
 907    }
 908
 909    pub async fn call_context_server_configuration(
 910        &self,
 911        store: &mut Store<WasmState>,
 912        context_server_id: Arc<str>,
 913        project: Resource<ExtensionProject>,
 914    ) -> Result<Result<Option<ContextServerConfiguration>, String>> {
 915        match self {
 916            Extension::V0_8_0(ext) => {
 917                ext.call_context_server_configuration(store, &context_server_id, project)
 918                    .await
 919            }
 920            Extension::V0_6_0(ext) => {
 921                ext.call_context_server_configuration(store, &context_server_id, project)
 922                    .await
 923            }
 924            Extension::V0_5_0(ext) => {
 925                ext.call_context_server_configuration(store, &context_server_id, project)
 926                    .await
 927            }
 928            Extension::V0_0_1(_)
 929            | Extension::V0_0_4(_)
 930            | Extension::V0_0_6(_)
 931            | Extension::V0_1_0(_)
 932            | Extension::V0_2_0(_)
 933            | Extension::V0_3_0(_)
 934            | Extension::V0_4_0(_) => {
 935                anyhow::bail!("`context_server_configuration` not available prior to v0.5.0");
 936            }
 937        }
 938    }
 939
 940    pub async fn call_suggest_docs_packages(
 941        &self,
 942        store: &mut Store<WasmState>,
 943        provider: &str,
 944    ) -> Result<Result<Vec<String>, String>> {
 945        match self {
 946            Extension::V0_8_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
 947            Extension::V0_6_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
 948            Extension::V0_5_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
 949            Extension::V0_4_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
 950            Extension::V0_3_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
 951            Extension::V0_2_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
 952            Extension::V0_1_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
 953            Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
 954                anyhow::bail!("`suggest_docs_packages` not available prior to v0.1.0");
 955            }
 956        }
 957    }
 958
 959    pub async fn call_index_docs(
 960        &self,
 961        store: &mut Store<WasmState>,
 962        provider: &str,
 963        package_name: &str,
 964        kv_store: Resource<Arc<dyn KeyValueStoreDelegate>>,
 965    ) -> Result<Result<(), String>> {
 966        match self {
 967            Extension::V0_8_0(ext) => {
 968                ext.call_index_docs(store, provider, package_name, kv_store)
 969                    .await
 970            }
 971            Extension::V0_6_0(ext) => {
 972                ext.call_index_docs(store, provider, package_name, kv_store)
 973                    .await
 974            }
 975            Extension::V0_5_0(ext) => {
 976                ext.call_index_docs(store, provider, package_name, kv_store)
 977                    .await
 978            }
 979            Extension::V0_4_0(ext) => {
 980                ext.call_index_docs(store, provider, package_name, kv_store)
 981                    .await
 982            }
 983            Extension::V0_3_0(ext) => {
 984                ext.call_index_docs(store, provider, package_name, kv_store)
 985                    .await
 986            }
 987            Extension::V0_2_0(ext) => {
 988                ext.call_index_docs(store, provider, package_name, kv_store)
 989                    .await
 990            }
 991            Extension::V0_1_0(ext) => {
 992                ext.call_index_docs(store, provider, package_name, kv_store)
 993                    .await
 994            }
 995            Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
 996                anyhow::bail!("`index_docs` not available prior to v0.1.0");
 997            }
 998        }
 999    }
1000
1001    pub async fn call_get_dap_binary(
1002        &self,
1003        store: &mut Store<WasmState>,
1004        adapter_name: Arc<str>,
1005        task: DebugTaskDefinition,
1006        user_installed_path: Option<PathBuf>,
1007        resource: Resource<Arc<dyn WorktreeDelegate>>,
1008    ) -> Result<Result<DebugAdapterBinary, String>> {
1009        match self {
1010            Extension::V0_6_0(ext) => {
1011                let dap_binary = ext
1012                    .call_get_dap_binary(
1013                        store,
1014                        &adapter_name,
1015                        &task.try_into()?,
1016                        user_installed_path.as_ref().and_then(|p| p.to_str()),
1017                        resource,
1018                    )
1019                    .await?
1020                    .map_err(|e| anyhow!("{e:?}"))?;
1021
1022                Ok(Ok(dap_binary))
1023            }
1024            _ => anyhow::bail!("`get_dap_binary` not available prior to v0.6.0"),
1025        }
1026    }
1027
1028    pub async fn call_dap_request_kind(
1029        &self,
1030        store: &mut Store<WasmState>,
1031        adapter_name: Arc<str>,
1032        config: serde_json::Value,
1033    ) -> Result<Result<StartDebuggingRequestArgumentsRequest, String>> {
1034        match self {
1035            Extension::V0_6_0(ext) => {
1036                let config =
1037                    serde_json::to_string(&config).context("Adapter config is not a valid JSON")?;
1038                let dap_binary = ext
1039                    .call_dap_request_kind(store, &adapter_name, &config)
1040                    .await?
1041                    .map_err(|e| anyhow!("{e:?}"))?;
1042
1043                Ok(Ok(dap_binary))
1044            }
1045            _ => anyhow::bail!("`dap_request_kind` not available prior to v0.6.0"),
1046        }
1047    }
1048
1049    pub async fn call_dap_config_to_scenario(
1050        &self,
1051        store: &mut Store<WasmState>,
1052        config: ZedDebugConfig,
1053    ) -> Result<Result<DebugScenario, String>> {
1054        match self {
1055            Extension::V0_6_0(ext) => {
1056                let config = config.into();
1057                let dap_binary = ext
1058                    .call_dap_config_to_scenario(store, &config)
1059                    .await?
1060                    .map_err(|e| anyhow!("{e:?}"))?;
1061
1062                Ok(Ok(dap_binary.try_into()?))
1063            }
1064            _ => anyhow::bail!("`dap_config_to_scenario` not available prior to v0.6.0"),
1065        }
1066    }
1067
1068    pub async fn call_dap_locator_create_scenario(
1069        &self,
1070        store: &mut Store<WasmState>,
1071        locator_name: String,
1072        build_config_template: TaskTemplate,
1073        resolved_label: String,
1074        debug_adapter_name: String,
1075    ) -> Result<Option<DebugScenario>> {
1076        match self {
1077            Extension::V0_6_0(ext) => {
1078                let build_config_template = build_config_template.into();
1079                let dap_binary = ext
1080                    .call_dap_locator_create_scenario(
1081                        store,
1082                        &locator_name,
1083                        &build_config_template,
1084                        &resolved_label,
1085                        &debug_adapter_name,
1086                    )
1087                    .await?;
1088
1089                Ok(dap_binary.map(TryInto::try_into).transpose()?)
1090            }
1091            _ => anyhow::bail!("`dap_locator_create_scenario` not available prior to v0.6.0"),
1092        }
1093    }
1094
1095    pub async fn call_run_dap_locator(
1096        &self,
1097        store: &mut Store<WasmState>,
1098        locator_name: String,
1099        resolved_build_task: SpawnInTerminal,
1100    ) -> Result<Result<DebugRequest, String>> {
1101        match self {
1102            Extension::V0_6_0(ext) => {
1103                let build_config_template = resolved_build_task.try_into()?;
1104                let dap_request = ext
1105                    .call_run_dap_locator(store, &locator_name, &build_config_template)
1106                    .await?
1107                    .map_err(|e| anyhow!("{e:?}"))?;
1108
1109                Ok(Ok(dap_request.into()))
1110            }
1111            _ => anyhow::bail!("`dap_locator_create_scenario` not available prior to v0.6.0"),
1112        }
1113    }
1114}
1115
1116trait ToWasmtimeResult<T> {
1117    fn to_wasmtime_result(self) -> wasmtime::Result<Result<T, String>>;
1118}
1119
1120impl<T> ToWasmtimeResult<T> for Result<T> {
1121    fn to_wasmtime_result(self) -> wasmtime::Result<Result<T, String>> {
1122        Ok(self.map_err(|error| format!("{error:?}")))
1123    }
1124}