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
105
106
107
108
109
110
111
112
113
114
use crate::{
    arg::Arg,
    cli_error::{CliError, CliResult},
    input::Input,
    parser::Cmd,
};

use super::{command1::Command1, CompletionMode, DocInfo, ParserInfo};

pub struct Command0<'a> {
    docs: DocInfo,

    subcommands: Vec<Box<dyn Cmd + 'a>>,
    handler: Option<Box<dyn FnMut() -> CliResult<()> + 'a>>,
}

impl<'a> ParserInfo for Command0<'a> {
    fn symbols(&mut self) -> Vec<&mut dyn Input> {
        vec![]
    }

    fn call_handler(&mut self) -> CliResult<()> {
        if let Some(handler) = &mut self.handler {
            handler()
        } 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 parse_subcommand(&mut self, sub_idx: usize, tokens: &[String]) -> Result<(), CliError> {
        self.subcommands[sub_idx].parse_args(tokens)
    }

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

impl<'a> Command0<'a> {
    pub fn name(name: &str) -> Self {
        Self {
            docs: DocInfo {
                name: name.to_string(),
                ..Default::default()
            },
            subcommands: vec![],
            handler: None,
        }
    }

    pub fn with_completions(self) -> Self {
        let name = self.docs.name.clone();

        self.subcommand(
            Self::name("completions")
                .description("generate completions for a given shell")
                .input(Arg::<CompletionMode>::name("shell").completor(|prompt| {
                    Ok(["bash".to_string(), "zsh".to_string(), "fish".to_string()]
                        .into_iter()
                        .filter(|sh| sh.starts_with(prompt))
                        .collect())
                }))
                .handler(move |shell| {
                    shell.get().print_completion(&name);
                    Ok(())
                }),
        )
    }

    pub fn description(mut self, description: &str) -> Self {
        self.docs.description = Some(description.to_string());
        self
    }

    pub fn input<T: Input>(self, input: T) -> Command1<'a, T> {
        Command1 {
            docs: self.docs,
            handler: None,
            in1: input,

            subcommands: self.subcommands,
        }
    }

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

    pub fn subcommand<C: Cmd + 'a>(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
    }
}