cargo-lsp 0.0.5

LSP for Cargo.toml files
// These are all the prefixes that keys can have (non leaf)
// It's necessary because some of these don't have any known keys under, but
// still count for table completion (ex dependencies).
const TABLES: &[&str] = &[
    "package",
    "features",
    "dependencies",
    "dev-dependencies",
    "build-dependencies",
    "lints",
    "lints.clippy",
];

// These are the final keys including their full path (leaves)
const PROPS: &[&str] = &[
    "package.name",
    "package.version",
    "package.edition",
    "package.authors",
    "package.license",
    "package.description",
    "package.homepage",
    "package.repository",
    "package.documentation",
    "package.readme",
    "package.keywords",
    "package.categories",
    "lints.clippy.pedantic",
];

pub fn tables() -> Vec<String> {
    TABLES.iter().map(|s| format!("[{s}]")).collect()
}

pub fn props(prefix: &str) -> Vec<String> {
    if prefix.is_empty() {
        return PROPS.iter().map(std::string::ToString::to_string).collect();
    }
    if !TABLES.contains(&prefix) {
        return vec![];
    }
    PROPS
        .iter()
        .filter_map(|s| s.strip_prefix(prefix))
        .filter_map(|s| s.strip_prefix('.'))
        .map(std::string::ToString::to_string)
        .collect()
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_all() {
        let p = props("");
        assert_eq!(p, PROPS);
    }

    #[test]
    fn test_unknown() {
        let p = props("ba");
        assert!(p.is_empty());
    }

    #[test]
    fn test_package() {
        let p = props("package");
        assert_eq!(
            p,
            &[
                "name",
                "version",
                "edition",
                "authors",
                "license",
                "description",
                "homepage",
                "repository",
                "documentation",
                "readme",
                "keywords",
                "categories",
            ]
        );
    }
}