1use crate::{
2 HasSpan, Parser, Span,
3 attributes::Attrlist,
4 blocks::{
5 AdmonitionBlock, Break, CompoundDelimitedBlock, ContentModel, IsBlock, ListBlock, ListItem,
6 ListItemMarker, MediaBlock, Preamble, QuoteBlock, RawDelimitedBlock, SectionBlock,
7 SimpleBlock, TableBlock, TocBlock, media::TargetResolution, metadata::BlockMetadata,
8 starts_with_admonition_label,
9 },
10 content::{Content, SubstitutionGroup, substitute_attributes_in_reftext},
11 document::{Attribute, InterpretedValue, RefType},
12 parser::{InlineSubstitutionRenderer, ReferenceResolver, ReferenceWarnings, XrefSignifier},
13 span::MatchedItem,
14 strings::CowStr,
15 warnings::{MatchAndWarnings, Warning, WarningType},
16};
17
18#[derive(Clone, Eq, Hash, PartialEq)]
31#[non_exhaustive]
32pub enum Block<'src> {
33 Simple(SimpleBlock<'src>),
36
37 Media(MediaBlock<'src>),
40
41 Section(SectionBlock<'src>),
44
45 List(ListBlock<'src>),
49
50 ListItem(ListItem<'src>),
53
54 RawDelimited(RawDelimitedBlock<'src>),
58
59 CompoundDelimited(CompoundDelimitedBlock<'src>),
61
62 Admonition(AdmonitionBlock<'src>),
66
67 Quote(QuoteBlock<'src>),
70
71 Table(TableBlock<'src>),
73
74 Preamble(Preamble<'src>),
77
78 Break(Break<'src>),
80
81 Toc(TocBlock<'src>),
84
85 DocumentAttribute(Attribute<'src>),
88}
89
90impl<'src> std::fmt::Debug for Block<'src> {
91 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92 match self {
93 Block::Simple(block) => f.debug_tuple("Block::Simple").field(block).finish(),
94 Block::Media(block) => f.debug_tuple("Block::Media").field(block).finish(),
95 Block::Section(block) => f.debug_tuple("Block::Section").field(block).finish(),
96 Block::List(block) => f.debug_tuple("Block::List").field(block).finish(),
97 Block::ListItem(block) => f.debug_tuple("Block::ListItem").field(block).finish(),
98
99 Block::RawDelimited(block) => {
100 f.debug_tuple("Block::RawDelimited").field(block).finish()
101 }
102
103 Block::CompoundDelimited(block) => f
104 .debug_tuple("Block::CompoundDelimited")
105 .field(block)
106 .finish(),
107
108 Block::Admonition(block) => f.debug_tuple("Block::Admonition").field(block).finish(),
109 Block::Quote(block) => f.debug_tuple("Block::Quote").field(block).finish(),
110 Block::Table(block) => f.debug_tuple("Block::Table").field(block).finish(),
111 Block::Preamble(block) => f.debug_tuple("Block::Preamble").field(block).finish(),
112 Block::Break(break_) => f.debug_tuple("Block::Break").field(break_).finish(),
113 Block::Toc(block) => f.debug_tuple("Block::Toc").field(block).finish(),
114
115 Block::DocumentAttribute(block) => f
116 .debug_tuple("Block::DocumentAttribute")
117 .field(block)
118 .finish(),
119 }
120 }
121}
122
123#[allow(clippy::large_enum_variant)]
135pub(crate) enum BlockParseOutcome<'src> {
136 Parsed(MatchedItem<'src, Block<'src>>),
138
139 Dropped(Span<'src>),
144
145 NoMatch,
147}
148
149impl<'src> Block<'src> {
150 #[cfg(test)]
159 pub(crate) fn parse(
160 source: Span<'src>,
161 parser: &mut Parser,
162 ) -> MatchAndWarnings<'src, Option<MatchedItem<'src, Self>>> {
163 let MatchAndWarnings { item, warnings } = Self::parse_internal(source, parser, None, false);
164
165 MatchAndWarnings {
166 item: match item {
167 BlockParseOutcome::Parsed(mi) => Some(mi),
168 BlockParseOutcome::Dropped(_) | BlockParseOutcome::NoMatch => None,
169 },
170 warnings,
171 }
172 }
173
174 pub(crate) fn parse_with_outcome(
181 source: Span<'src>,
182 parser: &mut Parser,
183 ) -> MatchAndWarnings<'src, BlockParseOutcome<'src>> {
184 Self::parse_internal(source, parser, None, false)
185 }
186
187 pub(crate) fn parse_for_list_item(
198 source: Span<'src>,
199 parser: &mut Parser,
200 parent_list_markers: &[ListItemMarker<'src>],
201 is_continuation: bool,
202 ) -> MatchAndWarnings<'src, BlockParseOutcome<'src>> {
203 Self::parse_internal(source, parser, Some(parent_list_markers), is_continuation)
204 }
205
206 fn parse_internal(
209 source: Span<'src>,
210 parser: &mut Parser,
211 parent_list_markers: Option<&[ListItemMarker<'src>]>,
212 is_continuation: bool,
213 ) -> MatchAndWarnings<'src, BlockParseOutcome<'src>> {
214 let first_line = source.take_line().item.discard_whitespace();
218
219 if let Some(first_char) = first_line.chars().next()
222 && !matches!(
223 first_char,
224 '.' | '#'
225 | '='
226 | '/'
227 | '-'
228 | '+'
229 | '*'
230 | '_'
231 | '`'
232 | '['
233 | ':'
234 | '\''
235 | '<'
236 | '>'
237 | '"'
238 | '•'
239 )
240 && !first_line.contains("::")
241 && !first_line.contains(";;")
242 && !TableBlock::is_table_delimiter(&first_line)
243 && !ListItemMarker::starts_with_marker(first_line)
244 && !starts_with_admonition_label(first_line)
245 && parent_list_markers.is_none()
246 && parser.pending_block_title.is_none()
247 && let Some(MatchedItem {
248 item: simple_block,
249 after,
250 }) = SimpleBlock::parse_fast(source, parser)
251 {
252 let mut warnings = vec![];
253 let block = Self::Simple(simple_block);
254
255 Self::register_block_id(
258 block.id(),
259 Self::block_reftext(&block, None).as_deref(),
260 Self::block_signifier(&block, parser),
261 block.span(),
262 parser,
263 &mut warnings,
264 );
265
266 return MatchAndWarnings {
267 item: BlockParseOutcome::Parsed(MatchedItem { item: block, after }),
268 warnings,
269 };
270 }
271
272 if first_line.starts_with(':')
274 && (first_line.ends_with(':') || first_line.contains(": "))
275 && let Some(attr) = Attribute::parse(source, parser)
276 {
277 let mut warnings: Vec<Warning<'src>> = vec![];
278 parser.set_attribute_from_body(&attr.item, &mut warnings);
279
280 return MatchAndWarnings {
281 item: BlockParseOutcome::Parsed(MatchedItem {
282 item: Self::DocumentAttribute(attr.item),
283 after: attr.after,
284 }),
285 warnings,
286 };
287 }
288
289 let MatchAndWarnings {
292 item: mut metadata,
293 mut warnings,
294 } = BlockMetadata::parse(source, parser);
295
296 if let Some(pending_title) = parser.pending_block_title.take()
302 && metadata.title.is_none()
303 {
304 metadata.title = Some(crate::content::Content::from_owned_title(
308 metadata.block_start,
309 pending_title,
310 ));
311 }
312
313 if parent_list_markers.is_none() && !metadata.is_empty() {
328 let after_blanks = metadata.block_start.discard_empty_lines();
329 if after_blanks != metadata.block_start && !after_blanks.is_empty() {
330 metadata.block_start = after_blanks;
331 }
332 }
333
334 let anchor_reftext = metadata
340 .anchor_reftext
341 .as_ref()
342 .map(|span| substitute_attributes_in_reftext(*span, parser));
343
344 let is_literal =
352 metadata.attrlist.as_ref().and_then(|a| a.block_style()) == Some("literal") && {
353 let first_line = metadata.block_start.take_normalized_line().item;
354 !RawDelimitedBlock::is_valid_delimiter(&first_line)
355 && !CompoundDelimitedBlock::is_valid_delimiter(&first_line)
356 && !TableBlock::is_table_delimiter(&first_line)
357 };
358
359 let mut simple_block_mi = None;
366
367 if !is_literal {
368 if let Some(mut adm_maw) = AdmonitionBlock::parse(&metadata, parser)
369 && let Some(adm) = adm_maw.item
370 {
371 if !adm_maw.warnings.is_empty() {
372 warnings.append(&mut adm_maw.warnings);
373 }
374
375 let block = Self::Admonition(adm.item);
376
377 Self::register_block_id(
378 block.id(),
379 Self::block_reftext(&block, anchor_reftext.as_deref()).as_deref(),
380 Self::block_signifier(&block, parser),
381 block.span(),
382 parser,
383 &mut warnings,
384 );
385
386 return MatchAndWarnings {
387 item: BlockParseOutcome::Parsed(MatchedItem {
388 item: block,
389 after: adm.after,
390 }),
391 warnings,
392 };
393 }
394
395 if let Some(mut quote_maw) = QuoteBlock::parse(&metadata, parser)
396 && let Some(quote) = quote_maw.item
397 {
398 if !quote_maw.warnings.is_empty() {
399 warnings.append(&mut quote_maw.warnings);
400 }
401
402 let block = Self::Quote(quote.item);
403
404 Self::register_block_id(
405 block.id(),
406 Self::block_reftext(&block, anchor_reftext.as_deref()).as_deref(),
407 Self::block_signifier(&block, parser),
408 block.span(),
409 parser,
410 &mut warnings,
411 );
412
413 return MatchAndWarnings {
414 item: BlockParseOutcome::Parsed(MatchedItem {
415 item: block,
416 after: quote.after,
417 }),
418 warnings,
419 };
420 }
421
422 if let Some(mut rdb_maw) = RawDelimitedBlock::parse(&metadata, parser)
423 && let Some(rdb) = rdb_maw.item
424 {
425 if !rdb_maw.warnings.is_empty() {
426 warnings.append(&mut rdb_maw.warnings);
427 }
428
429 let block = Self::RawDelimited(rdb.item);
430
431 Self::register_block_id(
432 block.id(),
433 Self::block_reftext(&block, anchor_reftext.as_deref()).as_deref(),
434 Self::block_signifier(&block, parser),
435 block.span(),
436 parser,
437 &mut warnings,
438 );
439
440 return MatchAndWarnings {
441 item: BlockParseOutcome::Parsed(MatchedItem {
442 item: block,
443 after: rdb.after,
444 }),
445 warnings,
446 };
447 }
448
449 if let Some(mut cdb_maw) = CompoundDelimitedBlock::parse(&metadata, parser)
450 && let Some(cdb) = cdb_maw.item
451 {
452 if !cdb_maw.warnings.is_empty() {
453 warnings.append(&mut cdb_maw.warnings);
454 }
455
456 let block = Self::CompoundDelimited(cdb.item);
457
458 Self::register_block_id(
459 block.id(),
460 Self::block_reftext(&block, anchor_reftext.as_deref()).as_deref(),
461 Self::block_signifier(&block, parser),
462 block.span(),
463 parser,
464 &mut warnings,
465 );
466
467 return MatchAndWarnings {
468 item: BlockParseOutcome::Parsed(MatchedItem {
469 item: block,
470 after: cdb.after,
471 }),
472 warnings,
473 };
474 }
475
476 if let Some(mut table_maw) = TableBlock::parse(&metadata, parser)
477 && let Some(table) = table_maw.item
478 {
479 if !table_maw.warnings.is_empty() {
480 warnings.append(&mut table_maw.warnings);
481 }
482
483 let block = Self::Table(table.item);
484
485 Self::register_block_id(
486 block.id(),
487 Self::block_reftext(&block, anchor_reftext.as_deref()).as_deref(),
488 Self::block_signifier(&block, parser),
489 block.span(),
490 parser,
491 &mut warnings,
492 );
493
494 return MatchAndWarnings {
495 item: BlockParseOutcome::Parsed(MatchedItem {
496 item: block,
497 after: table.after,
498 }),
499 warnings,
500 };
501 }
502
503 let line = metadata.block_start.take_normalized_line();
505
506 if line.item.starts_with("image::")
507 || line.item.starts_with("video::")
508 || line.item.starts_with("audio::")
509 {
510 let mut media_block_maw = MediaBlock::parse(&metadata, parser);
511
512 if let Some(mut media_block) = media_block_maw.item {
513 if !media_block_maw.warnings.is_empty() {
517 warnings.append(&mut media_block_maw.warnings);
518 }
519
520 if media_block.item.resolve_target(parser) == TargetResolution::Drop {
524 return MatchAndWarnings {
525 item: BlockParseOutcome::Dropped(media_block.after),
526 warnings,
527 };
528 }
529
530 media_block.item.assign_caption(parser);
534
535 let block = Self::Media(media_block.item);
536
537 Self::register_block_id(
538 block.id(),
539 Self::block_reftext(&block, anchor_reftext.as_deref()).as_deref(),
540 Self::block_signifier(&block, parser),
541 block.span(),
542 parser,
543 &mut warnings,
544 );
545
546 return MatchAndWarnings {
547 item: BlockParseOutcome::Parsed(MatchedItem {
548 item: block,
549 after: media_block.after,
550 }),
551 warnings,
552 };
553 }
554
555 }
558
559 if line.item.starts_with("toc::") {
560 let mut toc_block_maw = TocBlock::parse(&metadata, parser);
561
562 if let Some(toc_block) = toc_block_maw.item {
563 if !toc_block_maw.warnings.is_empty() {
567 warnings.append(&mut toc_block_maw.warnings);
568 }
569
570 let block = Self::Toc(toc_block.item);
571
572 Self::register_block_id(
573 block.id(),
574 Self::block_reftext(&block, anchor_reftext.as_deref()).as_deref(),
575 Self::block_signifier(&block, parser),
576 block.span(),
577 parser,
578 &mut warnings,
579 );
580
581 return MatchAndWarnings {
582 item: BlockParseOutcome::Parsed(MatchedItem {
583 item: block,
584 after: toc_block.after,
585 }),
586 warnings,
587 };
588 }
589
590 }
593
594 if (line.item.starts_with('=') || line.item.starts_with('#'))
595 && let Some(mi_section_block) =
596 SectionBlock::parse(&metadata, parser, &mut warnings)
597 {
598 return MatchAndWarnings {
602 item: BlockParseOutcome::Parsed(MatchedItem {
603 item: Self::Section(mi_section_block.item),
604 after: mi_section_block.after,
605 }),
606 warnings,
607 };
608 }
609
610 if (line.item.starts_with('\'')
611 || line.item.starts_with('-')
612 || line.item.starts_with('*')
613 || line.item.starts_with('_')
614 || line.item.starts_with('<'))
615 && let Some(mi_break) = Break::parse(&metadata, parser)
616 {
617 return MatchAndWarnings {
620 item: BlockParseOutcome::Parsed(MatchedItem {
621 item: Self::Break(mi_break.item),
622 after: mi_break.after,
623 }),
624 warnings,
625 };
626 }
627
628 if parent_list_markers.is_none()
632 && let Some(mi_list) = ListBlock::parse(&metadata, parser, &mut warnings)
633 {
634 return MatchAndWarnings {
635 item: BlockParseOutcome::Parsed(MatchedItem {
636 item: Self::List(mi_list.item),
637 after: mi_list.after,
638 }),
639 warnings,
640 };
641 }
642
643 simple_block_mi = if let Some(plm) = parent_list_markers {
650 SimpleBlock::parse_for_list_item(&metadata, parser, is_continuation, plm)
651 } else {
652 SimpleBlock::parse(&metadata, parser)
653 };
654
655 if simple_block_mi.is_none() && !metadata.is_empty() {
656 warnings.push(Warning {
660 source: metadata.source,
661 warning: WarningType::MissingBlockAfterTitleOrAttributeList,
662 origin: None,
663 });
664
665 metadata.title_source = None;
669 metadata.title = None;
670 metadata.anchor = None;
671 metadata.attrlist = None;
672 metadata.block_start = metadata.source;
673 }
674 }
675
676 let simple_block_mi = match simple_block_mi {
680 Some(mi) => Some(mi),
681 None => {
682 if let Some(plm) = parent_list_markers {
683 SimpleBlock::parse_for_list_item(&metadata, parser, is_continuation, plm)
684 } else {
685 SimpleBlock::parse(&metadata, parser)
686 }
687 }
688 };
689
690 let mut result = MatchAndWarnings {
691 item: match simple_block_mi {
692 Some(mi) => BlockParseOutcome::Parsed(MatchedItem {
693 item: Self::Simple(mi.item),
694 after: mi.after,
695 }),
696 None => BlockParseOutcome::NoMatch,
697 },
698 warnings,
699 };
700
701 if let BlockParseOutcome::Parsed(ref matched_item) = result.item {
702 Self::register_block_id(
703 matched_item.item.id(),
704 Self::block_reftext(&matched_item.item, anchor_reftext.as_deref()).as_deref(),
705 Self::block_signifier(&matched_item.item, parser),
706 matched_item.item.span(),
707 parser,
708 &mut result.warnings,
709 );
710 }
711
712 result
713 }
714
715 fn block_signifier<'a>(block: &'a Block<'a>, parser: &Parser) -> Option<XrefSignifier> {
726 let caption = block.caption()?;
728
729 let has_explicit_reftext = block
730 .attrlist()
731 .and_then(|attrlist| attrlist.named_attribute("reftext"))
732 .is_some()
733 || block.anchor_reftext().is_some();
734 if has_explicit_reftext {
735 return None;
736 }
737
738 if Self::has_caption_override(block, parser) {
744 return None;
745 }
746
747 let label = caption.strip_suffix(". ").unwrap_or(caption).to_string();
750 Some(XrefSignifier {
751 label,
752 emphasize: false,
753 })
754 }
755
756 fn has_caption_override<'a>(block: &'a Block<'a>, parser: &Parser) -> bool {
766 let attribute_override = block
767 .attrlist()
768 .and_then(|attrlist| attrlist.named_attribute("caption"))
769 .is_some()
770 || matches!(block, Block::Media(media)
771 if media.macro_attrlist().named_attribute("caption").is_some());
772
773 attribute_override
774 || matches!(
775 parser.attribute_value("caption"),
776 InterpretedValue::Value(value) if !value.is_empty(),
777 )
778 }
779
780 fn block_reftext<'a>(block: &'a Block<'a>, anchor_reftext: Option<&str>) -> Option<CowStr<'a>> {
794 if let Some(attr) = block
795 .attrlist()
796 .and_then(|attrlist| attrlist.named_attribute("reftext"))
797 {
798 return Some(CowStr::from(attr.value()));
799 }
800
801 if let Some(anchor_reftext) = anchor_reftext {
802 return Some(CowStr::from(anchor_reftext.to_string()));
803 }
804
805 block.title().map(CowStr::from)
806 }
807
808 fn register_block_id(
813 id: Option<&str>,
814 reftext: Option<&str>,
815 signifier: Option<XrefSignifier>,
816 span: Span<'src>,
817 parser: &mut Parser,
818 warnings: &mut Vec<Warning<'src>>,
819 ) {
820 if let Some(id) = id {
821 match parser.register_ref(id, reftext, RefType::Anchor) {
822 Ok(()) => {
823 if let Some(signifier) = signifier {
824 parser.set_ref_signifier(id, signifier);
825 }
826 }
827 Err(_duplicate_error) => {
828 warnings.push(Warning {
830 source: span,
831 warning: WarningType::DuplicateId(id.to_string()),
832 origin: None,
833 });
834 }
835 }
836 }
837 }
838
839 pub(crate) fn as_list_item(&self) -> Option<&ListItem<'src>> {
842 match self {
843 Self::ListItem(li) => Some(li),
844 _ => None,
845 }
846 }
847
848 pub(crate) fn resolve_references(
856 &mut self,
857 resolver: &dyn ReferenceResolver,
858 renderer: &dyn InlineSubstitutionRenderer,
859 warnings: &mut ReferenceWarnings<'src>,
860 ) {
861 if let Some(content) = self.content_mut() {
868 content.resolve_references(resolver, renderer, warnings);
869 }
870
871 if let Self::Table(table) = self {
874 table.resolve_references(resolver, renderer, warnings);
875 }
876
877 if let Self::Quote(quote) = self {
881 quote.resolve_references(resolver, renderer, warnings);
882 }
883
884 for child in self.child_blocks_mut() {
885 child.resolve_references(resolver, renderer, warnings);
886 }
887 }
888
889 pub(crate) fn block_title_content_mut(&mut self) -> Option<&mut Content<'src>> {
898 match self {
899 Self::Simple(b) => b.title_content_mut(),
900 Self::Media(b) => b.title_content_mut(),
901 Self::List(b) => b.title_content_mut(),
902 Self::RawDelimited(b) => b.title_content_mut(),
903 Self::CompoundDelimited(b) => b.title_content_mut(),
904 Self::Admonition(b) => b.title_content_mut(),
905 Self::Quote(b) => b.title_content_mut(),
906 Self::Table(b) => b.title_content_mut(),
907 Self::Break(b) => b.title_content_mut(),
908 Self::Toc(b) => b.title_content_mut(),
909 _ => None,
910 }
911 }
912}
913
914impl<'src> IsBlock<'src> for Block<'src> {
915 fn content_model(&self) -> ContentModel {
916 match self {
917 Self::Simple(_) => ContentModel::Simple,
918 Self::Media(b) => b.content_model(),
919 Self::Section(_) => ContentModel::Compound,
920 Self::List(b) => b.content_model(),
921 Self::ListItem(b) => b.content_model(),
922 Self::RawDelimited(b) => b.content_model(),
923 Self::CompoundDelimited(b) => b.content_model(),
924 Self::Admonition(b) => b.content_model(),
925 Self::Quote(b) => b.content_model(),
926 Self::Table(b) => b.content_model(),
927 Self::Preamble(b) => b.content_model(),
928 Self::Break(b) => b.content_model(),
929 Self::Toc(b) => b.content_model(),
930 Self::DocumentAttribute(b) => b.content_model(),
931 }
932 }
933
934 fn declared_style(&'src self) -> Option<&'src str> {
935 match self {
936 Self::Simple(b) => b.declared_style(),
937 Self::Media(b) => b.declared_style(),
938 Self::Section(b) => b.declared_style(),
939 Self::List(b) => b.declared_style(),
940 Self::ListItem(b) => b.declared_style(),
941 Self::RawDelimited(b) => b.declared_style(),
942 Self::CompoundDelimited(b) => b.declared_style(),
943 Self::Admonition(b) => b.declared_style(),
944 Self::Quote(b) => b.declared_style(),
945 Self::Table(b) => b.declared_style(),
946 Self::Preamble(b) => b.declared_style(),
947 Self::Break(b) => b.declared_style(),
948 Self::Toc(b) => b.declared_style(),
949 Self::DocumentAttribute(b) => b.declared_style(),
950 }
951 }
952
953 fn rendered_content(&'src self) -> Option<&'src str> {
954 match self {
955 Self::Simple(b) => b.rendered_content(),
956 Self::Media(b) => b.rendered_content(),
957 Self::Section(b) => b.rendered_content(),
958 Self::List(b) => b.rendered_content(),
959 Self::ListItem(b) => b.rendered_content(),
960 Self::RawDelimited(b) => b.rendered_content(),
961 Self::CompoundDelimited(b) => b.rendered_content(),
962 Self::Admonition(b) => b.rendered_content(),
963 Self::Quote(b) => b.rendered_content(),
964 Self::Table(b) => b.rendered_content(),
965 Self::Preamble(b) => b.rendered_content(),
966 Self::Break(b) => b.rendered_content(),
967 Self::Toc(b) => b.rendered_content(),
968 Self::DocumentAttribute(b) => b.rendered_content(),
969 }
970 }
971
972 fn raw_context(&self) -> CowStr<'src> {
973 match self {
974 Self::Simple(b) => b.raw_context(),
975 Self::Media(b) => b.raw_context(),
976 Self::Section(b) => b.raw_context(),
977 Self::List(b) => b.raw_context(),
978 Self::ListItem(b) => b.raw_context(),
979 Self::RawDelimited(b) => b.raw_context(),
980 Self::CompoundDelimited(b) => b.raw_context(),
981 Self::Admonition(b) => b.raw_context(),
982 Self::Quote(b) => b.raw_context(),
983 Self::Table(b) => b.raw_context(),
984 Self::Preamble(b) => b.raw_context(),
985 Self::Break(b) => b.raw_context(),
986 Self::Toc(b) => b.raw_context(),
987 Self::DocumentAttribute(b) => b.raw_context(),
988 }
989 }
990
991 fn child_blocks_mut(&mut self) -> &mut [Block<'src>] {
992 match self {
993 Self::Simple(b) => b.child_blocks_mut(),
994 Self::Media(b) => b.child_blocks_mut(),
995 Self::Section(b) => b.child_blocks_mut(),
996 Self::List(b) => b.child_blocks_mut(),
997 Self::ListItem(b) => b.child_blocks_mut(),
998 Self::RawDelimited(b) => b.child_blocks_mut(),
999 Self::CompoundDelimited(b) => b.child_blocks_mut(),
1000 Self::Admonition(b) => b.child_blocks_mut(),
1001 Self::Quote(b) => b.child_blocks_mut(),
1002 Self::Table(b) => b.child_blocks_mut(),
1003 Self::Preamble(b) => b.child_blocks_mut(),
1004 Self::Break(b) => b.child_blocks_mut(),
1005 Self::Toc(b) => b.child_blocks_mut(),
1006 Self::DocumentAttribute(b) => b.child_blocks_mut(),
1007 }
1008 }
1009
1010 fn content_mut(&mut self) -> Option<&mut Content<'src>> {
1011 match self {
1012 Self::Simple(b) => b.content_mut(),
1013 Self::Media(b) => b.content_mut(),
1014 Self::Section(b) => b.content_mut(),
1015 Self::List(b) => b.content_mut(),
1016 Self::ListItem(b) => b.content_mut(),
1017 Self::RawDelimited(b) => b.content_mut(),
1018 Self::CompoundDelimited(b) => b.content_mut(),
1019 Self::Admonition(b) => b.content_mut(),
1020 Self::Quote(b) => b.content_mut(),
1021 Self::Table(b) => b.content_mut(),
1022 Self::Preamble(b) => b.content_mut(),
1023 Self::Break(b) => b.content_mut(),
1024 Self::Toc(b) => b.content_mut(),
1025 Self::DocumentAttribute(b) => b.content_mut(),
1026 }
1027 }
1028
1029 fn title_source(&'src self) -> Option<Span<'src>> {
1030 match self {
1031 Self::Simple(b) => b.title_source(),
1032 Self::Media(b) => b.title_source(),
1033 Self::Section(b) => b.title_source(),
1034 Self::List(b) => b.title_source(),
1035 Self::ListItem(b) => b.title_source(),
1036 Self::RawDelimited(b) => b.title_source(),
1037 Self::CompoundDelimited(b) => b.title_source(),
1038 Self::Admonition(b) => b.title_source(),
1039 Self::Quote(b) => b.title_source(),
1040 Self::Table(b) => b.title_source(),
1041 Self::Preamble(b) => b.title_source(),
1042 Self::Break(b) => b.title_source(),
1043 Self::Toc(b) => b.title_source(),
1044 Self::DocumentAttribute(b) => b.title_source(),
1045 }
1046 }
1047
1048 fn title(&self) -> Option<&str> {
1049 match self {
1050 Self::Simple(b) => b.title(),
1051 Self::Media(b) => b.title(),
1052 Self::Section(b) => b.title(),
1053 Self::List(b) => b.title(),
1054 Self::ListItem(b) => b.title(),
1055 Self::RawDelimited(b) => b.title(),
1056 Self::CompoundDelimited(b) => b.title(),
1057 Self::Admonition(b) => b.title(),
1058 Self::Quote(b) => b.title(),
1059 Self::Table(b) => b.title(),
1060 Self::Preamble(b) => b.title(),
1061 Self::Break(b) => b.title(),
1062 Self::Toc(b) => b.title(),
1063 Self::DocumentAttribute(b) => b.title(),
1064 }
1065 }
1066
1067 fn caption(&self) -> Option<&str> {
1068 match self {
1069 Self::Simple(b) => b.caption(),
1070 Self::Media(b) => b.caption(),
1071 Self::Section(b) => b.caption(),
1072 Self::List(b) => b.caption(),
1073 Self::ListItem(b) => b.caption(),
1074 Self::RawDelimited(b) => b.caption(),
1075 Self::CompoundDelimited(b) => b.caption(),
1076 Self::Admonition(b) => b.caption(),
1077 Self::Quote(b) => b.caption(),
1078 Self::Table(b) => b.caption(),
1079 Self::Preamble(b) => b.caption(),
1080 Self::Break(b) => b.caption(),
1081 Self::Toc(b) => b.caption(),
1082 Self::DocumentAttribute(b) => b.caption(),
1083 }
1084 }
1085
1086 fn number(&self) -> Option<usize> {
1087 match self {
1088 Self::Simple(b) => b.number(),
1089 Self::Media(b) => b.number(),
1090 Self::Section(b) => b.number(),
1091 Self::List(b) => b.number(),
1092 Self::ListItem(b) => b.number(),
1093 Self::RawDelimited(b) => b.number(),
1094 Self::CompoundDelimited(b) => b.number(),
1095 Self::Admonition(b) => b.number(),
1096 Self::Quote(b) => b.number(),
1097 Self::Table(b) => b.number(),
1098 Self::Preamble(b) => b.number(),
1099 Self::Break(b) => b.number(),
1100 Self::Toc(b) => b.number(),
1101 Self::DocumentAttribute(b) => b.number(),
1102 }
1103 }
1104
1105 fn id(&'src self) -> Option<&'src str> {
1106 match self {
1123 Self::Media(b) => b.id(),
1124 Self::Section(b) => b.id(),
1125 Self::Toc(b) => b.id(),
1126 _ => self
1127 .anchor()
1128 .map(|a| a.data())
1129 .or_else(|| self.attrlist().and_then(|attrlist| attrlist.id())),
1130 }
1131 }
1132
1133 fn anchor(&'src self) -> Option<Span<'src>> {
1134 match self {
1135 Self::Simple(b) => b.anchor(),
1136 Self::Media(b) => b.anchor(),
1137 Self::Section(b) => b.anchor(),
1138 Self::List(b) => b.anchor(),
1139 Self::ListItem(b) => b.anchor(),
1140 Self::RawDelimited(b) => b.anchor(),
1141 Self::CompoundDelimited(b) => b.anchor(),
1142 Self::Admonition(b) => b.anchor(),
1143 Self::Quote(b) => b.anchor(),
1144 Self::Table(b) => b.anchor(),
1145 Self::Preamble(b) => b.anchor(),
1146 Self::Break(b) => b.anchor(),
1147 Self::Toc(b) => b.anchor(),
1148 Self::DocumentAttribute(b) => b.anchor(),
1149 }
1150 }
1151
1152 fn anchor_reftext(&'src self) -> Option<Span<'src>> {
1153 match self {
1154 Self::Simple(b) => b.anchor_reftext(),
1155 Self::Media(b) => b.anchor_reftext(),
1156 Self::Section(b) => b.anchor_reftext(),
1157 Self::List(b) => b.anchor_reftext(),
1158 Self::ListItem(b) => b.anchor_reftext(),
1159 Self::RawDelimited(b) => b.anchor_reftext(),
1160 Self::CompoundDelimited(b) => b.anchor_reftext(),
1161 Self::Admonition(b) => b.anchor_reftext(),
1162 Self::Quote(b) => b.anchor_reftext(),
1163 Self::Table(b) => b.anchor_reftext(),
1164 Self::Preamble(b) => b.anchor_reftext(),
1165 Self::Break(b) => b.anchor_reftext(),
1166 Self::Toc(b) => b.anchor_reftext(),
1167 Self::DocumentAttribute(b) => b.anchor_reftext(),
1168 }
1169 }
1170
1171 fn attrlist(&'src self) -> Option<&'src Attrlist<'src>> {
1172 match self {
1173 Self::Simple(b) => b.attrlist(),
1174 Self::Media(b) => b.attrlist(),
1175 Self::Section(b) => b.attrlist(),
1176 Self::List(b) => b.attrlist(),
1177 Self::ListItem(b) => b.attrlist(),
1178 Self::RawDelimited(b) => b.attrlist(),
1179 Self::CompoundDelimited(b) => b.attrlist(),
1180 Self::Admonition(b) => b.attrlist(),
1181 Self::Quote(b) => b.attrlist(),
1182 Self::Table(b) => b.attrlist(),
1183 Self::Preamble(b) => b.attrlist(),
1184 Self::Break(b) => b.attrlist(),
1185 Self::Toc(b) => b.attrlist(),
1186 Self::DocumentAttribute(b) => b.attrlist(),
1187 }
1188 }
1189
1190 fn substitution_group(&self) -> SubstitutionGroup {
1191 match self {
1192 Self::Simple(b) => b.substitution_group(),
1193 Self::Media(b) => b.substitution_group(),
1194 Self::Section(b) => b.substitution_group(),
1195 Self::List(b) => b.substitution_group(),
1196 Self::ListItem(b) => b.substitution_group(),
1197 Self::RawDelimited(b) => b.substitution_group(),
1198 Self::CompoundDelimited(b) => b.substitution_group(),
1199 Self::Admonition(b) => b.substitution_group(),
1200 Self::Quote(b) => b.substitution_group(),
1201 Self::Table(b) => b.substitution_group(),
1202 Self::Preamble(b) => b.substitution_group(),
1203 Self::Break(b) => b.substitution_group(),
1204 Self::Toc(b) => b.substitution_group(),
1205 Self::DocumentAttribute(b) => b.substitution_group(),
1206 }
1207 }
1208}
1209
1210impl<'src> HasSpan<'src> for Block<'src> {
1211 fn span(&self) -> Span<'src> {
1212 match self {
1213 Self::Simple(b) => b.span(),
1214 Self::Media(b) => b.span(),
1215 Self::Section(b) => b.span(),
1216 Self::List(b) => b.span(),
1217 Self::ListItem(b) => b.span(),
1218 Self::RawDelimited(b) => b.span(),
1219 Self::CompoundDelimited(b) => b.span(),
1220 Self::Admonition(b) => b.span(),
1221 Self::Quote(b) => b.span(),
1222 Self::Table(b) => b.span(),
1223 Self::Preamble(b) => b.span(),
1224 Self::Break(b) => b.span(),
1225 Self::Toc(b) => b.span(),
1226 Self::DocumentAttribute(b) => b.span(),
1227 }
1228 }
1229}