use crate::{DEBUG_MD_PARSER_STDOUT, fg_blue, fg_magenta, fg_red, is_any_of,
md_parser::md_parser_constants::{BACK_TICK, LEFT_BRACKET, LEFT_IMAGE,
NEW_LINE, NEW_LINE_CHAR, NULL_CHAR,
NULL_STR, STAR, UNDERSCORE},
specialized_parser_delim_matchers};
use nom::{IResult, Parser,
branch::alt,
bytes::complete::{tag, take_till1},
character::complete::anychar,
combinator::{not, recognize},
multi::many1,
sequence::preceded};
pub fn parse_fragment_plain_text_no_new_line(input: &str) -> IResult<&str, &str> {
DEBUG_MD_PARSER_STDOUT.then(|| {
println!("\n{} plain parser, input: {:?}", fg_magenta("██"), input);
});
if check_input_starts_with(input, &get_sp_char_set_2()).is_none() {
let tag_vec = get_sp_char_set_3()
.into_iter()
.map(tag::<&str, &str, nom::error::Error<&str>>)
.collect::<Vec<_>>();
let tag_tuple = {
assert_eq!(tag_vec.len(), 7);
tuple7(&tag_vec)
};
let it = recognize(
many1( preceded(
not(
alt(tag_tuple),
),
anychar,
)),
).parse(input);
DEBUG_MD_PARSER_STDOUT.then(|| {
println!(
"{} normal case :: {:?}",
if it.is_err() {
fg_red("⬢⬢")
} else {
fg_blue("▲▲")
},
it
);
});
return it;
}
if let Some(special_str) = check_input_starts_with(input, &get_sp_char_set_1()) {
let (count, _, _, _) =
specialized_parser_delim_matchers::count_delim_occurrences_until_eol(
input,
special_str,
);
if count == 1 {
let (rem, output) = recognize(many1(tag(special_str))).parse(input)?;
DEBUG_MD_PARSER_STDOUT.then(|| {
println!(
"{} edge case -> special case :: rem: {:?}, output: {:?}",
fg_blue("▲▲"),
rem,
output
);
});
return Ok((rem, output));
}
}
let it = take_till1(is_any_of(&[NEW_LINE_CHAR, NULL_CHAR]))(input);
DEBUG_MD_PARSER_STDOUT.then(|| {
println!(
"{} edge case -> normal case :: {:?}",
if it.is_err() {
fg_red("⬢⬢")
} else {
fg_blue("▲▲")
},
it
);
});
it
}
fn get_sp_char_set_1<'a>() -> [&'a str; 3] { [UNDERSCORE, STAR, BACK_TICK] }
fn get_sp_char_set_2<'a>() -> [&'a str; 5] {
get_sp_char_set_1()
.iter()
.chain([LEFT_IMAGE, LEFT_BRACKET].iter())
.copied()
.collect::<Vec<_>>()
.try_into()
.unwrap()
}
fn get_sp_char_set_3<'a>() -> [&'a str; 7] {
get_sp_char_set_2()
.iter()
.chain([NEW_LINE, NULL_STR].iter())
.copied()
.collect::<Vec<_>>()
.try_into()
.unwrap()
}
fn check_input_starts_with<'a>(input: &'a str, char_set: &[&'a str]) -> Option<&'a str> {
char_set
.iter()
.find(|&special_str| input.starts_with(special_str))
.copied()
}
#[allow(dead_code)]
fn tuple5<T>(a: &[T]) -> (&T, &T, &T, &T, &T) { (&a[0], &a[1], &a[2], &a[3], &a[4]) }
#[allow(dead_code)]
fn tuple6<T>(a: &[T]) -> (&T, &T, &T, &T, &T, &T) {
(&a[0], &a[1], &a[2], &a[3], &a[4], &a[5])
}
fn tuple7<T>(a: &[T]) -> (&T, &T, &T, &T, &T, &T, &T) {
(&a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6])
}
#[cfg(test)]
mod tests {
use super::*;
use crate::assert_eq2;
#[test]
fn test_parse_plain_text_with_null_padding() {
{
let input = "hello\0\0\0world";
let (remainder, content) =
parse_fragment_plain_text_no_new_line(input).unwrap();
assert_eq2!(content, "hello");
assert_eq2!(remainder, "\0\0\0world");
}
{
let input = "hello\n\0\0\0world";
let (remainder, content) =
parse_fragment_plain_text_no_new_line(input).unwrap();
assert_eq2!(content, "hello");
assert_eq2!(remainder, "\n\0\0\0world");
}
{
let input = "hello world\0\0\0";
let (remainder, content) =
parse_fragment_plain_text_no_new_line(input).unwrap();
assert_eq2!(content, "hello world");
assert_eq2!(remainder, "\0\0\0");
}
}
}