exa/src/options/misfire.rs
Benjamin Sago a8bf990674 Tie value suggestions to their arguments
This commit changes the definition of Arg so that it knows about which values it can accept, and can display them in the help text. They were already being shown in the help text, but they were passed in separately, so one argument could show two different sets of options if it wanted. Now, the argument itself knows whether there are suggestions, so it doesn’t have to be passed in separately.

This means we can use it for other things, including listing choices when an option is missed out, without having to repeat the list.

With Misfire::BadArgument now only having two fields, it’s not worth using a constructor function anymore.
2017-09-14 01:22:37 +01:00

137 lines
5.0 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 glob;
use options::{flags, HelpString, VersionString};
use 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 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
/// isn't 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 {
match *self {
Misfire::Help(_) => false,
Misfire::Version(_) => false,
_ => true,
}
}
}
impl From<glob::PatternError> for Misfire {
fn from(error: glob::PatternError) -> Misfire {
Misfire::FailedGlobPattern(error.to_string())
}
}
impl fmt::Display for Misfire {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use options::parser::TakesValue;
use self::Misfire::*;
match *self {
BadArgument(ref arg, ref 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)
}
},
InvalidOptions(ref e) => write!(f, "{}", e),
Help(ref text) => write!(f, "{}", text),
Version(ref version) => write!(f, "{}", version),
Conflict(ref a, ref b) => write!(f, "Option {} conflicts with option {}", a, b),
Duplicate(ref a, ref b) => if a == b { write!(f, "Flag {} was given twice", a) }
else { write!(f, "Flag {} conflicts with flag {}", a, b) },
Useless(ref a, false, ref b) => write!(f, "Option {} is useless without option {}", a, b),
Useless(ref a, true, ref b) => write!(f, "Option {} is useless given option {}", a, b),
Useless2(ref a, ref b1, ref b2) => write!(f, "Option {} is useless without options {} or {}", a, b1, b2),
TreeAllAll => write!(f, "Option --tree is useless given --all --all"),
FailedParse(ref e) => write!(f, "Failed to parse number: {}", e),
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 {
use self::ParseError::*;
match *self {
NeedsValue { ref flag, values: None } => write!(f, "Flag {} needs a value", flag),
NeedsValue { ref flag, values: Some(cs) } => write!(f, "Flag {} needs a value ({})", flag, Choices(cs)),
ForbiddenValue { ref flag } => write!(f, "Flag {} cannot take a value", flag),
UnknownShortArgument { ref attempt } => write!(f, "Unknown argument -{}", *attempt as char),
UnknownArgument { ref attempt } => write!(f, "Unknown argument --{}", attempt.to_string_lossy()),
}
}
}
impl Misfire {
pub fn suggestion(&self) -> Option<&'static str> {
if let Misfire::BadArgument(ref time, ref r) = *self {
if *time == &flags::TIME && r == "r" {
return Some("To sort newest files first, try \"--sort modified\", or just \"-stime\"");
}
}
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(", "))
}
}