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
use super::{command3::Command3, DocInfo, ParserInfo};
use crate::{
    cli_error::{CliError, CliResult},
    input::Input,
    parser::Cmd,
};

type Callback2<'a, T1, T2> = Box<dyn FnMut(&T1, &T2) -> CliResult<()> + 'a>;
pub struct Command2<'a, T1: Input, T2: Input> {
    pub docs: DocInfo,

    pub subcommands: Vec<Box<dyn Cmd + 'a>>,
    pub handler: Option<Callback2<'a, T1, T2>>,

    pub in1: T1,
    pub in2: T2,
}

impl<'a, T1, T2> ParserInfo for Command2<'a, T1, T2>
where
    T1: Input,
    T2: Input,
{
    fn symbols(&mut self) -> Vec<&mut dyn Input> {
        vec![&mut self.in1, &mut self.in2]
    }

    fn call_handler(&mut self) -> CliResult<()> {
        if let Some(handler) = &mut self.handler {
            handler(&self.in1, &self.in2)
        } else {
            Err(CliError::from(format!(
                "No handler hooked up to {}",
                self.docs.cmd_path()
            )))
        }
    }

    fn subcommand_docs(&self) -> Vec<DocInfo> {
        self.subcommands.iter().map(|s| s.docs().clone()).collect()
    }

    fn docs(&self) -> &DocInfo {
        &self.docs
    }

    fn push_parent(&mut self, parents: &[String]) {
        self.docs.parents.extend_from_slice(parents);
    }

    fn complete_subcommand(&mut self, sub_idx: usize, tokens: &[String]) -> Result<(), CliError> {
        self.subcommands[sub_idx].complete_args(tokens)
    }

    fn parse_subcommand(&mut self, sub_idx: usize, tokens: &[String]) -> Result<(), CliError> {
        self.subcommands[sub_idx].parse_args(tokens)
    }
}

impl<'a, T1: Input, T2: Input> Command2<'a, T1, T2> {
    pub fn handler<F>(mut self, handler: F) -> Self
    where
        F: FnMut(&T1, &T2) -> CliResult<()> + 'a,
    {
        self.handler = Some(Box::new(handler));
        self
    }

    pub fn input<T3: Input>(self, in3: T3) -> Command3<'a, T1, T2, T3> {
        Command3 {
            docs: self.docs,
            handler: None,

            in1: self.in1,
            in2: self.in2,
            in3,

            subcommands: self.subcommands,
        }
    }

    pub fn subcommand<C: Cmd + 'static>(mut self, mut sub: C) -> Self {
        sub.push_parent(&self.docs.parents);
        sub.push_parent(&[self.docs.name.clone()]);
        self.subcommands.push(Box::new(sub));
        self
    }
}