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
1 change: 0 additions & 1 deletion src/uu/dd/locales/en-US.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,6 @@ dd-error-multiple-case = Only one of conv=lcase or conv=ucase may be specified
dd-error-multiple-block = Only one of conv=block or conv=unblock may be specified
dd-error-multiple-excl = Only one ov conv=excl or conv=nocreat may be specified
dd-error-invalid-flag = invalid input flag: ‘{ $flag }’
Try '{ $cmd } --help' for more information.
dd-error-conv-flag-no-match = Unrecognized conv=CONV -> { $flag }
dd-error-multiplier-parse-failure = invalid number: '{ $input }'
dd-error-multiplier-overflow = Multiplier string would overflow on current system -> { $input }
Expand Down
1 change: 0 additions & 1 deletion src/uu/dd/locales/fr-FR.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,6 @@ dd-error-multiple-case = Seul un seul de conv=lcase ou conv=ucase peut être sp
dd-error-multiple-block = Seul un seul de conv=block ou conv=unblock peut être spécifié
dd-error-multiple-excl = Seul un seul de conv=excl ou conv=nocreat peut être spécifié
dd-error-invalid-flag = indicateur d'entrée invalide : '{ $flag }'
Essayez '{ $cmd } --help' pour plus d'informations.
dd-error-conv-flag-no-match = conv=CONV non reconnu -> { $flag }
dd-error-multiplier-parse-failure = nombre invalide : ‘{ $input }‘
dd-error-multiplier-overflow = La chaîne de multiplicateur déborderait sur le système actuel -> { $input }
Expand Down
7 changes: 1 addition & 6 deletions src/uu/dd/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,11 @@ fn render(args: &[OsString], operand: &str, error: &ParseError) -> bool {
let Some(index) = snapshot.index_of(OsStr::new(operand)) else {
return false;
};
// Some messages end with a "Try --help" hint of their own; the report
// closes with advice about the very syntax that failed, so only the
// headline is kept.
let message = error.to_string();
let headline = message.lines().next().unwrap_or_default();
snapshot.render_inside_at(
index,
operand,
span,
headline,
&error.to_string(),
None,
Some(&translate!(help)),
)
Expand Down
9 changes: 8 additions & 1 deletion src/uu/dd/src/parseargs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub enum ParseError {
MultipleBlockUnblock,
#[error("{}", translate!("dd-error-multiple-excl"))]
MultipleExclNoCreate,
#[error("{}", translate!("dd-error-invalid-flag", "flag" => .0.clone(), "cmd" => uucore::execution_phrase()))]
#[error("{}", translate!("dd-error-invalid-flag", "flag" => .0.clone()))]
FlagNoMatch(String),
#[error("{}", translate!("dd-error-conv-flag-no-match", "flag" => .0.clone()))]
ConvFlagNoMatch(String),
Expand Down Expand Up @@ -484,6 +484,13 @@ impl UError for ParseError {
fn code(&self) -> i32 {
1
}

/// The one message that ends on a hint about the syntax it rejected. The
/// hint is left to this, rather than written into the message, so that it
/// survives a caret report replacing the message.
fn usage(&self) -> bool {
matches!(self, Self::FlagNoMatch(_))
}
}

fn show_zero_multiplier_warning() {
Expand Down
41 changes: 36 additions & 5 deletions src/uucore/src/lib/mods/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,8 @@ impl ExitCode {
/// # Returns
///
/// A bare [`ExitCode`] carrying `error`'s code when `reported`, and `error`
/// itself otherwise.
/// itself otherwise. An error that asks for a usage hint still gets one: the
/// hint is not part of the message the report replaced.
///
/// # Examples
///
Expand All @@ -707,11 +708,13 @@ impl ExitCode {
/// ```
pub fn quiet_if_reported<E: Into<Box<dyn UError>>>(reported: bool, error: E) -> Box<dyn UError> {
let error = error.into();
if reported {
ExitCode::new(error.code())
} else {
error
if !reported {
return error;
}
if error.usage() {
return UUsageError::new(error.code(), String::new());
}
ExitCode::new(error.code())
}

impl Error for ExitCode {}
Expand Down Expand Up @@ -833,6 +836,34 @@ impl Display for ClapErrorWrapper {

#[cfg(test)]
mod tests {
use super::{USimpleError, UUsageError, quiet_if_reported};

/// A quieted error keeps its code but says nothing: the report already did.
#[test]
fn a_reported_error_carries_only_its_code() {
let error = quiet_if_reported(true, USimpleError::new(3, "bad size".to_string()));
assert_eq!(error.code(), 3);
assert_eq!(error.to_string(), "");
assert!(!error.usage());
}

/// Quieting a usage error must not swallow its "Try --help" hint, or the
/// output would depend on whether a caret happened to be drawn.
#[test]
fn a_reported_usage_error_still_asks_for_the_hint() {
let error = quiet_if_reported(true, UUsageError::new(125, "bad mode".to_string()));
assert_eq!(error.code(), 125);
assert_eq!(error.to_string(), "");
assert!(error.usage());
}

#[test]
fn an_unreported_error_is_left_alone() {
let error = quiet_if_reported(false, UUsageError::new(125, "bad mode".to_string()));
assert_eq!(error.to_string(), "bad mode");
assert!(error.usage());
}

#[test]
#[cfg(unix)]
fn test_nix_error_conversion() {
Expand Down
15 changes: 12 additions & 3 deletions tests/by-util/test_cut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1228,9 +1228,10 @@ mod diagnostics {
.fails_with_code(1);

// One item of the list is at fault, not the whole of it.
assert_eq!(
result.stderr_as_displayed(),
"\
let stderr = result.stderr_as_displayed();
assert!(
stderr.starts_with(
"\
cut: invalid decreasing range
╭─[ cut:1:10 ]
Expand All @@ -1240,6 +1241,14 @@ cut: invalid decreasing range
│ Help: a list is N, N-M, N- or -M, separated by commas, as in -f1,4-6,9-
───╯"
),
"{stderr}"
);
// The caret replaces the message, not the usage hint: a pipe and a
// terminal must not disagree on whether one was printed.
assert!(
stderr.ends_with("cut --help' for more information."),
"{stderr}"
);
}

Expand Down
23 changes: 19 additions & 4 deletions tests/by-util/test_dd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2335,18 +2335,33 @@ dd: Unrecognized operand 'bsx=1'

#[cfg(unix)]
#[test]
fn test_snippet_drops_the_try_help_hint_of_a_flag_message() {
fn test_snippet_keeps_the_try_help_hint_of_a_flag_message() {
let result = new_ucmd!()
.terminal_sim_stderr()
.args(&["iflag=nope"])
.pipe_in("")
.fails_with_code(1);
let stderr = result.stderr_as_displayed();

// The report ends with advice of its own, so the hint would be noise
// in the middle of it.
assert!(!stderr.contains("--help"), "{stderr}");
assert!(stderr.contains("dd:1:10"), "{stderr}");
// The caret replaces the message, not the usage hint: a pipe and a
// terminal must not disagree on whether one was printed.
assert!(
stderr
.trim_end()
.ends_with("dd --help' for more information."),
"{stderr}"
);
}

#[test]
fn test_plain_message_keeps_the_try_help_hint_of_a_flag_message() {
new_ucmd!()
.args(&["iflag=nope"])
.pipe_in("")
.fails_with_code(1)
.stderr_contains("dd: invalid input flag: \u{2018}nope\u{2019}")
.stderr_contains("--help' for more information.");
}

#[test]
Expand Down
15 changes: 12 additions & 3 deletions tests/by-util/test_stdbuf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,9 +447,10 @@ mod diagnostics {
.fails_with_code(125);

// The number parsed; only the unit did not.
assert_eq!(
result.stderr_as_displayed(),
"\
let stderr = result.stderr_as_displayed();
assert!(
stderr.starts_with(
"\
stdbuf: invalid mode '6pq'
╭─[ stdbuf:1:12 ]
Expand All @@ -459,6 +460,14 @@ stdbuf: invalid mode '6pq'
│ Help: a size is a number and an optional unit: K, M, G and so on for 1024, KB, MB, GB for 1000
───╯"
),
"{stderr}"
);
// The caret replaces the message, not the usage hint: a pipe and a
// terminal must not disagree on whether one was printed.
assert!(
stderr.ends_with("stdbuf --help' for more information."),
"{stderr}"
);
}

Expand Down
Loading