raw
1mod autolink;
2mod code_span;
3mod emphasis;
4mod environment_variable;
5mod footnote_reference;
6mod hard_newline;
7mod html_entity;
8mod image;
9mod inline_link;
10mod reference_link;
11mod strikethrough;
12mod tag;
13mod text;
14mod wikilink;
15
16#[cfg(test)]
17mod tests;
18
19use nom::{
20 IResult, Parser,
21 branch::alt,
22 combinator::map,
23 multi::{many0, many1},
24};
25
26use crate::ast::Inline;
27
28fn merge_consecutive_text_elements(inlines: Vec<Inline>) -> Vec<Inline> {
30 let mut result = Vec::new();
31 let mut current_text = String::new();
32 let mut has_text = false;
33
34 for inline in inlines {
35 match inline {
36 Inline::Text(text) => {
37 current_text.push_str(&text);
38 has_text = true;
39 }
40 other => {
41 if has_text {
43 result.push(Inline::Text(current_text.clone()));
44 current_text.clear();
45 has_text = false;
46 }
47 result.push(other);
49 }
50 }
51 }
52
53 if has_text {
55 result.push(Inline::Text(current_text));
56 }
57
58 result
59}
60
61pub(super) fn inline_many0<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, Vec<Inline>> {
62 move |input: &'a str| {
63 let (input, list_of_lists) = many0(inline()).parse(input)?;
64 let r: Vec<_> = list_of_lists.into_iter().flatten().collect();
65 let merged = merge_consecutive_text_elements(r);
66 Ok((input, merged))
67 }
68}
69
70pub(super) fn inline_many1<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, Vec<Inline>> {
71 move |input: &'a str| {
72 let (input, list_of_lists) = many1(inline()).parse(input)?;
73 let r: Vec<_> = list_of_lists.into_iter().flatten().collect();
74 let merged = merge_consecutive_text_elements(r);
75 Ok((input, merged))
76 }
77}
78
79pub(super) fn inline<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, Vec<Inline>> {
80 move |input: &'a str| {
81 alt((
82 map(wikilink::wikilink(), Inline::Wikilink),
83 map(autolink::autolink, Inline::Autolink),
84 map(inline_link::inline_link(), Inline::Link),
85 footnote_reference::footnote_reference,
86 reference_link::reference_link(),
87 hard_newline::hard_newline,
88 image::image(),
89 map(code_span::code_span, Inline::Code),
90 environment_variable::environment_variable,
91 emphasis::emphasis(),
92 strikethrough::strikethrough(),
93 map(tag::tag(), Inline::Tag),
94 text::text(),
95 ))
96 .map(|v| vec![v])
97 .parse(input)
98 }
99}
100