raw
1use nom::{
2 IResult, Parser,
3 branch::alt,
4 bytes::complete::tag,
5 character::complete::{anychar, char, line_ending, space0},
6 combinator::{not, peek, recognize, value},
7 multi::many1,
8 sequence::preceded,
9};
10
11pub(super) fn code_span(input: &str) -> IResult<&str, String> {
12 let (input, open_ticks) = backtick_string(input)?;
13 let tick_count = open_ticks.len();
14 let closing_tag_value = "`".repeat(tick_count);
15
16 let not_a_closing_tag = (tag(closing_tag_value.as_str()), char('`'));
17 let closing_tag = preceded(
18 peek(not(not_a_closing_tag)),
19 tag(closing_tag_value.as_str()),
20 );
21 let empty_line = (line_ending, space0, line_ending);
22 let content_parser = preceded(
23 peek(not(alt((value((), closing_tag), value((), empty_line))))),
24 anychar,
25 );
26
27 let (input, content) = recognize(many1(content_parser)).parse(input)?;
28 let (input, _) = tag(closing_tag_value.as_str()).parse(input)?;
29
30 let mut content = content.replace("\r\n", " ").replace('\n', " ");
31 if content.starts_with(' ') && content.ends_with(' ') && content.trim() != "" {
32 content = content[1..content.len() - 1].to_string();
33 }
34
35 Ok((input, content))
36}
37
38fn backtick_string(input: &str) -> IResult<&str, &str> {
39 recognize(many1(char('`'))).parse(input)
40}
41