kanata_parser/cfg/
error.rs

1use miette::{Diagnostic, NamedSource, SourceSpan};
2use thiserror::Error;
3
4use super::{sexpr::Span, *};
5
6pub type MResult<T> = miette::Result<T>;
7pub type Result<T> = std::result::Result<T, ParseError>;
8
9#[derive(Debug, Clone)]
10pub struct ParseError {
11    pub msg: String,
12    pub span: Option<Span>,
13}
14
15impl ParseError {
16    pub fn new(span: Span, err_msg: impl AsRef<str>) -> Self {
17        Self {
18            msg: err_msg.as_ref().to_string(),
19            span: Some(span),
20        }
21    }
22
23    pub fn new_without_span(err_msg: impl AsRef<str>) -> Self {
24        Self {
25            msg: err_msg.as_ref().to_string(),
26            span: None,
27        }
28    }
29
30    pub fn from_expr(expr: &sexpr::SExpr, err_msg: impl AsRef<str>) -> Self {
31        Self::new(expr.span(), err_msg)
32    }
33
34    pub fn from_spanned<T>(spanned: &Spanned<T>, err_msg: impl AsRef<str>) -> Self {
35        Self::new(spanned.span.clone(), err_msg)
36    }
37}
38
39impl From<anyhow::Error> for ParseError {
40    fn from(value: anyhow::Error) -> Self {
41        Self::new_without_span(value.to_string())
42    }
43}
44
45impl From<ParseError> for miette::Error {
46    fn from(val: ParseError) -> Self {
47        let diagnostic = CfgError {
48            err_span: val
49                .span
50                .as_ref()
51                .map(|s| SourceSpan::new(s.start().into(), (s.end() - s.start()).into())),
52            help_msg: help(val.msg),
53            file_name: val.span.as_ref().map(|s| s.file_name()),
54            file_content: val.span.as_ref().map(|s| s.file_content()),
55        };
56
57        let report: miette::Error = diagnostic.into();
58
59        if let Some(span) = val.span {
60            report.with_source_code(NamedSource::new(span.file_name(), span.file_content()))
61        } else {
62            report
63        }
64    }
65}
66
67#[derive(Error, Debug, Diagnostic, Clone)]
68#[error("Error in configuration")]
69#[diagnostic()]
70struct CfgError {
71    // Snippets and highlights can be included in the diagnostic!
72    #[label("Error here")]
73    err_span: Option<SourceSpan>,
74    #[help]
75    help_msg: String,
76    file_name: Option<String>,
77    file_content: Option<String>,
78}
79
80pub(super) fn help(err_msg: impl AsRef<str>) -> String {
81    format!(
82        r"{}
83
84For more info, see the configuration guide:
85https://github.com/jtroo/kanata/blob/main/docs/config.adoc",
86        err_msg.as_ref(),
87    )
88}