use nom::branch::alt; use nom::combinator::map; use nom::multi::many0; use super::clock::clock; use super::comment::comment; use super::diary_sexp::diary_sexp; use super::drawer::drawer; use super::dynamic_block::dynamic_block; use super::fixed_width_area::fixed_width_area; 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::util::get_consumed; use super::util::maybe_consume_trailing_whitespace_if_not_exiting; 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; use crate::types::SetSource; pub const fn element( can_be_paragraph: bool, ) -> impl for<'b, 'r, 's> Fn(RefContext<'b, '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"))] fn _element<'r, 's>( context: RefContext<'_, 'r, 's>, input: OrgSource<'s>, can_be_paragraph: bool, ) -> Res, Element<'s>> { 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 affiliated_keyword_matcher = parser_with_context!(affiliated_keyword)(context); let paragraph_matcher = parser_with_context!(paragraph)(context); let latex_environment_matcher = parser_with_context!(latex_environment)(context); // TODO: Affiliated keywords cannot be on comments, clocks, headings, inlinetasks, items, node properties, planning, property drawers, sections, and table rows let (remaining, mut affiliated_keywords) = many0(affiliated_keyword_matcher)(input)?; let (remaining, mut element) = match alt(( map(plain_list_matcher, Element::PlainList), map(greater_block_matcher, Element::GreaterBlock), 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(keyword_matcher, Element::Keyword), ))(remaining) { the_ok @ Ok(_) => the_ok, Err(_) => { if can_be_paragraph { match map(paragraph_matcher, Element::Paragraph)(remaining) { the_ok @ Ok(_) => the_ok, Err(_) => { affiliated_keywords.clear(); map(affiliated_keyword_matcher, Element::Keyword)(input) } } } else { affiliated_keywords.clear(); map(affiliated_keyword_matcher, Element::Keyword)(input) } } }?; let (remaining, _trailing_ws) = maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?; let source = get_consumed(input, remaining); element.set_source(source.into()); Ok((remaining, element)) } pub const fn detect_element( can_be_paragraph: bool, ) -> impl for<'b, 'r, 's> Fn(RefContext<'b, '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"))] fn _detect_element<'r, 's>( context: RefContext<'_, 'r, 's>, input: OrgSource<'s>, can_be_paragraph: bool, ) -> Res, ()> { if detect_plain_list(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(), )))); }