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