summaryrefslogtreecommitdiffstats
path: root/src/options/misfire.rs
blob: 1ee437d435a3ab883511b02927515debab5b3ef8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use std::fmt;
use std::num::ParseIntError;

use getopts;
use glob;


/// A list of legal choices for an argument-taking option
#[derive(PartialEq, Debug)]
pub struct Choices(Vec<&'static str>);

impl fmt::Display for Choices {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "(choices: {})", self.0.join(" "))
    }
}

/// A **misfire** is a thing that can happen instead of listing files -- a
/// catch-all for anything outside the program’s normal execution.
#[derive(PartialEq, Debug)]
pub enum Misfire {

    /// The getopts crate didn’t like these arguments.
    InvalidOptions(getopts::Fail),

    /// The user supplied an illegal choice to an argument
    BadArgument(getopts::Fail, Choices),

    /// The user asked for help. This isn’t strictly an error, which is why
    /// this enum isn’t named Error!
    Help(String),

    /// The user wanted the version number.
    Version,

    /// Two options were given that conflict with one another.
    Conflict(&'static str, &'static str),

    /// An option was given that does nothing when another one either is or
    /// isn't present.
    Useless(&'static str, bool, &'static str),

    /// An option was given that does nothing when either of two other options
    /// are not present.
    Useless2(&'static str, &'static str, &'static str),

    /// 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 error_code(&self) -> i32 {
        if let Misfire::Help(_) = *self { 2 }
                                   else { 3 }
    }

    /// The Misfire that happens when an option gets given the wrong
    /// argument. This has to use one of the `getopts` failure
    /// variants--it’s meant to take just an option name, rather than an
    /// option *and* an argument, but it works just as well.
    pub fn bad_argument(option: &str, otherwise: &str, legal: &[&'static str]) -> Misfire {
        Misfire::BadArgument(getopts::Fail::UnrecognizedOption(format!(
            "--{} {}",
            option, otherwise)), Choices(legal.into()))
    }
}

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 self::Misfire::*;

        match *self {
            InvalidOptions(ref e)      => write!(f, "{}", e),
            BadArgument(ref e, ref c)  => write!(f, "{} {}", e, c),
            Help(ref text)             => write!(f, "{}", text),
            Version                    => write!(f, "exa {}", env!("CARGO_PKG_VERSION")),
            Conflict(a, b)             => write!(f, "Option --{} conflicts with option {}.", a, b),
            Useless(a, false, b)       => write!(f, "Option --{} is useless without option --{}.", a, b),
            Useless(a, true, b)        => write!(f, "Option --{} is useless given option --{}.", a, b),
            Useless2(a, b1, b2)        => write!(f, "Option --{} is useless without options --{} or --{}.", a, b1, b2),
            FailedParse(ref e)         => write!(f, "Failed to parse number: {}", e),
            FailedGlobPattern(ref e)   => write!(f, "Failed to parse glob pattern: {}", e),
        }
    }
}