Revert "Migrating to the new context tree."
This reverts commit c37008df1d41c36780c57054c3d0e0244478c8d5.
This commit is contained in:
		
							parent
							
								
									29add885f3
								
							
						
					
					
						commit
						6e2ff8b870
					
				| @ -1,3 +1,4 @@ | |||||||
|  | mod new_context; | ||||||
| mod nom_context; | mod nom_context; | ||||||
| mod parser_with_context; | mod parser_with_context; | ||||||
| mod text; | mod text; | ||||||
|  | |||||||
							
								
								
									
										133
									
								
								src/parser/new_context.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								src/parser/new_context.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,133 @@ | |||||||
|  | use nom::combinator::not; | ||||||
|  | use nom::combinator::recognize; | ||||||
|  | use nom::complete::take; | ||||||
|  | use nom::error::ErrorKind; | ||||||
|  | use nom::error::ParseError; | ||||||
|  | use nom::error::VerboseError; | ||||||
|  | use nom::IResult; | ||||||
|  | use std::borrow::Cow; | ||||||
|  | 
 | ||||||
|  | use super::text::bold_end; | ||||||
|  | use super::text::Res; | ||||||
|  | 
 | ||||||
|  | type Matcher = dyn for<'s> Fn(&'s str) -> IResult<&'s str, &'s str, VerboseError<&'s str>>; | ||||||
|  | type Link<'r, T> = Option<&'r Node<'r, T>>; | ||||||
|  | 
 | ||||||
