1736: WIP: get rig of pub doc(hidden) r=pksunkara a=CreepySkeleton



Co-authored-by: CreepySkeleton <creepy-skeleton@yandex.ru>
This commit is contained in:
bors[bot] 2020-04-11 16:23:47 +00:00 committed by GitHub
commit 874fbcf807
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 295 additions and 238 deletions

View file

@ -4,7 +4,7 @@ mod shells;
use std::io::Write; use std::io::Write;
// Internal // Internal
use clap::{find_subcmd, flags, match_alias, subcommands, App, AppSettings, Arg}; use clap::{find_subcmd, flags, match_alias, App, AppSettings, Arg};
pub use shells::*; pub use shells::*;
/// Generator trait which can be used to write generators /// Generator trait which can be used to write generators
@ -61,7 +61,11 @@ pub trait Generator {
fn all_subcommands(app: &App) -> Vec<(String, String)> { fn all_subcommands(app: &App) -> Vec<(String, String)> {
let mut subcmds: Vec<_> = Self::subcommands(app); let mut subcmds: Vec<_> = Self::subcommands(app);
for sc_v in subcommands!(app).map(|s| Self::all_subcommands(&s)) { for sc_v in app
.get_subcommands()
.iter()
.map(|s| Self::all_subcommands(&s))
{
subcmds.extend(sc_v); subcmds.extend(sc_v);
} }
@ -88,7 +92,7 @@ pub trait Generator {
/// Subcommand `rustup toolchain install` would be converted to /// Subcommand `rustup toolchain install` would be converted to
/// `("install", "rustup toolchain install")`. /// `("install", "rustup toolchain install")`.
fn subcommands(p: &App) -> Vec<(String, String)> { fn subcommands(p: &App) -> Vec<(String, String)> {
debugln!("subcommands: name={}", p.name); debugln!("subcommands: name={}", p.get_name());
debugln!("subcommands: Has subcommands...{:?}", p.has_subcommands()); debugln!("subcommands: Has subcommands...{:?}", p.has_subcommands());
let mut subcmds = vec![]; let mut subcmds = vec![];
@ -97,16 +101,16 @@ pub trait Generator {
return subcmds; return subcmds;
} }
for sc in &p.subcommands { for sc in p.get_subcommands() {
let sc_bin_name = sc.get_bin_name().unwrap(); let sc_bin_name = sc.get_bin_name().unwrap();
debugln!( debugln!(
"subcommands:iter: name={}, bin_name={}", "subcommands:iter: name={}, bin_name={}",
sc.name, sc.get_name(),
sc_bin_name sc_bin_name
); );
subcmds.push((sc.name.clone(), sc_bin_name.to_string())); subcmds.push((sc.get_name().to_string(), sc_bin_name.to_string()));
} }
subcmds subcmds
@ -115,15 +119,14 @@ pub trait Generator {
/// Gets all the short options and flags of a [`clap::App`](../clap/struct.App.html). /// Gets all the short options and flags of a [`clap::App`](../clap/struct.App.html).
/// Includes `h` and `V` depending on the [`clap::AppSettings`](../clap/enum.AppSettings.html). /// Includes `h` and `V` depending on the [`clap::AppSettings`](../clap/enum.AppSettings.html).
fn shorts<'b>(p: &'b App<'b>) -> Vec<char> { fn shorts<'b>(p: &'b App<'b>) -> Vec<char> {
debugln!("shorts: name={}", p.name); debugln!("shorts: name={}", p.get_name());
let mut shorts: Vec<char> = p let mut shorts: Vec<char> = p
.args .get_arguments()
.args
.iter() .iter()
.filter_map(|a| { .filter_map(|a| {
if a.index.is_none() && a.short.is_some() { if a.get_index().is_none() && a.get_short().is_some() {
Some(a.short.unwrap()) Some(a.get_short().unwrap())
} else { } else {
None None
} }
@ -144,15 +147,14 @@ pub trait Generator {
/// Gets all the long options and flags of a [`clap::App`](../clap/struct.App.html). /// Gets all the long options and flags of a [`clap::App`](../clap/struct.App.html).
/// Includes `help` and `version` depending on the [`clap::AppSettings`](../clap/enum.AppSettings.html). /// Includes `help` and `version` depending on the [`clap::AppSettings`](../clap/enum.AppSettings.html).
fn longs<'b>(p: &'b App<'b>) -> Vec<String> { fn longs<'b>(p: &'b App<'b>) -> Vec<String> {
debugln!("longs: name={}", p.name); debugln!("longs: name={}", p.get_name());
let mut longs: Vec<String> = p let mut longs: Vec<String> = p
.args .get_arguments()
.args
.iter() .iter()
.filter_map(|a| { .filter_map(|a| {
if a.index.is_none() && a.long.is_some() { if a.get_index().is_none() && a.get_long().is_some() {
Some(a.long.unwrap().to_string()) Some(a.get_long().unwrap().to_string())
} else { } else {
None None
} }
@ -175,11 +177,11 @@ pub trait Generator {
/// Gets all the flags of a [`clap::App`](../clap/struct.App.html). /// Gets all the flags of a [`clap::App`](../clap/struct.App.html).
/// Includes `help` and `version` depending on the [`clap::AppSettings`](../clap/enum.AppSettings.html). /// Includes `help` and `version` depending on the [`clap::AppSettings`](../clap/enum.AppSettings.html).
fn flags<'b>(p: &'b App<'b>) -> Vec<Arg> { fn flags<'b>(p: &'b App<'b>) -> Vec<Arg> {
debugln!("flags: name={}", p.name); debugln!("flags: name={}", p.get_name());
let mut flags: Vec<_> = flags!(p).cloned().collect(); let mut flags: Vec<_> = flags!(p).cloned().collect();
if flags.iter().find(|x| x.name == "help").is_none() { if flags.iter().find(|x| x.get_name() == "help").is_none() {
flags.push( flags.push(
Arg::with_name("help") Arg::with_name("help")
.short('h') .short('h')
@ -189,7 +191,7 @@ pub trait Generator {
} }
if !p.is_set(AppSettings::DisableVersion) if !p.is_set(AppSettings::DisableVersion)
&& flags.iter().find(|x| x.name == "version").is_none() && flags.iter().find(|x| x.get_name() == "version").is_none()
{ {
flags.push( flags.push(
Arg::with_name("version") Arg::with_name("version")
@ -267,7 +269,7 @@ mod tests {
let app = common(); let app = common();
let sc_app = Foo::find_subcommand_with_path(&app, "test config".split(' ').collect()); let sc_app = Foo::find_subcommand_with_path(&app, "test config".split(' ').collect());
assert_eq!(sc_app.name, "config"); assert_eq!(sc_app.get_name(), "config");
} }
#[test] #[test]
@ -276,15 +278,15 @@ mod tests {
let flags = Foo::flags(&app); let flags = Foo::flags(&app);
assert_eq!(flags.len(), 2); assert_eq!(flags.len(), 2);
assert_eq!(flags[0].long, Some("help")); assert_eq!(flags[0].get_long(), Some("help"));
assert_eq!(flags[1].long, Some("version")); assert_eq!(flags[1].get_long(), Some("version"));
let sc_flags = Foo::flags(Foo::find_subcommand_with_path(&app, vec!["test"])); let sc_flags = Foo::flags(Foo::find_subcommand_with_path(&app, vec!["test"]));
assert_eq!(sc_flags.len(), 3); assert_eq!(sc_flags.len(), 3);
assert_eq!(sc_flags[0].long, Some("file")); assert_eq!(sc_flags[0].get_long(), Some("file"));
assert_eq!(sc_flags[1].long, Some("help")); assert_eq!(sc_flags[1].get_long(), Some("help"));
assert_eq!(sc_flags[2].long, Some("version")); assert_eq!(sc_flags[2].get_long(), Some("version"));
} }
#[test] #[test]

View file

@ -147,7 +147,7 @@ fn option_details_for_path(app: &App, path: &str) -> String {
let mut opts = String::new(); let mut opts = String::new();
for o in opts!(p) { for o in opts!(p) {
if let Some(l) = o.long { if let Some(l) = o.get_long() {
opts = format!( opts = format!(
"{} "{}
--{}) --{})
@ -160,7 +160,7 @@ fn option_details_for_path(app: &App, path: &str) -> String {
); );
} }
if let Some(s) = o.short { if let Some(s) = o.get_short() {
opts = format!( opts = format!(
"{} "{}
-{}) -{})
@ -180,7 +180,7 @@ fn option_details_for_path(app: &App, path: &str) -> String {
fn vals_for(o: &Arg) -> String { fn vals_for(o: &Arg) -> String {
debugln!("Bash::vals_for: o={}", o.name); debugln!("Bash::vals_for: o={}", o.name);
if let Some(ref vals) = o.possible_vals { if let Some(ref vals) = o.get_possible_values() {
format!("$(compgen -W \"{}\" -- ${{cur}})", vals.join(" ")) format!("$(compgen -W \"{}\" -- ${{cur}})", vals.join(" "))
} else { } else {
String::from("$(compgen -f ${cur})") String::from("$(compgen -f ${cur})")

View file

@ -71,22 +71,22 @@ fn generate_inner<'b>(
let command_name = if previous_command_name.is_empty() { let command_name = if previous_command_name.is_empty() {
p.get_bin_name().expect(INTERNAL_ERROR_MSG).to_string() p.get_bin_name().expect(INTERNAL_ERROR_MSG).to_string()
} else { } else {
format!("{};{}", previous_command_name, &p.name) format!("{};{}", previous_command_name, &p.get_name())
}; };
let mut completions = String::new(); let mut completions = String::new();
let preamble = String::from("\n cand "); let preamble = String::from("\n cand ");
for option in opts!(p) { for option in opts!(p) {
if let Some(data) = option.short { if let Some(data) = option.get_short() {
let tooltip = get_tooltip(option.help, data); let tooltip = get_tooltip(option.get_help(), data);
completions.push_str(&preamble); completions.push_str(&preamble);
completions.push_str(format!("-{} '{}'", data, tooltip).as_str()); completions.push_str(format!("-{} '{}'", data, tooltip).as_str());
} }
if let Some(data) = option.long { if let Some(data) = option.get_long() {
let tooltip = get_tooltip(option.help, data); let tooltip = get_tooltip(option.get_help(), data);
completions.push_str(&preamble); completions.push_str(&preamble);
completions.push_str(format!("--{} '{}'", data, tooltip).as_str()); completions.push_str(format!("--{} '{}'", data, tooltip).as_str());
@ -94,24 +94,24 @@ fn generate_inner<'b>(
} }
for flag in Elvish::flags(p) { for flag in Elvish::flags(p) {
if let Some(data) = flag.short { if let Some(data) = flag.get_short() {
let tooltip = get_tooltip(flag.help, data); let tooltip = get_tooltip(flag.get_help(), data);
completions.push_str(&preamble); completions.push_str(&preamble);
completions.push_str(format!("-{} '{}'", data, tooltip).as_str()); completions.push_str(format!("-{} '{}'", data, tooltip).as_str());
} }
if let Some(data) = flag.long { if let Some(data) = flag.get_long() {
let tooltip = get_tooltip(flag.help, data); let tooltip = get_tooltip(flag.get_help(), data);
completions.push_str(&preamble); completions.push_str(&preamble);
completions.push_str(format!("--{} '{}'", data, tooltip).as_str()); completions.push_str(format!("--{} '{}'", data, tooltip).as_str());
} }
} }
for subcommand in &p.subcommands { for subcommand in p.get_subcommands() {
let data = &subcommand.name; let data = &subcommand.get_name();
let tooltip = get_tooltip(subcommand.about, data); let tooltip = get_tooltip(subcommand.get_about(), data);
completions.push_str(&preamble); completions.push_str(&preamble);
completions.push_str(format!("{} '{}'", data, tooltip).as_str()); completions.push_str(format!("{} '{}'", data, tooltip).as_str());
@ -124,7 +124,7 @@ fn generate_inner<'b>(
&command_name, completions &command_name, completions
); );
for subcommand in &p.subcommands { for subcommand in p.get_subcommands() {
let subcommand_subcommands_cases = generate_inner(&subcommand, &command_name, names); let subcommand_subcommands_cases = generate_inner(&subcommand, &command_name, names);
subcommands_cases.push_str(&subcommand_subcommands_cases); subcommands_cases.push_str(&subcommand_subcommands_cases);
} }

View file

@ -48,7 +48,7 @@ fn gen_fish_inner(root_command: &str, app: &App, buffer: &mut String) {
if root_command == bin_name { if root_command == bin_name {
basic_template.push_str("\"__fish_use_subcommand\""); basic_template.push_str("\"__fish_use_subcommand\"");
} else { } else {
bin_name = &app.name; bin_name = &app.get_name();
basic_template.push_str(format!("\"__fish_seen_subcommand_from {}\"", bin_name).as_str()); basic_template.push_str(format!("\"__fish_seen_subcommand_from {}\"", bin_name).as_str());
} }
@ -57,19 +57,19 @@ fn gen_fish_inner(root_command: &str, app: &App, buffer: &mut String) {
for option in opts!(app) { for option in opts!(app) {
let mut template = basic_template.clone(); let mut template = basic_template.clone();
if let Some(data) = option.short { if let Some(data) = option.get_short() {
template.push_str(format!(" -s {}", data).as_str()); template.push_str(format!(" -s {}", data).as_str());
} }
if let Some(data) = option.long { if let Some(data) = option.get_long() {
template.push_str(format!(" -l {}", data).as_str()); template.push_str(format!(" -l {}", data).as_str());
} }
if let Some(data) = option.help { if let Some(data) = option.get_help() {
template.push_str(format!(" -d '{}'", escape_string(data)).as_str()); template.push_str(format!(" -d '{}'", escape_string(data)).as_str());
} }
if let Some(ref data) = option.possible_vals { if let Some(ref data) = option.get_possible_values() {
template.push_str(format!(" -r -f -a \"{}\"", data.join(" ")).as_str()); template.push_str(format!(" -r -f -a \"{}\"", data.join(" ")).as_str());
} }
@ -80,15 +80,15 @@ fn gen_fish_inner(root_command: &str, app: &App, buffer: &mut String) {
for flag in Fish::flags(app) { for flag in Fish::flags(app) {
let mut template = basic_template.clone(); let mut template = basic_template.clone();
if let Some(data) = flag.short { if let Some(data) = flag.get_short() {
template.push_str(format!(" -s {}", data).as_str()); template.push_str(format!(" -s {}", data).as_str());
} }
if let Some(data) = flag.long { if let Some(data) = flag.get_long() {
template.push_str(format!(" -l {}", data).as_str()); template.push_str(format!(" -l {}", data).as_str());
} }
if let Some(data) = flag.help { if let Some(data) = flag.get_help() {
template.push_str(format!(" -d '{}'", escape_string(data)).as_str()); template.push_str(format!(" -d '{}'", escape_string(data)).as_str());
} }
@ -96,13 +96,13 @@ fn gen_fish_inner(root_command: &str, app: &App, buffer: &mut String) {
buffer.push_str("\n"); buffer.push_str("\n");
} }
for subcommand in &app.subcommands { for subcommand in app.get_subcommands() {
let mut template = basic_template.clone(); let mut template = basic_template.clone();
template.push_str(" -f"); template.push_str(" -f");
template.push_str(format!(" -a \"{}\"", &subcommand.name).as_str()); template.push_str(format!(" -a \"{}\"", &subcommand.get_name()).as_str());
if let Some(data) = subcommand.about { if let Some(data) = subcommand.get_about() {
template.push_str(format!(" -d '{}'", escape_string(data)).as_str()) template.push_str(format!(" -d '{}'", escape_string(data)).as_str())
} }
@ -111,7 +111,7 @@ fn gen_fish_inner(root_command: &str, app: &App, buffer: &mut String) {
} }
// generate options of subcommands // generate options of subcommands
for subcommand in &app.subcommands { for subcommand in app.get_subcommands() {
gen_fish_inner(root_command, subcommand, buffer); gen_fish_inner(root_command, subcommand, buffer);
} }
} }

View file

@ -78,15 +78,15 @@ fn generate_inner<'b>(
let command_name = if previous_command_name.is_empty() { let command_name = if previous_command_name.is_empty() {
p.get_bin_name().expect(INTERNAL_ERROR_MSG).to_string() p.get_bin_name().expect(INTERNAL_ERROR_MSG).to_string()
} else { } else {
format!("{};{}", previous_command_name, &p.name) format!("{};{}", previous_command_name, &p.get_name())
}; };
let mut completions = String::new(); let mut completions = String::new();
let preamble = String::from("\n [CompletionResult]::new("); let preamble = String::from("\n [CompletionResult]::new(");
for option in opts!(p) { for option in opts!(p) {
if let Some(data) = option.short { if let Some(data) = option.get_short() {
let tooltip = get_tooltip(option.help, data); let tooltip = get_tooltip(option.get_help(), data);
completions.push_str(&preamble); completions.push_str(&preamble);
completions.push_str( completions.push_str(
@ -98,8 +98,8 @@ fn generate_inner<'b>(
); );
} }
if let Some(data) = option.long { if let Some(data) = option.get_long() {
let tooltip = get_tooltip(option.help, data); let tooltip = get_tooltip(option.get_help(), data);
completions.push_str(&preamble); completions.push_str(&preamble);
completions.push_str( completions.push_str(
@ -113,8 +113,8 @@ fn generate_inner<'b>(
} }
for flag in PowerShell::flags(p) { for flag in PowerShell::flags(p) {
if let Some(data) = flag.short { if let Some(data) = flag.get_short() {
let tooltip = get_tooltip(flag.help, data); let tooltip = get_tooltip(flag.get_help(), data);
completions.push_str(&preamble); completions.push_str(&preamble);
completions.push_str( completions.push_str(
@ -126,8 +126,8 @@ fn generate_inner<'b>(
); );
} }
if let Some(data) = flag.long { if let Some(data) = flag.get_long() {
let tooltip = get_tooltip(flag.help, data); let tooltip = get_tooltip(flag.get_help(), data);
completions.push_str(&preamble); completions.push_str(&preamble);
completions.push_str( completions.push_str(
@ -140,9 +140,9 @@ fn generate_inner<'b>(
} }
} }
for subcommand in subcommands!(p) { for subcommand in p.get_subcommands() {
let data = &subcommand.name; let data = &subcommand.get_name();
let tooltip = get_tooltip(subcommand.about, data); let tooltip = get_tooltip(subcommand.get_about(), data);
completions.push_str(&preamble); completions.push_str(&preamble);
completions.push_str( completions.push_str(
@ -162,7 +162,7 @@ fn generate_inner<'b>(
&command_name, completions &command_name, completions
); );
for subcommand in &p.subcommands { for subcommand in p.get_subcommands() {
let subcommand_subcommands_cases = generate_inner(&subcommand, &command_name, names); let subcommand_subcommands_cases = generate_inner(&subcommand, &command_name, names);
subcommands_cases.push_str(&subcommand_subcommands_cases); subcommands_cases.push_str(&subcommand_subcommands_cases);
} }

View file

@ -149,7 +149,7 @@ fn subcommands_of(p: &App) -> String {
"\"{name}:{help}\" \\", "\"{name}:{help}\" \\",
name = n, name = n,
help = sc help = sc
.about .get_about()
.unwrap_or("") .unwrap_or("")
.replace("[", "\\[") .replace("[", "\\[")
.replace("]", "\\]") .replace("]", "\\]")
@ -161,15 +161,13 @@ fn subcommands_of(p: &App) -> String {
} }
// The subcommands // The subcommands
for sc in subcommands!(p) { for sc in p.get_subcommands() {
debugln!("Zsh::subcommands_of:iter: subcommand={}", sc.name); debugln!("Zsh::subcommands_of:iter: subcommand={}", sc.get_name());
add_sc(sc, &sc.name, &mut ret); add_sc(sc, &sc.get_name(), &mut ret);
if let Some(ref v) = sc.aliases { for alias in sc.get_visible_aliases() {
for alias in v.iter().filter(|&&(_, vis)| vis).map(|&(n, _)| n) { add_sc(sc, alias, &mut ret);
add_sc(sc, alias, &mut ret);
}
} }
} }
@ -248,7 +246,7 @@ fn get_subcommands_of(p: &App) -> String {
esac esac
;; ;;
esac", esac",
name = p.name, name = p.get_name(),
name_hyphen = p.get_bin_name().unwrap().replace(" ", "-"), name_hyphen = p.get_bin_name().unwrap().replace(" ", "-"),
subcommands = subcmds.join("\n"), subcommands = subcmds.join("\n"),
pos = positionals!(p).count() + 1 pos = positionals!(p).count() + 1
@ -297,14 +295,14 @@ fn get_args_of(p: &App) -> String {
let sc_or_a = if p.has_subcommands() { let sc_or_a = if p.has_subcommands() {
format!( format!(
"\":: :_{name}_commands\" \\", "\":: :_{name}_commands\" \\",
name = p.bin_name.as_ref().unwrap().replace(" ", "__") name = p.get_bin_name().as_ref().unwrap().replace(" ", "__")
) )
} else { } else {
String::new() String::new()
}; };
let sc = if p.has_subcommands() { let sc = if p.has_subcommands() {
format!("\"*::: :->{name}\" \\", name = p.name) format!("\"*::: :->{name}\" \\", name = p.get_name())
} else { } else {
String::new() String::new()
}; };
@ -358,16 +356,10 @@ fn write_opts_of(p: &App) -> String {
let mut ret = vec![]; let mut ret = vec![];
for o in opts!(p) { for o in opts!(p) {
debugln!("Zsh::write_opts_of:iter: o={}", o.name); debugln!("Zsh::write_opts_of:iter: o={}", o.get_name());
let help = o.help.map_or(String::new(), escape_help); let help = o.get_help().map_or(String::new(), escape_help);
let mut conflicts = get_zsh_arg_conflicts!(p, o, INTERNAL_ERROR_MSG); let conflicts = arg_conflicts(p, o);
conflicts = if conflicts.is_empty() {
String::new()
} else {
format!("({})", conflicts)
};
// @TODO @soundness should probably be either multiple occurrences or multiple values and // @TODO @soundness should probably be either multiple occurrences or multiple values and
// not both // not both
@ -379,7 +371,7 @@ fn write_opts_of(p: &App) -> String {
"" ""
}; };
let pv = if let Some(ref pv_vec) = o.possible_vals { let pv = if let Some(ref pv_vec) = o.get_possible_values() {
format!( format!(
": :({})", ": :({})",
pv_vec pv_vec
@ -392,7 +384,7 @@ fn write_opts_of(p: &App) -> String {
String::new() String::new()
}; };
if let Some(short) = o.short { if let Some(short) = o.get_short() {
let s = format!( let s = format!(
"'{conflicts}{multiple}-{arg}+[{help}]{possible_values}' \\", "'{conflicts}{multiple}-{arg}+[{help}]{possible_values}' \\",
conflicts = conflicts, conflicts = conflicts,
@ -406,7 +398,7 @@ fn write_opts_of(p: &App) -> String {
ret.push(s); ret.push(s);
} }
if let Some(long) = o.long { if let Some(long) = o.get_long() {
let l = format!( let l = format!(
"'{conflicts}{multiple}--{arg}=[{help}]{possible_values}' \\", "'{conflicts}{multiple}--{arg}=[{help}]{possible_values}' \\",
conflicts = conflicts, conflicts = conflicts,
@ -424,22 +416,37 @@ fn write_opts_of(p: &App) -> String {
ret.join("\n") ret.join("\n")
} }
fn arg_conflicts(app: &App, arg: &Arg) -> String {
let conflicts = app.get_arg_conflicts_with(arg);
if conflicts.is_empty() {
return String::new();
}
let mut res = vec![];
for conflict in conflicts {
if let Some(s) = conflict.get_short() {
res.push(format!("-{}", s));
}
if let Some(l) = conflict.get_long() {
res.push(format!("--{}", l));
}
}
format!("({})", res.join(" "))
}
fn write_flags_of(p: &App) -> String { fn write_flags_of(p: &App) -> String {
debugln!("Zsh::write_flags_of;"); debugln!("Zsh::write_flags_of;");
let mut ret = vec![]; let mut ret = vec![];
for f in Zsh::flags(p) { for f in Zsh::flags(p) {
debugln!("Zsh::write_flags_of:iter: f={}", f.name); debugln!("Zsh::write_flags_of:iter: f={}", f.get_name());
let help = f.help.map_or(String::new(), escape_help); let help = f.get_help().map_or(String::new(), escape_help);
let mut conflicts = get_zsh_arg_conflicts!(p, f, INTERNAL_ERROR_MSG); let conflicts = arg_conflicts(p, &f);
conflicts = if conflicts.is_empty() {
String::new()
} else {
format!("({})", conflicts)
};
let multiple = if f.is_set(ArgSettings::MultipleOccurrences) { let multiple = if f.is_set(ArgSettings::MultipleOccurrences) {
"*" "*"
@ -447,7 +454,7 @@ fn write_flags_of(p: &App) -> String {
"" ""
}; };
if let Some(short) = f.short { if let Some(short) = f.get_short() {
let s = format!( let s = format!(
"'{conflicts}{multiple}-{arg}[{help}]' \\", "'{conflicts}{multiple}-{arg}[{help}]' \\",
multiple = multiple, multiple = multiple,
@ -461,7 +468,7 @@ fn write_flags_of(p: &App) -> String {
ret.push(s); ret.push(s);
} }
if let Some(long) = f.long { if let Some(long) = f.get_long() {
let l = format!( let l = format!(
"'{conflicts}{multiple}--{arg}[{help}]' \\", "'{conflicts}{multiple}--{arg}[{help}]' \\",
conflicts = conflicts, conflicts = conflicts,
@ -485,7 +492,7 @@ fn write_positionals_of(p: &App) -> String {
let mut ret = vec![]; let mut ret = vec![];
for arg in positionals!(p) { for arg in positionals!(p) {
debugln!("Zsh::write_positionals_of:iter: arg={}", arg.name); debugln!("Zsh::write_positionals_of:iter: arg={}", arg.get_name());
let optional = if !arg.is_set(ArgSettings::Required) { let optional = if !arg.is_set(ArgSettings::Required) {
":" ":"
@ -496,16 +503,15 @@ fn write_positionals_of(p: &App) -> String {
let a = format!( let a = format!(
"'{optional}:{name}{help}:{action}' \\", "'{optional}:{name}{help}:{action}' \\",
optional = optional, optional = optional,
name = arg.name, name = arg.get_name(),
help = arg help = arg
.help .get_help()
.map_or("".to_owned(), |v| " -- ".to_owned() + v) .map_or("".to_owned(), |v| " -- ".to_owned() + v)
.replace("[", "\\[") .replace("[", "\\[")
.replace("]", "\\]") .replace("]", "\\]")
.replace(":", "\\:"), .replace(":", "\\:"),
action = arg action = arg
.possible_vals .get_possible_values()
.as_ref()
.map_or("_files".to_owned(), |values| { .map_or("_files".to_owned(), |values| {
format!( format!(
"({})", "({})",

View file

@ -178,7 +178,7 @@ where
G: Generator, G: Generator,
S: Into<String>, S: Into<String>,
{ {
app.bin_name = Some(bin_name.into()); app.set_bin_name(bin_name);
if !app.is_set(clap::AppSettings::Built) { if !app.is_set(clap::AppSettings::Built) {
app._build(); app._build();

View file

@ -7,30 +7,6 @@ macro_rules! w {
}; };
} }
macro_rules! get_zsh_arg_conflicts {
($app:expr, $arg:ident, $msg:ident) => {
if let Some(ref conf_vec) = $arg.blacklist {
let mut v = vec![];
for arg_name in conf_vec {
let arg = find!($app, arg_name).expect($msg);
if let Some(s) = arg.short {
v.push(format!("-{}", s));
}
if let Some(l) = arg.long {
v.push(format!("--{}", l));
}
}
v.join(" ")
} else {
String::new()
}
};
}
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
#[cfg_attr(feature = "debug", macro_use)] #[cfg_attr(feature = "debug", macro_use)]
#[cfg_attr(feature = "debug", allow(unused_macros))] #[cfg_attr(feature = "debug", allow(unused_macros))]
@ -70,18 +46,3 @@ mod debug_macros {
($fmt:expr, $($arg:tt)*) => {}; ($fmt:expr, $($arg:tt)*) => {};
} }
} }
macro_rules! find {
($app:expr, $name:expr, $what:ident) => {
$what!($app).find(|a| &a.name == $name)
};
($app:expr, $name:expr) => {
$app.args.args.iter().find(|a| {
if let Some(v) = a.index {
&v == $name
} else {
false
}
})
};
}

View file

@ -70,20 +70,16 @@ pub(crate) enum Propagation {
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
pub struct App<'b> { pub struct App<'b> {
pub(crate) id: Id, pub(crate) id: Id,
#[doc(hidden)] pub(crate) name: String,
pub name: String, pub(crate) bin_name: Option<String>,
#[doc(hidden)]
pub bin_name: Option<String>,
pub(crate) author: Option<&'b str>, pub(crate) author: Option<&'b str>,
pub(crate) version: Option<&'b str>, pub(crate) version: Option<&'b str>,
pub(crate) long_version: Option<&'b str>, pub(crate) long_version: Option<&'b str>,
#[doc(hidden)] pub(crate) about: Option<&'b str>,
pub about: Option<&'b str>,
pub(crate) long_about: Option<&'b str>, pub(crate) long_about: Option<&'b str>,
pub(crate) more_help: Option<&'b str>, pub(crate) more_help: Option<&'b str>,
pub(crate) pre_help: Option<&'b str>, pub(crate) pre_help: Option<&'b str>,
#[doc(hidden)] pub(crate) aliases: Option<Vec<(&'b str, bool)>>, // (name, visible)
pub aliases: Option<Vec<(&'b str, bool)>>, // (name, visible)
pub(crate) usage_str: Option<&'b str>, pub(crate) usage_str: Option<&'b str>,
pub(crate) usage: Option<String>, pub(crate) usage: Option<String>,
pub(crate) help_str: Option<&'b str>, pub(crate) help_str: Option<&'b str>,
@ -93,15 +89,88 @@ pub struct App<'b> {
pub(crate) template: Option<&'b str>, pub(crate) template: Option<&'b str>,
pub(crate) settings: AppFlags, pub(crate) settings: AppFlags,
pub(crate) g_settings: AppFlags, pub(crate) g_settings: AppFlags,
#[doc(hidden)] pub(crate) args: MKeyMap<'b>,
pub args: MKeyMap<'b>, pub(crate) subcommands: Vec<App<'b>>,
#[doc(hidden)]
pub subcommands: Vec<App<'b>>,
pub(crate) replacers: HashMap<&'b str, &'b [&'b str]>, pub(crate) replacers: HashMap<&'b str, &'b [&'b str]>,
pub(crate) groups: Vec<ArgGroup<'b>>, pub(crate) groups: Vec<ArgGroup<'b>>,
pub(crate) help_headings: Vec<Option<&'b str>>, pub(crate) help_headings: Vec<Option<&'b str>>,
} }
impl<'b> App<'b> {
/// Get the name of the app
pub fn get_name(&self) -> &str {
&self.name
}
/// Get the name of the binary
pub fn get_bin_name(&self) -> Option<&str> {
self.bin_name.as_deref()
}
/// Set binary name. Uses `&mut self` instead of `self`
pub fn set_bin_name<S: Into<String>>(&mut self, name: S) {
self.bin_name = Some(name.into());
}
/// Get the help message specified via [`App::about`]
pub fn get_about(&self) -> Option<&str> {
self.about.as_deref()
}
/// Iterate through the *visible* aliases for this subcommand.
pub fn get_visible_aliases(&self) -> impl Iterator<Item = &str> {
self.aliases
.as_ref()
.into_iter()
.flat_map(|aliases| aliases.iter().filter(|(_, vis)| *vis).map(|a| a.0))
}
/// Iterate through the set of *all* the aliases for this subcommand, both visible and hidden.
pub fn get_all_aliases(&self) -> impl Iterator<Item = &str> {
self.aliases
.as_ref()
.into_iter()
.flat_map(|aliases| aliases.iter().map(|a| a.0))
}
/// Get the list of subcommands
pub fn get_subcommands(&self) -> &[App<'b>] {
&self.subcommands
}
/// Get the list of subcommands
pub fn get_subcommands_mut(&mut self) -> &mut [App<'b>] {
&mut self.subcommands
}
/// Get the list of arguments
pub fn get_arguments(&self) -> &[Arg<'b>] {
&self.args.args
}
/// Get the list of arguments the given argument conflicts with
///
/// ### Panics
///
/// Panics if the given arg conflicts with an argument that is unknown to this application
pub fn get_arg_conflicts_with<'a, 'x, 'y>(&'a self, arg: &'x Arg<'y>) -> Vec<&Arg<'b>> // FIXME: This could probably have been an iterator
{
if let Some(black_ids) = arg.blacklist.as_ref() {
black_ids
.iter()
.map(|id| {
self.args.args.iter().find(|arg| arg.id == *id).expect(
"App::get_arg_conflicts_with: \
The passed arg conflicts with an arg unknown to the app",
)
})
.collect()
} else {
vec![]
}
}
}
impl<'b> App<'b> { impl<'b> App<'b> {
/// Creates a new instance of an application requiring a name. The name may be, but doesn't /// Creates a new instance of an application requiring a name. The name may be, but doesn't
/// have to be, same as the binary. The name will be displayed to the user when they request to /// have to be, same as the binary. The name will be displayed to the user when they request to
@ -125,16 +194,6 @@ impl<'b> App<'b> {
} }
} }
/// Get the name of the app
pub fn get_name(&self) -> &str {
&self.name
}
/// Get the name of the binary
pub fn get_bin_name(&self) -> Option<&str> {
self.bin_name.as_deref()
}
/// Sets a string of author(s) that will be displayed to the user when they /// Sets a string of author(s) that will be displayed to the user when they
/// request the help information with `--help` or `-h`. /// request the help information with `--help` or `-h`.
/// ///
@ -1715,7 +1774,7 @@ impl<'b> App<'b> {
} }
if self.has_subcommands() if self.has_subcommands()
&& !self.is_set(AppSettings::DisableHelpSubcommand) && !self.is_set(AppSettings::DisableHelpSubcommand)
&& !subcommands!(self).any(|s| s.id == HELP_HASH) && !self.subcommands.iter().any(|s| s.id == HELP_HASH)
{ {
debugln!("App::_create_help_and_version: Building help"); debugln!("App::_create_help_and_version: Building help");
self.subcommands.push( self.subcommands.push(
@ -1738,14 +1797,16 @@ impl<'b> App<'b> {
{ {
a.disp_ord = i; a.disp_ord = i;
} }
for (i, mut sc) in &mut subcommands!(self, iter_mut) for (i, mut sc) in &mut self
.subcommands
.iter_mut()
.enumerate() .enumerate()
.filter(|&(_, ref sc)| sc.disp_ord == 999) .filter(|&(_, ref sc)| sc.disp_ord == 999)
{ {
sc.disp_ord = i; sc.disp_ord = i;
} }
} }
for sc in subcommands!(self, iter_mut) { for sc in &mut self.subcommands {
sc._derive_display_order(); sc._derive_display_order();
} }
} }
@ -1754,7 +1815,7 @@ impl<'b> App<'b> {
#[doc(hidden)] #[doc(hidden)]
pub fn _build_bin_names(&mut self) { pub fn _build_bin_names(&mut self) {
debugln!("App::_build_bin_names;"); debugln!("App::_build_bin_names;");
for mut sc in subcommands!(self, iter_mut) { for mut sc in &mut self.subcommands {
debug!("Parser::build_bin_names:iter: bin_name set..."); debug!("Parser::build_bin_names:iter: bin_name set...");
if sc.bin_name.is_none() { if sc.bin_name.is_none() {
sdebugln!("No"); sdebugln!("No");
@ -1880,7 +1941,8 @@ impl<'b> App<'b> {
} }
pub(crate) fn has_visible_subcommands(&self) -> bool { pub(crate) fn has_visible_subcommands(&self) -> bool {
subcommands!(self) self.subcommands
.iter()
.filter(|sc| sc.name != "help") .filter(|sc| sc.name != "help")
.any(|sc| !sc.is_set(AppSettings::Hidden)) .any(|sc| !sc.is_set(AppSettings::Hidden))
} }

View file

@ -56,28 +56,22 @@ type Id = u64;
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub struct Arg<'help> { pub struct Arg<'help> {
pub(crate) id: Id, pub(crate) id: Id,
#[doc(hidden)] pub(crate) name: &'help str,
pub name: &'help str, pub(crate) help: Option<&'help str>,
#[doc(hidden)]
pub help: Option<&'help str>,
pub(crate) long_help: Option<&'help str>, pub(crate) long_help: Option<&'help str>,
#[doc(hidden)] pub(crate) blacklist: Option<Vec<Id>>,
pub blacklist: Option<Vec<Id>>,
pub(crate) settings: ArgFlags, pub(crate) settings: ArgFlags,
pub(crate) overrides: Option<Vec<Id>>, pub(crate) overrides: Option<Vec<Id>>,
pub(crate) groups: Option<Vec<Id>>, pub(crate) groups: Option<Vec<Id>>,
pub(crate) requires: Option<Vec<(Option<&'help str>, Id)>>, pub(crate) requires: Option<Vec<(Option<&'help str>, Id)>>,
pub(crate) r_ifs: Option<Vec<(Id, &'help str)>>, pub(crate) r_ifs: Option<Vec<(Id, &'help str)>>,
pub(crate) r_unless: Option<Vec<Id>>, pub(crate) r_unless: Option<Vec<Id>>,
#[doc(hidden)] pub(crate) short: Option<char>,
pub short: Option<char>, pub(crate) long: Option<&'help str>,
#[doc(hidden)]
pub long: Option<&'help str>,
pub(crate) aliases: Option<Vec<(&'help str, bool)>>, // (name, visible) pub(crate) aliases: Option<Vec<(&'help str, bool)>>, // (name, visible)
pub(crate) disp_ord: usize, pub(crate) disp_ord: usize,
pub(crate) unified_ord: usize, pub(crate) unified_ord: usize,
#[doc(hidden)] pub(crate) possible_vals: Option<Vec<&'help str>>,
pub possible_vals: Option<Vec<&'help str>>,
pub(crate) val_names: Option<VecMap<&'help str>>, pub(crate) val_names: Option<VecMap<&'help str>>,
pub(crate) num_vals: Option<u64>, pub(crate) num_vals: Option<u64>,
pub(crate) max_vals: Option<u64>, pub(crate) max_vals: Option<u64>,
@ -89,14 +83,50 @@ pub struct Arg<'help> {
pub(crate) default_vals_ifs: Option<VecMap<(Id, Option<&'help OsStr>, &'help OsStr)>>, pub(crate) default_vals_ifs: Option<VecMap<(Id, Option<&'help OsStr>, &'help OsStr)>>,
pub(crate) env: Option<(&'help OsStr, Option<OsString>)>, pub(crate) env: Option<(&'help OsStr, Option<OsString>)>,
pub(crate) terminator: Option<&'help str>, pub(crate) terminator: Option<&'help str>,
#[doc(hidden)] pub(crate) index: Option<u64>,
pub index: Option<u64>, pub(crate) help_heading: Option<&'help str>,
#[doc(hidden)]
pub help_heading: Option<&'help str>,
pub(crate) global: bool, pub(crate) global: bool,
pub(crate) exclusive: bool, pub(crate) exclusive: bool,
} }
/// Getters
impl<'help> Arg<'help> {
/// Get the name o the argument
pub fn get_name(&self) -> &str {
&self.name
}
/// Get the help specified for this argument, if any
pub fn get_help(&self) -> Option<&str> {
self.help
}
/// Get the help heading specified for this argument, if any
pub fn get_help_heading(&self) -> Option<&str> {
self.help_heading
}
/// Get the short option name for this argument, if any
pub fn get_short(&self) -> Option<char> {
self.short
}
/// Get the long option name for this argument, if any
pub fn get_long(&self) -> Option<&str> {
self.long
}
/// Get the list of the possible values for this argument, if any
pub fn get_possible_values(&self) -> Option<&[&str]> {
self.possible_vals.as_deref()
}
/// Get the index of this argument, if any
pub fn get_index(&self) -> Option<u64> {
self.index
}
}
impl<'help> Arg<'help> { impl<'help> Arg<'help> {
/// @TODO @p2 @docs @v3-beta1: Write Docs /// @TODO @p2 @docs @v3-beta1: Write Docs
pub fn new<T: Key>(t: T) -> Self { pub fn new<T: Key>(t: T) -> Self {

View file

@ -929,11 +929,10 @@ macro_rules! write_nspaces {
#[doc(hidden)] #[doc(hidden)]
macro_rules! flags { macro_rules! flags {
($app:expr, $how:ident) => {{ ($app:expr, $how:ident) => {{
$app.args $app.get_arguments()
.args
.$how() .$how()
.filter(|a| !a.is_set($crate::ArgSettings::TakesValue) && a.index.is_none()) .filter(|a| !a.is_set($crate::ArgSettings::TakesValue) && a.get_index().is_none())
.filter(|a| !a.help_heading.is_some()) .filter(|a| !a.get_help_heading().is_some())
}}; }};
($app:expr) => { ($app:expr) => {
$crate::flags!($app, iter) $crate::flags!($app, iter)
@ -944,11 +943,10 @@ macro_rules! flags {
#[doc(hidden)] #[doc(hidden)]
macro_rules! opts { macro_rules! opts {
($app:expr, $how:ident) => {{ ($app:expr, $how:ident) => {{
$app.args $app.get_arguments()
.args
.$how() .$how()
.filter(|a| a.is_set($crate::ArgSettings::TakesValue) && a.index.is_none()) .filter(|a| a.is_set($crate::ArgSettings::TakesValue) && a.get_index().is_none())
.filter(|a| !a.help_heading.is_some()) .filter(|a| !a.get_help_heading().is_some())
}}; }};
($app:expr) => { ($app:expr) => {
opts!($app, iter) opts!($app, iter)
@ -958,26 +956,11 @@ macro_rules! opts {
#[macro_export] #[macro_export]
#[doc(hidden)] #[doc(hidden)]
macro_rules! positionals { macro_rules! positionals {
($app:expr, $how:ident) => {{ ($app:expr) => {{
$app.args $app.get_arguments()
.args .iter()
.$how() .filter(|a| !(a.get_short().is_some() || a.get_long().is_some()))
.filter(|a| !(a.short.is_some() || a.long.is_some()))
}}; }};
($app:expr) => {
positionals!($app, iter)
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! subcommands {
($app:expr, $how:ident) => {
$app.subcommands.$how()
};
($app:expr) => {
subcommands!($app, iter)
};
} }
macro_rules! groups_for_arg { macro_rules! groups_for_arg {
@ -992,21 +975,30 @@ macro_rules! groups_for_arg {
macro_rules! find_subcmd_cloned { macro_rules! find_subcmd_cloned {
($app:expr, $sc:expr) => {{ ($app:expr, $sc:expr) => {{
subcommands!($app) $app.get_subcommands()
.iter()
.cloned() .cloned()
.find(|a| match_alias!(a, $sc, &*a.name)) .find(|a| match_alias!(a, $sc, a.get_name()))
}}; }};
} }
#[macro_export] #[macro_export]
#[doc(hidden)] #[doc(hidden)]
macro_rules! find_subcmd { macro_rules! find_subcmd {
($app:expr, $sc:expr, $how:ident) => {{ ($app:expr, $sc:expr) => {{
subcommands!($app, $how).find(|a| match_alias!(a, $sc, &*a.name)) $app.get_subcommands()
.iter()
.find(|a| match_alias!(a, $sc, a.get_name()))
}};
}
#[macro_export]
#[doc(hidden)]
macro_rules! find_subcmd_mut {
($app:expr, $sc:expr) => {{
$app.get_subcommands_mut()
.find(|a| match_alias!(a, $sc, a.get_name()))
}}; }};
($app:expr, $sc:expr) => {
find_subcmd!($app, $sc, iter)
};
} }
macro_rules! longs { macro_rules! longs {
@ -1029,11 +1021,11 @@ macro_rules! longs {
#[doc(hidden)] #[doc(hidden)]
macro_rules! names { macro_rules! names {
(@args $app:expr) => {{ (@args $app:expr) => {{
$app.args.args.iter().map(|a| &*a.name) $app.get_arguments().iter().map(|a| &*a.get_name())
}}; }};
(@sc $app:expr) => {{ (@sc $app:expr) => {{
$app.subcommands.iter().map(|s| &*s.name).chain( $app.get_subcommands().iter().map(|s| &*s.get_name()).chain(
$app.subcommands $app.get_subcommands()
.iter() .iter()
.filter(|s| s.aliases.is_some()) .filter(|s| s.aliases.is_some())
.flat_map(|s| s.aliases.as_ref().unwrap().iter().map(|&(n, _)| n)), .flat_map(|s| s.aliases.as_ref().unwrap().iter().map(|&(n, _)| n)),
@ -1053,13 +1045,6 @@ macro_rules! sc_names {
#[doc(hidden)] #[doc(hidden)]
macro_rules! match_alias { macro_rules! match_alias {
($a:expr, $to:expr, $what:expr) => {{ ($a:expr, $to:expr, $what:expr) => {{
$what == $to $what == $to || $a.get_all_aliases().any(|alias| alias == $to)
|| ($a.aliases.is_some()
&& $a
.aliases
.as_ref()
.unwrap()
.iter()
.any(|alias| alias.0 == $to))
}}; }};
} }

View file

@ -747,7 +747,11 @@ impl<'b, 'c, 'd, 'w> Help<'b, 'c, 'd, 'w> {
// The shortest an arg can legally be is 2 (i.e. '-x') // The shortest an arg can legally be is 2 (i.e. '-x')
self.longest = 2; self.longest = 2;
let mut ord_m = VecMap::new(); let mut ord_m = VecMap::new();
for sc in subcommands!(app).filter(|s| !s.is_set(AppSettings::Hidden)) { for sc in app
.subcommands
.iter()
.filter(|s| !s.is_set(AppSettings::Hidden))
{
let btm = ord_m.entry(sc.disp_ord).or_insert(BTreeMap::new()); let btm = ord_m.entry(sc.disp_ord).or_insert(BTreeMap::new());
self.longest = cmp::max(self.longest, str_width(sc.name.as_str())); self.longest = cmp::max(self.longest, str_width(sc.name.as_str()));
btm.insert(sc.name.clone(), sc.clone()); btm.insert(sc.name.clone(), sc.clone());

View file

@ -642,7 +642,14 @@ where
.count(); .count();
} }
if let Some(p) = positionals!(self.app).find(|p| p.index == Some(pos_counter as u64)) { if let Some(p) = self
.app
.args
.args
.iter()
.filter(|a| a.short.is_none() && a.long.is_none())
.find(|p| p.index == Some(pos_counter as u64))
{
if p.is_set(ArgSettings::Last) && !self.is_set(AS::TrailingValues) { if p.is_set(ArgSettings::Last) && !self.is_set(AS::TrailingValues) {
return Err(ClapError::unknown_argument( return Err(ClapError::unknown_argument(
&*arg_os.to_string_lossy(), &*arg_os.to_string_lossy(),
@ -984,7 +991,7 @@ where
self.app._propagate(Propagation::To(id)); self.app._propagate(Propagation::To(id));
} }
if let Some(sc) = subcommands!(self.app, iter_mut).find(|s| s.name == sc_name) { if let Some(sc) = self.app.subcommands.iter_mut().find(|s| s.name == sc_name) {
let mut sc_matcher = ArgMatcher::default(); let mut sc_matcher = ArgMatcher::default();
// bin_name should be parent's bin_name + [<reqs>] + the sc's name separated by // bin_name should be parent's bin_name + [<reqs>] + the sc's name separated by
// a space // a space
@ -1091,7 +1098,7 @@ where
self.app.long_about.is_some() self.app.long_about.is_some()
|| self.app.args.args.iter().any(|f| should_long(&f)) || self.app.args.args.iter().any(|f| should_long(&f))
|| subcommands!(self.app).any(|s| s.long_about.is_some()) || self.app.subcommands.iter().any(|s| s.long_about.is_some())
} }
fn parse_long_arg( fn parse_long_arg(

View file

@ -65,7 +65,7 @@ fn quoted_app_name() {
(@arg scpositional: index(1) "tests positionals")) (@arg scpositional: index(1) "tests positionals"))
); );
assert_eq!(app.name, "app name with spaces-and-hyphens"); assert_eq!(app.get_name(), "app name with spaces-and-hyphens");
let mut help_text = vec![]; let mut help_text = vec![];
app.write_help(&mut help_text) app.write_help(&mut help_text)