From 2d4e54845b6e9b035161f329d9860f95dc53f258 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Fri, 25 Aug 2023 06:13:29 -0400 Subject: [PATCH] Add support for parsing tags in headlines. --- .../greater_element/dynamic_block/simple.org | 6 ++-- src/compare/diff.rs | 2 ++ src/parser/document.rs | 30 ++++++++++++++++--- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/org_mode_samples/greater_element/dynamic_block/simple.org b/org_mode_samples/greater_element/dynamic_block/simple.org index a21ce8a..1034c5e 100644 --- a/org_mode_samples/greater_element/dynamic_block/simple.org +++ b/org_mode_samples/greater_element/dynamic_block/simple.org @@ -14,10 +14,12 @@ |-------+------+----------+------------------------------| | Baz | | B | :thisisatag: | | Lorem | | B | :thisshouldinheritfromabove: | -| Ipsum | | B | | +| Ipsum | | B | :multiple:tags: | #+END: * Foo * TODO Bar * Baz :thisisatag: ** Lorem :thisshouldinheritfromabove: -*** Ipsum +*** Ipsum :multiple:tags: +* Dolar :: +* cat :dog: bat diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 4b18716..c68db81 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -348,6 +348,8 @@ fn compare_heading<'s>( child_status.push(compare_object(source, emacs_child, rust_child)?); } + // TODO: Compare tags, todo-keyword, level, priority + for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { match rust_child { DocumentElement::Heading(rust_heading) => { diff --git a/src/parser/document.rs b/src/parser/document.rs index 957fff2..dd4e117 100644 --- a/src/parser/document.rs +++ b/src/parser/document.rs @@ -1,6 +1,8 @@ use nom::branch::alt; use nom::bytes::complete::tag; +use nom::character::complete::anychar; use nom::character::complete::line_ending; +use nom::character::complete::space0; use nom::character::complete::space1; use nom::combinator::eof; use nom::combinator::map; @@ -12,6 +14,7 @@ use nom::multi::many0; use nom::multi::many1; use nom::multi::many1_count; use nom::multi::many_till; +use nom::multi::separated_list1; use nom::sequence::tuple; use super::element::Element; @@ -297,26 +300,45 @@ fn headline<'r, 's>( let parser_context = context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { class: ExitClass::Document, - exit_matcher: &headline_end, + exit_matcher: &headline_title_end, })); let standard_set_object_matcher = parser_with_context!(standard_set_object)(&parser_context); - let (remaining, (_sol, star_count, ws, title, _line_ending)) = tuple(( + let (remaining, (_sol, star_count, ws, title, maybe_tags, _ws, _line_ending)) = tuple(( start_of_line, many1_count(tag("*")), space1, many1(standard_set_object_matcher), + opt(tuple((space0, tags))), + space0, alt((line_ending, eof)), ))(input)?; Ok((remaining, (star_count, ws, title))) } #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] -fn headline_end<'r, 's>( +fn headline_title_end<'r, 's>( _context: Context<'r, 's>, input: OrgSource<'s>, ) -> Res, OrgSource<'s>> { - line_ending(input) + recognize(tuple(( + opt(tuple((space0, tags, space0))), + alt((line_ending, eof)), + )))(input) +} + +#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] +fn tags<'s>(input: OrgSource<'s>) -> Res, Vec>> { + let (remaining, (_open, tags, _close)) = + tuple((tag(":"), separated_list1(tag(":"), single_tag), tag(":")))(input)?; + Ok((remaining, tags)) +} + +#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] +fn single_tag<'r, 's>(input: OrgSource<'s>) -> Res, OrgSource<'s>> { + recognize(many1(verify(anychar, |c| { + c.is_alphanumeric() || "_@#%".contains(*c) + })))(input) } impl<'s> Document<'s> {