|
1 | | -use zed_extension_api::settings::LspSettings; |
2 | | -use zed_extension_api::{self as zed, Command, LanguageServerId, Result, Worktree}; |
| 1 | +use std::fs; |
| 2 | +use std::path::PathBuf; |
| 3 | +use zed_extension_api::{self as zed, Result}; |
3 | 4 |
|
4 | | -struct SpellcheckExtension { |
5 | | - // ... stat |
| 5 | +const EXTENSION_LSP_NAME: &str = "codebook-lsp"; |
| 6 | + |
| 7 | +struct CodebookExtension { |
| 8 | + binary_cache: Option<PathBuf>, |
| 9 | +} |
| 10 | + |
| 11 | +#[derive(Clone)] |
| 12 | +struct CodebookBinary { |
| 13 | + path: PathBuf, |
| 14 | + env: Option<Vec<(String, String)>>, |
| 15 | +} |
| 16 | + |
| 17 | +impl CodebookExtension { |
| 18 | + fn new() -> Self { |
| 19 | + Self { binary_cache: None } |
| 20 | + } |
| 21 | + |
| 22 | + fn get_binary( |
| 23 | + &mut self, |
| 24 | + language_server_id: &zed::LanguageServerId, |
| 25 | + worktree: &zed::Worktree, |
| 26 | + ) -> Result<CodebookBinary> { |
| 27 | + let dev_path = PathBuf::from(EXTENSION_LSP_NAME); |
| 28 | + if dev_path.exists() { |
| 29 | + return Ok(CodebookBinary { |
| 30 | + path: dev_path, |
| 31 | + env: Some(vec![("RUST_LOG".to_string(), "debug".to_string())]), |
| 32 | + }); |
| 33 | + } |
| 34 | + |
| 35 | + if let Some(path) = worktree.which(EXTENSION_LSP_NAME) { |
| 36 | + return Ok(CodebookBinary { |
| 37 | + path: PathBuf::from(path), |
| 38 | + env: Some(worktree.shell_env()), |
| 39 | + }); |
| 40 | + } |
| 41 | + |
| 42 | + if let Some(path) = &self.binary_cache { |
| 43 | + if path.exists() { |
| 44 | + return Ok(CodebookBinary { |
| 45 | + path: path.clone(), |
| 46 | + env: None, |
| 47 | + }); |
| 48 | + } |
| 49 | + } |
| 50 | + |
| 51 | + self.install_binary(language_server_id) |
| 52 | + } |
| 53 | + |
| 54 | + fn install_binary( |
| 55 | + &mut self, |
| 56 | + language_server_id: &zed::LanguageServerId, |
| 57 | + ) -> Result<CodebookBinary> { |
| 58 | + zed::set_language_server_installation_status( |
| 59 | + language_server_id, |
| 60 | + &zed::LanguageServerInstallationStatus::CheckingForUpdate, |
| 61 | + ); |
| 62 | + |
| 63 | + let release = zed::latest_github_release( |
| 64 | + "blopker/codebook", |
| 65 | + zed::GithubReleaseOptions { |
| 66 | + require_assets: true, |
| 67 | + pre_release: false, |
| 68 | + }, |
| 69 | + ) |
| 70 | + .map_err(|e| format!("Failed to fetch latest release: {}", e))?; |
| 71 | + |
| 72 | + let (platform, arch) = zed::current_platform(); |
| 73 | + let arch_name = match arch { |
| 74 | + zed::Architecture::Aarch64 => "aarch64", |
| 75 | + zed::Architecture::X8664 => "x86_64", |
| 76 | + zed::Architecture::X86 => return Err("x86 architecture is not supported".into()), |
| 77 | + }; |
| 78 | + |
| 79 | + let (os_str, file_ext) = match platform { |
| 80 | + zed::Os::Mac => ("apple-darwin", "tar.gz"), |
| 81 | + zed::Os::Linux => ("unknown-linux-gnu", "tar.gz"), |
| 82 | + zed::Os::Windows => ("pc-windows-msvc", "zip"), |
| 83 | + }; |
| 84 | + |
| 85 | + let asset_name = format!("{EXTENSION_LSP_NAME}-{arch_name}-{os_str}.{file_ext}"); |
| 86 | + let asset = release |
| 87 | + .assets |
| 88 | + .iter() |
| 89 | + .find(|a| a.name == asset_name) |
| 90 | + .ok_or_else(|| { |
| 91 | + format!("No compatible Codebook binary found for {arch_name}-{os_str}") |
| 92 | + })?; |
| 93 | + |
| 94 | + let version_dir = format!("{EXTENSION_LSP_NAME}-{}", release.version); |
| 95 | + let mut binary_path = PathBuf::from(&version_dir).join(EXTENSION_LSP_NAME); |
| 96 | + |
| 97 | + if platform == zed::Os::Windows { |
| 98 | + binary_path.set_extension("exe"); |
| 99 | + } |
| 100 | + |
| 101 | + if !binary_path.exists() { |
| 102 | + zed::set_language_server_installation_status( |
| 103 | + language_server_id, |
| 104 | + &zed::LanguageServerInstallationStatus::Downloading, |
| 105 | + ); |
| 106 | + |
| 107 | + let download_result = (|| -> Result<()> { |
| 108 | + zed::download_file( |
| 109 | + &asset.download_url, |
| 110 | + &version_dir, |
| 111 | + if platform == zed::Os::Windows { |
| 112 | + zed::DownloadedFileType::Zip |
| 113 | + } else { |
| 114 | + zed::DownloadedFileType::GzipTar |
| 115 | + }, |
| 116 | + ) |
| 117 | + .map_err(|e| format!("Failed to download Codebook binary: {}", e))?; |
| 118 | + |
| 119 | + zed::make_file_executable(binary_path.to_str().ok_or("Invalid binary path")?) |
| 120 | + .map_err(|e| format!("Failed to make binary executable: {}", e))?; |
| 121 | + |
| 122 | + Ok(()) |
| 123 | + })(); |
| 124 | + |
| 125 | + if let Err(e) = download_result { |
| 126 | + fs::remove_dir_all(&version_dir).ok(); |
| 127 | + return Err(e); |
| 128 | + } |
| 129 | + |
| 130 | + if let Ok(entries) = fs::read_dir(".") { |
| 131 | + for entry in entries.flatten() { |
| 132 | + if let Ok(name) = entry.file_name().into_string() { |
| 133 | + if name != version_dir { |
| 134 | + fs::remove_dir_all(entry.path()).ok(); |
| 135 | + } |
| 136 | + } |
| 137 | + } |
| 138 | + } |
| 139 | + } |
| 140 | + |
| 141 | + self.binary_cache = Some(binary_path.clone()); |
| 142 | + Ok(CodebookBinary { |
| 143 | + path: binary_path, |
| 144 | + env: None, |
| 145 | + }) |
| 146 | + } |
6 | 147 | } |
7 | 148 |
|
8 | | -impl zed::Extension for SpellcheckExtension { |
| 149 | +impl zed::Extension for CodebookExtension { |
9 | 150 | fn new() -> Self { |
10 | | - Self {} |
| 151 | + Self::new() |
11 | 152 | } |
12 | 153 |
|
13 | 154 | fn language_server_command( |
14 | 155 | &mut self, |
15 | | - language_server_id: &LanguageServerId, |
16 | | - worktree: &Worktree, |
17 | | - ) -> Result<Command> { |
18 | | - let settings = LspSettings::for_worktree(language_server_id.as_ref(), worktree)?; |
19 | | - eprintln!("yooooooooooooooooooooooo"); |
20 | | - println!("yooooooooooooooooooooooo2"); |
21 | | - eprintln!("language_server_command: {:?}", settings); |
22 | | - Ok(Command { |
23 | | - command: "codebook-lsp".to_string(), |
| 156 | + language_server_id: &zed::LanguageServerId, |
| 157 | + worktree: &zed::Worktree, |
| 158 | + ) -> Result<zed::Command> { |
| 159 | + let binary = self.get_binary(language_server_id, worktree)?; |
| 160 | + Ok(zed::Command { |
| 161 | + command: binary |
| 162 | + .path |
| 163 | + .to_str() |
| 164 | + .ok_or("Failed to convert binary path to string")? |
| 165 | + .to_string(), |
24 | 166 | args: vec![], |
25 | | - env: vec![], |
| 167 | + env: binary.env.unwrap_or_default(), |
26 | 168 | }) |
27 | 169 | } |
28 | 170 | } |
29 | 171 |
|
30 | | -zed::register_extension!(SpellcheckExtension); |
| 172 | +zed::register_extension!(CodebookExtension); |
0 commit comments