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