html.rs

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