]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_errors/src/snippet.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / compiler / rustc_errors / src / snippet.rs
CommitLineData
a7813a04
XL
1// Code for annotating snippets.
2
353b0b11 3use crate::{Level, Loc};
a7813a04 4
5bcae85e
SL
5#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
6pub struct Line {
7 pub line_index: usize,
8 pub annotations: Vec<Annotation>,
a7813a04
XL
9}
10
353b0b11
FG
11#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Default)]
12pub struct AnnotationColumn {
13 /// the (0-indexed) column for *display* purposes, counted in characters, not utf-8 bytes
14 pub display: usize,
15 /// the (0-indexed) column in the file, counted in characters, not utf-8 bytes.
16 ///
17 /// this may be different from `self.display`,
18 /// e.g. if the file contains hard tabs, because we convert tabs to spaces for error messages.
19 ///
20 /// for example:
21 /// ```text
22 /// (hard tab)hello
23 /// ^ this is display column 4, but file column 1
24 /// ```
25 ///
26 /// we want to keep around the correct file offset so that column numbers in error messages
27 /// are correct. (motivated by <https://github.com/rust-lang/rust/issues/109537>)
28 pub file: usize,
29}
30
31impl AnnotationColumn {
32 pub fn from_loc(loc: &Loc) -> AnnotationColumn {
33 AnnotationColumn { display: loc.col_display, file: loc.col.0 }
34 }
35}
36
476ff2be
SL
37#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
38pub struct MultilineAnnotation {
39 pub depth: usize,
40 pub line_start: usize,
41 pub line_end: usize,
353b0b11
FG
42 pub start_col: AnnotationColumn,
43 pub end_col: AnnotationColumn,
476ff2be
SL
44 pub is_primary: bool,
45 pub label: Option<String>,
532ac7d7 46 pub overlaps_exactly: bool,
476ff2be
SL
47}
48
49impl MultilineAnnotation {
50 pub fn increase_depth(&mut self) {
51 self.depth += 1;
52 }
53
532ac7d7
XL
54 /// Compare two `MultilineAnnotation`s considering only the `Span` they cover.
55 pub fn same_span(&self, other: &MultilineAnnotation) -> bool {
dfeec247
XL
56 self.line_start == other.line_start
57 && self.line_end == other.line_end
58 && self.start_col == other.start_col
59 && self.end_col == other.end_col
532ac7d7
XL
60 }
61
476ff2be
SL
62 pub fn as_start(&self) -> Annotation {
63 Annotation {
64 start_col: self.start_col,
353b0b11
FG
65 end_col: AnnotationColumn {
66 // these might not correspond to the same place anymore,
67 // but that's okay for our purposes
68 display: self.start_col.display + 1,
69 file: self.start_col.file + 1,
70 },
476ff2be 71 is_primary: self.is_primary,
cc61c64b 72 label: None,
dfeec247 73 annotation_type: AnnotationType::MultilineStart(self.depth),
476ff2be
SL
74 }
75 }
76
77 pub fn as_end(&self) -> Annotation {
78 Annotation {
353b0b11
FG
79 start_col: AnnotationColumn {
80 // these might not correspond to the same place anymore,
81 // but that's okay for our purposes
82 display: self.end_col.display.saturating_sub(1),
83 file: self.end_col.file.saturating_sub(1),
84 },
476ff2be
SL
85 end_col: self.end_col,
86 is_primary: self.is_primary,
cc61c64b 87 label: self.label.clone(),
dfeec247 88 annotation_type: AnnotationType::MultilineEnd(self.depth),
476ff2be
SL
89 }
90 }
91
92 pub fn as_line(&self) -> Annotation {
93 Annotation {
353b0b11
FG
94 start_col: Default::default(),
95 end_col: Default::default(),
476ff2be
SL
96 is_primary: self.is_primary,
97 label: None,
dfeec247 98 annotation_type: AnnotationType::MultilineLine(self.depth),
476ff2be
SL
99 }
100 }
101}
102
103#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
104pub enum AnnotationType {
105 /// Annotation under a single line of code
106 Singleline,
107
476ff2be
SL
108 // The Multiline type above is replaced with the following three in order
109 // to reuse the current label drawing code.
110 //
111 // Each of these corresponds to one part of the following diagram:
112 //
113 // x | foo(1 + bar(x,
cc61c64b
XL
114 // | _________^ < MultilineStart
115 // x | | y), < MultilineLine
116 // | |______________^ label < MultilineEnd
476ff2be
SL
117 // x | z);
118 /// Annotation marking the first character of a fully shown multiline span
119 MultilineStart(usize),
120 /// Annotation marking the last character of a fully shown multiline span
121 MultilineEnd(usize),
122 /// Line at the left enclosing the lines of a fully shown multiline span
cc61c64b
XL
123 // Just a placeholder for the drawing algorithm, to know that it shouldn't skip the first 4
124 // and last 2 lines of code. The actual line is drawn in `emit_message_default` and not in
125 // `draw_multiline_line`.
476ff2be
SL
126 MultilineLine(usize),
127}
128
a7813a04 129#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
5bcae85e 130pub struct Annotation {
353b0b11
FG
131 /// Start column.
132 /// Note that it is important that this field goes
a7813a04
XL
133 /// first, so that when we sort, we sort orderings by start
134 /// column.
353b0b11 135 pub start_col: AnnotationColumn,
a7813a04
XL
136
137 /// End column within the line (exclusive)
353b0b11 138 pub end_col: AnnotationColumn,
a7813a04
XL
139
140 /// Is this annotation derived from primary span
5bcae85e 141 pub is_primary: bool,
a7813a04 142
a7813a04 143 /// Optional label to display adjacent to the annotation.
5bcae85e 144 pub label: Option<String>,
476ff2be
SL
145
146 /// Is this a single line, multiline or multiline span minimized down to a
147 /// smaller span.
148 pub annotation_type: AnnotationType,
149}
150
151impl Annotation {
3b2f2976 152 /// Whether this annotation is a vertical line placeholder.
32a655c1 153 pub fn is_line(&self) -> bool {
1b1a35ee 154 matches!(self.annotation_type, AnnotationType::MultilineLine(_))
32a655c1
SL
155 }
156
353b0b11 157 /// Length of this annotation as displayed in the stderr output
32a655c1
SL
158 pub fn len(&self) -> usize {
159 // Account for usize underflows
353b0b11
FG
160 if self.end_col.display > self.start_col.display {
161 self.end_col.display - self.start_col.display
32a655c1 162 } else {
353b0b11 163 self.start_col.display - self.end_col.display
32a655c1
SL
164 }
165 }
166
167 pub fn has_label(&self) -> bool {
168 if let Some(ref label) = self.label {
169 // Consider labels with no text as effectively not being there
170 // to avoid weird output with unnecessary vertical lines, like:
171 //
172 // X | fn foo(x: u32) {
173 // | -------^------
174 // | | |
175 // | |
176 // |
177 //
178 // Note that this would be the complete output users would see.
74b04a01 179 !label.is_empty()
32a655c1
SL
180 } else {
181 false
182 }
183 }
cc61c64b
XL
184
185 pub fn takes_space(&self) -> bool {
186 // Multiline annotations always have to keep vertical space.
5869c6ff
XL
187 matches!(
188 self.annotation_type,
189 AnnotationType::MultilineStart(_) | AnnotationType::MultilineEnd(_)
190 )
cc61c64b 191 }
a7813a04
XL
192}
193
194#[derive(Debug)]
195pub struct StyledString {
196 pub text: String,
197 pub style: Style,
198}
199
3dfed10e 200#[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
a7813a04 201pub enum Style {
8faf50e0 202 MainHeaderMsg,
5bcae85e 203 HeaderMsg,
a7813a04
XL
204 LineAndColumn,
205 LineNumber,
206 Quotation,
207 UnderlinePrimary,
208 UnderlineSecondary,
209 LabelPrimary,
210 LabelSecondary,
a7813a04 211 NoStyle,
5bcae85e 212 Level(Level),
32a655c1 213 Highlight,
94222f64
XL
214 Addition,
215 Removal,
c30ab7b3 216}