Implement check_exit_matcher.

This commit is contained in:
Tom Alexander 2023-09-03 00:05:47 -04:00
parent 8502a8830d
commit 15e8d1ab77
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
5 changed files with 191 additions and 73 deletions

View File

@ -1,10 +1,13 @@
use nom::combinator::eof; use nom::combinator::eof;
use nom::IResult;
use super::exiting::ExitClass; use super::exiting::ExitClass;
use super::global_settings::GlobalSettings; use super::global_settings::GlobalSettings;
use super::list::List; use super::list::List;
use super::DynContextMatcher; use super::DynContextMatcher;
use super::RefContext; use super::RefContext;
use crate::error::CustomError;
use crate::error::MyError;
use crate::error::Res; use crate::error::Res;
use crate::parser::OrgSource; use crate::parser::OrgSource;
use crate::types::Object; use crate::types::Object;
@ -169,6 +172,56 @@ impl<'r, 's> Context<'r, 's> {
tree: parent_tree.clone(), tree: parent_tree.clone(),
}) })
} }
pub fn get_data(&self) -> &ContextElement<'r, 's> {
self.tree.get_data()
}
#[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>>> {
let mut current_class_filter = ExitClass::Gamma;
for current_node in self.iter_context() {
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_result = (exit_matcher.exit_matcher)(&current_node, 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() {
match current_node {
ContextElement::ConsumeTrailingWhitespace(should) => {
return Some(*should);
}
_ => {}
}
}
None
}
} }
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]

View File

