use nom::branch::alt; use nom::combinator::map; use nom::combinator::opt; use nom::combinator::peek; use nom::multi::many0; use nom::sequence::tuple; #[cfg(feature = "tracing")] use tracing::span; use super::babel_call::babel_call; use super::clock::clock; use super::comment::comment; use super::comment::detect_comment; use super::diary_sexp::detect_diary_sexp; use super::diary_sexp::diary_sexp; use super::drawer::drawer; use super::dynamic_block::dynamic_block; use super::fixed_width_area::detect_fixed_width_area; use super::fixed_width_area::fixed_width_area; use super::footnote_definition::detect_footnote_definition; use super::footnote_definition::footnote_definition; use super::greater_block::greater_block; use super::horizontal_rule::horizontal_rule; use super::keyword::affiliated_keyword; use super::keyword::keyword; use super::latex_environment::latex_environment; use super::lesser_block::comment_block; use super::lesser_block::example_block; use super::lesser_block::export_block; use super::lesser_block::src_block; use super::lesser_block::verse_block; use super::org_source::OrgSource; use super::paragraph::paragraph; use super::plain_list::detect_plain_list; use super::plain_list::plain_list; use super::table::detect_table; use crate::context::parser_with_context; use crate::context::RefContext; use crate::error::CustomError; use crate::error::MyError; use crate::error::Res; use crate::parser::table::org_mode_table; use crate::types::Element; pub(crate) const fn element( can_be_paragraph: bool, ) -> impl for<'b, 'g, 'r, 's> Fn( RefContext<'b, 'g, 'r, 's>, OrgSource<'s>, ) -> Res, Element<'s>> { move |context, input: OrgSource<'_>| _element(context, input, can_be_paragraph) } #[cfg_attr( feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) )] fn _element<'b, 'g, 'r, 's>( context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, can_be_paragraph: bool, ) -> Res, Element<'s>> { let (post_affiliated_keywords_input, affiliated_keywords) = many0(affiliated_keyword)(input)?; let plain_list_matcher = parser_with_context!(plain_list)(context); let greater_block_matcher = parser_with_context!(greater_block)(context); let dynamic_block_matcher = parser_with_context!(dynamic_block)(context); let footnote_definition_matcher = parser_with_context!(footnote_definition)(context); let comment_matcher = parser_with_context!(comment)(context); let drawer_matcher = parser_with_context!(drawer)(context); let table_matcher = parser_with_context!(org_mode_table)(context); let verse_block_matcher = parser_with_context!(verse_block)(context); let comment_block_matcher = parser_with_context!(comment_block)(context); let example_block_matcher = parser_with_context!(example_block)(context); let export_block_matcher = parser_with_context!(export_block)(context); let src_block_matcher = parser_with_context!(src_block)(context); let clock_matcher = parser_with_context!(clock)(context); let diary_sexp_matcher = parser_with_context!(diary_sexp)(context); let fixed_width_area_matcher = parser_with_context!(fixed_width_area)(context); let horizontal_rule_matcher = parser_with_context!(horizontal_rule)(context); let keyword_matcher = parser_with_context!(keyword)(context); let babel_keyword_matcher = parser_with_context!(babel_call)(context); let paragraph_matcher = parser_with_context!(paragraph)(context); let latex_environment_matcher = parser_with_context!(latex_environment)(context); let (mut remaining, mut maybe_element) = { #[cfg(feature = "tracing")] let span = span!(tracing::Level::DEBUG, "Main element block"); #[cfg(feature = "tracing")] let _enter = span.enter(); opt(alt(( map(plain_list_matcher, Element::PlainList), greater_block_matcher, map(dynamic_block_matcher, Element::DynamicBlock), map(footnote_definition_matcher, Element::FootnoteDefinition), map(comment_matcher, Element::Comment), map(drawer_matcher, Element::Drawer), map(table_matcher, Element::Table), map(verse_block_matcher, Element::VerseBlock), map(comment_block_matcher, Element::CommentBlock), map(example_block_matcher, Element::ExampleBlock), map(export_block_matcher, Element::ExportBlock), map(src_block_matcher, Element::SrcBlock), map(clock_matcher, Element::Clock), map(diary_sexp_matcher, Element::DiarySexp), map(fixed_width_area_matcher, Element::FixedWidthArea), map(horizontal_rule_matcher, Element::HorizontalRule), map(latex_environment_matcher, Element::LatexEnvironment), map(babel_keyword_matcher, Element::BabelCall), map(keyword_matcher, Element::Keyword), )))(input)? }; if maybe_element.is_none() && can_be_paragraph { #[cfg(feature = "tracing")] let span = span!(tracing::Level::DEBUG, "Paragraph with affiliated keyword."); #[cfg(feature = "tracing")] let _enter = span.enter(); let (remain, paragraph_with_affiliated_keyword) = opt(map( tuple(( peek(affiliated_keyword), map(paragraph_matcher, Element::Paragraph), )), |(_, paragraph)| paragraph, ))(remaining)?; if paragraph_with_affiliated_keyword.is_some() { remaining = remain; maybe_element = paragraph_with_affiliated_keyword; } } if maybe_element.is_none() && can_be_paragraph { #[cfg(feature = "tracing")] let span = span!( tracing::Level::DEBUG, "Paragraph without affiliated keyword." ); #[cfg(feature = "tracing")] let _enter = span.enter(); let (remain, paragraph_without_affiliated_keyword) = map(paragraph_matcher, Element::Paragraph)(remaining)?; remaining = remain; maybe_element = Some(paragraph_without_affiliated_keyword); } if maybe_element.is_none() { return Err(nom::Err::Error(CustomError::MyError(MyError( "No element.", )))); } let element = maybe_element.expect("The above if-statement ensures this is Some()."); Ok((remaining, element)) } pub(crate) const fn detect_element( can_be_paragraph: bool, ) -> impl for<'b, 'g, 'r, 's> Fn(RefContext<'b, 'g, 'r, 's>, OrgSource<'s>) -> Res, ()> { move |context, input: OrgSource<'_>| _detect_element(context, input, can_be_paragraph) } #[cfg_attr( feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) )] fn _detect_element<'b, 'g, 'r, 's>( context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, can_be_paragraph: bool, ) -> Res, ()> { if alt(( parser_with_context!(detect_plain_list)(context), detect_footnote_definition, detect_diary_sexp, detect_comment, detect_fixed_width_area, detect_table, ))(input) .is_ok() { return Ok((input, ())); } if _element(context, input, can_be_paragraph).is_ok() { return Ok((input, ())); } return Err(nom::Err::Error(CustomError::MyError(MyError( "No element detected.".into(), )))); }