]> git.lizzy.rs Git - rust.git/blob - src/librustc_errors/snippet.rs
Auto merge of #41437 - cuviper:remove-unstable-deprecated, r=alexcrichton
[rust.git] / src / librustc_errors / snippet.rs
1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 // Code for annotating snippets.
12
13 use syntax_pos::{Span, FileMap};
14 use CodeMapper;
15 use std::rc::Rc;
16 use Level;
17
18 #[derive(Clone)]
19 pub struct SnippetData {
20     codemap: Rc<CodeMapper>,
21     files: Vec<FileInfo>,
22 }
23
24 #[derive(Clone)]
25 pub struct FileInfo {
26     file: Rc<FileMap>,
27
28     /// The "primary file", if any, gets a `-->` marker instead of
29     /// `>>>`, and has a line-number/column printed and not just a
30     /// filename.  It appears first in the listing. It is known to
31     /// contain at least one primary span, though primary spans (which
32     /// are designated with `^^^`) may also occur in other files.
33     primary_span: Option<Span>,
34
35     lines: Vec<Line>,
36 }
37
38 #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
39 pub struct Line {
40     pub line_index: usize,
41     pub annotations: Vec<Annotation>,
42 }
43
44
45 #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
46 pub struct MultilineAnnotation {
47     pub depth: usize,
48     pub line_start: usize,
49     pub line_end: usize,
50     pub start_col: usize,
51     pub end_col: usize,
52     pub is_primary: bool,
53     pub label: Option<String>,
54 }
55
56 impl MultilineAnnotation {
57     pub fn increase_depth(&mut self) {
58         self.depth += 1;
59     }
60
61     pub fn as_start(&self) -> Annotation {
62         Annotation {
63             start_col: self.start_col,
64             end_col: self.start_col + 1,
65             is_primary: self.is_primary,
66             label: None,
67             annotation_type: AnnotationType::MultilineStart(self.depth)
68         }
69     }
70
71     pub fn as_end(&self) -> Annotation {
72         Annotation {
73             start_col: self.end_col - 1,
74             end_col: self.end_col,
75             is_primary: self.is_primary,
76             label: self.label.clone(),
77             annotation_type: AnnotationType::MultilineEnd(self.depth)
78         }
79     }
80
81     pub fn as_line(&self) -> Annotation {
82         Annotation {
83             start_col: 0,
84             end_col: 0,
85             is_primary: self.is_primary,
86             label: None,
87             annotation_type: AnnotationType::MultilineLine(self.depth)
88         }
89     }
90 }
91
92 #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
93 pub enum AnnotationType {
94     /// Annotation under a single line of code
95     Singleline,
96
97     /// Annotation enclosing the first and last character of a multiline span
98     Multiline(MultilineAnnotation),
99
100     // The Multiline type above is replaced with the following three in order
101     // to reuse the current label drawing code.
102     //
103     // Each of these corresponds to one part of the following diagram:
104     //
105     //     x |   foo(1 + bar(x,
106     //       |  _________^              < MultilineStart
107     //     x | |             y),        < MultilineLine
108     //       | |______________^ label   < MultilineEnd
109     //     x |       z);
110     /// Annotation marking the first character of a fully shown multiline span
111     MultilineStart(usize),
112     /// Annotation marking the last character of a fully shown multiline span
113     MultilineEnd(usize),
114     /// Line at the left enclosing the lines of a fully shown multiline span
115     // Just a placeholder for the drawing algorithm, to know that it shouldn't skip the first 4
116     // and last 2 lines of code. The actual line is drawn in `emit_message_default` and not in
117     // `draw_multiline_line`.
118     MultilineLine(usize),
119 }
120
121 #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
122 pub struct Annotation {
123     /// Start column, 0-based indexing -- counting *characters*, not
124     /// utf-8 bytes. Note that it is important that this field goes
125     /// first, so that when we sort, we sort orderings by start
126     /// column.
127     pub start_col: usize,
128
129     /// End column within the line (exclusive)
130     pub end_col: usize,
131
132     /// Is this annotation derived from primary span
133     pub is_primary: bool,
134
135     /// Optional label to display adjacent to the annotation.
136     pub label: Option<String>,
137
138     /// Is this a single line, multiline or multiline span minimized down to a
139     /// smaller span.
140     pub annotation_type: AnnotationType,
141 }
142
143 impl Annotation {
144     /// Wether this annotation is a vertical line placeholder.
145     pub fn is_line(&self) -> bool {
146         if let AnnotationType::MultilineLine(_) = self.annotation_type {
147             true
148         } else {
149             false
150         }
151     }
152
153     pub fn is_multiline(&self) -> bool {
154         match self.annotation_type {
155             AnnotationType::Multiline(_) |
156             AnnotationType::MultilineStart(_) |
157             AnnotationType::MultilineLine(_) |
158             AnnotationType::MultilineEnd(_) => true,
159             _ => false,
160         }
161     }
162
163     pub fn len(&self) -> usize {
164         // Account for usize underflows
165         if self.end_col > self.start_col {
166             self.end_col - self.start_col
167         } else {
168             self.start_col - self.end_col
169         }
170     }
171
172     pub fn has_label(&self) -> bool {
173         if let Some(ref label) = self.label {
174             // Consider labels with no text as effectively not being there
175             // to avoid weird output with unnecessary vertical lines, like:
176             //
177             //     X | fn foo(x: u32) {
178             //       | -------^------
179             //       | |      |
180             //       | |
181             //       |
182             //
183             // Note that this would be the complete output users would see.
184             label.len() > 0
185         } else {
186             false
187         }
188     }
189
190     pub fn takes_space(&self) -> bool {
191         // Multiline annotations always have to keep vertical space.
192         match self.annotation_type {
193             AnnotationType::MultilineStart(_) |
194             AnnotationType::MultilineEnd(_) => true,
195             _ => false,
196         }
197     }
198 }
199
200 #[derive(Debug)]
201 pub struct StyledString {
202     pub text: String,
203     pub style: Style,
204 }
205
206 #[derive(Copy, Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
207 pub enum Style {
208     HeaderMsg,
209     FileNameStyle,
210     LineAndColumn,
211     LineNumber,
212     Quotation,
213     UnderlinePrimary,
214     UnderlineSecondary,
215     LabelPrimary,
216     LabelSecondary,
217     OldSchoolNoteText,
218     OldSchoolNote,
219     NoStyle,
220     ErrorCode,
221     Level(Level),
222     Highlight,
223 }