1use crate::wasm_host::WasmState;
2use anyhow::Result;
3use extension::{KeyValueStoreDelegate, ProjectDelegate, WorktreeDelegate};
4use gpui::BackgroundExecutor;
5use semantic_version::SemanticVersion;
6use std::sync::{Arc, OnceLock};
7use wasmtime::component::{Linker, Resource};
8
9use super::latest;
10
11pub const MIN_VERSION: SemanticVersion = SemanticVersion::new(0, 2, 0);
12
13wasmtime::component::bindgen!({
14 async: true,
15 trappable_imports: true,
16 path: "../extension_api/wit/since_v0.2.0",
17 with: {
18 "worktree": ExtensionWorktree,
19 "project": ExtensionProject,
20 "key-value-store": ExtensionKeyValueStore,
21 "zed:extension/github": latest::zed::extension::github,
22 "zed:extension/http-client": latest::zed::extension::http_client,
23 "zed:extension/lsp": latest::zed::extension::lsp,
24 "zed:extension/nodejs": latest::zed::extension::nodejs,
25 "zed:extension/platform": latest::zed::extension::platform,
26 "zed:extension/slash-command": latest::zed::extension::slash_command,
27 },
28});
29
30pub use self::zed::extension::*;
31
32mod settings {
33 #![allow(dead_code)]
34 include!(concat!(env!("OUT_DIR"), "/since_v0.2.0/settings.rs"));
35}
36
37pub type ExtensionWorktree = Arc<dyn WorktreeDelegate>;
38pub type ExtensionProject = Arc<dyn ProjectDelegate>;
39pub type ExtensionKeyValueStore = Arc<dyn KeyValueStoreDelegate>;
40
41pub fn linker(executor: &BackgroundExecutor) -> &'static Linker<WasmState> {
42 static LINKER: OnceLock<Linker<WasmState>> = OnceLock::new();
43 LINKER.get_or_init(|| super::new_linker(executor, Extension::add_to_linker))
44}
45
46impl From<Command> for latest::Command {
47 fn from(value: Command) -> Self {
48 Self {
49 command: value.command,
50 args: value.args,
51 env: value.env,
52 }
53 }
54}
55
56impl From<SettingsLocation> for latest::SettingsLocation {
57 fn from(value: SettingsLocation) -> Self {
58 Self {
59 worktree_id: value.worktree_id,
60 path: value.path,
61 }
62 }
63}
64
65impl From<LanguageServerInstallationStatus> for latest::LanguageServerInstallationStatus {
66 fn from(value: LanguageServerInstallationStatus) -> Self {
67 match value {
68 LanguageServerInstallationStatus::None => Self::None,
69 LanguageServerInstallationStatus::Downloading => Self::Downloading,
70 LanguageServerInstallationStatus::CheckingForUpdate => Self::CheckingForUpdate,
71 LanguageServerInstallationStatus::Failed(message) => Self::Failed(message),
72 }
73 }
74}
75
76impl From<DownloadedFileType> for latest::DownloadedFileType {
77 fn from(value: DownloadedFileType) -> Self {
78 match value {
79 DownloadedFileType::Gzip => Self::Gzip,
80 DownloadedFileType::GzipTar => Self::GzipTar,
81 DownloadedFileType::Zip => Self::Zip,
82 DownloadedFileType::Uncompressed => Self::Uncompressed,
83 }
84 }
85}
86
87impl From<Range> for latest::Range {
88 fn from(value: Range) -> Self {
89 Self {
90 start: value.start,
91 end: value.end,
92 }
93 }
94}
95
96impl From<CodeLabelSpan> for latest::CodeLabelSpan {
97 fn from(value: CodeLabelSpan) -> Self {
98 match value {
99 CodeLabelSpan::CodeRange(range) => Self::CodeRange(range.into()),
100 CodeLabelSpan::Literal(literal) => Self::Literal(literal.into()),
101 }
102 }
103}
104
105impl From<CodeLabelSpanLiteral> for latest::CodeLabelSpanLiteral {
106 fn from(value: CodeLabelSpanLiteral) -> Self {
107 Self {
108 text: value.text,
109 highlight_name: value.highlight_name,
110 }
111 }
112}
113
114impl From<CodeLabel> for latest::CodeLabel {
115 fn from(value: CodeLabel) -> Self {
116 Self {
117 code: value.code,
118 spans: value.spans.into_iter().map(Into::into).collect(),
119 filter_range: value.filter_range.into(),
120 }
121 }
122}
123
124impl HostKeyValueStore for WasmState {
125 async fn insert(
126 &mut self,
127 kv_store: Resource<ExtensionKeyValueStore>,
128 key: String,
129 value: String,
130 ) -> wasmtime::Result<Result<(), String>> {
131 latest::HostKeyValueStore::insert(self, kv_store, key, value).await
132 }
133
134 async fn drop(&mut self, _worktree: Resource<ExtensionKeyValueStore>) -> Result<()> {
135 // We only ever hand out borrows of key-value stores.
136 Ok(())
137 }
138}
139
140impl HostProject for WasmState {
141 async fn worktree_ids(
142 &mut self,
143 project: Resource<ExtensionProject>,
144 ) -> wasmtime::Result<Vec<u64>> {
145 latest::HostProject::worktree_ids(self, project).await
146 }
147
148 async fn drop(&mut self, _project: Resource<Project>) -> Result<()> {
149 // We only ever hand out borrows of projects.
150 Ok(())
151 }
152}
153
154impl HostWorktree for WasmState {
155 async fn id(&mut self, delegate: Resource<Arc<dyn WorktreeDelegate>>) -> wasmtime::Result<u64> {
156 latest::HostWorktree::id(self, delegate).await
157 }
158
159 async fn root_path(
160 &mut self,
161 delegate: Resource<Arc<dyn WorktreeDelegate>>,
162 ) -> wasmtime::Result<String> {
163 latest::HostWorktree::root_path(self, delegate).await
164 }
165
166 async fn read_text_file(
167 &mut self,
168 delegate: Resource<Arc<dyn WorktreeDelegate>>,
169 path: String,
170 ) -> wasmtime::Result<Result<String, String>> {
171 latest::HostWorktree::read_text_file(self, delegate, path).await
172 }
173
174 async fn shell_env(
175 &mut self,
176 delegate: Resource<Arc<dyn WorktreeDelegate>>,
177 ) -> wasmtime::Result<EnvVars> {
178 latest::HostWorktree::shell_env(self, delegate).await
179 }
180
181 async fn which(
182 &mut self,
183 delegate: Resource<Arc<dyn WorktreeDelegate>>,
184 binary_name: String,
185 ) -> wasmtime::Result<Option<String>> {
186 latest::HostWorktree::which(self, delegate, binary_name).await
187 }
188
189 async fn drop(&mut self, _worktree: Resource<Worktree>) -> Result<()> {
190 // We only ever hand out borrows of worktrees.
191 Ok(())
192 }
193}
194
195impl common::Host for WasmState {}
196
197impl ExtensionImports for WasmState {
198 async fn get_settings(
199 &mut self,
200 location: Option<self::SettingsLocation>,
201 category: String,
202 key: Option<String>,
203 ) -> wasmtime::Result<Result<String, String>> {
204 latest::ExtensionImports::get_settings(
205 self,
206 location.map(|location| location.into()),
207 category,
208 key,
209 )
210 .await
211 }
212
213 async fn set_language_server_installation_status(
214 &mut self,
215 server_name: String,
216 status: LanguageServerInstallationStatus,
217 ) -> wasmtime::Result<()> {
218 latest::ExtensionImports::set_language_server_installation_status(
219 self,
220 server_name,
221 status.into(),
222 )
223 .await
224 }
225
226 async fn download_file(
227 &mut self,
228 url: String,
229 path: String,
230 file_type: DownloadedFileType,
231 ) -> wasmtime::Result<Result<(), String>> {
232 latest::ExtensionImports::download_file(self, url, path, file_type.into()).await
233 }
234
235 async fn make_file_executable(&mut self, path: String) -> wasmtime::Result<Result<(), String>> {
236 latest::ExtensionImports::make_file_executable(self, path).await
237 }
238}