use nom::{bytes::complete::tag, combinator::opt, sequence::preceded, IResult, Parser};
use crate::{md_parser::constants::{COLON, NEW_LINE, SPACE},
take_text_until_new_line_or_end,
tiny_inline_string};
pub fn parse_unique_kv_opt_eol<'a>(
tag_name: &'a str,
input: &'a str,
) -> IResult<&'a str, &'a str> {
let (remainder, title_text) = preceded(
(tag(tag_name), tag(COLON), tag(SPACE)),
take_text_until_new_line_or_end(),
)
.parse(input)?;
let tag_fragment = tiny_inline_string!("{tag_name}{COLON}{SPACE}");
if title_text.contains(tag_fragment.as_str())
| remainder.contains(tag_fragment.as_str())
{
return Err(nom::Err::Error(nom::error::Error::new(
"Can't have more than one tag_name in kv expr.",
nom::error::ErrorKind::Fail,
)));
}
let (remainder, _) = opt(tag(NEW_LINE)).parse(remainder)?;
if title_text.is_empty() {
Ok((remainder, ""))
}
else {
Ok((remainder, title_text))
}
}
#[cfg(test)]
mod test_parse_title_no_eol {
use super::*;
use crate::{assert_eq2, fg_black, inline_string, md_parser::constants::TITLE};
#[test]
fn test_not_quoted_no_eol() {
let input = "@title: Something";
let (input, output) = parse_unique_kv_opt_eol(TITLE, input).unwrap();
println!(
"input: '{i}', output: '{o}'",
i = fg_black(input).bg_yellow(),
o = fg_black(output).bg_green(),
);
assert_eq2!(input, "");
assert_eq2!(output, "Something");
}
#[test]
fn test_not_quoted_with_eol() {
let input = "@title: Something\n";
let (input, output) = parse_unique_kv_opt_eol(TITLE, input).unwrap();
println!(
"input: '{i}', output: '{o}'",
i = fg_black(input).bg_yellow(),
o = fg_black(output).bg_green(),
);
assert_eq2!(input, "");
assert_eq2!(output, "Something");
}
#[test]
fn test_no_quoted_no_eol_nested_title() {
let input = "@title: Something @title: Something";
let it = parse_unique_kv_opt_eol(TITLE, input);
assert_eq2!(it.is_err(), true);
if let Err(nom::Err::Error(ref e)) = it {
assert_eq2!(e.input, "Can't have more than one tag_name in kv expr.");
assert_eq2!(e.code, nom::error::ErrorKind::Fail);
}
println!(
"err: '{}'",
fg_black(&inline_string!("{:?}", it.err().unwrap())).bg_yellow(),
);
}
#[test]
fn test_no_quoted_no_eol_multiple_title_tags() {
let input = "@title: Something\n@title: Else\n";
let it = parse_unique_kv_opt_eol(TITLE, input);
assert_eq2!(it.is_err(), true);
if let Err(nom::Err::Error(ref e)) = it {
assert_eq2!(e.input, "Can't have more than one tag_name in kv expr.");
assert_eq2!(e.code, nom::error::ErrorKind::Fail);
}
println!(
"err: '{}'",
fg_black(&inline_string!("{:?}", it.err().unwrap())).bg_yellow(),
);
}
#[test]
fn test_no_quoted_with_eol_title_with_postfix_content_1() {
let input = "@title: \nfoo\nbar";
println!("input: '{}'", fg_black(input).bg_cyan(),);
let (input, output) = parse_unique_kv_opt_eol(TITLE, input).unwrap();
println!(
"input: '{i}', output: '{o}'",
i = fg_black(input).bg_yellow(),
o = fg_black(output).bg_green(),
);
assert_eq2!(input, "foo\nbar");
assert_eq2!(output, "");
}
#[test]
fn test_no_quoted_with_eol_title_with_postfix_content_2() {
let input = "@title: a\nfoo\nbar";
println!("input: '{}'", fg_black(input).bg_cyan(),);
let (input, output) = parse_unique_kv_opt_eol(TITLE, input).unwrap();
println!(
"input: '{i}', output: '{o}'",
i = fg_black(input).bg_yellow(),
o = fg_black(output).bg_green(),
);
assert_eq2!(input, "foo\nbar");
assert_eq2!(output, " a");
}
#[test]
fn test_no_quoted_with_eol_title_with_postfix_content_3() {
let input = "@title: \n\n# heading1\n## heading2";
println!("❯ input: \n'{}'", fg_black(input).bg_cyan(),);
let (remainder, title) = parse_unique_kv_opt_eol(TITLE, input).unwrap();
println!(
"❯ remainder: \n'{r}'\n❯ title: \n'{t}'",
r = fg_black(remainder).bg_yellow(),
t = fg_black(title).bg_green(),
);
assert_eq2!(remainder, "\n# heading1\n## heading2");
assert_eq2!(title, "");
}
}