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.
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.
11 // Code for annotating snippets.
13 use syntax_pos::{Span, FileMap};
19 pub struct SnippetData {
20 codemap: Rc<CodeMapper>,
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 (other files are not guaranteed to have line numbers
31 /// or columns). It appears first in the listing. It is known to
32 /// contain at least one primary span, though primary spans (which
33 /// are designated with `^^^`) may also occur in other files.
34 primary_span: Option<Span>,
39 #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
41 pub line_index: usize,
42 pub annotations: Vec<Annotation>,
46 #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
47 pub struct MultilineAnnotation {
49 pub line_start: usize,
54 pub label: Option<String>,
57 impl MultilineAnnotation {
58 pub fn increase_depth(&mut self) {
62 pub fn as_start(&self) -> Annotation {
64 start_col: self.start_col,
65 end_col: self.start_col + 1,
66 is_primary: self.is_primary,
68 annotation_type: AnnotationType::MultilineStart(self.depth)
72 pub fn as_end(&self) -> Annotation {
74 start_col: self.end_col.saturating_sub(1),
75 end_col: self.end_col,
76 is_primary: self.is_primary,
77 label: self.label.clone(),
78 annotation_type: AnnotationType::MultilineEnd(self.depth)
82 pub fn as_line(&self) -> Annotation {
86 is_primary: self.is_primary,
88 annotation_type: AnnotationType::MultilineLine(self.depth)
93 #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
94 pub enum AnnotationType {
95 /// Annotation under a single line of code
98 /// Annotation enclosing the first and last character of a multiline span
99 Multiline(MultilineAnnotation),
101 // The Multiline type above is replaced with the following three in order
102 // to reuse the current label drawing code.
104 // Each of these corresponds to one part of the following diagram:
106 // x | foo(1 + bar(x,
107 // | _________^ < MultilineStart
108 // x | | y), < MultilineLine
109 // | |______________^ label < MultilineEnd
111 /// Annotation marking the first character of a fully shown multiline span
112 MultilineStart(usize),
113 /// Annotation marking the last character of a fully shown multiline span
115 /// Line at the left enclosing the lines of a fully shown multiline span
116 // Just a placeholder for the drawing algorithm, to know that it shouldn't skip the first 4
117 // and last 2 lines of code. The actual line is drawn in `emit_message_default` and not in
118 // `draw_multiline_line`.
119 MultilineLine(usize),
122 #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
123 pub struct Annotation {
124 /// Start column, 0-based indexing -- counting *characters*, not
125 /// utf-8 bytes. Note that it is important that this field goes
126 /// first, so that when we sort, we sort orderings by start
128 pub start_col: usize,
130 /// End column within the line (exclusive)
133 /// Is this annotation derived from primary span
134 pub is_primary: bool,
136 /// Optional label to display adjacent to the annotation.
137 pub label: Option<String>,
139 /// Is this a single line, multiline or multiline span minimized down to a
141 pub annotation_type: AnnotationType,
145 /// Whether this annotation is a vertical line placeholder.
146 pub fn is_line(&self) -> bool {
147 if let AnnotationType::MultilineLine(_) = self.annotation_type {
154 pub fn is_multiline(&self) -> bool {
155 match self.annotation_type {
156 AnnotationType::Multiline(_) |
157 AnnotationType::MultilineStart(_) |
158 AnnotationType::MultilineLine(_) |
159 AnnotationType::MultilineEnd(_) => true,
164 pub fn len(&self) -> usize {
165 // Account for usize underflows
166 if self.end_col > self.start_col {
167 self.end_col - self.start_col
169 self.start_col - self.end_col
173 pub fn has_label(&self) -> bool {
174 if let Some(ref label) = self.label {
175 // Consider labels with no text as effectively not being there
176 // to avoid weird output with unnecessary vertical lines, like:
178 // X | fn foo(x: u32) {
184 // Note that this would be the complete output users would see.
191 pub fn takes_space(&self) -> bool {
192 // Multiline annotations always have to keep vertical space.
193 match self.annotation_type {
194 AnnotationType::MultilineStart(_) |
195 AnnotationType::MultilineEnd(_) => true,
202 pub struct StyledString {
207 #[derive(Copy, Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]