@ -17,8 +17,6 @@ use nom::multi::many_till;
use nom::multi::separated_list1; use nom::multi::separated_list1;
use nom::sequence::tuple; use nom::sequence::tuple;
use super::element::Element;
use super::object::Object;
use super::org_source::convert_error; use super::org_source::convert_error;
use super::org_source::OrgSource; use super::org_source::OrgSource;
use super::token::AllTokensIterator; use super::token::AllTokensIterator;
@ -26,6 +24,14 @@ use super::token::Token;
use super::util::exit_matcher_parser; use super::util::exit_matcher_parser;
use super::util::get_consumed; use super::util::get_consumed;
use super::util::start_of_line; use super::util::start_of_line;
use crate::context::parser_with_context;
use crate::context::Context;
use crate::context::ContextElement;
use crate::context::ExitClass;
use crate::context::ExitMatcherNode;
use crate::context::GlobalSettings;
use crate::context::List;
use crate::context::RefContext;
use crate::error::Res; use crate::error::Res;
use crate::parser::comment::comment; use crate::parser::comment::comment;
use crate::parser::element_parser::element; use crate::parser::element_parser::element;
@ -34,11 +40,19 @@ use crate::parser::planning::planning;
use crate::parser::property_drawer::property_drawer; use crate::parser::property_drawer::property_drawer;
use crate::parser::util::blank_line; use crate::parser::util::blank_line;
use crate::parser::util::maybe_consume_trailing_whitespace_if_not_exiting; use crate::parser::util::maybe_consume_trailing_whitespace_if_not_exiting;
use crate::types::Document;
use crate::types::DocumentElement;
use crate::types::Element;
use crate::types::Heading;
use crate::types::Object;
use crate::types::Section;
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
#[allow(dead_code)] #[allow(dead_code)]
pub fn document(input: &str) -> Res<&str, Document> { pub fn document(input: &str) -> Res<&str, Document> {
let initial_context = Context::default(); let global_settings = GlobalSettings::default();
let initial_context = ContextElement::document_context();
let initial_context = Context::new(&global_settings, List::new(&initial_context));
let wrapped_input = OrgSource::new(input); let wrapped_input = OrgSource::new(input);
let (remaining, document) = _document(&initial_context, wrapped_input) let (remaining, document) = _document(&initial_context, wrapped_input)
.map(|(rem, out)| (Into::<&str>::into(rem), out)) .map(|(rem, out)| (Into::<&str>::into(rem), out))
@ -58,9 +72,9 @@ pub fn document(input: &str) -> Res<&str, Document> {
.map(|rt| &rt.children) .map(|rt| &rt.children)
.collect(); .collect();
if !all_radio_targets.is_empty() { if !all_radio_targets.is_empty() {
let initial_context = initial_context let parser_context = ContextElement::RadioTarget(all_radio_targets);
.with_additional_node(ContextElement::RadioTarget(all_radio_targets)); let parser_context = initial_context.with_additional_node(&parser_context);
let (remaining, document) = _document(&initial_context, wrapped_input) let (remaining, document) = _document(&parser_context, wrapped_input)
.map(|(rem, out)| (Into::<&str>::into(rem), out)) .map(|(rem, out)| (Into::<&str>::into(rem), out))
.map_err(convert_error)?; .map_err(convert_error)?;
return Ok((remaining.into(), document)); return Ok((remaining.into(), document));
@ -96,15 +110,21 @@ fn zeroth_section<'r, 's>(
input: OrgSource<'s>, input: OrgSource<'s>,
) -> Res<OrgSource<'s>, Section<'s>> { ) -> Res<OrgSource<'s>, Section<'s>> {
// TODO: The zeroth section is specialized so it probably needs its own parser // TODO: The zeroth section is specialized so it probably needs its own parser
let parser_context = context let contexts = [
.with_additional_node(ContextElement::ConsumeTrailingWhitespace(true)) ContextElement::ConsumeTrailingWhitespace(true),
.with_additional_node(ContextElement::Context("section")) ContextElement::Context("section"),
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { ContextElement::ExitMatcherNode(ExitMatcherNode {
class: ExitClass::Document, class: ExitClass::Document,
exit_matcher: &section_end, exit_matcher: &section_end,
})); }),
];
let parser_context = context
.with_additional_node(&contexts[0])
.with_additional_node(&contexts[1])
.with_additional_node(&contexts[2]);
let without_consuming_whitespace_context = ContextElement::ConsumeTrailingWhitespace(false);
let without_consuming_whitespace_context = let without_consuming_whitespace_context =
parser_context.with_additional_node(ContextElement::ConsumeTrailingWhitespace(false)); parser_context.with_additional_node(&without_consuming_whitespace_context);
let element_matcher = parser_with_context!(element(true))(&parser_context); let element_matcher = parser_with_context!(element(true))(&parser_context);
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context); let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
@ -150,13 +170,18 @@ fn section<'r, 's>(
mut input: OrgSource<'s>, mut input: OrgSource<'s>,
) -> Res<OrgSource<'s>, Section<'s>> { ) -> Res<OrgSource<'s>, Section<'s>> {
// TODO: The zeroth section is specialized so it probably needs its own parser // TODO: The zeroth section is specialized so it probably needs its own parser
let parser_context = context let contexts = [
.with_additional_node(ContextElement::ConsumeTrailingWhitespace(true)) ContextElement::ConsumeTrailingWhitespace(true),
.with_additional_node(ContextElement::Context("section")) ContextElement::Context("section"),
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { ContextElement::ExitMatcherNode(ExitMatcherNode {
class: ExitClass::Document, class: ExitClass::Document,
exit_matcher: &section_end, exit_matcher: &section_end,
})); }),
];
let parser_context = context
.with_additional_node(&contexts[0])
.with_additional_node(&contexts[1])
.with_additional_node(&contexts[2]);
let element_matcher = parser_with_context!(element(true))(&parser_context); let element_matcher = parser_with_context!(element(true))(&parser_context);
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context); let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
let (mut remaining, (planning_element, property_drawer_element)) = tuple(( let (mut remaining, (planning_element, property_drawer_element)) = tuple((
@ -204,8 +229,9 @@ fn section_end<'r, 's>(
const fn heading( const fn heading(
parent_stars: usize, parent_stars: usize,
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, Heading<'s>> { ) -> impl for<'b, 'r, 's> Fn(RefContext<'b, 'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, Heading<'s>>
move |context: Context, input: OrgSource<'_>| _heading(context, input, parent_stars) {
move |context, input: OrgSource<'_>| _heading(context, input, parent_stars)
} }
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
@ -270,11 +296,11 @@ fn headline<'r, 's>(
Vec<&'s str>, Vec<&'s str>,
), ),
> { > {
let parser_context = let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
class: ExitClass::Document, class: ExitClass::Document,
exit_matcher: &headline_title_end, exit_matcher: &headline_title_end,
})); });
let parser_context = context.with_additional_node(&parser_context);
let standard_set_object_matcher = parser_with_context!(standard_set_object)(&parser_context); let standard_set_object_matcher = parser_with_context!(standard_set_object)(&parser_context);
let ( let (

View File

@ -16,21 +16,26 @@ use nom::multi::many1;
use nom::multi::many_till; use nom::multi::many_till;
use nom::sequence::tuple; use nom::sequence::tuple;
use super::greater_element::PlainList; use super::element_parser::element;
use super::greater_element::PlainListItem; use super::object_parser::standard_set_object;
use super::org_source::OrgSource; use super::org_source::OrgSource;
use super::util::non_whitespace_character; use super::util::non_whitespace_character;
use super::Context; use crate::context::parser_with_context;
use super::Object; use crate::context::ContextElement;
use crate::context::ExitClass;
use crate::context::ExitMatcherNode;
use crate::context::RefContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::error::MyError; use crate::error::MyError;
use crate::error::Res; use crate::error::Res;
use crate::parser::element_parser::element;
use crate::parser::util::blank_line; use crate::parser::util::blank_line;
use crate::parser::util::exit_matcher_parser; use crate::parser::util::exit_matcher_parser;
use crate::parser::util::get_consumed; use crate::parser::util::get_consumed;
use crate::parser::util::maybe_consume_trailing_whitespace_if_not_exiting; use crate::parser::util::maybe_consume_trailing_whitespace_if_not_exiting;
use crate::parser::util::start_of_line; use crate::parser::util::start_of_line;
use crate::types::Object;
use crate::types::PlainList;
use crate::types::PlainListItem;
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
pub fn detect_plain_list<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, ()> { pub fn detect_plain_list<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, ()> {
@ -59,13 +64,19 @@ pub fn plain_list<'r, 's>(
context: RefContext<'_, 'r, 's>, context: RefContext<'_, 'r, 's>,
input: OrgSource<'s>, input: OrgSource<'s>,
) -> Res<OrgSource<'s>, PlainList<'s>> { ) -> Res<OrgSource<'s>, PlainList<'s>> {
let parser_context = context let contexts = [
.with_additional_node(ContextElement::Context("plain list")) ContextElement::Context("plain list"),
.with_additional_node(ContextElement::ConsumeTrailingWhitespace(true)) ContextElement::ConsumeTrailingWhitespace(true),
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { ContextElement::ExitMatcherNode(ExitMatcherNode {
class: ExitClass::Beta, class: ExitClass::Beta,
exit_matcher: &plain_list_end, exit_matcher: &plain_list_end,
})); }),
];
let parser_context = context
.with_additional_node(&contexts[0])
.with_additional_node(&contexts[1])
.with_additional_node(&contexts[2]);
// children stores tuple of (input string, parsed object) so we can re-parse the final item // children stores tuple of (input string, parsed object) so we can re-parse the final item
let mut children = Vec::new(); let mut children = Vec::new();
let mut first_item_indentation: Option<usize> = None; let mut first_item_indentation: Option<usize> = None;
@ -107,8 +118,8 @@ pub fn plain_list<'r, 's>(
)))); ))));
} }
}; };
let final_item_context = let final_item_context = ContextElement::ConsumeTrailingWhitespace(false);
parser_context.with_additional_node(ContextElement::ConsumeTrailingWhitespace(false)); let final_item_context = parser_context.with_additional_node(&final_item_context);
let (remaining, reparsed_final_item) = let (remaining, reparsed_final_item) =
parser_with_context!(plain_list_item)(&final_item_context)(final_child_start)?; parser_with_context!(plain_list_item)(&final_item_context)(final_child_start)?;
children.push((final_child_start, reparsed_final_item)); children.push((final_child_start, reparsed_final_item));
@ -164,12 +175,16 @@ pub fn plain_list_item<'r, 's>(
}; };
let (remaining, _ws) = item_tag_post_gap(context, remaining)?; let (remaining, _ws) = item_tag_post_gap(context, remaining)?;
let exit_matcher = plain_list_item_end(indent_level); let exit_matcher = plain_list_item_end(indent_level);
let parser_context = context let contexts = [
.with_additional_node(ContextElement::ConsumeTrailingWhitespace(true)) ContextElement::ConsumeTrailingWhitespace(true),
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { ContextElement::ExitMatcherNode(ExitMatcherNode {
class: ExitClass::Beta, class: ExitClass::Beta,
exit_matcher: &exit_matcher, exit_matcher: &exit_matcher,
})); }),
];
let parser_context = context
.with_additional_node(&contexts[0])
.with_additional_node(&contexts[1]);
let (mut remaining, (mut children, _exit_contents)) = many_till( let (mut remaining, (mut children, _exit_contents)) = many_till(
include_input(parser_with_context!(element(true))(&parser_context)), include_input(parser_with_context!(element(true))(&parser_context)),
@ -177,8 +192,8 @@ pub fn plain_list_item<'r, 's>(
)(remaining)?; )(remaining)?;
if !children.is_empty() && !context.should_consume_trailing_whitespace() { if !children.is_empty() && !context.should_consume_trailing_whitespace() {
let final_item_context = let final_item_context = ContextElement::ConsumeTrailingWhitespace(false);
parser_context.with_additional_node(ContextElement::ConsumeTrailingWhitespace(false)); let final_item_context = parser_context.with_additional_node(&final_item_context);
let (final_child_start, _original_final_child) = children let (final_child_start, _original_final_child) = children
.pop() .pop()
.expect("if-statement already checked that children was non-empty."); .expect("if-statement already checked that children was non-empty.");
@ -249,9 +264,10 @@ fn plain_list_end<'r, 's>(
const fn plain_list_item_end( const fn plain_list_item_end(
indent_level: usize, indent_level: usize,
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> { ) -> impl for<'b, 'r, 's> Fn(RefContext<'b, 'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>>
{
let line_indented_lte_matcher = line_indented_lte(indent_level); let line_indented_lte_matcher = line_indented_lte(indent_level);
move |context: Context, input: OrgSource<'_>| { move |context, input: OrgSource<'_>| {
_plain_list_item_end(context, input, &line_indented_lte_matcher) _plain_list_item_end(context, input, &line_indented_lte_matcher)
} }
} }
@ -263,8 +279,8 @@ const fn plain_list_item_end(
fn _plain_list_item_end<'r, 's>( fn _plain_list_item_end<'r, 's>(
context: RefContext<'_, 'r, 's>, context: RefContext<'_, 'r, 's>,
input: OrgSource<'s>, input: OrgSource<'s>,
line_indented_lte_matcher: impl for<'rr, 'ss> Fn( line_indented_lte_matcher: impl for<'bb, 'rr, 'ss> Fn(
Context<'rr, 'ss>, RefContext<'bb, 'rr, 'ss>,
OrgSource<'ss>, OrgSource<'ss>,
) -> Res<OrgSource<'ss>, OrgSource<'ss>>, ) -> Res<OrgSource<'ss>, OrgSource<'ss>>,
) -> Res<OrgSource<'s>, OrgSource<'s>> { ) -> Res<OrgSource<'s>, OrgSource<'s>> {
@ -277,8 +293,9 @@ fn _plain_list_item_end<'r, 's>(
const fn line_indented_lte( const fn line_indented_lte(
indent_level: usize, indent_level: usize,
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> { ) -> impl for<'b, 'r, 's> Fn(RefContext<'b, 'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>>
move |context: Context, input: OrgSource<'_>| _line_indented_lte(context, input, indent_level) {
move |context, input: OrgSource<'_>| _line_indented_lte(context, input, indent_level)
} }
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
@ -301,11 +318,11 @@ fn item_tag<'r, 's>(
context: RefContext<'_, 'r, 's>, context: RefContext<'_, 'r, 's>,
input: OrgSource<'s>, input: OrgSource<'s>,
) -> Res<OrgSource<'s>, Vec<Object<'s>>> { ) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
let parser_context = let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
class: ExitClass::Gamma, class: ExitClass::Gamma,
exit_matcher: &item_tag_end, exit_matcher: &item_tag_end,
})); });
let parser_context = context.with_additional_node(&parser_context);
let (remaining, (children, _exit_contents)) = verify( let (remaining, (children, _exit_contents)) = verify(
many_till( many_till(
// TODO: Should this be using a different set like the minimal set? // TODO: Should this be using a different set like the minimal set?
@ -353,14 +370,16 @@ fn item_tag_post_gap<'r, 's>(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::parser::parser_context::ContextTree; use crate::context::Context;
use crate::parser::parser_with_context::parser_with_context; use crate::context::GlobalSettings;
use crate::parser::Source; use crate::context::List;
#[test] #[test]
fn plain_list_item_empty() { fn plain_list_item_empty() {
let input = OrgSource::new("1."); let input = OrgSource::new("1.");
let initial_context: ContextTree<'_, '_> = ContextTree::new(); let global_settings = GlobalSettings::default();
let initial_context = ContextElement::document_context();
let initial_context = Context::new(&global_settings, List::new(&initial_context));
let plain_list_item_matcher = parser_with_context!(plain_list_item)(&initial_context); let plain_list_item_matcher = parser_with_context!(plain_list_item)(&initial_context);
let (remaining, result) = plain_list_item_matcher(input).unwrap(); let (remaining, result) = plain_list_item_matcher(input).unwrap();
assert_eq!(Into::<&str>::into(remaining), ""); assert_eq!(Into::<&str>::into(remaining), "");
@ -370,7 +389,9 @@ mod tests {
#[test] #[test]
fn plain_list_item_simple() { fn plain_list_item_simple() {
let input = OrgSource::new("1. foo"); let input = OrgSource::new("1. foo");
let initial_context: ContextTree<'_, '_> = ContextTree::new(); let global_settings = GlobalSettings::default();
let initial_context = ContextElement::document_context();
let initial_context = Context::new(&global_settings, List::new(&initial_context));
let plain_list_item_matcher = parser_with_context!(plain_list_item)(&initial_context); let plain_list_item_matcher = parser_with_context!(plain_list_item)(&initial_context);
let (remaining, result) = plain_list_item_matcher(input).unwrap(); let (remaining, result) = plain_list_item_matcher(input).unwrap();
assert_eq!(Into::<&str>::into(remaining), ""); assert_eq!(Into::<&str>::into(remaining), "");
@ -380,7 +401,9 @@ mod tests {
#[test] #[test]
fn plain_list_empty() { fn plain_list_empty() {
let input = OrgSource::new("1."); let input = OrgSource::new("1.");
let initial_context: ContextTree<'_, '_> = ContextTree::new(); let global_settings = GlobalSettings::default();
let initial_context = ContextElement::document_context();
let initial_context = Context::new(&global_settings, List::new(&initial_context));
let plain_list_matcher = parser_with_context!(plain_list)(&initial_context); let plain_list_matcher = parser_with_context!(plain_list)(&initial_context);
let (remaining, result) = plain_list_matcher(input).unwrap(); let (remaining, result) = plain_list_matcher(input).unwrap();
assert_eq!(Into::<&str>::into(remaining), ""); assert_eq!(Into::<&str>::into(remaining), "");
@ -390,7 +413,9 @@ mod tests {
#[test] #[test]
fn plain_list_simple() { fn plain_list_simple() {
let input = OrgSource::new("1. foo"); let input = OrgSource::new("1. foo");
let initial_context: ContextTree<'_, '_> = ContextTree::new(); let global_settings = GlobalSettings::default();
let initial_context = ContextElement::document_context();
let initial_context = Context::new(&global_settings, List::new(&initial_context));
let plain_list_matcher = parser_with_context!(plain_list)(&initial_context); let plain_list_matcher = parser_with_context!(plain_list)(&initial_context);
let (remaining, result) = plain_list_matcher(input).unwrap(); let (remaining, result) = plain_list_matcher(input).unwrap();
assert_eq!(Into::<&str>::into(remaining), ""); assert_eq!(Into::<&str>::into(remaining), "");
@ -401,7 +426,9 @@ mod tests {
fn plain_list_cant_start_line_with_asterisk() { fn plain_list_cant_start_line_with_asterisk() {
// Plain lists with an asterisk bullet must be indented or else they would be a headline // Plain lists with an asterisk bullet must be indented or else they would be a headline
let input = OrgSource::new("* foo"); let input = OrgSource::new("* foo");
let initial_context: ContextTree<'_, '_> = ContextTree::new(); let global_settings = GlobalSettings::default();
let initial_context = ContextElement::document_context();
let initial_context = Context::new(&global_settings, List::new(&initial_context));
let plain_list_matcher = parser_with_context!(plain_list)(&initial_context); let plain_list_matcher = parser_with_context!(plain_list)(&initial_context);
let result = plain_list_matcher(input); let result = plain_list_matcher(input);
assert!(result.is_err()); assert!(result.is_err());
@ -411,7 +438,9 @@ mod tests {
fn indented_can_start_line_with_asterisk() { fn indented_can_start_line_with_asterisk() {
// Plain lists with an asterisk bullet must be indented or else they would be a headline // Plain lists with an asterisk bullet must be indented or else they would be a headline
let input = OrgSource::new(" * foo"); let input = OrgSource::new(" * foo");
let initial_context: ContextTree<'_, '_> = ContextTree::new(); let global_settings = GlobalSettings::default();
let initial_context = ContextElement::document_context();
let initial_context = Context::new(&global_settings, List::new(&initial_context));
let plain_list_matcher = parser_with_context!(plain_list)(&initial_context); let plain_list_matcher = parser_with_context!(plain_list)(&initial_context);
let result = plain_list_matcher(input); let result = plain_list_matcher(input);
assert!(result.is_ok()); assert!(result.is_ok());
@ -429,7 +458,9 @@ mod tests {
ipsum ipsum
"#, "#,
); );
let initial_context: ContextTree<'_, '_> = ContextTree::new(); let global_settings = GlobalSettings::default();
let initial_context = ContextElement::document_context();
let initial_context = Context::new(&global_settings, List::new(&initial_context));
let plain_list_matcher = parser_with_context!(element(true))(&initial_context); let plain_list_matcher = parser_with_context!(element(true))(&initial_context);
let (remaining, result) = let (remaining, result) =
plain_list_matcher(input).expect("Should parse the plain list successfully."); plain_list_matcher(input).expect("Should parse the plain list successfully.");
@ -455,7 +486,9 @@ mod tests {
baz"#, baz"#,
); );
let initial_context: ContextTree<'_, '_> = ContextTree::new(); let global_settings = GlobalSettings::default();
let initial_context = ContextElement::document_context();
let initial_context = Context::new(&global_settings, List::new(&initial_context));
let plain_list_matcher = parser_with_context!(element(true))(&initial_context); let plain_list_matcher = parser_with_context!(element(true))(&initial_context);
let (remaining, result) = let (remaining, result) =
plain_list_matcher(input).expect("Should parse the plain list successfully."); plain_list_matcher(input).expect("Should parse the plain list successfully.");
@ -486,7 +519,9 @@ baz"#,
dolar"#, dolar"#,
); );
let initial_context: ContextTree<'_, '_> = ContextTree::new(); let global_settings = GlobalSettings::default();
let initial_context = ContextElement::document_context();
let initial_context = Context::new(&global_settings, List::new(&initial_context));
let plain_list_matcher = parser_with_context!(element(true))(&initial_context); let plain_list_matcher = parser_with_context!(element(true))(&initial_context);
let (remaining, result) = let (remaining, result) =
plain_list_matcher(input).expect("Should parse the plain list successfully."); plain_list_matcher(input).expect("Should parse the plain list successfully.");

View File

@ -7,13 +7,18 @@ use nom::combinator::verify;
use nom::multi::many_till; use nom::multi::many_till;
use super::org_source::OrgSource; use super::org_source::OrgSource;
use super::util::exit_matcher_parser;
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting; use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
use super::Context; use crate::context::parser_with_context;
use crate::context::ContextElement;
use crate::context::ExitClass;
use crate::context::ExitMatcherNode;
use crate::context::RefContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::error::MyError; use crate::error::MyError;
use crate::error::Res; use crate::error::Res;
use crate::parser::util::get_consumed; use crate::parser::util::get_consumed;
use crate::parser::Target; use crate::types::Target;
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
pub fn target<'r, 's>( pub fn target<'r, 's>(
@ -25,11 +30,11 @@ pub fn target<'r, 's>(
!c.is_whitespace() && !"<>\n".contains(*c) !c.is_whitespace() && !"<>\n".contains(*c)
}))(remaining)?; }))(remaining)?;
let parser_context = let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
class: ExitClass::Beta, class: ExitClass::Beta,
exit_matcher: &target_end, exit_matcher: &target_end,
})); });
let parser_context = context.with_additional_node(&parser_context);
let (remaining, _body) = recognize(many_till( let (remaining, _body) = recognize(many_till(
anychar, anychar,
parser_with_context!(exit_matcher_parser)(&parser_context), parser_with_context!(exit_matcher_parser)(&parser_context),

View File

@ -20,7 +20,6 @@ use super::org_source::OrgSource;
use super::radio_link::RematchObject; use super::radio_link::RematchObject;
use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting; use super::util::maybe_consume_object_trailing_whitespace_if_not_exiting;
use crate::context::parser_with_context; use crate::context::parser_with_context;
use crate::context::Context;
use crate::context::ContextElement; use crate::context::ContextElement;
use crate::context::ExitClass; use crate::context::ExitClass;
use crate::context::ExitMatcherNode; use crate::context::ExitMatcherNode;