1 use std::fmt;
2 
3 use crate::formatter::{get_term_style, style::Stylesheet};
4 
5 /// List of lines to be displayed.
6 pub struct DisplayList<'a> {
7     pub body: Vec<DisplayLine<'a>>,
8     pub stylesheet: Box<dyn Stylesheet>,
9     pub anonymized_line_numbers: bool,
10 }
11 
12 impl<'a> From<Vec<DisplayLine<'a>>> for DisplayList<'a> {
from(body: Vec<DisplayLine<'a>>) -> DisplayList<'a>13     fn from(body: Vec<DisplayLine<'a>>) -> DisplayList<'a> {
14         Self {
15             body,
16             anonymized_line_numbers: false,
17             stylesheet: get_term_style(false),
18         }
19     }
20 }
21 
22 impl<'a> PartialEq for DisplayList<'a> {
eq(&self, other: &Self) -> bool23     fn eq(&self, other: &Self) -> bool {
24         self.body == other.body && self.anonymized_line_numbers == other.anonymized_line_numbers
25     }
26 }
27 
28 impl<'a> fmt::Debug for DisplayList<'a> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result29     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30         f.debug_struct("DisplayList")
31             .field("body", &self.body)
32             .field("anonymized_line_numbers", &self.anonymized_line_numbers)
33             .finish()
34     }
35 }
36 
37 #[derive(Debug, Default, Copy, Clone)]
38 pub struct FormatOptions {
39     pub color: bool,
40     pub anonymized_line_numbers: bool,
41 }
42 
43 /// Inline annotation which can be used in either Raw or Source line.
44 #[derive(Debug, PartialEq)]
45 pub struct Annotation<'a> {
46     pub annotation_type: DisplayAnnotationType,
47     pub id: Option<&'a str>,
48     pub label: Vec<DisplayTextFragment<'a>>,
49 }
50 
51 /// A single line used in `DisplayList`.
52 #[derive(Debug, PartialEq)]
53 pub enum DisplayLine<'a> {
54     /// A line with `lineno` portion of the slice.
55     Source {
56         lineno: Option<usize>,
57         inline_marks: Vec<DisplayMark>,
58         line: DisplaySourceLine<'a>,
59     },
60 
61     /// A line indicating a folded part of the slice.
62     Fold { inline_marks: Vec<DisplayMark> },
63 
64     /// A line which is displayed outside of slices.
65     Raw(DisplayRawLine<'a>),
66 }
67 
68 /// A source line.
69 #[derive(Debug, PartialEq)]
70 pub enum DisplaySourceLine<'a> {
71     /// A line with the content of the Slice.
72     Content {
73         text: &'a str,
74         range: (usize, usize), // meta information for annotation placement.
75     },
76 
77     /// An annotation line which is displayed in context of the slice.
78     Annotation {
79         annotation: Annotation<'a>,
80         range: (usize, usize),
81         annotation_type: DisplayAnnotationType,
82         annotation_part: DisplayAnnotationPart,
83     },
84 
85     /// An empty source line.
86     Empty,
87 }
88 
89 /// Raw line - a line which does not have the `lineno` part and is not considered
90 /// a part of the snippet.
91 #[derive(Debug, PartialEq)]
92 pub enum DisplayRawLine<'a> {
93     /// A line which provides information about the location of the given
94     /// slice in the project structure.
95     Origin {
96         path: &'a str,
97         pos: Option<(usize, usize)>,
98         header_type: DisplayHeaderType,
99     },
100 
101     /// An annotation line which is not part of any snippet.
102     Annotation {
103         annotation: Annotation<'a>,
104 
105         /// If set to `true`, the annotation will be aligned to the
106         /// lineno delimiter of the snippet.
107         source_aligned: bool,
108         /// If set to `true`, only the label of the `Annotation` will be
109         /// displayed. It allows for a multiline annotation to be aligned
110         /// without displaing the meta information (`type` and `id`) to be
111         /// displayed on each line.
112         continuation: bool,
113     },
114 }
115 
116 /// An inline text fragment which any label is composed of.
117 #[derive(Debug, PartialEq)]
118 pub struct DisplayTextFragment<'a> {
119     pub content: &'a str,
120     pub style: DisplayTextStyle,
121 }
122 
123 /// A style for the `DisplayTextFragment` which can be visually formatted.
124 ///
125 /// This information may be used to emphasis parts of the label.
126 #[derive(Debug, Clone, Copy, PartialEq)]
127 pub enum DisplayTextStyle {
128     Regular,
129     Emphasis,
130 }
131 
132 /// An indicator of what part of the annotation a given `Annotation` is.
133 #[derive(Debug, Clone, PartialEq)]
134 pub enum DisplayAnnotationPart {
135     /// A standalone, single-line annotation.
136     Standalone,
137     /// A continuation of a multi-line label of an annotation.
138     LabelContinuation,
139     /// A consequitive annotation in case multiple annotations annotate a single line.
140     Consequitive,
141     /// A line starting a multiline annotation.
142     MultilineStart,
143     /// A line ending a multiline annotation.
144     MultilineEnd,
145 }
146 
147 /// A visual mark used in `inline_marks` field of the `DisplaySourceLine`.
148 #[derive(Debug, Clone, PartialEq)]
149 pub struct DisplayMark {
150     pub mark_type: DisplayMarkType,
151     pub annotation_type: DisplayAnnotationType,
152 }
153 
154 /// A type of the `DisplayMark`.
155 #[derive(Debug, Clone, PartialEq)]
156 pub enum DisplayMarkType {
157     /// A mark indicating a multiline annotation going through the current line.
158     AnnotationThrough,
159     /// A mark indicating a multiline annotation starting on the given line.
160     AnnotationStart,
161 }
162 
163 /// A type of the `Annotation` which may impact the sigils, style or text displayed.
164 ///
165 /// There are several ways in which the `DisplayListFormatter` uses this information
166 /// when formatting the `DisplayList`:
167 ///
168 /// * An annotation may display the name of the type like `error` or `info`.
169 /// * An underline for `Error` may be `^^^` while for `Warning` it coule be `---`.
170 /// * `ColorStylesheet` may use different colors for different annotations.
171 #[derive(Debug, Clone, PartialEq)]
172 pub enum DisplayAnnotationType {
173     None,
174     Error,
175     Warning,
176     Info,
177     Note,
178     Help,
179 }
180 
181 /// Information whether the header is the initial one or a consequitive one
182 /// for multi-slice cases.
183 // TODO: private
184 #[derive(Debug, Clone, PartialEq)]
185 pub enum DisplayHeaderType {
186     /// Initial header is the first header in the snippet.
187     Initial,
188 
189     /// Continuation marks all headers of following slices in the snippet.
190     Continuation,
191 }
192