mirror of
https://github.com/clap-rs/clap
synced 2024-11-10 06:44:16 +00:00
Issues rollup (#637)
* feat: adds App::with_defaults to automatically use crate_authors! and crate_version! macros One can now use ```rust let a = App::with_defaults("My Program"); // same as let a2 = App::new("My Program") .version(crate_version!()) .author(crate_authors!()); ``` Closes #600 * imp(YAML Errors): vastly improves error messages when using YAML When errors are made while developing, the panic error messages have been improved instead of relying on the default panic message which is extremely unhelpful. Closes #574 * imp(Completions): uses standard conventions for bash completion files, namely '{bin}.bash-completion' Closes #567 * imp(Help): automatically moves help text to the next line and wraps when term width is determined to be too small, or help text is too long Now `clap` will check if it should automatically place long help messages on the next line after the flag/option. This is determined by checking to see if the space taken by flag/option plus spaces and values doesn't leave enough room for the entirety of the help message, with the single exception of of if the flag/option/spaces/values is less than 25% of the width. Closes #597 * tests: updates help tests to new forced new line rules * fix(Groups): fixes some usage strings that contain both args in groups and ones that conflict with each other Args that conflict *and* are in a group will now only display in the group and not in the usage string itself. Closes #616 * chore: updates dep graph Closes #633 * chore: clippy run * style: changes debug header to match other Rust projects * chore: increase version
This commit is contained in:
parent
13fe03b033
commit
b7793a2f4d
16 changed files with 298 additions and 210 deletions
24
CHANGELOG.md
24
CHANGELOG.md
|
@ -1,3 +1,27 @@
|
|||
<a name="v2.11.0"></a>
|
||||
### v2.11.0 (2016-08-28)
|
||||
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* **Groups:** fixes some usage strings that contain both args in groups and ones that conflict with each other ([3d782def](https://github.com/kbknapp/clap-rs/commit/3d782def57725e2de26ca5a5bc5cc2e40ddebefb), closes [#616](https://github.com/kbknapp/clap-rs/issues/616))
|
||||
|
||||
#### Documentation
|
||||
|
||||
* moves docs to docs.rs ([03209d5e](https://github.com/kbknapp/clap-rs/commit/03209d5e1300906f00bafec1869c2047a92e5071), closes [#634](https://github.com/kbknapp/clap-rs/issues/634))
|
||||
|
||||
#### Improvements
|
||||
|
||||
* **Completions:** uses standard conventions for bash completion files, namely '{bin}.bash-completion' ([27f5bbfb](https://github.com/kbknapp/clap-rs/commit/27f5bbfbcc9474c2f57c2b92b1feb898ae46ee70), closes [#567](https://github.com/kbknapp/clap-rs/issues/567))
|
||||
* **Help:** automatically moves help text to the next line and wraps when term width is determined to be too small, or help text is too long ([150964c4](https://github.com/kbknapp/clap-rs/commit/150964c4e7124d54476c9d9b4b3f2406f0fd00e5), closes [#597](https://github.com/kbknapp/clap-rs/issues/597))
|
||||
* **YAML Errors:** vastly improves error messages when using YAML ([f43b7c65](https://github.com/kbknapp/clap-rs/commit/f43b7c65941c53adc0616b8646a21dc255862eb2), closes [#574](https://github.com/kbknapp/clap-rs/issues/574))
|
||||
|
||||
#### Features
|
||||
|
||||
* adds App::with_defaults to automatically use crate_authors! and crate_version! macros ([5520bb01](https://github.com/kbknapp/clap-rs/commit/5520bb012c127dfd299fd55699443c744d8dcd5b), closes [#600](https://github.com/kbknapp/clap-rs/issues/600))
|
||||
|
||||
|
||||
|
||||
<a name="v2.10.4"></a>
|
||||
### v2.10.4 (2016-08-25)
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
|
||||
name = "clap"
|
||||
version = "2.10.4"
|
||||
version = "2.11.0"
|
||||
authors = ["Kevin K. <kbknapp@gmail.com>"]
|
||||
exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"]
|
||||
repository = "https://github.com/kbknapp/clap-rs.git"
|
||||
|
@ -21,7 +21,7 @@ libc = { version = "~0.2.9", optional = true }
|
|||
ansi_term = { version = "~0.8.0", optional = true }
|
||||
strsim = { version = "~0.5.1", optional = true }
|
||||
yaml-rust = { version = "~0.3.2", optional = true }
|
||||
clippy = { version = "~0.0.79", optional = true }
|
||||
clippy = { version = "~0.0.85", optional = true }
|
||||
unicode-width = "~0.1.3"
|
||||
unicode-segmentation = "~0.1.2"
|
||||
term_size = { version = "~0.1.0", optional = true }
|
||||
|
|
11
README.md
11
README.md
|
@ -39,6 +39,17 @@ Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc)
|
|||
|
||||
## What's New
|
||||
|
||||
Here's the highlights for v2.11.0
|
||||
|
||||
* Adds the ability to wrap help text intelligently on Windows!
|
||||
* Moves docs to [docs.rs!](https://docs.rs/clap/)
|
||||
* Fixes some usage strings that contain both args in groups and ones that conflict with each other
|
||||
* Uses standard conventions for bash completion files, namely `{bin}.bash-completion`
|
||||
* Automatically moves help text to the next line and wraps when term width is determined to be too small, or help text is too long
|
||||
* Vastly improves *development* error messages when using YAML
|
||||
* Adds `App::with_defaults` to automatically use `crate_authors!` and `crate_version!` macros
|
||||
* Other minor improvements and bug fixes
|
||||
|
||||
Here's the highlights for v2.10.4
|
||||
|
||||
* Fixes a bug where help is wrapped incorrectly and causing a panic with some non-English characters
|
||||
|
|
|
@ -1,55 +1,41 @@
|
|||
digraph dependencies {
|
||||
N0[label="clap"];
|
||||
N1[label="ansi_term",style=dashed];
|
||||
N1[label="ansi_term"];
|
||||
N2[label="bitflags"];
|
||||
N3[label="clippy",color=blue,style=dashed];
|
||||
N4[label="libc",style=dashed];
|
||||
N5[label="strsim",style=dashed];
|
||||
N6[label="unicode-width",style=dashed];
|
||||
N7[label="vec_map"];
|
||||
N8[label="yaml-rust",style=dashed,color=red];
|
||||
N10[label="aho-corasick",color=blue,style=dashed];
|
||||
N11[label="memchr",color=blue,style=dashed];
|
||||
N12[label="regex",color=blue,style=dashed];
|
||||
N13[label="quine-mc_cluskey",color=blue,style=dashed];
|
||||
N14[label="regex-syntax",color=blue,style=dashed];
|
||||
N15[label="semver",color=blue,style=dashed];
|
||||
N16[label="toml",color=blue,style=dashed];
|
||||
N17[label="unicode-normalization",color=blue,style=dashed];
|
||||
N18[label="kernel32-sys",color=blue,style=dashed];
|
||||
N19[label="winapi",color=blue,style=dashed];
|
||||
N20[label="winapi-build",color=blue,style=dashed];
|
||||
N21[label="nom",color=blue,style=dashed];
|
||||
N22[label="thread_local",color=blue,style=dashed];
|
||||
N23[label="utf8-ranges",color=blue,style=dashed];
|
||||
N24[label="rustc-serialize",color=blue,style=dashed];
|
||||
N25[label="thread-id"color=blue,style=dashed];
|
||||
N3[label="clippy",color=blue];
|
||||
N4[label="strsim"];
|
||||
N5[label="term_size"];
|
||||
N6[label="unicode-segmentation"];
|
||||
N7[label="unicode-width"];
|
||||
N8[label="vec_map"];
|
||||
N9[label="yaml-rust",color=red];
|
||||
N10[label="clippy_lints",color=blue];
|
||||
N11[label="matches",color=blue];
|
||||
N12[label="quine-mc_cluskey",color=blue];
|
||||
N13[label="regex-syntax",color=red];
|
||||
N14[label="rustc-serialize",color=blue];
|
||||
N15[label="semver",color=blue];
|
||||
N16[label="toml",color=blue];
|
||||
N17[label="unicode-normalization",color=blue];
|
||||
N0 -> N1[label="",style=dashed];
|
||||
N0 -> N2[label=""];
|
||||
N0 -> N3[label="",style=dashed,color=blue];
|
||||
N0 -> N4[label="",style=dashed];
|
||||
N0 -> N5[label="",style=dashed];
|
||||
N0 -> N6[label="",style=dashed];
|
||||
N0 -> N6[label=""];
|
||||
N0 -> N7[label=""];
|
||||
N0 -> N8[label="",style=dashed,color=red];
|
||||
N0 -> N12[label="",style=dashed,color=blue];
|
||||
N3 -> N13[label="",style=dashed,color=blue];
|
||||
N3 -> N14[label="",style=dashed,color=blue];
|
||||
N3 -> N15[label="",style=dashed,color=blue];
|
||||
N3 -> N16[label="",style=dashed,color=blue];
|
||||
N3 -> N17[label="",style=dashed,color=blue];
|
||||
N0 -> N8[label=""];
|
||||
N0 -> N9[label="",style=dashed,color=red];
|
||||
N3 -> N10[label="",style=dashed,color=blue];
|
||||
N5 -> N3[label="",style=dashed,color=blue];
|
||||
N9 -> N3[label="",style=dashed,color=blue];
|
||||
N9 -> N13[label="",style=dashed,color=red];
|
||||
N10 -> N11[label="",style=dashed,color=blue];
|
||||
N11 -> N4[label="",style=dashed,color=blue];
|
||||
N12 -> N10[label="",style=dashed,color=blue];
|
||||
N12 -> N11[label="",style=dashed,color=blue];
|
||||
N12 -> N14[label="",style=dashed,color=blue];
|
||||
N12 -> N22[label="",style=dashed,color=blue];
|
||||
N12 -> N23[label="",style=dashed,color=blue];
|
||||
N15 -> N21[label="",style=dashed,color=blue];
|
||||
N16 -> N24[label="",style=dashed,color=blue];
|
||||
N18 -> N19[label="",style=dashed,color=blue];
|
||||
N18 -> N20[label="",style=dashed,color=blue];
|
||||
N22 -> N25[label="",style=dashed,color=blue];
|
||||
N25 -> N4[label="",style=dashed,color=blue];
|
||||
N25 -> N18[label="",style=dashed,color=blue];
|
||||
N10 -> N12[label="",style=dashed,color=blue];
|
||||
N10 -> N13[label="",style=dashed,color=blue];
|
||||
N10 -> N14[label="",style=dashed,color=blue];
|
||||
N10 -> N15[label="",style=dashed,color=blue];
|
||||
N10 -> N16[label="",style=dashed,color=blue];
|
||||
N10 -> N17[label="",style=dashed,color=blue];
|
||||
N16 -> N14[label="",style=dashed,color=blue];
|
||||
}
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 94 KiB |
|
@ -1,5 +1,5 @@
|
|||
name: yml_app
|
||||
version: 1.0
|
||||
version: "1.0"
|
||||
about: an example using a .yml file to build a CLI
|
||||
author: Kevin K. <kbknapp@gmail.com>
|
||||
|
||||
|
@ -69,7 +69,7 @@ subcommands:
|
|||
# Rust code later
|
||||
- subcmd:
|
||||
about: demos subcommands from yaml
|
||||
version: 0.1
|
||||
version: "0.1"
|
||||
author: Kevin K. <kbknapp@gmail.com>
|
||||
# Subcommand args are exactly like App args
|
||||
args:
|
||||
|
|
|
@ -339,8 +339,16 @@ impl<'a> Help<'a> {
|
|||
} else {
|
||||
try!(color!(self, "{}", arg, good));
|
||||
}
|
||||
|
||||
let spec_vals = self.spec_vals(arg);
|
||||
let h = arg.help().unwrap_or("");
|
||||
let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp);
|
||||
let width = self.term_w;
|
||||
let taken = (longest + 12) + str_width(&*spec_vals);
|
||||
let force_next_line = !nlh && width >= taken && str_width(h) > (width - taken) && (taken as f32 / width as f32) > 0.25;
|
||||
|
||||
if arg.has_switch() {
|
||||
if !(self.next_line_help || arg.is_set(ArgSettings::NextLineHelp)) {
|
||||
if !(nlh || force_next_line) {
|
||||
let self_len = arg.to_string().len();
|
||||
// subtract ourself
|
||||
let mut spcs = longest - self_len;
|
||||
|
@ -356,7 +364,7 @@ impl<'a> Help<'a> {
|
|||
|
||||
write_nspaces!(self.writer, spcs);
|
||||
}
|
||||
} else if !(self.next_line_help || arg.is_set(ArgSettings::NextLineHelp)) {
|
||||
} else if !(nlh || force_next_line) {
|
||||
write_nspaces!(self.writer, longest + 4 - (arg.to_string().len()));
|
||||
}
|
||||
Ok(())
|
||||
|
@ -416,19 +424,30 @@ impl<'a> Help<'a> {
|
|||
let spec_vals = self.spec_vals(arg);
|
||||
let mut help = String::new();
|
||||
let h = arg.help().unwrap_or("");
|
||||
let spcs = if self.next_line_help || arg.is_set(ArgSettings::NextLineHelp) {
|
||||
let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp);
|
||||
debugln!("Next Line...{:?}", nlh);
|
||||
|
||||
// determine if our help fits or needs to wrap
|
||||
let width = self.term_w;
|
||||
debugln!("Term width...{}", width);
|
||||
|
||||
// We calculate with longest+12 since if it's already NLH we don't care
|
||||
let taken = (longest + 12) + str_width(&*spec_vals);
|
||||
let force_next_line = !nlh && width >= taken && str_width(h) > (width - taken) && (taken as f32 / width as f32) > 0.25;
|
||||
debugln!("Force Next Line...{:?}", force_next_line);
|
||||
debugln!("Force Next Line math (help_len > (width - flags/opts/spcs))...{} > ({} - {})", str_width(h), width, taken);
|
||||
|
||||
let spcs = if nlh || force_next_line {
|
||||
8 // "tab" + "tab"
|
||||
} else {
|
||||
longest + 12
|
||||
};
|
||||
// determine if our help fits or needs to wrap
|
||||
let width = self.term_w;
|
||||
debugln!("Term width...{}", width);
|
||||
|
||||
let too_long = spcs + str_width(h) + str_width(&*spec_vals) >= width;
|
||||
debugln!("Spaces: {}", spcs);
|
||||
|
||||
// Is help on next line, if so newline + 2x tab
|
||||
if self.next_line_help || arg.is_set(ArgSettings::NextLineHelp) {
|
||||
if nlh || force_next_line {
|
||||
try!(write!(self.writer, "\n{}{}", TAB, TAB));
|
||||
}
|
||||
|
||||
|
@ -470,7 +489,7 @@ impl<'a> Help<'a> {
|
|||
}
|
||||
for part in help.split("{n}").skip(1) {
|
||||
try!(write!(self.writer, "\n"));
|
||||
if self.next_line_help || arg.is_set(ArgSettings::NextLineHelp) {
|
||||
if nlh || force_next_line {
|
||||
try!(write!(self.writer, "{}{}", TAB, TAB));
|
||||
} else if arg.has_switch() {
|
||||
write_nspaces!(self.writer, longest + 12);
|
||||
|
@ -916,6 +935,7 @@ impl<'a> Help<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "lints", allow(explicit_counter_loop))]
|
||||
fn wrap_help(help: &mut String, longest_w: usize, avail_chars: usize) {
|
||||
debugln!("fn=wrap_help;longest_w={},avail_chars={}", longest_w, avail_chars);
|
||||
debug!("Enough space to wrap...");
|
||||
|
|
147
src/app/mod.rs
147
src/app/mod.rs
|
@ -82,6 +82,27 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
App { p: Parser::with_name(n.into()) }
|
||||
}
|
||||
|
||||
/// Creates a new instance of an application requiring a name, but uses the [`crate_authors!`]
|
||||
/// and [`crate_version!`] macros to fill in the [`App::author`] and [`App::version`] fields.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use clap::{App, Arg};
|
||||
/// let prog = App::with_defaults("My Program")
|
||||
/// # ;
|
||||
/// ```
|
||||
/// [`crate_authors!`]: ./macro.crate_authors!.html
|
||||
/// [`crate_version!`]: ./macro.crate_version!.html
|
||||
/// [`App::author`]: ./struct.App.html#method.author
|
||||
/// [`App::version`]: ./struct.App.html#method.author
|
||||
pub fn with_defaults<S: Into<String>>(n: S) -> Self {
|
||||
let mut a = App { p: Parser::with_name(n.into()) };
|
||||
a.p.meta.author = Some(crate_authors!());
|
||||
a.p.meta.version = Some(crate_version!());
|
||||
a
|
||||
}
|
||||
|
||||
/// Creates a new instace of [`App`] from a .yml (YAML) file. A full example of supported YAML
|
||||
/// objects can be found in [`examples/17_yaml.rs`] and [`examples/17_yaml.yml`]. One great use
|
||||
/// for using YAML is when supporting multiple languages and dialects, as each language could
|
||||
|
@ -1060,9 +1081,11 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
/// env!("OUT_DIR")); // Then say where write the completions to
|
||||
/// }
|
||||
/// ```
|
||||
/// Now, once we combile there will be a `bash.sh` file in the directory. Assuming we compiled
|
||||
/// with debug mode, it would be somewhere similar to
|
||||
/// `<project>/target/debug/build/myapp-<hash>/out/myapp_bash.sh`
|
||||
/// Now, once we combile there will be a `{bin_name}.bash-completion` file in the directory.
|
||||
/// Assuming we compiled with debug mode, it would be somewhere similar to
|
||||
/// `<project>/target/debug/build/myapp-<hash>/out/myapp.bash-completion`.
|
||||
///
|
||||
/// Fish shell completions will use the file format `{bin_name}.fish`
|
||||
pub fn gen_completions<T: Into<OsString>, S: Into<String>>(&mut self, bin_name: S, for_shell: Shell, out_dir: T) {
|
||||
self.p.meta.bin_name = Some(bin_name.into());
|
||||
self.p.gen_completions(for_shell, out_dir.into());
|
||||
|
@ -1324,54 +1347,57 @@ impl<'a> From<&'a Yaml> for App<'a, 'a> {
|
|||
} else {
|
||||
yaml
|
||||
};
|
||||
if let Some(v) = yaml["version"].as_str() {
|
||||
a = a.version(v);
|
||||
}
|
||||
if let Some(v) = yaml["author"].as_str() {
|
||||
a = a.author(v);
|
||||
}
|
||||
if let Some(v) = yaml["bin_name"].as_str() {
|
||||
a = a.bin_name(v);
|
||||
}
|
||||
if let Some(v) = yaml["about"].as_str() {
|
||||
a = a.about(v);
|
||||
}
|
||||
if let Some(v) = yaml["before_help"].as_str() {
|
||||
a = a.before_help(v);
|
||||
}
|
||||
if let Some(v) = yaml["template"].as_str() {
|
||||
a = a.template(v);
|
||||
}
|
||||
if let Some(v) = yaml["after_help"].as_str() {
|
||||
a = a.after_help(v);
|
||||
|
||||
macro_rules! yaml_str {
|
||||
($a:ident, $y:ident, $i:ident) => {
|
||||
if let Some(v) = $y[stringify!($i)].as_str() {
|
||||
$a = $a.$i(v);
|
||||
} else if $y[stringify!($i)] != Yaml::BadValue {
|
||||
panic!("Failed to convert YAML value {:?} to a string", $y[stringify!($i)]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
yaml_str!(a, yaml, version);
|
||||
yaml_str!(a, yaml, bin_name);
|
||||
yaml_str!(a, yaml, about);
|
||||
yaml_str!(a, yaml, before_help);
|
||||
yaml_str!(a, yaml, after_help);
|
||||
yaml_str!(a, yaml, template);
|
||||
yaml_str!(a, yaml, usage);
|
||||
yaml_str!(a, yaml, help);
|
||||
yaml_str!(a, yaml, help_short);
|
||||
yaml_str!(a, yaml, version_short);
|
||||
yaml_str!(a, yaml, alias);
|
||||
yaml_str!(a, yaml, visible_alias);
|
||||
|
||||
if let Some(v) = yaml["display_order"].as_i64() {
|
||||
a = a.display_order(v as usize);
|
||||
}
|
||||
if let Some(v) = yaml["usage"].as_str() {
|
||||
a = a.usage(v);
|
||||
}
|
||||
if let Some(v) = yaml["help"].as_str() {
|
||||
a = a.help(v);
|
||||
}
|
||||
if let Some(v) = yaml["help_short"].as_str() {
|
||||
a = a.help_short(v);
|
||||
}
|
||||
if let Some(v) = yaml["version_short"].as_str() {
|
||||
a = a.version_short(v);
|
||||
} else if yaml["display_order"] != Yaml::BadValue {
|
||||
panic!("Failed to convert YAML value {:?} to a u64", yaml["display_order"]);
|
||||
}
|
||||
if let Some(v) = yaml["setting"].as_str() {
|
||||
a = a.setting(v.parse().ok().expect("unknown AppSetting found in YAML file"));
|
||||
a = a.setting(v.parse().expect("unknown AppSetting found in YAML file"));
|
||||
} else if yaml["setting"] != Yaml::BadValue {
|
||||
panic!("Failed to convert YAML value {:?} to an AppSetting", yaml["setting"]);
|
||||
}
|
||||
if let Some(v) = yaml["settings"].as_vec() {
|
||||
for ys in v {
|
||||
if let Some(s) = ys.as_str() {
|
||||
a = a.setting(s.parse().ok().expect("unknown AppSetting found in YAML file"));
|
||||
a = a.setting(s.parse().expect("unknown AppSetting found in YAML file"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let Some(v) = yaml["settings"].as_str() {
|
||||
a = a.setting(v.parse().expect("unknown AppSetting found in YAML file"));
|
||||
} else if yaml["settings"] != Yaml::BadValue {
|
||||
panic!("Failed to convert YAML value {:?} to a string", yaml["settings"]);
|
||||
}
|
||||
}
|
||||
if let Some(v) = yaml["global_setting"].as_str() {
|
||||
a = a.setting(v.parse().ok().expect("unknown AppSetting found in YAML file"));
|
||||
} else if yaml["global_setting"] != Yaml::BadValue {
|
||||
panic!("Failed to convert YAML value {:?} to an AppSetting", yaml["setting"]);
|
||||
}
|
||||
if let Some(v) = yaml["global_settings"].as_vec() {
|
||||
for ys in v {
|
||||
|
@ -1379,27 +1405,40 @@ impl<'a> From<&'a Yaml> for App<'a, 'a> {
|
|||
a = a.global_setting(s.parse().ok().expect("unknown AppSetting found in YAML file"));
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(v) = yaml["alias"].as_str() {
|
||||
a = a.alias(v);
|
||||
}
|
||||
if let Some(v) = yaml["aliases"].as_vec() {
|
||||
for ys in v {
|
||||
if let Some(s) = ys.as_str() {
|
||||
a = a.alias(s);
|
||||
}
|
||||
} else {
|
||||
if let Some(v) = yaml["global_settings"].as_str() {
|
||||
a = a.global_setting(v.parse().expect("unknown AppSetting found in YAML file"));
|
||||
} else if yaml["global_settings"] != Yaml::BadValue {
|
||||
panic!("Failed to convert YAML value {:?} to a string", yaml["global_settings"]);
|
||||
}
|
||||
}
|
||||
if let Some(v) = yaml["visible_alias"].as_str() {
|
||||
a = a.visible_alias(v);
|
||||
}
|
||||
if let Some(v) = yaml["visible_aliases"].as_vec() {
|
||||
for ys in v {
|
||||
if let Some(s) = ys.as_str() {
|
||||
a = a.visible_alias(s);
|
||||
|
||||
macro_rules! vec_or_str {
|
||||
($a:ident, $y:ident, $as_vec:ident, $as_single:ident) => {{
|
||||
let maybe_vec = $y[stringify!($as_vec)].as_vec();
|
||||
if let Some(vec) = maybe_vec {
|
||||
for ys in vec {
|
||||
if let Some(s) = ys.as_str() {
|
||||
$a = $a.$as_single(s);
|
||||
} else {
|
||||
panic!("Failed to convert YAML value {:?} to a string", ys);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let Some(s) = $y[stringify!($as_vec)].as_str() {
|
||||
$a = $a.$as_single(s);
|
||||
} else if $y[stringify!($as_vec)] != Yaml::BadValue {
|
||||
panic!("Failed to convert YAML value {:?} to either a vec or string", $y[stringify!($as_vec)]);
|
||||
}
|
||||
}
|
||||
$a
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
a = vec_or_str!(a, yaml, aliases, alias);
|
||||
a = vec_or_str!(a, yaml, visible_aliases, visible_alias);
|
||||
|
||||
if let Some(v) = yaml["args"].as_vec() {
|
||||
for arg_yaml in v {
|
||||
a = a.arg(Arg::from_yaml(&arg_yaml.as_hash().unwrap()));
|
||||
|
|
|
@ -114,7 +114,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
|
||||
let out_dir = PathBuf::from(od);
|
||||
let suffix = match for_shell {
|
||||
Shell::Bash => "_bash.sh",
|
||||
Shell::Bash => ".bash-completion",
|
||||
Shell::Fish => ".fish",
|
||||
};
|
||||
|
||||
|
@ -371,17 +371,17 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
ret_val.push_back(s);
|
||||
}
|
||||
macro_rules! write_arg {
|
||||
($i:expr, $m:ident, $v:ident, $r:ident) => {
|
||||
($i:expr, $m:ident, $v:ident, $r:ident, $aig:ident) => {
|
||||
for f in $v.into_iter() {
|
||||
if $m.is_some() && $m.as_ref().unwrap().contains(f) {
|
||||
if $m.is_some() && $m.as_ref().unwrap().contains(f) || $aig.contains(&f) {
|
||||
continue;
|
||||
}
|
||||
$r.push_back($i.filter(|flg| &flg.name == &f).next().unwrap().to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
write_arg!(self.flags.iter(), matcher, c_flags, ret_val);
|
||||
write_arg!(self.opts.iter(), matcher, c_opt, ret_val);
|
||||
write_arg!(self.flags.iter(), matcher, c_flags, ret_val, args_in_groups);
|
||||
write_arg!(self.opts.iter(), matcher, c_opt, ret_val, args_in_groups);
|
||||
let mut g_vec = vec![];
|
||||
for g in grps.into_iter() {
|
||||
let g_string = self.args_in_group(g)
|
||||
|
|
|
@ -145,71 +145,52 @@ impl<'a, 'b> Arg<'a, 'b> {
|
|||
let mut a = Arg::with_name(name_str);
|
||||
let arg_settings = y.get(name_yml).unwrap().as_hash().unwrap();
|
||||
|
||||
macro_rules! vec_or_str {
|
||||
($v:ident, $a:ident, $c:ident) => {{
|
||||
let maybe_vec = $v.as_vec();
|
||||
if let Some(vec) = maybe_vec {
|
||||
for ys in vec {
|
||||
if let Some(s) = ys.as_str() {
|
||||
$a = $a.$c(s);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let Some(s) = $v.as_str() {
|
||||
$a = $a.$c(s);
|
||||
}
|
||||
}
|
||||
$a
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
for (k, v) in arg_settings.iter() {
|
||||
a = match k.as_str().unwrap() {
|
||||
"short" => a.short(v.as_str().unwrap()),
|
||||
"long" => a.long(v.as_str().unwrap()),
|
||||
"help" => a.help(v.as_str().unwrap()),
|
||||
"required" => a.required(v.as_bool().unwrap()),
|
||||
"takes_value" => a.takes_value(v.as_bool().unwrap()),
|
||||
"index" => a.index(v.as_i64().unwrap() as u64),
|
||||
"global" => a.global(v.as_bool().unwrap()),
|
||||
"multiple" => a.multiple(v.as_bool().unwrap()),
|
||||
"hidden" => a.hidden(v.as_bool().unwrap()),
|
||||
"next_line_help" => a.next_line_help(v.as_bool().unwrap()),
|
||||
"empty_values" => a.empty_values(v.as_bool().unwrap()),
|
||||
"group" => a.group(v.as_str().unwrap()),
|
||||
"number_of_values" => a.number_of_values(v.as_i64().unwrap() as u64),
|
||||
"max_values" => a.max_values(v.as_i64().unwrap() as u64),
|
||||
"min_values" => a.min_values(v.as_i64().unwrap() as u64),
|
||||
"value_name" => a.value_name(v.as_str().unwrap()),
|
||||
"use_delimiter" => a.use_delimiter(v.as_bool().unwrap()),
|
||||
"value_delimiter" => a.value_delimiter(v.as_str().unwrap()),
|
||||
"required_unless" => a.required_unless(v.as_str().unwrap()),
|
||||
"display_order" => a.display_order(v.as_i64().unwrap() as usize),
|
||||
"default_value" => a.default_value(v.as_str().unwrap()),
|
||||
"short" => yaml_to_str!(a, v, short),
|
||||
"long" => yaml_to_str!(a, v, long),
|
||||
"help" => yaml_to_str!(a, v, help),
|
||||
"required" => yaml_to_bool!(a, v, required),
|
||||
"takes_value" => yaml_to_bool!(a, v, takes_value),
|
||||
"index" => yaml_to_u64!(a, v, index),
|
||||
"global" => yaml_to_bool!(a, v, global),
|
||||
"multiple" => yaml_to_bool!(a, v, multiple),
|
||||
"hidden" => yaml_to_bool!(a, v, hidden),
|
||||
"next_line_help" => yaml_to_bool!(a, v, next_line_help),
|
||||
"empty_values" => yaml_to_bool!(a, v, empty_values),
|
||||
"group" => yaml_to_str!(a, v, group),
|
||||
"number_of_values" => yaml_to_u64!(a, v, number_of_values),
|
||||
"max_values" => yaml_to_u64!(a, v, max_values),
|
||||
"min_values" => yaml_to_u64!(a, v, min_values),
|
||||
"value_name" => yaml_to_str!(a, v, value_name),
|
||||
"use_delimiter" => yaml_to_bool!(a, v, use_delimiter),
|
||||
"value_delimiter" => yaml_to_str!(a, v, value_delimiter),
|
||||
"required_unless" => yaml_to_str!(a, v, required_unless),
|
||||
"display_order" => yaml_to_usize!(a, v, display_order),
|
||||
"default_value" => yaml_to_str!(a, v, default_value),
|
||||
"value_names" => {
|
||||
vec_or_str!(v, a, value_name)
|
||||
yaml_vec_or_str!(v, a, value_name)
|
||||
}
|
||||
"groups" => {
|
||||
vec_or_str!(v, a, group)
|
||||
yaml_vec_or_str!(v, a, group)
|
||||
}
|
||||
"requires" => {
|
||||
vec_or_str!(v, a, requires)
|
||||
yaml_vec_or_str!(v, a, requires)
|
||||
}
|
||||
"conflicts_with" => {
|
||||
vec_or_str!(v, a, conflicts_with)
|
||||
yaml_vec_or_str!(v, a, conflicts_with)
|
||||
}
|
||||
"overrides_with" => {
|
||||
vec_or_str!(v, a, overrides_with)
|
||||
yaml_vec_or_str!(v, a, overrides_with)
|
||||
}
|
||||
"possible_values" => {
|
||||
vec_or_str!(v, a, possible_value)
|
||||
yaml_vec_or_str!(v, a, possible_value)
|
||||
}
|
||||
"required_unless_one" => {
|
||||
vec_or_str!(v, a, required_unless)
|
||||
yaml_vec_or_str!(v, a, required_unless)
|
||||
}
|
||||
"required_unless_all" => {
|
||||
a = vec_or_str!(v, a, required_unless);
|
||||
a = yaml_vec_or_str!(v, a, required_unless);
|
||||
a.setb(ArgSettings::RequiredUnlessAll);
|
||||
a
|
||||
}
|
||||
|
|
|
@ -458,7 +458,7 @@ impl<'a> From<&'a BTreeMap<Yaml, Yaml>> for ArgGroup<'a> {
|
|||
let mut a = ArgGroup::default();
|
||||
let group_settings = if b.len() == 1 {
|
||||
let name_yml = b.keys().nth(0).expect("failed to get name");
|
||||
let name_str = name_yml.as_str().expect("failed to convert name to str");
|
||||
let name_str = name_yml.as_str().expect("failed to convert arg YAML name to str");
|
||||
a.name = name_str;
|
||||
b.get(name_yml)
|
||||
.expect("failed to get name_str")
|
||||
|
@ -472,12 +472,7 @@ impl<'a> From<&'a BTreeMap<Yaml, Yaml>> for ArgGroup<'a> {
|
|||
a = match k.as_str().unwrap() {
|
||||
"required" => a.required(v.as_bool().unwrap()),
|
||||
"args" => {
|
||||
for ys in v.as_vec().unwrap() {
|
||||
if let Some(s) = ys.as_str() {
|
||||
a = a.arg(s);
|
||||
}
|
||||
}
|
||||
a
|
||||
yaml_vec_or_str!(v, a, arg)
|
||||
}
|
||||
"arg" => {
|
||||
if let Some(ys) = v.as_str() {
|
||||
|
@ -486,20 +481,10 @@ impl<'a> From<&'a BTreeMap<Yaml, Yaml>> for ArgGroup<'a> {
|
|||
a
|
||||
}
|
||||
"requires" => {
|
||||
for ys in v.as_vec().unwrap() {
|
||||
if let Some(s) = ys.as_str() {
|
||||
a = a.requires(s);
|
||||
}
|
||||
}
|
||||
a
|
||||
yaml_vec_or_str!(v, a, requires)
|
||||
}
|
||||
"conflicts_with" => {
|
||||
for ys in v.as_vec().unwrap() {
|
||||
if let Some(s) = ys.as_str() {
|
||||
a = a.conflicts_with(s);
|
||||
}
|
||||
}
|
||||
a
|
||||
yaml_vec_or_str!(v, a, conflicts_with)
|
||||
}
|
||||
"name" => {
|
||||
if let Some(ys) = v.as_str() {
|
||||
|
|
47
src/args/macros.rs
Normal file
47
src/args/macros.rs
Normal file
|
@ -0,0 +1,47 @@
|
|||
|
||||
macro_rules! yaml_vec_or_str {
|
||||
($v:ident, $a:ident, $c:ident) => {{
|
||||
let maybe_vec = $v.as_vec();
|
||||
if let Some(vec) = maybe_vec {
|
||||
for ys in vec {
|
||||
if let Some(s) = ys.as_str() {
|
||||
$a = $a.$c(s);
|
||||
} else {
|
||||
panic!("Failed to convert YAML value {:?} to a string", ys);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let Some(s) = $v.as_str() {
|
||||
$a = $a.$c(s);
|
||||
} else {
|
||||
panic!("Failed to convert YAML value {:?} to either a vec or string", $v);
|
||||
}
|
||||
}
|
||||
$a
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! yaml_to_str {
|
||||
($a:ident, $v:ident, $c:ident) => {{
|
||||
$a.$c($v.as_str().unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v)))
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! yaml_to_bool {
|
||||
($a:ident, $v:ident, $c:ident) => {{
|
||||
$a.$c($v.as_bool().unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v)))
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! yaml_to_u64 {
|
||||
($a:ident, $v:ident, $c:ident) => {{
|
||||
$a.$c($v.as_i64().unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v)) as u64)
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! yaml_to_usize {
|
||||
($a:ident, $v:ident, $c:ident) => {{
|
||||
$a.$c($v.as_i64().unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v)) as usize)
|
||||
}};
|
||||
}
|
|
@ -8,6 +8,8 @@ pub use self::group::ArgGroup;
|
|||
pub use self::any_arg::{AnyArg, DispOrder};
|
||||
pub use self::settings::ArgSettings;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
mod arg;
|
||||
pub mod any_arg;
|
||||
mod arg_matches;
|
||||
|
|
|
@ -576,16 +576,16 @@ macro_rules! werr(
|
|||
#[cfg_attr(feature = "debug", macro_use)]
|
||||
mod debug_macros {
|
||||
macro_rules! debugln {
|
||||
($fmt:expr) => (println!(concat!("**DEBUG** ", $fmt)));
|
||||
($fmt:expr, $($arg:tt)*) => (println!(concat!("**DEBUG** ",$fmt), $($arg)*));
|
||||
($fmt:expr) => (println!(concat!("*DEBUG:clap: ", $fmt)));
|
||||
($fmt:expr, $($arg:tt)*) => (println!(concat!("*DEBUG:clap: ",$fmt), $($arg)*));
|
||||
}
|
||||
macro_rules! sdebugln {
|
||||
($fmt:expr) => (println!($fmt));
|
||||
($fmt:expr, $($arg:tt)*) => (println!($fmt, $($arg)*));
|
||||
}
|
||||
macro_rules! debug {
|
||||
($fmt:expr) => (print!(concat!("**DEBUG** ", $fmt)));
|
||||
($fmt:expr, $($arg:tt)*) => (print!(concat!("**DEBUG** ",$fmt), $($arg)*));
|
||||
($fmt:expr) => (print!(concat!("*DEBUG:clap: ", $fmt)));
|
||||
($fmt:expr, $($arg:tt)*) => (print!(concat!("*DEBUG:clap: ",$fmt), $($arg)*));
|
||||
}
|
||||
macro_rules! sdebug {
|
||||
($fmt:expr) => (print!($fmt));
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: claptests
|
||||
version: 1.0
|
||||
version: "1.0"
|
||||
about: tests clap library
|
||||
author: Kevin K. <kbknapp@gmail.com>
|
||||
settings:
|
||||
|
@ -81,7 +81,7 @@ arg_groups:
|
|||
subcommands:
|
||||
- subcmd:
|
||||
about: tests subcommands
|
||||
version: 0.1
|
||||
version: "0.1"
|
||||
author: Kevin K. <kbknapp@gmail.com>
|
||||
args:
|
||||
- scoption:
|
||||
|
|
|
@ -91,15 +91,13 @@ FLAGS:
|
|||
-V, --version Prints version information
|
||||
|
||||
OPTIONS:
|
||||
-c, --cafe <FILE> A coffeehouse, coffee shop, or café is an
|
||||
establishment which primarily serves hot
|
||||
coffee, related coffee beverages (e.g.,
|
||||
café latte, cappuccino, espresso), tea,
|
||||
and other hot beverages. Some
|
||||
coffeehouses also serve cold beverages
|
||||
such as iced coffee and iced tea. Many
|
||||
cafés also serve some type of food, such
|
||||
as light snacks, muffins, or pastries.";
|
||||
-c, --cafe <FILE>
|
||||
A coffeehouse, coffee shop, or café is an establishment which
|
||||
primarily serves hot coffee, related coffee beverages
|
||||
(e.g., café latte, cappuccino, espresso), tea, and other
|
||||
hot beverages. Some coffeehouses also serve cold beverages
|
||||
such as iced coffee and iced tea. Many cafés also serve
|
||||
some type of food, such as light snacks, muffins, or pastries.";
|
||||
|
||||
static ISSUE_626_PANIC: &'static str = "ctest 0.1
|
||||
|
||||
|
@ -111,19 +109,14 @@ FLAGS:
|
|||
-V, --version Prints version information
|
||||
|
||||
OPTIONS:
|
||||
-c, --cafe <FILE> La culture du café est
|
||||
très développée dans de
|
||||
nombreux pays à climat
|
||||
chaud d'Amérique,
|
||||
d'Afrique et d'Asie,
|
||||
dans des plantations
|
||||
qui sont cultivées pour
|
||||
les marchés
|
||||
d'exportation. Le café
|
||||
est souvent une
|
||||
contribution majeure
|
||||
aux exportations des
|
||||
régions productrices.";
|
||||
-c, --cafe <FILE>
|
||||
La culture du café est très développée dans
|
||||
de nombreux pays à climat chaud
|
||||
d\'Amérique, d\'Afrique et d\'Asie, dans
|
||||
des plantations qui sont cultivées pour
|
||||
les marchés d\'exportation. Le café est
|
||||
souvent une contribution majeure aux
|
||||
exportations des régions productrices.";
|
||||
|
||||
#[test]
|
||||
fn help_short() {
|
||||
|
|
Loading…
Reference in a new issue