diff --git a/benches/02_simple.rs b/benches/02_simple.rs index b1ee4db7..776006b1 100644 --- a/benches/02_simple.rs +++ b/benches/02_simple.rs @@ -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. ") - .args_from_usage("-f --flag 'tests flags' + .version("0.1") + .about("tests clap library") + .author("Kevin K. ") + .args_from_usage( + "-f --flag 'tests flags' -o --option=[opt] 'tests options' - [positional] 'tests positional'") - }) + [positional] 'tests positional'", + ) + }}; } #[bench] diff --git a/benches/05_ripgrep.rs b/benches/05_ripgrep.rs index d662d5cf..80c07a2e 100644 --- a/benches/05_ripgrep.rs +++ b/benches/05_ripgrep.rs @@ -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 }; diff --git a/src/build/app/mod.rs b/src/build/app/mod.rs index 309681ee..2ae55197 100644 --- a/src/build/app/mod.rs +++ b/src/build/app/mod.rs @@ -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>, #[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)) diff --git a/src/build/app/settings.rs b/src/build/app/settings.rs index 5549f4ab..4d09c7f5 100644 --- a/src/build/app/settings.rs +++ b/src/build/app/settings.rs @@ -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 { diff --git a/src/build/arg/settings.rs b/src/build/arg/settings.rs index 8c04b2a9..6f630fc8 100644 --- a/src/build/arg/settings.rs +++ b/src/build/arg/settings.rs @@ -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 { diff --git a/src/build/arg_group.rs b/src/build/arg_group.rs index d46b1304..d03c6892 100644 --- a/src/build/arg_group.rs +++ b/src/build/arg_group.rs @@ -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 /// diff --git a/src/build/macros.rs b/src/build/macros.rs index 1de12f4e..ac4b1a2d 100644 --- a/src/build/macros.rs +++ b/src/build/macros.rs @@ -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) }}; } diff --git a/src/build/mod.rs b/src/build/mod.rs index 1647d260..3d67ba6b 100644 --- a/src/build/mod.rs +++ b/src/build/mod.rs @@ -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; \ No newline at end of file +pub use self::arg_group::ArgGroup; +pub use self::usage_parser::UsageParser; diff --git a/src/build/usage_parser.rs b/src/build/usage_parser.rs index 332cf802..df805aad 100644 --- a/src/build/usage_parser.rs +++ b/src/build/usage_parser.rs @@ -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'-' diff --git a/src/completions/elvish.rs b/src/completions/elvish.rs index ec50479b..acba459b 100644 --- a/src/completions/elvish.rs +++ b/src/completions/elvish.rs @@ -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(help: Option<&str>, data: T) -> String { +fn get_tooltip(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); } diff --git a/src/completions/macros.rs b/src/completions/macros.rs index 8e771e9f..233bddd1 100644 --- a/src/completions/macros.rs +++ b/src/completions/macros.rs @@ -24,5 +24,5 @@ macro_rules! get_zsh_arg_conflicts { } else { String::new() } - } + }; } diff --git a/src/completions/mod.rs b/src/completions/mod.rs index b08cc266..4ad156a3 100644 --- a/src/completions/mod.rs +++ b/src/completions/mod.rs @@ -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"), } } } diff --git a/src/completions/powershell.rs b/src/completions/powershell.rs index 45a85cb0..a9da8371 100644 --- a/src/completions/powershell.rs +++ b/src/completions/powershell.rs @@ -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(help: Option<&str>, data: T) -> String { +fn get_tooltip(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); } diff --git a/src/completions/shell.rs b/src/completions/shell.rs index b1f13167..08425ad4 100644 --- a/src/completions/shell.rs +++ b/src/completions/shell.rs @@ -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"), } } } diff --git a/src/completions/zsh.rs b/src/completions/zsh.rs index d6299921..cb27d25c 100644 --- a/src/completions/zsh.rs +++ b/src/completions/zsh.rs @@ -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::>() - .join(" ") - )) + .map_or("_files".to_owned(), |values| { + format!( + "({})", + values + .iter() + .map(|v| escape_value(*v)) + .collect::>() + .join(" ") + ) + }) ); debugln!("write_positionals_of:iter: Wrote...{}", a); diff --git a/src/lib.rs b/src/lib.rs index 7220d504..7a0b20dd 100644 --- a/src/lib.rs +++ b/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; diff --git a/src/macros.rs b/src/macros.rs index dc19995d..17fa96ec 100644 --- a/src/macros.rs +++ b/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::>() + 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::>() } 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)) + }}; +} diff --git a/src/mkeymap.rs b/src/mkeymap.rs index df3d1d49..37080150 100644 --- a/src/mkeymap.rs +++ b/src/mkeymap.rs @@ -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.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")) ); } diff --git a/src/output/fmt.rs b/src/output/fmt.rs index 3c00c1dc..432c5920 100644 --- a/src/output/fmt.rs +++ b/src/output/fmt.rs @@ -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 fmt::Display for Format { #[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() { diff --git a/src/output/help.rs b/src/output/help.rs index c30ebd90..d18157bc 100644 --- a/src/output/help.rs +++ b/src/output/help.rs @@ -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>, + where + 'a: 'b, + I: Iterator>, { 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>, + where + 'a: 'b, + I: Iterator>, { 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() diff --git a/src/output/mod.rs b/src/output/mod.rs index 3b0b6d38..71db550a 100644 --- a/src/output/mod.rs +++ b/src/output/mod.rs @@ -4,4 +4,4 @@ mod usage; pub mod fmt; pub use self::help::Help; -pub use self::usage::Usage; \ No newline at end of file +pub use self::usage::Usage; diff --git a/src/parse/features/mod.rs b/src/parse/features/mod.rs index 2cabee83..ad75db59 100644 --- a/src/parse/features/mod.rs +++ b/src/parse/features/mod.rs @@ -1 +1 @@ -pub mod suggestions; \ No newline at end of file +pub mod suggestions; diff --git a/src/parse/matches/mod.rs b/src/parse/matches/mod.rs index 51b71a5f..1a0ed65a 100644 --- a/src/parse/matches/mod.rs +++ b/src/parse/matches/mod.rs @@ -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; \ No newline at end of file diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 03d81559..fba88301 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -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; \ No newline at end of file +pub use self::matches::ArgMatches; +pub use self::matches::{MatchedArg, OsValues, SubCommand, Values}; +pub use self::parser::{ParseResult, Parser}; +pub use self::validator::Validator; diff --git a/src/parse/parser.rs b/src/parse/parser.rs index 60dfb329..9c050911 100644 --- a/src/parse/parser.rs +++ b/src/parse/parser.rs @@ -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, } @@ -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() } diff --git a/src/util/map.rs b/src/util/map.rs index 345f0412..41db995a 100644 --- a/src/util/map.rs +++ b/src/util/map.rs @@ -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)] diff --git a/src/util/mod.rs b/src/util/mod.rs index 9c51e9ac..faf1ea42 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -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; \ No newline at end of file +pub use self::strext::_StrExt; diff --git a/src/util/osstringext.rs b/src/util/osstringext.rs index 3539feee..af4f00b3 100644 --- a/src/util/osstringext.rs +++ b/src/util/osstringext.rs @@ -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 { diff --git a/tests/app_settings.rs b/tests/app_settings.rs index ee2d6028..c4bc3cc3 100644 --- a/tests/app_settings.rs +++ b/tests/app_settings.rs @@ -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::>(), &*expected_args); + assert_eq!( + m.values_of("ARGS").unwrap().collect::>(), + &*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::>(), &*expected_args); + assert_eq!( + m.values_of("ARGS").unwrap().collect::>(), + &*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::>(), &*expected_args); + assert_eq!( + m.values_of("ARGS").unwrap().collect::>(), + &*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(); diff --git a/tests/arg_aliases.rs b/tests/arg_aliases.rs index 761fe218..5ea36003 100644 --- a/tests/arg_aliases.rs +++ b/tests/arg_aliases.rs @@ -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(); diff --git a/tests/completions.rs b/tests/completions.rs index f2ab7ac3..36340b1c 100644 --- a/tests/completions.rs +++ b/tests/completions.rs @@ -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] diff --git a/tests/hidden_args.rs b/tests/hidden_args.rs index 04a18641..35a3d90d 100644 --- a/tests/hidden_args.rs +++ b/tests/hidden_args.rs @@ -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)); -} \ No newline at end of file + assert!(test::compare_output( + app, + "test -h", + HIDDEN_LONG_ARGS_SHORT_HELP, + false + )); +} diff --git a/tests/macros.rs b/tests/macros.rs index 948de6c1..542b9208 100644 --- a/tests/macros.rs +++ b/tests/macros.rs @@ -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")); } diff --git a/tests/opts.rs b/tests/opts.rs index a6f96c89..2869fa25 100644 --- a/tests/opts.rs +++ b/tests/opts.rs @@ -398,10 +398,7 @@ fn issue_1047_min_zero_vals_default_val() { fn issue_1105_setup(argv: Vec<&'static str>) -> Result, 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) } diff --git a/tests/posix_compatible.rs b/tests/posix_compatible.rs index 83db4b18..6781e53d 100644 --- a/tests/posix_compatible.rs +++ b/tests/posix_compatible.rs @@ -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::>(), &["some", "other", "one", "two"]); + assert_eq!( + m.values_of("opt").unwrap().collect::>(), + &["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::>(), &["first", "overides", "some", "other", "val"]); + assert_eq!( + m.values_of("opt").unwrap().collect::>(), + &["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::>(), &["one,two"]); + assert_eq!( + m.values_of("opt").unwrap().collect::>(), + &["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::>(), &["some", "other", "value"]); + assert_eq!( + m.values_of("val").unwrap().collect::>(), + &["some", "other", "value"] + ); } #[test] fn posix_compatible_flags_long() { diff --git a/tests/require.rs b/tests/require.rs index 15901490..1c86eb95 100644 --- a/tests/require.rs +++ b/tests/require.rs @@ -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()); diff --git a/tests/subcommands.rs b/tests/subcommands.rs index def9197d..db093583 100644 --- a/tests/subcommands.rs +++ b/tests/subcommands.rs @@ -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::>()); + let expected = Some(vec![ + "sloppy", + "slop", + "-a", + "--", + "subprogram", + "position", + "args", + ]); + let actual = m.values_of("slop").map(|vals| vals.collect::>()); assert_eq!(expected, actual); -} \ No newline at end of file +} diff --git a/tests/utf8.rs b/tests/utf8.rs index 4252447d..5b439757 100644 --- a/tests/utf8.rs +++ b/tests/utf8.rs @@ -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() {