diff --git a/src/errors.rs b/src/errors.rs index 5ca0c36..427a343 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,5 +1,13 @@ +use std::sync::Arc; + +use annotate_snippets::AnnotationKind; +use annotate_snippets::Level; +use annotate_snippets::Renderer; +use annotate_snippets::Snippet; use thiserror::Error; +use crate::input::NomoInput; +use crate::lexer::ParseError; use crate::parser::AstError; #[derive(Debug, Error)] @@ -50,3 +58,51 @@ impl AstFailure { renderer.render(&reports) } } + +#[derive(Debug, Error)] +pub struct ParseFailure { + input: Arc, + errors: Vec, +} + +impl std::fmt::Display for ParseFailure { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(&self.to_report()) + } +} + +impl ParseFailure { + pub(crate) fn from_errors(errors: Vec, input: NomoInput) -> ParseFailure { + ParseFailure { + input: Arc::from(input.to_string()), + errors, + } + } + + pub fn to_report(&self) -> String { + let reports = self + .errors + .iter() + .map(|error| { + Level::ERROR + .primary_title( + error + .message + .as_deref() + .unwrap_or("An error occurred while parsing"), + ) + .element( + Snippet::source(self.input.as_ref()).annotation( + AnnotationKind::Primary + .span(error.span.clone().map(|s| s.range).unwrap_or_else(|| 0..0)), + ), + ) + .elements(error.help.as_ref().map(|help| Level::HELP.message(help))) + }) + .collect::>(); + + let renderer = + Renderer::styled().decor_style(annotate_snippets::renderer::DecorStyle::Unicode); + renderer.render(&reports) + } +} diff --git a/src/lexer/mod.rs b/src/lexer/mod.rs index 277f3e3..65872b7 100644 --- a/src/lexer/mod.rs +++ b/src/lexer/mod.rs @@ -39,60 +39,13 @@ use winnow::token::take_until; use winnow::token::take_while; use crate::SourceSpan; +use crate::errors::ParseFailure; use crate::input::NomoInput; use crate::resume_after_cut; type Input<'input> = Recoverable, ParseError>; type PResult<'input, T> = Result; -#[derive(Debug, Error)] -pub struct ParseFailure { - input: Arc, - errors: Vec, -} - -impl std::fmt::Display for ParseFailure { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(&self.to_report()) - } -} - -impl ParseFailure { - fn from_errors(errors: Vec, input: NomoInput) -> ParseFailure { - ParseFailure { - input: Arc::from(input.to_string()), - errors, - } - } - - pub fn to_report(&self) -> String { - let reports = self - .errors - .iter() - .map(|error| { - Level::ERROR - .primary_title( - error - .message - .as_deref() - .unwrap_or("An error occurred while parsing"), - ) - .element( - Snippet::source(self.input.as_ref()).annotation( - AnnotationKind::Primary - .span(error.span.clone().map(|s| s.range).unwrap_or_else(|| 0..0)), - ), - ) - .elements(error.help.as_ref().map(|help| Level::HELP.message(help))) - }) - .collect::>(); - - let renderer = - Renderer::styled().decor_style(annotate_snippets::renderer::DecorStyle::Unicode); - renderer.render(&reports) - } -} - #[derive(Debug, Clone)] pub struct ParseError { pub(crate) message: Option, diff --git a/src/lib.rs b/src/lib.rs index 685fbb8..8d970d7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,7 +26,7 @@ feature = "document-features", cfg_attr(doc, doc = ::document_features::document_features!()) )] -//! +//! use std::collections::HashMap; @@ -84,7 +84,7 @@ pub enum NomoError { ParseError { #[from] #[expect(missing_docs)] - source: lexer::ParseFailure, + source: errors::ParseFailure, }, /// Invalid Template AstError {