ragit_cli/
error.rs

1use crate::{ArgCount, ArgType};
2use crate::span::{RenderedSpan, Span};
3
4pub struct Error {
5    pub span: Option<RenderedSpan>,
6    pub kind: ErrorKind,
7}
8
9pub struct RawError {
10    pub span: Span,
11    pub kind: ErrorKind,
12}
13
14pub enum ErrorKind {
15    /// see <https://doc.rust-lang.org/stable/std/num/struct.ParseIntError.html>
16    ParseIntError(std::num::ParseIntError),
17
18    /// see <https://doc.rust-lang.org/stable/std/num/struct.ParseFloatError.html>
19    ParseFloatError(std::num::ParseFloatError),
20
21    ParseFileSizeError,
22    NumberNotInRange {
23        min: Option<String>,
24        max: Option<String>,
25        n: String,
26    },
27
28    /// (prev_flag, curr_flag)
29    SameFlagMultipleTimes(String, String),
30
31    /// of an arg_flag
32    MissingArgument(String, ArgType),
33
34    WrongArgCount {
35        expected: ArgCount,
36        got: usize,
37    },
38    MissingFlag(String),
39    UnknownFlag {
40        flag: String,
41        similar_flag: Option<String>,
42    },
43    UnknownVariant {
44        variant: String,
45        similar_variant: Option<String>,
46    },
47}
48
49impl ErrorKind {
50    pub fn render(&self) -> String {
51        match self {
52            ErrorKind::ParseIntError(_) => String::from("Cannot parse int."),
53            ErrorKind::ParseFloatError(_) => String::from("Cannot parse float."),
54            ErrorKind::ParseFileSizeError => String::from("Cannot parse file size."),
55            ErrorKind::NumberNotInRange { min, max, n } => match (min, max) {
56                (Some(min), Some(max)) => format!("N is supposed to be between {min} and {max}, but is {n}."),
57                (Some(min), None) => format!("N is supposed to be at least {min}, but is {n}."),
58                (None, Some(max)) => format!("N is supposed to be at most {max}, but is {n}."),
59                (None, None) => unreachable!(),
60            },
61            ErrorKind::SameFlagMultipleTimes(prev, next) => if prev == next {
62                format!("Flag `{next}` cannot be used multiple times.")
63            } else {
64                format!("Flag `{prev}` and `{next}` cannot be used together.")
65            },
66            ErrorKind::MissingArgument(arg, arg_type) => format!(
67                "A {} value is required for flag `{arg}`, but is missing.",
68                format!("{arg_type:?}").to_ascii_lowercase(),
69            ),
70            ErrorKind::WrongArgCount { expected, got } => format!(
71                "Expected {} arguments, got {got} arguments",
72                match expected {
73                    ArgCount::Exact(n) => format!("exactly {n}"),
74                    ArgCount::Geq(n) => format!("at least {n}"),
75                    ArgCount::Leq(n) => format!("at most {n}"),
76                    ArgCount::None => String::from("no"),
77                    ArgCount::Any => unreachable!(),
78                },
79            ),
80            ErrorKind::MissingFlag(flag) => format!("Flag `{flag}` is missing."),
81            ErrorKind::UnknownFlag { flag, similar_flag } => format!(
82                "Unknown flag: `{flag}`.{}",
83                if let Some(flag) = similar_flag {
84                    format!(" There is a similar flag: `{flag}`.")
85                } else {
86                    String::new()
87                },
88            ),
89            ErrorKind::UnknownVariant { variant, similar_variant } => format!(
90                "Unknown variant: `{variant}`.{}",
91                if let Some(variant) = similar_variant {
92                    format!(" There is a similar variant: `{variant}`.")
93                } else {
94                    String::new()
95                },
96            ),
97        }
98    }
99}