okane_core/report/
error.rs1use std::{fmt::Display, path::PathBuf};
4
5use annotate_snippets::{Annotation, Level, Snippet};
6use bumpalo::Bump;
7
8use crate::{
9 load,
10 parse::{self, ParsedSpan},
11};
12
13use super::{
14 book_keeping::{self, BookKeepError},
15 price_db,
16};
17
18#[derive(thiserror::Error, Debug)]
20pub enum ReportError {
21 Load(#[from] load::LoadError),
22 PriceDB(#[from] price_db::LoadError),
23 BookKeep(book_keeping::BookKeepError, Box<ErrorContext>),
24}
25
26impl Display for ReportError {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 match self {
29 ReportError::Load(_) => write!(f, "failed to load the given file"),
30 ReportError::PriceDB(_) => write!(f, "failed to load the Price DB"),
31 ReportError::BookKeep(err, ctx) => ctx.print(f, err),
32 }
33 }
34}
35
36#[derive(Debug)]
38pub struct ErrorContext {
39 renderer: annotate_snippets::Renderer,
40 path: PathBuf,
41 line_start: usize,
42 text: String,
43 parsed_span: ParsedSpan,
44}
45
46impl ErrorContext {
47 fn print(&self, f: &mut std::fmt::Formatter<'_>, err: &BookKeepError) -> std::fmt::Result {
48 let message = err.to_string();
49 let path = self.path.to_string_lossy();
50 let bump = Bump::new();
51 let annotations: Vec<Annotation> = err.annotations(&bump, &self.parsed_span, &self.text);
52 let message = Level::ERROR.primary_title(&message).element(
53 Snippet::source(&self.text)
54 .path(&path)
55 .line_start(self.line_start)
56 .fold(false)
57 .annotations(annotations),
58 );
59 let rendered = self.renderer.render(&[message]);
60 rendered.fmt(f)
61 }
62
63 pub(super) fn new(
64 renderer: annotate_snippets::Renderer,
65 path: PathBuf,
66 pctx: &parse::ParsedContext,
67 ) -> Box<Self> {
68 Box::new(Self {
69 renderer,
70 path,
71 line_start: pctx.compute_line_start(),
72 text: pctx.as_str().to_owned(),
73 parsed_span: pctx.span(),
74 })
75 }
76}