Skip to content

Commit fe63d9e

Browse files
author
Zibi Braniecki
committed
Support aligned footers
1 parent 2a254a0 commit fe63d9e

File tree

8 files changed

+191
-105
lines changed

8 files changed

+191
-105
lines changed

examples/footer.rs

+17-17
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
extern crate annotate_snippets;
22

33
use annotate_snippets::display_list::DisplayList;
4-
use annotate_snippets::snippet::{SourceAnnotation, AnnotationType, Slice, Snippet, Annotation};
4+
use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation};
55

66
fn main() {
77
let snippet = Snippet {
@@ -11,25 +11,25 @@ fn main() {
1111
annotation_type: AnnotationType::Error,
1212
}),
1313
footer: Some(Annotation {
14-
label: Some("foo".to_string()),
14+
label: Some(
15+
"expected type: `snippet::Annotation`\n found type: `__&__snippet::Annotation`"
16+
.to_string(),
17+
),
1518
id: None,
1619
annotation_type: AnnotationType::Note,
1720
}),
18-
slices: vec![
19-
Slice {
20-
source: " slices: vec![\"A\",".to_string(),
21-
line_start: 13,
22-
origin: Some("src/multislice.rs".to_string()),
23-
fold: false,
24-
annotations: vec![
25-
SourceAnnotation {
26-
label: "expected struct `annotate_snippets::snippet::Slice`, found reference".to_string(),
27-
annotation_type: AnnotationType::Error,
28-
range: (22, 25),
29-
},
30-
],
31-
},
32-
],
21+
slices: vec![Slice {
22+
source: " slices: vec![\"A\",".to_string(),
23+
line_start: 13,
24+
origin: Some("src/multislice.rs".to_string()),
25+
fold: false,
26+
annotations: vec![SourceAnnotation {
27+
label: "expected struct `annotate_snippets::snippet::Slice`, found reference"
28+
.to_string(),
29+
annotation_type: AnnotationType::Error,
30+
range: (22, 25),
31+
}],
32+
}],
3333
};
3434

3535
println!("{}", DisplayList::from(snippet));

examples/format.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
extern crate annotate_snippets;
22

33
use annotate_snippets::display_list::DisplayList;
4-
use annotate_snippets::snippet::{SourceAnnotation, AnnotationType, Slice, Snippet, Annotation};
4+
use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation};
55

