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 if v.get("reason").and_then(|r| r.as_str()) == Some("compiler-message") {
22 if let Some(msg_obj) = v.get("message") {
23 let level = msg_obj
24 .get("level")
25 .and_then(|l| l.as_str())
26 .unwrap_or("info")
27 .to_string();
28 let message = msg_obj
29 .get("message")
30 .and_then(|m| m.as_str())
31 .unwrap_or("")
32 .to_string();
33
34 let mut file = None;
35 let mut line_num = None;
36 let mut col_num = None;
37
38 if let Some(spans) = msg_obj.get("spans").and_then(|s| s.as_array()) {
39 if let Some(primary) = spans.iter().find(|s| s.get("is_primary").and_then(|p| p.as_bool()) == Some(true)) {
40 file = primary.get("file_name").and_then(|f| f.as_str()).map(String::from);
41 line_num = primary.get("line_start").and_then(|l| l.as_u64()).map(|n| n as u32);
42 col_num = primary.get("column_start").and_then(|c| c.as_u64()).map(|n| n as u32);
43 }
44 }
45
46 diagnostics.push(CheckDiagnosticItem {
47 message,
48 level,
49 file,
50 line: line_num,
51 col: col_num,
52 });
53 }
54 }
55 }
56 }
57
58 Ok(CheckResponse {
59 success: output.status.success(),
60 diagnostics,
61 })
62}