From beec17e55d2a1ddf8dc052c546b88f90b935e7c0 Mon Sep 17 00:00:00 2001 From: Alexandru Macovei Date: Mon, 4 Jan 2021 23:51:02 +0200 Subject: [PATCH] Add ability to generate shell completions via clap --- src/main.rs | 71 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 21 deletions(-) diff --git a/src/main.rs b/src/main.rs index 76a46fa6..fefddf3b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,8 +3,9 @@ extern crate clap; #[macro_use] extern crate log; +use anyhow::anyhow; use chrono::Local; -use clap::{App, AppSettings, ArgMatches}; +use clap::{App, AppSettings, Arg, ArgMatches, Shell, SubCommand}; use env_logger::Builder; use log::LevelFilter; use mdbook::utils; @@ -20,7 +21,40 @@ const VERSION: &str = concat!("v", crate_version!()); fn main() { init_logger(); - // Create a list of valid arguments and sub-commands + let app = create_clap_app(); + + // Check which subcomamnd the user ran... + let res = match app.get_matches().subcommand() { + ("init", Some(sub_matches)) => cmd::init::execute(sub_matches), + ("build", Some(sub_matches)) => cmd::build::execute(sub_matches), + ("clean", Some(sub_matches)) => cmd::clean::execute(sub_matches), + #[cfg(feature = "watch")] + ("watch", Some(sub_matches)) => cmd::watch::execute(sub_matches), + #[cfg(feature = "serve")] + ("serve", Some(sub_matches)) => cmd::serve::execute(sub_matches), + ("test", Some(sub_matches)) => cmd::test::execute(sub_matches), + ("completions", Some(sub_matches)) => (|| { + let shell: Shell = sub_matches + .value_of("shell") + .ok_or_else(|| anyhow!("Shell name missing."))? + .parse() + .map_err(|s| anyhow!("Invalid shell: {}", s))?; + + create_clap_app().gen_completions_to("mdbook", shell, &mut std::io::stdout().lock()); + Ok(()) + })(), + (_, _) => unreachable!(), + }; + + if let Err(e) = res { + utils::log_backtrace(&e); + + std::process::exit(101); + } +} + +/// Create a list of valid arguments and sub-commands +fn create_clap_app<'a, 'b>() -> App<'a, 'b> { let app = App::new(crate_name!()) .about(crate_description!()) .author("Mathieu David ") @@ -35,31 +69,26 @@ fn main() { .subcommand(cmd::init::make_subcommand()) .subcommand(cmd::build::make_subcommand()) .subcommand(cmd::test::make_subcommand()) - .subcommand(cmd::clean::make_subcommand()); + .subcommand(cmd::clean::make_subcommand()) + .subcommand( + SubCommand::with_name("completions") + .about("Generate shell completions for your shell to stdout") + .arg( + Arg::with_name("shell") + .takes_value(true) + .possible_values(&Shell::variants()) + .help("the shell to generate completions for") + .value_name("SHELL") + .required(true), + ), + ); #[cfg(feature = "watch")] let app = app.subcommand(cmd::watch::make_subcommand()); #[cfg(feature = "serve")] let app = app.subcommand(cmd::serve::make_subcommand()); - // Check which subcomamnd the user ran... - let res = match app.get_matches().subcommand() { - ("init", Some(sub_matches)) => cmd::init::execute(sub_matches), - ("build", Some(sub_matches)) => cmd::build::execute(sub_matches), - ("clean", Some(sub_matches)) => cmd::clean::execute(sub_matches), - #[cfg(feature = "watch")] - ("watch", Some(sub_matches)) => cmd::watch::execute(sub_matches), - #[cfg(feature = "serve")] - ("serve", Some(sub_matches)) => cmd::serve::execute(sub_matches), - ("test", Some(sub_matches)) => cmd::test::execute(sub_matches), - (_, _) => unreachable!(), - }; - - if let Err(e) = res { - utils::log_backtrace(&e); - - std::process::exit(101); - } + app } fn init_logger() {