vrl/diagnostic/
formatter.rs

1use std::fmt;
2
3use super::DiagnosticList;
4
5/// A formatter to display diagnostics tied to a given source.
6pub struct Formatter<'a> {
7    source: &'a str,
8    diagnostics: DiagnosticList,
9    color: bool,
10}
11
12impl<'a> Formatter<'a> {
13    pub fn new(source: &'a str, diagnostics: impl Into<DiagnosticList>) -> Self {
14        Self {
15            source,
16            diagnostics: diagnostics.into(),
17            color: false,
18        }
19    }
20
21    #[must_use]
22    pub fn colored(mut self) -> Self {
23        self.color = true;
24        self
25    }
26
27    pub fn enable_colors(&mut self, color: bool) {
28        self.color = color
29    }
30
31    #[must_use]
32    pub fn diagnostics(&self) -> &DiagnosticList {
33        &self.diagnostics
34    }
35}
36
37impl fmt::Display for Formatter<'_> {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        use std::str::from_utf8;
40
41        use codespan_reporting::{files::SimpleFile, term};
42        use termcolor::Buffer;
43
44        if self.diagnostics.is_empty() {
45            return Ok(());
46        }
47
48        let file = SimpleFile::new("", self.source);
49        let config = term::Config::default();
50        let mut buffer = if self.color {
51            Buffer::ansi()
52        } else {
53            Buffer::no_color()
54        };
55
56        f.write_str("\n")?;
57
58        for diagnostic in self.diagnostics.iter() {
59            term::emit(&mut buffer, &config, &file, &diagnostic.clone().into())
60                .map_err(|_| fmt::Error)?;
61        }
62
63        // Diagnostic messages can contain whitespace at the end of some lines.
64        // This causes problems when used in our UI testing, as editors often
65        // strip end-of-line whitespace. Removing this has no actual visual
66        // impact.
67        let string = from_utf8(buffer.as_slice())
68            .map_err(|_| fmt::Error)?
69            .lines()
70            .map(str::trim_end)
71            .collect::<Vec<_>>()
72            .join("\n");
73
74        f.write_str(&string)
75    }
76}