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
//! Completions command

use super::Command;
use crate::err::Error;
use async_trait::async_trait;
use clap::{Arg, ArgAction, ArgMatches, Command as ClapCommand};
use clap_complete::{generate, Generator, Shell};

/// Abstract shell completions command
///
/// ```sh
/// Generate shell Completions

/// USAGE:
///     leetcode completions <shell>

/// ARGUMENTS:
///     <shell>  [possible values: bash, elvish, fish, powershell, zsh]
/// ```
pub struct CompletionCommand;

#[async_trait]
impl Command for CompletionCommand {
    /// `pick` usage
    fn usage() -> ClapCommand {
        ClapCommand::new("completions")
            .about("Generate shell Completions")
            .visible_alias("c")
            .arg(
                Arg::new("shell")
                    .action(ArgAction::Set)
                    .value_parser(clap::value_parser!(Shell)),
            )
    }

    async fn handler(_m: &ArgMatches) -> Result<(), Error> {
        // defining custom handler to print the completions. Handler method signature limits taking
        // other params. We need &ArgMatches and &mut ClapCommand to generate completions.
        println!("Don't use this handler. Does not implement the functionality to print completions. Use completions_handler() below.");
        Ok(())
    }
}

fn get_completions_string<G: Generator>(gen: G, cmd: &mut ClapCommand) -> Result<String, Error> {
    let mut v: Vec<u8> = Vec::new();
    let name = cmd.get_name().to_string();
    generate(gen, cmd, name, &mut v);
    Ok(String::from_utf8(v)?)
}

pub fn completion_handler(m: &ArgMatches, cmd: &mut ClapCommand) -> Result<(), Error> {
    let shell = *m.get_one::<Shell>("shell").unwrap_or(
        // if shell value is not provided try to get from the environment
        {
            println!("# Since shell arg value is not provided trying to get the default shell from the environment.");
            &Shell::from_env().ok_or(Error::MatchError)?
        }
    );
    let completions = get_completions_string(shell, cmd)?;
    println!("{}", completions);
    Ok(())
}