use super::*;
pub(crate) fn run_lsp() {
let rt = tokio::runtime::Runtime::new().expect("failed to create tokio runtime");
rt.block_on(async {
let stdin = tokio::io::stdin();
let stdout = tokio::io::stdout();
let (service, socket) = tower_lsp::LspService::new(assura_lsp::AssuraLanguageServer::new);
tower_lsp::Server::new(stdin, stdout, socket)
.serve(service)
.await;
});
}
pub(crate) fn run_doctor() {
let mut all_ok = true;
let version = env!("CARGO_PKG_VERSION");
println!("Assura Doctor");
println!(" assura: v{version}");
match process::Command::new("rustc").arg("--version").output() {
Ok(out) if out.status.success() => {
let ver = String::from_utf8_lossy(&out.stdout);
let ver = ver.trim().strip_prefix("rustc ").unwrap_or(ver.trim());
println!(" rustc: {ver} ... OK");
}
_ => {
println!(" rustc: not found ... MISSING");
println!(" Install: https://rustup.rs/");
all_ok = false;
}
}
match process::Command::new("cargo").arg("--version").output() {
Ok(out) if out.status.success() => {
let ver = String::from_utf8_lossy(&out.stdout);
let ver = ver.trim().strip_prefix("cargo ").unwrap_or(ver.trim());
println!(" cargo: {ver} ... OK");
}
_ => {
println!(" cargo: not found ... MISSING");
all_ok = false;
}
}
match process::Command::new("z3").arg("--version").output() {
Ok(out) if out.status.success() => {
let ver = String::from_utf8_lossy(&out.stdout);
let ver = ver.trim();
let short = ver
.strip_prefix("Z3 version ")
.and_then(|s| s.split_whitespace().next())
.unwrap_or(ver);
println!(" z3: {short} ... OK");
}
_ => {
println!(" z3: not found ... MISSING (required for verification)");
println!(" Install: brew install z3 (macOS)");
println!(" sudo apt-get install -y libz3-dev (Ubuntu)");
all_ok = false;
}
}
match process::Command::new("cvc5").arg("--version").output() {
Ok(out) if out.status.success() => {
let ver = String::from_utf8_lossy(&out.stdout);
let ver = ver.trim();
let short = ver.lines().next().unwrap_or(ver);
println!(" cvc5: {short} ... OK");
}
_ => {
println!(" cvc5: not found ... OPTIONAL (enables portfolio mode)");
println!(" Install: bash scripts/setup-cvc5.sh");
}
}
match process::Command::new("rustup")
.args(["target", "list", "--installed"])
.output()
{
Ok(out) if out.status.success() => {
let installed = String::from_utf8_lossy(&out.stdout);
if installed.contains("wasm32") {
println!(" wasm target: installed ... OK");
} else {
println!(" wasm target: not installed ... OPTIONAL");
println!(" Install: rustup target add wasm32-wasip1");
}
}
_ => {
println!(" wasm target: unknown (rustup not found) ... OPTIONAL");
}
}
println!();
if all_ok {
println!("All required dependencies are installed.");
} else {
println!(
"Some required dependencies are missing. Install them and re-run `assura doctor`."
);
process::exit(1);
}
}
#[cfg(test)]
mod tests {
#[test]
fn z3_version_prefix_strip() {
let ver = "Z3 version 4.13.0 - 64 bit";
let short = ver
.strip_prefix("Z3 version ")
.and_then(|s| s.split_whitespace().next())
.unwrap_or(ver);
assert_eq!(short, "4.13.0");
}
#[test]
fn z3_version_unexpected_format_falls_back() {
let ver = "z3 unknown format";
let short = ver
.strip_prefix("Z3 version ")
.and_then(|s| s.split_whitespace().next())
.unwrap_or(ver);
assert_eq!(short, "z3 unknown format");
}
#[test]
fn rustc_version_prefix_strip() {
let ver = "rustc 1.85.0 (4d91de4e4 2025-02-17)";
let short = ver.strip_prefix("rustc ").unwrap_or(ver);
assert_eq!(short, "1.85.0 (4d91de4e4 2025-02-17)");
}
#[test]
fn cargo_version_prefix_strip() {
let ver = "cargo 1.85.0 (d73d2caf9 2024-12-31)";
let short = ver.strip_prefix("cargo ").unwrap_or(ver);
assert_eq!(short, "1.85.0 (d73d2caf9 2024-12-31)");
}
}