1pub(crate) fn is_built_in_context(context: &str) -> bool {
2 BuiltInContext::from_str(context).is_some()
3}
4
5#[derive(Clone, Copy, Eq, PartialEq, Hash)]
24#[non_exhaustive]
25pub enum BuiltInContext {
26 Admonition,
28
29 Audio,
31
32 Colist,
34
35 Dlist,
37
38 Document,
40
41 Example,
43
44 FloatingTitle,
46
47 Image,
49
50 ListItem,
52
53 Listing,
55
56 Literal,
58
59 Olist,
61
62 Open,
64
65 PageBreak,
67
68 Paragraph,
70
71 Pass,
73
74 Preamble,
76
77 Quote,
79
80 Section,
82
83 Sidebar,
85
86 Stem,
88
89 Table,
91
92 TableCell,
94
95 ThematicBreak,
97
98 Toc,
100
101 Ulist,
103
104 Verse,
106
107 Video,
109}
110
111impl BuiltInContext {
112 pub const ALL: &'static [BuiltInContext] = &[
117 Self::Admonition,
118 Self::Audio,
119 Self::Colist,
120 Self::Dlist,
121 Self::Document,
122 Self::Example,
123 Self::FloatingTitle,
124 Self::Image,
125 Self::ListItem,
126 Self::Listing,
127 Self::Literal,
128 Self::Olist,
129 Self::Open,
130 Self::PageBreak,
131 Self::Paragraph,
132 Self::Pass,
133 Self::Preamble,
134 Self::Quote,
135 Self::Section,
136 Self::Sidebar,
137 Self::Stem,
138 Self::Table,
139 Self::TableCell,
140 Self::ThematicBreak,
141 Self::Toc,
142 Self::Ulist,
143 Self::Verse,
144 Self::Video,
145 ];
146
147 pub fn as_str(self) -> &'static str {
155 match self {
156 Self::Admonition => "admonition",
157 Self::Audio => "audio",
158 Self::Colist => "colist",
159 Self::Dlist => "dlist",
160 Self::Document => "document",
161 Self::Example => "example",
162 Self::FloatingTitle => "floating_title",
163 Self::Image => "image",
164 Self::ListItem => "list_item",
165 Self::Listing => "listing",
166 Self::Literal => "literal",
167 Self::Olist => "olist",
168 Self::Open => "open",
169 Self::PageBreak => "page_break",
170 Self::Paragraph => "paragraph",
171 Self::Pass => "pass",
172 Self::Preamble => "preamble",
173 Self::Quote => "quote",
174 Self::Section => "section",
175 Self::Sidebar => "sidebar",
176 Self::Stem => "stem",
177 Self::Table => "table",
178 Self::TableCell => "table_cell",
179 Self::ThematicBreak => "thematic_break",
180 Self::Toc => "toc",
181 Self::Ulist => "ulist",
182 Self::Verse => "verse",
183 Self::Video => "video",
184 }
185 }
186
187 #[allow(clippy::should_implement_trait)]
195 pub fn from_str(context: &str) -> Option<Self> {
196 Some(match context {
197 "admonition" => Self::Admonition,
198 "audio" => Self::Audio,
199 "colist" => Self::Colist,
200 "dlist" => Self::Dlist,
201 "document" => Self::Document,
202 "example" => Self::Example,
203 "floating_title" => Self::FloatingTitle,
204 "image" => Self::Image,
205 "list_item" => Self::ListItem,
206 "listing" => Self::Listing,
207 "literal" => Self::Literal,
208 "olist" => Self::Olist,
209 "open" => Self::Open,
210 "page_break" => Self::PageBreak,
211 "paragraph" => Self::Paragraph,
212 "pass" => Self::Pass,
213 "preamble" => Self::Preamble,
214 "quote" => Self::Quote,
215 "section" => Self::Section,
216 "sidebar" => Self::Sidebar,
217 "stem" => Self::Stem,
218 "table" => Self::Table,
219 "table_cell" => Self::TableCell,
220 "thematic_break" => Self::ThematicBreak,
221 "toc" => Self::Toc,
222 "ulist" => Self::Ulist,
223 "verse" => Self::Verse,
224 "video" => Self::Video,
225 _ => return None,
226 })
227 }
228}
229
230impl std::fmt::Debug for BuiltInContext {
231 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
232 write!(f, "BuiltInContext::{}", {
233 match self {
234 Self::Admonition => "Admonition",
235 Self::Audio => "Audio",
236 Self::Colist => "Colist",
237 Self::Dlist => "Dlist",
238 Self::Document => "Document",
239 Self::Example => "Example",
240 Self::FloatingTitle => "FloatingTitle",
241 Self::Image => "Image",
242 Self::ListItem => "ListItem",
243 Self::Listing => "Listing",
244 Self::Literal => "Literal",
245 Self::Olist => "Olist",
246 Self::Open => "Open",
247 Self::PageBreak => "PageBreak",
248 Self::Paragraph => "Paragraph",
249 Self::Pass => "Pass",
250 Self::Preamble => "Preamble",
251 Self::Quote => "Quote",
252 Self::Section => "Section",
253 Self::Sidebar => "Sidebar",
254 Self::Stem => "Stem",
255 Self::Table => "Table",
256 Self::TableCell => "TableCell",
257 Self::ThematicBreak => "ThematicBreak",
258 Self::Toc => "Toc",
259 Self::Ulist => "Ulist",
260 Self::Verse => "Verse",
261 Self::Video => "Video",
262 }
263 })
264 }
265}
266
267#[derive(Clone, Copy, Eq, PartialEq)]
275pub enum AdmonitionVariant {
276 Note,
278
279 Tip,
281
282 Important,
284
285 Caution,
287
288 Warning,
290}
291
292impl AdmonitionVariant {
293 pub(crate) fn from_style(style: &str) -> Option<Self> {
299 Some(match style {
300 "NOTE" => Self::Note,
301 "TIP" => Self::Tip,
302 "IMPORTANT" => Self::Important,
303 "CAUTION" => Self::Caution,
304 "WARNING" => Self::Warning,
305 _ => return None,
306 })
307 }
308
309 pub fn style(self) -> &'static str {
311 match self {
312 Self::Note => "NOTE",
313 Self::Tip => "TIP",
314 Self::Important => "IMPORTANT",
315 Self::Caution => "CAUTION",
316 Self::Warning => "WARNING",
317 }
318 }
319
320 pub fn name(self) -> &'static str {
325 match self {
326 Self::Note => "note",
327 Self::Tip => "tip",
328 Self::Important => "important",
329 Self::Caution => "caution",
330 Self::Warning => "warning",
331 }
332 }
333
334 pub fn default_caption(self) -> &'static str {
340 match self {
341 Self::Note => "Note",
342 Self::Tip => "Tip",
343 Self::Important => "Important",
344 Self::Caution => "Caution",
345 Self::Warning => "Warning",
346 }
347 }
348}
349
350impl std::fmt::Debug for AdmonitionVariant {
351 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
352 match self {
353 Self::Note => write!(f, "AdmonitionVariant::Note"),
354 Self::Tip => write!(f, "AdmonitionVariant::Tip"),
355 Self::Important => write!(f, "AdmonitionVariant::Important"),
356 Self::Caution => write!(f, "AdmonitionVariant::Caution"),
357 Self::Warning => write!(f, "AdmonitionVariant::Warning"),
358 }
359 }
360}
361
362#[cfg(test)]
363mod tests {
364 mod built_in_context {
365 use crate::blocks::{BuiltInContext, context::is_built_in_context};
366
367 #[test]
368 fn round_trips_every_variant() {
369 for &context in BuiltInContext::ALL {
372 assert_eq!(BuiltInContext::from_str(context.as_str()), Some(context));
373 assert!(is_built_in_context(context.as_str()));
374 }
375 }
376
377 #[test]
378 fn all_is_complete_and_deduplicated() {
379 assert_eq!(BuiltInContext::ALL.len(), 28);
381
382 let mut seen: Vec<&str> = BuiltInContext::ALL.iter().map(|c| c.as_str()).collect();
383 seen.sort_unstable();
384 seen.dedup();
385 assert_eq!(seen.len(), BuiltInContext::ALL.len());
386 }
387
388 #[test]
389 fn known_contexts() {
390 assert_eq!(
391 BuiltInContext::from_str("paragraph"),
392 Some(BuiltInContext::Paragraph)
393 );
394 assert_eq!(BuiltInContext::Listing.as_str(), "listing");
395 assert_eq!(BuiltInContext::TableCell.as_str(), "table_cell");
396 }
397
398 #[test]
399 fn unknown_context_is_none() {
400 assert_eq!(BuiltInContext::from_str("verbatim"), None);
401 assert_eq!(BuiltInContext::from_str("Paragraph"), None);
403 assert!(!is_built_in_context("not-a-context"));
404 }
405
406 #[test]
407 fn impl_debug() {
408 assert_eq!(
410 format!("{:?}", BuiltInContext::FloatingTitle),
411 "BuiltInContext::FloatingTitle"
412 );
413
414 let mut seen = std::collections::HashSet::new();
417 for &context in BuiltInContext::ALL {
418 let debug = format!("{context:?}");
419 assert!(debug.starts_with("BuiltInContext::"));
420 assert!(!debug.contains(' '));
421 assert!(seen.insert(debug), "duplicate Debug rendering");
422 }
423 assert_eq!(seen.len(), BuiltInContext::ALL.len());
424 }
425 }
426}