Files
oak-gpui/extensions/ruff/src/ruff.rs
T
Marshall Bowers a054a2a9a3 ruff: Refactor language server loading (#15852)
This PR refactors the language server loading in the Ruff extension to
mirror our other extensions.

Also fixed an issue where the cached binary path was not being
respected.

Release Notes:

- N/A
2024-08-06 09:10:18 -04:00

170 lines
5.5 KiB
Rust

use std::fs;
use zed::LanguageServerId;
use zed_extension_api::{self as zed, settings::LspSettings, Result};
struct RuffBinary {
path: String,
args: Option<Vec<String>>,
}
struct RuffExtension {
cached_binary_path: Option<String>,
}
impl RuffExtension {
fn language_server_binary(
&mut self,
language_server_id: &LanguageServerId,
worktree: &zed::Worktree,
) -> Result<RuffBinary> {
let binary_settings = LspSettings::for_worktree("ruff", worktree)
.ok()
.and_then(|lsp_settings| lsp_settings.binary);
let binary_args = binary_settings
.as_ref()
.and_then(|binary_settings| binary_settings.arguments.clone());
if let Some(path) = binary_settings.and_then(|binary_settings| binary_settings.path) {
return Ok(RuffBinary {
path,
args: binary_args,
});
}
if let Some(path) = worktree.which("ruff") {
return Ok(RuffBinary {
path,
args: binary_args,
});
}
if let Some(path) = &self.cached_binary_path {
if fs::metadata(&path).map_or(false, |stat| stat.is_file()) {
return Ok(RuffBinary {
path: path.clone(),
args: binary_args,
});
}
}
zed::set_language_server_installation_status(
&language_server_id,
&zed::LanguageServerInstallationStatus::CheckingForUpdate,
);
let release = zed::latest_github_release(
"astral-sh/ruff",
zed::GithubReleaseOptions {
require_assets: true,
pre_release: false,
},
)?;
let (platform, arch) = zed::current_platform();
let asset_stem = format!(
"ruff-{arch}-{os}",
arch = match arch {
zed::Architecture::Aarch64 => "aarch64",
zed::Architecture::X86 => "x86",
zed::Architecture::X8664 => "x86_64",
},
os = match platform {
zed::Os::Mac => "apple-darwin",
zed::Os::Linux => "unknown-linux-gnu",
zed::Os::Windows => "pc-windows-msvc",
}
);
let asset_name = format!(
"{asset_stem}.{suffix}",
suffix = match platform {
zed::Os::Windows => "zip",
_ => "tar.gz",
}
);
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!("ruff-{}", release.version);
let binary_path = format!("{version_dir}/{asset_stem}/ruff");
if !fs::metadata(&binary_path).map_or(false, |stat| stat.is_file()) {
zed::set_language_server_installation_status(
&language_server_id,
&zed::LanguageServerInstallationStatus::Downloading,
);
let file_kind = match platform {
zed::Os::Windows => zed::DownloadedFileType::Zip,
_ => zed::DownloadedFileType::GzipTar,
};
zed::download_file(&asset.download_url, &version_dir, file_kind)
.map_err(|e| format!("failed to download file: {e}"))?;
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(RuffBinary {
path: binary_path,
args: binary_args,
})
}
}
impl zed::Extension for RuffExtension {
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 ruff_binary = self.language_server_binary(language_server_id, worktree)?;
Ok(zed::Command {
command: ruff_binary.path,
args: ruff_binary.args.unwrap_or_else(|| vec!["server".into()]),
env: vec![],
})
}
fn language_server_initialization_options(
&mut self,
server_id: &LanguageServerId,
worktree: &zed_extension_api::Worktree,
) -> Result<Option<zed_extension_api::serde_json::Value>> {
let settings = LspSettings::for_worktree(server_id.as_ref(), worktree)
.ok()
.and_then(|lsp_settings| lsp_settings.initialization_options.clone())
.unwrap_or_default();
Ok(Some(settings))
}
fn language_server_workspace_configuration(
&mut self,
server_id: &LanguageServerId,
worktree: &zed_extension_api::Worktree,
) -> Result<Option<zed_extension_api::serde_json::Value>> {
let settings = LspSettings::for_worktree(server_id.as_ref(), worktree)
.ok()
.and_then(|lsp_settings| lsp_settings.settings.clone())
.unwrap_or_default();
Ok(Some(settings))
}
}
zed::register_extension!(RuffExtension);