contract_cli/commands/
kinds.rs1use 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}