use std::fmt;
use std::mem;
use std::panic;
use crate::file::Span;
use crate::file::Spanned;
use crate::report::Report;
pub struct Diagnostic {
pub(super) report: Report,
pub(super) info: Info,
pub(super) speculative: bool,
}
pub use annotate_snippets::AnnotationType as Kind;
pub struct Info {
pub kind: Kind,
pub message: String,
pub snippets: Vec<Vec<(Span, String, Kind)>>,
pub notes: Vec<(String, Kind)>,
pub reported_at: Option<&'static panic::Location<'static>>,
}
impl Diagnostic {
pub(super) fn new(report: Report, kind: Kind, message: String) -> Self {
Diagnostic {
report,
speculative: false,
info: Info {
message,
kind,
snippets: Vec::new(),
notes: Vec::new(),
reported_at: None,
},
}
}
pub fn speculate(mut self) -> Self {
self.speculative = true;
self
}
pub fn commit(mut self) {
self.speculative = false;
drop(self);
}
pub fn at(self, span: impl Spanned) -> Self {
self.saying(span, "")
}
pub fn saying(self, span: impl Spanned, message: impl fmt::Display) -> Self {
self.snippet(span, message, None)
}
pub fn remark(self, span: impl Spanned, message: impl fmt::Display) -> Self {
self.snippet(span, message, Some(Kind::Help))
}
fn snippet(
mut self,
span: impl Spanned,
message: impl fmt::Display,
kind: Option<Kind>,
) -> Self {
if self.info.snippets.is_empty() {
self.info.snippets = vec![vec![]];
}
self.info.snippets.last_mut().unwrap().push((
span.span(&self.report.ctx),
message.to_string(),
kind.unwrap_or(self.info.kind),
));
self
}
pub fn new_snippet(mut self) -> Self {
self.info.snippets.push(Vec::new());
self
}
pub fn note(mut self, message: impl fmt::Display) -> Self {
let mut note = message.to_string();
note = note.replace("__", "_\u{200b}_");
self.info.notes.push((note, Kind::Note));
self
}
pub fn help(mut self, message: impl fmt::Display) -> Self {
let mut note = message.to_string();
note = note.replace("__", "_\u{200b}_");
self.info.notes.push((note, Kind::Help));
self
}
pub fn reported_at(mut self, at: &'static panic::Location<'static>) -> Self {
if self.report.state.opts.show_report_locations {
self.info.reported_at = Some(at)
}
self
}
}
impl Drop for Diagnostic {
fn drop(&mut self) {
if !self.speculative {
self.report.state.insert_diagnostic(mem::replace(
&mut self.info,
Info {
message: "".to_string(),
kind: Kind::Error,
snippets: Vec::new(),
notes: Vec::new(),
reported_at: None,
},
));
}
}
}