|
|
|
|
@@ -1,4 +1,5 @@
|
|
|
|
|
use nom::branch::alt;
|
|
|
|
|
use nom::bytes::complete::is_a;
|
|
|
|
|
use nom::bytes::complete::tag;
|
|
|
|
|
use nom::character::complete::anychar;
|
|
|
|
|
use nom::character::complete::space0;
|
|
|
|
|
@@ -11,7 +12,6 @@ use nom::combinator::recognize;
|
|
|
|
|
use nom::combinator::verify;
|
|
|
|
|
use nom::multi::many0;
|
|
|
|
|
use nom::multi::many1;
|
|
|
|
|
use nom::multi::many1_count;
|
|
|
|
|
use nom::multi::separated_list1;
|
|
|
|
|
use nom::sequence::tuple;
|
|
|
|
|
|
|
|
|
|
@@ -39,27 +39,27 @@ use crate::types::PriorityCookie;
|
|
|
|
|
use crate::types::TodoKeywordType;
|
|
|
|
|
|
|
|
|
|
pub(crate) const fn heading(
|
|
|
|
|
parent_stars: usize,
|
|
|
|
|
parent_level: usize,
|
|
|
|
|
) -> impl for<'b, 'g, 'r, 's> Fn(
|
|
|
|
|
RefContext<'b, 'g, 'r, 's>,
|
|
|
|
|
OrgSource<'s>,
|
|
|
|
|
) -> Res<OrgSource<'s>, Heading<'s>> {
|
|
|
|
|
move |context, input: OrgSource<'_>| _heading(context, input, parent_stars)
|
|
|
|
|
move |context, input: OrgSource<'_>| _heading(context, input, parent_level)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
|
|
|
|
fn _heading<'b, 'g, 'r, 's>(
|
|
|
|
|
context: RefContext<'b, 'g, 'r, 's>,
|
|
|
|
|
input: OrgSource<'s>,
|
|
|
|
|
parent_stars: usize,
|
|
|
|
|
parent_level: usize,
|
|
|
|
|
) -> Res<OrgSource<'s>, Heading<'s>> {
|
|
|
|
|
not(|i| context.check_exit_matcher(i))(input)?;
|
|
|
|
|
let (
|
|
|
|
|
remaining,
|
|
|
|
|
(star_count, maybe_todo_keyword, maybe_priority, maybe_comment, title, heading_tags),
|
|
|
|
|
) = headline(context, input, parent_stars)?;
|
|
|
|
|
(headline_level, maybe_todo_keyword, maybe_priority, maybe_comment, title, heading_tags),
|
|
|
|
|
) = headline(context, input, parent_level)?;
|
|
|
|
|
let section_matcher = parser_with_context!(section)(context);
|
|
|
|
|
let heading_matcher = parser_with_context!(heading(star_count))(context);
|
|
|
|
|
let heading_matcher = parser_with_context!(heading(headline_level))(context);
|
|
|
|
|
let (remaining, maybe_section) =
|
|
|
|
|
opt(map(section_matcher, DocumentElement::Section))(remaining)?;
|
|
|
|
|
let (remaining, _ws) = opt(tuple((start_of_line, many0(blank_line))))(remaining)?;
|
|
|
|
|
@@ -82,7 +82,7 @@ fn _heading<'b, 'g, 'r, 's>(
|
|
|
|
|
remaining,
|
|
|
|
|
Heading {
|
|
|
|
|
source: source.into(),
|
|
|
|
|
stars: star_count,
|
|
|
|
|
level: headline_level,
|
|
|
|
|
todo_keyword: maybe_todo_keyword.map(|(todo_keyword_type, todo_keyword)| {
|
|
|
|
|
(todo_keyword_type, Into::<&str>::into(todo_keyword))
|
|
|
|
|
}),
|
|
|
|
|
@@ -106,7 +106,7 @@ pub(crate) fn detect_headline<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, ()
|
|
|
|
|
fn headline<'b, 'g, 'r, 's>(
|
|
|
|
|
context: RefContext<'b, 'g, 'r, 's>,
|
|
|
|
|
input: OrgSource<'s>,
|
|
|
|
|
parent_stars: usize,
|
|
|
|
|
parent_level: usize,
|
|
|
|
|
) -> Res<
|
|
|
|
|
OrgSource<'s>,
|
|
|
|
|
(
|
|
|
|
|
@@ -124,11 +124,12 @@ fn headline<'b, 'g, 'r, 's>(
|
|
|
|
|
});
|
|
|
|
|
let parser_context = context.with_additional_node(&parser_context);
|
|
|
|
|
|
|
|
|
|
let (remaining, (_, star_count, _)) = tuple((
|
|
|
|
|
let (remaining, (_, (star_count, _), _)) = tuple((
|
|
|
|
|
start_of_line,
|
|
|
|
|
verify(many1_count(tag("*")), |star_count| {
|
|
|
|
|
*star_count > parent_stars
|
|
|
|
|
}),
|
|
|
|
|
verify(
|
|
|
|
|
parser_with_context!(headline_level)(&parser_context),
|
|
|
|
|
|(level, _)| *level > parent_level,
|
|
|
|
|
),
|
|
|
|
|
peek(org_space),
|
|
|
|
|
))(input)?;
|
|
|
|
|
|
|
|
|
|
@@ -255,3 +256,23 @@ fn priority_cookie<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, PriorityCooki
|
|
|
|
|
})?;
|
|
|
|
|
Ok((remaining, cookie))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
|
|
|
|
fn headline_level<'b, 'g, 'r, 's>(
|
|
|
|
|
context: RefContext<'b, 'g, 'r, 's>,
|
|
|
|
|
input: OrgSource<'s>,
|
|
|
|
|
) -> Res<OrgSource<'s>, (usize, OrgSource<'s>)> {
|
|
|
|
|
let (remaining, stars) = is_a("*")(input)?;
|
|
|
|
|
let count = stars.len();
|
|
|
|
|
let level = match context.get_global_settings().odd_levels_only {
|
|
|
|
|
crate::context::HeadlineLevelFilter::Odd => {
|
|
|
|
|
if count % 2 == 0 {
|
|
|
|
|
(count + 2) / 2
|
|
|
|
|
} else {
|
|
|
|
|
(count + 1) / 2
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
crate::context::HeadlineLevelFilter::OddEven => count,
|
|
|
|
|
};
|
|
|
|
|
Ok((remaining, (level, stars)))
|
|
|
|
|
}
|
|
|
|
|
|