use thiserror::Error;
use crate::manifest::{Manifest, ManifestError, ToolCategory, ToolSpec};
#[derive(Debug, Error)]
pub enum RegistryError {
#[error(transparent)]
Manifest(#[from] ManifestError),
}
pub struct Registry {
manifest: Manifest,
}
impl Registry {
pub fn new(manifest: Manifest) -> Self {
Self { manifest }
}
pub fn embedded() -> Result<Self, RegistryError> {
let s = include_str!("../anvil.toml");
let manifest = crate::manifest::parse_str(s)?;
Ok(Self::new(manifest))
}
pub fn names(&self) -> impl Iterator<Item = &str> {
self.manifest.tool.keys().map(|s| s.as_str())
}
pub fn get(&self, name: &str) -> Option<&ToolSpec> {
self.manifest.tool.get(name)
}
pub fn by_category(&self, c: ToolCategory) -> Vec<&str> {
self.manifest
.tool
.iter()
.filter(|(_, spec)| spec.category == c)
.map(|(name, _)| name.as_str())
.collect()
}
pub fn len(&self) -> usize {
self.manifest.tool.len()
}
pub fn is_empty(&self) -> bool {
self.manifest.tool.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn embedded() -> Registry {
Registry::embedded().expect("embedded anvil.toml must build a registry")
}
#[test]
fn embedded_succeeds() {
let r = embedded();
assert!(!r.is_empty());
}
#[test]
fn names_alphabetical() {
let r = embedded();
let names: Vec<_> = r.names().collect();
let mut sorted = names.clone();
sorted.sort_unstable();
assert_eq!(names, sorted, "names() must be alphabetical");
}
#[test]
fn get_known_tool() {
let r = embedded();
assert!(r.get("rust-analyzer").is_some());
}
#[test]
fn get_unknown_tool_is_none() {
let r = embedded();
assert!(r.get("definitely-not-a-tool").is_none());
}
#[test]
fn by_category_lsp_contains_expected() {
let r = embedded();
let lsp_tools = r.by_category(ToolCategory::Lsp);
assert!(lsp_tools.contains(&"rust-analyzer"), "{lsp_tools:?}");
assert!(lsp_tools.contains(&"gopls"), "{lsp_tools:?}");
assert!(lsp_tools.contains(&"lua-language-server"), "{lsp_tools:?}");
assert!(lsp_tools.contains(&"pyright"), "{lsp_tools:?}");
assert!(lsp_tools.contains(&"taplo"), "{lsp_tools:?}");
}
#[test]
fn by_category_formatter_contains_shfmt() {
let r = embedded();
let fmt_tools = r.by_category(ToolCategory::Formatter);
assert!(fmt_tools.contains(&"shfmt"), "{fmt_tools:?}");
}
#[test]
fn by_category_alphabetical() {
let r = embedded();
let lsp_tools = r.by_category(ToolCategory::Lsp);
let mut sorted = lsp_tools.clone();
sorted.sort_unstable();
assert_eq!(lsp_tools, sorted, "by_category() must be alphabetical");
}
#[test]
fn len_matches_tool_count() {
let r = embedded();
assert_eq!(r.len(), 6);
}
#[test]
fn registry_from_custom_manifest() {
let toml = r#"
[meta]
schema_version = 1
[tool.my-lsp]
category = "lsp"
description = "My custom LSP"
version = "1.0.0"
bin = "my-lsp"
method = "cargo"
crate_name = "my-lsp"
"#;
let manifest = crate::manifest::parse_str(toml).unwrap();
let r = Registry::new(manifest);
assert_eq!(r.len(), 1);
assert!(r.get("my-lsp").is_some());
assert!(r.get("other").is_none());
}
}