cargo.rs

 1use super::DapLocator;
 2use anyhow::{Result, anyhow};
 3use async_trait::async_trait;
 4use dap::DebugAdapterConfig;
 5use serde_json::Value;
 6use smol::{
 7    io::AsyncReadExt,
 8    process::{Command, Stdio},
 9};
10
11pub(super) struct CargoLocator {}
12
13#[async_trait]
14impl DapLocator for CargoLocator {
15    async fn run_locator(&self, debug_config: &mut DebugAdapterConfig) -> Result<()> {
16        let Some(launch_config) = (match &mut debug_config.request {
17            task::DebugRequestDisposition::UserConfigured(task::DebugRequestType::Launch(
18                launch_config,
19            )) => Some(launch_config),
20            _ => None,
21        }) else {
22            return Err(anyhow!("Couldn't get launch config in locator"));
23        };
24
25        let Some(cwd) = launch_config.cwd.clone() else {
26            return Err(anyhow!(
27                "Couldn't get cwd from debug config which is needed for locators"
28            ));
29        };
30
31        let mut child = Command::new("cargo")
32            .args(&debug_config.args)
33            .arg("--message-format=json")
34            .current_dir(cwd)
35            .stdout(Stdio::piped())
36            .spawn()?;
37
38        let mut output = String::new();
39        if let Some(mut stdout) = child.stdout.take() {
40            stdout.read_to_string(&mut output).await?;
41        }
42
43        let status = child.status().await?;
44        if !status.success() {
45            return Err(anyhow::anyhow!("Cargo command failed"));
46        }
47
48        let Some(executable) = output
49            .lines()
50            .filter(|line| !line.trim().is_empty())
51            .filter_map(|line| serde_json::from_str(line).ok())
52            .find_map(|json: Value| {
53                json.get("executable")
54                    .and_then(Value::as_str)
55                    .map(String::from)
56            })
57        else {
58            return Err(anyhow!("Couldn't get executable in cargo locator"));
59        };
60
61        launch_config.program = executable;
62        debug_config.args.clear();
63        Ok(())
64    }
65}