pr: update to clap 4

This commit is contained in:
Terts Diepraam 2022-09-30 16:07:15 +02:00
parent b5ab886f4d
commit 8ac1eaf2d6
2 changed files with 112 additions and 75 deletions

View file

@ -15,7 +15,7 @@ edition = "2021"
path = "src/pr.rs" path = "src/pr.rs"
[dependencies] [dependencies]
clap = { version = "3.2", features = ["wrap_help", "cargo"] } clap = { version = "4.0", features = ["wrap_help", "cargo"] }
time = { version = "0.3", features = ["local-offset", "macros", "formatting"] } time = { version = "0.3", features = ["local-offset", "macros", "formatting"] }
uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries"] }
quick-error = "2.0.1" quick-error = "2.0.1"

View file

@ -9,7 +9,7 @@
#[macro_use] #[macro_use]
extern crate quick_error; extern crate quick_error;
use clap::{crate_version, Arg, ArgMatches, Command}; use clap::{crate_version, Arg, ArgAction, ArgMatches, Command};
use itertools::Itertools; use itertools::Itertools;
use quick_error::ResultExt; use quick_error::ResultExt;
use regex::Regex; use regex::Regex;
@ -192,18 +192,18 @@ quick_error! {
} }
} }
pub fn uu_app<'a>() -> Command<'a> { pub fn uu_app() -> Command {
Command::new(uucore::util_name()) Command::new(uucore::util_name())
.version(crate_version!()) .version(crate_version!())
.about(ABOUT) .about(ABOUT)
.after_help(AFTER_HELP) .after_help(AFTER_HELP)
.infer_long_args(true) .infer_long_args(true)
.args_override_self(true) .args_override_self(true)
.disable_help_flag(true)
.arg( .arg(
Arg::new(options::PAGES) Arg::new(options::PAGES)
.long(options::PAGES) .long(options::PAGES)
.help("Begin and stop printing with page FIRST_PAGE[:LAST_PAGE]") .help("Begin and stop printing with page FIRST_PAGE[:LAST_PAGE]")
.takes_value(true)
.value_name("FIRST_PAGE[:LAST_PAGE]"), .value_name("FIRST_PAGE[:LAST_PAGE]"),
) )
.arg( .arg(
@ -214,157 +214,194 @@ pub fn uu_app<'a>() -> Command<'a> {
"Use the string header to replace the file name \ "Use the string header to replace the file name \
in the header line.", in the header line.",
) )
.takes_value(true)
.value_name("STRING"), .value_name("STRING"),
) )
.arg( .arg(
Arg::new(options::DOUBLE_SPACE) Arg::new(options::DOUBLE_SPACE)
.short('d') .short('d')
.long(options::DOUBLE_SPACE) .long(options::DOUBLE_SPACE)
.help("Produce output that is double spaced. An extra <newline> character is output following every <newline> .help(
found in the input.") "Produce output that is double spaced. An extra <newline> \
character is output following every <newline> found in the input.",
)
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::NUMBER_LINES) Arg::new(options::NUMBER_LINES)
.short('n') .short('n')
.long(options::NUMBER_LINES) .long(options::NUMBER_LINES)
.help("Provide width digit line numbering. The default for width, if not specified, is 5. The number occupies .help(
the first width column positions of each text column or each line of -m output. If char (any non-digit "Provide width digit line numbering. The default for width, \
character) is given, it is appended to the line number to separate it from whatever follows. The default if not specified, is 5. The number occupies the first width column \
for char is a <tab>. Line numbers longer than width columns are truncated.") positions of each text column or each line of -m output. If char \
.takes_value(true) (any non-digit character) is given, it is appended to the line number \
to separate it from whatever follows. The default for char is a <tab>. \
Line numbers longer than width columns are truncated.",
)
.allow_hyphen_values(true) .allow_hyphen_values(true)
.value_name("[char][width]") .value_name("[char][width]"),
) )
.arg( .arg(
Arg::new(options::FIRST_LINE_NUMBER) Arg::new(options::FIRST_LINE_NUMBER)
.short('N') .short('N')
.long(options::FIRST_LINE_NUMBER) .long(options::FIRST_LINE_NUMBER)
.help("start counting with NUMBER at 1st line of first page printed") .help("start counting with NUMBER at 1st line of first page printed")
.takes_value(true) .value_name("NUMBER"),
.value_name("NUMBER")
) )
.arg( .arg(
Arg::new(options::OMIT_HEADER) Arg::new(options::OMIT_HEADER)
.short('t') .short('t')
.long(options::OMIT_HEADER) .long(options::OMIT_HEADER)
.help("Write neither the five-line identifying header nor the five-line trailer usually supplied for each page. Quit .help(
writing after the last line of each file without spacing to the end of the page.") "Write neither the five-line identifying header nor the five-line \
trailer usually supplied for each page. Quit writing after the last line \
of each file without spacing to the end of the page.",
)
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::PAGE_LENGTH) Arg::new(options::PAGE_LENGTH)
.short('l') .short('l')
.long(options::PAGE_LENGTH) .long(options::PAGE_LENGTH)
.help("Override the 66-line default (default number of lines of text 56, and with -F 63) and reset the page length to lines. If lines is not greater than the sum of both .help(
the header and trailer depths (in lines), the pr utility shall suppress both the header and trailer, as if the "Override the 66-line default (default number of lines of text 56, \
-t option were in effect. ") and with -F 63) and reset the page length to lines. If lines is not \
.takes_value(true) greater than the sum of both the header and trailer depths (in lines), \
.value_name("PAGE_LENGTH") the pr utility shall suppress both the header and trailer, as if the -t \
option were in effect. ",
)
.value_name("PAGE_LENGTH"),
) )
.arg( .arg(
Arg::new(options::NO_FILE_WARNINGS) Arg::new(options::NO_FILE_WARNINGS)
.short('r') .short('r')
.long(options::NO_FILE_WARNINGS) .long(options::NO_FILE_WARNINGS)
.help("omit warning when a file cannot be opened") .help("omit warning when a file cannot be opened")
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::FORM_FEED) Arg::new(options::FORM_FEED)
.short('F') .short('F')
.short_alias('f') .short_alias('f')
.long(options::FORM_FEED) .long(options::FORM_FEED)
.help("Use a <form-feed> for new pages, instead of the default behavior that uses a sequence of <newline>s.") .help(
"Use a <form-feed> for new pages, instead of the default behavior that \
uses a sequence of <newline>s.",
)
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::COLUMN_WIDTH) Arg::new(options::COLUMN_WIDTH)
.short('w') .short('w')
.long(options::COLUMN_WIDTH) .long(options::COLUMN_WIDTH)
.help("Set the width of the line to width column positions for multiple text-column output only. If the -w option is .help(
not specified and the -s option is not specified, the default width shall be 72. If the -w option is not specified "Set the width of the line to width column positions for multiple \
and the -s option is specified, the default width shall be 512.") text-column output only. If the -w option is not specified and the -s option \
.takes_value(true) is not specified, the default width shall be 72. If the -w option is not specified \
.value_name("width") and the -s option is specified, the default width shall be 512.",
)
.value_name("width"),
) )
.arg( .arg(
Arg::new(options::PAGE_WIDTH) Arg::new(options::PAGE_WIDTH)
.short('W') .short('W')
.long(options::PAGE_WIDTH) .long(options::PAGE_WIDTH)
.help("set page width to PAGE_WIDTH (72) characters always, .help(
"set page width to PAGE_WIDTH (72) characters always,
truncate lines, except -J option is set, no interference truncate lines, except -J option is set, no interference
with -S or -s") with -S or -s",
.takes_value(true) )
.value_name("width") .value_name("width"),
) )
.arg( .arg(
Arg::new(options::ACROSS) Arg::new(options::ACROSS)
.short('a') .short('a')
.long(options::ACROSS) .long(options::ACROSS)
.help("Modify the effect of the - column option so that the columns are filled across the page in a round-robin order .help(
(for example, when column is 2, the first input line heads column 1, the second heads column 2, the third is the "Modify the effect of the - column option so that the columns are filled \
second line in column 1, and so on).") across the page in a round-robin order (for example, when column is 2, the \
first input line heads column 1, the second heads column 2, the third is the \
second line in column 1, and so on).",
)
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::COLUMN) Arg::new(options::COLUMN)
.long(options::COLUMN) .long(options::COLUMN)
.help("Produce multi-column output that is arranged in column columns (the default shall be 1) and is written down each .help(
column in the order in which the text is received from the input file. This option should not be used with -m. "Produce multi-column output that is arranged in column columns \
The options -e and -i shall be assumed for multiple text-column output. Whether or not text columns are produced (the default shall be 1) and is written down each column in the order in which \
with identical vertical lengths is unspecified, but a text column shall never exceed the length of the the text is received from the input file. This option should not be used with -m. \
page (see the -l option). When used with -t, use the minimum number of lines to write the output.") The options -e and -i shall be assumed for multiple text-column output. Whether \
.takes_value(true) or not text columns are produced with identical vertical lengths is unspecified, \
.value_name("column") but a text column shall never exceed the length of the page (see the -l option). \
When used with -t, use the minimum number of lines to write the output.",
)
.value_name("column"),
) )
.arg( .arg(
Arg::new(options::COLUMN_CHAR_SEPARATOR) Arg::new(options::COLUMN_CHAR_SEPARATOR)
.short('s') .short('s')
.long(options::COLUMN_CHAR_SEPARATOR) .long(options::COLUMN_CHAR_SEPARATOR)
.help("Separate text columns by the single character char instead of by the appropriate number of <space>s .help(
(default for char is the <tab> character).") "Separate text columns by the single character char instead of by the \
.takes_value(true) appropriate number of <space>s (default for char is the <tab> character).",
.value_name("char") )
.value_name("char"),
) )
.arg( .arg(
Arg::new(options::COLUMN_STRING_SEPARATOR) Arg::new(options::COLUMN_STRING_SEPARATOR)
.short('S') .short('S')
.long(options::COLUMN_STRING_SEPARATOR) .long(options::COLUMN_STRING_SEPARATOR)
.help("separate columns by STRING, .help(
without -S: Default separator <TAB> with -J and <space> "separate columns by STRING, \
otherwise (same as -S\" \"), no effect on column options") without -S: Default separator <TAB> with -J and <space> \
.takes_value(true) otherwise (same as -S\" \"), no effect on column options",
.value_name("string") )
.value_name("string"),
) )
.arg( .arg(
Arg::new(options::MERGE) Arg::new(options::MERGE)
.short('m') .short('m')
.long(options::MERGE) .long(options::MERGE)
.help("Merge files. Standard output shall be formatted so the pr utility writes one line from each file specified by a .help(
file operand, side by side into text columns of equal fixed widths, in terms of the number of column positions. "Merge files. Standard output shall be formatted so the pr utility \
Implementations shall support merging of at least nine file operands.") writes one line from each file specified by a file operand, side by side \
into text columns of equal fixed widths, in terms of the number of column \
positions. Implementations shall support merging of at least nine file operands.",
)
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::INDENT) Arg::new(options::INDENT)
.short('o') .short('o')
.long(options::INDENT) .long(options::INDENT)
.help("Each line of output shall be preceded by offset <space>s. If the -o option is not specified, the default offset .help(
shall be zero. The space taken is in addition to the output line width (see the -w option below).") "Each line of output shall be preceded by offset <space>s. If the -o \
.takes_value(true) option is not specified, the default offset shall be zero. The space taken is \
.value_name("margin") in addition to the output line width (see the -w option below).",
)
.value_name("margin"),
) )
.arg( .arg(
Arg::new(options::JOIN_LINES) Arg::new(options::JOIN_LINES)
.short('J') .short('J')
.help("merge full lines, turns off -W line truncation, no column .help(
alignment, --sep-string[=STRING] sets separators") "merge full lines, turns off -W line truncation, no column
alignment, --sep-string[=STRING] sets separators",
)
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::HELP) Arg::new(options::HELP)
.long(options::HELP) .long(options::HELP)
.help("Print help information") .help("Print help information")
.action(ArgAction::Help),
) )
.arg( .arg(
Arg::new(options::FILES) Arg::new(options::FILES)
.multiple_occurrences(true) .action(ArgAction::Append)
.multiple_values(true) .value_hint(clap::ValueHint::FilePath),
.value_hint(clap::ValueHint::FilePath)
) )
} }
@ -392,7 +429,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
files.insert(0, FILE_STDIN); files.insert(0, FILE_STDIN);
} }
let file_groups: Vec<_> = if matches.contains_id(options::MERGE) { let file_groups: Vec<_> = if matches.get_flag(options::MERGE) {
vec![files] vec![files]
} else { } else {
files.into_iter().map(|i| vec![i]).collect() files.into_iter().map(|i| vec![i]).collect()
@ -456,7 +493,7 @@ fn recreate_arguments(args: &[String]) -> Vec<String> {
} }
fn print_error(matches: &ArgMatches, err: &PrError) { fn print_error(matches: &ArgMatches, err: &PrError) {
if !matches.contains_id(options::NO_FILE_WARNINGS) { if !matches.get_flag(options::NO_FILE_WARNINGS) {
eprintln!("{}", err); eprintln!("{}", err);
} }
} }
@ -480,21 +517,21 @@ fn build_options(
paths: &[&str], paths: &[&str],
free_args: &str, free_args: &str,
) -> Result<OutputOptions, PrError> { ) -> Result<OutputOptions, PrError> {
let form_feed_used = matches.contains_id(options::FORM_FEED); let form_feed_used = matches.get_flag(options::FORM_FEED);
let is_merge_mode = matches.contains_id(options::MERGE); let is_merge_mode = matches.get_flag(options::MERGE);
if is_merge_mode && matches.contains_id(options::COLUMN) { if is_merge_mode && matches.contains_id(options::COLUMN) {
let err_msg = String::from("cannot specify number of columns when printing in parallel"); let err_msg = String::from("cannot specify number of columns when printing in parallel");
return Err(PrError::EncounteredErrors(err_msg)); return Err(PrError::EncounteredErrors(err_msg));
} }
if is_merge_mode && matches.contains_id(options::ACROSS) { if is_merge_mode && matches.get_flag(options::ACROSS) {
let err_msg = String::from("cannot specify both printing across and printing in parallel"); let err_msg = String::from("cannot specify both printing across and printing in parallel");
return Err(PrError::EncounteredErrors(err_msg)); return Err(PrError::EncounteredErrors(err_msg));
} }
let merge_files_print = if matches.contains_id(options::MERGE) { let merge_files_print = if matches.get_flag(options::MERGE) {
Some(paths.len()) Some(paths.len())
} else { } else {
None None
@ -546,7 +583,7 @@ fn build_options(
} }
}); });
let double_space = matches.contains_id(options::DOUBLE_SPACE); let double_space = matches.get_flag(options::DOUBLE_SPACE);
let content_line_separator = if double_space { let content_line_separator = if double_space {
"\n".repeat(2) "\n".repeat(2)
@ -652,7 +689,7 @@ fn build_options(
let page_length_le_ht = page_length < (HEADER_LINES_PER_PAGE + TRAILER_LINES_PER_PAGE); let page_length_le_ht = page_length < (HEADER_LINES_PER_PAGE + TRAILER_LINES_PER_PAGE);
let display_header_and_trailer = let display_header_and_trailer =
!(page_length_le_ht) && !matches.contains_id(options::OMIT_HEADER); !(page_length_le_ht) && !matches.get_flag(options::OMIT_HEADER);
let content_lines_per_page = if page_length_le_ht { let content_lines_per_page = if page_length_le_ht {
page_length page_length
@ -660,14 +697,14 @@ fn build_options(
page_length - (HEADER_LINES_PER_PAGE + TRAILER_LINES_PER_PAGE) page_length - (HEADER_LINES_PER_PAGE + TRAILER_LINES_PER_PAGE)
}; };
let page_separator_char = if matches.contains_id(options::FORM_FEED) { let page_separator_char = if matches.get_flag(options::FORM_FEED) {
let bytes = vec![FF]; let bytes = vec![FF];
String::from_utf8(bytes).unwrap() String::from_utf8(bytes).unwrap()
} else { } else {
"\n".to_string() "\n".to_string()
}; };
let across_mode = matches.contains_id(options::ACROSS); let across_mode = matches.get_flag(options::ACROSS);
let column_separator = match matches.get_one::<String>(options::COLUMN_STRING_SEPARATOR) { let column_separator = match matches.get_one::<String>(options::COLUMN_STRING_SEPARATOR) {
Some(x) => Some(x), Some(x) => Some(x),
@ -687,7 +724,7 @@ fn build_options(
let column_width = let column_width =
parse_usize(matches, options::COLUMN_WIDTH).unwrap_or(Ok(default_column_width))?; parse_usize(matches, options::COLUMN_WIDTH).unwrap_or(Ok(default_column_width))?;
let page_width = if matches.contains_id(options::JOIN_LINES) { let page_width = if matches.get_flag(options::JOIN_LINES) {
None None
} else { } else {
match parse_usize(matches, options::PAGE_WIDTH) { match parse_usize(matches, options::PAGE_WIDTH) {
@ -723,7 +760,7 @@ fn build_options(
}); });
let offset_spaces = " ".repeat(parse_usize(matches, options::INDENT).unwrap_or(Ok(0))?); let offset_spaces = " ".repeat(parse_usize(matches, options::INDENT).unwrap_or(Ok(0))?);
let join_lines = matches.contains_id(options::JOIN_LINES); let join_lines = matches.get_flag(options::JOIN_LINES);
let col_sep_for_printing = column_mode_options let col_sep_for_printing = column_mode_options
.as_ref() .as_ref()