annotate_snippets_builder/
lib.rs

1pub use annotate_snippets::display_list::DisplayList;
2pub use annotate_snippets::display_list::FormatOptions;
3pub use annotate_snippets::snippet::AnnotationType;
4
5use annotate_snippets::snippet::SourceAnnotation;
6use annotate_snippets::snippet::{
7	Annotation as __Annotation, Slice as __Slice, Snippet as __Snippet,
8};
9
10pub struct Snippet<'a> {
11	title: Option<__Annotation<'a>>,
12	footer: Vec<__Annotation<'a>>,
13	slices: Vec<__Slice<'a>>,
14	opt: FormatOptions,
15}
16
17impl<'a> Snippet<'a> {
18	pub const fn new() -> Self {
19		Self {
20			title: None,
21			footer: Vec::new(),
22			slices: Vec::new(),
23			opt: FormatOptions {
24				color: true,
25				anonymized_line_numbers: false,
26				margin: None,
27			},
28		}
29	}
30
31	pub const fn title(mut self, title: Annotation<'a>) -> Self {
32		self.title = Some(title.build());
33		self
34	}
35
36	pub fn add_footer(mut self, footer: Annotation<'a>) -> Self {
37		self.footer.push(footer.build());
38		self
39	}
40
41	pub fn add_slice(mut self, slice: impl SliceBuild<'a>) -> Self {
42		self.slices.push(slice.build());
43		self
44	}
45
46	pub fn format(mut self, opt: FormatOptions) -> Self {
47		self.opt = opt;
48		self
49	}
50
51	pub fn build(self) -> __Snippet<'a> {
52		__Snippet {
53			title: self.title,
54			footer: self.footer,
55			slices: self.slices,
56			opt: self.opt,
57		}
58	}
59}
60
61impl<'a> From<Snippet<'a>> for DisplayList<'a> {
62	fn from(snippet: Snippet<'a>) -> Self {
63		DisplayList::from(snippet.build())
64	}
65}
66
67pub struct Annotation<'a> {
68	id: Option<&'a str>,
69	label: Option<&'a str>,
70	annotation_type: AnnotationType,
71}
72
73impl<'a> Annotation<'a> {
74	pub const fn new(annotation_type: AnnotationType) -> Self {
75		Self {
76			id: None,
77			label: None,
78			annotation_type,
79		}
80	}
81
82	/// Identifier of the annotation. Usually error code like "E0308".
83	pub const fn id(mut self, id: &'a str) -> Self {
84		self.id = Some(id);
85		self
86	}
87
88	pub const fn label(mut self, label: &'a str) -> Self {
89		self.label = Some(label);
90		self
91	}
92
93	pub const fn build(self) -> __Annotation<'a> {
94		__Annotation {
95			id: self.id,
96			label: self.label,
97			annotation_type: self.annotation_type,
98		}
99	}
100}
101
102pub trait SliceBuild<'a> {
103	fn build(self) -> __Slice<'a>;
104}
105
106/// Structure containing the slice of text to be annotated and
107/// basic information about the location of the slice.
108///
109/// One `Slice` is meant to represent a single, continuous,
110/// slice of source code that you want to annotate.
111#[derive(Debug)]
112pub struct Slice<'a> {
113	pub source: &'a str,
114	pub line_start: usize,
115}
116
117impl<'a> Slice<'a> {
118	pub const fn origin(self, origin: &'a str) -> SliceBuilder<'a> {
119		let mut builder = SliceBuilder::new(self.source, self.line_start);
120		builder.origin = Some(origin);
121		builder
122	}
123
124	pub fn annotation(
125		self,
126		range: impl Into<(usize, usize)>,
127		annotation_type: AnnotationType,
128		label: &'a str,
129	) -> SliceBuilder<'a> {
130		SliceBuilder::new(self.source, self.line_start).annotation(range, annotation_type, label)
131	}
132
133	/// If set explicitly to `true`, the snippet will fold
134	/// parts of the slice that don't contain any annotations.
135	pub fn fold(self, fold: bool) -> SliceBuilder<'a> {
136		SliceBuilder::new(self.source, self.line_start).fold(fold)
137	}
138}
139
140impl<'a> SliceBuild<'a> for Slice<'a> {
141	fn build(self) -> __Slice<'a> {
142		SliceBuilder::new(self.source, self.line_start).build()
143	}
144}
145
146pub struct SliceBuilder<'a> {
147	source: &'a str,
148	line_start: usize,
149	origin: Option<&'a str>,
150	annotations: Vec<SourceAnnotation<'a>>,
151	fold: bool,
152}
153
154impl<'a> SliceBuilder<'a> {
155	const fn new(source: &'a str, line_start: usize) -> Self {
156		Self {
157			source,
158			line_start,
159			origin: None,
160			annotations: Vec::new(),
161			fold: false,
162		}
163	}
164
165	pub fn annotation(
166		mut self,
167		range: impl Into<(usize, usize)>,
168		annotation_type: AnnotationType,
169		label: &'a str,
170	) -> SliceBuilder<'a> {
171		self.annotations.push(SourceAnnotation {
172			annotation_type,
173			range: range.into(),
174			label,
175		});
176		self
177	}
178
179	/// If set explicitly to `true`, the snippet will fold
180	/// parts of the slice that don't contain any annotations.
181	pub const fn fold(mut self, fold: bool) -> SliceBuilder<'a> {
182		self.fold = fold;
183		self
184	}
185}
186
187impl<'a> SliceBuild<'a> for SliceBuilder<'a> {
188	fn build(self) -> __Slice<'a> {
189		__Slice {
190			source: self.source,
191			line_start: self.line_start,
192			origin: self.origin,
193			annotations: self.annotations,
194			fold: self.fold,
195		}
196	}
197}