Skip to main content

rust_analyzer_cli/
cargo.rs

1use crate::lsp::types::{CheckDiagnosticItem, CheckResponse};
2use anyhow::Result;
3use serde_json::Value;
4use std::path::Path;
5use tokio::process::Command;
6
7pub async fn run_cargo_check(workspace_root: &Path, target: Option<&str>) -> Result<CheckResponse> {
8    let mut cmd = Command::new("cargo");
9    cmd.arg("check").arg("--message-format=json");
10    if let Some(tgt) = target {
11        cmd.arg("--target").arg(tgt);
12    }
13    cmd.current_dir(workspace_root);
14
15    let output = cmd.output().await?;
16    let stdout_str = String::from_utf8_lossy(&output.stdout);
17
18    let mut diagnostics = Vec::new();
19    for line in stdout_str.lines() {
20        if let Ok(v) = serde_json::from_str::<Value>(line)
21            && v.get("reason").and_then(|r| r.as_str()) == Some("compiler-message")
22            && let Some(msg_obj) = v.get("message")
23        {
24            let level = msg_obj
25                .get("level")
26                .and_then(|l| l.as_str())
27                .unwrap_or("info")
28                .to_string();
29            let message = msg_obj
30                .get("message")
31                .and_then(|m| m.as_str())
32                .unwrap_or("")
33                .to_string();
34
35            let mut file = None;
36            let mut line_num = None;
37            let mut col_num = None;
38
39            if let Some(spans) = msg_obj.get("spans").and_then(|s| s.as_array())
40                && let Some(primary) = spans
41                    .iter()
42                    .find(|s| s.get("is_primary").and_then(|p| p.as_bool()) == Some(true))
43            {
44                file = primary
45                    .get("file_name")
46                    .and_then(|f| f.as_str())
47                    .map(String::from);
48                line_num = primary
49                    .get("line_start")
50                    .and_then(|l| l.as_u64())
51                    .map(|n| n as u32);
52                col_num = primary
53                    .get("column_start")
54                    .and_then(|c| c.as_u64())
55                    .map(|n| n as u32);
56            }
57
58            diagnostics.push(CheckDiagnosticItem {
59                message,
60                level,
61                file,
62                line: line_num,
63                col: col_num,
64            });
65        }
66    }
67
68    Ok(CheckResponse {
69        success: output.status.success(),
70        diagnostics,
71    })
72}