use nom::combinator::eof; use super::list::List; use super::org_source::OrgSource; use super::DynContextMatcher; use super::Object; use crate::error::Res; use crate::parser::exiting::ExitClass; use crate::parser::list::ListType; // type Matcher = // dyn for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res, OrgSource<'s>>; // #[derive(Debug, Clone)] // pub struct ContextTree<'r, 's> { // tree: List>, // } // impl<'r, 's> ContextTree<'r, 's> { // pub fn new() -> Self { // ContextTree { tree: List::new() } // } // pub fn branch_from(trunk: &Rc>>) -> Self { // ContextTree { // tree: List::branch_from(trunk), // } // } // #[allow(dead_code)] // pub fn ptr_eq<'x, 'y>(&self, other: &ContextTree<'x, 'y>) -> bool { // self.tree.ptr_eq(&other.tree) // } // pub fn with_additional_node(&self, data: ContextElement<'r, 's>) -> ContextTree<'r, 's> { // let new_list = self.tree.push_front(data); // ContextTree { tree: new_list } // } // pub fn iter(&self) -> impl Iterator>>> { // self.tree.iter() // } // #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] // pub fn check_exit_matcher( // &'r self, // i: OrgSource<'s>, // ) -> IResult, OrgSource<'s>, CustomError>> { // // Special check for EOF. We don't just make this a document-level exit matcher since the IgnoreParent ChainBehavior could cause early exit matchers to not run. // let at_end_of_file = eof(i); // if at_end_of_file.is_ok() { // return at_end_of_file; // } // let mut current_class_filter = ExitClass::Gamma; // for current_node in self.iter() { // let context_element = current_node.get_data(); // match context_element { // ContextElement::ExitMatcherNode(exit_matcher) => { // if exit_matcher.class as u32 <= current_class_filter as u32 { // current_class_filter = exit_matcher.class; // let local_context = ContextTree::branch_from(current_node); // let local_result = (exit_matcher.exit_matcher)(&local_context, i); // if local_result.is_ok() { // return local_result; // } // } // } // _ => {} // }; // } // // TODO: Make this a specific error instead of just a generic MyError // return Err(nom::Err::Error(CustomError::MyError(MyError( // "NoExit".into(), // )))); // } // /// Indicates if elements should consume the whitespace after them. // /// // /// Defaults to true. // pub fn should_consume_trailing_whitespace(&self) -> bool { // self._should_consume_trailing_whitespace().unwrap_or(true) // } // fn _should_consume_trailing_whitespace(&self) -> Option { // for current_node in self.iter() { // let context_element = current_node.get_data(); // match context_element { // ContextElement::ConsumeTrailingWhitespace(should) => { // return Some(*should); // } // _ => {} // } // } // None // } // } #[derive(Debug)] pub enum ContextElement<'r, 's> { /// Stores a parser that indicates that children should exit upon matching an exit matcher. ExitMatcherNode(ExitMatcherNode<'r>), /// Stores the name of the current element to prevent directly nesting elements of the same type. Context(&'r str), /// Indicates if elements should consume the whitespace after them. ConsumeTrailingWhitespace(bool), /// The contents of a radio target. /// /// If any are found, this will force a 2nd parse through the /// org-mode document since text needs to be re-parsed to look for /// radio links matching the contents of radio targets. RadioTarget(Vec<&'r Vec>>), } pub struct ExitMatcherNode<'r> { // TODO: Should this be "&'r DynContextMatcher<'c>" ? pub exit_matcher: &'r DynContextMatcher<'r>, pub class: ExitClass, } impl<'r> std::fmt::Debug for ExitMatcherNode<'r> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut formatter = f.debug_struct("ExitMatcherNode"); formatter.field("class", &self.class.to_string()); formatter.finish() } } #[derive(Debug)] pub struct GlobalSettings<'s> { placeholder: Option<&'s str>, } impl<'s> GlobalSettings<'s> { pub fn new() -> Self { GlobalSettings { placeholder: None } } } impl<'s> Default for GlobalSettings<'s> { fn default() -> Self { GlobalSettings::new() } } #[derive(Debug)] pub struct Context<'r, 's> { global_settings: &'s GlobalSettings<'s>, tree: List<'r, ContextElement<'r, 's>>, } impl<'r, 's> Context<'r, 's> { pub fn new( global_settings: &'s GlobalSettings<'s>, tree: List<'r, ContextElement<'r, 's>>, ) -> Self { Self { global_settings, tree, } } pub fn document_context(global_settings: &'s GlobalSettings<'s>) -> Self { Context::new( global_settings, List::new(ContextElement::ExitMatcherNode(ExitMatcherNode { exit_matcher: &document_end, class: ExitClass::Document, })), ) } pub fn push(&self, data: ContextElement<'r, 's>) -> Self { let new_tree = self.tree.push(data); Self { global_settings: self.global_settings, tree: new_tree, } } } impl<'r, 's> Default for Context<'r, 's> { fn default() -> Self { Context::new( GlobalSettings::default(), List::new(ContextElement::ExitMatcherNode(ExitMatcherNode { exit_matcher: &document_end, class: ExitClass::Document, })), ) } } #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] fn document_end<'r, 's>( _context: Context<'r, 's>, input: OrgSource<'s>, ) -> Res, OrgSource<'s>> { eof(input) }