From 65cc259e4559cbe3653c865ec0c4b1e42a389b07 Mon Sep 17 00:00:00 2001 From: Kevin K Date: Sun, 19 Apr 2015 20:19:21 -0400 Subject: [PATCH] feat(apps): add ability to display additional help info after auto-gen'ed help msg --- src/app.rs | 53 +++++++++++++++++++++++++++++++----------- src/args/subcommand.rs | 2 +- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/src/app.rs b/src/app.rs index 387d959a..c2a5d0a9 100644 --- a/src/app.rs +++ b/src/app.rs @@ -38,7 +38,7 @@ use args::{ FlagBuilder, OptBuilder, PosBuilder}; /// /// // Your pogram logic starts here... /// ``` -pub struct App<'a, 'v, 'ab, 'u, 'ar> { +pub struct App<'a, 'v, 'ab, 'u, 'h, 'ar> { // The name displayed to the user when showing version and help/usage information name: String, // A string of author(s) if desired. Displayed when showing help/usage information @@ -47,6 +47,8 @@ pub struct App<'a, 'v, 'ab, 'u, 'ar> { version: Option<&'v str>, // A brief explaination of the program that gets displayed to the user when shown help/usage information about: Option<&'ab str>, + // Additional help information + more_help: Option<&'h str>, // A list of possible flags flags: BTreeMap<&'ar str, FlagBuilder<'ar>>, // A list of possible options @@ -54,7 +56,7 @@ pub struct App<'a, 'v, 'ab, 'u, 'ar> { // A list of positional arguments positionals_idx: BTreeMap>, // A list of subcommands - subcommands: BTreeMap>, + subcommands: BTreeMap>, needs_long_help: bool, needs_long_version: bool, needs_short_help: bool, @@ -71,7 +73,7 @@ pub struct App<'a, 'v, 'ab, 'u, 'ar> { } -impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{ +impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ /// Creates a new instance of an application requiring a name (such as the binary). The name /// will be displayed to the user when they request to print version or help and usage /// information. The name should not contain spaces (hyphens '-' are ok). @@ -84,11 +86,12 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{ /// let prog = App::new("myprog") /// # .get_matches(); /// ``` - pub fn new<'n>(n: &'n str) -> App<'a, 'v, 'ab, 'u, 'ar> { + pub fn new<'n>(n: &'n str) -> App<'a, 'v, 'ab, 'u, 'h, 'ar> { App { name: n.to_owned(), author: None, about: None, + more_help: None, version: None, flags: BTreeMap::new(), opts: BTreeMap::new(), @@ -121,7 +124,7 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{ /// .author("Kevin ") /// # .get_matches(); /// ``` - pub fn author(mut self, a: &'a str) -> App<'a, 'v, 'ab, 'u, 'ar> { + pub fn author(mut self, a: &'a str) -> App<'a, 'v, 'ab, 'u, 'h, 'ar> { self.author = Some(a); self } @@ -137,11 +140,28 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{ /// .about("Does really amazing things to great people") /// # .get_matches(); /// ``` - pub fn about(mut self, a: &'ab str) -> App<'a, 'v, 'ab, 'u, 'ar> { + pub fn about(mut self, a: &'ab str) -> App<'a, 'v, 'ab, 'u, 'h, 'ar> { self.about = Some(a); self } + /// Adds additional help information to be displayed in addition to auto-generated help. This + /// information is displayed **after** the auto-generated help information. This additional + /// help is often used to describe how to use the arguments, or caveats to be noted. + /// + /// # Example + /// + /// ```no_run + /// # use clap::App; + /// # let app = App::new("myprog") + /// .more_help("Does really amazing things to great people") + /// # .get_matches(); + /// ``` + pub fn more_help(mut self, h: &'h str) -> App<'a, 'v, 'ab, 'u, 'h, 'ar> { + self.more_help = Some(h); + self + } + /// Sets a string of the version number to be displayed when displaying version or help /// information. /// @@ -153,7 +173,7 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{ /// .version("v0.1.24") /// # .get_matches(); /// ``` - pub fn version(mut self, v: &'v str) -> App<'a, 'v, 'ab, 'u, 'ar> { + pub fn version(mut self, v: &'v str) -> App<'a, 'v, 'ab, 'u, 'h, 'ar> { self.version = Some(v); self } @@ -178,7 +198,7 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{ /// .usage("myapp [-clDas] ") /// # .get_matches(); /// ``` - pub fn usage(mut self, u: &'u str) -> App<'a, 'v, 'ab, 'u, 'ar> { + pub fn usage(mut self, u: &'u str) -> App<'a, 'v, 'ab, 'u, 'h, 'ar> { self.usage_str = Some(u); self } @@ -205,7 +225,7 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{ /// .arg(Arg::from_usage("-c --config=[CONFIG] 'Optionally sets a configuration file to use'")) /// # .get_matches(); /// ``` - pub fn arg<'l, 'h, 'b, 'r>(mut self, a: Arg<'ar, 'ar, 'ar, 'ar, 'ar, 'ar>) -> App<'a, 'v, 'ab, 'u, 'ar> { + pub fn arg(mut self, a: Arg<'ar, 'ar, 'ar, 'ar, 'ar, 'ar>) -> App<'a, 'v, 'ab, 'u, 'h, 'ar> { if self.arg_list.contains(a.name) { panic!("Argument name must be unique, \"{}\" is already in use", a.name); } else { @@ -378,7 +398,7 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{ /// Arg::with_name("input").index(1).help("the input file to use")]) /// # .get_matches(); /// ``` - pub fn args(mut self, args: Vec>) -> App<'a, 'v, 'ab, 'u, 'ar> { + pub fn args(mut self, args: Vec>) -> App<'a, 'v, 'ab, 'u, 'h, 'ar> { for arg in args.into_iter() { self = self.arg(arg); } @@ -400,7 +420,7 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{ /// .arg_from_usage("-c --conf= 'Sets a configuration file to use'") /// # .get_matches(); /// ``` - pub fn arg_from_usage(mut self, usage: &'ar str) -> App<'a, 'v, 'ab, 'u, 'ar> { + pub fn arg_from_usage(mut self, usage: &'ar str) -> App<'a, 'v, 'ab, 'u, 'h, 'ar> { self = self.arg(Arg::from_usage(usage)); self } @@ -424,7 +444,7 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{ /// 'The input file to use'") /// # .get_matches(); /// ``` - pub fn args_from_usage(mut self, usage: &'ar str) -> App<'a, 'v, 'ab, 'u, 'ar> { + pub fn args_from_usage(mut self, usage: &'ar str) -> App<'a, 'v, 'ab, 'u, 'h, 'ar> { for l in usage.lines() { self = self.arg(Arg::from_usage(l.trim())); } @@ -448,7 +468,7 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{ /// // Additional subcommand configuration goes here, such as other arguments... /// # .get_matches(); /// ``` - pub fn subcommand(mut self, subcmd: App<'a, 'v, 'ab, 'u, 'ar>) -> App<'a, 'v, 'ab, 'u, 'ar> { + pub fn subcommand(mut self, subcmd: App<'a, 'v, 'ab, 'u, 'h, 'ar>) -> App<'a, 'v, 'ab, 'u, 'h, 'ar> { if subcmd.name == "help" { self.needs_subcmd_help = false; } self.subcommands.insert(subcmd.name.clone(), subcmd); self @@ -467,7 +487,7 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{ /// SubCommand::new("debug").about("Controls debug functionality")]) /// # .get_matches(); /// ``` - pub fn subcommands(mut self, subcmds: Vec>) -> App<'a, 'v, 'ab, 'u, 'ar> { + pub fn subcommands(mut self, subcmds: Vec>) -> App<'a, 'v, 'ab, 'u, 'h, 'ar> { for subcmd in subcmds.into_iter() { self = self.subcommand(subcmd); } @@ -695,6 +715,11 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{ } } + if let Some(h) = self.more_help { + println!(""); + println!("{}", h); + } + self.exit(0); } diff --git a/src/args/subcommand.rs b/src/args/subcommand.rs index a9dcd364..27346fb8 100644 --- a/src/args/subcommand.rs +++ b/src/args/subcommand.rs @@ -37,7 +37,7 @@ impl<'a> SubCommand<'a> { /// SubCommand::new("config") /// # ).get_matches(); /// ``` - pub fn new<'n, 'au, 'v, 'ab, 'u, 'ar>(name: &'n str) -> App<'au, 'v, 'ab, 'u, 'ar> { + pub fn new<'n, 'au, 'v, 'ab, 'u, 'h, 'ar>(name: &'n str) -> App<'au, 'v, 'ab, 'u, 'h, 'ar> { App::new(name) } } \ No newline at end of file