mod compact;
mod diagnostic;
mod formatter;
#[cfg(feature = "json")]
mod json;
mod macros;
mod smart;
mod style;
pub use compact::format_compact;
pub use diagnostic::*;
pub use formatter::{DiagnosticFormatter, RenderOptions, SourceCache};
pub use smart::{format_all_smart, print_all_smart};
use crate::style::*;
use colored::*;
#[derive(Debug)]
pub struct DiagnosticEngine<C: DiagnosticCode> {
diagnostics: Vec<Diagnostic<C>>,
bug_count: usize,
error_count: usize,
warning_count: usize,
help_count: usize,
note_count: usize,
}
impl<C: DiagnosticCode> Default for DiagnosticEngine<C> {
fn default() -> Self {
Self {
diagnostics: Vec::new(),
bug_count: 0,
error_count: 0,
warning_count: 0,
help_count: 0,
note_count: 0,
}
}
}
impl<C: DiagnosticCode> DiagnosticEngine<C> {
pub fn new() -> Self {
Self::default()
}
pub fn clear(&mut self) {
self.diagnostics.clear();
self.bug_count = 0;
self.error_count = 0;
self.warning_count = 0;
self.help_count = 0;
self.note_count = 0;
}
pub fn emit(&mut self, diagnostic: Diagnostic<C>) {
match diagnostic.severity {
Severity::Bug => self.bug_count += 1,
Severity::Error => self.error_count += 1,
Severity::Warning => self.warning_count += 1,
Severity::Help => self.help_count += 1,
Severity::Note => self.note_count += 1,
}
self.diagnostics.push(diagnostic);
}
pub fn emit_errors(&mut self, errors: Vec<Diagnostic<C>>) {
for d in errors {
self.emit(d);
}
}
pub fn emit_warnings(&mut self, warnings: Vec<Diagnostic<C>>) {
for d in warnings {
self.emit(d);
}
}
pub fn emit_helps(&mut self, helps: Vec<Diagnostic<C>>) {
for d in helps {
self.emit(d);
}
}
pub fn emit_notes(&mut self, notes: Vec<Diagnostic<C>>) {
for d in notes {
self.emit(d);
}
}
pub fn extend(&mut self, other: DiagnosticEngine<C>) {
self.diagnostics.extend(other.diagnostics);
self.bug_count += other.bug_count;
self.error_count += other.error_count;
self.warning_count += other.warning_count;
self.help_count += other.help_count;
self.note_count += other.note_count;
}
pub fn print_all(&self, source_code: &str) {
let cache = SourceCache::new(source_code);
for d in &self.diagnostics {
let f = DiagnosticFormatter::with_cache(d, &cache);
print!("{}", f.format());
}
let summary = self.format_summary();
if !summary.is_empty() {
println!("\n{}", summary);
}
}
pub fn format_all(&self, source_code: &str) -> String {
self.format_all_with(source_code, RenderOptions::default())
}
pub fn format_all_plain(&self, source_code: &str) -> String {
let opts = RenderOptions { color: false, ..Default::default() };
self.format_all_with(source_code, opts)
}
pub fn format_all_with(&self, source_code: &str, options: RenderOptions) -> String {
let cache = SourceCache::new(source_code);
let mut out = String::new();
for d in &self.diagnostics {
let f = DiagnosticFormatter::with_cache(d, &cache).with_options(options);
out.push_str(&f.format());
}
if options.color {
out.push_str(&self.format_summary());
} else {
out.push_str(&self.format_summary_plain());
}
out
}
pub fn format_all_compact(&self) -> String {
self.format_all_compact_with(true)
}
pub fn format_all_compact_plain(&self) -> String {
self.format_all_compact_with(false)
}
fn format_all_compact_with(&self, color: bool) -> String {
let mut out = String::new();
for d in &self.diagnostics {
out.push_str(&compact::format_compact(d, color));
}
if color {
out.push_str(&self.format_summary());
} else {
out.push_str(&self.format_summary_plain());
}
out
}
pub fn print_all_compact(&self) {
print!("{}", self.format_all_compact());
let summary = self.format_summary();
if !summary.is_empty() {
println!("\n{}", summary);
}
}
pub fn summary(&self, color: bool) -> String {
self.format_summary_with(color)
}
fn format_summary(&self) -> String {
self.format_summary_with(true)
}
fn format_summary_plain(&self) -> String {
self.format_summary_with(false)
}
fn format_summary_with(&self, color: bool) -> String {
if self.error_count + self.warning_count + self.bug_count == 0 {
return String::new();
}
let total_errors = self.error_count + self.bug_count;
if total_errors > 0 {
let warn_part = if self.warning_count > 0 {
format!(
"; {} {} emitted",
paint(&self.warning_count.to_string(), color, |s| s.yellow().bold()),
plural("warning", self.warning_count),
)
} else {
String::new()
};
format!(
"{}: could not compile due to {} previous {}{}",
paint("error", color, |s| s.red().bold()),
paint(&total_errors.to_string(), color, |s| s.red().bold()),
plural("error", total_errors),
warn_part,
)
} else {
format!(
"{}: {} {} emitted",
paint("warning", color, |s| s.yellow().bold()),
paint(&self.warning_count.to_string(), color, |s| s.yellow().bold()),
plural("warning", self.warning_count),
)
}
}
pub fn get_diagnostics(&self) -> &[Diagnostic<C>] {
&self.diagnostics
}
pub fn iter(&self) -> std::slice::Iter<'_, Diagnostic<C>> {
self.diagnostics.iter()
}
pub fn get_errors(&self) -> Vec<&Diagnostic<C>> {
self.diagnostics.iter().filter(|d| d.severity == Severity::Error).collect()
}
pub fn get_warnings(&self) -> Vec<&Diagnostic<C>> {
self.diagnostics.iter().filter(|d| d.severity == Severity::Warning).collect()
}
pub fn get_notes(&self) -> Vec<&Diagnostic<C>> {
self.diagnostics.iter().filter(|d| d.severity == Severity::Note).collect()
}
pub fn get_helps(&self) -> Vec<&Diagnostic<C>> {
self.diagnostics.iter().filter(|d| d.severity == Severity::Help).collect()
}
pub fn get_bugs(&self) -> Vec<&Diagnostic<C>> {
self.diagnostics.iter().filter(|d| d.severity == Severity::Bug).collect()
}
pub fn is_empty(&self) -> bool {
self.diagnostics.is_empty()
}
pub fn len(&self) -> usize {
self.diagnostics.len()
}
pub fn has_errors(&self) -> bool {
self.error_count > 0
}
pub fn has_warnings(&self) -> bool {
self.warning_count > 0
}
pub fn has_helps(&self) -> bool {
self.help_count > 0
}
pub fn has_notes(&self) -> bool {
self.note_count > 0
}
pub fn has_bugs(&self) -> bool {
self.bug_count > 0
}
pub fn bug_count(&self) -> usize {
self.bug_count
}
pub fn error_count(&self) -> usize {
self.error_count
}
pub fn warning_count(&self) -> usize {
self.warning_count
}
pub fn help_count(&self) -> usize {
self.help_count
}
pub fn note_count(&self) -> usize {
self.note_count
}
}
#[cfg(feature = "json")]
impl<C: DiagnosticCode + serde::Serialize> DiagnosticEngine<C> {
pub fn format_all_json(&self) -> String {
crate::json::format_all_json(&self.diagnostics)
}
}