This PR updates the Zig extension to use v0.1.0 of the Zed extension API. This allows us to pin ZLS to v0.11.0, as the more recent releases of ZLS don't have `.tar.gz` assets available. Release Notes: - N/A
171 lines
5.5 KiB
Rust
171 lines
5.5 KiB
Rust
use std::fs;
|
|
use zed_extension_api::{self as zed, serde_json, settings::LspSettings, LanguageServerId, Result};
|
|
|
|
struct ZigExtension {
|
|
cached_binary_path: Option<String>,
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
struct ZlsBinary {
|
|
path: String,
|
|
args: Option<Vec<String>>,
|
|
environment: Option<Vec<(String, String)>>,
|
|
}
|
|
|
|
impl ZigExtension {
|
|
fn language_server_binary(
|
|
&mut self,
|
|
language_server_id: &LanguageServerId,
|
|
worktree: &zed::Worktree,
|
|
) -> Result<ZlsBinary> {
|
|
let mut args: Option<Vec<String>> = None;
|
|
|
|
let (platform, arch) = zed::current_platform();
|
|
let environment = match platform {
|
|
zed::Os::Mac | zed::Os::Linux => Some(worktree.shell_env()),
|
|
zed::Os::Windows => None,
|
|
};
|
|
|
|
if let Ok(lsp_settings) = LspSettings::for_worktree("zls", worktree) {
|
|
if let Some(binary) = lsp_settings.binary {
|
|
args = binary.arguments;
|
|
if let Some(path) = binary.path {
|
|
return Ok(ZlsBinary {
|
|
path: path.clone(),
|
|
args,
|
|
environment,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if let Some(path) = worktree.which("zls") {
|
|
return Ok(ZlsBinary {
|
|
path,
|
|
args,
|
|
environment,
|
|
});
|
|
}
|
|
|
|
if let Some(path) = &self.cached_binary_path {
|
|
if fs::metadata(&path).map_or(false, |stat| stat.is_file()) {
|
|
return Ok(ZlsBinary {
|
|
path: path.clone(),
|
|
args,
|
|
environment,
|
|
});
|
|
}
|
|
}
|
|
|
|
zed::set_language_server_installation_status(
|
|
&language_server_id,
|
|
&zed::LanguageServerInstallationStatus::CheckingForUpdate,
|
|
);
|
|
// We're pinning ZLS to a release that has `.tar.gz` assets, since the latest release does not have
|
|
// them, at time of writing.
|
|
//
|
|
// ZLS tracking issue: https://github.com/zigtools/zls/issues/1879
|
|
let release = zed::github_release_by_tag_name("zigtools/zls", "0.11.0")?;
|
|
|
|
let asset_name = format!(
|
|
"zls-{arch}-{os}.{extension}",
|
|
arch = match arch {
|
|
zed::Architecture::Aarch64 => "aarch64",
|
|
zed::Architecture::X86 => "x86",
|
|
zed::Architecture::X8664 => "x86_64",
|
|
},
|
|
os = match platform {
|
|
zed::Os::Mac => "macos",
|
|
zed::Os::Linux => "linux",
|
|
zed::Os::Windows => "windows",
|
|
},
|
|
extension = match platform {
|
|
zed::Os::Mac | zed::Os::Linux => "tar.gz",
|
|
zed::Os::Windows => "zip",
|
|
}
|
|
);
|
|
|
|
let asset = release
|
|
.assets
|
|
.iter()
|
|
.find(|asset| asset.name == asset_name)
|
|
.ok_or_else(|| format!("no asset found matching {:?}", asset_name))?;
|
|
|
|
let version_dir = format!("zls-{}", release.version);
|
|
let binary_path = match platform {
|
|
zed::Os::Mac | zed::Os::Linux => format!("{version_dir}/bin/zls"),
|
|
zed::Os::Windows => format!("{version_dir}/zls.exe"),
|
|
};
|
|
|
|
if !fs::metadata(&binary_path).map_or(false, |stat| stat.is_file()) {
|
|
zed::set_language_server_installation_status(
|
|
&language_server_id,
|
|
&zed::LanguageServerInstallationStatus::Downloading,
|
|
);
|
|
|
|
zed::download_file(
|
|
&asset.download_url,
|
|
&version_dir,
|
|
match platform {
|
|
zed::Os::Mac | zed::Os::Linux => zed::DownloadedFileType::GzipTar,
|
|
zed::Os::Windows => zed::DownloadedFileType::Zip,
|
|
},
|
|
)
|
|
.map_err(|e| format!("failed to download file: {e}"))?;
|
|
|
|
zed::make_file_executable(&binary_path)?;
|
|
|
|
let entries =
|
|
fs::read_dir(".").map_err(|e| format!("failed to list working directory {e}"))?;
|
|
for entry in entries {
|
|
let entry = entry.map_err(|e| format!("failed to load directory entry {e}"))?;
|
|
if entry.file_name().to_str() != Some(&version_dir) {
|
|
fs::remove_dir_all(&entry.path()).ok();
|
|
}
|
|
}
|
|
}
|
|
|
|
self.cached_binary_path = Some(binary_path.clone());
|
|
Ok(ZlsBinary {
|
|
path: binary_path,
|
|
args,
|
|
environment,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl zed::Extension for ZigExtension {
|
|
fn new() -> Self {
|
|
Self {
|
|
cached_binary_path: None,
|
|
}
|
|
}
|
|
|
|
fn language_server_command(
|
|
&mut self,
|
|
language_server_id: &LanguageServerId,
|
|
worktree: &zed::Worktree,
|
|
) -> Result<zed::Command> {
|
|
let zls_binary = self.language_server_binary(language_server_id, worktree)?;
|
|
Ok(zed::Command {
|
|
command: zls_binary.path,
|
|
args: zls_binary.args.unwrap_or_default(),
|
|
env: zls_binary.environment.unwrap_or_default(),
|
|
})
|
|
}
|
|
|
|
fn language_server_workspace_configuration(
|
|
&mut self,
|
|
_language_server_id: &zed::LanguageServerId,
|
|
worktree: &zed::Worktree,
|
|
) -> Result<Option<serde_json::Value>> {
|
|
let settings = LspSettings::for_worktree("zls", worktree)
|
|
.ok()
|
|
.and_then(|lsp_settings| lsp_settings.settings.clone())
|
|
.unwrap_or_default();
|
|
Ok(Some(settings))
|
|
}
|
|
}
|
|
|
|
zed::register_extension!(ZigExtension);
|