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
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
use lliw::Fg::Red;
use lliw::Reset;
use std::fmt::{Display, Formatter};
use std::num::ParseIntError;

/// Simple macro rapper for `Result::Ok(T)`
#[macro_export]
macro_rules! pass {
    () => {
        Ok(())
    };
    ($item:expr) => {{
        Ok($item)
    }};
}

/// Macro to throw an error, `Result::Err(e)`
#[macro_export]
macro_rules! throw {
    ($kind:expr, $fmt:literal) => ({
        return $crate::error::_throw($kind, std::format!($fmt))
    });
    ($kind:expr, $fmt:literal, $($arg:tt)*) => ({
        return $crate::error::_throw($kind, std::format!($fmt, $($arg)*))
    })
}

#[doc(hidden)]
pub fn _throw<T>(kind: Kind, inner: String) -> Result<T, Error> {
    Err(Error::new(kind, inner))
}

/// Error type
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct Error {
    inner: String,
    // file: Option<String>,
    kind: Kind,
}

impl Error {
    #[must_use]
    /// creates new instance of `Error`
    pub fn new(kind: Kind, inner: String) -> Error {
        Error { inner, kind }
    }

    #[must_use]
    /// returns Error kind
    pub fn kind(&self) -> Kind {
        self.kind
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}{}: {}{}", Red, self.kind, Reset, self.inner)
    }
}

impl From<ParseIntError> for Error {
    fn from(pie: ParseIntError) -> Self {
        Error::new(Kind::VersionParse, pie.to_string())
    }
}

impl From<toml::de::Error> for Error {
    fn from(te: toml::de::Error) -> Self {
        Error::new(Kind::ConfigParse, te.to_string())
    }
}

impl From<jargon_args::Error> for Error {
    fn from(jae: jargon_args::Error) -> Self {
        match jae {
            jargon_args::Error::MissingArg(key) => {
                Error::new(Kind::ArgumentMissing, key.to_string())
            }
            jargon_args::Error::Other(s) => Error::new(Kind::JargonInternal, s),
        }
    }
}

impl std::error::Error for Error {}

/// Error Kinds
#[repr(i32)]
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub enum Kind {
    /// for when something weird happens in the program
    Internal = 1,
    /// for when environment variables can't be read
    Environment,
    /// for when the config file fails to be opened
    ConfigOpen,
    /// for when the config file fails to be read
    ConfigRead,
    /// for when Toml fails to parse config
    ConfigParse,
    /// Pfor when creating a Proton directory fails
    ProtonDir,
    /// for when Proton fails to spawn
    ProtonSpawn,
    /// for when waiting for child process fails
    ProtonWait,
    /// for when Proton is not found
    ProtonMissing,
    /// for when requested program is not found
    ProgramMissing,
    /// for when Indexing fails to read common directory
    IndexReadDir,
    /// for when parsing a version number fails
    VersionParse,
    /// for when Proton exits with an error
    ProtonExit,
    /// for when a command line argument is missing
    ArgumentMissing,
    /// for when Jargon has an internal Error,
    JargonInternal,
}

impl Display for Kind {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}",
            match self {
                Kind::Internal => "internal error",
                Kind::Environment => "failed to read environment",
                Kind::ConfigOpen => "failed to open config",
                Kind::ConfigRead => "failed to read config",
                Kind::ConfigParse => "failed to parse config",
                Kind::ProtonDir => "failed to create Proton directory",
                Kind::ProtonSpawn => "failed to spawn Proton",
                Kind::ProtonWait => "failed to wait for Proton child",
                Kind::IndexReadDir => "failed to Index",
                Kind::VersionParse => "failed to parse version",
                Kind::ProtonMissing => "cannot find Proton",
                Kind::ProgramMissing => "cannot find program",
                Kind::ProtonExit => "proton exited with",
                Kind::ArgumentMissing => "missing command line argument",
                Kind::JargonInternal => "jargon args internal error",
            }
        )
    }
}