CorrosionMark 0.1.1

This is a markdown parser libary
Documentation
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;

        // we don't have characters to parse or another parser is matching, so we return
        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)
}