From 2a223dad82901fa2e74baad3bfc4c7b94509300f Mon Sep 17 00:00:00 2001 From: Kevin K Date: Mon, 5 Oct 2015 20:36:30 -0400 Subject: [PATCH] fix(Unified Help): sorts both flags and options as a unified category --- src/app/app.rs | 168 ++++++------------------------ src/args/argbuilder/flag.rs | 36 +++++++ src/args/argbuilder/option.rs | 41 ++++++++ src/args/argbuilder/positional.rs | 23 ++++ src/macros.rs | 13 ++- 5 files changed, 141 insertions(+), 140 deletions(-) diff --git a/src/app/app.rs b/src/app/app.rs index 17ab16cb..b590f9fe 100644 --- a/src/app/app.rs +++ b/src/app/app.rs @@ -1462,111 +1462,38 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ } let tab = " "; - if flags { - if !unified_help { + if unified_help && (flags || opts) { + try!(write!(w, "\nOPTIONS:\n")); + let mut combined = vec![]; + for f in self.flags.values().filter(|f| !f.settings.is_set(&ArgSettings::Hidden)) { + combined.push(f.name); + } + for o in self.opts.values().filter(|o| !o.settings.is_set(&ArgSettings::Hidden)) { + combined.push(o.name); + } + combined.sort(); + for a in combined { + if let Some(a) = self.flags.get(a) { + try!(a.write_help(w, tab, if !unified_help || longest_opt == 0 { longest_flag } else { longest_opt })); + } else if let Some(a) = self.opts.get(a) { + try!(a.write_help(w, tab, if !unified_help || longest_opt == 0 { longest_flag } else { longest_opt })); + } + } + } else { + if flags { try!(write!(w, "\nFLAGS:\n")); - } else { - try!(write!(w, "\nOPTIONS:\n")) + for v in self.flags.values() + .filter(|f| !f.settings.is_set(&ArgSettings::Hidden)) { + try!(v.write_help(w, tab, if !unified_help || longest_opt == 0 { longest_flag } else { longest_opt })); + } } - for v in self.flags - .values() - .filter(|f| !f.settings.is_set(&ArgSettings::Hidden)) { - try!(write!(w, "{}", tab)); - if let Some(s) = v.short { - try!(write!(w, "-{}",s)); - } else { - try!(write!(w, "{}", tab)); - } - if let Some(l) = v.long { - try!(write!(w, "{}--{}", - if v.short.is_some() { ", " } else {""}, - l - )); - try!(self.print_spaces( - if !unified_help || longest_opt == 0 { - (longest_flag + 4) - } else { - (longest_opt + 4) - } - (l.len() + 2), - w - )); - } else { - // 6 is tab (4) + -- (2) - try!(self.print_spaces( - if !unified_help { - (longest_flag + 6) - } else { - (longest_opt + 6) - }, - w - )); - } - if let Some(h) = v.help { - if h.contains("{n}") { - let mut hel = h.split("{n}"); - while let Some(part) = hel.next() { - try!(write!(w, "{}\n", part)); - try!(self.print_spaces( - if !unified_help { - longest_flag - } else { - longest_opt - } + 12, w)); - try!(write!(w, "{}", hel.next().unwrap_or(""))); - } - } else { - try!(write!(w, "{}", h)); - } - } - try!(write!(w, "\n")); - } - } - if opts { - if !unified_help { + if opts { try!(write!(w, "\nOPTIONS:\n")); - } else { - // maybe erase - } - for v in self.opts - .values() - .filter(|o| !o.settings.is_set(&ArgSettings::Hidden)) { - // if it supports multiple we add '...' i.e. 3 to the name length - try!(write!(w, "{}", tab)); - if let Some(s) = v.short { - try!(write!(w, "-{}",s)); - } else { - try!(write!(w, "{}", tab)); + for v in self.opts + .values() + .filter(|o| !o.settings.is_set(&ArgSettings::Hidden)) { + try!(v.write_help(w, tab, longest_opt)); } - if let Some(l) = v.long { - try!(write!(w, "{}--{}", if v.short.is_some() {", "} else {""}, l)); - } - if let Some(ref vec) = v.val_names { - for val in vec { - try!(write!(w, " <{}>", val)); - } - } else if let Some(num) = v.num_vals { - for _ in (0..num) { - try!(write!(w, " <{}>", v.name)); - } - } else { - try!(write!(w, " <{}>{}", v.name, - if v.settings.is_set(&ArgSettings::Multiple) { - "..." - } else { - "" - } - )); - } - if v.long.is_some() { - try!(self.print_spaces( - (longest_opt + 4) - (v.to_string().len()), w - )); - } else { - // 8 = tab + '-a, '.len() - try!(self.print_spaces((longest_opt + 8) - (v.to_string().len()), w)); - }; - print_opt_help!(self, v, longest_opt + 12, w); - try!(write!(w, "\n")); } } if pos { @@ -1574,25 +1501,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ for v in self.positionals_idx .values() .filter(|p| !p.settings.is_set(&ArgSettings::Hidden)) { - try!(write!(w, "{}", tab)); - try!(write!(w, "{}", v.name)); - if v.settings.is_set(&ArgSettings::Multiple) { - try!(write!(w, "...")); - } - try!(self.print_spaces((longest_pos + 4) - (v.to_string().len()), w)); - if let Some(h) = v.help { - if h.contains("{n}") { - let mut hel = h.split("{n}"); - while let Some(part) = hel.next() { - try!(write!(w, "{}\n", part)); - try!(self.print_spaces(longest_pos + 6, w)); - try!(write!(w, "{}", hel.next().unwrap_or(""))); - } - } else { - try!(write!(w, "{}", h)); - } - } - try!(write!(w, "\n")); + try!(v.write_help(w, tab, longest_pos)); } } if subcmds { @@ -1601,13 +1510,13 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ .values() .filter(|s| !s.settings.is_set(&AppSettings::Hidden)) { try!(write!(w, "{}{}", tab, sc.name)); - try!(self.print_spaces((longest_sc + 4) - (sc.name.len()), w)); + write_spaces!((longest_sc + 4) - (sc.name.len()), w); if let Some(a) = sc.about { if a.contains("{n}") { let mut ab = a.split("{n}"); while let Some(part) = ab.next() { try!(write!(w, "{}\n", part)); - try!(self.print_spaces(longest_sc + 8, w)); + write_spaces!(longest_sc + 8, w); try!(write!(w, "{}", ab.next().unwrap_or(""))); } } else { @@ -1626,21 +1535,6 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ w.flush() } - // Used when spacing arguments and their help message when displaying help information - fn print_spaces(&self, - num: usize, - w: &mut W) - -> io::Result<()> { - for _ in (0..num) { - try!(write!(w, " ")); - } - - // Flush? or let parent print_help flush? - // w.flush() - - Ok(()) - } - // Prints the version to the user and exits if quit=true fn print_version(&self, w: &mut W) diff --git a/src/args/argbuilder/flag.rs b/src/args/argbuilder/flag.rs index 8ba5e0c2..8426d0b1 100644 --- a/src/args/argbuilder/flag.rs +++ b/src/args/argbuilder/flag.rs @@ -1,6 +1,7 @@ // use std::collections::HashSet; use std::fmt::{Display, Formatter, Result}; use std::convert::From; +use std::io; use Arg; use args::settings::{ArgFlags, ArgSettings}; @@ -42,6 +43,41 @@ impl<'n> FlagBuilder<'n> { settings: ArgFlags::new() } } + + pub fn write_help(&self, + w: &mut W, + tab: &str, + longest: usize) -> io::Result<()> { + try!(write!(w, "{}", tab)); + if let Some(s) = self.short { + try!(write!(w, "-{}", s)); + } else { + try!(write!(w, "{}", tab)); + } + if let Some(l) = self.long { + try!(write!(w, "{}--{}", + if self.short.is_some() { ", " } else { "" }, + l + )); + write_spaces!((longest + 4) - (l.len() + 2), w); + } else { + // 6 is tab (4) + -- (2) + write_spaces!((longest + 6), w); + } + if let Some(h) = self.help { + if h.contains("{n}") { + let mut hel = h.split("{n}"); + while let Some(part) = hel.next() { + try!(write!(w, "{}\n", part)); + write_spaces!((longest + 12), w); + try!(write!(w, "{}", hel.next().unwrap_or(""))); + } + } else { + try!(write!(w, "{}", h)); + } + } + write!(w, "\n") + } } impl<'n, 'a> From<&'a Arg<'n, 'n, 'n, 'n, 'n, 'n>> for FlagBuilder<'n> { diff --git a/src/args/argbuilder/option.rs b/src/args/argbuilder/option.rs index 763bcba5..6fe0344f 100644 --- a/src/args/argbuilder/option.rs +++ b/src/args/argbuilder/option.rs @@ -2,6 +2,7 @@ use std::rc::Rc; use std::collections::BTreeSet; use std::fmt::{Display, Formatter, Result}; use std::result::Result as StdResult; +use std::io; use Arg; use args::settings::{ArgFlags, ArgSettings}; @@ -138,6 +139,46 @@ impl<'n> OptBuilder<'n> { ob } + + pub fn write_help(&self, w: &mut W, tab: &str, longest: usize) -> io::Result<()> { + // if it supports multiple we add '...' i.e. 3 to the name length + try!(write!(w, "{}", tab)); + if let Some(s) = self.short { + try!(write!(w, "-{}",s)); + } else { + try!(write!(w, "{}", tab)); + } + if let Some(l) = self.long { + try!(write!(w, "{}--{}", if self.short.is_some() {", "} else {""}, l)); + } + if let Some(ref vec) = self.val_names { + for val in vec { + try!(write!(w, " <{}>", val)); + } + } else if let Some(num) = self.num_vals { + for _ in (0..num) { + try!(write!(w, " <{}>", self.name)); + } + } else { + try!(write!(w, " <{}>{}", self.name, + if self.settings.is_set(&ArgSettings::Multiple) { + "..." + } else { + "" + } + )); + } + if self.long.is_some() { + write_spaces!( + (longest + 4) - (self.to_string().len()), w + ); + } else { + // 8 = tab + '-a, '.len() + write_spaces!((longest + 8) - (self.to_string().len()), w); + }; + print_opt_help!(self, longest + 12, w); + write!(w, "\n") + } } impl<'n> Display for OptBuilder<'n> { diff --git a/src/args/argbuilder/positional.rs b/src/args/argbuilder/positional.rs index 1f99fff9..faad702b 100644 --- a/src/args/argbuilder/positional.rs +++ b/src/args/argbuilder/positional.rs @@ -1,6 +1,7 @@ use std::fmt::{Display, Formatter, Result}; use std::result::Result as StdResult; use std::rc::Rc; +use std::io; use Arg; use args::settings::{ArgFlags, ArgSettings}; @@ -138,6 +139,28 @@ impl<'n> PosBuilder<'n> { pb } + + pub fn write_help(&self, w: &mut W, tab: &str, longest: usize) -> io::Result<()> { + try!(write!(w, "{}", tab)); + try!(write!(w, "{}", self.name)); + if self.settings.is_set(&ArgSettings::Multiple) { + try!(write!(w, "...")); + } + write_spaces!((longest + 4) - (self.to_string().len()), w); + if let Some(h) = self.help { + if h.contains("{n}") { + let mut hel = h.split("{n}"); + while let Some(part) = hel.next() { + try!(write!(w, "{}\n", part)); + write_spaces!(longest + 6, w); + try!(write!(w, "{}", hel.next().unwrap_or(""))); + } + } else { + try!(write!(w, "{}", h)); + } + } + write!(w, "\n") + } } impl<'n> Display for PosBuilder<'n> { diff --git a/src/macros.rs b/src/macros.rs index 907e96e1..9ad0886d 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -44,6 +44,14 @@ macro_rules! load_yaml { ); } +macro_rules! write_spaces { + ($num:expr, $w:ident) => ({ + for _ in (0..$num) { + try!(write!($w, " ")); + } + }) +} + // convienience macro for remove an item from a vec macro_rules! vec_remove { ($vec:expr, $to_rem:ident) => { @@ -121,7 +129,7 @@ macro_rules! remove_override { // De-duplication macro used in src/app.rs macro_rules! print_opt_help { - ($me:ident, $opt:ident, $spc:expr, $w:ident) => { + ($opt:ident, $spc:expr, $w:ident) => { if let Some(h) = $opt.help { if h.contains("{n}") { let mut hel = h.split("{n}"); @@ -130,9 +138,8 @@ macro_rules! print_opt_help { } while let Some(part) = hel.next() { try!(write!($w, "\n")); - try!($me.print_spaces($spc, $w)); + write_spaces!($spc, $w); try!(write!($w, "{}", part)); - // try!(write!($w, "{}", hel.next().unwrap_or(""))); } } else { try!(write!($w, "{}", h));