1use std::{env, fs};
2
3use zed_extension_api::{self as zed, LanguageServerId, Result};
4
5const SERVER_PATH: &str = "node_modules/intelephense/lib/intelephense.js";
6const PACKAGE_NAME: &str = "intelephense";
7
8pub struct Intelephense {
9 did_find_server: bool,
10}
11
12impl Intelephense {
13 pub const LANGUAGE_SERVER_ID: &'static str = "intelephense";
14
15 pub fn new() -> Self {
16 Self {
17 did_find_server: false,
18 }
19 }
20
21 pub fn language_server_command(
22 &mut self,
23 language_server_id: &LanguageServerId,
24 worktree: &zed::Worktree,
25 ) -> Result<zed::Command> {
26 if let Some(path) = worktree.which("intelephense") {
27 return Ok(zed::Command {
28 command: path,
29 args: vec!["--stdio".to_string()],
30 env: Default::default(),
31 });
32 }
33
34 let server_path = self.server_script_path(language_server_id)?;
35 Ok(zed::Command {
36 command: zed::node_binary_path()?,
37 args: vec![
38 env::current_dir()
39 .unwrap()
40 .join(&server_path)
41 .to_string_lossy()
42 .to_string(),
43 "--stdio".to_string(),
44 ],
45 env: Default::default(),
46 })
47 }
48
49 fn server_exists(&self) -> bool {
50 fs::metadata(SERVER_PATH).map_or(false, |stat| stat.is_file())
51 }
52
53 fn server_script_path(&mut self, language_server_id: &LanguageServerId) -> Result<String> {
54 let server_exists = self.server_exists();
55 if self.did_find_server && server_exists {
56 return Ok(SERVER_PATH.to_string());
57 }
58
59 zed::set_language_server_installation_status(
60 &language_server_id,
61 &zed::LanguageServerInstallationStatus::CheckingForUpdate,
62 );
63 let version = zed::npm_package_latest_version(PACKAGE_NAME)?;
64
65 if !server_exists
66 || zed::npm_package_installed_version(PACKAGE_NAME)?.as_ref() != Some(&version)
67 {
68 zed::set_language_server_installation_status(
69 &language_server_id,
70 &zed::LanguageServerInstallationStatus::Downloading,
71 );
72 let result = zed::npm_install_package(PACKAGE_NAME, &version);
73 match result {
74 Ok(()) => {
75 if !self.server_exists() {
76 Err(format!(
77 "installed package '{PACKAGE_NAME}' did not contain expected path '{SERVER_PATH}'",
78 ))?;
79 }
80 }
81 Err(error) => {
82 if !self.server_exists() {
83 Err(error)?;
84 }
85 }
86 }
87 }
88
89 self.did_find_server = true;
90 Ok(SERVER_PATH.to_string())
91 }
92}