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}