rustfmt_nightly/
format_report_formatter.rs1use crate::formatting::FormattingError;
2use crate::{ErrorKind, FormatReport};
3use annotate_snippets::{Annotation, AnnotationKind, Group, Level, Padding, Renderer, Snippet};
4use std::fmt::{self, Display};
5
6pub struct FormatReportFormatterBuilder<'a> {
8 report: &'a FormatReport,
9 enable_colors: bool,
10}
11
12impl<'a> FormatReportFormatterBuilder<'a> {
13 pub fn new(report: &'a FormatReport) -> Self {
15 Self {
16 report,
17 enable_colors: false,
18 }
19 }
20
21 #[must_use]
23 pub fn enable_colors(self, enable_colors: bool) -> Self {
24 Self {
25 enable_colors,
26 ..self
27 }
28 }
29
30 pub fn build(self) -> FormatReportFormatter<'a> {
32 FormatReportFormatter {
33 report: self.report,
34 enable_colors: self.enable_colors,
35 }
36 }
37}
38
39pub struct FormatReportFormatter<'a> {
43 report: &'a FormatReport,
44 enable_colors: bool,
45}
46
47impl<'a> Display for FormatReportFormatter<'a> {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 let errors_by_file = &self.report.internal.borrow().0;
50
51 let renderer = if self.enable_colors {
52 Renderer::styled()
53 } else {
54 Renderer::plain()
55 };
56
57 for (file, errors) in errors_by_file {
58 for error in errors {
59 let error_kind = error.kind.to_string();
60 let mut title =
61 error_kind_to_snippet_annotation_level(&error.kind).primary_title(error_kind);
62 if error.is_internal() {
63 title = title.id("internal");
64 }
65 let snippet = Snippet::source(&error.line_buffer)
66 .line_start(error.line)
67 .path(format!("{file}:{}", error.line))
68 .fold(false)
69 .annotations(annotation(error));
70 let mut group = title.element(snippet);
71 if let Some(message_suffix) = error.msg_suffix() {
72 group = group.element(Level::NOTE.message(message_suffix));
73 } else {
74 group = group.element(Padding);
75 }
76 writeln!(f, "{}\n", renderer.render(&[group]))?;
77 }
78 }
79
80 if !errors_by_file.is_empty() {
81 let label = format!(
82 "rustfmt has failed to format. See previous {} errors.",
83 self.report.warning_count()
84 );
85 let group = Group::with_title(Level::WARNING.primary_title(label));
86 writeln!(f, "{}\n", renderer.render(&[group]))?;
87 }
88 Ok(())
89 }
90}
91
92fn annotation(error: &FormattingError) -> Option<Annotation<'_>> {
93 error
94 .highlight
95 .clone()
96 .map(|range| AnnotationKind::Primary.span(range))
97}
98
99fn error_kind_to_snippet_annotation_level(error_kind: &ErrorKind) -> Level<'_> {
100 match error_kind {
101 ErrorKind::LineOverflow(..)
102 | ErrorKind::TrailingWhitespace
103 | ErrorKind::IoError(_)
104 | ErrorKind::ModuleResolutionError(_)
105 | ErrorKind::ParseError
106 | ErrorKind::LostComment
107 | ErrorKind::BadAttr
108 | ErrorKind::InvalidGlobPattern(_)
109 | ErrorKind::VersionMismatch => Level::ERROR,
110 ErrorKind::DeprecatedAttr => Level::WARNING,
111 }
112}