2023-09-02 18:40:01 -04:00
use nom ::combinator ::eof ;
2023-09-02 19:28:33 -04:00
use super ::exiting ::ExitClass ;
2023-09-02 20:46:17 -04:00
use super ::global_settings ::GlobalSettings ;
2022-12-03 22:18:37 -05:00
use super ::list ::List ;
2023-09-02 18:19:52 -04:00
use super ::DynContextMatcher ;
2023-09-02 20:52:02 -04:00
use super ::RefContext ;
2023-09-02 18:40:01 -04:00
use crate ::error ::Res ;
2023-09-02 19:28:33 -04:00
use crate ::parser ::OrgSource ;
use crate ::types ::Object ;
2023-09-02 18:19:52 -04:00
// type Matcher =
// dyn for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>>;
// #[derive(Debug, Clone)]
// pub struct ContextTree<'r, 's> {
// tree: List<ContextElement<'r, 's>>,
// }
// impl<'r, 's> ContextTree<'r, 's> {
// pub fn new() -> Self {
// ContextTree { tree: List::new() }
// }
// pub fn branch_from(trunk: &Rc<Node<ContextElement<'r, 's>>>) -> 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<Item = &Rc<Node<ContextElement<'r, 's>>>> {
// 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>, OrgSource<'s>, CustomError<OrgSource<'s>>> {
// // 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<bool> {
// for current_node in self.iter() {
// let context_element = current_node.get_data();
// match context_element {
// ContextElement::ConsumeTrailingWhitespace(should) => {
// return Some(*should);
// }
// _ => {}
// }
// }
// None
// }
// }
2022-11-26 22:36:02 -05:00
2022-12-03 23:57:39 -05:00
#[ derive(Debug) ]
2022-12-10 23:49:02 -05:00
pub enum ContextElement < ' r , ' s > {
2023-04-10 10:36:16 -04:00
/// Stores a parser that indicates that children should exit upon matching an exit matcher.
2022-12-15 21:24:53 -05:00
ExitMatcherNode ( ExitMatcherNode < ' r > ) ,
2023-03-25 14:10:22 -04:00
2023-08-27 22:35:37 -04:00
/// Stores the name of the current element to prevent directly nesting elements of the same type.
Context ( & ' r str ) ,
2023-04-10 10:36:16 -04:00
/// Indicates if elements should consume the whitespace after them.
ConsumeTrailingWhitespace ( bool ) ,
2023-04-24 20:41:40 -04:00
/// 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.
2023-07-14 19:06:58 -04:00
RadioTarget ( Vec < & ' r Vec < Object < ' s > > > ) ,
2022-11-26 22:54:54 -05:00
}
2022-12-15 21:24:53 -05:00
pub struct ExitMatcherNode < ' r > {
2023-09-02 18:19:52 -04:00
// TODO: Should this be "&'r DynContextMatcher<'c>" ?
pub exit_matcher : & ' r DynContextMatcher < ' r > ,
2023-04-18 20:33:01 -04:00
pub class : ExitClass ,
2022-11-26 22:36:02 -05:00
}
2023-04-18 20:33:01 -04:00
impl < ' r > std ::fmt ::Debug for ExitMatcherNode < ' r > {
2022-11-25 18:23:51 -05:00
fn fmt ( & self , f : & mut std ::fmt ::Formatter < '_ > ) -> std ::fmt ::Result {
2023-04-18 20:33:01 -04:00
let mut formatter = f . debug_struct ( " ExitMatcherNode " ) ;
2023-04-18 20:44:58 -04:00
formatter . field ( " class " , & self . class . to_string ( ) ) ;
2022-12-03 22:18:37 -05:00
formatter . finish ( )
2022-11-26 22:54:54 -05:00
}
}
2023-09-02 18:19:52 -04:00
2023-09-02 18:21:43 -04:00
#[ derive(Debug) ]
2023-09-02 18:19:52 -04:00
pub struct Context < ' r , ' s > {
global_settings : & ' s GlobalSettings < ' s > ,
2023-09-02 22:44:21 -04:00
tree : List < ' r , & ' r ContextElement < ' r , ' s > > ,
2023-09-02 18:19:52 -04:00
}
impl < ' r , ' s > Context < ' r , ' s > {
pub fn new (
global_settings : & ' s GlobalSettings < ' s > ,
2023-09-02 22:44:21 -04:00
tree : List < ' r , & ' r ContextElement < ' r , ' s > > ,
2023-09-02 18:19:52 -04:00
) -> Self {
2023-09-02 18:40:01 -04:00
Self {
2023-09-02 18:19:52 -04:00
global_settings ,
tree ,
}
}
2023-09-02 22:44:21 -04:00
pub fn with_additional_node ( & ' r self , new_element : & ' r ContextElement < ' r , ' s > ) -> Self {
let new_tree = self . tree . push ( new_element ) ;
Self ::new ( self . global_settings , new_tree )
2023-09-02 18:19:52 -04:00
}
2023-09-02 20:46:17 -04:00
2023-09-02 22:44:21 -04:00
pub fn iter ( & ' r self ) -> super ::list ::Iter < ' r , & ' r ContextElement < ' r , ' s > > {
2023-09-02 20:46:17 -04:00
self . tree . iter ( )
}
2023-09-02 22:44:21 -04:00
pub fn iter_context ( & ' r self ) -> Iter < ' r , ' s > {
2023-09-02 20:46:17 -04:00
Iter {
next : self . tree . iter_list ( ) ,
global_settings : self . global_settings ,
}
}
2023-09-02 22:44:21 -04:00
pub fn get_parent ( & ' r self ) -> Option < Self > {
2023-09-02 20:46:17 -04:00
self . tree . get_parent ( ) . map ( | parent_tree | Self {
global_settings : self . global_settings ,
2023-09-02 22:44:21 -04:00
tree : parent_tree . clone ( ) ,
2023-09-02 20:46:17 -04:00
} )
}
2023-09-02 18:19:52 -04:00
}
2023-09-02 18:40:01 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-09-02 22:44:21 -04:00
fn document_end < ' b , ' r , ' s > (
_context : RefContext < ' b , ' r , ' s > ,
2023-09-02 18:40:01 -04:00
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
eof ( input )
}
2023-09-02 20:46:17 -04:00
pub struct Iter < ' r , ' s > {
global_settings : & ' s GlobalSettings < ' s > ,
2023-09-02 22:44:21 -04:00
next : super ::list ::IterList < ' r , & ' r ContextElement < ' r , ' s > > ,
2023-09-02 20:46:17 -04:00
}
impl < ' r , ' s > Iterator for Iter < ' r , ' s > {
type Item = Context < ' r , ' s > ;
fn next ( & mut self ) -> Option < Self ::Item > {
let next_tree = self . next . next ( ) ;
2023-09-02 22:44:21 -04:00
let ret =
next_tree . map ( | parent_tree | Context ::new ( self . global_settings , parent_tree . clone ( ) ) ) ;
2023-09-02 20:46:17 -04:00
ret
}
}
impl < ' r , ' s > ContextElement < ' r , ' s > {
pub fn document_context ( ) -> Self {
Self ::ExitMatcherNode ( ExitMatcherNode {
exit_matcher : & document_end ,
class : ExitClass ::Document ,
} )
}
}