html.rs

  1use std::{env, fs, path::PathBuf};
  2use zed_extension_api::{self as zed, Result};
  3
  4const PACKAGE_NAME: &str = "vscode-language-server";
  5
  6struct HtmlExtension {
  7    path: Option<PathBuf>,
  8}
  9
 10impl HtmlExtension {
 11    fn server_script_path(&self, language_server_id: &zed::LanguageServerId) -> Result<PathBuf> {
 12        if let Some(path) = self.path.as_ref() {
 13            if fs::metadata(path).map_or(false, |stat| stat.is_dir()) {
 14                return Ok(path.clone());
 15            }
 16        }
 17
 18        zed::set_language_server_installation_status(
 19            language_server_id,
 20            &zed::LanguageServerInstallationStatus::CheckingForUpdate,
 21        );
 22        let release = zed::latest_github_release(
 23            "zed-industries/vscode-langservers-extracted",
 24            zed::GithubReleaseOptions {
 25                require_assets: true,
 26                pre_release: false,
 27            },
 28        )?;
 29
 30        let asset_name = "vscode-language-server.tar.gz";
 31
 32        let asset = release
 33            .assets
 34            .iter()
 35            .find(|asset| asset.name == asset_name)
 36            .ok_or_else(|| format!("no asset found matching {:?}", asset_name))?;
 37        let version_dir = format!("{}-{}", PACKAGE_NAME, release.version);
 38        if !fs::metadata(&version_dir).map_or(false, |stat| stat.is_dir()) {
 39            zed::set_language_server_installation_status(
 40                &language_server_id,
 41                &zed::LanguageServerInstallationStatus::Downloading,
 42            );
 43
 44            zed::download_file(
 45                &asset.download_url,
 46                &version_dir,
 47                zed::DownloadedFileType::GzipTar,
 48            )
 49            .map_err(|e| format!("failed to download file: {e}"))?;
 50
 51            let entries =
 52                fs::read_dir(".").map_err(|e| format!("failed to list working directory {e}"))?;
 53            for entry in entries {
 54                let entry = entry.map_err(|e| format!("failed to load directory entry {e}"))?;
 55                if entry.file_name().to_str() != Some(&version_dir) {
 56                    fs::remove_dir_all(&entry.path()).ok();
 57                }
 58            }
 59        }
 60        Ok(PathBuf::from(version_dir)
 61            .join("bin")
 62            .join("vscode-html-language-server"))
 63    }
 64}
 65
 66impl zed::Extension for HtmlExtension {
 67    fn new() -> Self {
 68        Self { path: None }
 69    }
 70
 71    fn language_server_command(
 72        &mut self,
 73        language_server_id: &zed::LanguageServerId,
 74        _worktree: &zed::Worktree,
 75    ) -> Result<zed::Command> {
 76        let path = match &self.path {
 77            Some(path) => path,
 78            None => {
 79                let path = self.server_script_path(language_server_id)?;
 80                self.path = Some(path);
 81                self.path.as_ref().unwrap()
 82            }
 83        };
 84
 85        Ok(zed::Command {
 86            command: zed::node_binary_path()?,
 87            args: vec![
 88                env::current_dir()
 89                    .unwrap()
 90                    .join(path)
 91                    .to_string_lossy()
 92                    .to_string(),
 93                "--stdio".to_string(),
 94            ],
 95            env: Default::default(),
 96        })
 97    }
 98}
 99
100zed::register_extension!(HtmlExtension);