|  | pub trait OrgModeContext<'r> { | ||||||
|  |     fn get_fail_matcher(&'r self) -> Cow<ChainBehavior<'r>>; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct FailMatcherNode<'r> { | ||||||
|  |     fail_matcher: ChainBehavior<'r>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct PreviousElementNode<'r> { | ||||||
|  |     dummy: &'r str, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Clone)] | ||||||
|  | pub enum ChainBehavior<'r> { | ||||||
|  |     AndParent(Option<&'r Matcher>), | ||||||
|  |     IgnoreParent(Option<&'r Matcher>), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct Node<'r, T: 'r + ?Sized> { | ||||||
|  |     elem: &'r T, | ||||||
|  |     parent: Link<'r, T>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct ContextTree<'r, T: 'r + ?Sized> { | ||||||
|  |     // Not using Link so the ContextTree can own this node
 | ||||||
|  |     head: Option<Node<'r, T>>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'r> ContextTree<'r, dyn OrgModeContext<'r>> { | ||||||
|  |     pub fn new() -> Self { | ||||||
|  |         ContextTree { head: None } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn with_additional_node( | ||||||
|  |         &'r self, | ||||||
|  |         new_elem: &'r dyn OrgModeContext<'r>, | ||||||
|  |     ) -> ContextTree<'r, dyn OrgModeContext<'r>> { | ||||||
|  |         let new_node = Node { | ||||||
|  |             elem: new_elem, | ||||||
|  |             parent: self.head.as_ref(), | ||||||
|  |         }; | ||||||
|  |         ContextTree { | ||||||
|  |             head: Some(new_node), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn check_fail_matcher<'s>( | ||||||
|  |         &'r self, | ||||||
|  |         i: &'s str, | ||||||
|  |     ) -> IResult<&'s str, &'s str, VerboseError<&'s str>> { | ||||||
|  |         let mut current_node = self.head.as_ref(); | ||||||
|  |         while current_node.is_some() { | ||||||
|  |             let current_node_unwrapped = | ||||||
|  |                 current_node.expect("while loop asserts current_node is some."); | ||||||
|  |             let current_fail_matcher = current_node_unwrapped.elem.get_fail_matcher(); | ||||||
|  |             match current_fail_matcher.as_ref() { | ||||||
|  |                 ChainBehavior::AndParent(Some(matcher)) => { | ||||||
|  |                     let local_result = matcher(i); | ||||||
|  |                     if local_result.is_ok() { | ||||||
|  |                         return local_result; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 ChainBehavior::AndParent(None) => {} | ||||||
|  |                 ChainBehavior::IgnoreParent(Some(matcher)) => { | ||||||
|  |                     return matcher(i); | ||||||
|  |                 } | ||||||
|  |                 ChainBehavior::IgnoreParent(None) => { | ||||||
|  |                     // TODO: Make this a custom error
 | ||||||
|  |                     return Err(nom::Err::Error(VerboseError::from_error_kind( | ||||||
|  |                         i, | ||||||
|  |                         ErrorKind::ManyTill, | ||||||
|  |                     ))); | ||||||
|  |                 } | ||||||
|  |             }; | ||||||
|  |             current_node = current_node | ||||||
|  |                 .map(|current_head| current_head.parent) | ||||||
|  |                 .flatten(); | ||||||
|  |         } | ||||||
|  |         // TODO: Make this a custom error
 | ||||||
|  |         return Err(nom::Err::Error(VerboseError::from_error_kind( | ||||||
|  |             i, | ||||||
|  |             ErrorKind::ManyTill, | ||||||
|  |         ))); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'r> OrgModeContext<'r> for FailMatcherNode<'r> { | ||||||
|  |     fn get_fail_matcher(&'r self) -> Cow<ChainBehavior<'r>> { | ||||||
|  |         Cow::Borrowed(&self.fail_matcher) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'r> OrgModeContext<'r> for PreviousElementNode<'r> { | ||||||
|  |     fn get_fail_matcher(&'r self) -> Cow<ChainBehavior<'r>> { | ||||||
|  |         Cow::Owned(ChainBehavior::AndParent(None)) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn recognize_bold_end(input: &str) -> Res<&str, &str> { | ||||||
|  |     recognize(bold_end)(input) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn test_context() { | ||||||
|  |     let foo = "foo"; | ||||||
|  |     let context = ContextTree::new(); | ||||||
|  |     let child1_context = PreviousElementNode { dummy: foo }; | ||||||
|  |     let child1 = context.with_additional_node(&child1_context); | ||||||
|  |     let child2_context = FailMatcherNode { | ||||||
|  |         fail_matcher: ChainBehavior::AndParent(Some(&recognize_bold_end)), | ||||||
|  |     }; | ||||||
|  |     let child2 = child1.with_additional_node(&child2_context); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'r, T> std::fmt::Debug for ContextTree<'r, T> { | ||||||
|  |     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||||
|  |         write!(f, "ContextTree") | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,75 +1,89 @@ | |||||||
|  | use std::cell::RefCell; | ||||||
|  | use std::rc::Rc; | ||||||
|  | 
 | ||||||
|  | use nom::branch::alt; | ||||||
|  | use nom::bytes::complete::take; | ||||||
| use nom::combinator::not; | use nom::combinator::not; | ||||||
| use nom::combinator::recognize; | use nom::error::ContextError; | ||||||
| use nom::complete::take; |  | ||||||
| use nom::error::ErrorKind; | use nom::error::ErrorKind; | ||||||
| use nom::error::ParseError; | use nom::error::ParseError; | ||||||
| use nom::error::VerboseError; | use nom::error::VerboseError; | ||||||
| use nom::IResult; | use nom::IResult; | ||||||
| use std::borrow::Cow; | use nom::Parser; | ||||||
|  | use tracing::trace; | ||||||
| 
 | 
 | ||||||
| use super::text::bold_end; |  | ||||||
| use super::text::Res; |  | ||||||
| 
 |  | ||||||
| type Matcher = dyn for<'s> Fn(&'s str) -> IResult<&'s str, &'s str, VerboseError<&'s str>>; |  | ||||||
| type Link<'r, T> = Option<&'r Node<'r, T>>; | type Link<'r, T> = Option<&'r Node<'r, T>>; | ||||||
| pub type OrgModeContextTree<'r> = ContextTree<'r, dyn OrgModeContext<'r>>; | type Matcher = dyn for<'s> Fn(&'s str) -> IResult<&'s str, &'s str, VerboseError<&'s str>>; | ||||||
|  | pub type OrgModeContextNode<'r> = ContextTree<'r, ContextElement<'r>>; | ||||||
| 
 | 
 | ||||||
| pub trait OrgModeContext<'r> { | struct Node<'r, T> { | ||||||
|     fn get_fail_matcher(&'r self) -> Cow<ChainBehavior<'r>>; |     elem: T, | ||||||
|  |     next: Link<'r, T>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct FailMatcherNode<'r> { | pub struct ContextTree<'r, T> { | ||||||
|     fail_matcher: ChainBehavior<'r>, |     head: Option<Node<'r, T>>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct PreviousElementNode<'r> { | impl<'r, T> ContextTree<'r, T> { | ||||||
|     dummy: &'r str, |     pub fn new() -> Self { | ||||||
|  |         ContextTree { head: None } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn with_additional_node(&'r self, element: T) -> ContextTree<'r, T> { | ||||||
|  |         let new_node = Node { | ||||||
|  |             elem: element, | ||||||
|  |             next: self.head.as_ref(), | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         ContextTree { | ||||||
|  |             head: Some(new_node), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct ContextElement<'r> { | ||||||
|  |     pub fail_matcher: ChainBehavior<'r>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct PreviousElementNode<'r> { | ||||||
|  |     pub dummy: &'r str, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Clone)] |  | ||||||
| pub enum ChainBehavior<'r> { | pub enum ChainBehavior<'r> { | ||||||
|     AndParent(Option<&'r Matcher>), |     AndParent(Option<&'r Matcher>), | ||||||
|     IgnoreParent(Option<&'r Matcher>), |     IgnoreParent(Option<&'r Matcher>), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct Node<'r, T: 'r + ?Sized> { | pub trait OrgModeContextTree<'r> { | ||||||
|     elem: &'r T, |     fn with_additional_fail_matcher(&'r self, fail_matcher: &'r Matcher) -> OrgModeContextNode<'r>; | ||||||
|     parent: Link<'r, T>, | 
 | ||||||
|  |     fn match_fail<'s>(&'r self, i: &'s str) -> IResult<&'s str, &'s str, VerboseError<&'s str>>; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub struct ContextTree<'r, T: 'r + ?Sized> { | impl<'r> OrgModeContextTree<'r> for OrgModeContextNode<'r> { | ||||||
|     // Not using Link so the ContextTree can own this node
 |     fn with_additional_fail_matcher( | ||||||
|     head: Option<Node<'r, T>>, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<'r> ContextTree<'r, dyn OrgModeContext<'r>> { |  | ||||||
|     pub fn new() -> Self { |  | ||||||
|         ContextTree { head: None } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn with_additional_node( |  | ||||||
|         &'r self, |         &'r self, | ||||||
|         new_elem: &'r dyn OrgModeContext<'r>, |         fail_matcher: &'r Matcher, | ||||||
|     ) -> ContextTree<'r, dyn OrgModeContext<'r>> { |     ) -> ContextTree<'r, ContextElement<'r>> { | ||||||
|         let new_node = Node { |         self.with_additional_node(ContextElement { | ||||||
|             elem: new_elem, |             fail_matcher: ChainBehavior::AndParent(Some(fail_matcher)), | ||||||
|             parent: self.head.as_ref(), |         }) | ||||||
|         }; |  | ||||||
|         ContextTree { |  | ||||||
|             head: Some(new_node), |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn check_fail_matcher<'s>( |     // fn with_previous_element(&'r self, dummy: &'r str) -> ContextTree<'r, PreviousElementNode<'r>> {
 | ||||||
|         &'r self, |     //     self.with_additional_node(PreviousElementNode {
 | ||||||
|         i: &'s str, |     //         dummy
 | ||||||
|     ) -> IResult<&'s str, &'s str, VerboseError<&'s str>> { |     //     })
 | ||||||
|  |     // }
 | ||||||
|  | 
 | ||||||
|  |     fn match_fail<'s>(&'r self, i: &'s str) -> IResult<&'s str, &'s str, VerboseError<&'s str>> { | ||||||
|         let mut current_node = self.head.as_ref(); |         let mut current_node = self.head.as_ref(); | ||||||
|         while current_node.is_some() { |         while current_node.is_some() { | ||||||
|             let current_node_unwrapped = |             let current_node_unwrapped = current_node | ||||||
|                 current_node.expect("while loop asserts current_node is some."); |                 .as_ref() | ||||||
|             let current_fail_matcher = current_node_unwrapped.elem.get_fail_matcher(); |                 .expect("while loop asserts current_node is some."); | ||||||
|             match current_fail_matcher.as_ref() { |             match current_node_unwrapped.elem.fail_matcher { | ||||||
|                 ChainBehavior::AndParent(Some(matcher)) => { |                 ChainBehavior::AndParent(Some(matcher)) => { | ||||||
|                     let local_result = matcher(i); |                     let local_result = matcher(i); | ||||||
|                     if local_result.is_ok() { |                     if local_result.is_ok() { | ||||||
| @ -78,55 +92,26 @@ impl<'r> ContextTree<'r, dyn OrgModeContext<'r>> { | |||||||
|                 } |                 } | ||||||
|                 ChainBehavior::AndParent(None) => {} |                 ChainBehavior::AndParent(None) => {} | ||||||
|                 ChainBehavior::IgnoreParent(Some(matcher)) => { |                 ChainBehavior::IgnoreParent(Some(matcher)) => { | ||||||
|                     return matcher(i); |                     let local_result = matcher(i); | ||||||
|  |                     if local_result.is_ok() { | ||||||
|  |                         return local_result; | ||||||
|  |                     } | ||||||
|  |                     // TODO: Make this a custom error
 | ||||||
|  |                     not(take(0usize))(i)?; | ||||||
|                 } |                 } | ||||||
|                 ChainBehavior::IgnoreParent(None) => { |                 ChainBehavior::IgnoreParent(None) => { | ||||||
|                     // TODO: Make this a custom error
 |                     // TODO: Make this a custom error
 | ||||||
|                     return Err(nom::Err::Error(VerboseError::from_error_kind( |                     not(take(0usize))(i)?; | ||||||
|                         i, |  | ||||||
|                         ErrorKind::ManyTill, |  | ||||||
|                     ))); |  | ||||||
|                 } |                 } | ||||||
|             }; |             }; | ||||||
|             current_node = current_node |             current_node = current_node.map(|current_head| current_head.next).flatten(); | ||||||
|                 .map(|current_head| current_head.parent) |  | ||||||
|                 .flatten(); |  | ||||||
|         } |         } | ||||||
|         // TODO: Make this a custom error
 |         // TODO: Make this a custom error
 | ||||||
|         return Err(nom::Err::Error(VerboseError::from_error_kind( |         not(take(0usize))(i)?; | ||||||
|             i, |         unreachable!() | ||||||
|             ErrorKind::ManyTill, |  | ||||||
|         ))); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'r> OrgModeContext<'r> for FailMatcherNode<'r> { |  | ||||||
|     fn get_fail_matcher(&'r self) -> Cow<ChainBehavior<'r>> { |  | ||||||
|         Cow::Borrowed(&self.fail_matcher) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<'r> OrgModeContext<'r> for PreviousElementNode<'r> { |  | ||||||
|     fn get_fail_matcher(&'r self) -> Cow<ChainBehavior<'r>> { |  | ||||||
|         Cow::Owned(ChainBehavior::AndParent(None)) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn recognize_bold_end(input: &str) -> Res<&str, &str> { |  | ||||||
|     recognize(bold_end)(input) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn test_context() { |  | ||||||
|     let foo = "foo"; |  | ||||||
|     let context = ContextTree::new(); |  | ||||||
|     let child1_context = PreviousElementNode { dummy: foo }; |  | ||||||
|     let child1 = context.with_additional_node(&child1_context); |  | ||||||
|     let child2_context = FailMatcherNode { |  | ||||||
|         fail_matcher: ChainBehavior::AndParent(Some(&recognize_bold_end)), |  | ||||||
|     }; |  | ||||||
|     let child2 = child1.with_additional_node(&child2_context); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<'r, T> std::fmt::Debug for ContextTree<'r, T> { | impl<'r, T> std::fmt::Debug for ContextTree<'r, T> { | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||||
|         write!(f, "ContextTree") |         write!(f, "ContextTree") | ||||||
|  | |||||||
| @ -29,6 +29,9 @@ use nom::sequence::tuple; | |||||||
| use nom::IResult; | use nom::IResult; | ||||||
| use tracing::instrument; | use tracing::instrument; | ||||||
| 
 | 
 | ||||||
|  | use super::nom_context::ContextTree; | ||||||
|  | use super::nom_context::OrgModeContextTree; | ||||||
|  | use super::parser_with_context::parser_with_context; | ||||||
| use super::text_element_parser::paragraph; | use super::text_element_parser::paragraph; | ||||||
| 
 | 
 | ||||||
| pub type Res<T, U> = IResult<T, U, VerboseError<T>>; | pub type Res<T, U> = IResult<T, U, VerboseError<T>>; | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ use crate::parser::parser_with_context::parser_with_context; | |||||||
| use crate::parser::text::paragraph_end; | use crate::parser::text::paragraph_end; | ||||||
| 
 | 
 | ||||||
| use super::nom_context::ContextTree; | use super::nom_context::ContextTree; | ||||||
|  | use super::nom_context::OrgModeContextNode; | ||||||
| use super::nom_context::OrgModeContextTree; | use super::nom_context::OrgModeContextTree; | ||||||
| use super::text::bold_end; | use super::text::bold_end; | ||||||
| use super::text::bold_start; | use super::text::bold_start; | ||||||
| @ -37,7 +38,7 @@ use tracing::instrument; | |||||||
| use tracing::trace; | use tracing::trace; | ||||||
| 
 | 
 | ||||||
| fn context_many_till<'r, I, O, E, F, M, T>( | fn context_many_till<'r, I, O, E, F, M, T>( | ||||||
|     context: &'r OrgModeContextTree<'r>, |     context: &'r OrgModeContextNode<'r>, | ||||||
|     mut many_matcher: M, |     mut many_matcher: M, | ||||||
|     mut till_matcher: T, |     mut till_matcher: T, | ||||||
| ) -> impl FnMut(I) -> IResult<I, (Vec<O>, F), E> | ) -> impl FnMut(I) -> IResult<I, (Vec<O>, F), E> | ||||||
| @ -87,7 +88,7 @@ pub fn document(input: &str) -> Res<&str, Vec<(Vec<TextElement>, &str)>> { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn paragraph<'s, 'r>( | pub fn paragraph<'s, 'r>( | ||||||
|     context: &'r OrgModeContextTree<'r>, |     context: &'r OrgModeContextNode<'r>, | ||||||
|     i: &'s str, |     i: &'s str, | ||||||
| ) -> Res<&'s str, (Vec<TextElement<'s>>, &'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
 | ||||||
| @ -100,10 +101,10 @@ pub fn paragraph<'s, 'r>( | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn flat_text_element<'s, 'r>( | fn flat_text_element<'s, 'r>( | ||||||
|     context: &'r OrgModeContextTree<'r>, |     context: &'r OrgModeContextNode<'r>, | ||||||
|     i: &'s str, |     i: &'s str, | ||||||
| ) -> Res<&'s str, TextElement<'s>> { | ) -> Res<&'s str, TextElement<'s>> { | ||||||
|     not(|i| context.check_fail_matcher(i))(i)?; |     not(|i| context.match_fail(i))(i)?; | ||||||
| 
 | 
 | ||||||
|     let bold_matcher = parser_with_context!(flat_bold)(context); |     let bold_matcher = parser_with_context!(flat_bold)(context); | ||||||
|     let link_matcher = parser_with_context!(flat_link)(context); |     let link_matcher = parser_with_context!(flat_link)(context); | ||||||
| @ -124,7 +125,7 @@ fn recognize_bold_end(input: &str) -> Res<&str, &str> { | |||||||
|     recognize(bold_end)(input) |     recognize(bold_end)(input) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn flat_bold<'s, 'r>(context: &'r OrgModeContextTree<'r>, i: &'s str) -> Res<&'s str, Bold<'s>> { | fn flat_bold<'s, 'r>(context: &'r OrgModeContextNode<'r>, i: &'s str) -> Res<&'s str, Bold<'s>> { | ||||||
|     let new_context = context.with_additional_fail_matcher(&recognize_bold_end); |     let new_context = context.with_additional_fail_matcher(&recognize_bold_end); | ||||||
|     let text_element_parser = parser_with_context!(flat_text_element)(&new_context); |     let text_element_parser = parser_with_context!(flat_text_element)(&new_context); | ||||||
|     let (remaining, captured) = recognize(tuple(( |     let (remaining, captured) = recognize(tuple(( | ||||||
| @ -139,7 +140,7 @@ fn recognize_link_end(input: &str) -> Res<&str, &str> { | |||||||
|     recognize(link_end)(input) |     recognize(link_end)(input) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn flat_link<'s, 'r>(context: &'r OrgModeContextTree<'r>, i: &'s str) -> Res<&'s str, Link<'s>> { | fn flat_link<'s, 'r>(context: &'r OrgModeContextNode<'r>, i: &'s str) -> Res<&'s str, Link<'s>> { | ||||||
|     let new_context = context.with_additional_fail_matcher(&recognize_link_end); |     let new_context = context.with_additional_fail_matcher(&recognize_link_end); | ||||||
|     let text_element_parser = parser_with_context!(flat_text_element)(&new_context); |     let text_element_parser = parser_with_context!(flat_text_element)(&new_context); | ||||||
|     let (remaining, captured) = recognize(tuple(( |     let (remaining, captured) = recognize(tuple(( | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Tom Alexander
						Tom Alexander