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
use std::process::exit;

use clap::{value_parser, Arg, ArgAction, Parser, Command};
use clap_complete::{generate, Generator, Shell};
use log::LevelFilter;
use simplelog::{Config, TermLogger, TerminalMode, ColorChoice};

pub trait HasVerboseFlag {
    fn log_level_filter(&self)-> LevelFilter;
}

pub trait FancyParser<P: Parser> {
    fn parse_cli() -> P;

    fn parse_markdown_help();
    fn parse_autocomplete();
}

impl<P> FancyParser<P> for P
where
    P: Parser + HasVerboseFlag,
{
    fn parse_cli() -> P {
        Self::parse_markdown_help();
        Self::parse_autocomplete();
        let cli = P::parse();

        let _ = TermLogger::init(
            cli.log_level_filter(),
            Config::default(),
            TerminalMode::Stderr,
            ColorChoice::Auto);
        cli
    }

    fn parse_markdown_help() {
        let matches = P::command()
            .ignore_errors(true)
            .arg(Arg::new("markdown-help").long("markdown-help").hide(true))
            .get_matches();

        if matches.contains_id("markdown-help") {
            clap_markdown::print_help_markdown::<P>();
            exit(0);
        }
    }

    fn parse_autocomplete() {
        let cmd = P::command();
        let matches = cmd.clone()
            .ignore_errors(true)
            .arg(
                Arg::new("autocomplete")
                    .long("autocomplete")
                    .action(ArgAction::Set)
                    .hide(true)
                    .value_parser(value_parser!(Shell)),
            )
            .get_matches();

        if let Some(generator) = matches.get_one::<Shell>("autocomplete") {
            let mut cmd = P::command();
            
            print_completions(*generator, &mut cmd);
            exit(0);
        }
    }
}

fn print_completions<G: Generator>(gen: G, cmd: &mut Command) {
    generate(gen, cmd, cmd.get_name().to_string(), &mut std::io::stdout());
}