Skip to content

Commit 6c5002a

Browse files
author
Zibi Braniecki
committed
Support multislice in a single snippet
1 parent 27f9dec commit 6c5002a

File tree

10 files changed

+240
-269
lines changed

10 files changed

+240
-269
lines changed

examples/format.rs

+15-15
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, Tit
55

66
fn main() {
77
let snippet = Snippet {
8-
slice: Slice {
8+
slices: vec![Slice {
99
source: r#") -> Option<String> {
1010
for ann in annotations {
1111
match (ann.range.0, ann.range.1) {
@@ -30,25 +30,25 @@ fn main() {
3030
}"#.to_string(),
3131
line_start: 51,
3232
origin: Some("src/format.rs".to_string()),
33-
},
33+
fold: true,
34+
annotations: vec![
35+
Annotation {
36+
label: "expected `Option<String>` because of return type".to_string(),
37+
annotation_type: AnnotationType::Warning,
38+
range: (6, 20),
39+
},
40+
Annotation {
41+
label: "expected enum `std::option::Option".to_string(),
42+
annotation_type: AnnotationType::Error,
43+
range: (23, 746),
44+
},
45+
],
46+
}],
3447
title: Some(TitleAnnotation {
3548
label: Some("mismatched types".to_string()),
3649
id: Some("E0308".to_string()),
3750
annotation_type: AnnotationType::Error,
3851
}),
39-
fold: Some(true),
40-
annotations: vec![
41-
Annotation {
42-
label: "expected `Option<String>` because of return type".to_string(),
43-
annotation_type: AnnotationType::Warning,
44-
range: (6, 20),
45-
},
46-
Annotation {
47-
label: "expected enum `std::option::Option".to_string(),
48-
annotation_type: AnnotationType::Error,
49-
range: (23, 746),
50-
},
51-
],
5252
};
5353

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

examples/multislice.rs

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
extern crate annotate_snippets;
2+
3+
use annotate_snippets::display_list::DisplayList;
4+
use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, TitleAnnotation};
5+
6+
fn main() {
7+
let snippet = Snippet {
8+
title: Some(TitleAnnotation {
9+
label: Some("mismatched types".to_string()),
10+
id: None,
11+
annotation_type: AnnotationType::Error,
12+
}),
13+
slices: vec![
14+
Slice {
15+
source: "Foo".to_string(),
16+
line_start: 51,
17+
origin: Some("src/format.rs".to_string()),
18+
fold: false,
19+
annotations: vec![],
20+
},
21+
Slice {
22+
source: "Faa".to_string(),
23+
line_start: 129,
24+
origin: Some("src/display.rs".to_string()),
25+
fold: false,
26+
annotations: vec![],
27+
},
28+
],
29+
};
30+
31+
println!("{}", DisplayList::from(snippet));
32+
}

src/display_list.rs

+64-91
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,4 @@
1-
//! `DisplayList` is an intermittent structure which converts the Snippet structure
2-
//! into a list of lines that resemble the final output.
3-
//!
4-
//! # Example:
5-
//!
6-
//! ```
7-
//! use annotate_snippets::snippet::{Snippet, Slice, Annotation, TitleAnnotation, AnnotationType};
8-
//! use annotate_snippets::display_list::{DisplayList, DisplayLine, DisplayAnnotationType,
9-
//! DisplaySnippetType};
10-
//!
11-
//! let snippet = Snippet {
12-
//! slice: Slice {
13-
//! source: "id: Option<>,\nlabel: Option<String>".to_string(),
14-
//! line_start: 145,
15-
//! origin: Some("src/display_list.rs".to_string())
16-
//! },
17-
//! title: Some(TitleAnnotation {
18-
//! id: Some("E0061".to_string()),
19-
//! label: Some("this function takes 1 parameter but 0 parameters were supplied".to_string()),
20-
//! annotation_type: AnnotationType::Error,
21-
//! }),
22-
//! fold: Some(false),
23-
//! annotations: vec![
24-
//! Annotation {
25-
//! label: "expected 1 parameter".to_string(),
26-
//! annotation_type: AnnotationType::Error,
27-
//! range: (4, 12)
28-
//! }
29-
//! ]
30-
//! };
31-
//! assert_eq!(DisplayList::from(snippet).body, vec![
32-
//! DisplayLine::Description {
33-
//! snippet_type: DisplaySnippetType::Error,
34-
//! id: Some("E0061".to_string()),
35-
//! label: "this function takes 1 parameter but 0 parameters were supplied".to_string(),
36-
//! },
37-
//! DisplayLine::Origin {
38-
//! path: "src/display_list.rs".to_string(),
39-
//! row: 145,
40-
//! col: 4,
41-
//! },
42-
//! DisplayLine::EmptySource,
43-
//! DisplayLine::Source {
44-
//! lineno: 145,
45-
//! inline_marks: vec![],
46-
//! content: "id: Option<>,".to_string(),
47-
//! range: (0, 14)
48-
//! },
49-
//! DisplayLine::Annotation {
50-
//! label: Some("expected 1 parameter".to_string()),
51-
//! range: (4, 12),
52-
//! inline_marks: vec![],
53-
//! annotation_type: DisplayAnnotationType::Error,
54-
//! },
55-
//! DisplayLine::Source {
56-
//! lineno: 146,
57-
//! inline_marks: vec![],
58-
//! content: "label: Option<String>".to_string(),
59-
//! range: (15, 37)
60-
//! },
61-
//! DisplayLine::EmptySource
62-
//! ]);
63-
//! ```
64-
use snippet::{AnnotationType, Snippet};
1+
use snippet::{AnnotationType, Slice, Snippet, TitleAnnotation};
652

663
pub struct DisplayList {
674
pub body: Vec<DisplayLine>,
@@ -76,8 +13,8 @@ pub enum DisplayLine {
7613
},
7714
Origin {
7815
path: String,
79-
row: usize,
80-
col: usize,
16+
pos: Option<(usize, usize)>,
17+
header_type: DisplayHeaderType,
8118
},
8219
EmptySource,
8320
Source {
@@ -117,25 +54,47 @@ pub enum DisplaySnippetType {
11754
Warning,
11855
}
11956

57+
#[derive(Debug, Clone, PartialEq)]
58+
pub enum DisplayHeaderType {
59+
Initial,
60+
Continuation,
61+
}
62+
12063
// Formatting
12164

122-
fn format_header(snippet: &Snippet, body: &[DisplayLine]) -> Vec<DisplayLine> {
123-
let mut header = vec![];
65+
fn format_title(annotation: &TitleAnnotation) -> DisplayLine {
66+
let label = annotation.label.clone().unwrap_or("".to_string());
67+
DisplayLine::Description {
68+
snippet_type: DisplaySnippetType::from(annotation.annotation_type),
69+
id: annotation.id.clone(),
70+
label,
71+
}
72+
}
73+
74+
fn format_slice(slice: &Slice, is_first: bool) -> Vec<DisplayLine> {
75+
let mut body = format_body(slice);
76+
let mut result = vec![];
12477

125-
if let Some(ref annotation) = snippet.title {
126-
let label = annotation.label.clone().unwrap_or("".to_string());
127-
header.push(DisplayLine::Description {
128-
snippet_type: DisplaySnippetType::from(annotation.annotation_type),
129-
id: annotation.id.clone(),
130-
label,
131-
})
78+
let header = format_header(slice, &body, is_first);
79+
if let Some(header) = header {
80+
result.push(header);
13281
}
82+
result.append(&mut body);
83+
result
84+
}
13385

134-
let main_annotation = snippet.annotations.get(0);
86+
fn format_header(slice: &Slice, body: &[DisplayLine], is_first: bool) -> Option<DisplayLine> {
87+
let main_annotation = slice.annotations.get(0);
88+
89+
let display_header = if is_first {
90+
DisplayHeaderType::Initial
91+
} else {
92+
DisplayHeaderType::Continuation
93+
};
13594

13695
if let Some(annotation) = main_annotation {
13796
let mut col = 1;
138-
let mut row = snippet.slice.line_start;
97+
let mut row = slice.line_start;
13998

14099
for idx in 0..body.len() {
141100
if let DisplayLine::Source { range, .. } = body[idx] {
@@ -146,15 +105,23 @@ fn format_header(snippet: &Snippet, body: &[DisplayLine]) -> Vec<DisplayLine> {
146105
row += 1;
147106
}
148107
}
149-
if let Some(ref path) = snippet.slice.origin {
150-
header.push(DisplayLine::Origin {
108+
if let Some(ref path) = slice.origin {
109+
return Some(DisplayLine::Origin {
110+
path: path.to_string(),
111+
pos: Some((row, col)),
112+
header_type: display_header,
113+
});
114+
}
115+
} else {
116+
if let Some(ref path) = slice.origin {
117+
return Some(DisplayLine::Origin {
151118
path: path.to_string(),
152-
row,
153-
col,
119+
pos: None,
120+
header_type: display_header,
154121
});
155122
}
156123
}
157-
header
124+
None
158125
}
159126

160127
fn fold_body(body: &[DisplayLine]) -> Vec<DisplayLine> {
@@ -204,14 +171,14 @@ fn fold_body(body: &[DisplayLine]) -> Vec<DisplayLine> {
204171
return new_body;
205172
}
206173

207-
fn format_body(snippet: &Snippet) -> Vec<DisplayLine> {
174+
fn format_body(slice: &Slice) -> Vec<DisplayLine> {
208175
let mut body = vec![];
209176

210-
let mut current_line = snippet.slice.line_start;
177+
let mut current_line = slice.line_start;
211178
let mut current_index = 0;
212179
let mut line_index_ranges = vec![];
213180

214-
for line in snippet.slice.source.lines() {
181+
for line in slice.source.lines() {
215182
let line_length = line.chars().count() + 1;
216183
let line_range = (current_index, current_index + line_length);
217184
body.push(DisplayLine::Source {
@@ -226,7 +193,7 @@ fn format_body(snippet: &Snippet) -> Vec<DisplayLine> {
226193
}
227194

228195
let mut annotation_line_count = 0;
229-
let mut annotations = snippet.annotations.clone();
196+
let mut annotations = slice.annotations.clone();
230197
for idx in 0..body.len() {
231198
let (line_start, line_end) = line_index_ranges[idx];
232199
annotations.drain_filter(|annotation| {
@@ -309,7 +276,7 @@ fn format_body(snippet: &Snippet) -> Vec<DisplayLine> {
309276
});
310277
}
311278

312-
if snippet.fold.unwrap_or(false) {
279+
if slice.fold {
313280
body = fold_body(&body);
314281
}
315282

@@ -322,12 +289,18 @@ fn format_body(snippet: &Snippet) -> Vec<DisplayLine> {
322289

323290
impl From<Snippet> for DisplayList {
324291
fn from(snippet: Snippet) -> Self {
325-
let body = format_body(&snippet);
326-
let header = format_header(&snippet, &body);
292+
let mut body = vec![];
293+
if let Some(annotation) = snippet.title {
294+
body.push(format_title(&annotation));
295+
}
327296

328-
Self {
329-
body: vec![&header[..], &body[..]].concat(),
297+
let mut slice_idx = 0;
298+
for slice in snippet.slices {
299+
body.append(&mut format_slice(&slice, slice_idx == 0));
300+
slice_idx += 1;
330301
}
302+
303+
Self { body }
331304
}
332305
}
333306

src/format.rs

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

@@ -85,14 +85,29 @@ impl DisplayListFormatting for Formatter {
8585
id: None,
8686
label,
8787
} => writeln!(f, "{}: {}", Self::format_snippet_type(&snippet_type), label),
88-
DisplayLine::Origin { path, row, col } => writeln!(
89-
f,
90-
"{}--> {}:{}:{}",
91-
" ".repeat(lineno_width),
88+
DisplayLine::Origin {
9289
path,
93-
row,
94-
col
95-
),
90+
pos,
91+
header_type,
92+
} => {
93+
let header_sigil = match header_type {
94+
DisplayHeaderType::Initial => "-->",
95+
DisplayHeaderType::Continuation => ":::",
96+
};
97+
if let Some((row, col)) = pos {
98+
writeln!(
99+
f,
100+
"{}{} {}:{}:{}",
101+
" ".repeat(lineno_width),
102+
header_sigil,
103+
path,
104+
row,
105+
col
106+
)
107+
} else {
108+
writeln!(f, "{}{} {}", " ".repeat(lineno_width), header_sigil, path,)
109+
}
110+
}
96111
DisplayLine::EmptySource => writeln!(f, "{} |", " ".repeat(lineno_width)),
97112
DisplayLine::Source {
98113
lineno,

0 commit comments

Comments
 (0)