1use std::{collections::HashMap, path::PathBuf, str::Utf8Error};
20
21use ariadne::{ColorGenerator, Fmt, Label, ReportBuilder, Source};
22use lsp_types::Url;
23use thiserror::Error;
24
25#[derive(Error, Clone, Debug, PartialEq, Eq)]
33pub enum ParseError {
34 #[error("{error:?}")]
35 LexerError {
36 range: lsp_types::Range,
37 #[source]
38 error: LexerError,
39 },
40 #[error("{error:?}")]
41 AstError {
42 range: lsp_types::Range,
43 #[source]
44 error: AstError,
45 },
46}
47
48impl From<ParseError> for lsp_types::Diagnostic {
49 fn from(error: ParseError) -> Self {
50 (&error).into()
51 }
52}
53
54impl From<&ParseError> for lsp_types::Diagnostic {
55 fn from(error: &ParseError) -> Self {
56 let (range, message) = match error {
57 ParseError::AstError { range, error } => (*range, error.to_string()),
58 ParseError::LexerError { range, error } => (*range, error.to_string()),
59 };
60 lsp_types::Diagnostic {
61 range,
62 severity: Some(lsp_types::DiagnosticSeverity::ERROR),
63 message,
64 code: Some(lsp_types::NumberOrString::String("AUTO_LSP".into())),
65 ..Default::default()
66 }
67 }
68}
69
70impl ParseError {
71 pub fn to_label(
73 &self,
74 source: &Source<&str>,
75 colors: &mut ColorGenerator,
76 report: &mut ReportBuilder<'_, std::ops::Range<usize>>,
77 ) {
78 let range = match self {
79 ParseError::LexerError { range, .. } => range,
80 ParseError::AstError { range, .. } => range,
81 };
82 let start_line = source.line(range.start.line as usize).unwrap().offset();
83 let end_line = source.line(range.end.line as usize).unwrap().offset();
84 let start = start_line + range.start.character as usize;
85 let end = end_line + range.end.character as usize;
86 let curr_color = colors.next();
87
88 report.add_label(
89 Label::new(start..end)
90 .with_message(format!("{}", self.to_string().fg(curr_color)))
91 .with_color(curr_color),
92 );
93 }
94}
95
96#[derive(Error, Clone, Debug, PartialEq, Eq)]
98pub enum AstError {
99 #[error("Unexpected {symbol:?} in {parent_name:?}")]
100 UnexpectedSymbol {
101 range: tree_sitter::Range,
102 symbol: &'static str,
103 parent_name: &'static str,
104 },
105}
106
107impl From<AstError> for ParseError {
108 fn from(error: AstError) -> Self {
109 let range = match &error {
110 AstError::UnexpectedSymbol { range, .. } => lsp_types::Range {
111 start: lsp_types::Position {
112 line: range.start_point.row as u32,
113 character: range.start_point.column as u32,
114 },
115 end: lsp_types::Position {
116 line: range.end_point.row as u32,
117 character: range.end_point.column as u32,
118 },
119 },
120 };
121 Self::AstError { range, error }
122 }
123}
124
125#[derive(Error, Clone, Debug, PartialEq, Eq)]
129pub enum LexerError {
130 #[error("{error:?}")]
131 Missing {
132 range: lsp_types::Range,
133 error: String,
134 },
135 #[error("{error:?}")]
136 Syntax {
137 range: lsp_types::Range,
138 error: String,
139 },
140}
141
142impl From<LexerError> for ParseError {
143 fn from(error: LexerError) -> Self {
144 let range = match &error {
145 LexerError::Missing { range, .. } => *range,
146 LexerError::Syntax { range, .. } => *range,
147 };
148 Self::LexerError { range, error }
149 }
150}
151
152#[derive(Debug)]
156#[salsa::accumulator]
157pub struct ParseErrorAccumulator(pub ParseError);
158
159impl ParseErrorAccumulator {
160 pub fn to_label(
161 &self,
162 source: &Source<&str>,
163 colors: &mut ColorGenerator,
164 report: &mut ReportBuilder<'_, std::ops::Range<usize>>,
165 ) {
166 self.0.to_label(source, colors, report);
167 }
168}
169
170impl From<&ParseErrorAccumulator> for lsp_types::Diagnostic {
171 fn from(error: &ParseErrorAccumulator) -> Self {
172 Self::from(&error.0)
173 }
174}
175
176impl From<&ParseError> for ParseErrorAccumulator {
177 fn from(diagnostic: &ParseError) -> Self {
178 Self(diagnostic.clone())
179 }
180}
181
182impl From<ParseError> for ParseErrorAccumulator {
183 fn from(diagnostic: ParseError) -> Self {
184 Self(diagnostic)
185 }
186}
187
188impl From<&ParseErrorAccumulator> for ParseError {
189 fn from(diagnostic: &ParseErrorAccumulator) -> Self {
190 diagnostic.0.clone()
191 }
192}
193
194impl From<LexerError> for ParseErrorAccumulator {
195 fn from(error: LexerError) -> Self {
196 Self(error.into())
197 }
198}
199
200impl From<AstError> for ParseErrorAccumulator {
201 fn from(error: AstError) -> Self {
202 Self(ParseError::from(error))
203 }
204}
205
206#[derive(Error, Clone, Debug, PartialEq, Eq)]
210pub enum PositionError {
211 #[error("Failed to find position of offset {offset:?}, max line length is {length:?}")]
212 LineOutOfBound { offset: usize, length: usize },
213 #[error("Failed to get position of offset {offset:?}")]
214 WrongPosition { offset: usize },
215 #[error("Failed to get range of {range:?}: {position_error:?}")]
216 WrongRange {
217 range: std::ops::Range<usize>,
218 #[source]
219 position_error: Box<PositionError>,
220 },
221 #[error("Failed to get text in {range:?}")]
222 WrongTextRange { range: std::ops::Range<usize> },
223 #[error("Failed to get text in {range:?}: Encountered UTF-8 error {utf8_error:?}")]
224 UTF8Error {
225 range: std::ops::Range<usize>,
226 utf8_error: Utf8Error,
227 },
228}
229
230#[derive(Error, Clone, Debug, PartialEq, Eq)]
232pub enum RuntimeError {
233 #[error("Document error in {uri:?}: {error:?}")]
234 DocumentError {
235 uri: Url,
236 #[source]
237 error: DocumentError,
238 },
239 #[error("Missing initialization options from client")]
240 MissingOptions,
241 #[error("Missing perFileParser object from initialization options")]
242 MissingPerFileParser,
243 #[error(transparent)]
244 DataBaseError(#[from] DataBaseError),
245 #[error(transparent)]
246 FileSystemError(#[from] FileSystemError),
247 #[error(transparent)]
248 ExtensionError(#[from] ExtensionError),
249}
250
251impl From<(&Url, DocumentError)> for RuntimeError {
252 fn from((uri, error): (&Url, DocumentError)) -> Self {
253 RuntimeError::DocumentError {
254 uri: uri.clone(),
255 error,
256 }
257 }
258}
259
260impl From<(&Url, TreeSitterError)> for RuntimeError {
261 fn from((uri, error): (&Url, TreeSitterError)) -> Self {
262 RuntimeError::DocumentError {
263 uri: uri.clone(),
264 error: DocumentError::TreeSitter(error),
265 }
266 }
267}
268
269impl From<(&Url, TexterError)> for RuntimeError {
270 fn from((uri, error): (&Url, TexterError)) -> Self {
271 RuntimeError::DocumentError {
272 uri: uri.clone(),
273 error: DocumentError::Texter(error),
274 }
275 }
276}
277
278#[derive(Error, Clone, Debug, PartialEq, Eq)]
280pub enum FileSystemError {
281 #[cfg(windows)]
282 #[error("Invalid host '{host:?}' for file path: {path:?}")]
283 FileUrlHost { host: String, path: Url },
284 #[error("Failed to convert url {path:?} to file path")]
285 FileUrlToFilePath { path: Url },
286 #[error("Failed to convert file path {path:?} to url")]
287 FilePathToUrl { path: PathBuf },
288 #[error("Failed to get extension of file {path:?}")]
289 FileExtension { path: Url },
290 #[error("Failed to open file {path:?}: {error:?}")]
291 FileOpen { path: Url, error: String },
292 #[error("Failed to read file {path:?}: {error:?}")]
293 FileRead { path: Url, error: String },
294 #[error(transparent)]
295 ExtensionError(#[from] ExtensionError),
296}
297
298#[derive(Error, Clone, Debug, PartialEq, Eq)]
300pub enum ExtensionError {
301 #[error("Unknown file extension {extension:?}, available extensions are: {available:?}")]
302 UnknownExtension {
303 extension: String,
304 available: HashMap<String, String>,
305 },
306 #[error("No parser found for extension {extension:?}, available parsers are: {available:?}")]
307 UnknownParser {
308 extension: String,
309 available: Vec<&'static str>,
310 },
311}
312
313#[derive(Error, Clone, Debug, PartialEq, Eq)]
315pub enum DataBaseError {
316 #[error("Failed to get file {uri:?}")]
317 FileNotFound { uri: Url },
318 #[error("File {uri:?} already exists")]
319 FileAlreadyExists { uri: Url },
320 #[error("Document error in {uri:?}: {error:?}")]
321 DocumentError {
322 uri: Url,
323 #[source]
324 error: DocumentError,
325 },
326}
327
328impl From<(&Url, DocumentError)> for DataBaseError {
329 fn from((uri, error): (&Url, DocumentError)) -> Self {
330 DataBaseError::DocumentError {
331 uri: uri.clone(),
332 error,
333 }
334 }
335}
336
337impl From<(&Url, TreeSitterError)> for DataBaseError {
338 fn from((uri, error): (&Url, TreeSitterError)) -> Self {
339 DataBaseError::DocumentError {
340 uri: uri.clone(),
341 error: DocumentError::TreeSitter(error),
342 }
343 }
344}
345
346#[derive(Error, Clone, Debug, PartialEq, Eq)]
350pub enum DocumentError {
351 #[error(transparent)]
352 TreeSitter(#[from] TreeSitterError),
353 #[error(transparent)]
354 Texter(#[from] TexterError),
355}
356
357#[derive(Error, Clone, Debug, PartialEq, Eq)]
358pub enum TreeSitterError {
359 #[error("Tree sitter failed to parse tree")]
360 TreeSitterParser,
361}
362
363#[derive(Error, Clone, Debug, PartialEq, Eq)]
364pub enum TexterError {
365 #[error("Texter failed to handle document")]
366 TexterError(#[from] texter::error::Error),
367}