From eaf8721ae9403ec1d4ce6e5a51ce2281c23fc812 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 18 Dec 2022 02:53:26 -0500 Subject: [PATCH] Move paragraph to its own module. --- src/parser/mod.rs | 1 + src/parser/paragraph.rs | 62 +++++++++++++++++++++++++++++++ src/parser/text.rs | 12 +----- src/parser/text_element_parser.rs | 42 +-------------------- 4 files changed, 66 insertions(+), 51 deletions(-) create mode 100644 src/parser/paragraph.rs diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 77336c97..14a49c27 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -3,6 +3,7 @@ mod combinator; mod error; mod link; mod list; +mod paragraph; mod parser_context; mod parser_with_context; mod text; diff --git a/src/parser/paragraph.rs b/src/parser/paragraph.rs new file mode 100644 index 00000000..43c987a0 --- /dev/null +++ b/src/parser/paragraph.rs @@ -0,0 +1,62 @@ +use super::combinator::context_many_till; +use super::parser_context::ChainBehavior; +use super::parser_context::ContextElement; +use super::parser_context::ExitMatcherNode; +use super::text::blank_line; +use super::text::line_break; +use super::text::Paragraph; +use super::text::Res; +use super::text::TextElement; +use super::text_element_parser::flat_text_element; +use super::token::Token; +use super::Context; +use nom::branch::alt; +use nom::combinator::eof; +use nom::combinator::map; +use nom::combinator::not; +use nom::combinator::recognize; +use nom::multi::many1; +use nom::sequence::tuple; + +pub fn paragraph<'s, 'r>(context: Context<'r, 's>, i: &'s str) -> Res<&'s str, Paragraph<'s>> { + // Add a not(eof) check because many_till cannot match a zero-length string + not(eof)(i)?; + let paragraph_context = context + .with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { + exit_matcher: ChainBehavior::AndParent(Some(&context_paragraph_end)), + })) + .with_additional_node(ContextElement::StartOfParagraph); + let (remaining, (many, till)) = + context_many_till(¶graph_context, flat_text_element, context_paragraph_end)(i)?; + let many = many + .into_iter() + .filter_map(|token| match token { + Token::TextElement(text_element) => Some(text_element), + Token::Paragraph(_) => panic!("There should only be text elements in paragraphs."), + }) + .collect(); + Ok(( + remaining, + Paragraph { + contents: many, + paragraph_end: till, + }, + )) +} + +fn context_paragraph_end<'s, 'r>( + context: Context<'r, 's>, + input: &'s str, +) -> Res<&'s str, &'s str> { + paragraph_end(input) +} + +fn paragraph_end(input: &str) -> Res<&str, &str> { + alt(( + recognize(tuple(( + map(line_break, TextElement::LineBreak), + many1(blank_line), + ))), + eof, + ))(input) +} diff --git a/src/parser/text.rs b/src/parser/text.rs index 0e7a01df..637a7d9a 100644 --- a/src/parser/text.rs +++ b/src/parser/text.rs @@ -90,7 +90,7 @@ pub fn symbol(symbol_tag: &'static str) -> impl for<'a> Fn(&'a str) -> Res<&'a s /// A line containing only whitespace and then a line break /// /// It is up to the caller to ensure this is called at the start of a line. -fn blank_line(input: &str) -> Res<&str, BlankLine> { +pub fn blank_line(input: &str) -> Res<&str, BlankLine> { map( recognize(many_till( map(space, TextElement::Space), @@ -99,13 +99,3 @@ fn blank_line(input: &str) -> Res<&str, BlankLine> { |contents| BlankLine { contents }, )(input) } - -pub fn paragraph_end(input: &str) -> Res<&str, &str> { - alt(( - recognize(tuple(( - map(line_break, TextElement::LineBreak), - many1(blank_line), - ))), - eof, - ))(input) -} diff --git a/src/parser/text_element_parser.rs b/src/parser/text_element_parser.rs index fc485e1b..24b92cfa 100644 --- a/src/parser/text_element_parser.rs +++ b/src/parser/text_element_parser.rs @@ -1,15 +1,10 @@ //! A single element of text. -use crate::parser::parser_with_context::parser_with_context; -use crate::parser::text::paragraph_end; - use super::bold::bold; use super::combinator::context_many1; -use super::combinator::context_many_till; use super::link::link; -use super::parser_context::ChainBehavior; +use super::paragraph::paragraph; use super::parser_context::ContextElement; use super::parser_context::ContextTree; -use super::parser_context::ExitMatcherNode; use super::text::line_break; use super::text::space; use super::text::span; @@ -19,8 +14,8 @@ use super::text::Res; use super::text::TextElement; use super::token::Token; use super::Context; +use crate::parser::parser_with_context::parser_with_context; use nom::branch::alt; -use nom::combinator::eof; use nom::combinator::map; use nom::combinator::not; use nom::IResult; @@ -40,13 +35,6 @@ pub fn document(input: &str) -> Res<&str, Vec> { Ok((remaining, paragraphs)) } -pub fn context_paragraph_end<'s, 'r>( - context: Context<'r, 's>, - input: &'s str, -) -> Res<&'s str, &'s str> { - paragraph_end(input) -} - pub fn in_section<'s, 'r, 'x>(context: Context<'r, 's>, section_name: &'x str) -> bool { for thing in context.iter() { match thing.get_data() { @@ -93,32 +81,6 @@ pub fn _preceded_by_whitespace<'s, 'r>(context: Context<'r, 's>) -> bool { false } -pub fn paragraph<'s, 'r>(context: Context<'r, 's>, i: &'s str) -> Res<&'s str, Paragraph<'s>> { - // Add a not(eof) check because many_till cannot match a zero-length string - not(eof)(i)?; - let paragraph_context = context - .with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { - exit_matcher: ChainBehavior::AndParent(Some(&context_paragraph_end)), - })) - .with_additional_node(ContextElement::StartOfParagraph); - let (remaining, (many, till)) = - context_many_till(¶graph_context, flat_text_element, context_paragraph_end)(i)?; - let many = many - .into_iter() - .filter_map(|token| match token { - Token::TextElement(text_element) => Some(text_element), - Token::Paragraph(_) => panic!("There should only be text elements in paragraphs."), - }) - .collect(); - Ok(( - remaining, - Paragraph { - contents: many, - paragraph_end: till, - }, - )) -} - pub fn flat_text_element<'s, 'r>( context: Context<'r, 's>, i: &'s str,