codemap_diagnostic/
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.
12use Level;
13
14#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
15pub struct Line {
16    pub line_index: usize,
17    pub annotations: Vec<Annotation>,
18}
19
20
21#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
22pub 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
32impl 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)]
69pub 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)]
98pub 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
119impl 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)]
177pub struct StyledString {
178    pub text: String,
179    pub style: Style,
180}
181
182#[derive(Copy, Clone, Debug, PartialEq)]
183#[allow(dead_code)]
184pub 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}