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},
13 document::{Attribute, InterpretedValue, RefType},
14 parser::{InlineSubstitutionRenderer, ReferenceResolver, ReferenceWarning, 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 && let Some(MatchedItem {
245 item: simple_block,
246 after,
247 }) = SimpleBlock::parse_fast(source, parser)
248 {
249 let mut warnings = vec![];
250 let block = Self::Simple(simple_block);
251
252 Self::register_block_id(
253 block.id(),
254 Self::block_reftext(&block),
255 Self::block_signifier(&block, parser),
256 block.span(),
257 parser,
258 &mut warnings,
259 );
260
261 return MatchAndWarnings {
262 item: BlockParseOutcome::Parsed(MatchedItem { item: block, after }),
263 warnings,
264 };
265 }
266
267 if first_line.starts_with(':')
269 && (first_line.ends_with(':') || first_line.contains(": "))
270 && let Some(attr) = Attribute::parse(source, parser)
271 {
272 let mut warnings: Vec<Warning<'src>> = vec![];
273 parser.set_attribute_from_body(&attr.item, &mut warnings);
274
275 return MatchAndWarnings {
276 item: BlockParseOutcome::Parsed(MatchedItem {
277 item: Self::DocumentAttribute(attr.item),
278 after: attr.after,
279 }),
280 warnings,
281 };
282 }
283
284 let MatchAndWarnings {
287 item: mut metadata,
288 mut warnings,
289 } = BlockMetadata::parse(source, parser);
290
291 if parent_list_markers.is_none() && !metadata.is_empty() {
306 let after_blanks = metadata.block_start.discard_empty_lines();
307 if after_blanks != metadata.block_start && !after_blanks.is_empty() {
308 metadata.block_start = after_blanks;
309 }
310 }
311
312 let is_literal =
320 metadata.attrlist.as_ref().and_then(|a| a.block_style()) == Some("literal") && {
321 let first_line = metadata.block_start.take_normalized_line().item;
322 !RawDelimitedBlock::is_valid_delimiter(&first_line)
323 && !CompoundDelimitedBlock::is_valid_delimiter(&first_line)
324 && !TableBlock::is_table_delimiter(&first_line)
325 };
326
327 let mut simple_block_mi = None;
334
335 if !is_literal {
336 if let Some(mut adm_maw) = AdmonitionBlock::parse(&metadata, parser)
337 && let Some(adm) = adm_maw.item
338 {
339 if !adm_maw.warnings.is_empty() {
340 warnings.append(&mut adm_maw.warnings);
341 }
342
343 let block = Self::Admonition(adm.item);
344
345 Self::register_block_id(
346 block.id(),
347 Self::block_reftext(&block),
348 Self::block_signifier(&block, parser),
349 block.span(),
350 parser,
351 &mut warnings,
352 );
353
354 return MatchAndWarnings {
355 item: BlockParseOutcome::Parsed(MatchedItem {
356 item: block,
357 after: adm.after,
358 }),
359 warnings,
360 };
361 }
362
363 if let Some(mut quote_maw) = QuoteBlock::parse(&metadata, parser)
364 && let Some(quote) = quote_maw.item
365 {
366 if !quote_maw.warnings.is_empty() {
367 warnings.append(&mut quote_maw.warnings);
368 }
369
370 let block = Self::Quote(quote.item);
371
372 Self::register_block_id(
373 block.id(),
374 Self::block_reftext(&block),
375 Self::block_signifier(&block, parser),
376 block.span(),
377 parser,
378 &mut warnings,
379 );
380
381 return MatchAndWarnings {
382 item: BlockParseOutcome::Parsed(MatchedItem {
383 item: block,
384 after: quote.after,
385 }),
386 warnings,
387 };
388 }
389
390 if let Some(mut rdb_maw) = RawDelimitedBlock::parse(&metadata, parser)
391 && let Some(rdb) = rdb_maw.item
392 {
393 if !rdb_maw.warnings.is_empty() {
394 warnings.append(&mut rdb_maw.warnings);
395 }
396
397 let block = Self::RawDelimited(rdb.item);
398
399 Self::register_block_id(
400 block.id(),
401 Self::block_reftext(&block),
402 Self::block_signifier(&block, parser),
403 block.span(),
404 parser,
405 &mut warnings,
406 );
407
408 return MatchAndWarnings {
409 item: BlockParseOutcome::Parsed(MatchedItem {
410 item: block,
411 after: rdb.after,
412 }),
413 warnings,
414 };
415 }
416
417 if let Some(mut cdb_maw) = CompoundDelimitedBlock::parse(&metadata, parser)
418 && let Some(cdb) = cdb_maw.item
419 {
420 if !cdb_maw.warnings.is_empty() {
421 warnings.append(&mut cdb_maw.warnings);
422 }
423
424 let block = Self::CompoundDelimited(cdb.item);
425
426 Self::register_block_id(
427 block.id(),
428 Self::block_reftext(&block),
429 Self::block_signifier(&block, parser),
430 block.span(),
431 parser,
432 &mut warnings,
433 );
434
435 return MatchAndWarnings {
436 item: BlockParseOutcome::Parsed(MatchedItem {
437 item: block,
438 after: cdb.after,
439 }),
440 warnings,
441 };
442 }
443
444 if let Some(mut table_maw) = TableBlock::parse(&metadata, parser)
445 && let Some(table) = table_maw.item
446 {
447 if !table_maw.warnings.is_empty() {
448 warnings.append(&mut table_maw.warnings);
449 }
450
451 let block = Self::Table(table.item);
452
453 Self::register_block_id(
454 block.id(),
455 Self::block_reftext(&block),
456 Self::block_signifier(&block, parser),
457 block.span(),
458 parser,
459 &mut warnings,
460 );
461
462 return MatchAndWarnings {
463 item: BlockParseOutcome::Parsed(MatchedItem {
464 item: block,
465 after: table.after,
466 }),
467 warnings,
468 };
469 }
470
471 let line = metadata.block_start.take_normalized_line();
473
474 if line.item.starts_with("image::")
475 || line.item.starts_with("video::")
476 || line.item.starts_with("audio::")
477 {
478 let mut media_block_maw = MediaBlock::parse(&metadata, parser);
479
480 if let Some(mut media_block) = media_block_maw.item {
481 if !media_block_maw.warnings.is_empty() {
485 warnings.append(&mut media_block_maw.warnings);
486 }
487
488 if media_block.item.resolve_target(parser) == TargetResolution::Drop {
492 return MatchAndWarnings {
493 item: BlockParseOutcome::Dropped(media_block.after),
494 warnings,
495 };
496 }
497
498 media_block.item.assign_caption(parser);
502
503 let block = Self::Media(media_block.item);
504
505 Self::register_block_id(
506 block.id(),
507 Self::block_reftext(&block),
508 Self::block_signifier(&block, parser),
509 block.span(),
510 parser,
511 &mut warnings,
512 );
513
514 return MatchAndWarnings {
515 item: BlockParseOutcome::Parsed(MatchedItem {
516 item: block,
517 after: media_block.after,
518 }),
519 warnings,
520 };
521 }
522
523 }
526
527 if (line.item.starts_with('=') || line.item.starts_with('#'))
528 && let Some(mi_section_block) =
529 SectionBlock::parse(&metadata, parser, &mut warnings)
530 {
531 return MatchAndWarnings {
535 item: BlockParseOutcome::Parsed(MatchedItem {
536 item: Self::Section(mi_section_block.item),
537 after: mi_section_block.after,
538 }),
539 warnings,
540 };
541 }
542
543 if (line.item.starts_with('\'')
544 || line.item.starts_with('-')
545 || line.item.starts_with('*')
546 || line.item.starts_with('<'))
547 && let Some(mi_break) = Break::parse(&metadata, parser)
548 {
549 return MatchAndWarnings {
552 item: BlockParseOutcome::Parsed(MatchedItem {
553 item: Self::Break(mi_break.item),
554 after: mi_break.after,
555 }),
556 warnings,
557 };
558 }
559
560 if parent_list_markers.is_none()
564 && let Some(mi_list) = ListBlock::parse(&metadata, parser, &mut warnings)
565 {
566 return MatchAndWarnings {
567 item: BlockParseOutcome::Parsed(MatchedItem {
568 item: Self::List(mi_list.item),
569 after: mi_list.after,
570 }),
571 warnings,
572 };
573 }
574
575 simple_block_mi = if let Some(plm) = parent_list_markers {
582 SimpleBlock::parse_for_list_item(&metadata, parser, is_continuation, plm)
583 } else {
584 SimpleBlock::parse(&metadata, parser)
585 };
586
587 if simple_block_mi.is_none() && !metadata.is_empty() {
588 warnings.push(Warning {
592 source: metadata.source,
593 warning: WarningType::MissingBlockAfterTitleOrAttributeList,
594 origin: None,
595 });
596
597 metadata.title_source = None;
601 metadata.title = None;
602 metadata.anchor = None;
603 metadata.attrlist = None;
604 metadata.block_start = metadata.source;
605 }
606 }
607
608 let simple_block_mi = match simple_block_mi {
612 Some(mi) => Some(mi),
613 None => {
614 if let Some(plm) = parent_list_markers {
615 SimpleBlock::parse_for_list_item(&metadata, parser, is_continuation, plm)
616 } else {
617 SimpleBlock::parse(&metadata, parser)
618 }
619 }
620 };
621
622 let mut result = MatchAndWarnings {
623 item: match simple_block_mi {
624 Some(mi) => BlockParseOutcome::Parsed(MatchedItem {
625 item: Self::Simple(mi.item),
626 after: mi.after,
627 }),
628 None => BlockParseOutcome::NoMatch,
629 },
630 warnings,
631 };
632
633 if let BlockParseOutcome::Parsed(ref matched_item) = result.item {
634 Self::register_block_id(
635 matched_item.item.id(),
636 Self::block_reftext(&matched_item.item),
637 Self::block_signifier(&matched_item.item, parser),
638 matched_item.item.span(),
639 parser,
640 &mut result.warnings,
641 );
642 }
643
644 result
645 }
646
647 fn block_signifier<'a>(block: &'a Block<'a>, parser: &Parser) -> Option<XrefSignifier> {
658 let caption = block.caption()?;
660
661 let has_explicit_reftext = block
662 .attrlist()
663 .and_then(|attrlist| attrlist.named_attribute("reftext"))
664 .is_some()
665 || block.anchor_reftext().is_some();
666 if has_explicit_reftext {
667 return None;
668 }
669
670 if Self::has_caption_override(block, parser) {
676 return None;
677 }
678
679 let label = caption.strip_suffix(". ").unwrap_or(caption).to_string();
682 Some(XrefSignifier {
683 label,
684 emphasize: false,
685 })
686 }
687
688 fn has_caption_override<'a>(block: &'a Block<'a>, parser: &Parser) -> bool {
698 let attribute_override = block
699 .attrlist()
700 .and_then(|attrlist| attrlist.named_attribute("caption"))
701 .is_some()
702 || matches!(block, Block::Media(media)
703 if media.macro_attrlist().named_attribute("caption").is_some());
704
705 attribute_override
706 || matches!(
707 parser.attribute_value("caption"),
708 InterpretedValue::Value(value) if !value.is_empty(),
709 )
710 }
711
712 fn block_reftext<'a>(block: &'a Block<'a>) -> Option<&'a str> {
717 block
718 .attrlist()
719 .and_then(|attrlist| attrlist.named_attribute("reftext"))
720 .map(|attr| attr.value())
721 .or_else(|| block.anchor_reftext().map(|span| span.data()))
722 .or_else(|| block.title())
723 }
724
725 fn register_block_id(
730 id: Option<&str>,
731 reftext: Option<&str>,
732 signifier: Option<XrefSignifier>,
733 span: Span<'src>,
734 parser: &mut Parser,
735 warnings: &mut Vec<Warning<'src>>,
736 ) {
737 if let Some(id) = id {
738 match parser.register_ref(id, reftext, RefType::Anchor) {
739 Ok(()) => {
740 if let Some(signifier) = signifier {
741 parser.set_ref_signifier(id, signifier);
742 }
743 }
744 Err(_duplicate_error) => {
745 warnings.push(Warning {
747 source: span,
748 warning: WarningType::DuplicateId(id.to_string()),
749 origin: None,
750 });
751 }
752 }
753 }
754 }
755
756 pub(crate) fn as_list_item(&self) -> Option<&ListItem<'src>> {
759 match self {
760 Self::ListItem(li) => Some(li),
761 _ => None,
762 }
763 }
764
765 pub(crate) fn resolve_references(
773 &mut self,
774 resolver: &dyn ReferenceResolver,
775 renderer: &dyn InlineSubstitutionRenderer,
776 warnings: &mut Vec<ReferenceWarning>,
777 ) {
778 if let Some(content) = self.content_mut() {
779 content.resolve_references(resolver, renderer, warnings);
780 }
781
782 if let Self::Table(table) = self {
785 table.resolve_references(resolver, renderer, warnings);
786 }
787
788 if let Self::Quote(quote) = self {
792 quote.resolve_references(resolver, renderer, warnings);
793 }
794
795 for child in self.nested_blocks_mut() {
796 child.resolve_references(resolver, renderer, warnings);
797 }
798 }
799}
800
801impl<'src> IsBlock<'src> for Block<'src> {
802 fn content_model(&self) -> ContentModel {
803 match self {
804 Self::Simple(_) => ContentModel::Simple,
805 Self::Media(b) => b.content_model(),
806 Self::Section(_) => ContentModel::Compound,
807 Self::List(b) => b.content_model(),
808 Self::ListItem(b) => b.content_model(),
809 Self::RawDelimited(b) => b.content_model(),
810 Self::CompoundDelimited(b) => b.content_model(),
811 Self::Admonition(b) => b.content_model(),
812 Self::Quote(b) => b.content_model(),
813 Self::Table(b) => b.content_model(),
814 Self::Preamble(b) => b.content_model(),
815 Self::Break(b) => b.content_model(),
816 Self::DocumentAttribute(b) => b.content_model(),
817 }
818 }
819
820 fn declared_style(&'src self) -> Option<&'src str> {
821 match self {
822 Self::Simple(b) => b.declared_style(),
823 Self::Media(b) => b.declared_style(),
824 Self::Section(b) => b.declared_style(),
825 Self::List(b) => b.declared_style(),
826 Self::ListItem(b) => b.declared_style(),
827 Self::RawDelimited(b) => b.declared_style(),
828 Self::CompoundDelimited(b) => b.declared_style(),
829 Self::Admonition(b) => b.declared_style(),
830 Self::Quote(b) => b.declared_style(),
831 Self::Table(b) => b.declared_style(),
832 Self::Preamble(b) => b.declared_style(),
833 Self::Break(b) => b.declared_style(),
834 Self::DocumentAttribute(b) => b.declared_style(),
835 }
836 }
837
838 fn rendered_content(&'src self) -> Option<&'src str> {
839 match self {
840 Self::Simple(b) => b.rendered_content(),
841 Self::Media(b) => b.rendered_content(),
842 Self::Section(b) => b.rendered_content(),
843 Self::List(b) => b.rendered_content(),
844 Self::ListItem(b) => b.rendered_content(),
845 Self::RawDelimited(b) => b.rendered_content(),
846 Self::CompoundDelimited(b) => b.rendered_content(),
847 Self::Admonition(b) => b.rendered_content(),
848 Self::Quote(b) => b.rendered_content(),
849 Self::Table(b) => b.rendered_content(),
850 Self::Preamble(b) => b.rendered_content(),
851 Self::Break(b) => b.rendered_content(),
852 Self::DocumentAttribute(b) => b.rendered_content(),
853 }
854 }
855
856 fn raw_context(&self) -> CowStr<'src> {
857 match self {
858 Self::Simple(b) => b.raw_context(),
859 Self::Media(b) => b.raw_context(),
860 Self::Section(b) => b.raw_context(),
861 Self::List(b) => b.raw_context(),
862 Self::ListItem(b) => b.raw_context(),
863 Self::RawDelimited(b) => b.raw_context(),
864 Self::CompoundDelimited(b) => b.raw_context(),
865 Self::Admonition(b) => b.raw_context(),
866 Self::Quote(b) => b.raw_context(),
867 Self::Table(b) => b.raw_context(),
868 Self::Preamble(b) => b.raw_context(),
869 Self::Break(b) => b.raw_context(),
870 Self::DocumentAttribute(b) => b.raw_context(),
871 }
872 }
873
874 fn nested_blocks(&'src self) -> Iter<'src, Block<'src>> {
875 match self {
876 Self::Simple(b) => b.nested_blocks(),
877 Self::Media(b) => b.nested_blocks(),
878 Self::Section(b) => b.nested_blocks(),
879 Self::List(b) => b.nested_blocks(),
880 Self::ListItem(b) => b.nested_blocks(),
881 Self::RawDelimited(b) => b.nested_blocks(),
882 Self::CompoundDelimited(b) => b.nested_blocks(),
883 Self::Admonition(b) => b.nested_blocks(),
884 Self::Quote(b) => b.nested_blocks(),
885 Self::Table(b) => b.nested_blocks(),
886 Self::Preamble(b) => b.nested_blocks(),
887 Self::Break(b) => b.nested_blocks(),
888 Self::DocumentAttribute(b) => b.nested_blocks(),
889 }
890 }
891
892 fn nested_blocks_mut(&mut self) -> &mut [Block<'src>] {
893 match self {
894 Self::Simple(b) => b.nested_blocks_mut(),
895 Self::Media(b) => b.nested_blocks_mut(),
896 Self::Section(b) => b.nested_blocks_mut(),
897 Self::List(b) => b.nested_blocks_mut(),
898 Self::ListItem(b) => b.nested_blocks_mut(),
899 Self::RawDelimited(b) => b.nested_blocks_mut(),
900 Self::CompoundDelimited(b) => b.nested_blocks_mut(),
901 Self::Admonition(b) => b.nested_blocks_mut(),
902 Self::Quote(b) => b.nested_blocks_mut(),
903 Self::Table(b) => b.nested_blocks_mut(),
904 Self::Preamble(b) => b.nested_blocks_mut(),
905 Self::Break(b) => b.nested_blocks_mut(),
906 Self::DocumentAttribute(b) => b.nested_blocks_mut(),
907 }
908 }
909
910 fn content_mut(&mut self) -> Option<&mut Content<'src>> {
911 match self {
912 Self::Simple(b) => b.content_mut(),
913 Self::Media(b) => b.content_mut(),
914 Self::Section(b) => b.content_mut(),
915 Self::List(b) => b.content_mut(),
916 Self::ListItem(b) => b.content_mut(),
917 Self::RawDelimited(b) => b.content_mut(),
918 Self::CompoundDelimited(b) => b.content_mut(),
919 Self::Admonition(b) => b.content_mut(),
920 Self::Quote(b) => b.content_mut(),
921 Self::Table(b) => b.content_mut(),
922 Self::Preamble(b) => b.content_mut(),
923 Self::Break(b) => b.content_mut(),
924 Self::DocumentAttribute(b) => b.content_mut(),
925 }
926 }
927
928 fn title_source(&'src self) -> Option<Span<'src>> {
929 match self {
930 Self::Simple(b) => b.title_source(),
931 Self::Media(b) => b.title_source(),
932 Self::Section(b) => b.title_source(),
933 Self::List(b) => b.title_source(),
934 Self::ListItem(b) => b.title_source(),
935 Self::RawDelimited(b) => b.title_source(),
936 Self::CompoundDelimited(b) => b.title_source(),
937 Self::Admonition(b) => b.title_source(),
938 Self::Quote(b) => b.title_source(),
939 Self::Table(b) => b.title_source(),
940 Self::Preamble(b) => b.title_source(),
941 Self::Break(b) => b.title_source(),
942 Self::DocumentAttribute(b) => b.title_source(),
943 }
944 }
945
946 fn title(&self) -> Option<&str> {
947 match self {
948 Self::Simple(b) => b.title(),
949 Self::Media(b) => b.title(),
950 Self::Section(b) => b.title(),
951 Self::List(b) => b.title(),
952 Self::ListItem(b) => b.title(),
953 Self::RawDelimited(b) => b.title(),
954 Self::CompoundDelimited(b) => b.title(),
955 Self::Admonition(b) => b.title(),
956 Self::Quote(b) => b.title(),
957 Self::Table(b) => b.title(),
958 Self::Preamble(b) => b.title(),
959 Self::Break(b) => b.title(),
960 Self::DocumentAttribute(b) => b.title(),
961 }
962 }
963
964 fn caption(&self) -> Option<&str> {
965 match self {
966 Self::Simple(b) => b.caption(),
967 Self::Media(b) => b.caption(),
968 Self::Section(b) => b.caption(),
969 Self::List(b) => b.caption(),
970 Self::ListItem(b) => b.caption(),
971 Self::RawDelimited(b) => b.caption(),
972 Self::CompoundDelimited(b) => b.caption(),
973 Self::Admonition(b) => b.caption(),
974 Self::Quote(b) => b.caption(),
975 Self::Table(b) => b.caption(),
976 Self::Preamble(b) => b.caption(),
977 Self::Break(b) => b.caption(),
978 Self::DocumentAttribute(b) => b.caption(),
979 }
980 }
981
982 fn number(&self) -> Option<usize> {
983 match self {
984 Self::Simple(b) => b.number(),
985 Self::Media(b) => b.number(),
986 Self::Section(b) => b.number(),
987 Self::List(b) => b.number(),
988 Self::ListItem(b) => b.number(),
989 Self::RawDelimited(b) => b.number(),
990 Self::CompoundDelimited(b) => b.number(),
991 Self::Admonition(b) => b.number(),
992 Self::Quote(b) => b.number(),
993 Self::Table(b) => b.number(),
994 Self::Preamble(b) => b.number(),
995 Self::Break(b) => b.number(),
996 Self::DocumentAttribute(b) => b.number(),
997 }
998 }
999
1000 fn id(&'src self) -> Option<&'src str> {
1001 match self {
1015 Self::Media(b) => b.id(),
1016 Self::Section(b) => b.id(),
1017 _ => self
1018 .anchor()
1019 .map(|a| a.data())
1020 .or_else(|| self.attrlist().and_then(|attrlist| attrlist.id())),
1021 }
1022 }
1023
1024 fn anchor(&'src self) -> Option<Span<'src>> {
1025 match self {
1026 Self::Simple(b) => b.anchor(),
1027 Self::Media(b) => b.anchor(),
1028 Self::Section(b) => b.anchor(),
1029 Self::List(b) => b.anchor(),
1030 Self::ListItem(b) => b.anchor(),
1031 Self::RawDelimited(b) => b.anchor(),
1032 Self::CompoundDelimited(b) => b.anchor(),
1033 Self::Admonition(b) => b.anchor(),
1034 Self::Quote(b) => b.anchor(),
1035 Self::Table(b) => b.anchor(),
1036 Self::Preamble(b) => b.anchor(),
1037 Self::Break(b) => b.anchor(),
1038 Self::DocumentAttribute(b) => b.anchor(),
1039 }
1040 }
1041
1042 fn anchor_reftext(&'src self) -> Option<Span<'src>> {
1043 match self {
1044 Self::Simple(b) => b.anchor_reftext(),
1045 Self::Media(b) => b.anchor_reftext(),
1046 Self::Section(b) => b.anchor_reftext(),
1047 Self::List(b) => b.anchor_reftext(),
1048 Self::ListItem(b) => b.anchor_reftext(),
1049 Self::RawDelimited(b) => b.anchor_reftext(),
1050 Self::CompoundDelimited(b) => b.anchor_reftext(),
1051 Self::Admonition(b) => b.anchor_reftext(),
1052 Self::Quote(b) => b.anchor_reftext(),
1053 Self::Table(b) => b.anchor_reftext(),
1054 Self::Preamble(b) => b.anchor_reftext(),
1055 Self::Break(b) => b.anchor_reftext(),
1056 Self::DocumentAttribute(b) => b.anchor_reftext(),
1057 }
1058 }
1059
1060 fn attrlist(&'src self) -> Option<&'src Attrlist<'src>> {
1061 match self {
1062 Self::Simple(b) => b.attrlist(),
1063 Self::Media(b) => b.attrlist(),
1064 Self::Section(b) => b.attrlist(),
1065 Self::List(b) => b.attrlist(),
1066 Self::ListItem(b) => b.attrlist(),
1067 Self::RawDelimited(b) => b.attrlist(),
1068 Self::CompoundDelimited(b) => b.attrlist(),
1069 Self::Admonition(b) => b.attrlist(),
1070 Self::Quote(b) => b.attrlist(),
1071 Self::Table(b) => b.attrlist(),
1072 Self::Preamble(b) => b.attrlist(),
1073 Self::Break(b) => b.attrlist(),
1074 Self::DocumentAttribute(b) => b.attrlist(),
1075 }
1076 }
1077
1078 fn substitution_group(&self) -> SubstitutionGroup {
1079 match self {
1080 Self::Simple(b) => b.substitution_group(),
1081 Self::Media(b) => b.substitution_group(),
1082 Self::Section(b) => b.substitution_group(),
1083 Self::List(b) => b.substitution_group(),
1084 Self::ListItem(b) => b.substitution_group(),
1085 Self::RawDelimited(b) => b.substitution_group(),
1086 Self::CompoundDelimited(b) => b.substitution_group(),
1087 Self::Admonition(b) => b.substitution_group(),
1088 Self::Quote(b) => b.substitution_group(),
1089 Self::Table(b) => b.substitution_group(),
1090 Self::Preamble(b) => b.substitution_group(),
1091 Self::Break(b) => b.substitution_group(),
1092 Self::DocumentAttribute(b) => b.substitution_group(),
1093 }
1094 }
1095}
1096
1097impl<'src> HasSpan<'src> for Block<'src> {
1098 fn span(&self) -> Span<'src> {
1099 match self {
1100 Self::Simple(b) => b.span(),
1101 Self::Media(b) => b.span(),
1102 Self::Section(b) => b.span(),
1103 Self::List(b) => b.span(),
1104 Self::ListItem(b) => b.span(),
1105 Self::RawDelimited(b) => b.span(),
1106 Self::CompoundDelimited(b) => b.span(),
1107 Self::Admonition(b) => b.span(),
1108 Self::Quote(b) => b.span(),
1109 Self::Table(b) => b.span(),
1110 Self::Preamble(b) => b.span(),
1111 Self::Break(b) => b.span(),
1112 Self::DocumentAttribute(b) => b.span(),
1113 }
1114 }
1115}