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, 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, PartialEq)]
31#[allow(clippy::large_enum_variant)] #[non_exhaustive]
33pub enum Block<'src> {
34 Simple(SimpleBlock<'src>),
37
38 Media(MediaBlock<'src>),
41
42 Section(SectionBlock<'src>),
45
46 List(ListBlock<'src>),
50
51 ListItem(ListItem<'src>),
54
55 RawDelimited(RawDelimitedBlock<'src>),
59
60 CompoundDelimited(CompoundDelimitedBlock<'src>),
62
63 Admonition(AdmonitionBlock<'src>),
67
68 Quote(QuoteBlock<'src>),
71
72 Table(TableBlock<'src>),
74
75 Preamble(Preamble<'src>),
78
79 Break(Break<'src>),
81
82 DocumentAttribute(Attribute<'src>),
85}
86
87impl<'src> std::fmt::Debug for Block<'src> {
88 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89 match self {
90 Block::Simple(block) => f.debug_tuple("Block::Simple").field(block).finish(),
91 Block::Media(block) => f.debug_tuple("Block::Media").field(block).finish(),
92 Block::Section(block) => f.debug_tuple("Block::Section").field(block).finish(),
93 Block::List(block) => f.debug_tuple("Block::List").field(block).finish(),
94 Block::ListItem(block) => f.debug_tuple("Block::ListItem").field(block).finish(),
95
96 Block::RawDelimited(block) => {
97 f.debug_tuple("Block::RawDelimited").field(block).finish()
98 }
99
100 Block::CompoundDelimited(block) => f
101 .debug_tuple("Block::CompoundDelimited")
102 .field(block)
103 .finish(),
104
105 Block::Admonition(block) => f.debug_tuple("Block::Admonition").field(block).finish(),
106 Block::Quote(block) => f.debug_tuple("Block::Quote").field(block).finish(),
107 Block::Table(block) => f.debug_tuple("Block::Table").field(block).finish(),
108 Block::Preamble(block) => f.debug_tuple("Block::Preamble").field(block).finish(),
109 Block::Break(break_) => f.debug_tuple("Block::Break").field(break_).finish(),
110
111 Block::DocumentAttribute(block) => f
112 .debug_tuple("Block::DocumentAttribute")
113 .field(block)
114 .finish(),
115 }
116 }
117}
118
119#[allow(clippy::large_enum_variant)]
131pub(crate) enum BlockParseOutcome<'src> {
132 Parsed(MatchedItem<'src, Block<'src>>),
134
135 Dropped(Span<'src>),
140
141 NoMatch,
143}
144
145impl<'src> Block<'src> {
146 #[cfg(test)]
155 pub(crate) fn parse(
156 source: Span<'src>,
157 parser: &mut Parser,
158 ) -> MatchAndWarnings<'src, Option<MatchedItem<'src, Self>>> {
159 let MatchAndWarnings { item, warnings } = Self::parse_internal(source, parser, None, false);
160
161 MatchAndWarnings {
162 item: match item {
163 BlockParseOutcome::Parsed(mi) => Some(mi),
164 BlockParseOutcome::Dropped(_) | BlockParseOutcome::NoMatch => None,
165 },
166 warnings,
167 }
168 }
169
170 pub(crate) fn parse_with_outcome(
177 source: Span<'src>,
178 parser: &mut Parser,
179 ) -> MatchAndWarnings<'src, BlockParseOutcome<'src>> {
180 Self::parse_internal(source, parser, None, false)
181 }
182
183 pub(crate) fn parse_for_list_item(
194 source: Span<'src>,
195 parser: &mut Parser,
196 parent_list_markers: &[ListItemMarker<'src>],
197 is_continuation: bool,
198 ) -> MatchAndWarnings<'src, BlockParseOutcome<'src>> {
199 Self::parse_internal(source, parser, Some(parent_list_markers), is_continuation)
200 }
201
202 fn parse_internal(
205 source: Span<'src>,
206 parser: &mut Parser,
207 parent_list_markers: Option<&[ListItemMarker<'src>]>,
208 is_continuation: bool,
209 ) -> MatchAndWarnings<'src, BlockParseOutcome<'src>> {
210 let first_line = source.take_line().item.discard_whitespace();
214
215 if let Some(first_char) = first_line.chars().next()
218 && !matches!(
219 first_char,
220 '.' | '#'
221 | '='
222 | '/'
223 | '-'
224 | '+'
225 | '*'
226 | '_'
227 | '`'
228 | '['
229 | ':'
230 | '\''
231 | '<'
232 | '>'
233 | '"'
234 | '•'
235 )
236 && !first_line.contains("::")
237 && !first_line.contains(";;")
238 && !TableBlock::is_table_delimiter(&first_line)
239 && !ListItemMarker::starts_with_marker(first_line)
240 && !starts_with_admonition_label(first_line)
241 && parent_list_markers.is_none()
242 && parser.pending_block_title.is_none()
243 && let Some(MatchedItem {
244 item: simple_block,
245 after,
246 }) = SimpleBlock::parse_fast(source, parser)
247 {
248 let mut warnings = vec![];
249 let block = Self::Simple(simple_block);
250
251 Self::register_block_id(
254 block.id(),
255 Self::block_reftext(&block, None).as_deref(),
256 Self::block_signifier(&block, parser),
257 block.span(),
258 parser,
259 &mut warnings,
260 );
261
262 return MatchAndWarnings {
263 item: BlockParseOutcome::Parsed(MatchedItem { item: block, after }),
264 warnings,
265 };
266 }
267
268 if first_line.starts_with(':')
270 && (first_line.ends_with(':') || first_line.contains(": "))
271 && let Some(attr) = Attribute::parse(source, parser)
272 {
273 let mut warnings: Vec<Warning<'src>> = vec![];
274 parser.set_attribute_from_body(&attr.item, &mut warnings);
275
276 return MatchAndWarnings {
277 item: BlockParseOutcome::Parsed(MatchedItem {
278 item: Self::DocumentAttribute(attr.item),
279 after: attr.after,
280 }),
281 warnings,
282 };
283 }
284
285 let MatchAndWarnings {
288 item: mut metadata,
289 mut warnings,
290 } = BlockMetadata::parse(source, parser);
291
292 if let Some(pending_title) = parser.pending_block_title.take()
298 && metadata.title.is_none()
299 {
300 metadata.title = Some(crate::content::Content::from_owned_title(
304 metadata.block_start,
305 pending_title,
306 ));
307 }
308
309 if parent_list_markers.is_none() && !metadata.is_empty() {
324 let after_blanks = metadata.block_start.discard_empty_lines();
325 if after_blanks != metadata.block_start && !after_blanks.is_empty() {
326 metadata.block_start = after_blanks;
327 }
328 }
329
330 let anchor_reftext = metadata
336 .anchor_reftext
337 .as_ref()
338 .map(|span| substitute_attributes_in_reftext(*span, parser));
339
340 let is_literal =
348 metadata.attrlist.as_ref().and_then(|a| a.block_style()) == Some("literal") && {
349 let first_line = metadata.block_start.take_normalized_line().item;
350 !RawDelimitedBlock::is_valid_delimiter(&first_line)
351 && !CompoundDelimitedBlock::is_valid_delimiter(&first_line)
352 && !TableBlock::is_table_delimiter(&first_line)
353 };
354
355 let mut simple_block_mi = None;
362
363 if !is_literal {
364 if let Some(mut adm_maw) = AdmonitionBlock::parse(&metadata, parser)
365 && let Some(adm) = adm_maw.item
366 {
367 if !adm_maw.warnings.is_empty() {
368 warnings.append(&mut adm_maw.warnings);
369 }
370
371 let block = Self::Admonition(adm.item);
372
373 Self::register_block_id(
374 block.id(),
375 Self::block_reftext(&block, anchor_reftext.as_deref()).as_deref(),
376 Self::block_signifier(&block, parser),
377 block.span(),
378 parser,
379 &mut warnings,
380 );
381
382 return MatchAndWarnings {
383 item: BlockParseOutcome::Parsed(MatchedItem {
384 item: block,
385 after: adm.after,
386 }),
387 warnings,
388 };
389 }
390
391 if let Some(mut quote_maw) = QuoteBlock::parse(&metadata, parser)
392 && let Some(quote) = quote_maw.item
393 {
394 if !quote_maw.warnings.is_empty() {
395 warnings.append(&mut quote_maw.warnings);
396 }
397
398 let block = Self::Quote(quote.item);
399
400 Self::register_block_id(
401 block.id(),
402 Self::block_reftext(&block, anchor_reftext.as_deref()).as_deref(),
403 Self::block_signifier(&block, parser),
404 block.span(),
405 parser,
406 &mut warnings,
407 );
408
409 return MatchAndWarnings {
410 item: BlockParseOutcome::Parsed(MatchedItem {
411 item: block,
412 after: quote.after,
413 }),
414 warnings,
415 };
416 }
417
418 if let Some(mut rdb_maw) = RawDelimitedBlock::parse(&metadata, parser)
419 && let Some(rdb) = rdb_maw.item
420 {
421 if !rdb_maw.warnings.is_empty() {
422 warnings.append(&mut rdb_maw.warnings);
423 }
424
425 let block = Self::RawDelimited(rdb.item);
426
427 Self::register_block_id(
428 block.id(),
429 Self::block_reftext(&block, anchor_reftext.as_deref()).as_deref(),
430 Self::block_signifier(&block, parser),
431 block.span(),
432 parser,
433 &mut warnings,
434 );
435
436 return MatchAndWarnings {
437 item: BlockParseOutcome::Parsed(MatchedItem {
438 item: block,
439 after: rdb.after,
440 }),
441 warnings,
442 };
443 }
444
445 if let Some(mut cdb_maw) = CompoundDelimitedBlock::parse(&metadata, parser)
446 && let Some(cdb) = cdb_maw.item
447 {
448 if !cdb_maw.warnings.is_empty() {
449 warnings.append(&mut cdb_maw.warnings);
450 }
451
452 let block = Self::CompoundDelimited(cdb.item);
453
454 Self::register_block_id(
455 block.id(),
456 Self::block_reftext(&block, anchor_reftext.as_deref()).as_deref(),
457 Self::block_signifier(&block, parser),
458 block.span(),
459 parser,
460 &mut warnings,
461 );
462
463 return MatchAndWarnings {
464 item: BlockParseOutcome::Parsed(MatchedItem {
465 item: block,
466 after: cdb.after,
467 }),
468 warnings,
469 };
470 }
471
472 if let Some(mut table_maw) = TableBlock::parse(&metadata, parser)
473 && let Some(table) = table_maw.item
474 {
475 if !table_maw.warnings.is_empty() {
476 warnings.append(&mut table_maw.warnings);
477 }
478
479 let block = Self::Table(table.item);
480
481 Self::register_block_id(
482 block.id(),
483 Self::block_reftext(&block, anchor_reftext.as_deref()).as_deref(),
484 Self::block_signifier(&block, parser),
485 block.span(),
486 parser,
487 &mut warnings,
488 );
489
490 return MatchAndWarnings {
491 item: BlockParseOutcome::Parsed(MatchedItem {
492 item: block,
493 after: table.after,
494 }),
495 warnings,
496 };
497 }
498
499 let line = metadata.block_start.take_normalized_line();
501
502 if line.item.starts_with("image::")
503 || line.item.starts_with("video::")
504 || line.item.starts_with("audio::")
505 {
506 let mut media_block_maw = MediaBlock::parse(&metadata, parser);
507
508 if let Some(mut media_block) = media_block_maw.item {
509 if !media_block_maw.warnings.is_empty() {
513 warnings.append(&mut media_block_maw.warnings);
514 }
515
516 if media_block.item.resolve_target(parser) == TargetResolution::Drop {
520 return MatchAndWarnings {
521 item: BlockParseOutcome::Dropped(media_block.after),
522 warnings,
523 };
524 }
525
526 media_block.item.assign_caption(parser);
530
531 let block = Self::Media(media_block.item);
532
533 Self::register_block_id(
534 block.id(),
535 Self::block_reftext(&block, anchor_reftext.as_deref()).as_deref(),
536 Self::block_signifier(&block, parser),
537 block.span(),
538 parser,
539 &mut warnings,
540 );
541
542 return MatchAndWarnings {
543 item: BlockParseOutcome::Parsed(MatchedItem {
544 item: block,
545 after: media_block.after,
546 }),
547 warnings,
548 };
549 }
550
551 }
554
555 if (line.item.starts_with('=') || line.item.starts_with('#'))
556 && let Some(mi_section_block) =
557 SectionBlock::parse(&metadata, parser, &mut warnings)
558 {
559 return MatchAndWarnings {
563 item: BlockParseOutcome::Parsed(MatchedItem {
564 item: Self::Section(mi_section_block.item),
565 after: mi_section_block.after,
566 }),
567 warnings,
568 };
569 }
570
571 if (line.item.starts_with('\'')
572 || line.item.starts_with('-')
573 || line.item.starts_with('*')
574 || line.item.starts_with('_')
575 || line.item.starts_with('<'))
576 && let Some(mi_break) = Break::parse(&metadata, parser)
577 {
578 return MatchAndWarnings {
581 item: BlockParseOutcome::Parsed(MatchedItem {
582 item: Self::Break(mi_break.item),
583 after: mi_break.after,
584 }),
585 warnings,
586 };
587 }
588
589 if parent_list_markers.is_none()
593 && let Some(mi_list) = ListBlock::parse(&metadata, parser, &mut warnings)
594 {
595 return MatchAndWarnings {
596 item: BlockParseOutcome::Parsed(MatchedItem {
597 item: Self::List(mi_list.item),
598 after: mi_list.after,
599 }),
600 warnings,
601 };
602 }
603
604 simple_block_mi = if let Some(plm) = parent_list_markers {
611 SimpleBlock::parse_for_list_item(&metadata, parser, is_continuation, plm)
612 } else {
613 SimpleBlock::parse(&metadata, parser)
614 };
615
616 if simple_block_mi.is_none() && !metadata.is_empty() {
617 warnings.push(Warning {
621 source: metadata.source,
622 warning: WarningType::MissingBlockAfterTitleOrAttributeList,
623 origin: None,
624 });
625
626 metadata.title_source = None;
630 metadata.title = None;
631 metadata.anchor = None;
632 metadata.attrlist = None;
633 metadata.block_start = metadata.source;
634 }
635 }
636
637 let simple_block_mi = match simple_block_mi {
641 Some(mi) => Some(mi),
642 None => {
643 if let Some(plm) = parent_list_markers {
644 SimpleBlock::parse_for_list_item(&metadata, parser, is_continuation, plm)
645 } else {
646 SimpleBlock::parse(&metadata, parser)
647 }
648 }
649 };
650
651 let mut result = MatchAndWarnings {
652 item: match simple_block_mi {
653 Some(mi) => BlockParseOutcome::Parsed(MatchedItem {
654 item: Self::Simple(mi.item),
655 after: mi.after,
656 }),
657 None => BlockParseOutcome::NoMatch,
658 },
659 warnings,
660 };
661
662 if let BlockParseOutcome::Parsed(ref matched_item) = result.item {
663 Self::register_block_id(
664 matched_item.item.id(),
665 Self::block_reftext(&matched_item.item, anchor_reftext.as_deref()).as_deref(),
666 Self::block_signifier(&matched_item.item, parser),
667 matched_item.item.span(),
668 parser,
669 &mut result.warnings,
670 );
671 }
672
673 result
674 }
675
676 fn block_signifier<'a>(block: &'a Block<'a>, parser: &Parser) -> Option<XrefSignifier> {
687 let caption = block.caption()?;
689
690 let has_explicit_reftext = block
691 .attrlist()
692 .and_then(|attrlist| attrlist.named_attribute("reftext"))
693 .is_some()
694 || block.anchor_reftext().is_some();
695 if has_explicit_reftext {
696 return None;
697 }
698
699 if Self::has_caption_override(block, parser) {
705 return None;
706 }
707
708 let label = caption.strip_suffix(". ").unwrap_or(caption).to_string();
711 Some(XrefSignifier {
712 label,
713 emphasize: false,
714 })
715 }
716
717 fn has_caption_override<'a>(block: &'a Block<'a>, parser: &Parser) -> bool {
727 let attribute_override = block
728 .attrlist()
729 .and_then(|attrlist| attrlist.named_attribute("caption"))
730 .is_some()
731 || matches!(block, Block::Media(media)
732 if media.macro_attrlist().named_attribute("caption").is_some());
733
734 attribute_override
735 || matches!(
736 parser.attribute_value("caption"),
737 InterpretedValue::Value(value) if !value.is_empty(),
738 )
739 }
740
741 fn block_reftext<'a>(block: &'a Block<'a>, anchor_reftext: Option<&str>) -> Option<CowStr<'a>> {
755 if let Some(attr) = block
756 .attrlist()
757 .and_then(|attrlist| attrlist.named_attribute("reftext"))
758 {
759 return Some(CowStr::from(attr.value()));
760 }
761
762 if let Some(anchor_reftext) = anchor_reftext {
763 return Some(CowStr::from(anchor_reftext.to_string()));
764 }
765
766 block.title().map(CowStr::from)
767 }
768
769 fn register_block_id(
774 id: Option<&str>,
775 reftext: Option<&str>,
776 signifier: Option<XrefSignifier>,
777 span: Span<'src>,
778 parser: &mut Parser,
779 warnings: &mut Vec<Warning<'src>>,
780 ) {
781 if let Some(id) = id {
782 match parser.register_ref(id, reftext, RefType::Anchor) {
783 Ok(()) => {
784 if let Some(signifier) = signifier {
785 parser.set_ref_signifier(id, signifier);
786 }
787 }
788 Err(_duplicate_error) => {
789 warnings.push(Warning {
791 source: span,
792 warning: WarningType::DuplicateId(id.to_string()),
793 origin: None,
794 });
795 }
796 }
797 }
798 }
799
800 pub(crate) fn as_list_item(&self) -> Option<&ListItem<'src>> {
803 match self {
804 Self::ListItem(li) => Some(li),
805 _ => None,
806 }
807 }
808
809 pub(crate) fn resolve_references(
817 &mut self,
818 resolver: &dyn ReferenceResolver,
819 renderer: &dyn InlineSubstitutionRenderer,
820 warnings: &mut ReferenceWarnings<'src>,
821 ) {
822 if let Some(content) = self.content_mut() {
829 content.resolve_references(resolver, renderer, warnings);
830 }
831
832 if let Self::Table(table) = self {
835 table.resolve_references(resolver, renderer, warnings);
836 }
837
838 if let Self::Quote(quote) = self {
842 quote.resolve_references(resolver, renderer, warnings);
843 }
844
845 for child in self.child_blocks_mut() {
846 child.resolve_references(resolver, renderer, warnings);
847 }
848 }
849
850 pub(crate) fn block_title_content_mut(&mut self) -> Option<&mut Content<'src>> {
859 match self {
860 Self::Simple(b) => b.title_content_mut(),
861 Self::Media(b) => b.title_content_mut(),
862 Self::List(b) => b.title_content_mut(),
863 Self::RawDelimited(b) => b.title_content_mut(),
864 Self::CompoundDelimited(b) => b.title_content_mut(),
865 Self::Admonition(b) => b.title_content_mut(),
866 Self::Quote(b) => b.title_content_mut(),
867 Self::Table(b) => b.title_content_mut(),
868 Self::Break(b) => b.title_content_mut(),
869 _ => None,
870 }
871 }
872}
873
874impl<'src> IsBlock<'src> for Block<'src> {
875 fn content_model(&self) -> ContentModel {
876 match self {
877 Self::Simple(_) => ContentModel::Simple,
878 Self::Media(b) => b.content_model(),
879 Self::Section(_) => ContentModel::Compound,
880 Self::List(b) => b.content_model(),
881 Self::ListItem(b) => b.content_model(),
882 Self::RawDelimited(b) => b.content_model(),
883 Self::CompoundDelimited(b) => b.content_model(),
884 Self::Admonition(b) => b.content_model(),
885 Self::Quote(b) => b.content_model(),
886 Self::Table(b) => b.content_model(),
887 Self::Preamble(b) => b.content_model(),
888 Self::Break(b) => b.content_model(),
889 Self::DocumentAttribute(b) => b.content_model(),
890 }
891 }
892
893 fn declared_style(&'src self) -> Option<&'src str> {
894 match self {
895 Self::Simple(b) => b.declared_style(),
896 Self::Media(b) => b.declared_style(),
897 Self::Section(b) => b.declared_style(),
898 Self::List(b) => b.declared_style(),
899 Self::ListItem(b) => b.declared_style(),
900 Self::RawDelimited(b) => b.declared_style(),
901 Self::CompoundDelimited(b) => b.declared_style(),
902 Self::Admonition(b) => b.declared_style(),
903 Self::Quote(b) => b.declared_style(),
904 Self::Table(b) => b.declared_style(),
905 Self::Preamble(b) => b.declared_style(),
906 Self::Break(b) => b.declared_style(),
907 Self::DocumentAttribute(b) => b.declared_style(),
908 }
909 }
910
911 fn rendered_content(&'src self) -> Option<&'src str> {
912 match self {
913 Self::Simple(b) => b.rendered_content(),
914 Self::Media(b) => b.rendered_content(),
915 Self::Section(b) => b.rendered_content(),
916 Self::List(b) => b.rendered_content(),
917 Self::ListItem(b) => b.rendered_content(),
918 Self::RawDelimited(b) => b.rendered_content(),
919 Self::CompoundDelimited(b) => b.rendered_content(),
920 Self::Admonition(b) => b.rendered_content(),
921 Self::Quote(b) => b.rendered_content(),
922 Self::Table(b) => b.rendered_content(),
923 Self::Preamble(b) => b.rendered_content(),
924 Self::Break(b) => b.rendered_content(),
925 Self::DocumentAttribute(b) => b.rendered_content(),
926 }
927 }
928
929 fn raw_context(&self) -> CowStr<'src> {
930 match self {
931 Self::Simple(b) => b.raw_context(),
932 Self::Media(b) => b.raw_context(),
933 Self::Section(b) => b.raw_context(),
934 Self::List(b) => b.raw_context(),
935 Self::ListItem(b) => b.raw_context(),
936 Self::RawDelimited(b) => b.raw_context(),
937 Self::CompoundDelimited(b) => b.raw_context(),
938 Self::Admonition(b) => b.raw_context(),
939 Self::Quote(b) => b.raw_context(),
940 Self::Table(b) => b.raw_context(),
941 Self::Preamble(b) => b.raw_context(),
942 Self::Break(b) => b.raw_context(),
943 Self::DocumentAttribute(b) => b.raw_context(),
944 }
945 }
946
947 fn child_blocks_mut(&mut self) -> &mut [Block<'src>] {
948 match self {
949 Self::Simple(b) => b.child_blocks_mut(),
950 Self::Media(b) => b.child_blocks_mut(),
951 Self::Section(b) => b.child_blocks_mut(),
952 Self::List(b) => b.child_blocks_mut(),
953 Self::ListItem(b) => b.child_blocks_mut(),
954 Self::RawDelimited(b) => b.child_blocks_mut(),
955 Self::CompoundDelimited(b) => b.child_blocks_mut(),
956 Self::Admonition(b) => b.child_blocks_mut(),
957 Self::Quote(b) => b.child_blocks_mut(),
958 Self::Table(b) => b.child_blocks_mut(),
959 Self::Preamble(b) => b.child_blocks_mut(),
960 Self::Break(b) => b.child_blocks_mut(),
961 Self::DocumentAttribute(b) => b.child_blocks_mut(),
962 }
963 }
964
965 fn content_mut(&mut self) -> Option<&mut Content<'src>> {
966 match self {
967 Self::Simple(b) => b.content_mut(),
968 Self::Media(b) => b.content_mut(),
969 Self::Section(b) => b.content_mut(),
970 Self::List(b) => b.content_mut(),
971 Self::ListItem(b) => b.content_mut(),
972 Self::RawDelimited(b) => b.content_mut(),
973 Self::CompoundDelimited(b) => b.content_mut(),
974 Self::Admonition(b) => b.content_mut(),
975 Self::Quote(b) => b.content_mut(),
976 Self::Table(b) => b.content_mut(),
977 Self::Preamble(b) => b.content_mut(),
978 Self::Break(b) => b.content_mut(),
979 Self::DocumentAttribute(b) => b.content_mut(),
980 }
981 }
982
983 fn title_source(&'src self) -> Option<Span<'src>> {
984 match self {
985 Self::Simple(b) => b.title_source(),
986 Self::Media(b) => b.title_source(),
987 Self::Section(b) => b.title_source(),
988 Self::List(b) => b.title_source(),
989 Self::ListItem(b) => b.title_source(),
990 Self::RawDelimited(b) => b.title_source(),
991 Self::CompoundDelimited(b) => b.title_source(),
992 Self::Admonition(b) => b.title_source(),
993 Self::Quote(b) => b.title_source(),
994 Self::Table(b) => b.title_source(),
995 Self::Preamble(b) => b.title_source(),
996 Self::Break(b) => b.title_source(),
997 Self::DocumentAttribute(b) => b.title_source(),
998 }
999 }
1000
1001 fn title(&self) -> Option<&str> {
1002 match self {
1003 Self::Simple(b) => b.title(),
1004 Self::Media(b) => b.title(),
1005 Self::Section(b) => b.title(),
1006 Self::List(b) => b.title(),
1007 Self::ListItem(b) => b.title(),
1008 Self::RawDelimited(b) => b.title(),
1009 Self::CompoundDelimited(b) => b.title(),
1010 Self::Admonition(b) => b.title(),
1011 Self::Quote(b) => b.title(),
1012 Self::Table(b) => b.title(),
1013 Self::Preamble(b) => b.title(),
1014 Self::Break(b) => b.title(),
1015 Self::DocumentAttribute(b) => b.title(),
1016 }
1017 }
1018
1019 fn caption(&self) -> Option<&str> {
1020 match self {
1021 Self::Simple(b) => b.caption(),
1022 Self::Media(b) => b.caption(),
1023 Self::Section(b) => b.caption(),
1024 Self::List(b) => b.caption(),
1025 Self::ListItem(b) => b.caption(),
1026 Self::RawDelimited(b) => b.caption(),
1027 Self::CompoundDelimited(b) => b.caption(),
1028 Self::Admonition(b) => b.caption(),
1029 Self::Quote(b) => b.caption(),
1030 Self::Table(b) => b.caption(),
1031 Self::Preamble(b) => b.caption(),
1032 Self::Break(b) => b.caption(),
1033 Self::DocumentAttribute(b) => b.caption(),
1034 }
1035 }
1036
1037 fn number(&self) -> Option<usize> {
1038 match self {
1039 Self::Simple(b) => b.number(),
1040 Self::Media(b) => b.number(),
1041 Self::Section(b) => b.number(),
1042 Self::List(b) => b.number(),
1043 Self::ListItem(b) => b.number(),
1044 Self::RawDelimited(b) => b.number(),
1045 Self::CompoundDelimited(b) => b.number(),
1046 Self::Admonition(b) => b.number(),
1047 Self::Quote(b) => b.number(),
1048 Self::Table(b) => b.number(),
1049 Self::Preamble(b) => b.number(),
1050 Self::Break(b) => b.number(),
1051 Self::DocumentAttribute(b) => b.number(),
1052 }
1053 }
1054
1055 fn id(&'src self) -> Option<&'src str> {
1056 match self {
1070 Self::Media(b) => b.id(),
1071 Self::Section(b) => b.id(),
1072 _ => self
1073 .anchor()
1074 .map(|a| a.data())
1075 .or_else(|| self.attrlist().and_then(|attrlist| attrlist.id())),
1076 }
1077 }
1078
1079 fn anchor(&'src self) -> Option<Span<'src>> {
1080 match self {
1081 Self::Simple(b) => b.anchor(),
1082 Self::Media(b) => b.anchor(),
1083 Self::Section(b) => b.anchor(),
1084 Self::List(b) => b.anchor(),
1085 Self::ListItem(b) => b.anchor(),
1086 Self::RawDelimited(b) => b.anchor(),
1087 Self::CompoundDelimited(b) => b.anchor(),
1088 Self::Admonition(b) => b.anchor(),
1089 Self::Quote(b) => b.anchor(),
1090 Self::Table(b) => b.anchor(),
1091 Self::Preamble(b) => b.anchor(),
1092 Self::Break(b) => b.anchor(),
1093 Self::DocumentAttribute(b) => b.anchor(),
1094 }
1095 }
1096
1097 fn anchor_reftext(&'src self) -> Option<Span<'src>> {
1098 match self {
1099 Self::Simple(b) => b.anchor_reftext(),
1100 Self::Media(b) => b.anchor_reftext(),
1101 Self::Section(b) => b.anchor_reftext(),
1102 Self::List(b) => b.anchor_reftext(),
1103 Self::ListItem(b) => b.anchor_reftext(),
1104 Self::RawDelimited(b) => b.anchor_reftext(),
1105 Self::CompoundDelimited(b) => b.anchor_reftext(),
1106 Self::Admonition(b) => b.anchor_reftext(),
1107 Self::Quote(b) => b.anchor_reftext(),
1108 Self::Table(b) => b.anchor_reftext(),
1109 Self::Preamble(b) => b.anchor_reftext(),
1110 Self::Break(b) => b.anchor_reftext(),
1111 Self::DocumentAttribute(b) => b.anchor_reftext(),
1112 }
1113 }
1114
1115 fn attrlist(&'src self) -> Option<&'src Attrlist<'src>> {
1116 match self {
1117 Self::Simple(b) => b.attrlist(),
1118 Self::Media(b) => b.attrlist(),
1119 Self::Section(b) => b.attrlist(),
1120 Self::List(b) => b.attrlist(),
1121 Self::ListItem(b) => b.attrlist(),
1122 Self::RawDelimited(b) => b.attrlist(),
1123 Self::CompoundDelimited(b) => b.attrlist(),
1124 Self::Admonition(b) => b.attrlist(),
1125 Self::Quote(b) => b.attrlist(),
1126 Self::Table(b) => b.attrlist(),
1127 Self::Preamble(b) => b.attrlist(),
1128 Self::Break(b) => b.attrlist(),
1129 Self::DocumentAttribute(b) => b.attrlist(),
1130 }
1131 }
1132
1133 fn substitution_group(&self) -> SubstitutionGroup {
1134 match self {
1135 Self::Simple(b) => b.substitution_group(),
1136 Self::Media(b) => b.substitution_group(),
1137 Self::Section(b) => b.substitution_group(),
1138 Self::List(b) => b.substitution_group(),
1139 Self::ListItem(b) => b.substitution_group(),
1140 Self::RawDelimited(b) => b.substitution_group(),
1141 Self::CompoundDelimited(b) => b.substitution_group(),
1142 Self::Admonition(b) => b.substitution_group(),
1143 Self::Quote(b) => b.substitution_group(),
1144 Self::Table(b) => b.substitution_group(),
1145 Self::Preamble(b) => b.substitution_group(),
1146 Self::Break(b) => b.substitution_group(),
1147 Self::DocumentAttribute(b) => b.substitution_group(),
1148 }
1149 }
1150}
1151
1152impl<'src> HasSpan<'src> for Block<'src> {
1153 fn span(&self) -> Span<'src> {
1154 match self {
1155 Self::Simple(b) => b.span(),
1156 Self::Media(b) => b.span(),
1157 Self::Section(b) => b.span(),
1158 Self::List(b) => b.span(),
1159 Self::ListItem(b) => b.span(),
1160 Self::RawDelimited(b) => b.span(),
1161 Self::CompoundDelimited(b) => b.span(),
1162 Self::Admonition(b) => b.span(),
1163 Self::Quote(b) => b.span(),
1164 Self::Table(b) => b.span(),
1165 Self::Preamble(b) => b.span(),
1166 Self::Break(b) => b.span(),
1167 Self::DocumentAttribute(b) => b.span(),
1168 }
1169 }
1170}