plantuml_parser/dsl/line/
footer.rs

1use crate::FooterToken;
2use crate::dsl::line::LineWithComment;
3use crate::{InlineBlockCommentToken, ParseContainer, ParseResult, wr, wr2};
4use nom::character::complete::space0;
5use nom::combinator::map;
6use nom::{IResult, Parser};
7
8/// A token sequence that is a line containing a [`FooterToken`]. (like `"\tfooter EXAMPLE FOOTER  \n"`.)
9///
10/// # Examples
11///
12/// ```
13/// use plantuml_parser::{FooterLine, ParseContainer};
14///
15/// # fn main() -> anyhow::Result<()> {
16/// let input = " footer EXAMPLE FOOTER\n";
17/// let (rest, (raws, token)) = FooterLine::parse(input.into())?;
18/// let combined_raw: ParseContainer = raws.into();
19/// assert_eq!(rest, "");
20/// assert_eq!(combined_raw, " footer EXAMPLE FOOTER\n");
21/// assert_eq!(token.footer(), "EXAMPLE FOOTER");
22/// # Ok(())
23/// # }
24/// ```
25#[derive(Clone, Debug)]
26pub struct FooterLine {
27    token: FooterToken,
28    ibc: Option<InlineBlockCommentToken>,
29}
30
31impl FooterLine {
32    /// Tries to parse [`FooterLine`]. (e.g. `" footer EXAMPLE FOOTER\n"`.)
33    pub fn parse(input: ParseContainer) -> ParseResult<Self> {
34        let (rest, (parsed, lwc)) = LineWithComment::parse(inner_parser, input)?;
35
36        let (token, ibc) = lwc.into();
37
38        let ret0 = ParseContainer::from(parsed);
39        let ret1 = Self { token, ibc };
40
41        Ok((rest, (ret0, ret1)))
42    }
43
44    pub fn inline_block_comment(&self) -> Option<&InlineBlockCommentToken> {
45        self.ibc.as_ref()
46    }
47}
48
49impl std::ops::Deref for FooterLine {
50    type Target = FooterToken;
51    fn deref(&self) -> &Self::Target {
52        &self.token
53    }
54}
55
56fn inner_parser(
57    input: ParseContainer,
58) -> IResult<ParseContainer, (Vec<ParseContainer>, FooterToken)> {
59    map(
60        (wr!(space0), wr2!(FooterToken::parse), wr!(space0)),
61        |(p0, (p1, token), p2)| (vec![p0, p1, p2], token),
62    )
63    .parse(input)
64}
65
66#[cfg(test)]
67mod tests {
68    use super::*;
69
70    #[test]
71    fn test_parse_footer_line() -> anyhow::Result<()> {
72        let testdata = [
73            ("footer FOOTER\n", None),
74            (" \tfooter FOOTER\n", None),
75            ("footer FOOTER \t\n", None),
76            (" \tfooter FOOTER \t\n", None),
77            ("Footer FOOTER\n", None),
78            ("FOOTER FOOTER\n", None),
79            ("fooTer FOOTER\n", None),
80            (" /' comment '/ footer FOOTER\n", Some(" /' comment '/ ")),
81            ("footer FOOTER  /' comment '/  \n", Some("/' comment '/  ")),
82        ];
83
84        for (testdata, expected_comment) in testdata.into_iter() {
85            println!("try: testdata = {testdata:?}");
86
87            let (rest, (parsed, FooterLine { token, ibc })) = FooterLine::parse(testdata.into())?;
88            assert_eq!(rest, "");
89            assert_eq!(testdata, parsed);
90            assert_eq!(token.footer(), "FOOTER");
91            assert_eq!(ibc.as_ref().map(|x| x.comment()), expected_comment);
92        }
93
94        let testdata = "footer FOOTER /' c0 '/ /' c1 '/   \n";
95        let expected_comment = Some("/' c1 '/   ");
96
97        let (rest, (parsed, FooterLine { token, ibc })) = FooterLine::parse(testdata.into())?;
98        assert_eq!(rest, "");
99        assert_eq!(testdata, parsed);
100        assert_eq!(token.footer(), "FOOTER /' c0 '/");
101        assert_eq!(ibc.as_ref().map(|x| x.comment()), expected_comment);
102
103        Ok(())
104    }
105}