1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
use annotate_snippets::{
display_list::DisplayList,
formatter::DisplayListFormatter,
snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation},
};
use crate::syntax::Span;
#[derive(Debug, Clone)]
pub struct ErrorBuilder {
message: String,
annotation_type: AnnotationType,
annotations: Vec<BuilderAnnotation>,
}
#[derive(Debug, Clone)]
struct BuilderAnnotation {
span: Span,
message: String,
annotation_type: AnnotationType,
}
/// A builder that uses the annotate_snippets library to display nice error messages about source
/// code locations.
impl ErrorBuilder {
pub fn new(message: String) -> Self {
ErrorBuilder {
message,
annotation_type: AnnotationType::Error,
annotations: Vec::new(),
}
}
pub fn span_err(span: &Span, message: String) -> Self {
let mut builder = Self::new(message.clone());
builder.annotate_err(span, message);
builder
}
pub fn annotate_err(&mut self, span: &Span, message: String) {
self.annotations.push(BuilderAnnotation {
span: span.clone(),
message,
annotation_type: AnnotationType::Error,
})
}
pub fn annotate_info(&mut self, span: &Span, message: String) {
self.annotations.push(BuilderAnnotation {
span: span.clone(),
message,
annotation_type: AnnotationType::Help,
})
}
// TODO: handle multiple files
pub fn format(self) -> String {
let mut input = None;
let annotations = self
.annotations
.into_iter()
.filter_map(|annot| {
let span = match annot.span {
Span::Parsed(span) => span,
_ => return None,
};
if input.is_none() {
input = Some(span.to_input());
}
Some(SourceAnnotation {
label: annot.message,
annotation_type: annot.annotation_type,
range: span.as_char_range(),
})
})
.collect();
let input = match input {
Some(input) => input,
None => return format!("[unknown location] {}", self.message),
};
let snippet = Snippet {
title: Some(Annotation {
label: Some(self.message),
id: None,
annotation_type: self.annotation_type,
}),
footer: vec![],
slices: vec![Slice {
source: input,
line_start: 1, // TODO
origin: Some("<current file>".to_string()),
fold: true,
annotations,
}],
};
let dl = DisplayList::from(snippet);
let dlf = DisplayListFormatter::new(true, false);
format!("{}", dlf.format(&dl))
}
}
|