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