Introduce a struct for the partially-parsed headline.

We are returning so many fields from that parser that managing a tuple is becoming unreadable. The struct should add some structure 😉 to the code.
This commit is contained in:
Tom Alexander 2023-10-02 11:16:05 -04:00
parent 5a254392cb
commit de5788d8f3
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE

View File

@ -56,20 +56,9 @@ fn _heading<'b, 'g, 'r, 's>(
parent_star_count: HeadlineLevel, parent_star_count: HeadlineLevel,
) -> Res<OrgSource<'s>, Heading<'s>> { ) -> Res<OrgSource<'s>, Heading<'s>> {
not(|i| context.check_exit_matcher(i))(input)?; not(|i| context.check_exit_matcher(i))(input)?;
let ( let (remaining, pre_headline) = headline(context, input, parent_star_count)?;
remaining,
(
headline_level,
star_count,
maybe_todo_keyword,
maybe_priority,
maybe_comment,
title,
heading_tags,
),
) = headline(context, input, parent_star_count)?;
let section_matcher = parser_with_context!(section)(context); 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(pre_headline.star_count))(context);
let (remaining, maybe_section) = let (remaining, maybe_section) =
opt(map(section_matcher, DocumentElement::Section))(remaining)?; opt(map(section_matcher, DocumentElement::Section))(remaining)?;
let (remaining, _ws) = opt(tuple((start_of_line, many0(blank_line))))(remaining)?; let (remaining, _ws) = opt(tuple((start_of_line, many0(blank_line))))(remaining)?;
@ -85,22 +74,24 @@ fn _heading<'b, 'g, 'r, 's>(
} else { } else {
remaining remaining
}; };
let is_archived = heading_tags.contains(&"ARCHIVE"); let is_archived = pre_headline.tags.contains(&"ARCHIVE");
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
Ok(( Ok((
remaining, remaining,
Heading { Heading {
source: source.into(), source: source.into(),
level: headline_level, level: pre_headline.headline_level,
todo_keyword: maybe_todo_keyword.map(|(todo_keyword_type, todo_keyword)| { todo_keyword: pre_headline
(todo_keyword_type, Into::<&str>::into(todo_keyword)) .todo_keyword
}), .map(|(todo_keyword_type, todo_keyword)| {
priority_cookie: maybe_priority.map(|(_, priority)| priority), (todo_keyword_type, Into::<&str>::into(todo_keyword))
title, }),
tags: heading_tags, priority_cookie: pre_headline.priority_cookie.map(|(_, priority)| priority),
title: pre_headline.title,
tags: pre_headline.tags,
children, children,
is_comment: maybe_comment.is_some(), is_comment: pre_headline.comment.is_some(),
is_archived, is_archived,
is_footnote_section: false, // TODO is_footnote_section: false, // TODO
}, },
@ -113,23 +104,25 @@ pub(crate) fn detect_headline<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, ()
Ok((input, ())) Ok((input, ()))
} }
/// Fields from a not-yet-fully-parsed Headline.
///
/// This struct exists to give names to the fields of a partially-parsed Headline to avoid returning a large tuple of nameless fields.
struct PreHeadline<'s> {
headline_level: HeadlineLevel,
star_count: HeadlineLevel,
todo_keyword: Option<(TodoKeywordType, OrgSource<'s>)>,
priority_cookie: Option<(OrgSource<'s>, PriorityCookie)>,
comment: Option<OrgSource<'s>>,
title: Vec<Object<'s>>,
tags: Vec<&'s str>,
}
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
fn headline<'b, 'g, 'r, 's>( fn headline<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>, context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>, input: OrgSource<'s>,
parent_star_count: HeadlineLevel, parent_star_count: HeadlineLevel,
) -> Res< ) -> Res<OrgSource<'s>, PreHeadline<'s>> {
OrgSource<'s>,
(
HeadlineLevel,
HeadlineLevel,
Option<(TodoKeywordType, OrgSource<'s>)>,
Option<(OrgSource<'s>, PriorityCookie)>,
Option<OrgSource<'s>>,
Vec<Object<'s>>,
Vec<&'s str>,
),
> {
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode { let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
class: ExitClass::Document, class: ExitClass::Document,
exit_matcher: &headline_title_end, exit_matcher: &headline_title_end,
@ -172,23 +165,23 @@ fn headline<'b, 'g, 'r, 's>(
Ok(( Ok((
remaining, remaining,
( PreHeadline {
headline_level, headline_level,
star_count, star_count,
maybe_todo_keyword.map(|(_, todo, _)| todo), todo_keyword: maybe_todo_keyword.map(|(_, todo, _)| todo),
maybe_priority, priority_cookie: maybe_priority,
maybe_comment.map(|(_, comment, _)| comment), comment: maybe_comment.map(|(_, comment, _)| comment),
maybe_title title: maybe_title
.map(|(_, (_, title))| title) .map(|(_, (_, title))| title)
.unwrap_or(Vec::new()), .unwrap_or(Vec::new()),
maybe_tags tags: maybe_tags
.map(|(_ws, tags)| { .map(|(_ws, tags)| {
tags.into_iter() tags.into_iter()
.map(|single_tag| Into::<&str>::into(single_tag)) .map(|single_tag| Into::<&str>::into(single_tag))
.collect() .collect()
}) })
.unwrap_or(Vec::new()), .unwrap_or(Vec::new()),
), },
)) ))
} }