Merge pull request #68 from kbknapp/usage

Improves ergonomics and performance of usage generation
This commit is contained in:
Kevin K. 2015-04-10 10:55:20 -04:00
commit 76de2f553a
4 changed files with 36 additions and 33 deletions

View file

@ -427,7 +427,7 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{
}
}
let req_pos = self.positionals_idx.values().filter_map(|ref x| if x.required || matched_pos_reqs.contains(x.name) {
let mut req_pos = self.positionals_idx.values().filter_map(|ref x| if x.required || matched_pos_reqs.contains(x.name) {
num_req_pos += 1;
if x.multiple {
Some(format!("<{}>...", x.name))
@ -437,19 +437,21 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{
} else {
None
} )
.fold(String::new(), |acc, ref name| acc + &format!("{} ", name)[..]);
.fold(String::with_capacity(50), |acc, ref name| acc + &format!("{} ", name)[..]);
req_pos.shrink_to_fit();
let mut num_req_opts = 0;
let req_opts = self.opts.values().filter_map(|x| if x.required || self.matched_reqs.contains(x.name) {
let mut req_opts = self.opts.values().filter_map(|x| if x.required || self.matched_reqs.contains(x.name) {
num_req_opts += 1;
Some(x)
}else {
None
})
.fold(String::new(), |acc, ref o| acc + &format!("-{}{} ",if let Some(l) = o.long {
.fold(String::with_capacity(50), |acc, ref o| acc + &format!("-{}{} ",if let Some(l) = o.long {
format!("-{}=", l)
} else {
format!("{} ",o.short.unwrap())
},o.name));
req_opts.shrink_to_fit();
// usage.push_str(tab);
usage.push_str(&self.bin_name.clone().unwrap_or(self.name.clone())[..]);
@ -465,7 +467,7 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{
"[OPTIONS]".to_owned()
} else {
req_opts
});
}).unwrap_or_else(|e| self.report_error(format!("internal error: {}", e),false,true));
}
if pos {
write!(&mut usage, " {}",
@ -475,7 +477,7 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{
"[POSITIONAL]".to_owned()
} else {
req_pos
} );
} ).unwrap_or_else(|e| self.report_error(format!("internal error: {}", e),false,true));
}
if subcmds {
usage.push_str(" [SUBCOMMANDS]");
@ -589,16 +591,7 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{
// 7 is '--=' (3) + tab (4)
self.get_spaces((longest_opt + 6) - (v.name.len() + mult))
},
if let Some(h) = v.help {
format!("{}{}", h,
if let Some(ref pv) = v.possible_vals {
format!(" [values:{}]", pv.iter().fold(String::new(), |acc, name| acc + &format!(" {}",name)[..] ))
}else{
"".to_owned()
})
} else {
tab.to_owned()
} );
get_help!(v) );
}
}
if pos {
@ -609,15 +602,7 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{
println!("{}{}{}{}",tab,
if v.multiple {format!("{}...",v.name)} else {v.name.to_owned()},
self.get_spaces((longest_pos + 4) - (v.name.len() + mult)),
if let Some(h) = v.help {
format!("{}{}",
h,
if let Some(ref pv) = v.possible_vals {
format!(" [values:{}]", pv.iter().fold(String::new(), |acc, name| acc + &format!(" {}",name)[..] ))
}else{"".to_owned()})
} else {
tab.to_owned()
} );
get_help!(v));
}
}
if subcmds {
@ -706,7 +691,6 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{
}
}
}
matches.usage = Some(self.create_usage());
self.get_matches_from(&mut matches, &mut it );
matches
@ -811,7 +795,7 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{
if self.positionals_idx.is_empty() {
self.report_error(
format!("Found positional argument {}, but {} doesn't accept any", arg, self.name),
format!("Argument \"{}\" isn't a valid option for {}", arg, self.bin_name.clone().unwrap_or(self.name.clone())),
true, true);
}
// If we find that an argument requires a positiona, we need to update all the
@ -879,7 +863,7 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{
}
}
} else {
self.report_error(format!("Positional argument \"{}\" was found, but {} wasn't expecting any", arg, self.name), true, true);
self.report_error(format!("Argument \"{}\" isn't a valid argument for {}", arg, self.bin_name.clone().unwrap_or(self.name.clone())), true, true);
}
}
}
@ -899,6 +883,7 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{
true, true);
}
matches.usage = Some(self.create_usage());
if let Some(sc_name) = subcmd_name {
if let Some(ref mut sc) = self.subcommands.get_mut(&sc_name) {

View file

@ -266,7 +266,7 @@ impl<'a> ArgMatches<'a> {
("", None)
}
/// Returns a slice of the default usage for the *top level parent App only*
/// Returns a slice of the usage
///
///
/// # Example
@ -274,12 +274,14 @@ impl<'a> ArgMatches<'a> {
/// ```no_run
/// # use clap::{App, Arg, SubCommand};
/// # let app_matches = App::new("myapp").subcommand(SubCommand::new("test")).get_matches();
/// println!("{}",app_matches.usage().unwrap());
/// println!("{}",app_matches.usage());
/// ```
pub fn usage(&self) -> Option<&str> {
pub fn usage(&self) -> &str {
if let Some( ref u ) = self.usage {
return Some(&u[..]);
return &u[..];
}
None
// Should be un-reachable
""
}
}

View file

@ -5,6 +5,8 @@
pub use args::{Arg, SubCommand, ArgMatches};
pub use app::App;
#[macro_use]
mod macros;
mod app;
mod args;

14
src/macros.rs Normal file
View file

@ -0,0 +1,14 @@
macro_rules! get_help {
($opt:ident) => {
if let Some(h) = $opt.help {
format!("{}{}", h,
if let Some(ref pv) = $opt.possible_vals {
let mut pv_s = pv.iter().fold(String::with_capacity(50), |acc, name| acc + &format!(" {}",name)[..]);
pv_s.shrink_to_fit();
format!(" [values:{}]", &pv_s[..])
}else{"".to_owned()})
} else {
" ".to_owned()
}
};
}