flatiron 1.0.5

A parser and HTML renderer for the Textile markup language
Documentation
use crate::structs::InlineTag;
use nom::{
    branch::alt,
    bytes::complete::tag,
    character::complete::{char, digit1, satisfy},
    combinator::{eof, map, opt, value},
    sequence::tuple,
    IResult,
};

pub fn punctuation(input: &str) -> IResult<&str, InlineTag> {
    let (rest, s) = alt((
        apostrophe,
        apostrophe2,
        single_closing,
        double_closing,
        dimension_sign,
        map(
            alt((
                value("", tag("'")),
                value("", tag("\"")),
                value("", tag("...")),
                value("", tag("--")),
                value("", tag(" - ")),
                value("", tag("(TM)")),
                value("®", tag("(R)")),
                value("©", tag("(C)")),
            )),
            |s| String::from(s),
        ),
    ))(input)?;
    Ok((rest, InlineTag::Plaintext(s)))
}

fn apostrophe(input: &str) -> IResult<&str, String> {
    let (rest, (c0, apos, c1)) =
        tuple((alphanumeric, value('', char('\'')), alphanumeric))(input)?;
    Ok((rest, format!("{}{}{}", c0, apos, c1)))
}

fn apostrophe2(input: &str) -> IResult<&str, String> {
    let (rest, (space, apos, num, alphanum, end)) = tuple((
        whitespace,
        value('', char('\'')),
        digit1,
        opt(alphanumeric),
        satisfy(|c| !(c.is_alphanumeric() || c == '\'')),
    ))(input)?;
    Ok((
        rest,
        format!(
            "{}{}{}{}{}",
            space,
            apos,
            num,
            match alphanum {
                Some(c) => String::from(c),
                None => String::new(),
            },
            end
        ),
    ))
}

fn single_closing(input: &str) -> IResult<&str, String> {
    let (rest, (non_space, apos, end)) = tuple((
        non_whitespace,
        value('', char('\'')),
        alt((
            value(String::new(), eof),
            map(non_alphanumeric, |c| String::from(c)),
        )),
    ))(input)?;
    Ok((rest, format!("{}{}{}", non_space, apos, end)))
}

fn double_closing(input: &str) -> IResult<&str, String> {
    let (rest, (non_space, apos, end)) = tuple((
        non_whitespace,
        value('', char('"')),
        alt((
            value(String::new(), eof),
            map(non_alphanumeric, |c| String::from(c)),
        )),
    ))(input)?;
    Ok((rest, format!("{}{}{}", non_space, apos, end)))
}

fn alphanumeric(input: &str) -> IResult<&str, char> {
    satisfy(|c| c.is_alphanumeric())(input)
}

fn non_alphanumeric(input: &str) -> IResult<&str, char> {
    satisfy(|c| !c.is_alphanumeric())(input)
}

fn whitespace(input: &str) -> IResult<&str, char> {
    satisfy(|c| c.is_whitespace())(input)
}

fn non_whitespace(input: &str) -> IResult<&str, char> {
    satisfy(|c| !c.is_whitespace())(input)
}

fn dimension_sign(input: &str) -> IResult<&str, String> {
    let (rest, (num0, space0, x, space1, num1)) = tuple((
        digit1,
        alt((tag(" "), tag(""))),
        value('×', char('x')),
        alt((tag(" "), tag(""))),
        digit1,
    ))(input)?;
    Ok((rest, format!("{}{}{}{}{}", num0, space0, x, space1, num1)))
}