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