Skip to main content

contract_cli/commands/
kinds.rs

1use crate::cli::KindsCmd;
2use crate::error::{AppError, Result};
3use crate::kinds;
4use crate::output::{print_success, Ctx};
5
6#[derive(serde::Serialize)]
7struct KindInfo {
8    kind: &'static str,
9    prefix: &'static str,
10    roles: (&'static str, &'static str),
11    description: &'static str,
12    tags: &'static [&'static str],
13}
14
15fn info(k: &'static kinds::KindSpec) -> KindInfo {
16    KindInfo {
17        kind: k.kind,
18        prefix: k.prefix,
19        roles: k.roles,
20        description: k.description,
21        tags: k.tags,
22    }
23}
24
25pub fn run(cmd: KindsCmd, ctx: Ctx) -> Result<()> {
26    match cmd {
27        KindsCmd::List => {
28            let all: Vec<KindInfo> = kinds::KINDS.iter().map(info).collect();
29            print_success(ctx, &all, |ks| {
30                for k in ks {
31                    println!("  {:<12} {}", k.kind, k.description);
32                }
33            });
34            Ok(())
35        }
36        KindsCmd::Find { query } => {
37            let query = query.join(" ");
38            let mut scored: Vec<(f64, &kinds::KindSpec)> = kinds::KINDS
39                .iter()
40                .map(|k| (kinds::score(&query, k.description, k.tags), k))
41                .filter(|(s, _)| *s > 0.0)
42                .collect();
43            scored.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(std::cmp::Ordering::Equal));
44            if scored.is_empty() {
45                return Err(AppError::NotFound(format!(
46                    "no contract kind matches '{query}'. Run: contract kinds list"
47                )));
48            }
49            #[derive(serde::Serialize)]
50            struct Match {
51                kind: &'static str,
52                score: f64,
53                description: &'static str,
54            }
55            let matches: Vec<Match> = scored
56                .iter()
57                .map(|(s, k)| Match {
58                    kind: k.kind,
59                    score: (*s * 100.0).round() / 100.0,
60                    description: k.description,
61                })
62                .collect();
63            print_success(ctx, &matches, |ms| {
64                for m in ms {
65                    println!("  {:<12} {:>5.2}  {}", m.kind, m.score, m.description);
66                }
67            });
68            Ok(())
69        }
70    }
71}