mirror of
https://github.com/clap-rs/clap
synced 2024-12-14 23:02:31 +00:00
WIP. Big reformat
This commit is contained in:
parent
7e6d403009
commit
e1fb98a0c1
38 changed files with 1182 additions and 759 deletions
|
@ -8,15 +8,17 @@ use clap::{App, Arg};
|
|||
use test::Bencher;
|
||||
|
||||
macro_rules! create_app {
|
||||
() => ({
|
||||
() => {{
|
||||
App::new("claptests")
|
||||
.version("0.1")
|
||||
.about("tests clap library")
|
||||
.author("Kevin K. <kbknapp@gmail.com>")
|
||||
.args_from_usage("-f --flag 'tests flags'
|
||||
.version("0.1")
|
||||
.about("tests clap library")
|
||||
.author("Kevin K. <kbknapp@gmail.com>")
|
||||
.args_from_usage(
|
||||
"-f --flag 'tests flags'
|
||||
-o --option=[opt] 'tests options'
|
||||
[positional] 'tests positional'")
|
||||
})
|
||||
[positional] 'tests positional'",
|
||||
)
|
||||
}};
|
||||
}
|
||||
|
||||
#[bench]
|
||||
|
|
|
@ -12,9 +12,9 @@ extern crate test;
|
|||
|
||||
use clap::{App, AppSettings, Arg, ArgSettings};
|
||||
|
||||
use test::Bencher;
|
||||
use std::collections::HashMap;
|
||||
use std::io::Cursor;
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn build_app_short(b: &mut Bencher) { b.iter(|| app_short()); }
|
||||
|
@ -410,306 +410,451 @@ macro_rules! doc {
|
|||
doc!($map, $name, $short, $short)
|
||||
};
|
||||
($map:expr, $name:expr, $short:expr, $long:expr) => {
|
||||
$map.insert($name, Usage {
|
||||
short: $short,
|
||||
long: concat!($long, "\n "),
|
||||
});
|
||||
$map.insert(
|
||||
$name,
|
||||
Usage {
|
||||
short: $short,
|
||||
long: concat!($long, "\n "),
|
||||
},
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref USAGES: HashMap<&'static str, Usage> = {
|
||||
let mut h = HashMap::new();
|
||||
doc!(h, "help-short",
|
||||
"Show short help output.",
|
||||
"Show short help output. Use --help to show more details.");
|
||||
doc!(h, "help",
|
||||
"Show verbose help output.",
|
||||
"When given, more details about flags are provided.");
|
||||
doc!(h, "version",
|
||||
"Prints version information.");
|
||||
doc!(
|
||||
h,
|
||||
"help-short",
|
||||
"Show short help output.",
|
||||
"Show short help output. Use --help to show more details."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"help",
|
||||
"Show verbose help output.",
|
||||
"When given, more details about flags are provided."
|
||||
);
|
||||
doc!(h, "version", "Prints version information.");
|
||||
|
||||
doc!(h, "pattern",
|
||||
"A regular expression used for searching.",
|
||||
"A regular expression used for searching. Multiple patterns \
|
||||
may be given. To match a pattern beginning with a -, use [-].");
|
||||
doc!(h, "regexp",
|
||||
"A regular expression used for searching.",
|
||||
"A regular expression used for searching. Multiple patterns \
|
||||
may be given. To match a pattern beginning with a -, use [-].");
|
||||
doc!(h, "path",
|
||||
"A file or directory to search.",
|
||||
"A file or directory to search. Directories are searched \
|
||||
recursively.");
|
||||
doc!(h, "files",
|
||||
"Print each file that would be searched.",
|
||||
"Print each file that would be searched without actually \
|
||||
performing the search. This is useful to determine whether a \
|
||||
particular file is being searched or not.");
|
||||
doc!(h, "type-list",
|
||||
"Show all supported file types.",
|
||||
"Show all supported file types and their corresponding globs.");
|
||||
doc!(
|
||||
h,
|
||||
"pattern",
|
||||
"A regular expression used for searching.",
|
||||
"A regular expression used for searching. Multiple patterns \
|
||||
may be given. To match a pattern beginning with a -, use [-]."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"regexp",
|
||||
"A regular expression used for searching.",
|
||||
"A regular expression used for searching. Multiple patterns \
|
||||
may be given. To match a pattern beginning with a -, use [-]."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"path",
|
||||
"A file or directory to search.",
|
||||
"A file or directory to search. Directories are searched \
|
||||
recursively."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"files",
|
||||
"Print each file that would be searched.",
|
||||
"Print each file that would be searched without actually \
|
||||
performing the search. This is useful to determine whether a \
|
||||
particular file is being searched or not."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"type-list",
|
||||
"Show all supported file types.",
|
||||
"Show all supported file types and their corresponding globs."
|
||||
);
|
||||
|
||||
doc!(h, "text",
|
||||
"Search binary files as if they were text.");
|
||||
doc!(h, "count",
|
||||
"Only show count of matches for each file.");
|
||||
doc!(h, "color",
|
||||
"When to use color. [default: auto]",
|
||||
"When to use color in the output. The possible values are \
|
||||
never, auto, always or ansi. The default is auto. When always \
|
||||
is used, coloring is attempted based on your environment. When \
|
||||
ansi used, coloring is forcefully done using ANSI escape color \
|
||||
codes.");
|
||||
doc!(h, "colors",
|
||||
"Configure color settings and styles.",
|
||||
"This flag specifies color settings for use in the output. \
|
||||
This flag may be provided multiple times. Settings are applied \
|
||||
iteratively. Colors are limited to one of eight choices: \
|
||||
red, blue, green, cyan, magenta, yellow, white and black. \
|
||||
Styles are limited to nobold, bold, nointense or intense.\n\n\
|
||||
The format of the flag is {type}:{attribute}:{value}. {type} \
|
||||
should be one of path, line or match. {attribute} can be fg, bg \
|
||||
or style. {value} is either a color (for fg and bg) or a text \
|
||||
style. A special format, {type}:none, will clear all color \
|
||||
settings for {type}.\n\nFor example, the following command will \
|
||||
change the match color to magenta and the background color for \
|
||||
line numbers to yellow:\n\n\
|
||||
rg --colors 'match:fg:magenta' --colors 'line:bg:yellow' foo.");
|
||||
doc!(h, "fixed-strings",
|
||||
"Treat the pattern as a literal string.",
|
||||
"Treat the pattern as a literal string instead of a regular \
|
||||
expression. When this flag is used, special regular expression \
|
||||
meta characters such as (){}*+. do not need to be escaped.");
|
||||
doc!(h, "glob",
|
||||
"Include or exclude files/directories.",
|
||||
"Include or exclude files/directories for searching that \
|
||||
match the given glob. This always overrides any other \
|
||||
ignore logic. Multiple glob flags may be used. Globbing \
|
||||
rules match .gitignore globs. Precede a glob with a ! \
|
||||
to exclude it.");
|
||||
doc!(h, "ignore-case",
|
||||
"Case insensitive search.",
|
||||
"Case insensitive search. This is overridden by \
|
||||
--case-sensitive.");
|
||||
doc!(h, "line-number",
|
||||
"Show line numbers.",
|
||||
"Show line numbers (1-based). This is enabled by default when \
|
||||
searching in a tty.");
|
||||
doc!(h, "no-line-number",
|
||||
"Suppress line numbers.",
|
||||
"Suppress line numbers. This is enabled by default when NOT \
|
||||
searching in a tty.");
|
||||
doc!(h, "quiet",
|
||||
"Do not print anything to stdout.",
|
||||
"Do not print anything to stdout. If a match is found in a file, \
|
||||
stop searching. This is useful when ripgrep is used only for \
|
||||
its exit code.");
|
||||
doc!(h, "type",
|
||||
"Only search files matching TYPE.",
|
||||
"Only search files matching TYPE. Multiple type flags may be \
|
||||
provided. Use the --type-list flag to list all available \
|
||||
types.");
|
||||
doc!(h, "type-not",
|
||||
"Do not search files matching TYPE.",
|
||||
"Do not search files matching TYPE. Multiple type-not flags may \
|
||||
be provided. Use the --type-list flag to list all available \
|
||||
types.");
|
||||
doc!(h, "unrestricted",
|
||||
"Reduce the level of \"smart\" searching.",
|
||||
"Reduce the level of \"smart\" searching. A single -u \
|
||||
won't respect .gitignore (etc.) files. Two -u flags will \
|
||||
additionally search hidden files and directories. Three \
|
||||
-u flags will additionally search binary files. -uu is \
|
||||
roughly equivalent to grep -r and -uuu is roughly \
|
||||
equivalent to grep -a -r.");
|
||||
doc!(h, "invert-match",
|
||||
"Invert matching.",
|
||||
"Invert matching. Show lines that don't match given patterns.");
|
||||
doc!(h, "word-regexp",
|
||||
"Only show matches surrounded by word boundaries.",
|
||||
"Only show matches surrounded by word boundaries. This is \
|
||||
equivalent to putting \\b before and after all of the search \
|
||||
patterns.");
|
||||
doc!(h, "text", "Search binary files as if they were text.");
|
||||
doc!(h, "count", "Only show count of matches for each file.");
|
||||
doc!(
|
||||
h,
|
||||
"color",
|
||||
"When to use color. [default: auto]",
|
||||
"When to use color in the output. The possible values are \
|
||||
never, auto, always or ansi. The default is auto. When always \
|
||||
is used, coloring is attempted based on your environment. When \
|
||||
ansi used, coloring is forcefully done using ANSI escape color \
|
||||
codes."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"colors",
|
||||
"Configure color settings and styles.",
|
||||
"This flag specifies color settings for use in the output. \
|
||||
This flag may be provided multiple times. Settings are applied \
|
||||
iteratively. Colors are limited to one of eight choices: \
|
||||
red, blue, green, cyan, magenta, yellow, white and black. \
|
||||
Styles are limited to nobold, bold, nointense or intense.\n\n\
|
||||
The format of the flag is {type}:{attribute}:{value}. {type} \
|
||||
should be one of path, line or match. {attribute} can be fg, bg \
|
||||
or style. {value} is either a color (for fg and bg) or a text \
|
||||
style. A special format, {type}:none, will clear all color \
|
||||
settings for {type}.\n\nFor example, the following command will \
|
||||
change the match color to magenta and the background color for \
|
||||
line numbers to yellow:\n\n\
|
||||
rg --colors 'match:fg:magenta' --colors 'line:bg:yellow' foo."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"fixed-strings",
|
||||
"Treat the pattern as a literal string.",
|
||||
"Treat the pattern as a literal string instead of a regular \
|
||||
expression. When this flag is used, special regular expression \
|
||||
meta characters such as (){}*+. do not need to be escaped."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"glob",
|
||||
"Include or exclude files/directories.",
|
||||
"Include or exclude files/directories for searching that \
|
||||
match the given glob. This always overrides any other \
|
||||
ignore logic. Multiple glob flags may be used. Globbing \
|
||||
rules match .gitignore globs. Precede a glob with a ! \
|
||||
to exclude it."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"ignore-case",
|
||||
"Case insensitive search.",
|
||||
"Case insensitive search. This is overridden by \
|
||||
--case-sensitive."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"line-number",
|
||||
"Show line numbers.",
|
||||
"Show line numbers (1-based). This is enabled by default when \
|
||||
searching in a tty."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"no-line-number",
|
||||
"Suppress line numbers.",
|
||||
"Suppress line numbers. This is enabled by default when NOT \
|
||||
searching in a tty."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"quiet",
|
||||
"Do not print anything to stdout.",
|
||||
"Do not print anything to stdout. If a match is found in a file, \
|
||||
stop searching. This is useful when ripgrep is used only for \
|
||||
its exit code."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"type",
|
||||
"Only search files matching TYPE.",
|
||||
"Only search files matching TYPE. Multiple type flags may be \
|
||||
provided. Use the --type-list flag to list all available \
|
||||
types."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"type-not",
|
||||
"Do not search files matching TYPE.",
|
||||
"Do not search files matching TYPE. Multiple type-not flags may \
|
||||
be provided. Use the --type-list flag to list all available \
|
||||
types."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"unrestricted",
|
||||
"Reduce the level of \"smart\" searching.",
|
||||
"Reduce the level of \"smart\" searching. A single -u \
|
||||
won't respect .gitignore (etc.) files. Two -u flags will \
|
||||
additionally search hidden files and directories. Three \
|
||||
-u flags will additionally search binary files. -uu is \
|
||||
roughly equivalent to grep -r and -uuu is roughly \
|
||||
equivalent to grep -a -r."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"invert-match",
|
||||
"Invert matching.",
|
||||
"Invert matching. Show lines that don't match given patterns."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"word-regexp",
|
||||
"Only show matches surrounded by word boundaries.",
|
||||
"Only show matches surrounded by word boundaries. This is \
|
||||
equivalent to putting \\b before and after all of the search \
|
||||
patterns."
|
||||
);
|
||||
|
||||
doc!(h, "after-context",
|
||||
"Show NUM lines after each match.");
|
||||
doc!(h, "before-context",
|
||||
"Show NUM lines before each match.");
|
||||
doc!(h, "context",
|
||||
"Show NUM lines before and after each match.");
|
||||
doc!(h, "column",
|
||||
"Show column numbers",
|
||||
"Show column numbers (1-based). This only shows the column \
|
||||
numbers for the first match on each line. This does not try \
|
||||
to account for Unicode. One byte is equal to one column. This \
|
||||
implies --line-number.");
|
||||
doc!(h, "context-separator",
|
||||
"Set the context separator string. [default: --]",
|
||||
"The string used to separate non-contiguous context lines in the \
|
||||
output. Escape sequences like \\x7F or \\t may be used. The \
|
||||
default value is --.");
|
||||
doc!(h, "debug",
|
||||
"Show debug messages.",
|
||||
"Show debug messages. Please use this when filing a bug report.");
|
||||
doc!(h, "file",
|
||||
"Search for patterns from the given file.",
|
||||
"Search for patterns from the given file, with one pattern per \
|
||||
line. When this flag is used or multiple times or in \
|
||||
combination with the -e/--regexp flag, then all patterns \
|
||||
provided are searched. Empty pattern lines will match all input \
|
||||
lines, and the newline is not counted as part of the pattern.");
|
||||
doc!(h, "files-with-matches",
|
||||
"Only show the path of each file with at least one match.");
|
||||
doc!(h, "files-without-match",
|
||||
"Only show the path of each file that contains zero matches.");
|
||||
doc!(h, "with-filename",
|
||||
"Show file name for each match.",
|
||||
"Prefix each match with the file name that contains it. This is \
|
||||
the default when more than one file is searched.");
|
||||
doc!(h, "no-filename",
|
||||
"Never show the file name for a match.",
|
||||
"Never show the file name for a match. This is the default when \
|
||||
one file is searched.");
|
||||
doc!(h, "heading",
|
||||
"Show matches grouped by each file.",
|
||||
"This shows the file name above clusters of matches from each \
|
||||
file instead of showing the file name for every match. This is \
|
||||
the default mode at a tty.");
|
||||
doc!(h, "no-heading",
|
||||
"Don't group matches by each file.",
|
||||
"Don't group matches by each file. If -H/--with-filename is \
|
||||
enabled, then file names will be shown for every line matched. \
|
||||
This is the default mode when not at a tty.");
|
||||
doc!(h, "hidden",
|
||||
"Search hidden files and directories.",
|
||||
"Search hidden files and directories. By default, hidden files \
|
||||
and directories are skipped.");
|
||||
doc!(h, "ignore-file",
|
||||
"Specify additional ignore files.",
|
||||
"Specify additional ignore files for filtering file paths. \
|
||||
Ignore files should be in the gitignore format and are matched \
|
||||
relative to the current working directory. These ignore files \
|
||||
have lower precedence than all other ignore files. When \
|
||||
specifying multiple ignore files, earlier files have lower \
|
||||
precedence than later files.");
|
||||
doc!(h, "follow",
|
||||
"Follow symbolic links.");
|
||||
doc!(h, "max-count",
|
||||
"Limit the number of matches.",
|
||||
"Limit the number of matching lines per file searched to NUM.");
|
||||
doc!(h, "maxdepth",
|
||||
"Descend at most NUM directories.",
|
||||
"Limit the depth of directory traversal to NUM levels beyond \
|
||||
the paths given. A value of zero only searches the \
|
||||
starting-points themselves.\n\nFor example, \
|
||||
'rg --maxdepth 0 dir/' is a no-op because dir/ will not be \
|
||||
descended into. 'rg --maxdepth 1 dir/' will search only the \
|
||||
direct children of dir/.");
|
||||
doc!(h, "mmap",
|
||||
"Searching using memory maps when possible.",
|
||||
"Search using memory maps when possible. This is enabled by \
|
||||
default when ripgrep thinks it will be faster. Note that memory \
|
||||
map searching doesn't currently support all options, so if an \
|
||||
incompatible option (e.g., --context) is given with --mmap, \
|
||||
then memory maps will not be used.");
|
||||
doc!(h, "no-messages",
|
||||
"Suppress all error messages.",
|
||||
"Suppress all error messages. This is equivalent to redirecting \
|
||||
stderr to /dev/null.");
|
||||
doc!(h, "no-mmap",
|
||||
"Never use memory maps.",
|
||||
"Never use memory maps, even when they might be faster.");
|
||||
doc!(h, "no-ignore",
|
||||
"Don't respect ignore files.",
|
||||
"Don't respect ignore files (.gitignore, .ignore, etc.). This \
|
||||
implies --no-ignore-parent and --no-ignore-vcs.");
|
||||
doc!(h, "no-ignore-parent",
|
||||
"Don't respect ignore files in parent directories.",
|
||||
"Don't respect ignore files (.gitignore, .ignore, etc.) in \
|
||||
parent directories.");
|
||||
doc!(h, "no-ignore-vcs",
|
||||
"Don't respect VCS ignore files",
|
||||
"Don't respect version control ignore files (.gitignore, etc.). \
|
||||
This implies --no-ignore-parent. Note that .ignore files will \
|
||||
continue to be respected.");
|
||||
doc!(h, "null",
|
||||
"Print NUL byte after file names",
|
||||
"Whenever a file name is printed, follow it with a NUL byte. \
|
||||
This includes printing file names before matches, and when \
|
||||
printing a list of matching files such as with --count, \
|
||||
--files-with-matches and --files. This option is useful for use \
|
||||
with xargs.");
|
||||
doc!(h, "path-separator",
|
||||
"Path separator to use when printing file paths.",
|
||||
"The path separator to use when printing file paths. This \
|
||||
defaults to your platform's path separator, which is / on Unix \
|
||||
and \\ on Windows. This flag is intended for overriding the \
|
||||
default when the environment demands it (e.g., cygwin). A path \
|
||||
separator is limited to a single byte.");
|
||||
doc!(h, "pretty",
|
||||
"Alias for --color always --heading -n.");
|
||||
doc!(h, "replace",
|
||||
"Replace matches with string given.",
|
||||
"Replace every match with the string given when printing \
|
||||
results. Neither this flag nor any other flag will modify your \
|
||||
files.\n\nCapture group indices (e.g., $5) and names \
|
||||
(e.g., $foo) are supported in the replacement string.\n\n\
|
||||
Note that the replacement by default replaces each match, and \
|
||||
NOT the entire line. To replace the entire line, you should \
|
||||
match the entire line.");
|
||||
doc!(h, "case-sensitive",
|
||||
"Search case sensitively.",
|
||||
"Search case sensitively. This overrides -i/--ignore-case and \
|
||||
-S/--smart-case.");
|
||||
doc!(h, "smart-case",
|
||||
"Smart case search.",
|
||||
"Searches case insensitively if the pattern is all lowercase. \
|
||||
Search case sensitively otherwise. This is overridden by \
|
||||
either -s/--case-sensitive or -i/--ignore-case.");
|
||||
doc!(h, "sort-files",
|
||||
"Sort results by file path. Implies --threads=1.",
|
||||
"Sort results by file path. Note that this currently \
|
||||
disables all parallelism and runs search in a single thread.");
|
||||
doc!(h, "threads",
|
||||
"The approximate number of threads to use.",
|
||||
"The approximate number of threads to use. A value of 0 (which \
|
||||
is the default) causes ripgrep to choose the thread count \
|
||||
using heuristics.");
|
||||
doc!(h, "vimgrep",
|
||||
"Show results in vim compatible format.",
|
||||
"Show results with every match on its own line, including \
|
||||
line numbers and column numbers. With this option, a line with \
|
||||
more than one match will be printed more than once.");
|
||||
doc!(h, "after-context", "Show NUM lines after each match.");
|
||||
doc!(h, "before-context", "Show NUM lines before each match.");
|
||||
doc!(h, "context", "Show NUM lines before and after each match.");
|
||||
doc!(
|
||||
h,
|
||||
"column",
|
||||
"Show column numbers",
|
||||
"Show column numbers (1-based). This only shows the column \
|
||||
numbers for the first match on each line. This does not try \
|
||||
to account for Unicode. One byte is equal to one column. This \
|
||||
implies --line-number."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"context-separator",
|
||||
"Set the context separator string. [default: --]",
|
||||
"The string used to separate non-contiguous context lines in the \
|
||||
output. Escape sequences like \\x7F or \\t may be used. The \
|
||||
default value is --."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"debug",
|
||||
"Show debug messages.",
|
||||
"Show debug messages. Please use this when filing a bug report."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"file",
|
||||
"Search for patterns from the given file.",
|
||||
"Search for patterns from the given file, with one pattern per \
|
||||
line. When this flag is used or multiple times or in \
|
||||
combination with the -e/--regexp flag, then all patterns \
|
||||
provided are searched. Empty pattern lines will match all input \
|
||||
lines, and the newline is not counted as part of the pattern."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"files-with-matches",
|
||||
"Only show the path of each file with at least one match."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"files-without-match",
|
||||
"Only show the path of each file that contains zero matches."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"with-filename",
|
||||
"Show file name for each match.",
|
||||
"Prefix each match with the file name that contains it. This is \
|
||||
the default when more than one file is searched."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"no-filename",
|
||||
"Never show the file name for a match.",
|
||||
"Never show the file name for a match. This is the default when \
|
||||
one file is searched."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"heading",
|
||||
"Show matches grouped by each file.",
|
||||
"This shows the file name above clusters of matches from each \
|
||||
file instead of showing the file name for every match. This is \
|
||||
the default mode at a tty."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"no-heading",
|
||||
"Don't group matches by each file.",
|
||||
"Don't group matches by each file. If -H/--with-filename is \
|
||||
enabled, then file names will be shown for every line matched. \
|
||||
This is the default mode when not at a tty."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"hidden",
|
||||
"Search hidden files and directories.",
|
||||
"Search hidden files and directories. By default, hidden files \
|
||||
and directories are skipped."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"ignore-file",
|
||||
"Specify additional ignore files.",
|
||||
"Specify additional ignore files for filtering file paths. \
|
||||
Ignore files should be in the gitignore format and are matched \
|
||||
relative to the current working directory. These ignore files \
|
||||
have lower precedence than all other ignore files. When \
|
||||
specifying multiple ignore files, earlier files have lower \
|
||||
precedence than later files."
|
||||
);
|
||||
doc!(h, "follow", "Follow symbolic links.");
|
||||
doc!(
|
||||
h,
|
||||
"max-count",
|
||||
"Limit the number of matches.",
|
||||
"Limit the number of matching lines per file searched to NUM."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"maxdepth",
|
||||
"Descend at most NUM directories.",
|
||||
"Limit the depth of directory traversal to NUM levels beyond \
|
||||
the paths given. A value of zero only searches the \
|
||||
starting-points themselves.\n\nFor example, \
|
||||
'rg --maxdepth 0 dir/' is a no-op because dir/ will not be \
|
||||
descended into. 'rg --maxdepth 1 dir/' will search only the \
|
||||
direct children of dir/."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"mmap",
|
||||
"Searching using memory maps when possible.",
|
||||
"Search using memory maps when possible. This is enabled by \
|
||||
default when ripgrep thinks it will be faster. Note that memory \
|
||||
map searching doesn't currently support all options, so if an \
|
||||
incompatible option (e.g., --context) is given with --mmap, \
|
||||
then memory maps will not be used."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"no-messages",
|
||||
"Suppress all error messages.",
|
||||
"Suppress all error messages. This is equivalent to redirecting \
|
||||
stderr to /dev/null."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"no-mmap",
|
||||
"Never use memory maps.",
|
||||
"Never use memory maps, even when they might be faster."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"no-ignore",
|
||||
"Don't respect ignore files.",
|
||||
"Don't respect ignore files (.gitignore, .ignore, etc.). This \
|
||||
implies --no-ignore-parent and --no-ignore-vcs."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"no-ignore-parent",
|
||||
"Don't respect ignore files in parent directories.",
|
||||
"Don't respect ignore files (.gitignore, .ignore, etc.) in \
|
||||
parent directories."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"no-ignore-vcs",
|
||||
"Don't respect VCS ignore files",
|
||||
"Don't respect version control ignore files (.gitignore, etc.). \
|
||||
This implies --no-ignore-parent. Note that .ignore files will \
|
||||
continue to be respected."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"null",
|
||||
"Print NUL byte after file names",
|
||||
"Whenever a file name is printed, follow it with a NUL byte. \
|
||||
This includes printing file names before matches, and when \
|
||||
printing a list of matching files such as with --count, \
|
||||
--files-with-matches and --files. This option is useful for use \
|
||||
with xargs."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"path-separator",
|
||||
"Path separator to use when printing file paths.",
|
||||
"The path separator to use when printing file paths. This \
|
||||
defaults to your platform's path separator, which is / on Unix \
|
||||
and \\ on Windows. This flag is intended for overriding the \
|
||||
default when the environment demands it (e.g., cygwin). A path \
|
||||
separator is limited to a single byte."
|
||||
);
|
||||
doc!(h, "pretty", "Alias for --color always --heading -n.");
|
||||
doc!(
|
||||
h,
|
||||
"replace",
|
||||
"Replace matches with string given.",
|
||||
"Replace every match with the string given when printing \
|
||||
results. Neither this flag nor any other flag will modify your \
|
||||
files.\n\nCapture group indices (e.g., $5) and names \
|
||||
(e.g., $foo) are supported in the replacement string.\n\n\
|
||||
Note that the replacement by default replaces each match, and \
|
||||
NOT the entire line. To replace the entire line, you should \
|
||||
match the entire line."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"case-sensitive",
|
||||
"Search case sensitively.",
|
||||
"Search case sensitively. This overrides -i/--ignore-case and \
|
||||
-S/--smart-case."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"smart-case",
|
||||
"Smart case search.",
|
||||
"Searches case insensitively if the pattern is all lowercase. \
|
||||
Search case sensitively otherwise. This is overridden by \
|
||||
either -s/--case-sensitive or -i/--ignore-case."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"sort-files",
|
||||
"Sort results by file path. Implies --threads=1.",
|
||||
"Sort results by file path. Note that this currently \
|
||||
disables all parallelism and runs search in a single thread."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"threads",
|
||||
"The approximate number of threads to use.",
|
||||
"The approximate number of threads to use. A value of 0 (which \
|
||||
is the default) causes ripgrep to choose the thread count \
|
||||
using heuristics."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"vimgrep",
|
||||
"Show results in vim compatible format.",
|
||||
"Show results with every match on its own line, including \
|
||||
line numbers and column numbers. With this option, a line with \
|
||||
more than one match will be printed more than once."
|
||||
);
|
||||
|
||||
doc!(h, "type-add",
|
||||
"Add a new glob for a file type.",
|
||||
"Add a new glob for a particular file type. Only one glob can be \
|
||||
added at a time. Multiple --type-add flags can be provided. \
|
||||
Unless --type-clear is used, globs are added to any existing \
|
||||
globs defined inside of ripgrep.\n\nNote that this MUST be \
|
||||
passed to every invocation of ripgrep. Type settings are NOT \
|
||||
persisted.\n\nExample: \
|
||||
rg --type-add 'foo:*.foo' -tfoo PATTERN.\n\n\
|
||||
--type-add can also be used to include rules from other types \
|
||||
with the special include directive. The include directive \
|
||||
permits specifying one or more other type names (separated by a \
|
||||
comma) that have been defined and its rules will automatically \
|
||||
be imported into the type specified. For example, to create a \
|
||||
type called src that matches C++, Python and Markdown files, one \
|
||||
can use:\n\n\
|
||||
--type-add 'src:include:cpp,py,md'\n\n\
|
||||
Additional glob rules can still be added to the src type by \
|
||||
using the --type-add flag again:\n\n\
|
||||
--type-add 'src:include:cpp,py,md' --type-add 'src:*.foo'\n\n\
|
||||
Note that type names must consist only of Unicode letters or \
|
||||
numbers. Punctuation characters are not allowed.");
|
||||
doc!(h, "type-clear",
|
||||
"Clear globs for given file type.",
|
||||
"Clear the file type globs previously defined for TYPE. This \
|
||||
only clears the default type definitions that are found inside \
|
||||
of ripgrep.\n\nNote that this MUST be passed to every \
|
||||
invocation of ripgrep. Type settings are NOT persisted.");
|
||||
doc!(
|
||||
h,
|
||||
"type-add",
|
||||
"Add a new glob for a file type.",
|
||||
"Add a new glob for a particular file type. Only one glob can be \
|
||||
added at a time. Multiple --type-add flags can be provided. \
|
||||
Unless --type-clear is used, globs are added to any existing \
|
||||
globs defined inside of ripgrep.\n\nNote that this MUST be \
|
||||
passed to every invocation of ripgrep. Type settings are NOT \
|
||||
persisted.\n\nExample: \
|
||||
rg --type-add 'foo:*.foo' -tfoo PATTERN.\n\n\
|
||||
--type-add can also be used to include rules from other types \
|
||||
with the special include directive. The include directive \
|
||||
permits specifying one or more other type names (separated by a \
|
||||
comma) that have been defined and its rules will automatically \
|
||||
be imported into the type specified. For example, to create a \
|
||||
type called src that matches C++, Python and Markdown files, one \
|
||||
can use:\n\n\
|
||||
--type-add 'src:include:cpp,py,md'\n\n\
|
||||
Additional glob rules can still be added to the src type by \
|
||||
using the --type-add flag again:\n\n\
|
||||
--type-add 'src:include:cpp,py,md' --type-add 'src:*.foo'\n\n\
|
||||
Note that type names must consist only of Unicode letters or \
|
||||
numbers. Punctuation characters are not allowed."
|
||||
);
|
||||
doc!(
|
||||
h,
|
||||
"type-clear",
|
||||
"Clear globs for given file type.",
|
||||
"Clear the file type globs previously defined for TYPE. This \
|
||||
only clears the default type definitions that are found inside \
|
||||
of ripgrep.\n\nNote that this MUST be passed to every \
|
||||
invocation of ripgrep. Type settings are NOT persisted."
|
||||
);
|
||||
|
||||
h
|
||||
};
|
||||
|
|
|
@ -106,7 +106,7 @@ where
|
|||
#[doc(hidden)]
|
||||
pub g_settings: AppFlags,
|
||||
#[doc(hidden)]
|
||||
pub args: MKeyMap,
|
||||
pub args: MKeyMap<'a, 'b>,
|
||||
#[doc(hidden)]
|
||||
pub subcommands: Vec<App<'a, 'b>>,
|
||||
#[doc(hidden)]
|
||||
|
@ -990,7 +990,7 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
{
|
||||
let i = self
|
||||
.args
|
||||
.iter()
|
||||
.values()
|
||||
.enumerate()
|
||||
.filter_map(|(i, a)| if a.name == arg { Some(i) } else { None })
|
||||
.next();
|
||||
|
@ -1412,7 +1412,7 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
|
||||
let global_arg_vec: Vec<&str> = (&self)
|
||||
.args
|
||||
.iter()
|
||||
.values()
|
||||
.filter(|a| a.is_set(ArgSettings::Global))
|
||||
.map(|ga| ga.name)
|
||||
.collect();
|
||||
|
@ -1446,7 +1446,7 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
}
|
||||
true
|
||||
});
|
||||
//TODO add .values_mut() for MKeyMap
|
||||
|
||||
for a in self.args.values_mut() {
|
||||
// Fill in the groups
|
||||
if let Some(ref grps) = a.groups {
|
||||
|
@ -1483,16 +1483,18 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
debugln!("App::app_debug_asserts;");
|
||||
// * Args listed inside groups should exist
|
||||
// * Groups should not have naming conflicts with Args
|
||||
let g = groups!(self).find(|g| {
|
||||
g.args
|
||||
.iter()
|
||||
.any(|arg| !(find!(self, arg).is_some() || groups!(self).any(|g| &g.name == arg)))
|
||||
});
|
||||
assert!(
|
||||
g.is_none(),
|
||||
"The group '{}' contains an arg that doesn't exist or has a naming conflict with a group.",
|
||||
g.unwrap().name
|
||||
);
|
||||
|
||||
// * Will be removed as a part of removing String types
|
||||
// let g = groups!(self).find(|g| {
|
||||
// g.args
|
||||
// .iter()
|
||||
// .any(|arg| !(find!(self, arg).is_some() || groups!(self).any(|g| &g.name == arg)))
|
||||
// });
|
||||
// assert!(
|
||||
// g.is_none(),
|
||||
// "The group '{}' contains an arg that doesn't exist or has a naming conflict with a group.",
|
||||
// g.unwrap().name
|
||||
// );
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -1519,7 +1521,7 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
sc.max_w = self.max_w;
|
||||
}
|
||||
{
|
||||
for a in self.args.iter().filter(|a| a.is_set(ArgSettings::Global)) {
|
||||
for a in self.args.values().filter(|a| a.is_set(ArgSettings::Global)) {
|
||||
sc.args.push(a.clone());
|
||||
}
|
||||
}
|
||||
|
@ -1744,9 +1746,11 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
ColorWhen::Auto
|
||||
}
|
||||
}
|
||||
pub(crate) fn contains_long(&self, l: &str) -> bool { longs!(self).any(|al| al == l) }
|
||||
pub(crate) fn contains_long(&self, l: &str) -> bool {
|
||||
longs!(self).any(|&al| al == OsString::from(l).as_os_str())
|
||||
}
|
||||
|
||||
pub(crate) fn contains_short(&self, s: char) -> bool { shorts!(self).any(|arg_s| arg_s == s) }
|
||||
pub(crate) fn contains_short(&self, s: char) -> bool { shorts!(self).any(|&arg_s| arg_s == s) }
|
||||
|
||||
pub fn is_set(&self, s: AppSettings) -> bool {
|
||||
self.settings.is_set(s) || self.g_settings.is_set(s)
|
||||
|
@ -1770,9 +1774,13 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
|
||||
pub fn has_positionals(&self) -> bool { positionals!(self).count() > 0 }
|
||||
|
||||
pub fn has_visible_opts(&self) -> bool { opts!(self).any(|o| !o.is_set(ArgSettings::Hidden)) }
|
||||
pub fn has_visible_opts(&self) -> bool {
|
||||
opts!(self).any(|(k, o)| !o.is_set(ArgSettings::Hidden))
|
||||
}
|
||||
|
||||
pub fn has_visible_flags(&self) -> bool { flags!(self).any(|o| !o.is_set(ArgSettings::Hidden)) }
|
||||
pub fn has_visible_flags(&self) -> bool {
|
||||
flags!(self).any(|(k, o)| !o.is_set(ArgSettings::Hidden))
|
||||
}
|
||||
|
||||
pub fn has_visible_positionals(&self) -> bool {
|
||||
positionals!(self).any(|o| !o.is_set(ArgSettings::Hidden))
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// Std
|
||||
#[allow(unused_imports)]
|
||||
use std::ascii::AsciiExt;
|
||||
use std::str::FromStr;
|
||||
use std::ops::BitOr;
|
||||
use std::str::FromStr;
|
||||
|
||||
bitflags! {
|
||||
struct Flags: u64 {
|
||||
|
@ -62,8 +62,11 @@ impl BitOr for AppFlags {
|
|||
impl Default for AppFlags {
|
||||
fn default() -> Self {
|
||||
AppFlags(
|
||||
Flags::NEEDS_LONG_VERSION | Flags::NEEDS_LONG_HELP | Flags::NEEDS_SC_HELP
|
||||
| Flags::UTF8_NONE | Flags::COLOR_AUTO,
|
||||
Flags::NEEDS_LONG_VERSION
|
||||
| Flags::NEEDS_LONG_HELP
|
||||
| Flags::NEEDS_SC_HELP
|
||||
| Flags::UTF8_NONE
|
||||
| Flags::COLOR_AUTO,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -713,7 +716,10 @@ pub enum AppSettings {
|
|||
///
|
||||
/// assert!(m.subcommand_matches("foo").is_none());
|
||||
/// ```
|
||||
#[deprecated(since = "2.27.0", note = "No longer required to propagate values")]
|
||||
#[deprecated(
|
||||
since = "2.27.0",
|
||||
note = "No longer required to propagate values"
|
||||
)]
|
||||
PropagateGlobalValuesDown,
|
||||
|
||||
/// Allows [`SubCommand`]s to override all requirements of the parent command.
|
||||
|
@ -925,23 +931,32 @@ pub enum AppSettings {
|
|||
/// [`SubCommand`]: ./struct.SubCommand.html
|
||||
WaitOnError,
|
||||
|
||||
#[doc(hidden)] NeedsLongVersion,
|
||||
#[doc(hidden)]
|
||||
NeedsLongVersion,
|
||||
|
||||
#[doc(hidden)] NeedsLongHelp,
|
||||
#[doc(hidden)]
|
||||
NeedsLongHelp,
|
||||
|
||||
#[doc(hidden)] NeedsSubcommandHelp,
|
||||
#[doc(hidden)]
|
||||
NeedsSubcommandHelp,
|
||||
|
||||
#[doc(hidden)] LowIndexMultiplePositional,
|
||||
#[doc(hidden)]
|
||||
LowIndexMultiplePositional,
|
||||
|
||||
#[doc(hidden)] TrailingValues,
|
||||
#[doc(hidden)]
|
||||
TrailingValues,
|
||||
|
||||
#[doc(hidden)] ValidNegNumFound,
|
||||
#[doc(hidden)]
|
||||
ValidNegNumFound,
|
||||
|
||||
#[doc(hidden)] Propagated,
|
||||
#[doc(hidden)]
|
||||
Propagated,
|
||||
|
||||
#[doc(hidden)] ValidArgFound,
|
||||
#[doc(hidden)]
|
||||
ValidArgFound,
|
||||
|
||||
#[doc(hidden)] ContainsLast,
|
||||
#[doc(hidden)]
|
||||
ContainsLast,
|
||||
}
|
||||
|
||||
impl FromStr for AppSettings {
|
||||
|
|
|
@ -86,7 +86,7 @@ pub enum ArgSettings {
|
|||
AllowEmptyValues,
|
||||
/// Sets an arg to be global (i.e. exist in all subcommands)
|
||||
/// **DEPRECATED**
|
||||
#[deprecated(since="2.32.0", note="Use `App::global_arg` instead")]
|
||||
#[deprecated(since = "2.32.0", note = "Use `App::global_arg` instead")]
|
||||
Global,
|
||||
/// Hides an arg from the help message
|
||||
Hidden,
|
||||
|
@ -119,8 +119,10 @@ pub enum ArgSettings {
|
|||
HiddenShortHelp,
|
||||
/// The argument should **not** be shown in long help text
|
||||
HiddenLongHelp,
|
||||
#[doc(hidden)] RequiredUnlessAll,
|
||||
#[doc(hidden)] ValueDelimiterNotSet,
|
||||
#[doc(hidden)]
|
||||
RequiredUnlessAll,
|
||||
#[doc(hidden)]
|
||||
ValueDelimiterNotSet,
|
||||
}
|
||||
|
||||
impl FromStr for ArgSettings {
|
||||
|
|
|
@ -129,7 +129,9 @@ impl<'a> ArgGroup<'a> {
|
|||
/// # }
|
||||
/// ```
|
||||
#[cfg(feature = "yaml")]
|
||||
pub fn from_yaml(y: &'a yaml_rust::Yaml) -> ArgGroup<'a> { ArgGroup::from(y.as_hash().unwrap()) }
|
||||
pub fn from_yaml(y: &'a yaml_rust::Yaml) -> ArgGroup<'a> {
|
||||
ArgGroup::from(y.as_hash().unwrap())
|
||||
}
|
||||
|
||||
/// Adds an [argument] to this group by name
|
||||
///
|
||||
|
|
|
@ -1,72 +1,75 @@
|
|||
#[cfg(feature = "yaml")]
|
||||
macro_rules! yaml_tuple2 {
|
||||
($a:ident, $v:ident, $c:ident) => {{
|
||||
if let Some(vec) = $v.as_vec() {
|
||||
for ys in vec {
|
||||
if let Some(tup) = ys.as_vec() {
|
||||
debug_assert_eq!(2, tup.len());
|
||||
$a = $a.$c(yaml_str!(tup[0]), yaml_str!(tup[1]));
|
||||
} else {
|
||||
panic!("Failed to convert YAML value to vec");
|
||||
}
|
||||
if let Some(vec) = $v.as_vec() {
|
||||
for ys in vec {
|
||||
if let Some(tup) = ys.as_vec() {
|
||||
debug_assert_eq!(2, tup.len());
|
||||
$a = $a.$c(yaml_str!(tup[0]), yaml_str!(tup[1]));
|
||||
} else {
|
||||
panic!("Failed to convert YAML value to vec");
|
||||
}
|
||||
} else {
|
||||
panic!("Failed to convert YAML value to vec");
|
||||
}
|
||||
$a
|
||||
} else {
|
||||
panic!("Failed to convert YAML value to vec");
|
||||
}
|
||||
};
|
||||
$a
|
||||
}};
|
||||
}
|
||||
|
||||
#[cfg(feature = "yaml")]
|
||||
macro_rules! yaml_tuple3 {
|
||||
($a:ident, $v:ident, $c:ident) => {{
|
||||
if let Some(vec) = $v.as_vec() {
|
||||
for ys in vec {
|
||||
if let Some(tup) = ys.as_vec() {
|
||||
debug_assert_eq!(3, tup.len());
|
||||
$a = $a.$c(yaml_str!(tup[0]), yaml_opt_str!(tup[1]), yaml_str!(tup[2]));
|
||||
} else {
|
||||
panic!("Failed to convert YAML value to vec");
|
||||
}
|
||||
if let Some(vec) = $v.as_vec() {
|
||||
for ys in vec {
|
||||
if let Some(tup) = ys.as_vec() {
|
||||
debug_assert_eq!(3, tup.len());
|
||||
$a = $a.$c(yaml_str!(tup[0]), yaml_opt_str!(tup[1]), yaml_str!(tup[2]));
|
||||
} else {
|
||||
panic!("Failed to convert YAML value to vec");
|
||||
}
|
||||
} else {
|
||||
panic!("Failed to convert YAML value to vec");
|
||||
}
|
||||
$a
|
||||
} else {
|
||||
panic!("Failed to convert YAML value to vec");
|
||||
}
|
||||
};
|
||||
$a
|
||||
}};
|
||||
}
|
||||
|
||||
#[cfg(feature = "yaml")]
|
||||
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() {
|
||||
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 either a vec or string", $v);
|
||||
panic!("Failed to convert YAML value {:?} to a string", ys);
|
||||
}
|
||||
}
|
||||
$a
|
||||
} 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
|
||||
}};
|
||||
}
|
||||
|
||||
#[cfg(feature = "yaml")]
|
||||
macro_rules! yaml_opt_str {
|
||||
($v:expr) => {{
|
||||
if $v.is_null() {
|
||||
Some($v.as_str().unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v)))
|
||||
Some(
|
||||
$v.as_str()
|
||||
.unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v)),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -76,7 +79,8 @@ macro_rules! yaml_opt_str {
|
|||
#[cfg(feature = "yaml")]
|
||||
macro_rules! yaml_str {
|
||||
($v:expr) => {{
|
||||
$v.as_str().unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v))
|
||||
$v.as_str()
|
||||
.unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v))
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -90,20 +94,28 @@ macro_rules! yaml_to_str {
|
|||
#[cfg(feature = "yaml")]
|
||||
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)))
|
||||
$a.$c($v
|
||||
.as_bool()
|
||||
.unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v)))
|
||||
}};
|
||||
}
|
||||
|
||||
#[cfg(feature = "yaml")]
|
||||
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)
|
||||
$a.$c($v
|
||||
.as_i64()
|
||||
.unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v))
|
||||
as u64)
|
||||
}};
|
||||
}
|
||||
|
||||
#[cfg(feature = "yaml")]
|
||||
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)
|
||||
$a.$c($v
|
||||
.as_i64()
|
||||
.unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v))
|
||||
as usize)
|
||||
}};
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ pub mod arg;
|
|||
mod arg_group;
|
||||
mod usage_parser;
|
||||
|
||||
pub use self::usage_parser::UsageParser;
|
||||
pub use self::app::{App, AppFlags, AppSettings, Propagation};
|
||||
pub use self::arg::{Arg, ArgFlags, ArgSettings};
|
||||
pub use self::arg_group::ArgGroup;
|
||||
pub use self::arg_group::ArgGroup;
|
||||
pub use self::usage_parser::UsageParser;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Internal
|
||||
use INTERNAL_ERROR_MSG;
|
||||
use build::{Arg, ArgSettings};
|
||||
use util::VecMap;
|
||||
use INTERNAL_ERROR_MSG;
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum UsageToken {
|
||||
|
@ -74,7 +74,8 @@ impl<'a> UsageParser<'a> {
|
|||
|
||||
fn name(&mut self, arg: &mut Arg<'a, 'a>) {
|
||||
debugln!("UsageParser::name;");
|
||||
if *self.usage
|
||||
if *self
|
||||
.usage
|
||||
.as_bytes()
|
||||
.get(self.pos)
|
||||
.expect(INTERNAL_ERROR_MSG) == b'<' && !self.explicit_name_set
|
||||
|
@ -122,7 +123,8 @@ impl<'a> UsageParser<'a> {
|
|||
fn short_or_long(&mut self, arg: &mut Arg<'a, 'a>) {
|
||||
debugln!("UsageParser::short_or_long;");
|
||||
self.pos += 1;
|
||||
if *self.usage
|
||||
if *self
|
||||
.usage
|
||||
.as_bytes()
|
||||
.get(self.pos)
|
||||
.expect(INTERNAL_ERROR_MSG) == b'-'
|
||||
|
|
|
@ -8,7 +8,7 @@ use INTERNAL_ERROR_MSG;
|
|||
pub struct ElvishGen<'a, 'b, 'c>
|
||||
where
|
||||
'a: 'b,
|
||||
'b: 'c
|
||||
'b: 'c,
|
||||
{
|
||||
app: &'c App<'a, 'b>,
|
||||
}
|
||||
|
@ -20,10 +20,10 @@ impl<'a, 'b, 'c> ElvishGen<'a, 'b, 'c> {
|
|||
let bin_name = self.app.bin_name.as_ref().unwrap();
|
||||
|
||||
let mut names = vec![];
|
||||
let subcommands_cases =
|
||||
generate_inner(self.app, "", &mut names);
|
||||
let subcommands_cases = generate_inner(self.app, "", &mut names);
|
||||
|
||||
let result = format!(r#"
|
||||
let result = format!(
|
||||
r#"
|
||||
edit:completion:arg-completer[{bin_name}] = [@words]{{
|
||||
fn spaces [n]{{
|
||||
repeat $n ' ' | joins ''
|
||||
|
@ -54,10 +54,10 @@ edit:completion:arg-completer[{bin_name}] = [@words]{{
|
|||
// Escape string inside single quotes
|
||||
fn escape_string(string: &str) -> String { string.replace("'", "''") }
|
||||
|
||||
fn get_tooltip<T : ToString>(help: Option<&str>, data: T) -> String {
|
||||
fn get_tooltip<T: ToString>(help: Option<&str>, data: T) -> String {
|
||||
match help {
|
||||
Some(help) => escape_string(help),
|
||||
_ => data.to_string()
|
||||
_ => data.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,11 @@ fn generate_inner<'a, 'b, 'c>(
|
|||
p: &'c App<'a, 'b>,
|
||||
previous_command_name: &str,
|
||||
names: &mut Vec<&'a str>,
|
||||
) -> String where 'a: 'b, 'b: 'c{
|
||||
) -> String
|
||||
where
|
||||
'a: 'b,
|
||||
'b: 'c,
|
||||
{
|
||||
debugln!("ElvishGen::generate_inner;");
|
||||
let command_name = if previous_command_name.is_empty() {
|
||||
p.bin_name.as_ref().expect(INTERNAL_ERROR_MSG).clone()
|
||||
|
@ -113,13 +117,11 @@ fn generate_inner<'a, 'b, 'c>(
|
|||
r"
|
||||
&'{}'= {{{}
|
||||
}}",
|
||||
&command_name,
|
||||
completions
|
||||
&command_name, completions
|
||||
);
|
||||
|
||||
for subcommand in &p.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);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,5 +24,5 @@ macro_rules! get_zsh_arg_conflicts {
|
|||
} else {
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
#[macro_use]
|
||||
mod macros;
|
||||
mod bash;
|
||||
mod fish;
|
||||
mod zsh;
|
||||
mod powershell;
|
||||
mod elvish;
|
||||
mod fish;
|
||||
mod powershell;
|
||||
mod shell;
|
||||
mod zsh;
|
||||
|
||||
// Std
|
||||
use std::io::Write;
|
||||
|
||||
// Internal
|
||||
use build::App;
|
||||
use self::bash::BashGen;
|
||||
use self::fish::FishGen;
|
||||
use self::zsh::ZshGen;
|
||||
use self::powershell::PowerShellGen;
|
||||
use self::elvish::ElvishGen;
|
||||
use self::fish::FishGen;
|
||||
use self::powershell::PowerShellGen;
|
||||
pub use self::shell::Shell;
|
||||
use self::zsh::ZshGen;
|
||||
use build::App;
|
||||
|
||||
pub struct ComplGen<'a, 'b>(&'b App<'a, 'b>)
|
||||
where
|
||||
|
@ -33,7 +33,7 @@ impl<'a, 'b> ComplGen<'a, 'b> {
|
|||
Shell::Zsh => ZshGen::new(self.0).generate_to(buf),
|
||||
Shell::PowerShell => PowerShellGen::new(self.0).generate_to(buf),
|
||||
Shell::Elvish => ElvishGen::new(self.0).generate_to(buf),
|
||||
_ => panic!("Unsupported shell type for generating completions")
|
||||
_ => panic!("Unsupported shell type for generating completions"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,10 +16,10 @@ impl<'a, 'b> PowerShellGen<'a, 'b> {
|
|||
let bin_name = self.0.bin_name.as_ref().unwrap();
|
||||
|
||||
let mut names = vec![];
|
||||
let subcommands_cases =
|
||||
generate_inner(self.0, "", &mut names);
|
||||
let subcommands_cases = generate_inner(self.0, "", &mut names);
|
||||
|
||||
let result = format!(r#"
|
||||
let result = format!(
|
||||
r#"
|
||||
using namespace System.Management.Automation
|
||||
using namespace System.Management.Automation.Language
|
||||
|
||||
|
@ -57,10 +57,10 @@ Register-ArgumentCompleter -Native -CommandName '{bin_name}' -ScriptBlock {{
|
|||
// Escape string inside single quotes
|
||||
fn escape_string(string: &str) -> String { string.replace("'", "''") }
|
||||
|
||||
fn get_tooltip<T : ToString>(help: Option<&str>, data: T) -> String {
|
||||
fn get_tooltip<T: ToString>(help: Option<&str>, data: T) -> String {
|
||||
match help {
|
||||
Some(help) => escape_string(&help),
|
||||
_ => data.to_string()
|
||||
_ => data.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,14 +83,22 @@ fn generate_inner<'a, 'b, 'p>(
|
|||
if let Some(data) = option.short {
|
||||
let tooltip = get_tooltip(option.help, data);
|
||||
completions.push_str(&preamble);
|
||||
completions.push_str(format!("'-{}', '{}', {}, '{}')",
|
||||
data, data, "[CompletionResultType]::ParameterName", tooltip).as_str());
|
||||
completions.push_str(
|
||||
format!(
|
||||
"'-{}', '{}', {}, '{}')",
|
||||
data, data, "[CompletionResultType]::ParameterName", tooltip
|
||||
).as_str(),
|
||||
);
|
||||
}
|
||||
if let Some(data) = option.long {
|
||||
let tooltip = get_tooltip(option.help, data);
|
||||
completions.push_str(&preamble);
|
||||
completions.push_str(format!("'--{}', '{}', {}, '{}')",
|
||||
data, data, "[CompletionResultType]::ParameterName", tooltip).as_str());
|
||||
completions.push_str(
|
||||
format!(
|
||||
"'--{}', '{}', {}, '{}')",
|
||||
data, data, "[CompletionResultType]::ParameterName", tooltip
|
||||
).as_str(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,14 +106,22 @@ fn generate_inner<'a, 'b, 'p>(
|
|||
if let Some(data) = flag.short {
|
||||
let tooltip = get_tooltip(flag.help, data);
|
||||
completions.push_str(&preamble);
|
||||
completions.push_str(format!("'-{}', '{}', {}, '{}')",
|
||||
data, data, "[CompletionResultType]::ParameterName", tooltip).as_str());
|
||||
completions.push_str(
|
||||
format!(
|
||||
"'-{}', '{}', {}, '{}')",
|
||||
data, data, "[CompletionResultType]::ParameterName", tooltip
|
||||
).as_str(),
|
||||
);
|
||||
}
|
||||
if let Some(data) = flag.long {
|
||||
let tooltip = get_tooltip(flag.help, data);
|
||||
completions.push_str(&preamble);
|
||||
completions.push_str(format!("'--{}', '{}', {}, '{}')",
|
||||
data, data, "[CompletionResultType]::ParameterName", tooltip).as_str());
|
||||
completions.push_str(
|
||||
format!(
|
||||
"'--{}', '{}', {}, '{}')",
|
||||
data, data, "[CompletionResultType]::ParameterName", tooltip
|
||||
).as_str(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,8 +129,12 @@ fn generate_inner<'a, 'b, 'p>(
|
|||
let data = &subcommand.name;
|
||||
let tooltip = get_tooltip(subcommand.about, data);
|
||||
completions.push_str(&preamble);
|
||||
completions.push_str(format!("'{}', '{}', {}, '{}')",
|
||||
data, data, "[CompletionResultType]::ParameterValue", tooltip).as_str());
|
||||
completions.push_str(
|
||||
format!(
|
||||
"'{}', '{}', {}, '{}')",
|
||||
data, data, "[CompletionResultType]::ParameterValue", tooltip
|
||||
).as_str(),
|
||||
);
|
||||
}
|
||||
|
||||
let mut subcommands_cases = format!(
|
||||
|
@ -122,13 +142,11 @@ fn generate_inner<'a, 'b, 'p>(
|
|||
'{}' {{{}
|
||||
break
|
||||
}}",
|
||||
&command_name,
|
||||
completions
|
||||
&command_name, completions
|
||||
);
|
||||
|
||||
for subcommand in &p.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);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#[allow(unused_imports)]
|
||||
use std::ascii::AsciiExt;
|
||||
use std::str::FromStr;
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
/// Describes which shell to produce a completions file for
|
||||
#[cfg_attr(feature = "lints", allow(enum_variant_names))]
|
||||
|
@ -36,7 +36,9 @@ impl FromStr for Shell {
|
|||
"BASH" | _ if s.eq_ignore_ascii_case("bash") => Ok(Shell::Bash),
|
||||
"POWERSHELL" | _ if s.eq_ignore_ascii_case("powershell") => Ok(Shell::PowerShell),
|
||||
"ELVISH" | _ if s.eq_ignore_ascii_case("elvish") => Ok(Shell::Elvish),
|
||||
_ => Err(String::from("[valid values: bash, fish, zsh, powershell, elvish]")),
|
||||
_ => Err(String::from(
|
||||
"[valid values: bash, fish, zsh, powershell, elvish]",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +51,7 @@ impl fmt::Display for Shell {
|
|||
Shell::Zsh => write!(f, "ZSH"),
|
||||
Shell::PowerShell => write!(f, "POWERSHELL"),
|
||||
Shell::Elvish => write!(f, "ELVISH"),
|
||||
_ => panic!("Unsupported shell type for completion generation")
|
||||
_ => panic!("Unsupported shell type for completion generation"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Std
|
||||
use std::io::Write;
|
||||
#[allow(unused_imports)]
|
||||
use std::ascii::AsciiExt;
|
||||
use std::io::Write;
|
||||
|
||||
// Internal
|
||||
use build::{App, ArgSettings};
|
||||
|
@ -86,9 +86,8 @@ _{name} \"$@\"",
|
|||
fn subcommand_details(p: &App) -> String {
|
||||
debugln!("ZshGen::subcommand_details;");
|
||||
// First we do ourself
|
||||
let mut ret = vec![
|
||||
format!(
|
||||
"\
|
||||
let mut ret = vec![format!(
|
||||
"\
|
||||
(( $+functions[_{bin_name_underscore}_commands] )) ||
|
||||
_{bin_name_underscore}_commands() {{
|
||||
local commands; commands=(
|
||||
|
@ -96,11 +95,10 @@ _{bin_name_underscore}_commands() {{
|
|||
)
|
||||
_describe -t commands '{bin_name} commands' commands \"$@\"
|
||||
}}",
|
||||
bin_name_underscore = p.bin_name.as_ref().unwrap().replace(" ", "__"),
|
||||
bin_name = p.bin_name.as_ref().unwrap(),
|
||||
subcommands_and_args = subcommands_of(p)
|
||||
),
|
||||
];
|
||||
bin_name_underscore = p.bin_name.as_ref().unwrap().replace(" ", "__"),
|
||||
bin_name = p.bin_name.as_ref().unwrap(),
|
||||
subcommands_and_args = subcommands_of(p)
|
||||
)];
|
||||
|
||||
// Next we start looping through all the children, grandchildren, etc.
|
||||
let mut all_subcommands = completions::all_subcommands(p);
|
||||
|
@ -145,7 +143,8 @@ fn subcommands_of(p: &App) -> String {
|
|||
let s = format!(
|
||||
"\"{name}:{help}\" \\",
|
||||
name = n,
|
||||
help = sc.about
|
||||
help = sc
|
||||
.about
|
||||
.unwrap_or("")
|
||||
.replace("[", "\\[")
|
||||
.replace("]", "\\]")
|
||||
|
@ -458,20 +457,24 @@ fn write_positionals_of(p: &App) -> String {
|
|||
""
|
||||
},
|
||||
name = arg.name,
|
||||
help = arg.help
|
||||
help = arg
|
||||
.help
|
||||
.map_or("".to_owned(), |v| " -- ".to_owned() + v)
|
||||
.replace("[", "\\[")
|
||||
.replace("]", "\\]"),
|
||||
action = arg.possible_vals
|
||||
action = arg
|
||||
.possible_vals
|
||||
.as_ref()
|
||||
.map_or("_files".to_owned(), |values| format!(
|
||||
"({})",
|
||||
values
|
||||
.iter()
|
||||
.map(|v| escape_value(*v))
|
||||
.collect::<Vec<String>>()
|
||||
.join(" ")
|
||||
))
|
||||
.map_or("_files".to_owned(), |values| {
|
||||
format!(
|
||||
"({})",
|
||||
values
|
||||
.iter()
|
||||
.map(|v| escape_value(*v))
|
||||
.collect::<Vec<String>>()
|
||||
.join(" ")
|
||||
)
|
||||
})
|
||||
);
|
||||
|
||||
debugln!("write_positionals_of:iter: Wrote...{}", a);
|
||||
|
|
10
src/lib.rs
10
src/lib.rs
|
@ -517,7 +517,11 @@
|
|||
//! [license]: https://raw.githubusercontent.com/kbknapp/clap-rs/master/LICENSE-MIT
|
||||
|
||||
#![crate_type = "lib"]
|
||||
<<<<<<< HEAD
|
||||
#![doc(html_root_url = "https://docs.rs/clap/3.0.0-alpha.1")]
|
||||
=======
|
||||
#![doc(html_root_url = "https://docs.rs/clap/3.0.0-alpha1")]
|
||||
>>>>>>> WIP. Big reformat
|
||||
#![deny(
|
||||
missing_docs,
|
||||
missing_debug_implementations,
|
||||
|
@ -582,11 +586,17 @@ use std::result::Result as StdResult;
|
|||
#[macro_use]
|
||||
mod macros;
|
||||
<<<<<<< HEAD
|
||||
<<<<<<< HEAD
|
||||
mod build;
|
||||
=======
|
||||
mod mkeymap;
|
||||
>>>>>>> WIP changing macros into MKeyMap calls
|
||||
mod completions;
|
||||
=======
|
||||
mod build;
|
||||
mod completions;
|
||||
mod mkeymap;
|
||||
>>>>>>> WIP. Big reformat
|
||||
mod output;
|
||||
mod parse;
|
||||
mod util;
|
||||
|
|
246
src/macros.rs
246
src/macros.rs
|
@ -26,9 +26,10 @@
|
|||
#[cfg(feature = "yaml")]
|
||||
#[macro_export]
|
||||
macro_rules! load_yaml {
|
||||
($yml:expr) => (
|
||||
&::clap::YamlLoader::load_from_str(include_str!($yml)).expect("failed to load YAML file")[0]
|
||||
);
|
||||
($yml:expr) => {
|
||||
&::clap::YamlLoader::load_from_str(include_str!($yml))
|
||||
.expect("failed to load YAML file")[0]
|
||||
};
|
||||
}
|
||||
|
||||
/// Convenience macro getting a typed value `T` where `T` implements [`std::str::FromStr`] from an
|
||||
|
@ -66,9 +67,10 @@ macro_rules! value_t {
|
|||
if let Some(v) = $m.value_of($v) {
|
||||
match v.parse::<$t>() {
|
||||
Ok(val) => Ok(val),
|
||||
Err(_) =>
|
||||
Err(::clap::Error::value_validation_auto(
|
||||
format!("The argument '{}' isn't a valid value", v))),
|
||||
Err(_) => Err(::clap::Error::value_validation_auto(format!(
|
||||
"The argument '{}' isn't a valid value",
|
||||
v
|
||||
))),
|
||||
}
|
||||
} else {
|
||||
Err(::clap::Error::argument_not_found_auto($v))
|
||||
|
@ -111,9 +113,10 @@ macro_rules! value_t_or_exit {
|
|||
if let Some(v) = $m.value_of($v) {
|
||||
match v.parse::<$t>() {
|
||||
Ok(val) => val,
|
||||
Err(_) =>
|
||||
::clap::Error::value_validation_auto(
|
||||
format!("The argument '{}' isn't a valid value", v)).exit(),
|
||||
Err(_) => ::clap::Error::value_validation_auto(format!(
|
||||
"The argument '{}' isn't a valid value",
|
||||
v
|
||||
)).exit(),
|
||||
}
|
||||
} else {
|
||||
::clap::Error::argument_not_found_auto($v).exit()
|
||||
|
@ -163,9 +166,11 @@ macro_rules! values_t {
|
|||
match pv.parse::<$t>() {
|
||||
Ok(rv) => tmp.push(rv),
|
||||
Err(..) => {
|
||||
err = Some(::clap::Error::value_validation_auto(
|
||||
format!("The argument '{}' isn't a valid value", pv)));
|
||||
break
|
||||
err = Some(::clap::Error::value_validation_auto(format!(
|
||||
"The argument '{}' isn't a valid value",
|
||||
pv
|
||||
)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -218,10 +223,13 @@ macro_rules! values_t_or_exit {
|
|||
};
|
||||
($m:ident.values_of($v:expr), $t:ty) => {
|
||||
if let Some(vals) = $m.values_of($v) {
|
||||
vals.map(|v| v.parse::<$t>().unwrap_or_else(|_|{
|
||||
::clap::Error::value_validation_auto(
|
||||
format!("One or more arguments aren't valid values")).exit()
|
||||
})).collect::<Vec<$t>>()
|
||||
vals.map(|v| {
|
||||
v.parse::<$t>().unwrap_or_else(|_| {
|
||||
::clap::Error::value_validation_auto(format!(
|
||||
"One or more arguments aren't valid values"
|
||||
)).exit()
|
||||
})
|
||||
}).collect::<Vec<$t>>()
|
||||
} else {
|
||||
::clap::Error::argument_not_found_auto($v).exit()
|
||||
}
|
||||
|
@ -451,12 +459,14 @@ macro_rules! crate_version {
|
|||
macro_rules! crate_authors {
|
||||
($sep:expr) => {{
|
||||
use std::ops::Deref;
|
||||
use std::sync::{ONCE_INIT, Once};
|
||||
use std::sync::{Once, ONCE_INIT};
|
||||
|
||||
#[allow(missing_copy_implementations)]
|
||||
#[allow(dead_code)]
|
||||
struct CargoAuthors { __private_field: () };
|
||||
|
||||
struct CargoAuthors {
|
||||
__private_field: (),
|
||||
};
|
||||
|
||||
impl Deref for CargoAuthors {
|
||||
type Target = str;
|
||||
|
||||
|
@ -476,7 +486,9 @@ macro_rules! crate_authors {
|
|||
}
|
||||
}
|
||||
|
||||
&*CargoAuthors { __private_field: () }
|
||||
&*CargoAuthors {
|
||||
__private_field: (),
|
||||
}
|
||||
}};
|
||||
() => {
|
||||
env!("CARGO_PKG_AUTHORS")
|
||||
|
@ -845,16 +857,16 @@ mod debug_macros {
|
|||
#[cfg_attr(not(feature = "debug"), macro_use)]
|
||||
mod debug_macros {
|
||||
macro_rules! debugln {
|
||||
($fmt:expr) => ();
|
||||
($fmt:expr, $($arg:tt)*) => ();
|
||||
($fmt:expr) => {};
|
||||
($fmt:expr, $($arg:tt)*) => {};
|
||||
}
|
||||
macro_rules! sdebugln {
|
||||
($fmt:expr) => ();
|
||||
($fmt:expr, $($arg:tt)*) => ();
|
||||
($fmt:expr) => {};
|
||||
($fmt:expr, $($arg:tt)*) => {};
|
||||
}
|
||||
macro_rules! debug {
|
||||
($fmt:expr) => ();
|
||||
($fmt:expr, $($arg:tt)*) => ();
|
||||
($fmt:expr) => {};
|
||||
($fmt:expr, $($arg:tt)*) => {};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -863,12 +875,12 @@ mod debug_macros {
|
|||
// src/args/arg_builder/*.rs
|
||||
// src/app/mod.rs
|
||||
macro_rules! write_nspaces {
|
||||
($dst:expr, $num:expr) => ({
|
||||
($dst:expr, $num:expr) => {{
|
||||
debugln!("write_spaces!: num={}", $num);
|
||||
for _ in 0..$num {
|
||||
$dst.write_all(b" ")?;
|
||||
}
|
||||
})
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! args {
|
||||
|
@ -876,70 +888,94 @@ macro_rules! args {
|
|||
$app.args.$how()
|
||||
};
|
||||
($app:expr) => {
|
||||
args!($app, iter)
|
||||
}
|
||||
args!($app, values)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! args_mut {
|
||||
($app:expr) => {
|
||||
args!($app, iter_mut)
|
||||
}
|
||||
args!($app, values_mut)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! flags {
|
||||
($app:expr, $how:ident) => {
|
||||
$app.args.$how()
|
||||
.filter(|a| !a.settings.is_set(::build::ArgSettings::TakesValue))
|
||||
.filter(|a| a.short.is_some() || a.long.is_some())
|
||||
.filter(|a| !a.help_heading.is_some())
|
||||
};
|
||||
($app:expr, $how:ident) => {{
|
||||
use mkeymap::KeyType::*;
|
||||
$app.args
|
||||
.$how()
|
||||
.filter(|(k, a)| !a.settings.is_set(::build::ArgSettings::TakesValue))
|
||||
.filter(|(k, a)| match k {
|
||||
Long(_) => true,
|
||||
Short(_) => true,
|
||||
Position(_) => false,
|
||||
})
|
||||
.filter(|(k, a)| !a.help_heading.is_some())
|
||||
}};
|
||||
($app:expr) => {
|
||||
flags!($app, iter)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! flags_mut {
|
||||
($app:expr) => {
|
||||
flags!($app, iter_mut)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! opts {
|
||||
($app:expr, $how:ident) => {
|
||||
$app.args.$how()
|
||||
.filter(|a| a.settings.is_set(::build::ArgSettings::TakesValue))
|
||||
.filter(|a| a.short.is_some() || a.long.is_some())
|
||||
.filter(|a| !a.help_heading.is_some())
|
||||
};
|
||||
($app:expr, $how:ident) => {{
|
||||
use mkeymap::KeyType::*;
|
||||
$app.args
|
||||
.$how()
|
||||
.filter(|(k, a)| a.settings.is_set(::build::ArgSettings::TakesValue))
|
||||
.filter(|(k, a)| match k {
|
||||
Long(_) => true,
|
||||
Short(_) => true,
|
||||
Position(_) => false,
|
||||
})
|
||||
.filter(|(k, a)| !a.help_heading.is_some())
|
||||
}};
|
||||
($app:expr) => {
|
||||
opts!($app, iter)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! opts_mut {
|
||||
($app:expr) => {
|
||||
opts!($app, iter_mut)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// * We need a way to iterate through all the Positional Args
|
||||
// macro_rules! positionals {
|
||||
// ($app:expr, $how:ident) => {
|
||||
// $app.args
|
||||
// .$how()
|
||||
// .filter(|a| !a.help_heading.is_some())
|
||||
// .filter(|a| !(a.short.is_some() || a.long.is_some()))
|
||||
// };
|
||||
// ($app:expr) => {
|
||||
// positionals!($app, values)
|
||||
// };
|
||||
// }
|
||||
|
||||
macro_rules! positionals {
|
||||
($app:expr, $how:ident) => {
|
||||
$app.args.$how()
|
||||
.filter(|a| !a.help_heading.is_some())
|
||||
($app:expr) => {
|
||||
$app.args
|
||||
.values()
|
||||
.filter(|a| !(a.short.is_some() || a.long.is_some()))
|
||||
};
|
||||
($app:expr) => {
|
||||
positionals!($app, iter)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! positionals_mut {
|
||||
($app:expr) => {
|
||||
positionals!($app, iter_mut)
|
||||
}
|
||||
$app.args
|
||||
.values_mut()
|
||||
.filter(|a| !(a.short.is_some() || a.long.is_some()))
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(unused_macros)]
|
||||
|
@ -948,15 +984,15 @@ macro_rules! custom_headings {
|
|||
$app.args.$how().filter(|a| (a.help_heading.is_some()))
|
||||
};
|
||||
($app:expr) => {
|
||||
custom_headings!($app, iter)
|
||||
}
|
||||
custom_headings!($app, values)
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! custom_headings_mut {
|
||||
($app:expr) => {
|
||||
custom_headings!($app, iter_mut)
|
||||
}
|
||||
custom_headings!($app, values_mut)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! subcommands_cloned {
|
||||
|
@ -965,7 +1001,7 @@ macro_rules! subcommands_cloned {
|
|||
};
|
||||
($app:expr) => {
|
||||
subcommands_cloned!($app, iter)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! subcommands {
|
||||
|
@ -974,13 +1010,13 @@ macro_rules! subcommands {
|
|||
};
|
||||
($app:expr) => {
|
||||
subcommands!($app, iter)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! subcommands_mut {
|
||||
($app:expr) => {
|
||||
subcommands!($app, iter_mut)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! groups {
|
||||
|
@ -989,13 +1025,13 @@ macro_rules! groups {
|
|||
};
|
||||
($app:expr) => {
|
||||
groups!($app, iter)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! groups_mut {
|
||||
($app:expr) => {
|
||||
groups!($app, iter_mut)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! find_from {
|
||||
|
@ -1015,13 +1051,14 @@ macro_rules! find_from {
|
|||
}
|
||||
|
||||
// Finds an arg by name
|
||||
// ! look up usages and find ways to improve performance
|
||||
macro_rules! find {
|
||||
($app:expr, $name:expr, $what:ident) => {
|
||||
$what!($app).find(|a| &a.name == $name)
|
||||
};
|
||||
($app:expr, $name:expr) => {
|
||||
$app.args.iter().find(|a| &a.name == $name)
|
||||
}
|
||||
$app.args.values().find(|a| &a.name == $name)
|
||||
};
|
||||
}
|
||||
|
||||
// macro_rules! find_by_long {
|
||||
|
@ -1050,15 +1087,13 @@ macro_rules! find {
|
|||
|
||||
macro_rules! find_subcmd_cloned {
|
||||
($_self:expr, $sc:expr) => {{
|
||||
subcommands_cloned!($_self)
|
||||
.find(|a| match_alias!(a, $sc, &*a.name))
|
||||
subcommands_cloned!($_self).find(|a| match_alias!(a, $sc, &*a.name))
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! find_subcmd {
|
||||
($app:expr, $sc:expr) => {{
|
||||
subcommands!($app)
|
||||
.find(|a| match_alias!(a, $sc, &*a.name))
|
||||
subcommands!($app).find(|a| match_alias!(a, $sc, &*a.name))
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -1085,35 +1120,45 @@ macro_rules! find_subcmd {
|
|||
// }};
|
||||
// }
|
||||
|
||||
//TODO change into one macro (repeated structure)
|
||||
//TODO change into one macro (repeated structure) + Positionals
|
||||
macro_rules! longs {
|
||||
($app:expr) => ({
|
||||
($app:expr) => {{
|
||||
use mkeymap::KeyType;
|
||||
$app.args.keys().filter_map(|a| if let KeyType::Long(v) = a {Some(v)} else {None})
|
||||
});
|
||||
$app.args.keys().filter_map(|a| {
|
||||
if let KeyType::Long(v) = a {
|
||||
Some(v)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! shorts {
|
||||
($app:expr) => ({
|
||||
($app:expr) => {{
|
||||
use mkeymap::KeyType;
|
||||
$app.args.keys().filter_map(|a| if let KeyType::Short(v) = a {Some(v)} else {None})
|
||||
})
|
||||
$app.args.keys().filter_map(|a| {
|
||||
if let KeyType::Short(v) = a {
|
||||
Some(v)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! _names {
|
||||
(@args $app:expr) => {{
|
||||
$app.args.iter().map(|a| &*a.name)
|
||||
$app.args.values().map(|a| &*a.name)
|
||||
}};
|
||||
(@sc $app:expr) => {{
|
||||
$app.subcommands
|
||||
.iter()
|
||||
.map(|s| &*s.name)
|
||||
.chain($app.subcommands
|
||||
.iter()
|
||||
.filter(|s| s.aliases.is_some())
|
||||
.flat_map(|s| s.aliases.as_ref().unwrap().iter().map(|&(n, _)| n)))
|
||||
|
||||
}}
|
||||
$app.subcommands.iter().map(|s| &*s.name).chain(
|
||||
$app.subcommands
|
||||
.iter()
|
||||
.filter(|s| s.aliases.is_some())
|
||||
.flat_map(|s| s.aliases.as_ref().unwrap().iter().map(|&(n, _)| n)),
|
||||
)
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! arg_names {
|
||||
|
@ -1128,15 +1173,16 @@ macro_rules! sc_names {
|
|||
}};
|
||||
}
|
||||
|
||||
// macro_rules! match_alias {
|
||||
// ($a:expr, $to:expr, $what:expr) => {{
|
||||
// $what == $to ||
|
||||
// ($a.aliases.is_some() &&
|
||||
// $a.aliases
|
||||
// .as_ref()
|
||||
// .unwrap()
|
||||
// .iter()
|
||||
// .any(|alias| alias.0 == $to))
|
||||
|
||||
// }}
|
||||
// }
|
||||
//probably scrap it altogether, as instead of iterating and matching alias we can just find by a Long
|
||||
macro_rules! match_alias {
|
||||
($a:expr, $to:expr, $what:expr) => {{
|
||||
$what == $to
|
||||
|| ($a.aliases.is_some()
|
||||
&& $a
|
||||
.aliases
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|alias| alias.0 == $to))
|
||||
}};
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ impl<'a, 'b> MKeyMap<'a, 'b> {
|
|||
set
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
index
|
||||
}
|
||||
//TODO ::push_many([x, y])
|
||||
|
@ -89,6 +89,8 @@ impl<'a, 'b> MKeyMap<'a, 'b> {
|
|||
self.keys.insert(key, index);
|
||||
}
|
||||
|
||||
// ! Arg mutation functionality
|
||||
|
||||
pub fn get(&self, key: KeyType<'a>) -> Option<&Arg<'a, 'b>> {
|
||||
self.keys
|
||||
.get(&key)
|
||||
|
@ -97,13 +99,11 @@ impl<'a, 'b> MKeyMap<'a, 'b> {
|
|||
//TODO ::get_first([KeyA, KeyB])
|
||||
|
||||
pub fn get_mut(&mut self, key: KeyType<'a>) -> Option<&mut Arg<'a, 'b>> {
|
||||
if let Some(&idx) = self
|
||||
.keys
|
||||
.get(&key) {
|
||||
self.value_index.get_mut(idx)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
if let Some(&idx) = self.keys.get(&key) {
|
||||
self.value_index.get_mut(idx)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool { self.keys.is_empty() && self.values.is_empty() }
|
||||
|
@ -122,13 +122,13 @@ impl<'a, 'b> MKeyMap<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn values(&'a self) -> Values<'a, Arg> {
|
||||
pub fn values(&'a self) -> Values<'a, Arg<'a, 'b>> {
|
||||
Values {
|
||||
iter: self.value_index.iter(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn values_mut(&'a mut self) -> ValuesMut<'a, Arg> {
|
||||
pub fn values_mut(&'a mut self) -> ValuesMut<'a, Arg<'a, 'b>> {
|
||||
ValuesMut {
|
||||
iter: self.value_index.iter_mut(),
|
||||
}
|
||||
|
@ -173,14 +173,19 @@ impl<'a, V> Iterator for ValuesMut<'a, V> {
|
|||
fn next(&mut self) -> Option<Self::Item> { self.iter.next() }
|
||||
}
|
||||
|
||||
pub struct Iter<'a, 'b, 'c> where
|
||||
'a: 'b,
|
||||
'b: 'c {
|
||||
pub struct Iter<'a, 'b, 'c>
|
||||
where
|
||||
'a: 'b,
|
||||
'b: 'c,
|
||||
{
|
||||
map: &'c MKeyMap<'a, 'b>,
|
||||
keys: Keys<'c, usize>,
|
||||
}
|
||||
|
||||
impl <'a, 'b, 'c> Iterator for Iter<'a, 'b, 'c>
|
||||
impl<'a, 'b, 'c> Iterator for Iter<'a, 'b, 'c>
|
||||
where
|
||||
'a: 'b,
|
||||
'b: 'c,
|
||||
{
|
||||
type Item = (&'c KeyType<'a>, &'c Arg<'a, 'b>);
|
||||
|
||||
|
@ -203,11 +208,12 @@ mod tests {
|
|||
fn get_some_value() {
|
||||
let mut map: MKeyMap = MKeyMap::new();
|
||||
|
||||
{
|
||||
map.insert(Long(&OsStr::new("One")), Arg::with_name("Value1"));
|
||||
}
|
||||
map.insert(Long(&OsStr::new("One")), Arg::with_name("Value1"));
|
||||
|
||||
assert_eq!(map.get(Long(&OsStr::new("One"))), &Arg::with_name("Value1"));
|
||||
assert_eq!(
|
||||
map.get(Long(&OsStr::new("One"))),
|
||||
Some(&Arg::with_name("Value1"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -217,6 +223,8 @@ mod tests {
|
|||
|
||||
map.insert(Long(&OsStr::new("One")), Arg::with_name("Value1"));
|
||||
map.get(Long(&OsStr::new("Two")));
|
||||
|
||||
assert_eq!(map.get(Long(&OsStr::new("Two"))), None);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
|
@ -301,7 +309,7 @@ mod tests {
|
|||
|
||||
assert_eq!(
|
||||
map.get_mut(Long(&OsStr::new("One"))),
|
||||
&mut Arg::with_name("Value1")
|
||||
Some(&mut Arg::with_name("Value1"))
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ use ansi_term::Colour::{Green, Red, Yellow};
|
|||
|
||||
#[cfg(feature = "color")]
|
||||
use atty;
|
||||
use std::fmt;
|
||||
use std::env;
|
||||
use std::fmt;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
|
@ -164,9 +164,9 @@ impl<T: fmt::Display> fmt::Display for Format<T> {
|
|||
|
||||
#[cfg(all(test, feature = "color", not(target_os = "windows")))]
|
||||
mod test {
|
||||
use super::Format;
|
||||
use ansi_term::ANSIString;
|
||||
use ansi_term::Colour::{Green, Red, Yellow};
|
||||
use super::Format;
|
||||
|
||||
#[test]
|
||||
fn colored_output() {
|
||||
|
|
|
@ -7,18 +7,18 @@ use std::usize;
|
|||
|
||||
// Internal
|
||||
use build::{App, AppSettings, Arg, ArgSettings};
|
||||
use parse::Parser;
|
||||
use parse::errors::{Error, Result as ClapResult};
|
||||
use output::fmt::{Colorizer, ColorizerOption, Format};
|
||||
use output::Usage;
|
||||
use parse::errors::{Error, Result as ClapResult};
|
||||
use parse::Parser;
|
||||
use util::VecMap;
|
||||
use INTERNAL_ERROR_MSG;
|
||||
|
||||
// Third Party
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
#[cfg(feature = "wrap_help")]
|
||||
use term_size;
|
||||
use textwrap;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
#[cfg(not(feature = "wrap_help"))]
|
||||
mod term_size {
|
||||
|
@ -173,18 +173,16 @@ impl<'w> Help<'w> {
|
|||
impl<'w> Help<'w> {
|
||||
/// Writes help for each argument in the order they were declared to the wrapped stream.
|
||||
fn write_args_unsorted<'a, 'b, I>(&mut self, args: I) -> io::Result<()>
|
||||
where
|
||||
'a: 'b,
|
||||
I: Iterator<Item=&'b Arg<'a, 'b>>,
|
||||
where
|
||||
'a: 'b,
|
||||
I: Iterator<Item = &'b Arg<'a, 'b>>,
|
||||
{
|
||||
debugln!("Help::write_args_unsorted;");
|
||||
// The shortest an arg can legally be is 2 (i.e. '-x')
|
||||
self.longest = 2;
|
||||
let mut arg_v = Vec::with_capacity(10);
|
||||
let use_long = self.use_long;
|
||||
for arg in args.filter(|arg| {
|
||||
should_show_arg(use_long, *arg)
|
||||
}) {
|
||||
for arg in args.filter(|arg| should_show_arg(use_long, *arg)) {
|
||||
if arg.longest_filter() {
|
||||
self.longest = cmp::max(self.longest, str_width(arg.to_string().as_str()));
|
||||
}
|
||||
|
@ -207,9 +205,9 @@ impl<'w> Help<'w> {
|
|||
|
||||
/// Sorts arguments by length and display order and write their help to the wrapped stream.
|
||||
fn write_args<'a, 'b, I>(&mut self, args: I) -> io::Result<()>
|
||||
where
|
||||
'a: 'b,
|
||||
I: Iterator<Item=&'b Arg<'a, 'b>>,
|
||||
where
|
||||
'a: 'b,
|
||||
I: Iterator<Item = &'b Arg<'a, 'b>>,
|
||||
{
|
||||
debugln!("Help::write_args;");
|
||||
// The shortest an arg can legally be is 2 (i.e. '-x')
|
||||
|
@ -346,7 +344,8 @@ impl<'w> Help<'w> {
|
|||
let h_w = str_width(h) + str_width(&*spec_vals);
|
||||
let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp);
|
||||
let taken = self.longest + 12;
|
||||
self.force_next_line = !nlh && self.term_w >= taken
|
||||
self.force_next_line = !nlh
|
||||
&& self.term_w >= taken
|
||||
&& (taken as f32 / self.term_w as f32) > 0.40
|
||||
&& h_w > (self.term_w - taken);
|
||||
|
||||
|
@ -427,7 +426,12 @@ impl<'w> Help<'w> {
|
|||
}
|
||||
|
||||
/// Writes argument's help to the wrapped stream.
|
||||
fn help<'b, 'c>(&mut self, arg: &Arg<'b, 'c>, spec_vals: &str, prevent_nlh: bool) -> io::Result<()> {
|
||||
fn help<'b, 'c>(
|
||||
&mut self,
|
||||
arg: &Arg<'b, 'c>,
|
||||
spec_vals: &str,
|
||||
prevent_nlh: bool,
|
||||
) -> io::Result<()> {
|
||||
debugln!("Help::help;");
|
||||
let h = if self.use_long {
|
||||
arg.long_help.unwrap_or_else(|| arg.help.unwrap_or(""))
|
||||
|
@ -577,7 +581,8 @@ impl<'w> Help<'w> {
|
|||
let h_w = str_width(h) + str_width(&*spec_vals);
|
||||
let nlh = self.next_line_help;
|
||||
let taken = self.longest + 12;
|
||||
self.force_next_line = !nlh && self.term_w >= taken
|
||||
self.force_next_line = !nlh
|
||||
&& self.term_w >= taken
|
||||
&& (taken as f32 / self.term_w as f32) > 0.40
|
||||
&& h_w > (self.term_w - taken);
|
||||
|
||||
|
@ -739,16 +744,22 @@ impl<'w> Help<'w> {
|
|||
first = false;
|
||||
}
|
||||
if custom_headings {
|
||||
for heading in parser.app.help_headings.iter()
|
||||
for heading in parser
|
||||
.app
|
||||
.help_headings
|
||||
.iter()
|
||||
.filter(|heading| heading.is_some())
|
||||
.map(|heading| heading.unwrap()) {
|
||||
if !first {
|
||||
self.writer.write_all(b"\n\n")?;
|
||||
}
|
||||
color!(self, format!("{}:\n", heading), warning)?;
|
||||
self.write_args(custom_headings!(parser.app).filter(|a| a.help_heading.unwrap() == heading))?;
|
||||
first = false
|
||||
.map(|heading| heading.unwrap())
|
||||
{
|
||||
if !first {
|
||||
self.writer.write_all(b"\n\n")?;
|
||||
}
|
||||
color!(self, format!("{}:\n", heading), warning)?;
|
||||
self.write_args(
|
||||
custom_headings!(parser.app).filter(|a| a.help_heading.unwrap() == heading),
|
||||
)?;
|
||||
first = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -832,8 +843,7 @@ impl<'w> Help<'w> {
|
|||
($thing:expr) => {{
|
||||
let mut owned_thing = $thing.to_owned();
|
||||
owned_thing = owned_thing.replace("{n}", "\n");
|
||||
write!(self.writer, "{}\n",
|
||||
wrap_help(&owned_thing, self.term_w))?
|
||||
write!(self.writer, "{}\n", wrap_help(&owned_thing, self.term_w))?
|
||||
}};
|
||||
}
|
||||
// Print the version
|
||||
|
@ -1113,16 +1123,19 @@ impl<'w> Help<'w> {
|
|||
}
|
||||
|
||||
fn should_show_arg(use_long: bool, arg: &Arg) -> bool {
|
||||
debugln!("Help::should_show_arg: use_long={:?}, arg={}", use_long, arg.name);
|
||||
debugln!(
|
||||
"Help::should_show_arg: use_long={:?}, arg={}",
|
||||
use_long,
|
||||
arg.name
|
||||
);
|
||||
if arg.is_set(ArgSettings::Hidden) {
|
||||
return false;
|
||||
}
|
||||
(!arg.is_set(ArgSettings::HiddenLongHelp) && use_long) ||
|
||||
(!arg.is_set(ArgSettings::HiddenShortHelp) && !use_long) ||
|
||||
arg.is_set(ArgSettings::NextLineHelp)
|
||||
(!arg.is_set(ArgSettings::HiddenLongHelp) && use_long)
|
||||
|| (!arg.is_set(ArgSettings::HiddenShortHelp) && !use_long)
|
||||
|| arg.is_set(ArgSettings::NextLineHelp)
|
||||
}
|
||||
|
||||
|
||||
fn wrap_help(help: &str, avail_chars: usize) -> String {
|
||||
let wrapper = textwrap::Wrapper::new(avail_chars).break_words(false);
|
||||
help.lines()
|
||||
|
|
|
@ -4,4 +4,4 @@ mod usage;
|
|||
pub mod fmt;
|
||||
|
||||
pub use self::help::Help;
|
||||
pub use self::usage::Usage;
|
||||
pub use self::usage::Usage;
|
||||
|
|
|
@ -1 +1 @@
|
|||
pub mod suggestions;
|
||||
pub mod suggestions;
|
||||
|
|
|
@ -2,6 +2,6 @@ mod arg_matches;
|
|||
mod matched_arg;
|
||||
mod subcommand;
|
||||
|
||||
pub use self::arg_matches::{ArgMatches, Values, OsValues};
|
||||
pub use self::arg_matches::{ArgMatches, OsValues, Values};
|
||||
pub use self::matched_arg::MatchedArg;
|
||||
pub use self::subcommand::SubCommand;
|
||||
pub use self::matched_arg::MatchedArg;
|
|
@ -1,13 +1,13 @@
|
|||
pub mod errors;
|
||||
pub mod features;
|
||||
|
||||
mod matches;
|
||||
mod arg_matcher;
|
||||
mod matches;
|
||||
mod parser;
|
||||
mod validator;
|
||||
|
||||
pub use self::parser::{Parser, ParseResult};
|
||||
pub use self::matches::ArgMatches;
|
||||
pub use self::arg_matcher::ArgMatcher;
|
||||
pub use self::matches::{Values, OsValues, SubCommand, MatchedArg};
|
||||
pub use self::validator::Validator;
|
||||
pub use self::matches::ArgMatches;
|
||||
pub use self::matches::{MatchedArg, OsValues, SubCommand, Values};
|
||||
pub use self::parser::{ParseResult, Parser};
|
||||
pub use self::validator::Validator;
|
||||
|
|
|
@ -27,6 +27,7 @@ use util::VecMap;
|
|||
use build::app::Propagation;
|
||||
use build::AppSettings as AS;
|
||||
use build::{App, Arg, ArgSettings};
|
||||
use mkeymap::KeyType;
|
||||
use output::Help;
|
||||
use output::Usage;
|
||||
use parse::errors::Error as ClapError;
|
||||
|
@ -40,7 +41,6 @@ use INVALID_UTF8;
|
|||
use INTERNAL_ERROR_MSG;
|
||||
use parse::features::suggestions;
|
||||
use output::Usage;
|
||||
use mkeymap::KeyType;
|
||||
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
#[doc(hidden)]
|
||||
|
@ -64,10 +64,10 @@ where
|
|||
pub required: Vec<&'a str>,
|
||||
pub r_ifs: Vec<(&'a str, &'b str, &'a str)>,
|
||||
pub overriden: Vec<&'a str>,
|
||||
cache: Option<&'a str>,
|
||||
//cache: Option<&'a str>,
|
||||
num_opts: usize,
|
||||
num_flags: usize,
|
||||
pub positionals: VecMap<&'a str>,
|
||||
//pub positionals: VecMap<&'a str>,
|
||||
seen: Vec<&'a str>,
|
||||
cur_idx: Cell<usize>,
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ where
|
|||
pub fn new(app: &'c mut App<'a, 'b>) -> Self {
|
||||
let reqs = app
|
||||
.args
|
||||
.iter()
|
||||
.values()
|
||||
.filter(|a| a.settings.is_set(ArgSettings::Required))
|
||||
.map(|a| a.name)
|
||||
.collect();
|
||||
|
@ -117,10 +117,8 @@ where
|
|||
required: reqs,
|
||||
r_ifs: Vec::new(),
|
||||
overriden: Vec::new(),
|
||||
cache: None,
|
||||
num_opts: 0,
|
||||
num_flags: 0,
|
||||
positionals: VecMap::new(),
|
||||
seen: Vec::new(),
|
||||
cur_idx: Cell::new(0),
|
||||
}
|
||||
|
@ -135,15 +133,41 @@ where
|
|||
// Firt we verify that the index highest supplied index, is equal to the number of
|
||||
// positional arguments to verify there are no gaps (i.e. supplying an index of 1 and 3
|
||||
// but no 2)
|
||||
#[cfg(feature = "vec_map")]
|
||||
fn _highest_idx(map: &VecMap<&str>) -> usize { map.keys().last().unwrap_or(0) }
|
||||
|
||||
#[cfg(not(feature = "vec_map"))]
|
||||
fn _highest_idx(map: &VecMap<&str>) -> usize { *map.keys().last().unwrap_or(&0) }
|
||||
// #[cfg(feature = "vec_map")]
|
||||
// fn _highest_idx(map: &VecMap<&str>) -> usize { map.keys().last().unwrap_or(0) }
|
||||
|
||||
let highest_idx = _highest_idx(&self.positionals);
|
||||
// #[cfg(not(feature = "vec_map"))]
|
||||
// fn _highest_idx(map: &VecMap<&str>) -> usize { *map.keys().last().unwrap_or(&0) }
|
||||
|
||||
let num_p = self.positionals.len();
|
||||
let highest_idx = *self
|
||||
.app
|
||||
.args
|
||||
.keys()
|
||||
.filter_map(|x| {
|
||||
if let KeyType::Position(n) = x {
|
||||
Some(n)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.max()
|
||||
.unwrap_or(&0);
|
||||
|
||||
//_highest_idx(&self.positionals);
|
||||
|
||||
let num_p = self
|
||||
.app
|
||||
.args
|
||||
.keys()
|
||||
.filter(|x| {
|
||||
if let KeyType::Position(_) = x {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.count();
|
||||
|
||||
assert!(
|
||||
highest_idx == num_p,
|
||||
|
@ -162,14 +186,29 @@ where
|
|||
// * a value terminator
|
||||
// * ArgSettings::Last
|
||||
// * The last arg is Required
|
||||
let mut it = self.positionals.values().rev();
|
||||
let mut it = self.app.args.keys().filter(|x| {
|
||||
if let KeyType::Position(_) = x {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
//self.positionals.values().rev();
|
||||
|
||||
// We can't pass the closure (it.next()) to the macro directly because each call to
|
||||
// find() (iterator, not macro) gets called repeatedly.
|
||||
let last_name = it.next().expect(INTERNAL_ERROR_MSG);
|
||||
let second_to_last_name = it.next().expect(INTERNAL_ERROR_MSG);
|
||||
let last = find!(self.app, last_name).expect(INTERNAL_ERROR_MSG);
|
||||
let second_to_last = find!(self.app, second_to_last_name).expect(INTERNAL_ERROR_MSG);
|
||||
let last = self
|
||||
.app
|
||||
.args
|
||||
.get(KeyType::Position(highest_idx))
|
||||
.expect(INTERNAL_ERROR_MSG);
|
||||
//let second_to_last_name = it.next().expect(INTERNAL_ERROR_MSG);
|
||||
//let last = find!(self.app, last_name).expect(INTERNAL_ERROR_MSG);
|
||||
let second_to_last = self
|
||||
.app
|
||||
.args
|
||||
.get(KeyType::Position(highest_idx - 1))
|
||||
.expect(INTERNAL_ERROR_MSG);
|
||||
|
||||
// Either the final positional is required
|
||||
// Or the second to last has a terminator or .last(true) set
|
||||
|
@ -217,9 +256,10 @@ where
|
|||
// index are also required.
|
||||
let mut found = false;
|
||||
let mut foundx2 = false;
|
||||
|
||||
//? What is going on here?
|
||||
for p in self
|
||||
.positionals
|
||||
.values()
|
||||
.rev()
|
||||
.map(|p_name| find!(self.app, p_name).expect(INTERNAL_ERROR_MSG))
|
||||
{
|
||||
|
@ -308,7 +348,7 @@ where
|
|||
|
||||
for (i, a) in self.app.args.values_mut().enumerate() {
|
||||
if let Some(index) = a.index {
|
||||
self.app.args.insert_key(KeyType::Positional(index), i);
|
||||
self.app.args.insert_key(KeyType::Position(index), i);
|
||||
} else {
|
||||
if let Some(c) = a.short {
|
||||
self.app.args.insert_key(KeyType::Short(c), i);
|
||||
|
@ -318,7 +358,9 @@ where
|
|||
}
|
||||
if let Some(v) = a.aliases {
|
||||
for (item, _) in &v {
|
||||
self.app.args.insert_key(KeyType::Long(&OsStr::new(item)), i);
|
||||
self.app
|
||||
.args
|
||||
.insert_key(KeyType::Long(&OsStr::new(item)), i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -356,7 +398,13 @@ where
|
|||
// Set the LowIndexMultiple flag if required
|
||||
if positionals!(self.app).any(|a| {
|
||||
a.is_set(ArgSettings::MultipleValues)
|
||||
&& (a.index.unwrap_or(0) as usize != self.positionals.len())
|
||||
&& (a.index.unwrap_or(0) as usize
|
||||
!= self
|
||||
.app
|
||||
.args
|
||||
.keys()
|
||||
.filter(|x| if let Position(_) = x { true } else { false })
|
||||
.count())
|
||||
}) && self.positionals.values().last().map_or(false, |p_name| {
|
||||
!find!(self.app, p_name)
|
||||
.expect(INTERNAL_ERROR_MSG)
|
||||
|
@ -1030,39 +1078,34 @@ where
|
|||
sdebugln!("No");
|
||||
full_arg.trim_left_matches(b'-')
|
||||
};
|
||||
// opts?? Should probably now check once, then check whether it's opt or flag, or sth else
|
||||
if let Some(opt) = self.app.args.get(KeyType::Long(arg))
|
||||
{
|
||||
// opts?? Should probably now check once, then check whether it's opt or flag, or sth else
|
||||
if let Some(opt) = self.app.args.get(KeyType::Long(arg)) {
|
||||
debugln!(
|
||||
"Parser::parse_long_arg: Found valid opt '{}'",
|
||||
opt.to_string()
|
||||
);
|
||||
self.app.settings.set(AS::ValidArgFound);
|
||||
let ret = self.parse_opt(val, opt, val.is_some(), matcher)?;
|
||||
if self.cache.map_or(true, |name| name != opt.name) {
|
||||
self.cache = Some(opt.name);
|
||||
|
||||
if opt.is_set(ArgSettings::TakesValue) {
|
||||
let ret = self.parse_opt(val, opt, val.is_some(), matcher)?;
|
||||
// if self.cache.map_or(true, |name| name != opt.name) {
|
||||
// self.cache = Some(opt.name);
|
||||
// }
|
||||
|
||||
return Ok(ret);
|
||||
} else {
|
||||
// Only flags could be help or version, and we need to check the raw long
|
||||
// so this is the first point to check
|
||||
self.check_for_help_and_version_str(arg)?;
|
||||
|
||||
self.parse_flag(opt, matcher)?;
|
||||
|
||||
// if self.cache.map_or(true, |name| name != opt.name) {
|
||||
// self.cache = Some(opt.name);
|
||||
// }
|
||||
|
||||
return Ok(ParseResult::Flag);
|
||||
}
|
||||
|
||||
return Ok(ret);
|
||||
//flags??
|
||||
} else if let Some(flag) = self.app.args.get(KeyType::Long(arg)) {
|
||||
debugln!(
|
||||
"Parser::parse_long_arg: Found valid flag '{}'",
|
||||
flag.to_string()
|
||||
);
|
||||
self.app.settings.set(AS::ValidArgFound);
|
||||
// Only flags could be help or version, and we need to check the raw long
|
||||
// so this is the first point to check
|
||||
self.check_for_help_and_version_str(arg)?;
|
||||
|
||||
self.parse_flag(flag, matcher)?;
|
||||
|
||||
// Handle conflicts, requirements, etc.
|
||||
if self.cache.map_or(true, |name| name != flag.name) {
|
||||
self.cache = Some(flag.name);
|
||||
}
|
||||
|
||||
return Ok(ParseResult::Flag);
|
||||
} else if self.is_set(AS::AllowLeadingHyphen) {
|
||||
return Ok(ParseResult::MaybeHyphenValue);
|
||||
} else if self.is_set(AS::ValidNegNumFound) {
|
||||
|
@ -1487,7 +1530,7 @@ where
|
|||
}
|
||||
|
||||
pub(crate) fn add_env(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
|
||||
for a in &self.app.args {
|
||||
for a in self.app.args.values() {
|
||||
if let Some(ref val) = a.env {
|
||||
if matcher
|
||||
.get(a.name)
|
||||
|
@ -1678,7 +1721,20 @@ where
|
|||
|
||||
pub(crate) fn has_flags(&self) -> bool { self.app.has_flags() }
|
||||
|
||||
pub(crate) fn has_positionals(&self) -> bool { !self.positionals.is_empty() }
|
||||
pub(crate) fn has_positionals(&self) -> bool {
|
||||
!self
|
||||
.app
|
||||
.args
|
||||
.keys()
|
||||
.filter(|x| {
|
||||
if let KeyType::Position(_) = x {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.count() == 0
|
||||
}
|
||||
|
||||
pub(crate) fn has_subcommands(&self) -> bool { self.app.has_subcommands() }
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ pub use self::vec_map::{Values, VecMap};
|
|||
|
||||
#[cfg(not(feature = "vec_map"))]
|
||||
mod vec_map {
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::btree_map;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
|
|
|
@ -6,4 +6,4 @@ pub use self::map::{Values, VecMap};
|
|||
pub use self::osstringext::OsStrExt2;
|
||||
#[cfg(any(target_os = "windows", target_arch = "wasm32"))]
|
||||
pub use self::osstringext::OsStrExt3;
|
||||
pub use self::strext::_StrExt;
|
||||
pub use self::strext::_StrExt;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#[cfg(any(target_os = "windows", target_arch = "wasm32"))]
|
||||
use INVALID_UTF8;
|
||||
use std::ffi::OsStr;
|
||||
#[cfg(not(any(target_os = "windows", target_arch = "wasm32")))]
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
#[cfg(any(target_os = "windows", target_arch = "wasm32"))]
|
||||
use INVALID_UTF8;
|
||||
|
||||
#[cfg(any(target_os = "windows", target_arch = "wasm32"))]
|
||||
pub trait OsStrExt3 {
|
||||
|
|
|
@ -498,8 +498,7 @@ fn leading_double_hyphen_trailingvararg() {
|
|||
|
||||
#[test]
|
||||
fn unset_setting() {
|
||||
let m = App::new("unset_setting")
|
||||
.setting(AppSettings::AllArgsOverrideSelf);
|
||||
let m = App::new("unset_setting").setting(AppSettings::AllArgsOverrideSelf);
|
||||
assert!(m.is_set(AppSettings::AllArgsOverrideSelf));
|
||||
|
||||
let m = m.unset_setting(AppSettings::AllArgsOverrideSelf);
|
||||
|
@ -660,7 +659,10 @@ fn missing_positional_no_hyphen() {
|
|||
let expected_args = vec!["arg1", "arg2", "arg3"];
|
||||
|
||||
assert_eq!(m.value_of("BENCH"), expected_bench);
|
||||
assert_eq!(m.values_of("ARGS").unwrap().collect::<Vec<_>>(), &*expected_args);
|
||||
assert_eq!(
|
||||
m.values_of("ARGS").unwrap().collect::<Vec<_>>(),
|
||||
&*expected_args
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -678,7 +680,10 @@ fn missing_positional_hyphen() {
|
|||
let expected_args = vec!["arg1", "arg2", "arg3"];
|
||||
|
||||
assert_eq!(m.value_of("BENCH"), expected_bench);
|
||||
assert_eq!(m.values_of("ARGS").unwrap().collect::<Vec<_>>(), &*expected_args);
|
||||
assert_eq!(
|
||||
m.values_of("ARGS").unwrap().collect::<Vec<_>>(),
|
||||
&*expected_args
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -702,7 +707,10 @@ fn missing_positional_hyphen_far_back() {
|
|||
assert_eq!(m.value_of("BENCH1"), expected_bench1);
|
||||
assert_eq!(m.value_of("BENCH2"), expected_bench2);
|
||||
assert_eq!(m.value_of("BENCH3"), expected_bench3);
|
||||
assert_eq!(m.values_of("ARGS").unwrap().collect::<Vec<_>>(), &*expected_args);
|
||||
assert_eq!(
|
||||
m.values_of("ARGS").unwrap().collect::<Vec<_>>(),
|
||||
&*expected_args
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -911,7 +919,7 @@ fn aaos_opts_mult_req_delims() {
|
|||
.setting(AppSettings::AllArgsOverrideSelf)
|
||||
.arg(Arg::from("--opt [val]... 'some option'"))
|
||||
.get_matches_from_safe(vec![
|
||||
"", "--opt", "first", "overides", "--opt", "some", "other", "val"
|
||||
"", "--opt", "first", "overides", "--opt", "some", "other", "val",
|
||||
]);
|
||||
assert!(res.is_ok());
|
||||
let m = res.unwrap();
|
||||
|
|
|
@ -59,22 +59,26 @@ fn multiple_aliases_of_option() {
|
|||
.help("multiple aliases")
|
||||
.aliases(&vec!["alias1", "alias2", "alias3"]),
|
||||
);
|
||||
let long = a.clone()
|
||||
let long = a
|
||||
.clone()
|
||||
.get_matches_from_safe(vec!["", "--aliases", "value"]);
|
||||
assert!(long.is_ok());
|
||||
let long = long.unwrap();
|
||||
|
||||
let als1 = a.clone()
|
||||
let als1 = a
|
||||
.clone()
|
||||
.get_matches_from_safe(vec!["", "--alias1", "value"]);
|
||||
assert!(als1.is_ok());
|
||||
let als1 = als1.unwrap();
|
||||
|
||||
let als2 = a.clone()
|
||||
let als2 = a
|
||||
.clone()
|
||||
.get_matches_from_safe(vec!["", "--alias2", "value"]);
|
||||
assert!(als2.is_ok());
|
||||
let als2 = als2.unwrap();
|
||||
|
||||
let als3 = a.clone()
|
||||
let als3 = a
|
||||
.clone()
|
||||
.get_matches_from_safe(vec!["", "--alias3", "value"]);
|
||||
assert!(als3.is_ok());
|
||||
let als3 = als3.unwrap();
|
||||
|
|
|
@ -721,45 +721,63 @@ fn build_app_with_name(s: &'static str) -> App<'static, 'static> {
|
|||
App::new(s)
|
||||
.about("Tests completions")
|
||||
.arg(Arg::with_name("file").help("some input file"))
|
||||
.subcommand(SubCommand::with_name("test")
|
||||
.about("tests things")
|
||||
.arg(Arg::with_name("case")
|
||||
.long("case")
|
||||
.takes_value(true)
|
||||
.help("the case to test")))
|
||||
.subcommand(
|
||||
SubCommand::with_name("test").about("tests things").arg(
|
||||
Arg::with_name("case")
|
||||
.long("case")
|
||||
.takes_value(true)
|
||||
.help("the case to test"),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fn build_app_special_commands() -> App<'static, 'static> {
|
||||
build_app_with_name("my_app")
|
||||
.subcommand(SubCommand::with_name("some_cmd")
|
||||
.about("tests other things")
|
||||
.arg(Arg::with_name("config")
|
||||
.long("--config")
|
||||
.takes_value(true)
|
||||
.help("the other case to test")))
|
||||
.subcommand(
|
||||
SubCommand::with_name("some_cmd")
|
||||
.about("tests other things")
|
||||
.arg(
|
||||
Arg::with_name("config")
|
||||
.long("--config")
|
||||
.takes_value(true)
|
||||
.help("the other case to test"),
|
||||
),
|
||||
)
|
||||
.subcommand(SubCommand::with_name("some-cmd-with-hypens"))
|
||||
}
|
||||
|
||||
fn build_app_special_help() -> App<'static, 'static> {
|
||||
App::new("my_app")
|
||||
.arg(Arg::with_name("single-quotes")
|
||||
.long("single-quotes")
|
||||
.help("Can be 'always', 'auto', or 'never'"))
|
||||
.arg(Arg::with_name("double-quotes")
|
||||
.long("double-quotes")
|
||||
.help("Can be \"always\", \"auto\", or \"never\""))
|
||||
.arg(Arg::with_name("backticks")
|
||||
.long("backticks")
|
||||
.help("For more information see `echo test`"))
|
||||
.arg(Arg::with_name("backslash")
|
||||
.long("backslash")
|
||||
.help("Avoid '\\n'"))
|
||||
.arg(Arg::with_name("brackets")
|
||||
.long("brackets")
|
||||
.help("List packages [filter]"))
|
||||
.arg(Arg::with_name("expansions")
|
||||
.long("expansions")
|
||||
.help("Execute the shell command with $SHELL"))
|
||||
.arg(
|
||||
Arg::with_name("single-quotes")
|
||||
.long("single-quotes")
|
||||
.help("Can be 'always', 'auto', or 'never'"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("double-quotes")
|
||||
.long("double-quotes")
|
||||
.help("Can be \"always\", \"auto\", or \"never\""),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("backticks")
|
||||
.long("backticks")
|
||||
.help("For more information see `echo test`"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("backslash")
|
||||
.long("backslash")
|
||||
.help("Avoid '\\n'"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("brackets")
|
||||
.long("brackets")
|
||||
.help("List packages [filter]"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("expansions")
|
||||
.long("expansions")
|
||||
.help("Execute the shell command with $SHELL"),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -79,13 +79,19 @@ fn hidden_short_args() {
|
|||
.short('c')
|
||||
.long("config")
|
||||
.hidden_short_help(true)
|
||||
.help("Some help text describing the --config arg"),
|
||||
.help("Some help text describing the --config arg"),
|
||||
Arg::with_name("visible")
|
||||
.short('v')
|
||||
.long("visible")
|
||||
.help("This text should be visible")]);
|
||||
.help("This text should be visible"),
|
||||
]);
|
||||
|
||||
assert!(test::compare_output(app, "test -h", HIDDEN_SHORT_ARGS, false));
|
||||
assert!(test::compare_output(
|
||||
app,
|
||||
"test -h",
|
||||
HIDDEN_SHORT_ARGS,
|
||||
false
|
||||
));
|
||||
}
|
||||
|
||||
/// Ensure visible with opposite option
|
||||
|
@ -100,13 +106,19 @@ fn hidden_short_args_long_help() {
|
|||
.short('c')
|
||||
.long("config")
|
||||
.hidden_short_help(true)
|
||||
.help("Some help text describing the --config arg"),
|
||||
.help("Some help text describing the --config arg"),
|
||||
Arg::with_name("visible")
|
||||
.short('v')
|
||||
.long("visible")
|
||||
.help("This text should be visible")]);
|
||||
.help("This text should be visible"),
|
||||
]);
|
||||
|
||||
assert!(test::compare_output(app, "test --help", HIDDEN_SHORT_ARGS_LONG_HELP, false));
|
||||
assert!(test::compare_output(
|
||||
app,
|
||||
"test --help",
|
||||
HIDDEN_SHORT_ARGS_LONG_HELP,
|
||||
false
|
||||
));
|
||||
}
|
||||
|
||||
static HIDDEN_LONG_ARGS: &'static str = "test 2.31.2
|
||||
|
@ -137,13 +149,19 @@ fn hidden_long_args() {
|
|||
.short('c')
|
||||
.long("config")
|
||||
.hidden_long_help(true)
|
||||
.help("Some help text describing the --config arg"),
|
||||
.help("Some help text describing the --config arg"),
|
||||
Arg::with_name("visible")
|
||||
.short('v')
|
||||
.long("visible")
|
||||
.help("This text should be visible")]);
|
||||
.help("This text should be visible"),
|
||||
]);
|
||||
|
||||
assert!(test::compare_output(app, "test --help", HIDDEN_LONG_ARGS, false));
|
||||
assert!(test::compare_output(
|
||||
app,
|
||||
"test --help",
|
||||
HIDDEN_LONG_ARGS,
|
||||
false
|
||||
));
|
||||
}
|
||||
|
||||
static HIDDEN_LONG_ARGS_SHORT_HELP: &'static str = "test 2.31.2
|
||||
|
@ -170,11 +188,17 @@ fn hidden_long_args_short_help() {
|
|||
.short('c')
|
||||
.long("config")
|
||||
.hidden_long_help(true)
|
||||
.help("Some help text describing the --config arg"),
|
||||
.help("Some help text describing the --config arg"),
|
||||
Arg::with_name("visible")
|
||||
.short('v')
|
||||
.long("visible")
|
||||
.help("This text should be visible")]);
|
||||
.help("This text should be visible"),
|
||||
]);
|
||||
|
||||
assert!(test::compare_output(app, "test -h", HIDDEN_LONG_ARGS_SHORT_HELP, false));
|
||||
}
|
||||
assert!(test::compare_output(
|
||||
app,
|
||||
"test -h",
|
||||
HIDDEN_LONG_ARGS_SHORT_HELP,
|
||||
false
|
||||
));
|
||||
}
|
||||
|
|
|
@ -109,9 +109,9 @@ fn quoted_arg_long_name() {
|
|||
(@arg scpositional: index(1) "tests positionals"))
|
||||
);
|
||||
|
||||
let matches =
|
||||
app.get_matches_from_safe(vec!["bin_name", "value1", "value2", "--long-option-2"])
|
||||
.expect("Expected to successfully match the given args.");
|
||||
let matches = app
|
||||
.get_matches_from_safe(vec!["bin_name", "value1", "value2", "--long-option-2"])
|
||||
.expect("Expected to successfully match the given args.");
|
||||
assert!(matches.is_present("option2"));
|
||||
}
|
||||
|
||||
|
@ -147,9 +147,9 @@ fn quoted_arg_name() {
|
|||
(@arg scpositional: index(1) "tests positionals"))
|
||||
);
|
||||
|
||||
let matches =
|
||||
app.get_matches_from_safe(vec!["bin_name", "value1", "value2", "--long-option-2"])
|
||||
.expect("Expected to successfully match the given args.");
|
||||
let matches = app
|
||||
.get_matches_from_safe(vec!["bin_name", "value1", "value2", "--long-option-2"])
|
||||
.expect("Expected to successfully match the given args.");
|
||||
assert!(matches.is_present("option2"));
|
||||
}
|
||||
|
||||
|
|
|
@ -398,10 +398,7 @@ fn issue_1047_min_zero_vals_default_val() {
|
|||
|
||||
fn issue_1105_setup(argv: Vec<&'static str>) -> Result<ArgMatches<'static>, clap::Error> {
|
||||
App::new("opts")
|
||||
.arg(
|
||||
Arg::from("-o, --option [opt] 'some option'")
|
||||
.setting(ArgSettings::AllowEmptyValues),
|
||||
)
|
||||
.arg(Arg::from("-o, --option [opt] 'some option'").setting(ArgSettings::AllowEmptyValues))
|
||||
.arg(Arg::from("--flag 'some flag'"))
|
||||
.try_get_matches_from(argv)
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ use clap::{App, Arg, ErrorKind};
|
|||
#[test]
|
||||
fn flag_overrides_itself() {
|
||||
let res = App::new("posix")
|
||||
.arg(Arg::from("--flag 'some flag'").overrides_with("flag"))
|
||||
.get_matches_from_safe(vec!["", "--flag", "--flag"]);
|
||||
.arg(Arg::from("--flag 'some flag'").overrides_with("flag"))
|
||||
.get_matches_from_safe(vec!["", "--flag", "--flag"]);
|
||||
assert!(res.is_ok());
|
||||
let m = res.unwrap();
|
||||
assert!(m.is_present("flag"));
|
||||
|
@ -15,8 +15,8 @@ fn flag_overrides_itself() {
|
|||
#[test]
|
||||
fn mult_flag_overrides_itself() {
|
||||
let res = App::new("posix")
|
||||
.arg(Arg::from("--flag... 'some flag'").overrides_with("flag"))
|
||||
.get_matches_from_safe(vec!["", "--flag", "--flag", "--flag", "--flag"]);
|
||||
.arg(Arg::from("--flag... 'some flag'").overrides_with("flag"))
|
||||
.get_matches_from_safe(vec!["", "--flag", "--flag", "--flag", "--flag"]);
|
||||
assert!(res.is_ok());
|
||||
let m = res.unwrap();
|
||||
assert!(m.is_present("flag"));
|
||||
|
@ -26,8 +26,8 @@ fn mult_flag_overrides_itself() {
|
|||
#[test]
|
||||
fn option_overrides_itself() {
|
||||
let res = App::new("posix")
|
||||
.arg(Arg::from("--opt [val] 'some option'").overrides_with("opt"))
|
||||
.get_matches_from_safe(vec!["", "--opt=some", "--opt=other"]);
|
||||
.arg(Arg::from("--opt [val] 'some option'").overrides_with("opt"))
|
||||
.get_matches_from_safe(vec!["", "--opt=some", "--opt=other"]);
|
||||
assert!(res.is_ok());
|
||||
let m = res.unwrap();
|
||||
assert!(m.is_present("opt"));
|
||||
|
@ -38,54 +38,67 @@ fn option_overrides_itself() {
|
|||
#[test]
|
||||
fn mult_option_require_delim_overrides_itself() {
|
||||
let res = App::new("posix")
|
||||
.arg(Arg::from("--opt [val]... 'some option'")
|
||||
.overrides_with("opt")
|
||||
.number_of_values(1)
|
||||
.require_delimiter(true))
|
||||
.get_matches_from_safe(vec!["", "--opt=some", "--opt=other", "--opt=one,two"]);
|
||||
.arg(
|
||||
Arg::from("--opt [val]... 'some option'")
|
||||
.overrides_with("opt")
|
||||
.number_of_values(1)
|
||||
.require_delimiter(true),
|
||||
)
|
||||
.get_matches_from_safe(vec!["", "--opt=some", "--opt=other", "--opt=one,two"]);
|
||||
assert!(res.is_ok());
|
||||
let m = res.unwrap();
|
||||
assert!(m.is_present("opt"));
|
||||
assert_eq!(m.occurrences_of("opt"), 3);
|
||||
assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["some", "other", "one", "two"]);
|
||||
assert_eq!(
|
||||
m.values_of("opt").unwrap().collect::<Vec<_>>(),
|
||||
&["some", "other", "one", "two"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mult_option_overrides_itself() {
|
||||
let res = App::new("posix")
|
||||
.arg(Arg::from("--opt [val]... 'some option'")
|
||||
.overrides_with("opt"))
|
||||
.get_matches_from_safe(vec!["", "--opt", "first", "overides", "--opt", "some", "other", "val"]);
|
||||
.arg(Arg::from("--opt [val]... 'some option'").overrides_with("opt"))
|
||||
.get_matches_from_safe(vec![
|
||||
"", "--opt", "first", "overides", "--opt", "some", "other", "val",
|
||||
]);
|
||||
assert!(res.is_ok());
|
||||
let m = res.unwrap();
|
||||
assert!(m.is_present("opt"));
|
||||
assert_eq!(m.occurrences_of("opt"), 2);
|
||||
assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["first", "overides", "some", "other", "val"]);
|
||||
assert_eq!(
|
||||
m.values_of("opt").unwrap().collect::<Vec<_>>(),
|
||||
&["first", "overides", "some", "other", "val"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn option_use_delim_false_override_itself() {
|
||||
|
||||
let m = App::new("posix")
|
||||
.arg(Arg::from("--opt [val] 'some option'")
|
||||
.overrides_with("opt"))
|
||||
.get_matches_from(vec!["", "--opt=some,other", "--opt=one,two"]);
|
||||
.arg(Arg::from("--opt [val] 'some option'").overrides_with("opt"))
|
||||
.get_matches_from(vec!["", "--opt=some,other", "--opt=one,two"]);
|
||||
assert!(m.is_present("opt"));
|
||||
assert_eq!(m.occurrences_of("opt"), 1);
|
||||
assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["one,two"]);
|
||||
assert_eq!(
|
||||
m.values_of("opt").unwrap().collect::<Vec<_>>(),
|
||||
&["one,two"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pos_mult_overrides_itself() {
|
||||
// opts with multiple
|
||||
let res = App::new("posix")
|
||||
.arg(Arg::from("[val]... 'some pos'").overrides_with("val"))
|
||||
.get_matches_from_safe(vec!["", "some", "other", "value"]);
|
||||
.arg(Arg::from("[val]... 'some pos'").overrides_with("val"))
|
||||
.get_matches_from_safe(vec!["", "some", "other", "value"]);
|
||||
assert!(res.is_ok());
|
||||
let m = res.unwrap();
|
||||
assert!(m.is_present("val"));
|
||||
assert_eq!(m.occurrences_of("val"), 3);
|
||||
assert_eq!(m.values_of("val").unwrap().collect::<Vec<_>>(), &["some", "other", "value"]);
|
||||
assert_eq!(
|
||||
m.values_of("val").unwrap().collect::<Vec<_>>(),
|
||||
&["some", "other", "value"]
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn posix_compatible_flags_long() {
|
||||
|
|
|
@ -196,19 +196,15 @@ fn issue_753() {
|
|||
"-l, --list 'List available interfaces (and stop there)'",
|
||||
))
|
||||
.arg(
|
||||
Arg::from(
|
||||
"-i, --iface=[INTERFACE] 'Ethernet interface for fetching NTP packets'",
|
||||
).required_unless("list"),
|
||||
Arg::from("-i, --iface=[INTERFACE] 'Ethernet interface for fetching NTP packets'")
|
||||
.required_unless("list"),
|
||||
)
|
||||
.arg(
|
||||
Arg::from("-f, --file=[TESTFILE] 'Fetch NTP packets from pcap file'")
|
||||
.conflicts_with("iface")
|
||||
.required_unless("list"),
|
||||
)
|
||||
.arg(
|
||||
Arg::from("-s, --server=[SERVER_IP] 'NTP server IP address'")
|
||||
.required_unless("list"),
|
||||
)
|
||||
.arg(Arg::from("-s, --server=[SERVER_IP] 'NTP server IP address'").required_unless("list"))
|
||||
.arg(Arg::from("-p, --port=[SERVER_PORT] 'NTP server port'").default_value("123"))
|
||||
.get_matches_from_safe(vec!["test", "--list"]);
|
||||
assert!(m.is_ok());
|
||||
|
|
|
@ -220,15 +220,32 @@ fn issue_1161_multiple_hyphen_hyphen() {
|
|||
.arg(Arg::with_name("eff").short('f'))
|
||||
.arg(Arg::with_name("pea").short('p').takes_value(true))
|
||||
.arg(Arg::with_name("slop").multiple(true).last(true))
|
||||
.get_matches_from_safe(vec!["-f", "-p=bob", "--", "sloppy", "slop", "-a", "--", "subprogram", "position", "args"]);
|
||||
.get_matches_from_safe(vec![
|
||||
"-f",
|
||||
"-p=bob",
|
||||
"--",
|
||||
"sloppy",
|
||||
"slop",
|
||||
"-a",
|
||||
"--",
|
||||
"subprogram",
|
||||
"position",
|
||||
"args",
|
||||
]);
|
||||
|
||||
assert!(res.is_ok(), "{:?}", res.unwrap_err().kind);
|
||||
let m = res.unwrap();
|
||||
|
||||
let expected = Some(vec!["sloppy", "slop", "-a", "--", "subprogram", "position", "args"]);
|
||||
let actual = m
|
||||
.values_of("slop")
|
||||
.map(|vals| vals.collect::<Vec<_>>());
|
||||
let expected = Some(vec![
|
||||
"sloppy",
|
||||
"slop",
|
||||
"-a",
|
||||
"--",
|
||||
"subprogram",
|
||||
"position",
|
||||
"args",
|
||||
]);
|
||||
let actual = m.values_of("slop").map(|vals| vals.collect::<Vec<_>>());
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
extern crate clap;
|
||||
|
||||
use clap::{App, AppSettings, Arg, ErrorKind};
|
||||
use std::ffi::OsString;
|
||||
use std::os::unix::ffi::OsStringExt;
|
||||
use clap::{App, AppSettings, Arg, ErrorKind};
|
||||
|
||||
#[test]
|
||||
fn invalid_utf8_strict_positional() {
|
||||
|
|
Loading…
Reference in a new issue