aboutsummaryrefslogtreecommitdiff
path: root/mingling_cli/src/linter/cmd_explain.rs
blob: d1758e17a3d45fa7624a35bad66b062d19090cc0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use crate::{Next, linter::registry::ResLintRegistry};
use mingling::{
    Grouped, LazyRes, Routable, ShellContext, Suggest, SuggestItem,
    macros::{
        arg, buffer, chain, completion, dispatcher, metadata, pack, pack_err, r_println, renderer,
        routeify,
    },
    metadata::Description,
    picker::EntryPicker,
};

dispatcher!("explain");

#[metadata(EntryExplain)]
pub fn desc_explain() -> Description {
    "Explain the meaning of the specified Lint".into()
}

pack!(StateExplainLint = String);
pack_err!(ErrorNoExplainLintProvided);
pack_err!(ErrorNoSuchLint = String);

#[derive(Debug, Default, Grouped)]
pub struct ResultExplainLint {
    pub lint_name: String,
    pub title: String,
    pub summary: String,
    pub active_on: String,
    pub author: String,
    pub default: String,
}

#[chain(routeify)]
pub fn handle_explain(args: EntryExplain) -> Next {
    let lint_name = args
        .pick_or_route(&arg![String], || {
            ErrorNoExplainLintProvided::default().to_chain()
        })
        .to_result()?;
    StateExplainLint::new(lint_name).into()
}

#[chain]
pub fn handle_state_explain_lint(
    p: StateExplainLint,
    registry: &mut LazyRes<ResLintRegistry>,
) -> Next {
    let registry = registry.get_ref();
    let lint_name = p.inner;
    let Some(entry) = registry.lints.iter().find(|l| l.name == lint_name) else {
        return ErrorNoSuchLint::new(lint_name).to_chain();
    };
    ResultExplainLint {
        lint_name: entry.name.clone(),
        title: entry.title.clone(),
        summary: entry.summary.clone(),
        active_on: entry.metadata.active_on.clone(),
        author: entry.metadata.author.clone(),
        default: entry.metadata.default.clone(),
    }
    .to_chain()
}

#[renderer(buffer)]
pub fn render_explain_lint(r: ResultExplainLint) {
    r_println!("{}", r.title);
    r_println!("");
    r_println!("  Name   : #[mlint[{}({})]", r.default, r.lint_name);
    r_println!("  Author : {}", r.author);
    r_println!("");
    r_println!("{}", r.summary);
}

#[renderer(buffer)]
pub fn render_error_no_explain_lint_provided(_: ErrorNoExplainLintProvided) {
    r_println!("No lint name provided");
    r_println!("");
    r_println!("Usage: mling explain <LINT>");
}

#[renderer(buffer)]
pub fn render_error_no_such_lint(err: ErrorNoSuchLint, registry: &mut LazyRes<ResLintRegistry>) {
    let registry = registry.get_ref();
    r_println!("No such lint: \"{}\"", err.info);
    r_println!("");
    r_println!("Available lints:");
    for entry in registry.lints.iter() {
        r_println!("  {}", entry.name);
    }
}

#[completion(EntryExplain)]
pub fn complete_explain(ctx: &ShellContext, registry: &mut LazyRes<ResLintRegistry>) -> Suggest {
    let registry = registry.get_ref();
    if ctx.previous_word != "explain" {
        return Suggest::FileCompletion;
    }
    let lints: Vec<String> = registry.lints.iter().map(|l| l.name.clone()).collect();
    let mut suggest = Suggest::new();
    for lint in lints {
        suggest.insert(SuggestItem::Simple(lint));
    }
    suggest
}