sable-markdown/src/parser/blocks/footnote_definition.rs@main
raw
1use nom::{
2 IResult, Parser,
3 bytes::complete::tag,
4 character::complete::{char, none_of},
5 combinator::{recognize, verify},
6 multi::{many_m_n, many0, many1},
7 sequence::preceded,
8};
9
10use crate::{
11 ast::FootnoteDefinition,
12 parser::util::{line_terminated, not_eof_or_eol1},
13};
14
15pub(super) fn footnote_definition<'a>()
16-> impl FnMut(&'a str) -> IResult<&'a str, FootnoteDefinition> {
17 move |input: &'a str| {
18 let (input, _) = many_m_n(0, 3, char(' ')).parse(input)?;
19 let (input, _) = tag("[^").parse(input)?;
20 let (input, label) = recognize(many1(verify(none_of("]"), |c| *c != ']'))).parse(input)?;
21 let (input, _) = tag("]:").parse(input)?;
22 let (input, _) = many_m_n(0, 3, char(' ')).parse(input)?;
23 let (input, first_line) = line_terminated(not_eof_or_eol1).parse(input)?;
24 let (input, rest_lines) = many0(preceded(
25 many_m_n(3, 3, char(' ')),
26 line_terminated(not_eof_or_eol1),
27 ))
28 .parse(input)?;
29
30 let total_size = first_line.len() + rest_lines.len();
31 let mut footnote_content = String::with_capacity(total_size);
32 if !first_line.is_empty() {
33 footnote_content.push_str(first_line);
34 }
35 for line in rest_lines {
36 footnote_content.push('\n');
37 footnote_content.push_str(line);
38 }
39
40 let (_, blocks) = many0(crate::parser::blocks::block())
41 .parse(&footnote_content)
42 .map_err(|err| err.map_input(|_| input))?;
43
44 let blocks = blocks.into_iter().flatten().collect();
45
46 let v = FootnoteDefinition {
47 label: label.to_owned(),
48 blocks,
49 };
50
51 Ok((input, v))
52 }
53}
54