rust_analyzer_cli/
cargo.rs1use 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}