Use context_many1 for paragraphs in a document.
This commit is contained in:
		
							parent
							
								
									601fc4776a
								
							
						
					
					
						commit
						1da38c8f7d
					
				| @ -72,7 +72,7 @@ where | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         let elements: Vec<Token<'s>> = current_context |         let mut elements: Vec<Token<'s>> = current_context | ||||||
|             .into_iter_until(context) |             .into_iter_until(context) | ||||||
|             .filter_map(|context_element| match context_element { |             .filter_map(|context_element| match context_element { | ||||||
|                 ContextElement::PreviousElementNode(elem) => Some(elem.element), |                 ContextElement::PreviousElementNode(elem) => Some(elem.element), | ||||||
| @ -86,6 +86,7 @@ where | |||||||
|                 err?; |                 err?; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         elements.reverse(); | ||||||
|         Ok((i, elements)) |         Ok((i, elements)) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -79,6 +79,12 @@ pub struct Link<'a> { | |||||||
|     pub contents: &'a str, |     pub contents: &'a str, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct Paragraph<'a> { | ||||||
|  |     pub contents: Vec<TextElement<'a>>, | ||||||
|  |     pub paragraph_end: &'a str, | ||||||
|  | } | ||||||
|  | 
 | ||||||
| pub fn line_break(input: &str) -> Res<&str, LineBreak> { | pub fn line_break(input: &str) -> Res<&str, LineBreak> { | ||||||
|     map(line_ending, |s: &str| LineBreak { contents: s })(input) |     map(line_ending, |s: &str| LineBreak { contents: s })(input) | ||||||
| } | } | ||||||
|  | |||||||
| @ -21,6 +21,7 @@ use super::text::span; | |||||||
| use super::text::symbol; | use super::text::symbol; | ||||||
| use super::text::Bold; | use super::text::Bold; | ||||||
| use super::text::Link; | use super::text::Link; | ||||||
|  | use super::text::Paragraph; | ||||||
| use super::text::Res; | use super::text::Res; | ||||||
| use super::text::TextElement; | use super::text::TextElement; | ||||||
| use super::token::Token; | use super::token::Token; | ||||||
| @ -45,10 +46,16 @@ use nom::InputLength; | |||||||
| 
 | 
 | ||||||
| type UnboundMatcher<'r, 's, I, O, E> = dyn Fn(Context<'r, 's>, I) -> IResult<I, O, E>; | type UnboundMatcher<'r, 's, I, O, E> = dyn Fn(Context<'r, 's>, I) -> IResult<I, O, E>; | ||||||
| 
 | 
 | ||||||
| pub fn document(input: &str) -> Res<&str, Vec<(Vec<TextElement>, &str)>> { | pub fn document(input: &str) -> Res<&str, Vec<Paragraph>> { | ||||||
|     let initial_context: ContextTree<'_, '_> = ContextTree::new(); |     let initial_context: ContextTree<'_, '_> = ContextTree::new(); | ||||||
|     let ret = context_many1(&initial_context, paragraph)(input); |     let (remaining, tokens) = context_many1(&initial_context, paragraph)(input)?; | ||||||
|     ret |     let paragraphs = tokens.into_iter().map(|token| { | ||||||
|  |         match token { | ||||||
|  |             Token::TextElement(_) => unreachable!(), | ||||||
|  |             Token::Paragraph(paragraph) => paragraph, | ||||||
|  |         } | ||||||
|  |     }).collect(); | ||||||
|  |     Ok((remaining, paragraphs)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn context_paragraph_end<'s, 'r>( | pub fn context_paragraph_end<'s, 'r>( | ||||||
| @ -93,6 +100,7 @@ fn _preceded_by_whitespace<'s, 'r>(context: Context<'r, 's>) -> bool { | |||||||
|                                 TextElement::Link(_) => return false, |                                 TextElement::Link(_) => return false, | ||||||
|                             }; |                             }; | ||||||
|                         } |                         } | ||||||
|  |                         Token::Paragraph(_) => unreachable!(), | ||||||
|                     }; |                     }; | ||||||
|                 } |                 } | ||||||
|                 ContextElement::StartOfParagraph => { |                 ContextElement::StartOfParagraph => { | ||||||
| @ -134,26 +142,30 @@ pub fn context_bold_end<'s, 'r>(context: Context<'r, 's>, input: &'s str) -> Res | |||||||
|     Ok((remaining, actual_match)) |     Ok((remaining, actual_match)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn paragraph<'s, 'r>( | pub fn paragraph<'s, 'r>(context: Context<'r, 's>, i: &'s str) -> Res<&'s str, Paragraph<'s>> { | ||||||
|     context: Context<'r, 's>, |  | ||||||
|     i: &'s str, |  | ||||||
| ) -> Res<&'s str, (Vec<TextElement<'s>>, &'s str)> { |  | ||||||
|     // Add a not(eof) check because many_till cannot match a zero-length string
 |     // Add a not(eof) check because many_till cannot match a zero-length string
 | ||||||
|     not(eof)(i)?; |     not(eof)(i)?; | ||||||
|     let paragraph_context = context |     let paragraph_context = context | ||||||
|         .with_additional_node(ContextElement::StartOfParagraph) |  | ||||||
|         .with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { |         .with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { | ||||||
|             exit_matcher: ChainBehavior::AndParent(Some(&context_paragraph_end)), |             exit_matcher: ChainBehavior::AndParent(Some(&context_paragraph_end)), | ||||||
|         })); |         })) | ||||||
|  |         .with_additional_node(ContextElement::StartOfParagraph); | ||||||
|     let (remaining, (many, till)) = |     let (remaining, (many, till)) = | ||||||
|         context_many_till(¶graph_context, flat_text_element, context_paragraph_end)(i)?; |         context_many_till(¶graph_context, flat_text_element, context_paragraph_end)(i)?; | ||||||
|     let many = many |     let many = many | ||||||
|         .into_iter() |         .into_iter() | ||||||
|         .filter_map(|token| match token { |         .filter_map(|token| match token { | ||||||
|             Token::TextElement(text_element) => Some(text_element), |             Token::TextElement(text_element) => Some(text_element), | ||||||
|  |             Token::Paragraph(_) => panic!("There should only be text elements in paragraphs."), | ||||||
|         }) |         }) | ||||||
|         .collect(); |         .collect(); | ||||||
|     Ok((remaining, (many, till))) |     Ok(( | ||||||
|  |         remaining, | ||||||
|  |         Paragraph { | ||||||
|  |             contents: many, | ||||||
|  |             paragraph_end: till, | ||||||
|  |         }, | ||||||
|  |     )) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn flat_text_element<'s, 'r>( | fn flat_text_element<'s, 'r>( | ||||||
|  | |||||||
| @ -1,8 +1,10 @@ | |||||||
|  | use super::text::Paragraph; | ||||||
| use super::text::TextElement; | use super::text::TextElement; | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub enum Token<'a> { | pub enum Token<'a> { | ||||||
|     TextElement(TextElement<'a>), |     TextElement(TextElement<'a>), | ||||||
|  |     Paragraph(Paragraph<'a>), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'a> Into<Token<'a>> for TextElement<'a> { | impl<'a> Into<Token<'a>> for TextElement<'a> { | ||||||
| @ -10,3 +12,9 @@ impl<'a> Into<Token<'a>> for TextElement<'a> { | |||||||
|         Token::TextElement(self) |         Token::TextElement(self) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | impl<'a> Into<Token<'a>> for Paragraph<'a> { | ||||||
|  |     fn into(self) -> Token<'a> { | ||||||
|  |         Token::Paragraph(self) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Tom Alexander
						Tom Alexander