1use std::slice::Iter;
2
3use crate::{
4 HasSpan, Parser, Span,
5 attributes::Attrlist,
6 blocks::{
7 AdmonitionBlock, Break, CompoundDelimitedBlock, ContentModel, IsBlock, ListBlock, ListItem,
8 ListItemMarker, MediaBlock, Preamble, QuoteBlock, RawDelimitedBlock, SectionBlock,
9 SimpleBlock, TableBlock, media::TargetResolution, metadata::BlockMetadata,
10 starts_with_admonition_label,
11 },
12 content::{Content, SubstitutionGroup, substitute_attributes_in_reftext},
13 document::{Attribute, InterpretedValue, RefType},
14 parser::{InlineSubstitutionRenderer, ReferenceResolver, ReferenceWarnings, XrefSignifier},
15 span::MatchedItem,
16 strings::CowStr,
17 warnings::{MatchAndWarnings, Warning, WarningType},
18};
19
20#[derive(Clone, Eq, PartialEq)]
33#[allow(clippy::large_enum_variant)] #[non_exhaustive]
35pub enum Block<'src> {
36 Simple(SimpleBlock<'src>),
39
40 Media(MediaBlock<'src>),
43
44 Section(SectionBlock<'src>),
47
48 List(ListBlock<'src>),
52
53 ListItem(ListItem<'src>),
56
57 RawDelimited(RawDelimitedBlock<'src>),
61
62 CompoundDelimited(CompoundDelimitedBlock<'src>),
64
65 Admonition(AdmonitionBlock<'src>),
69
70 Quote(QuoteBlock<'src>),
73
74 Table(TableBlock<'src>),
76
77 Preamble(Preamble<'src>),
80
81 Break(Break<'src>),
83
84 DocumentAttribute(Attribute<'src>),
87}
88
89impl<'src> std::fmt::Debug for Block<'src> {
90 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91 match self {
92 Block::Simple(block) => f.debug_tuple("Block::Simple").field(block).finish(),
93 Block::Media(block) => f.debug_tuple("Block::Media").field(block).finish(),
94 Block::Section(block) => f.debug_tuple("Block::Section").field(block).finish(),
95 Block::List(block) => f.debug_tuple("Block::List").field(block).finish(),
96 Block::ListItem(block) => f.debug_tuple("Block::ListItem").field(block).finish(),
97
98 Block::RawDelimited(block) => {
99 f.debug_tuple("Block::RawDelimited").field(block).finish()
100 }
101
102 Block::CompoundDelimited(block) => f
103 .debug_tuple("Block::CompoundDelimited")
104 .field(block)
105 .finish(),
106
107 Block::Admonition(block) => f.debug_tuple("Block::Admonition").field(block).finish(),
108 Block::Quote(block) => f.debug_tuple("Block::Quote").field(block).finish(),
109 Block::Table(block) => f.debug_tuple("Block::Table").field(block).finish(),
110 Block::Preamble(block) => f.debug_tuple("Block::Preamble").field(block).finish(),
111 Block::Break(break_) => f.debug_tuple("Block::Break").field(break_).finish(),
112
113 Block::DocumentAttribute(block) => f
114 .debug_tuple("Block::DocumentAttribute")
115 .field(block)
116 .finish(),
117 }
118 }
119}
120
121#[allow(clippy::large_enum_variant)]
133pub(crate) enum BlockParseOutcome<'src> {
134 Parsed(MatchedItem<'src, Block<'src>>),
136
137 Dropped(Span<'src>),
142
143 NoMatch,
145}
146
147impl<'src> Block<'src> {
148 #[cfg(test)]
157 pub(crate) fn parse(
158 source: Span<'src>,
159 parser: &mut Parser,
160 ) -> MatchAndWarnings<'src, Option<MatchedItem<'src, Self>>> {
161 let MatchAndWarnings { item, warnings } = Self::parse_internal(source, parser, None, false);
162
163 MatchAndWarnings {
164 item: match item {
165 BlockParseOutcome::Parsed(mi) => Some(mi),
166 BlockParseOutcome::Dropped(_) | BlockParseOutcome::NoMatch => None,
167 },
168 warnings,
169 }
170 }
171
172 pub(crate) fn parse_with_outcome(
179 source: Span<'src>,
180 parser: &mut Parser,
181 ) -> MatchAndWarnings<'src, BlockParseOutcome<'src>> {
182 Self::parse_internal(source, parser, None, false)
183 }
184
185 pub(crate) fn parse_for_list_item(
196 source: Span<'src>,
197 parser: &mut Parser,
198 parent_list_markers: &[ListItemMarker<'src>],
199 is_continuation: bool,
200 ) -> MatchAndWarnings<'src, BlockParseOutcome<'src>> {
201 Self::parse_internal(source, parser, Some(parent_list_markers), is_continuation)
202 }
203
204 fn parse_internal(
207 source: Span<'src>,
208 parser: &mut Parser,
209 parent_list_markers: Option<&[ListItemMarker<'src>]>,
210 is_continuation: bool,
211 ) -> MatchAndWarnings<'src, BlockParseOutcome<'src>> {
212 let first_line = source.take_line().item.discard_whitespace();
216
217 if let Some(first_char) = first_line.chars().next()
220 && !matches!(
221 first_char,
222 '.' | '#'
223 | '='
224 | '/'
225 | '-'
226 | '+'
227 | '*'
228 | '_'
229 | '`'
230 | '['
231 | ':'
232 | '\''
233 | '<'
234 | '>'
235 | '"'
236 | '•'
237 )
238 && !first_line.contains("::")
239 && !first_line.contains(";;")
240 && !TableBlock::is_table_delimiter(&first_line)
241 && !ListItemMarker::starts_with_marker(first_line)
242 && !starts_with_admonition_label(first_line)
243 && parent_list_markers.is_none()
244 && parser.pending_block_title.is_none()
245 && let Some(MatchedItem {
246 item: simple_block,
247 after,
248 }) = SimpleBlock::parse_fast(source, parser)
249 {
250 let mut warnings = vec![];
251 let block = Self::Simple(simple_block);
252
253 Self::register_block_id(
256 block.id(),
257 Self::block_reftext(&block, None).as_deref(),
258 Self::block_signifier(&block, parser),
259 block.span(),
260 parser,
261 &mut warnings,
262 );
263
264 return MatchAndWarnings {
265 item: BlockParseOutcome::Parsed(MatchedItem { item: block, after }),
266 warnings,
267 };
268 }
269
270 if first_line.starts_with(':')
272 && (first_line.ends_with(':') || first_line.contains(": "))
273 && let Some(attr) = Attribute::parse(source, parser)
274 {
275 let mut warnings: Vec<Warning<'src>> = vec![];
276 parser.set_attribute_from_body(&attr.item, &mut warnings);
277
278 return MatchAndWarnings {
279 item: BlockParseOutcome::Parsed(MatchedItem {
280 item: Self::DocumentAttribute(attr.item),
281 after: attr.after,
282 }),
283 warnings,
284 };
285 }
286
287 let MatchAndWarnings {
290 item: mut metadata,
291 mut warnings,
292 } = BlockMetadata::parse(source, parser);
293
294 if let Some(pending_title) = parser.pending_block_title.take()
300 && metadata.title.is_none()
301 {
302 metadata.title = Some(crate::content::Content::from_owned_title(
306 metadata.block_start,
307 pending_title,
308 ));
309 }
310
311 if parent_list_markers.is_none() && !metadata.is_empty() {
326 let after_blanks = metadata.block_start.discard_empty_lines();
327 if after_blanks != metadata.block_start && !after_blanks.is_empty() {
328 metadata.block_start = after_blanks;
329 }
330 }
331
332 let anchor_reftext = metadata
338 .anchor_reftext
339 .as_ref()
340 .map(|span| substitute_attributes_in_reftext(*span, parser));
341
342 let is_literal =
350 metadata.attrlist.as_ref().and_then(|a| a.block_style()) == Some("literal") && {
351 let first_line = metadata.block_start.take_normalized_line().item;
352 !RawDelimitedBlock::is_valid_delimiter(&first_line)
353 && !CompoundDelimitedBlock::is_valid_delimiter(&first_line)
354 && !TableBlock::is_table_delimiter(&first_line)
355 };
356
357 let mut simple_block_mi = None;
364
365 if !is_literal {
366 if let Some(mut adm_maw) = AdmonitionBlock::parse(&metadata, parser)
367 && let Some(adm) = adm_maw.item
368 {
369 if !adm_maw.warnings.is_empty() {
370 warnings.append(&mut adm_maw.warnings);
371 }
372
373 let block = Self::Admonition(adm.item);
374
375 Self::register_block_id(
376 block.id(),
377 Self::block_reftext(&block, anchor_reftext.as_deref()).as_deref(),
378 Self::block_signifier(&block, parser),
379 block.span(),
380 parser,
381 &mut warnings,
382 );
383
384 return MatchAndWarnings {
385 item: BlockParseOutcome::Parsed(MatchedItem {
386 item: block,
387 after: adm.after,
388 }),
389 warnings,
390 };
391 }
392
393 if let Some(mut quote_maw) = QuoteBlock::parse(&metadata, parser)
394 && let Some(quote) = quote_maw.item
395 {
396 if !quote_maw.warnings.is_empty() {
397 warnings.append(&mut quote_maw.warnings);
398 }
399
400 let block = Self::Quote(quote.item);
401
402 Self::register_block_id(
403 block.id(),
404 Self::block_reftext(&block, anchor_reftext.as_deref()).as_deref(),
405 Self::block_signifier(&block, parser),
406 block.span(),
407 parser,
408 &mut warnings,
409 );
410
411 return MatchAndWarnings {
412 item: BlockParseOutcome::Parsed(MatchedItem {
413 item: block,
414 after: quote.after,
415 }),
416 warnings,
417 };
418 }
419
420 if let Some(mut rdb_maw) = RawDelimitedBlock::parse(&metadata, parser)
421 && let Some(rdb) = rdb_maw.item
422 {
423 if !rdb_maw.warnings.is_empty() {
424 warnings.append(&mut rdb_maw.warnings);
425 }
426
427 let block = Self::RawDelimited(rdb.item);
428
429 Self::register_block_id(
430 block.id(),
431 Self::block_reftext(&block, anchor_reftext.as_deref()).as_deref(),
432 Self::block_signifier(&block, parser),
433 block.span(),
434 parser,
435 &mut warnings,
436 );
437
438 return MatchAndWarnings {
439 item: BlockParseOutcome::Parsed(MatchedItem {
440 item: block,
441 after: rdb.after,
442 }),
443 warnings,
444 };
445 }
446
447 if let Some(mut cdb_maw) = CompoundDelimitedBlock::parse(&metadata, parser)
448 && let Some(cdb) = cdb_maw.item
449 {
450 if !cdb_maw.warnings.is_empty() {
451 warnings.append(&mut cdb_maw.warnings);
452 }
453
454 let block = Self::CompoundDelimited(cdb.item);
455
456 Self::register_block_id(
457 block.id(),
458 Self::block_reftext(&block, anchor_reftext.as_deref()).as_deref(),
459 Self::block_signifier(&block, parser),
460 block.span(),
461 parser,
462 &mut warnings,
463 );
464
465 return MatchAndWarnings {
466 item: BlockParseOutcome::Parsed(MatchedItem {
467 item: block,
468 after: cdb.after,
469 }),
470 warnings,
471 };
472 }
473
474 if let Some(mut table_maw) = TableBlock::parse(&metadata, parser)
475 && let Some(table) = table_maw.item
476 {
477 if !table_maw.warnings.is_empty() {
478 warnings.append(&mut table_maw.warnings);
479 }
480
481 let block = Self::Table(table.item);
482
483 Self::register_block_id(
484 block.id(),
485 Self::block_reftext(&block, anchor_reftext.as_deref()).as_deref(),
486 Self::block_signifier(&block, parser),
487 block.span(),
488 parser,
489 &mut warnings,
490 );
491
492 return MatchAndWarnings {
493 item: BlockParseOutcome::Parsed(MatchedItem {
494 item: block,
495 after: table.after,
496 }),
497 warnings,
498 };
499 }
500
501 let line = metadata.block_start.take_normalized_line();
503
504 if line.item.starts_with("image::")
505 || line.item.starts_with("video::")
506 || line.item.starts_with("audio::")
507 {
508 let mut media_block_maw = MediaBlock::parse(&metadata, parser);
509
510 if let Some(mut media_block) = media_block_maw.item {
511 if !media_block_maw.warnings.is_empty() {
515 warnings.append(&mut media_block_maw.warnings);
516 }
517
518 if media_block.item.resolve_target(parser) == TargetResolution::Drop {
522 return MatchAndWarnings {
523 item: BlockParseOutcome::Dropped(media_block.after),
524 warnings,
525 };
526 }
527
528 media_block.item.assign_caption(parser);
532
533 let block = Self::Media(media_block.item);
534
535 Self::register_block_id(
536 block.id(),
537 Self::block_reftext(&block, anchor_reftext.as_deref()).as_deref(),
538 Self::block_signifier(&block, parser),
539 block.span(),
540 parser,
541 &mut warnings,
542 );
543
544 return MatchAndWarnings {
545 item: BlockParseOutcome::Parsed(MatchedItem {
546 item: block,
547 after: media_block.after,
548 }),
549 warnings,
550 };
551 }
552
553 }
556
557 if (line.item.starts_with('=') || line.item.starts_with('#'))
558 && let Some(mi_section_block) =
559 SectionBlock::parse(&metadata, parser, &mut warnings)
560 {
561 return MatchAndWarnings {
565 item: BlockParseOutcome::Parsed(MatchedItem {
566 item: Self::Section(mi_section_block.item),
567 after: mi_section_block.after,
568 }),
569 warnings,
570 };
571 }
572
573 if (line.item.starts_with('\'')
574 || line.item.starts_with('-')
575 || line.item.starts_with('*')
576 || line.item.starts_with('_')
577 || line.item.starts_with('<'))
578 && let Some(mi_break) = Break::parse(&metadata, parser)
579 {
580 return MatchAndWarnings {
583 item: BlockParseOutcome::Parsed(MatchedItem {
584 item: Self::Break(mi_break.item),
585 after: mi_break.after,
586 }),
587 warnings,
588 };
589 }
590
591 if parent_list_markers.is_none()
595 && let Some(mi_list) = ListBlock::parse(&metadata, parser, &mut warnings)
596 {
597 return MatchAndWarnings {
598 item: BlockParseOutcome::Parsed(MatchedItem {
599 item: Self::List(mi_list.item),
600 after: mi_list.after,
601 }),
602 warnings,
603 };
604 }
605
606 simple_block_mi = if let Some(plm) = parent_list_markers {
613 SimpleBlock::parse_for_list_item(&metadata, parser, is_continuation, plm)
614 } else {
615 SimpleBlock::parse(&metadata, parser)
616 };
617
618 if simple_block_mi.is_none() && !metadata.is_empty() {
619 warnings.push(Warning {
623 source: metadata.source,
624 warning: WarningType::MissingBlockAfterTitleOrAttributeList,
625 origin: None,
626 });
627
628 metadata.title_source = None;
632 metadata.title = None;
633 metadata.anchor = None;
634 metadata.attrlist = None;
635 metadata.block_start = metadata.source;
636 }
637 }
638
639 let simple_block_mi = match simple_block_mi {
643 Some(mi) => Some(mi),
644 None => {
645 if let Some(plm) = parent_list_markers {
646 SimpleBlock::parse_for_list_item(&metadata, parser, is_continuation, plm)
647 } else {
648 SimpleBlock::parse(&metadata, parser)
649 }
650 }
651 };
652
653 let mut result = MatchAndWarnings {
654 item: match simple_block_mi {
655 Some(mi) => BlockParseOutcome::Parsed(MatchedItem {
656 item: Self::Simple(mi.item),
657 after: mi.after,
658 }),
659 None => BlockParseOutcome::NoMatch,
660 },
661 warnings,
662 };
663
664 if let BlockParseOutcome::Parsed(ref matched_item) = result.item {
665 Self::register_block_id(
666 matched_item.item.id(),
667 Self::block_reftext(&matched_item.item, anchor_reftext.as_deref()).as_deref(),
668 Self::block_signifier(&matched_item.item, parser),
669 matched_item.item.span(),
670 parser,
671 &mut result.warnings,
672 );
673 }
674
675 result
676 }
677
678 fn block_signifier<'a>(block: &'a Block<'a>, parser: &Parser) -> Option<XrefSignifier> {
689 let caption = block.caption()?;
691
692 let has_explicit_reftext = block
693 .attrlist()
694 .and_then(|attrlist| attrlist.named_attribute("reftext"))
695 .is_some()
696 || block.anchor_reftext().is_some();
697 if has_explicit_reftext {
698 return None;
699 }
700
701 if Self::has_caption_override(block, parser) {
707 return None;
708 }
709
710 let label = caption.strip_suffix(". ").unwrap_or(caption).to_string();
713 Some(XrefSignifier {
714 label,
715 emphasize: false,
716 })
717 }
718
719 fn has_caption_override<'a>(block: &'a Block<'a>, parser: &Parser) -> bool {
729 let attribute_override = block
730 .attrlist()
731 .and_then(|attrlist| attrlist.named_attribute("caption"))
732 .is_some()
733 || matches!(block, Block::Media(media)
734 if media.macro_attrlist().named_attribute("caption").is_some());
735
736 attribute_override
737 || matches!(
738 parser.attribute_value("caption"),
739 InterpretedValue::Value(value) if !value.is_empty(),
740 )
741 }
742
743 fn block_reftext<'a>(block: &'a Block<'a>, anchor_reftext: Option<&str>) -> Option<CowStr<'a>> {
757 if let Some(attr) = block
758 .attrlist()
759 .and_then(|attrlist| attrlist.named_attribute("reftext"))
760 {
761 return Some(CowStr::from(attr.value()));
762 }
763
764 if let Some(anchor_reftext) = anchor_reftext {
765 return Some(CowStr::from(anchor_reftext.to_string()));
766 }
767
768 block.title().map(CowStr::from)
769 }
770
771 fn register_block_id(
776 id: Option<&str>,
777 reftext: Option<&str>,
778 signifier: Option<XrefSignifier>,
779 span: Span<'src>,
780 parser: &mut Parser,
781 warnings: &mut Vec<Warning<'src>>,
782 ) {
783 if let Some(id) = id {
784 match parser.register_ref(id, reftext, RefType::Anchor) {
785 Ok(()) => {
786 if let Some(signifier) = signifier {
787 parser.set_ref_signifier(id, signifier);
788 }
789 }
790 Err(_duplicate_error) => {
791 warnings.push(Warning {
793 source: span,
794 warning: WarningType::DuplicateId(id.to_string()),
795 origin: None,
796 });
797 }
798 }
799 }
800 }
801
802 pub(crate) fn as_list_item(&self) -> Option<&ListItem<'src>> {
805 match self {
806 Self::ListItem(li) => Some(li),
807 _ => None,
808 }
809 }
810
811 pub(crate) fn resolve_references(
819 &mut self,
820 resolver: &dyn ReferenceResolver,
821 renderer: &dyn InlineSubstitutionRenderer,
822 warnings: &mut ReferenceWarnings<'src>,
823 ) {
824 if let Some(content) = self.content_mut() {
831 content.resolve_references(resolver, renderer, warnings);
832 }
833
834 if let Self::Table(table) = self {
837 table.resolve_references(resolver, renderer, warnings);
838 }
839
840 if let Self::Quote(quote) = self {
844 quote.resolve_references(resolver, renderer, warnings);
845 }
846
847 for child in self.nested_blocks_mut() {
848 child.resolve_references(resolver, renderer, warnings);
849 }
850 }
851
852 pub(crate) fn block_title_content_mut(&mut self) -> Option<&mut Content<'src>> {
861 match self {
862 Self::Simple(b) => b.title_content_mut(),
863 Self::Media(b) => b.title_content_mut(),
864 Self::List(b) => b.title_content_mut(),
865 Self::RawDelimited(b) => b.title_content_mut(),
866 Self::CompoundDelimited(b) => b.title_content_mut(),
867 Self::Admonition(b) => b.title_content_mut(),
868 Self::Quote(b) => b.title_content_mut(),
869 Self::Table(b) => b.title_content_mut(),
870 Self::Break(b) => b.title_content_mut(),
871 _ => None,
872 }
873 }
874}
875
876impl<'src> IsBlock<'src> for Block<'src> {
877 fn content_model(&self) -> ContentModel {
878 match self {
879 Self::Simple(_) => ContentModel::Simple,
880 Self::Media(b) => b.content_model(),
881 Self::Section(_) => ContentModel::Compound,
882 Self::List(b) => b.content_model(),
883 Self::ListItem(b) => b.content_model(),
884 Self::RawDelimited(b) => b.content_model(),
885 Self::CompoundDelimited(b) => b.content_model(),
886 Self::Admonition(b) => b.content_model(),
887 Self::Quote(b) => b.content_model(),
888 Self::Table(b) => b.content_model(),
889 Self::Preamble(b) => b.content_model(),
890 Self::Break(b) => b.content_model(),
891 Self::DocumentAttribute(b) => b.content_model(),
892 }
893 }
894
895 fn declared_style(&'src self) -> Option<&'src str> {
896 match self {
897 Self::Simple(b) => b.declared_style(),
898 Self::Media(b) => b.declared_style(),
899 Self::Section(b) => b.declared_style(),
900 Self::List(b) => b.declared_style(),
901 Self::ListItem(b) => b.declared_style(),
902 Self::RawDelimited(b) => b.declared_style(),
903 Self::CompoundDelimited(b) => b.declared_style(),
904 Self::Admonition(b) => b.declared_style(),
905 Self::Quote(b) => b.declared_style(),
906 Self::Table(b) => b.declared_style(),
907 Self::Preamble(b) => b.declared_style(),
908 Self::Break(b) => b.declared_style(),
909 Self::DocumentAttribute(b) => b.declared_style(),
910 }
911 }
912
913 fn rendered_content(&'src self) -> Option<&'src str> {
914 match self {
915 Self::Simple(b) => b.rendered_content(),
916 Self::Media(b) => b.rendered_content(),
917 Self::Section(b) => b.rendered_content(),
918 Self::List(b) => b.rendered_content(),
919 Self::ListItem(b) => b.rendered_content(),
920 Self::RawDelimited(b) => b.rendered_content(),
921 Self::CompoundDelimited(b) => b.rendered_content(),
922 Self::Admonition(b) => b.rendered_content(),
923 Self::Quote(b) => b.rendered_content(),
924 Self::Table(b) => b.rendered_content(),
925 Self::Preamble(b) => b.rendered_content(),
926 Self::Break(b) => b.rendered_content(),
927 Self::DocumentAttribute(b) => b.rendered_content(),
928 }
929 }
930
931 fn raw_context(&self) -> CowStr<'src> {
932 match self {
933 Self::Simple(b) => b.raw_context(),
934 Self::Media(b) => b.raw_context(),
935 Self::Section(b) => b.raw_context(),
936 Self::List(b) => b.raw_context(),
937 Self::ListItem(b) => b.raw_context(),
938 Self::RawDelimited(b) => b.raw_context(),
939 Self::CompoundDelimited(b) => b.raw_context(),
940 Self::Admonition(b) => b.raw_context(),
941 Self::Quote(b) => b.raw_context(),
942 Self::Table(b) => b.raw_context(),
943 Self::Preamble(b) => b.raw_context(),
944 Self::Break(b) => b.raw_context(),
945 Self::DocumentAttribute(b) => b.raw_context(),
946 }
947 }
948
949 fn nested_blocks(&'src self) -> Iter<'src, Block<'src>> {
950 match self {
951 Self::Simple(b) => b.nested_blocks(),
952 Self::Media(b) => b.nested_blocks(),
953 Self::Section(b) => b.nested_blocks(),
954 Self::List(b) => b.nested_blocks(),
955 Self::ListItem(b) => b.nested_blocks(),
956 Self::RawDelimited(b) => b.nested_blocks(),
957 Self::CompoundDelimited(b) => b.nested_blocks(),
958 Self::Admonition(b) => b.nested_blocks(),
959 Self::Quote(b) => b.nested_blocks(),
960 Self::Table(b) => b.nested_blocks(),
961 Self::Preamble(b) => b.nested_blocks(),
962 Self::Break(b) => b.nested_blocks(),
963 Self::DocumentAttribute(b) => b.nested_blocks(),
964 }
965 }
966
967 fn nested_blocks_mut(&mut self) -> &mut [Block<'src>] {
968 match self {
969 Self::Simple(b) => b.nested_blocks_mut(),
970 Self::Media(b) => b.nested_blocks_mut(),
971 Self::Section(b) => b.nested_blocks_mut(),
972 Self::List(b) => b.nested_blocks_mut(),
973 Self::ListItem(b) => b.nested_blocks_mut(),
974 Self::RawDelimited(b) => b.nested_blocks_mut(),
975 Self::CompoundDelimited(b) => b.nested_blocks_mut(),
976 Self::Admonition(b) => b.nested_blocks_mut(),
977 Self::Quote(b) => b.nested_blocks_mut(),
978 Self::Table(b) => b.nested_blocks_mut(),
979 Self::Preamble(b) => b.nested_blocks_mut(),
980 Self::Break(b) => b.nested_blocks_mut(),
981 Self::DocumentAttribute(b) => b.nested_blocks_mut(),
982 }
983 }
984
985 fn content_mut(&mut self) -> Option<&mut Content<'src>> {
986 match self {
987 Self::Simple(b) => b.content_mut(),
988 Self::Media(b) => b.content_mut(),
989 Self::Section(b) => b.content_mut(),
990 Self::List(b) => b.content_mut(),
991 Self::ListItem(b) => b.content_mut(),
992 Self::RawDelimited(b) => b.content_mut(),
993 Self::CompoundDelimited(b) => b.content_mut(),
994 Self::Admonition(b) => b.content_mut(),
995 Self::Quote(b) => b.content_mut(),
996 Self::Table(b) => b.content_mut(),
997 Self::Preamble(b) => b.content_mut(),
998 Self::Break(b) => b.content_mut(),
999 Self::DocumentAttribute(b) => b.content_mut(),
1000 }
1001 }
1002
1003 fn title_source(&'src self) -> Option<Span<'src>> {
1004 match self {
1005 Self::Simple(b) => b.title_source(),
1006 Self::Media(b) => b.title_source(),
1007 Self::Section(b) => b.title_source(),
1008 Self::List(b) => b.title_source(),
1009 Self::ListItem(b) => b.title_source(),
1010 Self::RawDelimited(b) => b.title_source(),
1011 Self::CompoundDelimited(b) => b.title_source(),
1012 Self::Admonition(b) => b.title_source(),
1013 Self::Quote(b) => b.title_source(),
1014 Self::Table(b) => b.title_source(),
1015 Self::Preamble(b) => b.title_source(),
1016 Self::Break(b) => b.title_source(),
1017 Self::DocumentAttribute(b) => b.title_source(),
1018 }
1019 }
1020
1021 fn title(&self) -> Option<&str> {
1022 match self {
1023 Self::Simple(b) => b.title(),
1024 Self::Media(b) => b.title(),
1025 Self::Section(b) => b.title(),
1026 Self::List(b) => b.title(),
1027 Self::ListItem(b) => b.title(),
1028 Self::RawDelimited(b) => b.title(),
1029 Self::CompoundDelimited(b) => b.title(),
1030 Self::Admonition(b) => b.title(),
1031 Self::Quote(b) => b.title(),
1032 Self::Table(b) => b.title(),
1033 Self::Preamble(b) => b.title(),
1034 Self::Break(b) => b.title(),
1035 Self::DocumentAttribute(b) => b.title(),
1036 }
1037 }
1038
1039 fn caption(&self) -> Option<&str> {
1040 match self {
1041 Self::Simple(b) => b.caption(),
1042 Self::Media(b) => b.caption(),
1043 Self::Section(b) => b.caption(),
1044 Self::List(b) => b.caption(),
1045 Self::ListItem(b) => b.caption(),
1046 Self::RawDelimited(b) => b.caption(),
1047 Self::CompoundDelimited(b) => b.caption(),
1048 Self::Admonition(b) => b.caption(),
1049 Self::Quote(b) => b.caption(),
1050 Self::Table(b) => b.caption(),
1051 Self::Preamble(b) => b.caption(),
1052 Self::Break(b) => b.caption(),
1053 Self::DocumentAttribute(b) => b.caption(),
1054 }
1055 }
1056
1057 fn number(&self) -> Option<usize> {
1058 match self {
1059 Self::Simple(b) => b.number(),
1060 Self::Media(b) => b.number(),
1061 Self::Section(b) => b.number(),
1062 Self::List(b) => b.number(),
1063 Self::ListItem(b) => b.number(),
1064 Self::RawDelimited(b) => b.number(),
1065 Self::CompoundDelimited(b) => b.number(),
1066 Self::Admonition(b) => b.number(),
1067 Self::Quote(b) => b.number(),
1068 Self::Table(b) => b.number(),
1069 Self::Preamble(b) => b.number(),
1070 Self::Break(b) => b.number(),
1071 Self::DocumentAttribute(b) => b.number(),
1072 }
1073 }
1074
1075 fn id(&'src self) -> Option<&'src str> {
1076 match self {
1090 Self::Media(b) => b.id(),
1091 Self::Section(b) => b.id(),
1092 _ => self
1093 .anchor()
1094 .map(|a| a.data())
1095 .or_else(|| self.attrlist().and_then(|attrlist| attrlist.id())),
1096 }
1097 }
1098
1099 fn anchor(&'src self) -> Option<Span<'src>> {
1100 match self {
1101 Self::Simple(b) => b.anchor(),
1102 Self::Media(b) => b.anchor(),
1103 Self::Section(b) => b.anchor(),
1104 Self::List(b) => b.anchor(),
1105 Self::ListItem(b) => b.anchor(),
1106 Self::RawDelimited(b) => b.anchor(),
1107 Self::CompoundDelimited(b) => b.anchor(),
1108 Self::Admonition(b) => b.anchor(),
1109 Self::Quote(b) => b.anchor(),
1110 Self::Table(b) => b.anchor(),
1111 Self::Preamble(b) => b.anchor(),
1112 Self::Break(b) => b.anchor(),
1113 Self::DocumentAttribute(b) => b.anchor(),
1114 }
1115 }
1116
1117 fn anchor_reftext(&'src self) -> Option<Span<'src>> {
1118 match self {
1119 Self::Simple(b) => b.anchor_reftext(),
1120 Self::Media(b) => b.anchor_reftext(),
1121 Self::Section(b) => b.anchor_reftext(),
1122 Self::List(b) => b.anchor_reftext(),
1123 Self::ListItem(b) => b.anchor_reftext(),
1124 Self::RawDelimited(b) => b.anchor_reftext(),
1125 Self::CompoundDelimited(b) => b.anchor_reftext(),
1126 Self::Admonition(b) => b.anchor_reftext(),
1127 Self::Quote(b) => b.anchor_reftext(),
1128 Self::Table(b) => b.anchor_reftext(),
1129 Self::Preamble(b) => b.anchor_reftext(),
1130 Self::Break(b) => b.anchor_reftext(),
1131 Self::DocumentAttribute(b) => b.anchor_reftext(),
1132 }
1133 }
1134
1135 fn attrlist(&'src self) -> Option<&'src Attrlist<'src>> {
1136 match self {
1137 Self::Simple(b) => b.attrlist(),
1138 Self::Media(b) => b.attrlist(),
1139 Self::Section(b) => b.attrlist(),
1140 Self::List(b) => b.attrlist(),
1141 Self::ListItem(b) => b.attrlist(),
1142 Self::RawDelimited(b) => b.attrlist(),
1143 Self::CompoundDelimited(b) => b.attrlist(),
1144 Self::Admonition(b) => b.attrlist(),
1145 Self::Quote(b) => b.attrlist(),
1146 Self::Table(b) => b.attrlist(),
1147 Self::Preamble(b) => b.attrlist(),
1148 Self::Break(b) => b.attrlist(),
1149 Self::DocumentAttribute(b) => b.attrlist(),
1150 }
1151 }
1152
1153 fn substitution_group(&self) -> SubstitutionGroup {
1154 match self {
1155 Self::Simple(b) => b.substitution_group(),
1156 Self::Media(b) => b.substitution_group(),
1157 Self::Section(b) => b.substitution_group(),
1158 Self::List(b) => b.substitution_group(),
1159 Self::ListItem(b) => b.substitution_group(),
1160 Self::RawDelimited(b) => b.substitution_group(),
1161 Self::CompoundDelimited(b) => b.substitution_group(),
1162 Self::Admonition(b) => b.substitution_group(),
1163 Self::Quote(b) => b.substitution_group(),
1164 Self::Table(b) => b.substitution_group(),
1165 Self::Preamble(b) => b.substitution_group(),
1166 Self::Break(b) => b.substitution_group(),
1167 Self::DocumentAttribute(b) => b.substitution_group(),
1168 }
1169 }
1170}
1171
1172impl<'src> HasSpan<'src> for Block<'src> {
1173 fn span(&self) -> Span<'src> {
1174 match self {
1175 Self::Simple(b) => b.span(),
1176 Self::Media(b) => b.span(),
1177 Self::Section(b) => b.span(),
1178 Self::List(b) => b.span(),
1179 Self::ListItem(b) => b.span(),
1180 Self::RawDelimited(b) => b.span(),
1181 Self::CompoundDelimited(b) => b.span(),
1182 Self::Admonition(b) => b.span(),
1183 Self::Quote(b) => b.span(),
1184 Self::Table(b) => b.span(),
1185 Self::Preamble(b) => b.span(),
1186 Self::Break(b) => b.span(),
1187 Self::DocumentAttribute(b) => b.span(),
1188 }
1189 }
1190}