exa/src/options/misfire.rs

139 lines
5.3 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use std::ffi::OsString;
use std::fmt;
use std::num::ParseIntError;
use crate::options::{flags, HelpString, VersionString};
use crate::options::parser::{Arg, Flag, ParseError};
/// A **misfire** is a thing that can happen instead of listing files — a
/// catch-all for anything outside the programs normal execution.
#[derive(PartialEq, Debug)]
pub enum Misfire {
/// The getopts crate didnt like these Arguments.
InvalidOptions(ParseError),
/// The user supplied an illegal choice to an Argument.
BadArgument(&'static Arg, OsString),
/// The user supplied a set of options
Unsupported(String),
/// The user asked for help. This isnt strictly an error, which is why
/// this enum isnt named Error!
Help(HelpString),
/// The user wanted the version number.
Version(VersionString),
/// An option was given twice or more in strict mode.
Duplicate(Flag, Flag),
/// Two options were given that conflict with one another.
Conflict(&'static Arg, &'static Arg),
/// An option was given that does nothing when another one either is or
/// isnt present.
Useless(&'static Arg, bool, &'static Arg),
/// An option was given that does nothing when either of two other options
/// are not present.
Useless2(&'static Arg, &'static Arg, &'static Arg),
/// A very specific edge case where --tree cant be used with --all twice.
TreeAllAll,
/// A numeric option was given that failed to be parsed as a number.
FailedParse(ParseIntError),
/// A glob ignore was given that failed to be parsed as a pattern.
FailedGlobPattern(String),
}
impl Misfire {
/// The OS return code this misfire should signify.
pub fn is_error(&self) -> bool {
! matches!(self, Self::Help(_) | Self::Version(_))
}
}
impl From<glob::PatternError> for Misfire {
fn from(error: glob::PatternError) -> Self {
Self::FailedGlobPattern(error.to_string())
}
}
impl fmt::Display for Misfire {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use crate::options::parser::TakesValue;
match self {
Self::BadArgument(arg, attempt) => {
if let TakesValue::Necessary(Some(values)) = arg.takes_value {
write!(f, "Option {} has no {:?} setting ({})", arg, attempt, Choices(values))
}
else {
write!(f, "Option {} has no {:?} setting", arg, attempt)
}
},
Self::InvalidOptions(e) => write!(f, "{}", e),
Self::Unsupported(e) => write!(f, "{}", e),
Self::Help(text) => write!(f, "{}", text),
Self::Version(version) => write!(f, "{}", version),
Self::Conflict(a, b) => write!(f, "Option {} conflicts with option {}", a, b),
Self::Duplicate(a, b) if a == b => write!(f, "Flag {} was given twice", a),
Self::Duplicate(a, b) => write!(f, "Flag {} conflicts with flag {}", a, b),
Self::Useless(a, false, b) => write!(f, "Option {} is useless without option {}", a, b),
Self::Useless(a, true, b) => write!(f, "Option {} is useless given option {}", a, b),
Self::Useless2(a, b1, b2) => write!(f, "Option {} is useless without options {} or {}", a, b1, b2),
Self::TreeAllAll => write!(f, "Option --tree is useless given --all --all"),
Self::FailedParse(ref e) => write!(f, "Failed to parse number: {}", e),
Self::FailedGlobPattern(ref e) => write!(f, "Failed to parse glob pattern: {}", e),
}
}
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::NeedsValue { flag, values: None } => write!(f, "Flag {} needs a value", flag),
Self::NeedsValue { flag, values: Some(cs) } => write!(f, "Flag {} needs a value ({})", flag, Choices(cs)),
Self::ForbiddenValue { flag } => write!(f, "Flag {} cannot take a value", flag),
Self::UnknownShortArgument { attempt } => write!(f, "Unknown argument -{}", *attempt as char),
Self::UnknownArgument { attempt } => write!(f, "Unknown argument --{}", attempt.to_string_lossy()),
}
}
}
impl Misfire {
/// Try to second-guess what the user was trying to do, depending on what
/// went wrong.
pub fn suggestion(&self) -> Option<&'static str> {
// ls -lt and ls -ltr are common combinations
match self {
Self::BadArgument(time, r) if *time == &flags::TIME && r == "r" => {
Some("To sort oldest files last, try \"--sort oldest\", or just \"-sold\"")
}
Self::InvalidOptions(ParseError::NeedsValue { ref flag, .. }) if *flag == Flag::Short(b't') => {
Some("To sort newest files last, try \"--sort newest\", or just \"-snew\"")
}
_ => {
None
}
}
}
}
/// A list of legal choices for an argument-taking option.
#[derive(PartialEq, Debug)]
pub struct Choices(&'static [&'static str]);
impl fmt::Display for Choices {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "choices: {}", self.0.join(", "))
}
}