use nom::branch::alt;
use nom::bytes::complete::{is_not, tag};
use nom::character::complete::anychar;
use nom::combinator::{map, map_parser, not};
use nom::sequence::{delimited, tuple};
use nom::IResult;
use crate::{FormattedTextBlock, TextFormat};
impl FormattedTextBlock {
pub fn parser_for_one_element(input: &str) -> IResult<&str, Vec<TextFormat>> {
let mut output_vec: Vec<TextFormat> = vec![];
let mut res = input;
while let Ok((input, new_element)) = alt((
TextFormat::parse_bold,
TextFormat::parse_italic,
TextFormat::parse_strike_through,
TextFormat::parse_link,
TextFormat::parse_text,
))(res)
{
res = input;
output_vec.push(new_element);
if input.is_empty() {
break;
}
}
Ok((res, output_vec))
}
pub fn parser(input: &str) -> IResult<&str, Self> {
map(Self::parser_for_one_element, |parsed| Self {
inhalt: parsed,
})(input)
}
}
impl TextFormat {
fn parse_inner_element(input: &str) -> IResult<&str, Vec<TextFormat>> {
FormattedTextBlock::parser_for_one_element(input)
}
pub fn parse_text(full_line: &str) -> IResult<&str, Self> {
let mut output: String = String::new();
let mut result: &str = full_line;
while !result.is_empty()
&& not(alt((
Self::parse_bold,
Self::parse_italic,
Self::parse_strike_through,
Self::parse_link,
)))(result)
.ok()
.is_some()
{
let (full_line, char_output) = anychar(result)?;
output.push(char_output);
result = full_line;
}
Ok((result, Self::Text(output)))
}
pub fn parse_bold(input: &str) -> IResult<&str, Self> {
map(
map_parser(
alt((
delimited(tag("**"), is_not("*"), tag("**")),
delimited(tag("__"), is_not("_"), tag("__")),
)),
Self::parse_inner_element,
),
Self::Bold,
)(input)
}
pub fn parse_italic(input: &str) -> IResult<&str, Self> {
map(
map_parser(
alt((
delimited(tag("*"), is_not("*"), tag("*")),
delimited(tag("_"), is_not("_"), tag("_")),
)),
Self::parse_inner_element,
),
Self::Italic,
)(input)
}
pub fn parse_strike_through(input: &str) -> IResult<&str, Self> {
map(
map_parser(
alt((
delimited(tag("~~"), is_not("~"), tag("~~")),
delimited(tag("~~"), is_not("~"), tag("~~")),
)),
Self::parse_inner_element,
),
Self::StrikeThrough,
)(input)
}
pub fn parse_link(input: &str) -> IResult<&str, Self> {
let (rest, (name, href)) = parser_square_bracket_and_bracket(input)?;
let (remainder, name) = Self::parse_inner_element(name)?;
debug_assert!(remainder.is_empty());
Ok((
rest,
TextFormat::Link {
name,
href: href.to_owned(),
},
))
}
}
pub fn parser_square_bracket_and_bracket(input: &str) -> IResult<&str, (&str, &str)> {
tuple((parser_square_bracket, parser_bracket))(input)
}
pub fn parser_bracket(input: &str) -> IResult<&str, &str> {
delimited(tag("("), is_not(")"), tag(")"))(input)
}
pub fn parser_square_bracket(input: &str) -> IResult<&str, &str> {
delimited(tag("["), is_not("]"), tag("]"))(input)
}