1use crate::wasm_host::WasmState;
2use anyhow::Result;
3use extension::{KeyValueStoreDelegate, ProjectDelegate, WorktreeDelegate};
4use gpui::BackgroundExecutor;
5use semver::Version;
6use std::sync::{Arc, OnceLock};
7use wasmtime::component::{Linker, Resource};
8
9use super::latest;
10
11pub const MIN_VERSION: Version = Version::new(0, 6, 0);
12pub const MAX_VERSION: Version = Version::new(0, 7, 0);
13
14wasmtime::component::bindgen!({
15 imports: {
16 default: async | trappable,
17 },
18 exports: {
19 default: async,
20 },
21 path: "../extension_api/wit/since_v0.6.0",
22 with: {
23 "worktree": ExtensionWorktree,
24 "project": ExtensionProject,
25 "key-value-store": ExtensionKeyValueStore,
26 "zed:extension/common": latest::zed::extension::common,
27 "zed:extension/http-client": latest::zed::extension::http_client,
28 "zed:extension/nodejs": latest::zed::extension::nodejs,
29 "zed:extension/platform": latest::zed::extension::platform,
30 "zed:extension/process": latest::zed::extension::process,
31 "zed:extension/slash-command": latest::zed::extension::slash_command,
32 "zed:extension/context-server": latest::zed::extension::context_server,
33 "zed:extension/dap": latest::zed::extension::dap,
34 },
35});
36
37pub use self::zed::extension::*;
38
39mod settings {
40 #![allow(dead_code)]
41 include!(concat!(env!("OUT_DIR"), "/since_v0.6.0/settings.rs"));
42}
43
44pub type ExtensionWorktree = Arc<dyn WorktreeDelegate>;
45pub type ExtensionProject = Arc<dyn ProjectDelegate>;
46pub type ExtensionKeyValueStore = Arc<dyn KeyValueStoreDelegate>;
47
48pub fn linker(executor: &BackgroundExecutor) -> &'static Linker<WasmState> {
49 static LINKER: OnceLock<Linker<WasmState>> = OnceLock::new();
50 LINKER.get_or_init(|| {
51 super::new_linker(executor, |linker| {
52 Extension::add_to_linker::<_, WasmState>(linker, |s| s)
53 })
54 })
55}
56
57impl From<CodeLabel> for latest::CodeLabel {
58 fn from(value: CodeLabel) -> Self {
59 Self {
60 code: value.code,
61 spans: value.spans.into_iter().map(Into::into).collect(),
62 filter_range: value.filter_range,
63 }
64 }
65}
66
67impl From<CodeLabelSpan> for latest::CodeLabelSpan {
68 fn from(value: CodeLabelSpan) -> Self {
69 match value {
70 CodeLabelSpan::CodeRange(range) => Self::CodeRange(range),
71 CodeLabelSpan::Literal(literal) => Self::Literal(literal.into()),
72 }
73 }
74}
75
76impl From<CodeLabelSpanLiteral> for latest::CodeLabelSpanLiteral {
77 fn from(value: CodeLabelSpanLiteral) -> Self {
78 Self {
79 text: value.text,
80 highlight_name: value.highlight_name,
81 }
82 }
83}
84
85impl From<SettingsLocation> for latest::SettingsLocation {
86 fn from(value: SettingsLocation) -> Self {
87 Self {
88 worktree_id: value.worktree_id,
89 path: value.path,
90 }
91 }
92}
93
94impl From<LanguageServerInstallationStatus> for latest::LanguageServerInstallationStatus {
95 fn from(value: LanguageServerInstallationStatus) -> Self {
96 match value {
97 LanguageServerInstallationStatus::None => Self::None,
98 LanguageServerInstallationStatus::Downloading => Self::Downloading,
99 LanguageServerInstallationStatus::CheckingForUpdate => Self::CheckingForUpdate,
100 LanguageServerInstallationStatus::Failed(message) => Self::Failed(message),
101 }
102 }
103}
104
105impl From<DownloadedFileType> for latest::DownloadedFileType {
106 fn from(value: DownloadedFileType) -> Self {
107 match value {
108 DownloadedFileType::Gzip => Self::Gzip,
109 DownloadedFileType::GzipTar => Self::GzipTar,
110 DownloadedFileType::Zip => Self::Zip,
111 DownloadedFileType::Uncompressed => Self::Uncompressed,
112 }
113 }
114}
115
116impl From<latest::github::GithubReleaseAsset> for github::GithubReleaseAsset {
117 fn from(value: latest::github::GithubReleaseAsset) -> Self {
118 Self {
119 name: value.name,
120 download_url: value.download_url,
121 }
122 }
123}
124
125impl From<latest::github::GithubRelease> for github::GithubRelease {
126 fn from(value: latest::github::GithubRelease) -> Self {
127 Self {
128 version: value.version,
129 assets: value.assets.into_iter().map(Into::into).collect(),
130 }
131 }
132}
133
134impl From<github::GithubReleaseOptions> for latest::github::GithubReleaseOptions {
135 fn from(value: github::GithubReleaseOptions) -> Self {
136 Self {
137 require_assets: value.require_assets,
138 pre_release: value.pre_release,
139 }
140 }
141}
142
143impl zed::extension::github::Host for WasmState {
144 async fn github_release_by_tag_name(
145 &mut self,
146 repo: String,
147 tag: String,
148 ) -> wasmtime::Result<Result<github::GithubRelease, String>> {
149 latest::github::Host::github_release_by_tag_name(self, repo, tag)
150 .await
151 .map(|result| result.map(Into::into))
152 }
153
154 async fn latest_github_release(
155 &mut self,
156 repo: String,
157 options: github::GithubReleaseOptions,
158 ) -> wasmtime::Result<Result<github::GithubRelease, String>> {
159 latest::github::Host::latest_github_release(self, repo, options.into())
160 .await
161 .map(|result| result.map(Into::into))
162 }
163}
164
165impl From<latest::lsp::Completion> for lsp::Completion {
166 fn from(value: latest::lsp::Completion) -> Self {
167 Self {
168 label: value.label,
169 label_details: value.label_details.map(Into::into),
170 detail: value.detail,
171 kind: value.kind.map(Into::into),
172 insert_text_format: value.insert_text_format.map(Into::into),
173 }
174 }
175}
176
177impl From<latest::lsp::Symbol> for lsp::Symbol {
178 fn from(value: latest::lsp::Symbol) -> Self {
179 Self {
180 name: value.name,
181 kind: value.kind.into(),
182 }
183 }
184}
185
186impl From<latest::lsp::CompletionLabelDetails> for lsp::CompletionLabelDetails {
187 fn from(value: latest::lsp::CompletionLabelDetails) -> Self {
188 Self {
189 detail: value.detail,
190 description: value.description,
191 }
192 }
193}
194
195impl From<latest::lsp::CompletionKind> for lsp::CompletionKind {
196 fn from(value: latest::lsp::CompletionKind) -> Self {
197 match value {
198 latest::lsp::CompletionKind::Text => Self::Text,
199 latest::lsp::CompletionKind::Method => Self::Method,
200 latest::lsp::CompletionKind::Function => Self::Function,
201 latest::lsp::CompletionKind::Constructor => Self::Constructor,
202 latest::lsp::CompletionKind::Field => Self::Field,
203 latest::lsp::CompletionKind::Variable => Self::Variable,
204 latest::lsp::CompletionKind::Class => Self::Class,
205 latest::lsp::CompletionKind::Interface => Self::Interface,
206 latest::lsp::CompletionKind::Module => Self::Module,
207 latest::lsp::CompletionKind::Property => Self::Property,
208 latest::lsp::CompletionKind::Unit => Self::Unit,
209 latest::lsp::CompletionKind::Value => Self::Value,
210 latest::lsp::CompletionKind::Enum => Self::Enum,
211 latest::lsp::CompletionKind::Keyword => Self::Keyword,
212 latest::lsp::CompletionKind::Snippet => Self::Snippet,
213 latest::lsp::CompletionKind::Color => Self::Color,
214 latest::lsp::CompletionKind::File => Self::File,
215 latest::lsp::CompletionKind::Reference => Self::Reference,
216 latest::lsp::CompletionKind::Folder => Self::Folder,
217 latest::lsp::CompletionKind::EnumMember => Self::EnumMember,
218 latest::lsp::CompletionKind::Constant => Self::Constant,
219 latest::lsp::CompletionKind::Struct => Self::Struct,
220 latest::lsp::CompletionKind::Event => Self::Event,
221 latest::lsp::CompletionKind::Operator => Self::Operator,
222 latest::lsp::CompletionKind::TypeParameter => Self::TypeParameter,
223 latest::lsp::CompletionKind::Other(kind) => Self::Other(kind),
224 }
225 }
226}
227
228impl From<latest::lsp::InsertTextFormat> for lsp::InsertTextFormat {
229 fn from(value: latest::lsp::InsertTextFormat) -> Self {
230 match value {
231 latest::lsp::InsertTextFormat::PlainText => Self::PlainText,
232 latest::lsp::InsertTextFormat::Snippet => Self::Snippet,
233 latest::lsp::InsertTextFormat::Other(value) => Self::Other(value),
234 }
235 }
236}
237
238impl From<latest::lsp::SymbolKind> for lsp::SymbolKind {
239 fn from(value: latest::lsp::SymbolKind) -> Self {
240 match value {
241 latest::lsp::SymbolKind::File => Self::File,
242 latest::lsp::SymbolKind::Module => Self::Module,
243 latest::lsp::SymbolKind::Namespace => Self::Namespace,
244 latest::lsp::SymbolKind::Package => Self::Package,
245 latest::lsp::SymbolKind::Class => Self::Class,
246 latest::lsp::SymbolKind::Method => Self::Method,
247 latest::lsp::SymbolKind::Property => Self::Property,
248 latest::lsp::SymbolKind::Field => Self::Field,
249 latest::lsp::SymbolKind::Constructor => Self::Constructor,
250 latest::lsp::SymbolKind::Enum => Self::Enum,
251 latest::lsp::SymbolKind::Interface => Self::Interface,
252 latest::lsp::SymbolKind::Function => Self::Function,
253 latest::lsp::SymbolKind::Variable => Self::Variable,
254 latest::lsp::SymbolKind::Constant => Self::Constant,
255 latest::lsp::SymbolKind::String => Self::String,
256 latest::lsp::SymbolKind::Number => Self::Number,
257 latest::lsp::SymbolKind::Boolean => Self::Boolean,
258 latest::lsp::SymbolKind::Array => Self::Array,
259 latest::lsp::SymbolKind::Object => Self::Object,
260 latest::lsp::SymbolKind::Key => Self::Key,
261 latest::lsp::SymbolKind::Null => Self::Null,
262 latest::lsp::SymbolKind::EnumMember => Self::EnumMember,
263 latest::lsp::SymbolKind::Struct => Self::Struct,
264 latest::lsp::SymbolKind::Event => Self::Event,
265 latest::lsp::SymbolKind::Operator => Self::Operator,
266 latest::lsp::SymbolKind::TypeParameter => Self::TypeParameter,
267 latest::lsp::SymbolKind::Other(kind) => Self::Other(kind),
268 }
269 }
270}
271
272impl lsp::Host for WasmState {}
273
274impl HostKeyValueStore for WasmState {
275 async fn insert(
276 &mut self,
277 kv_store: Resource<ExtensionKeyValueStore>,
278 key: String,
279 value: String,
280 ) -> wasmtime::Result<Result<(), String>> {
281 latest::HostKeyValueStore::insert(self, kv_store, key, value).await
282 }
283
284 async fn drop(&mut self, _worktree: Resource<ExtensionKeyValueStore>) -> Result<()> {
285 // We only ever hand out borrows of key-value stores.
286 Ok(())
287 }
288}
289
290impl HostProject for WasmState {
291 async fn worktree_ids(
292 &mut self,
293 project: Resource<ExtensionProject>,
294 ) -> wasmtime::Result<Vec<u64>> {
295 latest::HostProject::worktree_ids(self, project).await
296 }
297
298 async fn drop(&mut self, _project: Resource<Project>) -> Result<()> {
299 // We only ever hand out borrows of projects.
300 Ok(())
301 }
302}
303
304impl HostWorktree for WasmState {
305 async fn id(&mut self, delegate: Resource<Arc<dyn WorktreeDelegate>>) -> wasmtime::Result<u64> {
306 latest::HostWorktree::id(self, delegate).await
307 }
308
309 async fn root_path(
310 &mut self,
311 delegate: Resource<Arc<dyn WorktreeDelegate>>,
312 ) -> wasmtime::Result<String> {
313 latest::HostWorktree::root_path(self, delegate).await
314 }
315
316 async fn read_text_file(
317 &mut self,
318 delegate: Resource<Arc<dyn WorktreeDelegate>>,
319 path: String,
320 ) -> wasmtime::Result<Result<String, String>> {
321 latest::HostWorktree::read_text_file(self, delegate, path).await
322 }
323
324 async fn shell_env(
325 &mut self,
326 delegate: Resource<Arc<dyn WorktreeDelegate>>,
327 ) -> wasmtime::Result<EnvVars> {
328 latest::HostWorktree::shell_env(self, delegate).await
329 }
330
331 async fn which(
332 &mut self,
333 delegate: Resource<Arc<dyn WorktreeDelegate>>,
334 binary_name: String,
335 ) -> wasmtime::Result<Option<String>> {
336 latest::HostWorktree::which(self, delegate, binary_name).await
337 }
338
339 async fn drop(&mut self, _worktree: Resource<Worktree>) -> Result<()> {
340 // We only ever hand out borrows of worktrees.
341 Ok(())
342 }
343}
344
345impl ExtensionImports for WasmState {
346 async fn get_settings(
347 &mut self,
348 location: Option<self::SettingsLocation>,
349 category: String,
350 key: Option<String>,
351 ) -> wasmtime::Result<Result<String, String>> {
352 latest::ExtensionImports::get_settings(
353 self,
354 location.map(|location| location.into()),
355 category,
356 key,
357 )
358 .await
359 }
360
361 async fn set_language_server_installation_status(
362 &mut self,
363 server_name: String,
364 status: LanguageServerInstallationStatus,
365 ) -> wasmtime::Result<()> {
366 latest::ExtensionImports::set_language_server_installation_status(
367 self,
368 server_name,
369 status.into(),
370 )
371 .await
372 }
373
374 async fn download_file(
375 &mut self,
376 url: String,
377 path: String,
378 file_type: DownloadedFileType,
379 ) -> wasmtime::Result<Result<(), String>> {
380 latest::ExtensionImports::download_file(self, url, path, file_type.into()).await
381 }
382
383 async fn make_file_executable(&mut self, path: String) -> wasmtime::Result<Result<(), String>> {
384 latest::ExtensionImports::make_file_executable(self, path).await
385 }
386}