wit.rs

  1mod since_v0_0_1;
  2mod since_v0_0_4;
  3mod since_v0_0_6;
  4
  5use std::ops::RangeInclusive;
  6use std::sync::Arc;
  7
  8use anyhow::{Context, Result};
  9use language::{LanguageServerName, LspAdapterDelegate};
 10use semantic_version::SemanticVersion;
 11use wasmtime::{
 12    component::{Component, Instance, Linker, Resource},
 13    Store,
 14};
 15
 16use super::{wasm_engine, WasmState};
 17
 18use since_v0_0_6 as latest;
 19
 20pub use latest::{
 21    zed::extension::lsp::{Completion, CompletionKind, InsertTextFormat, Symbol, SymbolKind},
 22    CodeLabel, CodeLabelSpan, Command, Range,
 23};
 24pub use since_v0_0_4::LanguageServerConfig;
 25
 26pub fn new_linker(
 27    f: impl Fn(&mut Linker<WasmState>, fn(&mut WasmState) -> &mut WasmState) -> Result<()>,
 28) -> Linker<WasmState> {
 29    let mut linker = Linker::new(&wasm_engine());
 30    wasmtime_wasi::command::add_to_linker(&mut linker).unwrap();
 31    f(&mut linker, wasi_view).unwrap();
 32    linker
 33}
 34
 35fn wasi_view(state: &mut WasmState) -> &mut WasmState {
 36    state
 37}
 38
 39/// Returns whether the given Wasm API version is supported by the Wasm host.
 40pub fn is_supported_wasm_api_version(version: SemanticVersion) -> bool {
 41    wasm_api_version_range().contains(&version)
 42}
 43
 44/// Returns the Wasm API version range that is supported by the Wasm host.
 45#[inline(always)]
 46pub fn wasm_api_version_range() -> RangeInclusive<SemanticVersion> {
 47    since_v0_0_1::MIN_VERSION..=latest::MAX_VERSION
 48}
 49
 50pub enum Extension {
 51    V006(since_v0_0_6::Extension),
 52    V004(since_v0_0_4::Extension),
 53    V001(since_v0_0_1::Extension),
 54}
 55
 56impl Extension {
 57    pub async fn instantiate_async(
 58        store: &mut Store<WasmState>,
 59        version: SemanticVersion,
 60        component: &Component,
 61    ) -> Result<(Self, Instance)> {
 62        if version >= latest::MIN_VERSION {
 63            let (extension, instance) =
 64                latest::Extension::instantiate_async(store, &component, latest::linker())
 65                    .await
 66                    .context("failed to instantiate wasm extension")?;
 67            Ok((Self::V006(extension), instance))
 68        } else if version >= since_v0_0_4::MIN_VERSION {
 69            let (extension, instance) = since_v0_0_4::Extension::instantiate_async(
 70                store,
 71                &component,
 72                since_v0_0_4::linker(),
 73            )
 74            .await
 75            .context("failed to instantiate wasm extension")?;
 76            Ok((Self::V004(extension), instance))
 77        } else {
 78            let (extension, instance) = since_v0_0_1::Extension::instantiate_async(
 79                store,
 80                &component,
 81                since_v0_0_1::linker(),
 82            )
 83            .await
 84            .context("failed to instantiate wasm extension")?;
 85            Ok((Self::V001(extension), instance))
 86        }
 87    }
 88
 89    pub async fn call_init_extension(&self, store: &mut Store<WasmState>) -> Result<()> {
 90        match self {
 91            Extension::V006(ext) => ext.call_init_extension(store).await,
 92            Extension::V004(ext) => ext.call_init_extension(store).await,
 93            Extension::V001(ext) => ext.call_init_extension(store).await,
 94        }
 95    }
 96
 97    pub async fn call_language_server_command(
 98        &self,
 99        store: &mut Store<WasmState>,
100        language_server_id: &LanguageServerName,
101        config: &LanguageServerConfig,
102        resource: Resource<Arc<dyn LspAdapterDelegate>>,
103    ) -> Result<Result<Command, String>> {
104        match self {
105            Extension::V006(ext) => {
106                ext.call_language_server_command(store, &language_server_id.0, resource)
107                    .await
108            }
109            Extension::V004(ext) => Ok(ext
110                .call_language_server_command(store, config, resource)
111                .await?
112                .map(|command| command.into())),
113            Extension::V001(ext) => Ok(ext
114                .call_language_server_command(store, &config.clone().into(), resource)
115                .await?
116                .map(|command| command.into())),
117        }
118    }
119
120    pub async fn call_language_server_initialization_options(
121        &self,
122        store: &mut Store<WasmState>,
123        language_server_id: &LanguageServerName,
124        config: &LanguageServerConfig,
125        resource: Resource<Arc<dyn LspAdapterDelegate>>,
126    ) -> Result<Result<Option<String>, String>> {
127        match self {
128            Extension::V006(ext) => {
129                ext.call_language_server_initialization_options(
130                    store,
131                    &language_server_id.0,
132                    resource,
133                )
134                .await
135            }
136            Extension::V004(ext) => {
137                ext.call_language_server_initialization_options(store, config, resource)
138                    .await
139            }
140            Extension::V001(ext) => {
141                ext.call_language_server_initialization_options(
142                    store,
143                    &config.clone().into(),
144                    resource,
145                )
146                .await
147            }
148        }
149    }
150
151    pub async fn call_labels_for_completions(
152        &self,
153        store: &mut Store<WasmState>,
154        language_server_id: &LanguageServerName,
155        completions: Vec<latest::Completion>,
156    ) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
157        match self {
158            Extension::V001(_) | Extension::V004(_) => Ok(Ok(Vec::new())),
159            Extension::V006(ext) => {
160                ext.call_labels_for_completions(store, &language_server_id.0, &completions)
161                    .await
162            }
163        }
164    }
165
166    pub async fn call_labels_for_symbols(
167        &self,
168        store: &mut Store<WasmState>,
169        language_server_id: &LanguageServerName,
170        symbols: Vec<latest::Symbol>,
171    ) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
172        match self {
173            Extension::V001(_) | Extension::V004(_) => Ok(Ok(Vec::new())),
174            Extension::V006(ext) => {
175                ext.call_labels_for_symbols(store, &language_server_id.0, &symbols)
176                    .await
177            }
178        }
179    }
180}
181
182trait ToWasmtimeResult<T> {
183    fn to_wasmtime_result(self) -> wasmtime::Result<Result<T, String>>;
184}
185
186impl<T> ToWasmtimeResult<T> for Result<T> {
187    fn to_wasmtime_result(self) -> wasmtime::Result<Result<T, String>> {
188        Ok(self.map_err(|error| error.to_string()))
189    }
190}