use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Severity {
Error,
Warning,
}
impl fmt::Display for Severity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Severity::Error => f.write_str("error"),
Severity::Warning => f.write_str("warning"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Diagnostic {
pub rule: &'static str,
pub severity: Severity,
pub message: String,
pub pos: Option<(u32, u32)>,
pub file: Option<String>,
}
impl Diagnostic {
pub fn new(
rule: &'static str,
severity: Severity,
pos: Option<(u32, u32)>,
message: impl Into<String>,
) -> Self {
Self {
rule,
severity,
message: message.into(),
pos,
file: None,
}
}
pub fn in_file(mut self, file: Option<String>) -> Self {
self.file = file;
self
}
pub fn error(rule: &'static str, pos: Option<(u32, u32)>, message: impl Into<String>) -> Self {
Self::new(rule, Severity::Error, pos, message)
}
pub fn warning(
rule: &'static str,
pos: Option<(u32, u32)>,
message: impl Into<String>,
) -> Self {
Self::new(rule, Severity::Warning, pos, message)
}
pub fn line(&self) -> Option<u32> {
self.pos.map(|(line, _)| line)
}
pub fn column(&self) -> Option<u32> {
self.pos.map(|(_, col)| col)
}
}
impl fmt::Display for Diagnostic {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let sev = self.severity;
let rule = self.rule;
let msg = &self.message;
match (&self.file, self.pos) {
(None, Some((line, col))) => write!(f, "{sev} [{rule}] {line}:{col}: {msg}"),
(None, None) => write!(f, "{sev} [{rule}]: {msg}"),
(Some(path), Some((line, col))) => {
write!(f, "{sev} [{rule}] {path}:{line}:{col}: {msg}")
}
(Some(path), None) => write!(f, "{sev} [{rule}] {path}: {msg}"),
}
}
}