Skip to content

Commit

Permalink
feat(Subcommands): adds support for custom ordering in help messages
Browse files Browse the repository at this point in the history
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.

```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

```
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
```

Closes #442
  • Loading branch information
kbknapp committed Mar 10, 2016
1 parent 9803b51 commit 7d2a2ed
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 16 deletions.
2 changes: 2 additions & 0 deletions src/app/meta.rs
Expand Up @@ -10,6 +10,7 @@ pub struct AppMeta<'b> {
pub usage_str: Option<&'b str>,
pub usage: Option<String>,
pub help_str: Option<&'b str>,
pub disp_ord: usize,
}

impl<'b> Default for AppMeta<'b> {
Expand All @@ -24,6 +25,7 @@ impl<'b> Default for AppMeta<'b> {
usage: None,
bin_name: None,
help_str: None,
disp_ord: 999,
}
}
}
Expand Down
50 changes: 50 additions & 0 deletions src/app/mod.rs
Expand Up @@ -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`
///
Expand Down
36 changes: 20 additions & 16 deletions src/app/parser.rs
Expand Up @@ -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::<BTreeMap<_, _>>() {
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"));
}
}

Expand Down

0 comments on commit 7d2a2ed

Please sign in to comment.