227 lines
8.9 KiB
Rust
227 lines
8.9 KiB
Rust
//! Static language server definitions and core types.
|
|||
|
|
//!
|
||
|
|
//! Defines the set of supported LSP servers, their install tiers, and the
|
||
|
|
//! result/enum types used across the provisioner.
|
||
|
|
|
||
|
|
/// Optional progress callback type (non-owning, caller ensures liveness
|
||
|
|
/// for the duration of the provisioning call).
|
||
|
|
/// Intended to be hooked up to a UI toast / status-bar mechanism.
|
||
|
|
pub type ProgressFn<'a> = Option<&'a dyn Fn(&str)>;
|
||
|
|
|
||
|
|
/// Result of attempting to make a single language server available.
|
||
|
|
///
|
||
|
|
/// The caller should switch on this variant: `AlreadyAvailable` and
|
||
|
|
/// Installed both mean the binary can be launched; Failed means we
|
||
|
|
/// gave up and the user needs to install manually (see `manual_instructions`).
|
||
|
|
#[derive(Debug, Clone)]
|
||
|
|
pub enum ProvisionResult {
|
||
|
|
/// Binary was already on PATH — no install was needed.
|
||
|
|
AlreadyAvailable {
|
||
|
|
server_name: String,
|
||
|
|
language: String,
|
||
|
|
binary_path: String,
|
||
|
|
},
|
||
|
|
/// Provisioner successfully installed the binary during this run.
|
||
|
|
Installed {
|
||
|
|
server_name: String,
|
||
|
|
language: String,
|
||
|
|
binary_path: String,
|
||
|
|
},
|
||
|
|
/// Every install tier failed. Tells the user how to install by hand.
|
||
|
|
Failed {
|
||
|
|
language: String,
|
||
|
|
server_name: String,
|
||
|
|
reason: String,
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Sentinel command names used by `provision_single` to detect "download"
|
||
|
|
/// tiers (which are dispatched to `download_*` helpers rather than
|
||
|
|
/// `run_command`). Kept as constants so `supported_servers` stays readable.
|
||
|
|
pub(super) const DOWNLOAD_RUST_BIN: &str = "__download_rust_analyzer__";
|
||
|
|
pub(super) const DOWNLOAD_JDTLS: &str = "__download_jdtls__";
|
||
|
|
|
||
|
|
/// Static description of a single language server: how to detect it,
|
||
|
|
/// what file extensions it handles, and how to install it.
|
||
|
|
#[derive(Debug, Clone)]
|
||
|
|
pub struct LanguageServerDef {
|
||
|
|
/// Human-readable server name (e.g. "rust-analyzer").
|
||
|
|
pub name: String,
|
||
|
|
/// LSP language identifier (e.g. "rust").
|
||
|
|
pub language: String,
|
||
|
|
/// File extensions this server handles (with leading dot).
|
||
|
|
pub extensions: Vec<String>,
|
||
|
|
/// Candidate binary names — the provisioner accepts whichever appears on PATH.
|
||
|
|
pub binary_names: Vec<String>,
|
||
|
|
/// Install strategies, tried in order until one succeeds.
|
||
|
|
pub install_tiers: Vec<InstallTier>,
|
||
|
|
}
|
||
|
|
|
||
|
|
/// A single install attempt: a command (plus args) gated by a prerequisite.
|
||
|
|
///
|
||
|
|
/// `requires` lists binaries that must already be on PATH for this tier
|
||
|
|
/// to be considered. If any required binary is missing, the tier is
|
||
|
|
/// skipped (not attempted) so we don't produce misleading failures
|
||
|
|
/// like "rustup: command not found" when the real fix was to install
|
||
|
|
/// rustup first.
|
||
|
|
#[derive(Debug, Clone)]
|
||
|
|
pub struct InstallTier {
|
||
|
|
/// Short human-readable label, e.g. "rustup component".
|
||
|
|
pub label: String,
|
||
|
|
/// Binaries that must be available before this tier is attempted.
|
||
|
|
pub requires: Vec<String>,
|
||
|
|
/// Command to run.
|
||
|
|
pub command: String,
|
||
|
|
/// Arguments to pass to the command.
|
||
|
|
pub args: Vec<String>,
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Return the static set of supported language servers.
|
||
|
|
///
|
||
|
|
/// The order is significant: it determines provisioning order and
|
||
|
|
/// the order results appear in `provision_all_with_progress()`. Tier 1 paths are
|
||
|
|
/// the canonical/idiomatic install for each ecosystem; later tiers
|
||
|
|
/// are fallbacks for hosts that lack the primary tooling.
|
||
|
|
///
|
||
|
|
/// Why hard-coded rather than loaded from settings: the set is small,
|
||
|
|
/// changes rarely, and bundling it lets the provisioner run before any
|
||
|
|
/// user config has been read (e.g. on first launch).
|
||
|
|
pub fn supported_servers() -> Vec<LanguageServerDef> {
|
||
|
|
vec![
|
||
|
|
LanguageServerDef {
|
||
|
|
name: "rust-analyzer".to_string(),
|
||
|
|
language: "rust".to_string(),
|
||
|
|
extensions: vec![".rs".to_string()],
|
||
|
|
binary_names: vec!["rust-analyzer".to_string()],
|
||
|
|
install_tiers: vec![
|
||
|
|
InstallTier {
|
||
|
|
label: "rustup component".to_string(),
|
||
|
|
requires: vec!["rustup".to_string()],
|
||
|
|
command: "rustup".to_string(),
|
||
|
|
args: vec![
|
||
|
|
"component".to_string(),
|
||
|
|
"add".to_string(),
|
||
|
|
"rust-analyzer".to_string(),
|
||
|
|
],
|
||
|
|
},
|
||
|
|
InstallTier {
|
||
|
|
label: "pacman".to_string(),
|
||
|
|
requires: vec!["pacman".to_string()],
|
||
|
|
command: "pacman".to_string(),
|
||
|
|
args: vec![
|
||
|
|
"-S".to_string(),
|
||
|
|
"--noconfirm".to_string(),
|
||
|
|
"--needed".to_string(),
|
||
|
|
"rust-analyzer".to_string(),
|
||
|
|
],
|
||
|
|
},
|
||
|
|
InstallTier {
|
||
|
|
label: "brew".to_string(),
|
||
|
|
requires: vec!["brew".to_string()],
|
||
|
|
command: "brew".to_string(),
|
||
|
|
args: vec!["install".to_string(), "rust-analyzer".to_string()],
|
||
|
|
},
|
||
|
|
InstallTier {
|
||
|
|
label: "cargo install".to_string(),
|
||
|
|
requires: vec!["cargo".to_string()],
|
||
|
|
command: "cargo".to_string(),
|
||
|
|
args: vec![
|
||
|
|
"install".to_string(),
|
||
|
|
"--locked".to_string(),
|
||
|
|
"rust-analyzer".to_string(),
|
||
|
|
],
|
||
|
|
},
|
||
|
|
InstallTier {
|
||
|
|
label: "download prebuilt".to_string(),
|
||
|
|
requires: vec!["curl".to_string(), "tar".to_string()],
|
||
|
|
command: DOWNLOAD_RUST_BIN.to_string(),
|
||
|
|
args: vec![],
|
||
|
|
},
|
||
|
|
],
|
||
|
|
},
|
||
|
|
LanguageServerDef {
|
||
|
|
name: "typescript-language-server".to_string(),
|
||
|
|
language: "typescript".to_string(),
|
||
|
|
extensions: vec![
|
||
|
|
".ts".to_string(),
|
||
|
|
".tsx".to_string(),
|
||
|
|
".js".to_string(),
|
||
|
|
".jsx".to_string(),
|
||
|
|
],
|
||
|
|
binary_names: vec!["typescript-language-server".to_string()],
|
||
|
|
install_tiers: vec![InstallTier {
|
||
|
|
label: "npm global".to_string(),
|
||
|
|
requires: vec!["npm".to_string()],
|
||
|
|
command: "npm".to_string(),
|
||
|
|
args: vec![
|
||
|
|
"install".to_string(),
|
||
|
|
"-g".to_string(),
|
||
|
|
"typescript".to_string(),
|
||
|
|
"typescript-language-server".to_string(),
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
},
|
||
|
|
LanguageServerDef {
|
||
|
|
name: "gopls".to_string(),
|
||
|
|
language: "go".to_string(),
|
||
|
|
extensions: vec![".go".to_string()],
|
||
|
|
binary_names: vec!["gopls".to_string()],
|
||
|
|
install_tiers: vec![InstallTier {
|
||
|
|
label: "go install".to_string(),
|
||
|
|
requires: vec!["go".to_string()],
|
||
|
|
command: "go".to_string(),
|
||
|
|
args: vec![
|
||
|
|
"install".to_string(),
|
||
|
|
"golang.org/x/tools/gopls@latest".to_string(),
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
},
|
||
|
|
LanguageServerDef {
|
||
|
|
name: "jdtls".to_string(),
|
||
|
|
language: "java".to_string(),
|
||
|
|
extensions: vec![".java".to_string()],
|
||
|
|
binary_names: vec![
|
||
|
|
"jdtls".to_string(),
|
||
|
|
"eclipse-jdt-ls".to_string(),
|
||
|
|
"jdtls-launcher".to_string(),
|
||
|
|
],
|
||
|
|
install_tiers: vec![
|
||
|
|
InstallTier {
|
||
|
|
label: "pacman".to_string(),
|
||
|
|
requires: vec!["java".to_string(), "pacman".to_string()],
|
||
|
|
command: "pacman".to_string(),
|
||
|
|
args: vec![
|
||
|
|
"-S".to_string(),
|
||
|
|
"--noconfirm".to_string(),
|
||
|
|
"--needed".to_string(),
|
||
|
|
"eclipse-jdt-ls".to_string(),
|
||
|
|
],
|
||
|
|
},
|
||
|
|
InstallTier {
|
||
|
|
label: "apt".to_string(),
|
||
|
|
requires: vec!["java".to_string(), "apt".to_string()],
|
||
|
|
command: "sudo".to_string(),
|
||
|
|
args: vec![
|
||
|
|
"apt".to_string(),
|
||
|
|
"install".to_string(),
|
||
|
|
"-y".to_string(),
|
||
|
|
"eclipse-jdt-ls".to_string(),
|
||
|
|
],
|
||
|
|
},
|
||
|
|
InstallTier {
|
||
|
|
label: "brew".to_string(),
|
||
|
|
requires: vec!["java".to_string(), "brew".to_string()],
|
||
|
|
command: "brew".to_string(),
|
||
|
|
args: vec!["install".to_string(), "jdtls".to_string()],
|
||
|
|
},
|
||
|
|
InstallTier {
|
||
|
|
label: "download from eclipse".to_string(),
|
||
|
|
requires: vec!["java".to_string(), "curl".to_string(), "tar".to_string()],
|
||
|
|
command: DOWNLOAD_JDTLS.to_string(),
|
||
|
|
args: vec![],
|
||
|
|
},
|
||
|
|
],
|
||
|
|
},
|
||
|
|
]
|
||
|
|
}
|