cargo-lsp 0.0.12

LSP for Cargo.toml files
use std::{collections::HashMap, process::Command};

use serde::Deserialize;

#[derive(Clone, Debug, Default, Deserialize)]
pub struct Metadata {
    pub packages: Vec<Package>,
}

#[derive(Clone, Debug, Default, Deserialize)]
pub struct Package {
    pub name: String,
    pub features: HashMap<String, Vec<String>>,
}

pub fn get_metadata(path: &str) -> Metadata {
    let path = path.strip_prefix("file://").unwrap_or(path);
    let Ok(out) = Command::new("cargo")
        .args(["metadata", "--manifest-path", path])
        .output()
    else {
        return Metadata::default();
    };
    let Ok(out) = str::from_utf8(&out.stdout) else {
        return Metadata::default();
    };
    let Ok(metadata) = serde_json::from_str(out) else {
        return Metadata::default();
    };
    metadata
}

#[cfg(test)]
mod test {
    use crate::metadata::get_metadata;

    #[test]
    fn test() {
        let md = get_metadata("test_fixtures/features/Cargo.toml");
        assert!(!md.packages.is_empty());
        let dep = md
            .packages
            .iter()
            .find(|p| p.name == "serde")
            .expect("serde package not found in metadata");
        assert!(dep.features.contains_key("derive"));
    }

    #[test]
    fn test_by_url() {
        let md = get_metadata("file://test_fixtures/features/Cargo.toml");
        assert!(!md.packages.is_empty());
        let dep = md
            .packages
            .iter()
            .find(|p| p.name == "serde")
            .expect("serde package not found in metadata");
        assert!(dep.features.contains_key("derive"));
    }
}