Skip to content

Commit

Permalink
fix(Unified Help): sorts both flags and options as a unified category
Browse files Browse the repository at this point in the history
  • Loading branch information
kbknapp committed Oct 6, 2015
1 parent b76a8b5 commit 2a223da
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 139 deletions.
166 changes: 30 additions & 136 deletions src/app/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1462,137 +1462,46 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}

let tab = " ";
if flags {
if !unified_help {
try!(write!(w, "\nFLAGS:\n"));
} else {
try!(write!(w, "\nOPTIONS:\n"))
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 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 {
try!(write!(w, "\nOPTIONS:\n"));
} else {
// maybe erase
for o in self.opts.values().filter(|o| !o.settings.is_set(&ArgSettings::Hidden)) {
combined.push(o.name);
}
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));
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 }));
}
if let Some(l) = v.long {
try!(write!(w, "{}--{}", if v.short.is_some() {", "} else {""}, l));
}
} else {
if flags {
try!(write!(w, "\nFLAGS:\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 }));
}
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 opts {
try!(write!(w, "\nOPTIONS:\n"));
for v in self.opts
.values()
.filter(|o| !o.settings.is_set(&ArgSettings::Hidden)) {
try!(v.write_help(w, tab, longest_opt));
}
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 {
try!(write!(w, "\nARGS:\n"));
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 {
Expand All @@ -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 {
Expand All @@ -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<W: Write>(&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<W: Write>(&self,
w: &mut W)
Expand Down
36 changes: 36 additions & 0 deletions src/args/argbuilder/flag.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -42,6 +43,41 @@ impl<'n> FlagBuilder<'n> {
settings: ArgFlags::new()
}
}

pub fn write_help<W: io::Write>(&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> {
Expand Down
41 changes: 41 additions & 0 deletions src/args/argbuilder/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -138,6 +139,46 @@ impl<'n> OptBuilder<'n> {

ob
}

pub fn write_help<W: io::Write>(&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> {
Expand Down
23 changes: 23 additions & 0 deletions src/args/argbuilder/positional.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -138,6 +139,28 @@ impl<'n> PosBuilder<'n> {

pb
}

pub fn write_help<W: io::Write>(&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> {
Expand Down
13 changes: 10 additions & 3 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down Expand Up @@ -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}");
Expand All @@ -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));
Expand Down

0 comments on commit 2a223da

Please sign in to comment.