winnow_parse_error/
lib.rs

1use std::{error::Error, fmt::Display};
2use winnow::error::ContextError;
3
4#[derive(Debug, PartialEq, Eq)]
5pub struct ParseError {
6    message: String,
7    span: std::ops::Range<usize>,
8    input: String,
9}
10
11impl ParseError {
12    // Avoiding `From` so `winnow` types don't become part of our public API
13    pub fn from_parse(error: winnow::error::ParseError<&str, ContextError>) -> Self {
14        let message = error.inner().to_string();
15        let input = (*error.input()).to_owned();
16        let span = error.char_span();
17        Self {
18            message,
19            span,
20            input,
21        }
22    }
23}
24
25impl Display for ParseError {
26    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27        let message = annotate_snippets::Level::Error
28            .title(&self.message)
29            .snippet(
30                annotate_snippets::Snippet::source(&self.input)
31                    .fold(true)
32                    .annotation(annotate_snippets::Level::Error.span(self.span.clone())),
33            );
34        let renderer = annotate_snippets::Renderer::plain();
35        let rendered = renderer.render(message);
36        rendered.fmt(f)
37    }
38}
39
40impl Error for ParseError {}
41
42#[cfg(test)]
43mod tests {
44    use super::*;
45    use pretty_assertions::assert_eq;
46
47    // TODO
48}