wit.rs

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