Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions src/uu/cut/src/cut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1097,17 +1097,20 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
// The list is the value of the option that selected the mode, so the
// caret can be put under the one range that is at fault.
let (short, long) = mode_arg_names(mode_arg);
let reported = diag_args.as_ref().is_some_and(|args| {
e.render_option_value(
args,
list,
Some(short),
long,
&translate!("cut-diag-label-zero-bound"),
&translate!("cut-diag-help-list-syntax"),
)
});
uucore::error::quiet_if_reported(reported, UUsageError::new(1, e.message))
uucore::diagnostics::error_after_report(
diag_args.as_deref(),
UUsageError::new(1, e.message.clone()),
|args, _| {
e.render_option_value(
args,
list,
Some(short),
long,
&translate!("cut-diag-label-zero-bound"),
&translate!("cut-diag-help-list-syntax"),
)
},
)
})?;

let mode = match mode_arg {
Expand Down
7 changes: 3 additions & 4 deletions src/uu/dd/src/dd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1494,10 +1494,9 @@ fn is_fifo(filename: &str) -> bool {

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let raw_args: Vec<OsString> = args.collect();
// Kept for the caret in operand diagnostics, which echoes the command line.
let diag_args = uucore::diagnostics::capture(&raw_args);
let matches = uucore::clap_localization::handle_clap_result(uu_app(), raw_args)?;
// The command line is kept for the caret in operand diagnostics.
let (matches, diag_args) =
uucore::clap_localization::handle_clap_result_with_diagnostics(uu_app(), args.collect())?;

let settings: Settings = Parser::new().parse_with_diagnostics(
matches
Expand Down
27 changes: 10 additions & 17 deletions src/uu/dd/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
use std::ffi::{OsStr, OsString};
use std::ops::Range;

use uucore::diagnostics::Snapshot;
use uucore::error::{UError, quiet_if_reported};
use uucore::diagnostics::{Snapshot, list_items};
use uucore::error::UError;
use uucore::translate;

use crate::parseargs::ParseError;
Expand All @@ -37,8 +37,9 @@ pub fn operand_error(
operand: &str,
error: ParseError,
) -> Box<dyn UError> {
let reported = diag_args.is_some_and(|args| render(args, operand, &error));
quiet_if_reported(reported, error)
uucore::diagnostics::error_after_report(diag_args, error, |args, error| {
render(args, operand, error)
})
}

/// Render `error` against `args`, with a caret under the part of `operand`
Expand All @@ -53,20 +54,12 @@ fn render(args: &[OsString], operand: &str, error: &ParseError) -> bool {
// The value starts past the `=`, or ends the operand when there is none.
let value_start = operand.len().min(key_end + 1);
let value = || value_start..operand.len();
// A flag inside a comma-separated value. The list is walked the way the
// parser walks it rather than searched for the flag's text, which would
// match inside an earlier flag the failing one is a prefix of — the `noc`
// of `nocache,noc`.
// A flag inside a comma-separated value, at its place in the list rather
// than wherever its text first turns up.
let flag = |flag: &str| {
let mut at = value_start;
for part in operand[value_start..].split(',') {
if part == flag {
return Some(at..at + part.len());
}
// Every separator is one byte wide.
at += part.len() + 1;
}
None
list_items(&operand[value_start..], &[','])
.find(|&(part, _)| part == flag)
.map(|(_, span)| value_start + span.start..value_start + span.end)
};

let (span, help): (Range<usize>, &str) = match error {
Expand Down
17 changes: 6 additions & 11 deletions src/uu/head/src/head.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use std::os::fd::AsFd;
use std::path::Path;
use std::path::PathBuf;
use thiserror::Error;
use uucore::diagnostics::OptionValue;
use uucore::display::{Quotable, print_verbatim};
use uucore::error::{FromIo, UError, UResult, USimpleError};
use uucore::line_ending::LineEnding;
Expand Down Expand Up @@ -85,9 +86,7 @@ impl Default for Mode {
/// made of it.
pub struct SizeError {
pub message: String,
value: String,
short: char,
long: &'static str,
option: OptionValue,
error: ParseSizeError,
}

Expand All @@ -97,11 +96,9 @@ impl SizeError {
fn into_error(self, diag_args: Option<&[OsString]>) -> Box<dyn UError> {
self.error.size_value_error(
diag_args,
&self.value,
&self.option,
// The parser never saw the sign; the caret has to count it back in.
number_offset(&self.value),
self.short,
self.long,
number_offset(&self.option.value),
&self.message,
HeadError::MatchOption(self.message.clone()),
)
Expand All @@ -116,12 +113,10 @@ impl Mode {
long: &'static str,
key: &'static str,
) -> impl FnOnce(ParseSizeError) -> SizeError {
let value = value.to_string();
let option = OptionValue::new(value, short, long);
move |error| SizeError {
message: translate!(key, "err" => &error),
value,
short,
long,
option,
error,
}
}
Expand Down
35 changes: 16 additions & 19 deletions src/uu/join/src/join.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ use std::num::IntErrorKind;
#[cfg(unix)]
use std::os::unix::ffi::OsStrExt;
use thiserror::Error;
use uucore::diagnostics::OptionValue;
use uucore::display::Quotable;
use uucore::error::{FromIo, UError, UResult, USimpleError, quiet_if_reported, set_exit_code};
use uucore::error::{FromIo, UError, UResult, USimpleError, set_exit_code};
use uucore::i18n::collator::{
AlternateHandling, CollatorOptions, locale_cmp, should_use_locale_collation, try_init_collator,
};
Expand Down Expand Up @@ -788,27 +789,23 @@ fn parse_settings(matches: &clap::ArgMatches, diag_args: Option<&[OsString]>) ->
settings.autoformat = true;
} else {
let mut specs = vec![];
// Where the current field sits in the value, so that the caret can
// take the one field that is at fault out of a long list.
let mut at = 0;
for part in format.split([' ', ',', '\t']) {
// `-o` has no long form.
let option = OptionValue::with_names(format.clone(), Some('o'), None);
// Each field carries its place in the value, so that the caret can
// take the one that is at fault out of a long list.
for (part, span) in uucore::diagnostics::list_items(format, &[' ', ',', '\t']) {
specs.push(Spec::parse(part).map_err(|error| {
let message = error.to_string();
let reported = diag_args.is_some_and(|args| {
uucore::diagnostics::Snapshot::with_program(args).render_option_value(
format,
Some('o'),
None,
at..at + part.len(),
uucore::diagnostics::error_after_report(diag_args, error, |args, _| {
uucore::diagnostics::Snapshot::with_program(args).render_option(
&option,
span,
&message,
None,
Some(&translate!("join-diag-help-format")),
)
});
quiet_if_reported(reported, error)
})
})?);
// Every separator is one byte wide.
at += part.len() + 1;
}
settings.format = specs;
}
Expand Down Expand Up @@ -837,10 +834,10 @@ fn parse_settings(matches: &clap::ArgMatches, diag_args: Option<&[OsString]>) ->

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let raw_args: Vec<OsString> = args.collect();
// Kept for the caret in `-o` diagnostics, which needs the list as typed.
let diag_args = uucore::diagnostics::capture(&raw_args);
let matches = uucore::clap_localization::handle_clap_result(uu_app(), raw_args)?;
// The command line is kept for the caret in `-o` diagnostics, which needs
// the list as typed.
let (matches, diag_args) =
uucore::clap_localization::handle_clap_result_with_diagnostics(uu_app(), args.collect())?;

let mut opts = CollatorOptions::default();
opts.alternate_handling = Some(AlternateHandling::Shifted);
Expand Down
53 changes: 28 additions & 25 deletions src/uu/numfmt/src/numfmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use std::io::{BufRead, Write as _, stderr};
use std::str::FromStr;

use uucore::display::Quotable;
use uucore::error::{UResult, quiet_if_reported};
use uucore::error::UResult;
use uucore::i18n::decimal::locale_grouping_separator;
use uucore::parser::parse_size::{IEC_BASES, SI_BASES};
use uucore::parser::shortcut_value_parser::ShortcutValueParser;
Expand Down Expand Up @@ -132,10 +132,13 @@ fn handle_args<'a>(
// Only this mode stops on the first bad number; the others carry
// on, where a report per line would bury the output.
Err(error) => {
let reported = snapshot.is_some_and(|args| {
diagnostics::render_input(args, l, n, &error.to_string(), options)
});
return Err(quiet_if_reported(reported, error));
return Err(uucore::diagnostics::error_after_report(
snapshot,
error,
|args, error| {
diagnostics::render_input(args, l, n, &error.to_string(), options)
},
));
}
}
}
Expand Down Expand Up @@ -443,34 +446,34 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
// A format error still knows where in the format string it happened,
// so it is the one error worth a caret.
Err(ParseError::Format(error)) => {
let reported = format_args
.as_ref()
.zip(matches.get_one::<String>(FORMAT))
.is_some_and(|(args, format)| diagnostics::render(args, format, &error));
return Err(quiet_if_reported(
reported,
NumfmtError::IllegalArgument(error.message),
return Err(uucore::diagnostics::error_after_report(
format_args.as_deref(),
NumfmtError::IllegalArgument(error.message.clone()),
|args, _| {
matches
.get_one::<String>(FORMAT)
.is_some_and(|format| diagnostics::render(args, format, &error))
},
));
}
// As for a format, a field list knows which of its ranges is at fault.
Err(ParseError::Field(error)) => {
let reported = format_args
.as_ref()
.zip(matches.get_one::<String>(FIELD))
.is_some_and(|(args, fields)| diagnostics::render_field(args, fields, &error));
return Err(quiet_if_reported(
reported,
NumfmtError::IllegalArgument(error.message),
return Err(uucore::diagnostics::error_after_report(
format_args.as_deref(),
NumfmtError::IllegalArgument(error.message.clone()),
|args, _| {
matches
.get_one::<String>(FIELD)
.is_some_and(|fields| diagnostics::render_field(args, fields, &error))
},
));
}
// An option value that is wrong as a whole: underline it where typed.
Err(ParseError::Value(error)) => {
let reported = format_args
.as_ref()
.is_some_and(|args| diagnostics::render_value(args, &error));
return Err(quiet_if_reported(
reported,
NumfmtError::IllegalArgument(error.message),
return Err(uucore::diagnostics::error_after_report(
format_args.as_deref(),
NumfmtError::IllegalArgument(error.message.clone()),
|args, _| diagnostics::render_value(args, &error),
));
}
Err(ParseError::Other(message)) => {
Expand Down
Loading