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