1use zed_extension_api::{
2 self as zed, Architecture, DownloadedFileType, GithubReleaseOptions, Os, Result,
3 settings::LspSettings,
4};
5
6use crate::language_servers::util;
7
8pub(crate) struct ProtoLs {
9 cached_binary_path: Option<String>,
10}
11
12impl ProtoLs {
13 pub(crate) const SERVER_NAME: &str = "protols";
14
15 pub(crate) fn new() -> Self {
16 ProtoLs {
17 cached_binary_path: None,
18 }
19 }
20
21 pub(crate) fn language_server_binary(
22 &mut self,
23 worktree: &zed::Worktree,
24 ) -> Result<zed::Command> {
25 let binary_settings = LspSettings::for_worktree(Self::SERVER_NAME, worktree)
26 .ok()
27 .and_then(|lsp_settings| lsp_settings.binary);
28
29 let args = binary_settings
30 .as_ref()
31 .and_then(|binary_settings| binary_settings.arguments.clone())
32 .unwrap_or_default();
33
34 let env = worktree.shell_env();
35
36 if let Some(path) = binary_settings.and_then(|binary_settings| binary_settings.path) {
37 return Ok(zed::Command {
38 command: path,
39 args,
40 env,
41 });
42 } else if let Some(path) = self.cached_binary_path.clone() {
43 return Ok(zed::Command {
44 command: path,
45 args,
46 env,
47 });
48 } else if let Some(path) = worktree.which(Self::SERVER_NAME) {
49 self.cached_binary_path = Some(path.clone());
50 return Ok(zed::Command {
51 command: path,
52 args,
53 env,
54 });
55 }
56
57 let latest_release = zed::latest_github_release(
58 "coder3101/protols",
59 GithubReleaseOptions {
60 require_assets: true,
61 pre_release: false,
62 },
63 )?;
64
65 let (os, arch) = zed::current_platform();
66
67 let release_suffix = match (os, arch) {
68 (Os::Mac, Architecture::Aarch64) => "aarch64-apple-darwin.tar.gz",
69 (Os::Mac, Architecture::X8664) => "x86_64-apple-darwin.tar.gz",
70 (Os::Linux, Architecture::Aarch64) => "aarch64-unknown-linux-gnu.tar.gz",
71 (Os::Linux, Architecture::X8664) => "x86_64-unknown-linux-gnu.tar.gz",
72 (Os::Windows, Architecture::X8664) => "x86_64-pc-windows-msvc.zip",
73 _ => {
74 return Err("Platform and architecture not supported by Protols".to_string());
75 }
76 };
77
78 let release_name = format!("protols-{release_suffix}");
79
80 let file_type = if os == Os::Windows {
81 DownloadedFileType::Zip
82 } else {
83 DownloadedFileType::GzipTar
84 };
85
86 let version_dir = format!("{}-{}", Self::SERVER_NAME, latest_release.version);
87 let binary_path = format!("{version_dir}/protols");
88
89 let download_target = latest_release
90 .assets
91 .into_iter()
92 .find(|asset| asset.name == release_name)
93 .ok_or_else(|| {
94 format!(
95 "Could not find asset with name {} in Protols release",
96 &release_name
97 )
98 })?;
99
100 zed::download_file(&download_target.download_url, &version_dir, file_type)?;
101 zed::make_file_executable(&binary_path)?;
102
103 util::remove_outdated_versions(Self::SERVER_NAME, &version_dir)?;
104
105 self.cached_binary_path = Some(binary_path.clone());
106
107 Ok(zed::Command {
108 command: binary_path,
109 args,
110 env,
111 })
112 }
113}