From a4cce121c0a6e47a31a656608bf178d00c048615 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sat, 22 Apr 2023 19:46:27 -0400 Subject: [PATCH] Add an exit matcher to plain text. --- rustfmt.toml | 1 + src/parser/object_parser.rs | 14 ++++++++++++++ src/parser/plain_text.rs | 24 ++++++++++++++++++++---- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/rustfmt.toml b/rustfmt.toml index da3d1e78..5795ff15 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 7b9920e2..0fd833b4 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 6b515aa4..e65faaa5 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";