1use super::latest;
2use crate::wasm_host::WasmState;
3use anyhow::Result;
4use async_trait::async_trait;
5use language::{LanguageServerBinaryStatus, LspAdapterDelegate};
6use std::sync::{Arc, OnceLock};
7use wasmtime::component::{Linker, Resource};
8
9wasmtime::component::bindgen!({
10 async: true,
11 path: "../extension_api/wit/0.0.1",
12 with: {
13 "worktree": ExtensionWorktree,
14 },
15});
16
17pub type ExtensionWorktree = Arc<dyn LspAdapterDelegate>;
18
19pub fn linker() -> &'static Linker<WasmState> {
20 static LINKER: OnceLock<Linker<WasmState>> = OnceLock::new();
21 LINKER.get_or_init(|| super::new_linker(Extension::add_to_linker))
22}
23
24impl From<latest::Os> for Os {
25 fn from(value: latest::Os) -> Self {
26 match value {
27 latest::Os::Mac => Os::Mac,
28 latest::Os::Linux => Os::Linux,
29 latest::Os::Windows => Os::Windows,
30 }
31 }
32}
33
34impl From<latest::Architecture> for Architecture {
35 fn from(value: latest::Architecture) -> Self {
36 match value {
37 latest::Architecture::Aarch64 => Self::Aarch64,
38 latest::Architecture::X86 => Self::X86,
39 latest::Architecture::X8664 => Self::X8664,
40 }
41 }
42}
43
44impl From<latest::GithubRelease> for GithubRelease {
45 fn from(value: latest::GithubRelease) -> Self {
46 Self {
47 version: value.version,
48 assets: value.assets.into_iter().map(|asset| asset.into()).collect(),
49 }
50 }
51}
52
53impl From<latest::GithubReleaseAsset> for GithubReleaseAsset {
54 fn from(value: latest::GithubReleaseAsset) -> Self {
55 Self {
56 name: value.name,
57 download_url: value.download_url,
58 }
59 }
60}
61
62impl From<GithubReleaseOptions> for latest::GithubReleaseOptions {
63 fn from(value: GithubReleaseOptions) -> Self {
64 Self {
65 require_assets: value.require_assets,
66 pre_release: value.pre_release,
67 }
68 }
69}
70
71impl From<DownloadedFileType> for latest::DownloadedFileType {
72 fn from(value: DownloadedFileType) -> Self {
73 match value {
74 DownloadedFileType::Gzip => latest::DownloadedFileType::Gzip,
75 DownloadedFileType::GzipTar => latest::DownloadedFileType::GzipTar,
76 DownloadedFileType::Zip => latest::DownloadedFileType::Zip,
77 DownloadedFileType::Uncompressed => latest::DownloadedFileType::Uncompressed,
78 }
79 }
80}
81
82impl From<latest::LanguageServerConfig> for LanguageServerConfig {
83 fn from(value: latest::LanguageServerConfig) -> Self {
84 Self {
85 name: value.name,
86 language_name: value.language_name,
87 }
88 }
89}
90
91impl From<Command> for latest::Command {
92 fn from(value: Command) -> Self {
93 Self {
94 command: value.command,
95 args: value.args,
96 env: value.env,
97 }
98 }
99}
100
101#[async_trait]
102impl HostWorktree for WasmState {
103 async fn read_text_file(
104 &mut self,
105 delegate: Resource<Arc<dyn LspAdapterDelegate>>,
106 path: String,
107 ) -> wasmtime::Result<Result<String, String>> {
108 latest::HostWorktree::read_text_file(self, delegate, path).await
109 }
110
111 async fn shell_env(
112 &mut self,
113 delegate: Resource<Arc<dyn LspAdapterDelegate>>,
114 ) -> wasmtime::Result<EnvVars> {
115 latest::HostWorktree::shell_env(self, delegate).await
116 }
117
118 async fn which(
119 &mut self,
120 delegate: Resource<Arc<dyn LspAdapterDelegate>>,
121 binary_name: String,
122 ) -> wasmtime::Result<Option<String>> {
123 latest::HostWorktree::which(self, delegate, binary_name).await
124 }
125
126 fn drop(&mut self, _worktree: Resource<Worktree>) -> Result<()> {
127 Ok(())
128 }
129}
130
131#[async_trait]
132impl ExtensionImports for WasmState {
133 async fn node_binary_path(&mut self) -> wasmtime::Result<Result<String, String>> {
134 latest::ExtensionImports::node_binary_path(self).await
135 }
136
137 async fn npm_package_latest_version(
138 &mut self,
139 package_name: String,
140 ) -> wasmtime::Result<Result<String, String>> {
141 latest::ExtensionImports::npm_package_latest_version(self, package_name).await
142 }
143
144 async fn npm_package_installed_version(
145 &mut self,
146 package_name: String,
147 ) -> wasmtime::Result<Result<Option<String>, String>> {
148 latest::ExtensionImports::npm_package_installed_version(self, package_name).await
149 }
150
151 async fn npm_install_package(
152 &mut self,
153 package_name: String,
154 version: String,
155 ) -> wasmtime::Result<Result<(), String>> {
156 latest::ExtensionImports::npm_install_package(self, package_name, version).await
157 }
158
159 async fn latest_github_release(
160 &mut self,
161 repo: String,
162 options: GithubReleaseOptions,
163 ) -> wasmtime::Result<Result<GithubRelease, String>> {
164 Ok(
165 latest::ExtensionImports::latest_github_release(self, repo, options.into())
166 .await?
167 .map(|github| github.into()),
168 )
169 }
170
171 async fn current_platform(&mut self) -> Result<(Os, Architecture)> {
172 latest::ExtensionImports::current_platform(self)
173 .await
174 .map(|(os, arch)| (os.into(), arch.into()))
175 }
176
177 async fn set_language_server_installation_status(
178 &mut self,
179 server_name: String,
180 status: LanguageServerInstallationStatus,
181 ) -> wasmtime::Result<()> {
182 let status = match status {
183 LanguageServerInstallationStatus::CheckingForUpdate => {
184 LanguageServerBinaryStatus::CheckingForUpdate
185 }
186 LanguageServerInstallationStatus::Downloading => {
187 LanguageServerBinaryStatus::Downloading
188 }
189 LanguageServerInstallationStatus::Cached
190 | LanguageServerInstallationStatus::Downloaded => LanguageServerBinaryStatus::None,
191 LanguageServerInstallationStatus::Failed(error) => {
192 LanguageServerBinaryStatus::Failed { error }
193 }
194 };
195
196 self.host
197 .language_registry
198 .update_lsp_status(language::LanguageServerName(server_name.into()), status);
199 Ok(())
200 }
201
202 async fn download_file(
203 &mut self,
204 url: String,
205 path: String,
206 file_type: DownloadedFileType,
207 ) -> wasmtime::Result<Result<(), String>> {
208 latest::ExtensionImports::download_file(self, url, path, file_type.into()).await
209 }
210}