language_reporting/
models.rs

1use crate::diagnostic::Diagnostic;
2use crate::{FileName, Label, LabelStyle, Location, ReportingFiles, ReportingSpan, Severity};
3
4#[derive(Copy, Clone, Debug)]
5pub(crate) struct Header<'doc> {
6    severity: Severity,
7    code: Option<&'doc str>,
8    message: &'doc str,
9}
10
11impl<'doc> Header<'doc> {
12    pub(crate) fn new(diagnostic: &'doc Diagnostic<impl ReportingSpan>) -> Header<'doc> {
13        Header {
14            severity: diagnostic.severity,
15            code: diagnostic.code.as_ref().map(|c| &c[..]),
16            message: &diagnostic.message,
17        }
18    }
19
20    pub(crate) fn severity(&self) -> &'static str {
21        match self.severity {
22            Severity::Bug => "bug",
23            Severity::Error => "error",
24            Severity::Warning => "warning",
25            Severity::Help => "help",
26            Severity::Note => "note",
27        }
28    }
29
30    pub(crate) fn code(&self) -> &Option<&'doc str> {
31        &self.code
32    }
33
34    pub(crate) fn message(&self) -> String {
35        self.message.to_string()
36    }
37}
38
39pub(crate) fn severity(diagnostic: &Diagnostic<impl ReportingSpan>) -> &'static str {
40    match diagnostic.severity {
41        Severity::Bug => "bug",
42        Severity::Error => "error",
43        Severity::Warning => "warning",
44        Severity::Help => "help",
45        Severity::Note => "note",
46    }
47}
48
49#[derive(Copy, Clone, Debug)]
50pub(crate) struct SourceLine<'doc, Files: ReportingFiles> {
51    files: &'doc Files,
52    label: &'doc Label<Files::Span>,
53    config: &'doc dyn crate::Config,
54}
55
56impl<'doc, Files: ReportingFiles> SourceLine<'doc, Files> {
57    pub(crate) fn new(
58        files: &'doc Files,
59        label: &'doc Label<Files::Span>,
60        config: &'doc dyn crate::Config,
61    ) -> SourceLine<'doc, Files> {
62        SourceLine {
63            files,
64            label,
65            config,
66        }
67    }
68
69    pub(crate) fn location(&self) -> Location {
70        let span = self.label.span;
71
72        self.files
73            .location(self.files.file_id(span), span.start())
74            .expect("A valid location")
75    }
76
77    pub(crate) fn filename(&self) -> String {
78        match &self.files.file_name(self.files.file_id(self.label.span)) {
79            FileName::Virtual(name) => format!("<{}>", name.to_str().unwrap()),
80            FileName::Real(name) => self.config.filename(name),
81            FileName::Verbatim(name) => format!("{}", name),
82        }
83    }
84
85    pub(crate) fn line_span(&self) -> Files::Span {
86        let span = self.label.span;
87
88        self.files
89            .line_span(self.files.file_id(span), self.location().line)
90            .expect("line_span")
91    }
92
93    pub(crate) fn line_number(&self) -> usize {
94        self.location().line + 1
95    }
96
97    pub(crate) fn line_number_len(&self) -> usize {
98        self.line_number().to_string().len()
99    }
100
101    // pub(crate) fn before_line_len(&self) -> usize {
102    //     // TODO: Improve
103    //     self.before_marked().len() + self.line_number().to_string().len()
104    // }
105
106    pub(crate) fn before_marked(&self) -> String {
107        self.files
108            .source(self.line_span().with_end(self.label.span.start()))
109            .expect("line_prefix")
110    }
111
112    pub(crate) fn after_marked(&self) -> String {
113        self.files
114            .source(self.line_span().with_start(self.label.span.end()))
115            .expect("line_suffix")
116            .trim_end_matches(|ch| ch == '\r' || ch == '\n')
117            .to_string()
118    }
119
120    pub(crate) fn marked(&self) -> String {
121        self.files.source(self.label.span).expect("line_marked")
122    }
123}
124
125#[derive(Clone)]
126pub struct LabelledLine<'doc, Files: ReportingFiles> {
127    source_line: SourceLine<'doc, Files>,
128    label: &'doc Label<Files::Span>,
129}
130
131impl<'doc, Files: ReportingFiles> LabelledLine<'doc, Files> {
132    pub(crate) fn new(
133        source_line: SourceLine<'doc, Files>,
134        label: &'doc Label<Files::Span>,
135    ) -> LabelledLine<'doc, Files> {
136        LabelledLine { source_line, label }
137    }
138
139    pub(crate) fn mark(&self) -> &'static str {
140        match self.label.style {
141            LabelStyle::Primary => "^",
142            LabelStyle::Secondary => "-",
143        }
144    }
145
146    pub(crate) fn style(&self) -> &'static str {
147        match self.label.style {
148            LabelStyle::Primary => "primary",
149            LabelStyle::Secondary => "secondary",
150        }
151    }
152
153    pub(crate) fn message(&self) -> &Option<String> {
154        self.label.message()
155    }
156
157    pub(crate) fn source_line(&self) -> &SourceLine<'doc, Files> {
158        &self.source_line
159    }
160}