command/error.rs: add suggestions to BadValue variant

Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
pull/384/head
Manos Pitsidianakis 2 weeks ago
parent 8f3dee9b22
commit 89c7972e12
No known key found for this signature in database
GPG Key ID: 7729C7707F7E09D0

@ -656,9 +656,15 @@ mod tests {
assert_eq!(
parse_command(b"set foo").unwrap_err().to_string(),
BadValue {
inner: "Bad argument for `set`. Accepted arguments are [seen, unseen, plain, \
threaded, compact, conversations]."
.into(),
inner: "foo".into(),
suggestions: Some(&[
"seen",
"unseen",
"plain",
"threaded",
"compact",
"conversations"
])
}
.to_string(),
);

@ -29,6 +29,7 @@ pub enum CommandError {
},
BadValue {
inner: Cow<'static, str>,
suggestions: Option<&'static [&'static str]>,
},
WrongNumberOfArguments {
too_many: bool,
@ -63,7 +64,25 @@ impl std::fmt::Display for CommandError {
Self::Parsing { inner, kind: _ } => {
write!(fmt, "Could not parse command: {}", inner)
}
Self::BadValue { inner } => {
Self::BadValue {
inner,
suggestions: Some(suggs),
} => {
write!(fmt, "Bad value/argument: {}. Possible values are: ", inner)?;
let len = suggs.len();
for (i, val) in suggs.iter().enumerate() {
if i == len.saturating_sub(1) {
write!(fmt, "{}", val)?;
} else {
write!(fmt, "{}, ", val)?;
}
}
write!(fmt, "")
}
Self::BadValue {
inner,
suggestions: None,
} => {
write!(fmt, "Bad value/argument: {}", inner)
}
Self::WrongNumberOfArguments {
@ -121,3 +140,28 @@ impl std::fmt::Display for CommandError {
}
impl std::error::Error for CommandError {}
#[cfg(test)]
mod tests {
use super::CommandError;
#[test]
fn test_command_error_display() {
assert_eq!(
&CommandError::BadValue {
inner: "foo".into(),
suggestions: Some(&[
"seen",
"unseen",
"plain",
"threaded",
"compact",
"conversations"
])
}
.to_string(),
"Bad value/argument: foo. Possible values are: seen, unseen, plain, threaded, \
compact, conversations"
);
}
}

@ -24,22 +24,37 @@
use super::*;
use crate::command::{argcheck::*, error::*};
const FLAG_SUGGESTIONS: &[&str] = &[
"passed",
"replied",
"seen or read",
"junk or trash or trashed",
"draft",
"flagged",
];
macro_rules! command_err {
(nom $b:expr, $input: expr, $msg:literal) => {{
(nom $b:expr, $input: expr, $msg:expr, $suggs:expr) => {{
let evaluated: IResult<&'_ [u8], _> = { $b };
match evaluated {
Err(_) => {
let err = CommandError::BadValue { inner: $msg.into() };
let err = CommandError::BadValue {
inner: $msg.into(),
suggestions: $suggs,
};
return Ok(($input, Err(err)));
}
Ok(v) => v,
}
}};
($b:expr, $input: expr, $msg:literal) => {{
($b:expr, $input: expr, $msg:expr, $suggs:expr) => {{
let evaluated = { $b };
match evaluated {
Err(_) => {
let err = CommandError::BadValue { inner: $msg.into() };
let err = CommandError::BadValue {
inner: $msg.into(),
suggestions: $suggs,
};
return Ok(($input, Err(err)));
}
Ok(v) => v,
@ -206,7 +221,7 @@ pub fn parse_command(input: &[u8]) -> Result<Action, CommandError> {
/// assert_eq!(
/// &parsed.unwrap_err().to_string(),
/// "Bad value/argument: xunk is not a valid flag name. Possible values are: passed, replied, \
/// seen or read, junk or trash or trashed, draft and flagged."
/// seen or read, junk or trash or trashed, draft, flagged"
/// );
/// ```
pub fn flag<'a>(input: &'a [u8]) -> IResult<&'a [u8], Result<Action, CommandError>> {
@ -243,12 +258,8 @@ pub fn flag<'a>(input: &'a [u8]) -> IResult<&'a [u8], Result<Action, CommandErro
return Ok((
b"",
Err(CommandError::BadValue {
inner: format!(
"{flag} is not a valid flag name. Possible values are: passed, \
replied, seen or read, junk or trash or trashed, draft and \
flagged."
)
.into(),
inner: format!("{flag} is not a valid flag name").into(),
suggestions: Some(FLAG_SUGGESTIONS),
}),
));
};
@ -267,12 +278,8 @@ pub fn flag<'a>(input: &'a [u8]) -> IResult<&'a [u8], Result<Action, CommandErro
return Ok((
b"",
Err(CommandError::BadValue {
inner: format!(
"{flag} is not a valid flag name. Possible values are: passed, \
replied, seen or read, junk or trash or trashed, draft and \
flagged."
)
.into(),
inner: format!("{flag} is not a valid flag name").into(),
suggestions: Some(FLAG_SUGGESTIONS),
}),
));
};
@ -301,9 +308,13 @@ pub fn set(input: &[u8]) -> IResult<&[u8], Result<Action, CommandError>> {
let (input, _) = is_a(" ")(input)?;
arg_chk!(inc check, input);
let (input, ret) = command_err!(nom
alt((map(tag("seen"), |_| Listing(SetSeen)), map(tag("unseen"), |_| Listing(SetUnseen))))(input),
alt((
map(tag("seen"), |_| Listing(SetSeen)),
map(tag("unseen"), |_| Listing(SetUnseen)
)))(input),
input,
"Bad argument for `set`. Accepted arguments are [seen, unseen, plain, threaded, compact, conversations].");
String::from_utf8_lossy(input.trim()).to_string(),
Some(&["seen", "unseen", "plain", "threaded", "compact", "conversations"]));
arg_chk!(finish check, input);
let (input, _) = eof(input)?;
Ok((input, Ok(ret)))
@ -408,7 +419,8 @@ pub fn goto(input: &[u8]) -> IResult<&[u8], Result<Action, CommandError>> {
let (input, nth) = command_err!(nom
usize_c(input),
input,
"Argument must be an integer.");
"Argument must be an integer.",
None);
arg_chk!(finish check, input);
let (input, _) = eof(input)?;
Ok((input, Ok(Action::ViewMailbox(nth))))
@ -581,7 +593,8 @@ pub fn mailto(input: &[u8]) -> IResult<&[u8], Result<Action, CommandError>> {
let (input, val) = command_err!(
parser(val.as_bytes()),
val.as_bytes(),
"Could not parse mailto value. If the value is valid, please report this bug."
"Could not parse mailto value. If the value is valid, please report this bug.",
None
);
Ok((input, Ok(Compose(Mailto(val)))))
}
@ -958,7 +971,8 @@ pub fn toggle(input: &[u8]) -> IResult<&[u8], Result<Action, CommandError>> {
return Ok((
input,
Err(CommandError::BadValue {
inner: "Valid toggle values are thread_snooze, mouse, sign, encrypt.".into(),
inner: String::from_utf8_lossy(input).to_string().into(),
suggestions: Some(&["thread_snooze", "mouse", "sign", "encrypt"]),
}),
));
}

Loading…
Cancel
Save