Merge pull request #4695 from cakebaker/wc_total

wc: implement --total
This commit is contained in:
Sylvestre Ledru 2023-04-02 10:25:40 +02:00 committed by GitHub
commit dc8d07ccce
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 125 additions and 14 deletions

View file

@ -42,6 +42,7 @@ struct Settings {
show_max_line_length: bool,
files0_from_stdin_mode: bool,
title_quoting_style: QuotingStyle,
total_when: TotalWhen,
}
impl Settings {
@ -65,6 +66,7 @@ impl Settings {
show_max_line_length: matches.get_flag(options::MAX_LINE_LENGTH),
files0_from_stdin_mode,
title_quoting_style,
total_when: matches.get_one::<String>(options::TOTAL).unwrap().into(),
};
if settings.show_bytes
@ -84,6 +86,7 @@ impl Settings {
show_max_line_length: false,
files0_from_stdin_mode,
title_quoting_style: settings.title_quoting_style,
total_when: settings.total_when,
}
}
@ -107,6 +110,7 @@ pub mod options {
pub static FILES0_FROM: &str = "files0-from";
pub static LINES: &str = "lines";
pub static MAX_LINE_LENGTH: &str = "max-line-length";
pub static TOTAL: &str = "total";
pub static WORDS: &str = "words";
}
@ -160,6 +164,37 @@ impl Input {
}
}
/// When to show the "total" line
#[derive(PartialEq)]
enum TotalWhen {
Auto,
Always,
Only,
Never,
}
impl From<&String> for TotalWhen {
fn from(s: &String) -> Self {
match s.as_ref() {
"auto" => Self::Auto,
"always" => Self::Always,
"only" => Self::Only,
"never" => Self::Never,
_ => unreachable!("Should have been caught by clap"),
}
}
}
impl TotalWhen {
fn is_total_row_visible(&self, num_inputs: usize) -> bool {
match self {
Self::Auto => num_inputs > 1,
Self::Always | Self::Only => true,
Self::Never => false,
}
}
}
#[derive(Debug)]
enum WcError {
FilesDisabled(String),
@ -246,6 +281,15 @@ pub fn uu_app() -> Command {
.help("print the length of the longest line")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new(options::TOTAL)
.long(options::TOTAL)
.value_parser(["auto", "always", "only", "never"])
.default_value("auto")
.hide_default_value(true)
.value_name("WHEN")
.help("when to print a line with total counts"),
)
.arg(
Arg::new(options::WORDS)
.short('w')
@ -561,11 +605,19 @@ fn compute_number_width(inputs: &[Input], settings: &Settings) -> usize {
}
fn wc(inputs: &[Input], settings: &Settings) -> UResult<()> {
let number_width = compute_number_width(inputs, settings);
let mut total_word_count = WordCount::default();
let num_inputs = inputs.len();
let (number_width, are_stats_visible, total_row_title) =
if settings.total_when == TotalWhen::Only {
(1, false, None)
} else {
let number_width = compute_number_width(inputs, settings);
let title = Some(String::from("total"));
(number_width, true, title)
};
let is_total_row_visible = settings.total_when.is_total_row_visible(inputs.len());
for input in inputs {
let word_count = match word_count_from_input(input, settings) {
@ -595,20 +647,23 @@ fn wc(inputs: &[Input], settings: &Settings) -> UResult<()> {
};
total_word_count += word_count;
let result = word_count.with_title(input.to_title(&settings.title_quoting_style));
if let Err(err) = print_stats(settings, &result, number_width) {
show!(USimpleError::new(
1,
format!(
"failed to print result for {}: {}",
&result.title.unwrap_or_else(|| String::from("<stdin>")),
err,
),
));
if are_stats_visible {
if let Err(err) = print_stats(settings, &result, number_width) {
show!(USimpleError::new(
1,
format!(
"failed to print result for {}: {}",
&result.title.unwrap_or_else(|| String::from("<stdin>")),
err,
),
));
}
}
}
if num_inputs > 1 {
let total_result = total_word_count.with_title(Some(String::from("total")));
if is_total_row_visible {
let total_result = total_word_count.with_title(total_row_title);
if let Err(err) = print_stats(settings, &total_result, number_width) {
show!(USimpleError::new(
1,

View file

@ -464,3 +464,59 @@ fn test_files0_from_with_stdin_try_read_from_stdin() {
.stderr_contains(MSG)
.stdout_is("");
}
#[test]
fn test_total_auto() {
new_ucmd!()
.args(&["lorem_ipsum.txt", "--total=auto"])
.run()
.stdout_is(" 13 109 772 lorem_ipsum.txt\n");
new_ucmd!()
.args(&["lorem_ipsum.txt", "moby_dick.txt", "--total=auto"])
.run()
.stdout_is(
" 13 109 772 lorem_ipsum.txt\n 18 204 1115 moby_dick.txt\n 31 313 1887 total\n",
);
}
#[test]
fn test_total_always() {
new_ucmd!()
.args(&["lorem_ipsum.txt", "--total=always"])
.run()
.stdout_is(" 13 109 772 lorem_ipsum.txt\n 13 109 772 total\n");
new_ucmd!()
.args(&["lorem_ipsum.txt", "moby_dick.txt", "--total=always"])
.run()
.stdout_is(
" 13 109 772 lorem_ipsum.txt\n 18 204 1115 moby_dick.txt\n 31 313 1887 total\n",
);
}
#[test]
fn test_total_never() {
new_ucmd!()
.args(&["lorem_ipsum.txt", "--total=never"])
.run()
.stdout_is(" 13 109 772 lorem_ipsum.txt\n");
new_ucmd!()
.args(&["lorem_ipsum.txt", "moby_dick.txt", "--total=never"])
.run()
.stdout_is(" 13 109 772 lorem_ipsum.txt\n 18 204 1115 moby_dick.txt\n");
}
#[test]
fn test_total_only() {
new_ucmd!()
.args(&["lorem_ipsum.txt", "--total=only"])
.run()
.stdout_is("13 109 772\n");
new_ucmd!()
.args(&["lorem_ipsum.txt", "moby_dick.txt", "--total=only"])
.run()
.stdout_is("31 313 1887\n");
}