use crate::{App, UserConfig, ZigVersion, tools};
use color_eyre::eyre::{bail, eyre};
use std::path::PathBuf;
use std::process::{Command, Stdio};
pub async fn zls_main() -> crate::Result<()> {
crate::check_recursion_with_context("zls proxy")?;
let mut args: Vec<String> = std::env::args().collect();
args.remove(0);
let zls_path = find_compatible_zls().await?;
let recursion_count: u32 = std::env::var("ZV_RECURSION_COUNT")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(0);
let mut child = Command::new(zls_path)
.args(args)
.env("ZV_RECURSION_COUNT", (recursion_count + 1).to_string())
.stdin(Stdio::inherit())
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()
.map_err(|e| eyre!("Failed to launch ZLS: {}", e))?;
let status = child
.wait()
.map_err(|e| eyre!("Failed to wait for ZLS: {}", e))?;
std::process::exit(status.code().unwrap_or(1));
}
async fn find_compatible_zls() -> crate::Result<PathBuf> {
let paths = tools::ZvPaths::resolve()?;
let mut app = App::init(UserConfig { paths, shell: None })
.await
.map_err(|e| eyre!("Failed to initialize app: {}", e))?;
let zig_version = get_current_zig_version(&app)?;
match app.fetch_compatible_zls(&zig_version) {
Ok(zls_path) => Ok(zls_path),
Err(e) => {
tracing::warn!("Failed to find compatible ZLS: {}", e);
Err(eyre!(
"No compatible ZLS found and no system ZLS available: {}",
e
))
}
}
}
fn get_current_zig_version(app: &App) -> crate::Result<ZigVersion> {
if let Some(zig_path) = app.zv_zig() {
match get_zig_version_from_executable(&zig_path) {
Ok(version) => return Ok(version),
Err(e) => {
tracing::warn!(
"Failed to get version from zig executable {}: {}",
zig_path.display(),
e
);
}
}
}
bail!("No Zig installation found");
}
fn get_zig_version_from_executable(zig_path: &PathBuf) -> crate::Result<ZigVersion> {
let output = Command::new(zig_path)
.arg("version")
.output()
.map_err(|e| eyre!("Failed to execute zig version: {}", e))?;
if !output.status.success() {
return Err(eyre!("zig version command failed"));
}
let version_str = String::from_utf8(output.stdout)
.map_err(|e| eyre!("Invalid UTF-8 in zig version output: {}", e))?
.trim()
.to_string();
version_str
.parse::<ZigVersion>()
.map_err(|e| eyre!("Failed to parse Zig version '{}': {}", version_str, e))
}