diff --git a/src/app/meta.rs b/src/app/meta.rs index 973a6a3d12e..335d77f592d 100644 --- a/src/app/meta.rs +++ b/src/app/meta.rs @@ -10,6 +10,7 @@ pub struct AppMeta<'b> { pub usage_str: Option<&'b str>, pub usage: Option, pub help_str: Option<&'b str>, + pub disp_ord: usize, } impl<'b> Default for AppMeta<'b> { @@ -24,6 +25,7 @@ impl<'b> Default for AppMeta<'b> { usage: None, bin_name: None, help_str: None, + disp_ord: 999, } } } diff --git a/src/app/mod.rs b/src/app/mod.rs index 46497ef0bad..9f92d173420 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -545,6 +545,56 @@ impl<'a, 'b> App<'a, 'b> { self } + /// Allows custom ordering of subcommands within the help message. Subcommands with a lower + /// value will be displayed first in the help message. This is helpful when one would like to + /// emphasise frequently used subcommands, or prioritize those towards the top of the list. + /// Duplicate values **are** allowed. Subcommands with duplicate display orders will be + /// displayed in alphabetical order. + /// + /// **NOTE:** The default is 999 for all subcommands. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, SubCommand}; + /// let m = App::new("cust-ord") + /// .subcommand(SubCommand::with_name("alpha") // typically subcommands are grouped + /// // alphabetically by name. Subcommands + /// // without a display_order have a value of + /// // 999 and are displayed alphabetically with + /// // all other 999 subcommands + /// .about("Some help and text")) + /// .subcommand(SubCommand::with_name("beta") + /// .display_order(1) // In order to force this subcommand to appear *first* + /// // all we have to do is give it a value lower than 999. + /// // Any other subcommands with a value of 1 will be displayed + /// // alphabetically with this one...then 2 values, then 3, etc. + /// .about("I should be first!")) + /// .get_matches_from(vec![ + /// "cust-ord", "--help" + /// ]); + /// ``` + /// + /// The above example displays the following help message + /// + /// ```ignore + /// cust-ord + /// + /// USAGE: + /// cust-ord [FLAGS] [OPTIONS] + /// + /// FLAGS: + /// -h, --help Prints help information + /// -V, --version Prints version information + /// + /// SUBCOMMANDS: + /// beta I should be first! + /// alpha Some help and text + /// ``` + pub fn display_order(mut self, ord: usize) -> Self { + self.p.meta.disp_ord = ord; + self + } /// Prints the full help message to `io::stdout()` using a `BufWriter` /// diff --git a/src/app/parser.rs b/src/app/parser.rs index c6e0404ac16..a50ee70cade 100644 --- a/src/app/parser.rs +++ b/src/app/parser.rs @@ -1500,26 +1500,30 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b { } } if subcmds { + let mut ord_m = VecMap::new(); try!(write!(w, "\nSUBCOMMANDS:\n")); - for (name, sc) in self.subcommands.iter() - .filter(|s| !s.p.is_set(AppSettings::Hidden)) - .map(|s| (&s.p.meta.name[..], s)) - .collect::>() { - try!(write!(w, "{}{}", tab, name)); - write_spaces!((longest_sc + 4) - (name.len()), w); - if let Some(a) = sc.p.meta.about { - if a.contains("{n}") { - let mut ab = a.split("{n}"); - while let Some(part) = ab.next() { - try!(write!(w, "{}\n", part)); - write_spaces!(longest_sc + 8, w); - try!(write!(w, "{}", ab.next().unwrap_or(""))); + for sc in self.subcommands.iter().filter(|s| !s.p.is_set(AppSettings::Hidden)) { + let btm = ord_m.entry(sc.p.meta.disp_ord).or_insert(BTreeMap::new()); + btm.insert(sc.p.meta.name.clone(), sc); + } + for (_, btm) in ord_m.into_iter() { + for (name, sc) in btm.into_iter() { + try!(write!(w, "{}{}", tab, name)); + write_spaces!((longest_sc + 4) - (name.len()), w); + if let Some(a) = sc.p.meta.about { + if a.contains("{n}") { + let mut ab = a.split("{n}"); + while let Some(part) = ab.next() { + try!(write!(w, "{}\n", part)); + write_spaces!(longest_sc + 8, w); + try!(write!(w, "{}", ab.next().unwrap_or(""))); + } + } else { + try!(write!(w, "{}", a)); } - } else { - try!(write!(w, "{}", a)); } + try!(write!(w, "\n")); } - try!(write!(w, "\n")); } }