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 type OrgModeContextTree<'r> = ContextTree<'r, dyn OrgModeContext<'r>>; pub trait OrgModeContext<'r> { fn get_fail_matcher(&'r self) -> Cow>; } pub 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>, } pub struct ContextTree<'r, T: 'r + ?Sized> { // Not using Link so the ContextTree can own this node head: Option>, } 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> { Cow::Borrowed(&self.fail_matcher) } } impl<'r> OrgModeContext<'r> for PreviousElementNode<'r> { fn get_fail_matcher(&'r self) -> Cow> { Cow::Owned(ChainBehavior::AndParent(None)) } } impl<'r> FailMatcherNode<'r> { pub fn additional(fail_matcher: &'r Matcher) -> Self { FailMatcherNode { fail_matcher: ChainBehavior::AndParent(Some(fail_matcher)), } } } 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") } }