swc_common/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
13use super::Level;
14
15#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
16pub struct Line {
17    pub line_index: usize,
18    pub annotations: Vec<Annotation>,
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        matches!(self.annotation_type, AnnotationType::MultilineLine(_))
123    }
124
125    pub fn is_multiline(&self) -> bool {
126        matches!(
127            self.annotation_type,
128            AnnotationType::Multiline(_)
129                | AnnotationType::MultilineStart(_)
130                | AnnotationType::MultilineLine(_)
131                | AnnotationType::MultilineEnd(_)
132        )
133    }
134
135    pub fn len(&self) -> usize {
136        // Account for usize underflows
137        self.end_col.abs_diff(self.start_col)
138    }
139
140    pub fn has_label(&self) -> bool {
141        if let Some(ref label) = self.label {
142            // Consider labels with no text as effectively not being there
143            // to avoid weird output with unnecessary vertical lines, like:
144            //
145            //     X | fn foo(x: u32) {
146            //       | -------^------
147            //       | |      |
148            //       | |
149            //       |
150            //
151            // Note that this would be the complete output users would see.
152            !label.is_empty()
153        } else {
154            false
155        }
156    }
157
158    pub fn takes_space(&self) -> bool {
159        // Multiline annotations always have to keep vertical space.
160        matches!(
161            self.annotation_type,
162            AnnotationType::MultilineStart(_) | AnnotationType::MultilineEnd(_)
163        )
164    }
165}
166
167#[derive(Debug)]
168pub struct StyledString {
169    pub text: String,
170    pub style: Style,
171}
172
173#[allow(clippy::enum_variant_names)]
174#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
175#[cfg_attr(
176    feature = "diagnostic-serde",
177    derive(serde::Serialize, serde::Deserialize)
178)]
179#[cfg_attr(
180    any(feature = "rkyv-impl"),
181    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
182)]
183#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
184#[cfg_attr(feature = "rkyv-impl", repr(u32))]
185pub enum Style {
186    MainHeaderMsg,
187    HeaderMsg,
188    LineAndColumn,
189    LineNumber,
190    Quotation,
191    UnderlinePrimary,
192    UnderlineSecondary,
193    LabelPrimary,
194    LabelSecondary,
195    OldSchoolNoteText,
196    NoStyle,
197    Level(Level),
198    Highlight,
199}