erlang_language_platform.rs

  1use std::fs;
  2
  3use zed_extension_api::{self as zed, LanguageServerId, Result};
  4
  5pub struct ErlangLanguagePlatform {
  6    cached_binary_path: Option<String>,
  7}
  8
  9impl ErlangLanguagePlatform {
 10    pub const LANGUAGE_SERVER_ID: &'static str = "elp";
 11
 12    pub fn new() -> Self {
 13        Self {
 14            cached_binary_path: None,
 15        }
 16    }
 17
 18    pub fn language_server_command(
 19        &mut self,
 20        language_server_id: &LanguageServerId,
 21        worktree: &zed::Worktree,
 22    ) -> Result<zed::Command> {
 23        Ok(zed::Command {
 24            command: self.language_server_binary_path(language_server_id, worktree)?,
 25            args: vec!["server".to_string()],
 26            env: Default::default(),
 27        })
 28    }
 29
 30    fn language_server_binary_path(
 31        &mut self,
 32        language_server_id: &LanguageServerId,
 33        worktree: &zed::Worktree,
 34    ) -> Result<String> {
 35        if let Some(path) = worktree.which("elp") {
 36            return Ok(path);
 37        }
 38
 39        if let Some(path) = &self.cached_binary_path {
 40            if fs::metadata(path).map_or(false, |stat| stat.is_file()) {
 41                return Ok(path.clone());
 42            }
 43        }
 44
 45        zed::set_language_server_installation_status(
 46            language_server_id,
 47            &zed::LanguageServerInstallationStatus::CheckingForUpdate,
 48        );
 49        let release = zed::latest_github_release(
 50            "WhatsApp/erlang-language-platform",
 51            zed::GithubReleaseOptions {
 52                require_assets: true,
 53                pre_release: false,
 54            },
 55        )?;
 56
 57        let (platform, arch) = zed::current_platform();
 58        let asset_name = {
 59            let otp_version = "26.2";
 60            let (os, os_target) = match platform {
 61                zed::Os::Mac => ("macos", "apple-darwin"),
 62                zed::Os::Linux => ("linux", "unknown-linux-gnu"),
 63                zed::Os::Windows => return Err(format!("unsupported platform: {platform:?}")),
 64            };
 65
 66            format!(
 67                "elp-{os}-{arch}-{os_target}-otp-{otp_version}.tar.gz",
 68                arch = match arch {
 69                    zed::Architecture::Aarch64 => "aarch64",
 70                    zed::Architecture::X8664 => "x86_64",
 71                    zed::Architecture::X86 =>
 72                        return Err(format!("unsupported architecture: {arch:?}")),
 73                },
 74            )
 75        };
 76
 77        let asset = release
 78            .assets
 79            .iter()
 80            .find(|asset| asset.name == asset_name)
 81            .ok_or_else(|| format!("no asset found matching {:?}", asset_name))?;
 82
 83        let version_dir = format!("elp-{}", release.version);
 84        let binary_path = format!("{version_dir}/elp");
 85
 86        if !fs::metadata(&binary_path).map_or(false, |stat| stat.is_file()) {
 87            zed::set_language_server_installation_status(
 88                language_server_id,
 89                &zed::LanguageServerInstallationStatus::Downloading,
 90            );
 91
 92            zed::download_file(
 93                &asset.download_url,
 94                &version_dir,
 95                zed::DownloadedFileType::GzipTar,
 96            )
 97            .map_err(|e| format!("failed to download file: {e}"))?;
 98
 99            let entries =
100                fs::read_dir(".").map_err(|e| format!("failed to list working directory {e}"))?;
101            for entry in entries {
102                let entry = entry.map_err(|e| format!("failed to load directory entry {e}"))?;
103                if entry.file_name().to_str() != Some(&version_dir) {
104                    fs::remove_dir_all(entry.path()).ok();
105                }
106            }
107        }
108
109        self.cached_binary_path = Some(binary_path.clone());
110        Ok(binary_path)
111    }
112}