Skip to main content

draxl_patch/text/
error.rs

1use draxl_ast::Span;
2use draxl_parser::ParseError;
3use std::fmt;
4
5/// Error produced while parsing, resolving, or applying textual patch ops.
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct PatchTextError {
8    /// Human-readable description of the failure.
9    pub message: String,
10    /// Source span that triggered the failure.
11    pub span: Span,
12    /// One-based line number for the span start.
13    pub line: usize,
14    /// One-based column number for the span start.
15    pub column: usize,
16}
17
18impl fmt::Display for PatchTextError {
19    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20        write!(
21            f,
22            "{} at line {}, column {}",
23            self.message, self.line, self.column
24        )
25    }
26}
27
28impl std::error::Error for PatchTextError {}
29
30pub(crate) fn patch_text_error(source: &str, span: Span, message: &str) -> PatchTextError {
31    let (line, column) = line_col(source, span.start);
32    PatchTextError {
33        message: message.to_owned(),
34        span,
35        line,
36        column,
37    }
38}
39
40pub(crate) fn map_fragment_parse_error(
41    source: &str,
42    fragment_start: usize,
43    error: ParseError,
44) -> PatchTextError {
45    let span = Span {
46        start: fragment_start + error.span.start,
47        end: fragment_start + error.span.end,
48    };
49    patch_text_error(source, span, &error.message)
50}
51
52fn line_col(source: &str, offset: usize) -> (usize, usize) {
53    let mut line = 1;
54    let mut column = 1;
55    for (index, ch) in source.char_indices() {
56        if index >= offset {
57            break;
58        }
59        if ch == '\n' {
60            line += 1;
61            column = 1;
62        } else {
63            column += 1;
64        }
65    }
66    (line, column)
67}