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