| 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 | |