pub use crate::clap::{Error as ClapError, ErrorKind};
pub use crate::shlex::MismatchedQuotes;
use std::fmt::{Display, Formatter};
use std::{error, fmt, io};
#[allow(clippy::pub_enum_variant_names)]
#[derive(Debug)]
pub enum Error {
ClapError(ClapError),
ReadlineError(ReadlineError),
MismatchedQuotes(usize),
ExecutionError(ExecutionError),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::ClapError(e) => e.fmt(f),
Error::ReadlineError(e) => e.fmt(f),
Error::MismatchedQuotes(_) => write!(f, "Mismatched quotes"),
Error::ExecutionError(e) => e.fmt(f),
}
}
}
impl error::Error for Error {}
impl From<ClapError> for Error {
fn from(e: ClapError) -> Self {
Error::ClapError(e)
}
}
impl From<ReadlineError> for Error {
fn from(e: ReadlineError) -> Self {
Error::ReadlineError(e)
}
}
impl From<MismatchedQuotes> for Error {
fn from(e: MismatchedQuotes) -> Self {
Error::MismatchedQuotes(e.0)
}
}
impl From<ExecutionError> for Error {
fn from(e: ExecutionError) -> Self {
Error::ExecutionError(e)
}
}
#[derive(Debug)]
#[allow(clippy::pub_enum_variant_names)]
#[allow(clippy::module_name_repetitions)]
#[non_exhaustive]
pub enum ReadlineError {
Io(io::Error),
Eof,
Interrupted,
#[cfg(unix)]
Utf8Error,
#[cfg(unix)]
Errno(nix::Error),
#[cfg(windows)]
WindowResize,
#[cfg(windows)]
Decode(std::char::DecodeUtf16Error),
}
impl Display for ReadlineError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ReadlineError::Io(ref err) => err.fmt(f),
ReadlineError::Eof => write!(f, "EOF"),
ReadlineError::Interrupted => write!(f, "Interrupted"),
#[cfg(unix)]
ReadlineError::Utf8Error => write!(f, "invalid utf-8: corrupt contents"),
#[cfg(unix)]
ReadlineError::Errno(ref err) => err.fmt(f),
#[cfg(windows)]
ReadlineError::WindowResize => write!(f, "WindowResize"),
#[cfg(windows)]
ReadlineError::Decode(ref err) => err.fmt(f),
}
}
}
impl std::error::Error for ReadlineError {}
impl From<io::Error> for ReadlineError {
fn from(e: io::Error) -> Self {
Self::Io(e)
}
}
impl From<rustyline::error::ReadlineError> for ReadlineError {
fn from(e: rustyline::error::ReadlineError) -> Self {
use rustyline::error::ReadlineError as RustylineError;
match e {
RustylineError::Io(e) => Self::Io(e),
RustylineError::Eof => Self::Eof,
RustylineError::Interrupted => Self::Interrupted,
#[cfg(unix)]
RustylineError::Utf8Error => Self::Utf8Error,
#[cfg(unix)]
RustylineError::Errno(e) => Self::Errno(e),
#[cfg(windows)]
RustylineError::WindowResize => Self::WindowResize,
#[cfg(windows)]
RustylineError::Decode(e) => Self::Decode(e),
_ => unreachable!(),
}
}
}
impl From<rustyline::error::ReadlineError> for Error {
fn from(e: rustyline::error::ReadlineError) -> Self {
ReadlineError::from(e).into()
}
}
#[derive(Debug)]
#[allow(clippy::module_name_repetitions)]
pub enum ExecutionError {
FatalExit(Box<dyn error::Error>),
GracefulExit,
}
impl fmt::Display for ExecutionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ExecutionError::FatalExit(e) => write!(f, "{}", e),
ExecutionError::GracefulExit => write!(f, "Success"),
}
}
}
impl error::Error for ExecutionError {}
#[cfg(test)]
mod tests {
use std::io;
#[test]
fn test_readline_error_conversions() {
use super::ReadlineError;
use rustyline::error::ReadlineError as RustylineError;
#[cfg(unix)]
let io_error = io::Error::from_raw_os_error(22);
#[cfg(unix)]
let io_error_two = io::Error::from_raw_os_error(22);
#[cfg(windows)]
let io_error = io::Error::from_raw_os_error(10022);
#[cfg(windows)]
let io_error_two = io::Error::from_raw_os_error(10022);
let io_error_display = io_error.to_string();
let readline_io_error = ReadlineError::from(RustylineError::Io(io_error));
assert!(matches!(readline_io_error, ReadlineError::Io(_)));
assert_eq!(readline_io_error.to_string(), io_error_display);
let readline_io_error = ReadlineError::from(io_error_two);
assert!(matches!(readline_io_error, ReadlineError::Io(_)));
assert_eq!(readline_io_error.to_string(), io_error_display);
let error = ReadlineError::from(RustylineError::Interrupted);
assert!(matches!(error, ReadlineError::Interrupted));
assert_eq!(error.to_string(), RustylineError::Interrupted.to_string());
let error = ReadlineError::from(RustylineError::Eof);
assert!(matches!(error, ReadlineError::Eof));
assert_eq!(error.to_string(), RustylineError::Eof.to_string());
#[cfg(unix)]
if cfg!(unix) {
use nix::errno::Errno;
let error = ReadlineError::from(RustylineError::Utf8Error);
assert!(matches!(error, ReadlineError::Utf8Error));
assert_eq!(error.to_string(), RustylineError::Utf8Error.to_string());
let error = ReadlineError::from(RustylineError::Errno(nix::Error::Sys(Errno::E2BIG)));
assert!(matches!(error, ReadlineError::Errno(_)));
assert_eq!(
error.to_string(),
RustylineError::Errno(nix::Error::Sys(Errno::E2BIG)).to_string()
);
}
}
}