proc_macro2_diagnostics/
line.rs

1use std::fmt;
2use std::borrow::Cow;
3
4use crate::Level;
5
6#[derive(Copy, Clone, PartialEq)]
7enum Kind {
8    New,
9    Joined,
10}
11
12impl Kind {
13    fn raw_split(self) -> (Cow<'static, str>, Cow<'static, str>) {
14        match self {
15            Kind::New => ("[".into(), "] ".into()),
16            Kind::Joined => ("= ".into(), ": ".into()),
17        }
18    }
19
20    #[cfg(not(all(feature = "colors", not(nightly_diagnostics))))]
21    fn split(self) -> (Cow<'static, str>, Cow<'static, str>) {
22        self.raw_split()
23    }
24
25    #[cfg(all(feature = "colors", not(nightly_diagnostics)))]
26    fn split(self) -> (Cow<'static, str>, Cow<'static, str>) {
27        use yansi::Paint;
28
29        let (prefix, suffix) = self.raw_split();
30        let (prefix, suffix) = match self {
31            Kind::New => (prefix.blue().bold(), suffix.blue().bold()),
32            Kind::Joined => (prefix.blue().bold(), suffix.primary()),
33        };
34
35        (prefix.to_string().into(), suffix.to_string().into())
36    }
37}
38
39pub struct Line<'a> {
40    pub level: Level,
41    pub msg: &'a str,
42    kind: Kind
43}
44
45impl<'a> Line<'a> {
46    pub fn new(level: Level, msg: &'a str) -> Line<'a> {
47        Line { kind: Kind::New, level, msg }
48    }
49
50    pub fn joined(level: Level, msg: &'a str) -> Line<'a> {
51        Line { kind: Kind::Joined, level, msg }
52    }
53
54    pub fn is_new(&self) -> bool {
55        self.kind == Kind::New
56    }
57
58    fn parse_kind(kind: Kind, string: &str) -> Option<Line<'_>> {
59        let string = string.trim_start();
60        let (prefix, suffix) = kind.split();
61        if !string.starts_with(&*prefix) {
62            return None;
63        }
64
65        let end = string.find(&*suffix)?;
66        let level: Level = string[prefix.len()..end].parse().ok()?;
67        let msg = &string[end + suffix.len()..];
68        Some(Line { level, msg, kind })
69    }
70
71    pub fn parse(string: &str) -> Option<Line<'_>> {
72        Line::parse_kind(Kind::Joined, string)
73            .or_else(|| Line::parse_kind(Kind::New, string))
74    }
75}
76
77impl fmt::Display for Line<'_> {
78    #[cfg(all(feature = "colors", not(nightly_diagnostics)))]
79    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80        use yansi::{Paint, Color};
81        let style = match self.level {
82            Level::Error => Color::Red.bold(),
83            Level::Warning => Color::Yellow.bold(),
84            Level::Note => Color::Green.bold(),
85            Level::Help => Color::Cyan.bold(),
86        };
87
88        let ((prefix, suffix), msg) = (self.kind.split(), self.msg.primary());
89        write!(f, "{}{}{}{}", prefix, self.level.paint(style), suffix, msg.bold())
90    }
91
92    #[cfg(not(all(feature = "colors", not(nightly_diagnostics))))]
93    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94        let (prefix, suffix) = self.kind.split();
95        write!(f, "{}{}{}{}", prefix, self.level, suffix, self.msg)
96    }
97}