66
fn main() {
77
let snippet = Snippet {

examples/multislice.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
extern crate annotate_snippets;
22

33
use annotate_snippets::display_list::DisplayList;
4-
use annotate_snippets::snippet::{AnnotationType, Slice, Snippet, Annotation};
4+
use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet};
55

66
fn main() {
77
let snippet = Snippet {

src/display_list.rs

+60-18
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
1-
use snippet::{AnnotationType, Slice, Snippet, Annotation};
1+
use snippet::{Annotation, AnnotationType, Slice, Snippet};
22

33
pub struct DisplayList {
44
pub body: Vec<DisplayLine>,
55
}
66

77
#[derive(Debug, Clone, PartialEq)]
88
pub enum DisplayLine {
9-
AlignedAnnotation {
10-
label: String,
11-
annotation_type: DisplayAnnotationType,
12-
},
139
Annotation {
14-
label: String,
10+
label: Vec<DisplayTextFragment>,
1511
id: Option<String>,
12+
aligned: bool,
1613
annotation_type: DisplayAnnotationType,
1714
},
1815
Origin {
@@ -30,7 +27,7 @@ pub enum DisplayLine {
3027
SourceAnnotation {
3128
inline_marks: Vec<DisplayMark>,
3229
range: (usize, usize),
33-
label: Option<String>,
30+
label: Vec<DisplayTextFragment>,
3431
annotation_type: DisplayAnnotationType,
3532
annotation_part: DisplayAnnotationPart,
3633
},
@@ -39,6 +36,18 @@ pub enum DisplayLine {
3936
},
4037
}
4138

39+
#[derive(Debug, Clone, PartialEq)]
40+
pub struct DisplayTextFragment {
41+
pub content: String,
42+
pub style: DisplayTextStyle,
43+
}
44+
45+
#[derive(Debug, Clone, Copy, PartialEq)]
46+
pub enum DisplayTextStyle {
47+
Regular,
48+
Emphasis,
49+
}
50+
4251
#[derive(Debug, Clone, PartialEq)]
4352
pub enum DisplayAnnotationPart {
4453
Singleline,
@@ -68,25 +77,52 @@ pub enum DisplayHeaderType {
6877

6978
// Formatting
7079

80+
fn format_label(label: Option<&str>, style: Option<DisplayTextStyle>) -> Vec<DisplayTextFragment> {
81+
let mut result = vec![];
82+
if let Some(label) = label {
83+
let elements: Vec<&str> = label.split("__").collect();
84+
let mut idx = 0;
85+
for element in elements {
86+
let element_style = match style {
87+
Some(s) => s,
88+
None => if idx % 2 == 0 {
89+
DisplayTextStyle::Regular
90+
} else {
91+
DisplayTextStyle::Emphasis
92+
},
93+
};
94+
result.push(DisplayTextFragment {
95+
content: element.to_string(),
96+
style: element_style,
97+
});
98+
idx += 1;
99+
}
100+
}
101+
return result;
102+
}
103+
71104
fn format_title(annotation: &Annotation) -> DisplayLine {
72105
let label = annotation.label.clone().unwrap_or("".to_string());
73106
DisplayLine::Annotation {
74107
annotation_type: DisplayAnnotationType::from(annotation.annotation_type),
75108
id: annotation.id.clone(),
76-
label,
109+
aligned: false,
110+
label: format_label(Some(&label), Some(DisplayTextStyle::Emphasis)),
77111
}
78112
}
79113

80114
fn format_annotation(annotation: &Annotation) -> DisplayLine {
81115
let label = annotation.label.clone().unwrap_or("".to_string());
82-
DisplayLine::AlignedAnnotation {
116+
DisplayLine::Annotation {
83117
annotation_type: DisplayAnnotationType::from(annotation.annotation_type),
84-
label,
118+
aligned: true,
119+
id: None,
120+
label: format_label(Some(&label), None),
85121
}
86122
}
87123

88-
fn format_slice(slice: &Slice, is_first: bool) -> Vec<DisplayLine> {
89-
let mut body = format_body(slice);
124+
fn format_slice(slice: &Slice, is_first: bool, has_footer: bool) -> Vec<DisplayLine> {
125+
let mut body = format_body(slice, has_footer);
90126
let mut result = vec![];
91127

92128
let header = format_header(slice, &body, is_first);
@@ -185,7 +221,7 @@ fn fold_body(body: &[DisplayLine]) -> Vec<DisplayLine> {
185221
return new_body;
186222
}
187223

188-
fn format_body(slice: &Slice) -> Vec<DisplayLine> {
224+
fn format_body(slice: &Slice, has_footer: bool) -> Vec<DisplayLine> {
189225
let mut body = vec![];
190226

191227
let mut current_line = slice.line_start;
@@ -221,7 +257,7 @@ fn format_body(slice: &Slice) -> Vec<DisplayLine> {
221257
DisplayLine::SourceAnnotation {
222258
inline_marks: vec![],
223259
range,
224-
label: Some(annotation.label.clone()),
260+
label: format_label(Some(&annotation.label), None),
225261
annotation_type: DisplayAnnotationType::from(
226262
annotation.annotation_type,
227263
),
@@ -247,7 +283,7 @@ fn format_body(slice: &Slice) -> Vec<DisplayLine> {
247283
DisplayLine::SourceAnnotation {
248284
inline_marks: vec![],
249285
range,
250-
label: None,
286+
label: vec![],
251287
annotation_type: DisplayAnnotationType::from(
252288
annotation.annotation_type,
253289
),
@@ -282,7 +318,7 @@ fn format_body(slice: &Slice) -> Vec<DisplayLine> {
282318
DisplayLine::SourceAnnotation {
283319
inline_marks: vec![DisplayMark::AnnotationThrough],
284320
range,
285-
label: Some(annotation.label.clone()),
321+
label: format_label(Some(&annotation.label), None),
286322
annotation_type: DisplayAnnotationType::from(
287323
annotation.annotation_type,
288324
),
@@ -302,7 +338,9 @@ fn format_body(slice: &Slice) -> Vec<DisplayLine> {
302338
}
303339

304340
body.insert(0, DisplayLine::EmptySource);
305-
if let Some(DisplayLine::Source { .. }) = body.last() {
341+
if has_footer {
342+
body.push(DisplayLine::EmptySource);
343+
} else if let Some(DisplayLine::Source { .. }) = body.last() {
306344
body.push(DisplayLine::EmptySource);
307345
}
308346
body
@@ -317,7 +355,11 @@ impl From<Snippet> for DisplayList {
317355

318356
let mut slice_idx = 0;
319357
for slice in snippet.slices {
320-
body.append(&mut format_slice(&slice, slice_idx == 0));
358+
body.append(&mut format_slice(
359+
&slice,
360+
slice_idx == 0,
361+
snippet.footer.is_some(),
362+
));
321363
slice_idx += 1;
322364
}
323365
if let Some(annotation) = snippet.footer {

src/display_list_formatting.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use display_list::{DisplayLine, DisplayMark, DisplayAnnotationType, DisplayAnnotationPart};
1+
use display_list::{DisplayAnnotationPart, DisplayAnnotationType, DisplayLine, DisplayMark,
2+
DisplayTextFragment};
23
use std::fmt;
34

45
pub trait DisplayListFormatting {
@@ -8,11 +9,13 @@ pub trait DisplayListFormatting {
89

910
fn format_annotation_content(
1011
range: &(usize, usize),
11-
label: &Option<String>,
12+
label: &[DisplayTextFragment],
1213
annotation_type: &DisplayAnnotationType,
1314
annotation_part: &DisplayAnnotationPart,
1415
) -> String;
1516

17+
fn format_label(label: &[DisplayTextFragment]) -> String;
18+
1619
fn format_line(
1720
f: &mut fmt::Formatter,
1821
dl: &DisplayLine,

src/format.rs

+37-25
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use display_list::{DisplayAnnotationType, DisplayLine, DisplayList, DisplayMark,
2-
DisplayAnnotationPart, DisplayHeaderType};
1+
use display_list::{DisplayAnnotationPart, DisplayAnnotationType, DisplayHeaderType, DisplayLine,
2+
DisplayList, DisplayMark, DisplayTextFragment};
33
use display_list_formatting::DisplayListFormatting;
44
use std::fmt;
55

@@ -32,29 +32,42 @@ impl DisplayListFormatting for Formatter {
3232

3333
fn format_annotation_content(
3434
range: &(usize, usize),
35-
label: &Option<String>,
35+
label: &[DisplayTextFragment],
3636
annotation_type: &DisplayAnnotationType,
3737
annotation_part: &DisplayAnnotationPart,
3838
) -> String {
39-
let label = label.clone().map_or("".to_string(), |l| format!(" {}", l));
39+
let label = if label.is_empty() {
40+
"".to_string()
41+
} else {
42+
format!(" {}", Self::format_label(label))
43+
};
4044
let prefix = match annotation_part {
4145
DisplayAnnotationPart::Singleline => " ",
4246
DisplayAnnotationPart::MultilineStart => "_",
4347
DisplayAnnotationPart::MultilineEnd => "_",
44-
};
48+
};
4549
let mark = match annotation_type {
4650
DisplayAnnotationType::Error => "^",
4751
DisplayAnnotationType::Warning => "-",
4852
DisplayAnnotationType::Note => "-",
4953
DisplayAnnotationType::Help => "-",
5054
};
51-
format!("{}{}{}",
52-
prefix.repeat(range.0),
53-
mark.repeat(range.1 - range.0),
54-
label,
55+
format!(
56+
"{}{}{}",
57+
prefix.repeat(range.0),
58+
mark.repeat(range.1 - range.0),
59+
label,
5560
)
5661
}
5762

63+
fn format_label(label: &[DisplayTextFragment]) -> String {
64+
label
65+
.iter()
66+
.map(|fragment| fragment.content.as_str())
67+
.collect::<Vec<&str>>()
68+
.join("")
69+
}
70+
5871
fn format_line(
5972
f: &mut fmt::Formatter,
6073
dl: &DisplayLine,
@@ -65,18 +78,25 @@ impl DisplayListFormatting for Formatter {
6578
DisplayLine::Annotation {
6679
annotation_type,
6780
id,
81+
aligned,
6882
label,
6983
} => {
7084
let name = if let Some(id) = id {
7185
format!("{}[{}]", Self::format_annotation_type(&annotation_type), id)
7286
} else {
7387
Self::format_annotation_type(&annotation_type)
7488
};
89+
let prefix = if *aligned {
90+
format!("{} = ", " ".repeat(lineno_width))
91+
} else {
92+
"".to_string()
93+
};
7594
writeln!(
7695
f,
77-
"{}{}",
96+
"{}{}{}",
97+
prefix,
7898
name,
79-
format!(": {}", label)
99+
format!(": {}", Self::format_label(label))
80100
)
81101
}
82102
DisplayLine::Origin {
@@ -129,27 +149,19 @@ impl DisplayListFormatting for Formatter {
129149
"{}{}{}",
130150
prefix,
131151
Self::format_inline_marks(&inline_marks, inline_marks_width),
132-
Self::format_annotation_content(range, &label, &annotation_type, &annotation_part),
152+
Self::format_annotation_content(
153+
range,
154+
&label,
155+
&annotation_type,
156+
&annotation_part
157+
),
133158
)
134159
}
135160
DisplayLine::Fold { inline_marks } => writeln!(
136161
f,
137162
"... {}",
138163
Self::format_inline_marks(&inline_marks, inline_marks_width),
139164
),
140-
DisplayLine::AlignedAnnotation {
141-
label,
142-
annotation_type,
143-
} => {
144-
let prefix = format!("{} =", " ".repeat(lineno_width));
145-
writeln!(
146-
f,
147-
"{} {}: {}",
148-
prefix,
149-
Self::format_annotation_type(annotation_type),
150-
label
151-
)
152-
}
153165
}
154166
}
155167
}

0 commit comments

Comments
 (0)