typos_cli/
report.rs

1#![allow(clippy::needless_update)]
2
3use std::borrow::Cow;
4
5pub trait Report: Send + Sync {
6    fn report(&self, msg: Message<'_>) -> Result<(), std::io::Error>;
7
8    fn generate_final_result(&self) -> Result<(), std::io::Error> {
9        Ok(())
10    }
11}
12
13#[derive(Clone, Debug, serde::Serialize, derive_more::From)]
14#[serde(rename_all = "snake_case")]
15#[serde(tag = "type")]
16#[non_exhaustive]
17pub enum Message<'m> {
18    BinaryFile(BinaryFile<'m>),
19    Typo(Typo<'m>),
20    FileType(FileType<'m>),
21    File(File<'m>),
22    Parse(Parse<'m>),
23    Error(Error<'m>),
24}
25
26impl<'m> Message<'m> {
27    pub fn is_typo(&self) -> bool {
28        match self {
29            Message::BinaryFile(_) => false,
30            Message::Typo(c) => !c.corrections.is_valid(),
31            Message::FileType(_) => false,
32            Message::File(_) => false,
33            Message::Parse(_) => false,
34            Message::Error(_) => false,
35        }
36    }
37
38    pub fn is_error(&self) -> bool {
39        match self {
40            Message::BinaryFile(_) => false,
41            Message::Typo(_) => false,
42            Message::FileType(_) => false,
43            Message::File(_) => false,
44            Message::Parse(_) => false,
45            Message::Error(_) => true,
46        }
47    }
48
49    pub fn context(self, context: Option<Context<'m>>) -> Self {
50        match self {
51            Message::Typo(typo) => {
52                let typo = typo.context(context);
53                Message::Typo(typo)
54            }
55            Message::Parse(parse) => {
56                let parse = parse.context(context);
57                Message::Parse(parse)
58            }
59            Message::Error(error) => {
60                let error = error.context(context);
61                Message::Error(error)
62            }
63            _ => self,
64        }
65    }
66}
67
68#[derive(Clone, Debug, serde::Serialize, derive_more::Display, derive_setters::Setters)]
69#[display("Skipping binary file {}", path.display())]
70#[non_exhaustive]
71pub struct BinaryFile<'m> {
72    pub path: &'m std::path::Path,
73}
74
75#[derive(Clone, Debug, serde::Serialize, derive_setters::Setters)]
76#[non_exhaustive]
77pub struct Typo<'m> {
78    #[serde(flatten)]
79    pub context: Option<Context<'m>>,
80    #[serde(skip)]
81    pub buffer: Cow<'m, [u8]>,
82    pub byte_offset: usize,
83    pub typo: &'m str,
84    pub corrections: typos::Status<'m>,
85}
86
87impl Default for Typo<'_> {
88    fn default() -> Self {
89        Self {
90            context: None,
91            buffer: Cow::Borrowed(&[]),
92            byte_offset: 0,
93            typo: "",
94            corrections: typos::Status::Invalid,
95        }
96    }
97}
98
99#[derive(Clone, Debug, serde::Serialize, derive_more::From)]
100#[serde(untagged)]
101#[non_exhaustive]
102pub enum Context<'m> {
103    File(FileContext<'m>),
104    Path(PathContext<'m>),
105}
106
107impl std::fmt::Display for Context<'_> {
108    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
109        match self {
110            Context::File(c) => write!(f, "{}:{}", c.path.display(), c.line_num),
111            Context::Path(c) => write!(f, "{}", c.path.display()),
112        }
113    }
114}
115
116#[derive(Clone, Debug, serde::Serialize, derive_setters::Setters)]
117#[non_exhaustive]
118pub struct FileContext<'m> {
119    pub path: &'m std::path::Path,
120    pub line_num: usize,
121}
122
123impl Default for FileContext<'_> {
124    fn default() -> Self {
125        Self {
126            path: std::path::Path::new("-"),
127            line_num: 0,
128        }
129    }
130}
131
132#[derive(Clone, Debug, serde::Serialize, derive_setters::Setters)]
133#[non_exhaustive]
134pub struct PathContext<'m> {
135    pub path: &'m std::path::Path,
136}
137
138impl Default for PathContext<'_> {
139    fn default() -> Self {
140        Self {
141            path: std::path::Path::new("-"),
142        }
143    }
144}
145
146#[derive(Copy, Clone, Debug, serde::Serialize)]
147#[serde(rename_all = "snake_case")]
148#[non_exhaustive]
149pub enum ParseKind {
150    Identifier,
151    Word,
152}
153
154#[derive(Clone, Debug, serde::Serialize, derive_setters::Setters)]
155#[non_exhaustive]
156pub struct FileType<'m> {
157    pub path: &'m std::path::Path,
158    pub file_type: Option<&'m str>,
159}
160
161impl<'m> FileType<'m> {
162    pub fn new(path: &'m std::path::Path, file_type: Option<&'m str>) -> Self {
163        Self { path, file_type }
164    }
165}
166
167impl Default for FileType<'_> {
168    fn default() -> Self {
169        Self {
170            path: std::path::Path::new("-"),
171            file_type: None,
172        }
173    }
174}
175
176#[derive(Clone, Debug, serde::Serialize, derive_setters::Setters)]
177#[non_exhaustive]
178pub struct File<'m> {
179    pub path: &'m std::path::Path,
180}
181
182impl<'m> File<'m> {
183    pub fn new(path: &'m std::path::Path) -> Self {
184        Self { path }
185    }
186}
187
188impl Default for File<'_> {
189    fn default() -> Self {
190        Self {
191            path: std::path::Path::new("-"),
192        }
193    }
194}
195
196#[derive(Clone, Debug, serde::Serialize, derive_setters::Setters)]
197#[non_exhaustive]
198pub struct Parse<'m> {
199    #[serde(flatten)]
200    pub context: Option<Context<'m>>,
201    pub kind: ParseKind,
202    pub data: &'m str,
203}
204
205impl Default for Parse<'_> {
206    fn default() -> Self {
207        Self {
208            context: None,
209            kind: ParseKind::Identifier,
210            data: "",
211        }
212    }
213}
214
215#[derive(Clone, Debug, serde::Serialize, derive_setters::Setters)]
216#[non_exhaustive]
217pub struct Error<'m> {
218    #[serde(flatten)]
219    pub context: Option<Context<'m>>,
220    pub msg: String,
221}
222
223impl Error<'_> {
224    pub fn new(msg: String) -> Self {
225        Self { context: None, msg }
226    }
227}
228
229impl Default for Error<'_> {
230    fn default() -> Self {
231        Self {
232            context: None,
233            msg: "".to_owned(),
234        }
235    }
236}