diff options
Diffstat (limited to 'clap/src/app/usage.rs')
-rw-r--r-- | clap/src/app/usage.rs | 479 |
1 files changed, 0 insertions, 479 deletions
diff --git a/clap/src/app/usage.rs b/clap/src/app/usage.rs deleted file mode 100644 index 6090588..0000000 --- a/clap/src/app/usage.rs +++ /dev/null @@ -1,479 +0,0 @@ -// std -use std::collections::{BTreeMap, VecDeque}; - -// Internal -use INTERNAL_ERROR_MSG; -use args::{AnyArg, ArgMatcher, PosBuilder}; -use args::settings::ArgSettings; -use app::settings::AppSettings as AS; -use app::parser::Parser; - -// Creates a usage string for display. This happens just after all arguments were parsed, but before -// any subcommands have been parsed (so as to give subcommands their own usage recursively) -pub fn create_usage_with_title(p: &Parser, used: &[&str]) -> String { - debugln!("usage::create_usage_with_title;"); - let mut usage = String::with_capacity(75); - usage.push_str("USAGE:\n "); - usage.push_str(&*create_usage_no_title(p, used)); - usage -} - -// Creates a usage string to be used in error message (i.e. one with currently used args) -pub fn create_error_usage<'a, 'b>( - p: &Parser<'a, 'b>, - matcher: &'b ArgMatcher<'a>, - extra: Option<&str>, -) -> String { - let mut args: Vec<_> = matcher - .arg_names() - .iter() - .filter(|n| { - if let Some(o) = find_by_name!(p, **n, opts, iter) { - !o.b.is_set(ArgSettings::Required) && !o.b.is_set(ArgSettings::Hidden) - } else if let Some(p) = find_by_name!(p, **n, positionals, values) { - !p.b.is_set(ArgSettings::Required) && p.b.is_set(ArgSettings::Hidden) - } else { - true // flags can't be required, so they're always true - } - }) - .map(|&n| n) - .collect(); - if let Some(r) = extra { - args.push(r); - } - create_usage_with_title(p, &*args) -} - -// Creates a usage string (*without title*) if one was not provided by the user manually. -pub fn create_usage_no_title(p: &Parser, used: &[&str]) -> String { - debugln!("usage::create_usage_no_title;"); - if let Some(u) = p.meta.usage_str { - String::from(&*u) - } else if used.is_empty() { - create_help_usage(p, true) - } else { - create_smart_usage(p, used) - } -} - -// Creates a usage string for display in help messages (i.e. not for errors) -pub fn create_help_usage(p: &Parser, incl_reqs: bool) -> String { - let mut usage = String::with_capacity(75); - let name = p.meta - .usage - .as_ref() - .unwrap_or_else(|| p.meta.bin_name.as_ref().unwrap_or(&p.meta.name)); - usage.push_str(&*name); - let req_string = if incl_reqs { - let mut reqs: Vec<&str> = p.required().map(|r| &**r).collect(); - reqs.sort(); - reqs.dedup(); - get_required_usage_from(p, &reqs, None, None, false) - .iter() - .fold(String::new(), |a, s| a + &format!(" {}", s)[..]) - } else { - String::new() - }; - - let flags = needs_flags_tag(p); - if flags && !p.is_set(AS::UnifiedHelpMessage) { - usage.push_str(" [FLAGS]"); - } else if flags { - usage.push_str(" [OPTIONS]"); - } - if !p.is_set(AS::UnifiedHelpMessage) && p.opts.iter().any(|o| { - !o.is_set(ArgSettings::Required) && !o.is_set(ArgSettings::Hidden) - }) { - usage.push_str(" [OPTIONS]"); - } - - usage.push_str(&req_string[..]); - - let has_last = p.positionals.values().any(|p| p.is_set(ArgSettings::Last)); - // places a '--' in the usage string if there are args and options - // supporting multiple values - if p.opts.iter().any(|o| o.is_set(ArgSettings::Multiple)) - && p.positionals - .values() - .any(|p| !p.is_set(ArgSettings::Required)) - && !(p.has_visible_subcommands() || p.is_set(AS::AllowExternalSubcommands)) - && !has_last - { - usage.push_str(" [--]"); - } - let not_req_or_hidden = |p: &PosBuilder| { - (!p.is_set(ArgSettings::Required) || p.is_set(ArgSettings::Last)) - && !p.is_set(ArgSettings::Hidden) - }; - if p.has_positionals() && p.positionals.values().any(not_req_or_hidden) { - if let Some(args_tag) = get_args_tag(p, incl_reqs) { - usage.push_str(&*args_tag); - } else { - usage.push_str(" [ARGS]"); - } - if has_last && incl_reqs { - let pos = p.positionals - .values() - .find(|p| p.b.is_set(ArgSettings::Last)) - .expect(INTERNAL_ERROR_MSG); - debugln!("usage::create_help_usage: '{}' has .last(true)", pos.name()); - let req = pos.is_set(ArgSettings::Required); - if req - && p.positionals - .values() - .any(|p| !p.is_set(ArgSettings::Required)) - { - usage.push_str(" -- <"); - } else if req { - usage.push_str(" [--] <"); - } else { - usage.push_str(" [-- <"); - } - usage.push_str(&*pos.name_no_brackets()); - usage.push_str(">"); - usage.push_str(pos.multiple_str()); - if !req { - usage.push_str("]"); - } - } - } - - // incl_reqs is only false when this function is called recursively - if p.has_visible_subcommands() && incl_reqs || p.is_set(AS::AllowExternalSubcommands) { - if p.is_set(AS::SubcommandsNegateReqs) || p.is_set(AS::ArgsNegateSubcommands) { - if !p.is_set(AS::ArgsNegateSubcommands) { - usage.push_str("\n "); - usage.push_str(&*create_help_usage(p, false)); - usage.push_str(" <SUBCOMMAND>"); - } else { - usage.push_str("\n "); - usage.push_str(&*name); - usage.push_str(" <SUBCOMMAND>"); - } - } else if p.is_set(AS::SubcommandRequired) || p.is_set(AS::SubcommandRequiredElseHelp) { - usage.push_str(" <SUBCOMMAND>"); - } else { - usage.push_str(" [SUBCOMMAND]"); - } - } - usage.shrink_to_fit(); - debugln!("usage::create_help_usage: usage={}", usage); - usage -} - -// Creates a context aware usage string, or "smart usage" from currently used -// args, and requirements -fn create_smart_usage(p: &Parser, used: &[&str]) -> String { - debugln!("usage::smart_usage;"); - let mut usage = String::with_capacity(75); - let mut hs: Vec<&str> = p.required().map(|s| &**s).collect(); - hs.extend_from_slice(used); - - let r_string = get_required_usage_from(p, &hs, None, None, false) - .iter() - .fold(String::new(), |acc, s| acc + &format!(" {}", s)[..]); - - usage.push_str( - &p.meta - .usage - .as_ref() - .unwrap_or_else(|| p.meta.bin_name.as_ref().unwrap_or(&p.meta.name))[..], - ); - usage.push_str(&*r_string); - if p.is_set(AS::SubcommandRequired) { - usage.push_str(" <SUBCOMMAND>"); - } - usage.shrink_to_fit(); - usage -} - -// Gets the `[ARGS]` tag for the usage string -fn get_args_tag(p: &Parser, incl_reqs: bool) -> Option<String> { - debugln!("usage::get_args_tag;"); - let mut count = 0; - 'outer: for pos in p.positionals - .values() - .filter(|pos| !pos.is_set(ArgSettings::Required)) - .filter(|pos| !pos.is_set(ArgSettings::Hidden)) - .filter(|pos| !pos.is_set(ArgSettings::Last)) - { - debugln!("usage::get_args_tag:iter:{}:", pos.b.name); - if let Some(g_vec) = p.groups_for_arg(pos.b.name) { - for grp_s in &g_vec { - debugln!("usage::get_args_tag:iter:{}:iter:{};", pos.b.name, grp_s); - // if it's part of a required group we don't want to count it - if p.groups.iter().any(|g| g.required && (&g.name == grp_s)) { - continue 'outer; - } - } - } - count += 1; - debugln!( - "usage::get_args_tag:iter: {} Args not required or hidden", - count - ); - } - if !p.is_set(AS::DontCollapseArgsInUsage) && count > 1 { - debugln!("usage::get_args_tag:iter: More than one, returning [ARGS]"); - return None; // [ARGS] - } else if count == 1 && incl_reqs { - let pos = p.positionals - .values() - .find(|pos| { - !pos.is_set(ArgSettings::Required) && !pos.is_set(ArgSettings::Hidden) - && !pos.is_set(ArgSettings::Last) - }) - .expect(INTERNAL_ERROR_MSG); - debugln!( - "usage::get_args_tag:iter: Exactly one, returning '{}'", - pos.name() - ); - return Some(format!( - " [{}]{}", - pos.name_no_brackets(), - pos.multiple_str() - )); - } else if p.is_set(AS::DontCollapseArgsInUsage) && !p.positionals.is_empty() && incl_reqs { - debugln!("usage::get_args_tag:iter: Don't collapse returning all"); - return Some( - p.positionals - .values() - .filter(|pos| !pos.is_set(ArgSettings::Required)) - .filter(|pos| !pos.is_set(ArgSettings::Hidden)) - .filter(|pos| !pos.is_set(ArgSettings::Last)) - .map(|pos| { - format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str()) - }) - .collect::<Vec<_>>() - .join(""), - ); - } else if !incl_reqs { - debugln!("usage::get_args_tag:iter: incl_reqs=false, building secondary usage string"); - let highest_req_pos = p.positionals - .iter() - .filter_map(|(idx, pos)| { - if pos.b.is_set(ArgSettings::Required) && !pos.b.is_set(ArgSettings::Last) { - Some(idx) - } else { - None - } - }) - .max() - .unwrap_or_else(|| p.positionals.len()); - return Some( - p.positionals - .iter() - .filter_map(|(idx, pos)| { - if idx <= highest_req_pos { - Some(pos) - } else { - None - } - }) - .filter(|pos| !pos.is_set(ArgSettings::Required)) - .filter(|pos| !pos.is_set(ArgSettings::Hidden)) - .filter(|pos| !pos.is_set(ArgSettings::Last)) - .map(|pos| { - format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str()) - }) - .collect::<Vec<_>>() - .join(""), - ); - } - Some("".into()) -} - -// Determines if we need the `[FLAGS]` tag in the usage string -fn needs_flags_tag(p: &Parser) -> bool { - debugln!("usage::needs_flags_tag;"); - 'outer: for f in &p.flags { - debugln!("usage::needs_flags_tag:iter: f={};", f.b.name); - if let Some(l) = f.s.long { - if l == "help" || l == "version" { - // Don't print `[FLAGS]` just for help or version - continue; - } - } - if let Some(g_vec) = p.groups_for_arg(f.b.name) { - for grp_s in &g_vec { - debugln!("usage::needs_flags_tag:iter:iter: grp_s={};", grp_s); - if p.groups.iter().any(|g| &g.name == grp_s && g.required) { - debugln!("usage::needs_flags_tag:iter:iter: Group is required"); - continue 'outer; - } - } - } - if f.is_set(ArgSettings::Hidden) { - continue; - } - debugln!("usage::needs_flags_tag:iter: [FLAGS] required"); - return true; - } - - debugln!("usage::needs_flags_tag: [FLAGS] not required"); - false -} - -// Returns the required args in usage string form by fully unrolling all groups -pub fn get_required_usage_from<'a, 'b>( - p: &Parser<'a, 'b>, - reqs: &[&'a str], - matcher: Option<&ArgMatcher<'a>>, - extra: Option<&str>, - incl_last: bool, -) -> VecDeque<String> { - debugln!( - "usage::get_required_usage_from: reqs={:?}, extra={:?}", - reqs, - extra - ); - let mut desc_reqs: Vec<&str> = vec![]; - desc_reqs.extend(extra); - let mut new_reqs: Vec<&str> = vec![]; - macro_rules! get_requires { - (@group $a: ident, $v:ident, $p:ident) => {{ - if let Some(rl) = p.groups.iter() - .filter(|g| g.requires.is_some()) - .find(|g| &g.name == $a) - .map(|g| g.requires.as_ref().unwrap()) { - for r in rl { - if !$p.contains(&r) { - debugln!("usage::get_required_usage_from:iter:{}: adding group req={:?}", - $a, r); - $v.push(r); - } - } - } - }}; - ($a:ident, $what:ident, $how:ident, $v:ident, $p:ident) => {{ - if let Some(rl) = p.$what.$how() - .filter(|a| a.b.requires.is_some()) - .find(|arg| &arg.b.name == $a) - .map(|a| a.b.requires.as_ref().unwrap()) { - for &(_, r) in rl.iter() { - if !$p.contains(&r) { - debugln!("usage::get_required_usage_from:iter:{}: adding arg req={:?}", - $a, r); - $v.push(r); - } - } - } - }}; - } - // initialize new_reqs - for a in reqs { - get_requires!(a, flags, iter, new_reqs, reqs); - get_requires!(a, opts, iter, new_reqs, reqs); - get_requires!(a, positionals, values, new_reqs, reqs); - get_requires!(@group a, new_reqs, reqs); - } - desc_reqs.extend_from_slice(&*new_reqs); - debugln!( - "usage::get_required_usage_from: after init desc_reqs={:?}", - desc_reqs - ); - loop { - let mut tmp = vec![]; - for a in &new_reqs { - get_requires!(a, flags, iter, tmp, desc_reqs); - get_requires!(a, opts, iter, tmp, desc_reqs); - get_requires!(a, positionals, values, tmp, desc_reqs); - get_requires!(@group a, tmp, desc_reqs); - } - if tmp.is_empty() { - debugln!("usage::get_required_usage_from: no more children"); - break; - } else { - debugln!("usage::get_required_usage_from: after iter tmp={:?}", tmp); - debugln!( - "usage::get_required_usage_from: after iter new_reqs={:?}", - new_reqs - ); - desc_reqs.extend_from_slice(&*new_reqs); - new_reqs.clear(); - new_reqs.extend_from_slice(&*tmp); - debugln!( - "usage::get_required_usage_from: after iter desc_reqs={:?}", - desc_reqs - ); - } - } - desc_reqs.extend_from_slice(reqs); - desc_reqs.sort(); - desc_reqs.dedup(); - debugln!( - "usage::get_required_usage_from: final desc_reqs={:?}", - desc_reqs - ); - let mut ret_val = VecDeque::new(); - let args_in_groups = p.groups - .iter() - .filter(|gn| desc_reqs.contains(&gn.name)) - .flat_map(|g| p.arg_names_in_group(g.name)) - .collect::<Vec<_>>(); - - let pmap = if let Some(m) = matcher { - desc_reqs - .iter() - .filter(|a| p.positionals.values().any(|p| &&p.b.name == a)) - .filter(|&pos| !m.contains(pos)) - .filter_map(|pos| p.positionals.values().find(|x| &x.b.name == pos)) - .filter(|&pos| incl_last || !pos.is_set(ArgSettings::Last)) - .filter(|pos| !args_in_groups.contains(&pos.b.name)) - .map(|pos| (pos.index, pos)) - .collect::<BTreeMap<u64, &PosBuilder>>() // sort by index - } else { - desc_reqs - .iter() - .filter(|a| p.positionals.values().any(|pos| &&pos.b.name == a)) - .filter_map(|pos| p.positionals.values().find(|x| &x.b.name == pos)) - .filter(|&pos| incl_last || !pos.is_set(ArgSettings::Last)) - .filter(|pos| !args_in_groups.contains(&pos.b.name)) - .map(|pos| (pos.index, pos)) - .collect::<BTreeMap<u64, &PosBuilder>>() // sort by index - }; - debugln!( - "usage::get_required_usage_from: args_in_groups={:?}", - args_in_groups - ); - for &p in pmap.values() { - let s = p.to_string(); - if args_in_groups.is_empty() || !args_in_groups.contains(&&*s) { - ret_val.push_back(s); - } - } - for a in desc_reqs - .iter() - .filter(|name| !p.positionals.values().any(|p| &&p.b.name == name)) - .filter(|name| !p.groups.iter().any(|g| &&g.name == name)) - .filter(|name| !args_in_groups.contains(name)) - .filter(|name| { - !(matcher.is_some() && matcher.as_ref().unwrap().contains(name)) - }) { - debugln!("usage::get_required_usage_from:iter:{}:", a); - let arg = find_by_name!(p, *a, flags, iter) - .map(|f| f.to_string()) - .unwrap_or_else(|| { - find_by_name!(p, *a, opts, iter) - .map(|o| o.to_string()) - .expect(INTERNAL_ERROR_MSG) - }); - ret_val.push_back(arg); - } - let mut g_vec: Vec<String> = vec![]; - for g in desc_reqs - .iter() - .filter(|n| p.groups.iter().any(|g| &&g.name == n)) - { - let g_string = p.args_in_group(g).join("|"); - let elem = format!("<{}>", &g_string[..g_string.len()]); - if !g_vec.contains(&elem) { - g_vec.push(elem); - } - } - for g in g_vec { - ret_val.push_back(g); - } - - ret_val -} |