diff --git a/rustfmt.toml b/rustfmt.toml index da3d1e7..5795ff1 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,4 +1,5 @@ imports_granularity = "Item" +group_imports = "StdExternalCrate" # In rustfmt 2.0 I will want to adjust these settings. # diff --git a/src/parser/object_parser.rs b/src/parser/object_parser.rs index 7b9920e..0fd833b 100644 --- a/src/parser/object_parser.rs +++ b/src/parser/object_parser.rs @@ -43,3 +43,17 @@ pub fn minimal_set_object<'r, 's>( map(parser_with_context!(plain_text)(context), Object::PlainText), ))(input) } + +#[tracing::instrument(ret, level = "debug")] +pub fn any_object_except_plain_text<'r, 's>( + context: Context<'r, 's>, + input: &'s str, +) -> Res<&'s str, Object<'s>> { + // TODO: add entities, LaTeX fragments, export snippets, footnote references, citations (NOT citation references), inline babel calls, inline source blocks, line breaks, links, macros, targets and radio targets, statistics cookies, subscript and superscript, timestamps, and text markup. + not(|i| context.check_exit_matcher(i))(input)?; + + alt((map( + parser_with_context!(text_markup)(context), + Object::TextMarkup, + ),))(input) +} diff --git a/src/parser/plain_text.rs b/src/parser/plain_text.rs index 6b515aa..e65faaa 100644 --- a/src/parser/plain_text.rs +++ b/src/parser/plain_text.rs @@ -1,9 +1,16 @@ +use nom::combinator::not; +use nom::combinator::recognize; + use super::object::PlainText; use super::Context; use crate::error::CustomError; use crate::error::MyError; use crate::error::Res; -use nom::combinator::not; +use crate::parser::exiting::ExitClass; +use crate::parser::object_parser::any_object_except_plain_text; +use crate::parser::parser_context::ContextElement; +use crate::parser::parser_context::ExitMatcherNode; +use crate::parser::parser_with_context::parser_with_context; #[tracing::instrument(ret, level = "debug")] pub fn plain_text<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, PlainText<'s>> { @@ -12,12 +19,17 @@ pub fn plain_text<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s s "Zero input length to plain_text.", )))); } + let parser_context = + context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { + class: ExitClass::Beta, + exit_matcher: &plain_text_end, + })); let mut current_input = input.char_indices(); loop { match current_input.next() { Some((offset, _char)) => { let remaining = &input[offset..]; - let exit_matcher_status = not(|i| context.check_exit_matcher(i))(remaining); + let exit_matcher_status = not(|i| parser_context.check_exit_matcher(i))(remaining); if exit_matcher_status.is_err() { if offset == 0 { // If we're at the start of the input, then nothing is plain text, so fire an error for zero-length match. @@ -40,18 +52,22 @@ pub fn plain_text<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s s } } +#[tracing::instrument(ret, level = "debug")] +fn plain_text_end<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, &'s str> { + recognize(parser_with_context!(any_object_except_plain_text)(context))(input) +} + #[cfg(test)] mod tests { use nom::combinator::map; + use super::*; use crate::parser::object::Object; use crate::parser::parser_context::ContextElement; use crate::parser::parser_context::ContextTree; use crate::parser::parser_with_context::parser_with_context; use crate::parser::source::Source; - use super::*; - #[test] fn plain_text_simple() { let input = "foobarbaz";