]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_errors/src/snippet.rs
New upstream version 1.48.0~beta.8+dfsg1
[rustc.git] / compiler / rustc_errors / src / snippet.rs
1 // Code for annotating snippets.
2
3 use crate::Level;
4
5 #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
6 pub struct Line {
7 pub line_index: usize,
8 pub annotations: Vec<Annotation>,
9 }
10
11 #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
12 pub struct MultilineAnnotation {
13 pub depth: usize,
14 pub line_start: usize,
15 pub line_end: usize,
16 pub start_col: usize,
17 pub end_col: usize,
18 pub is_primary: bool,
19 pub label: Option<String>,
20 pub overlaps_exactly: bool,
21 }
22
23 impl MultilineAnnotation {
24 pub fn increase_depth(&mut self) {
25 self.depth += 1;
26 }
27
28 /// Compare two `MultilineAnnotation`s considering only the `Span` they cover.
29 pub fn same_span(&self, other: &MultilineAnnotation) -> bool {
30 self.line_start == other.line_start
31 && self.line_end == other.line_end
32 && self.start_col == other.start_col
33 && self.end_col == other.end_col
34 }
35
36 pub fn as_start(&self) -> Annotation {
37 Annotation {
38 start_col: self.start_col,
39 end_col: self.start_col + 1,
40 is_primary: self.is_primary,
41 label: None,
42 annotation_type: AnnotationType::MultilineStart(self.depth),
43 }
44 }
45
46 pub fn as_end(&self) -> Annotation {
47 Annotation {
48 start_col: self.end_col.saturating_sub(1),
49 end_col: self.end_col,
50 is_primary: self.is_primary,
51 label: self.label.clone(),
52 annotation_type: AnnotationType::MultilineEnd(self.depth),
53 }
54 }
55
56 pub fn as_line(&self) -> Annotation {
57 Annotation {
58 start_col: 0,
59 end_col: 0,
60 is_primary: self.is_primary,
61 label: None,
62 annotation_type: AnnotationType::MultilineLine(self.depth),
63 }
64 }
65 }
66
67 #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
68 pub enum AnnotationType {
69 /// Annotation under a single line of code
70 Singleline,
71
72 /// Annotation enclosing the first and last character of a multiline span
73 Multiline(MultilineAnnotation),
74
75 // The Multiline type above is replaced with the following three in order
76 // to reuse the current label drawing code.
77 //
78 // Each of these corresponds to one part of the following diagram:
79 //
80 // x | foo(1 + bar(x,
81 // | _________^ < MultilineStart
82 // x | | y), < MultilineLine
83 // | |______________^ label < MultilineEnd
84 // x | z);
85 /// Annotation marking the first character of a fully shown multiline span
86 MultilineStart(usize),
87 /// Annotation marking the last character of a fully shown multiline span
88 MultilineEnd(usize),
89 /// Line at the left enclosing the lines of a fully shown multiline span
90 // Just a placeholder for the drawing algorithm, to know that it shouldn't skip the first 4
91 // and last 2 lines of code. The actual line is drawn in `emit_message_default` and not in
92 // `draw_multiline_line`.
93 MultilineLine(usize),
94 }
95
96 #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
97 pub struct Annotation {
98 /// Start column, 0-based indexing -- counting *characters*, not
99 /// utf-8 bytes. Note that it is important that this field goes
100 /// first, so that when we sort, we sort orderings by start
101 /// column.
102 pub start_col: usize,
103
104 /// End column within the line (exclusive)
105 pub end_col: usize,
106
107 /// Is this annotation derived from primary span
108 pub is_primary: bool,
109
110 /// Optional label to display adjacent to the annotation.
111 pub label: Option<String>,
112
113 /// Is this a single line, multiline or multiline span minimized down to a
114 /// smaller span.
115 pub annotation_type: AnnotationType,
116 }
117
118 impl Annotation {
119 /// Whether this annotation is a vertical line placeholder.
120 pub fn is_line(&self) -> bool {
121 matches!(self.annotation_type, AnnotationType::MultilineLine(_))
122 }
123
124 pub fn is_multiline(&self) -> bool {
125 matches!(self.annotation_type,
126 AnnotationType::Multiline(_)
127 | AnnotationType::MultilineStart(_)
128 | AnnotationType::MultilineLine(_)
129 | AnnotationType::MultilineEnd(_))
130 }
131
132 pub fn len(&self) -> usize {
133 // Account for usize underflows
134 if self.end_col > self.start_col {
135 self.end_col - self.start_col
136 } else {
137 self.start_col - self.end_col
138 }
139 }
140
141 pub fn has_label(&self) -> bool {
142 if let Some(ref label) = self.label {
143 // Consider labels with no text as effectively not being there
144 // to avoid weird output with unnecessary vertical lines, like:
145 //
146 // X | fn foo(x: u32) {
147 // | -------^------
148 // | | |
149 // | |
150 // |
151 //
152 // Note that this would be the complete output users would see.
153 !label.is_empty()
154 } else {
155 false
156 }
157 }
158
159 pub fn takes_space(&self) -> bool {
160 // Multiline annotations always have to keep vertical space.
161 match self.annotation_type {
162 AnnotationType::MultilineStart(_) | AnnotationType::MultilineEnd(_) => true,
163 _ => false,
164 }
165 }
166 }
167
168 #[derive(Debug)]
169 pub struct StyledString {
170 pub text: String,
171 pub style: Style,
172 }
173
174 #[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
175 pub enum Style {
176 MainHeaderMsg,
177 HeaderMsg,
178 LineAndColumn,
179 LineNumber,
180 Quotation,
181 UnderlinePrimary,
182 UnderlineSecondary,
183 LabelPrimary,
184 LabelSecondary,
185 NoStyle,
186 Level(Level),
187 Highlight,
188 }