asciidoc_parser/blocks/
simple.rs

1use crate::{
2    HasSpan, Parser, Span,
3    attributes::Attrlist,
4    blocks::{ContentModel, IsBlock, metadata::BlockMetadata},
5    content::{Content, SubstitutionGroup},
6    span::MatchedItem,
7    strings::CowStr,
8};
9
10/// A block that's treated as contiguous lines of paragraph text (and subject to
11/// normal substitutions) (e.g., a paragraph block).
12#[derive(Clone, Debug, Eq, PartialEq)]
13pub struct SimpleBlock<'src> {
14    content: Content<'src>,
15    source: Span<'src>,
16    title_source: Option<Span<'src>>,
17    title: Option<String>,
18    anchor: Option<Span<'src>>,
19    attrlist: Option<Attrlist<'src>>,
20}
21
22impl<'src> SimpleBlock<'src> {
23    pub(crate) fn parse(
24        metadata: &BlockMetadata<'src>,
25        parser: &mut Parser,
26    ) -> Option<MatchedItem<'src, Self>> {
27        let source = metadata.block_start.take_non_empty_lines()?;
28
29        let mut content: Content<'src> = source.item.into();
30
31        SubstitutionGroup::Normal
32            .override_via_attrlist(metadata.attrlist.as_ref())
33            .apply(&mut content, parser, metadata.attrlist.as_ref());
34
35        Some(MatchedItem {
36            item: Self {
37                content,
38                source: metadata
39                    .source
40                    .trim_remainder(source.after)
41                    .trim_trailing_whitespace(),
42                title_source: metadata.title_source,
43                title: metadata.title.clone(),
44                anchor: metadata.anchor,
45                attrlist: metadata.attrlist.clone(),
46            },
47            after: source.after.discard_empty_lines(),
48        })
49    }
50
51    pub(crate) fn parse_fast(
52        source: Span<'src>,
53        parser: &mut Parser,
54    ) -> Option<MatchedItem<'src, Self>> {
55        let source = source.take_non_empty_lines()?;
56
57        let mut content: Content<'src> = source.item.into();
58        SubstitutionGroup::Normal.apply(&mut content, parser, None);
59
60        Some(MatchedItem {
61            item: Self {
62                content,
63                source: source.item,
64                title_source: None,
65                title: None,
66                anchor: None,
67                attrlist: None,
68            },
69            after: source.after.discard_empty_lines(),
70        })
71    }
72
73    /// Return the interpreted content of this block.
74    pub fn content(&self) -> &Content<'src> {
75        &self.content
76    }
77}
78
79impl<'src> IsBlock<'src> for SimpleBlock<'src> {
80    fn content_model(&self) -> ContentModel {
81        ContentModel::Simple
82    }
83
84    fn raw_context(&self) -> CowStr<'src> {
85        "paragraph".into()
86    }
87
88    fn title_source(&'src self) -> Option<Span<'src>> {
89        self.title_source
90    }
91
92    fn title(&self) -> Option<&str> {
93        self.title.as_deref()
94    }
95
96    fn anchor(&'src self) -> Option<Span<'src>> {
97        self.anchor
98    }
99
100    fn attrlist(&'src self) -> Option<&'src Attrlist<'src>> {
101        self.attrlist.as_ref()
102    }
103}
104
105impl<'src> HasSpan<'src> for SimpleBlock<'src> {
106    fn span(&self) -> Span<'src> {
107        self.source
108    }
109}