From 36217f5704510db764799bf6753dcd0834be4ce7 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Mon, 2 Oct 2023 21:14:07 -0400 Subject: [PATCH 1/3] Do not capture trailing whitespace in parameters. --- .../greater_element/greater_block/with_params.org | 3 +++ src/parser/greater_block.rs | 8 ++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 org_mode_samples/greater_element/greater_block/with_params.org diff --git a/org_mode_samples/greater_element/greater_block/with_params.org b/org_mode_samples/greater_element/greater_block/with_params.org new file mode 100644 index 00000000..86ce0203 --- /dev/null +++ b/org_mode_samples/greater_element/greater_block/with_params.org @@ -0,0 +1,3 @@ +#+begin_defun foo bar baz +lorem +#+end_defun diff --git a/src/parser/greater_block.rs b/src/parser/greater_block.rs index 97a00c3d..961da9ea 100644 --- a/src/parser/greater_block.rs +++ b/src/parser/greater_block.rs @@ -1,6 +1,7 @@ use nom::branch::alt; use nom::bytes::complete::is_not; use nom::bytes::complete::tag_no_case; +use nom::character::complete::anychar; use nom::character::complete::line_ending; use nom::character::complete::space0; use nom::character::complete::space1; @@ -8,6 +9,8 @@ use nom::combinator::consumed; use nom::combinator::eof; use nom::combinator::not; use nom::combinator::opt; +use nom::combinator::peek; +use nom::combinator::recognize; use nom::combinator::verify; use nom::multi::many0; use nom::multi::many_till; @@ -16,6 +19,7 @@ use nom::sequence::tuple; use super::org_source::OrgSource; use super::util::in_section; +use super::util::org_line_ending; use crate::context::parser_with_context; use crate::context::ContextElement; use crate::context::ContextMatcher; @@ -64,7 +68,7 @@ pub(crate) fn greater_block<'b, 'g, 'r, 's>( } let exit_with_name = greater_block_end(name.into()); let (remaining, parameters) = opt(tuple((space1, parameters)))(remaining)?; - let (remaining, _nl) = line_ending(remaining)?; + let (remaining, _nl) = tuple((space0, line_ending))(remaining)?; let contexts = [ ContextElement::ConsumeTrailingWhitespace(true), ContextElement::Context(context_name.as_str()), @@ -123,7 +127,7 @@ fn name<'s>(input: OrgSource<'s>) -> Res, OrgSource<'s>> { #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] fn parameters<'s>(input: OrgSource<'s>) -> Res, OrgSource<'s>> { - is_not("\r\n")(input) + recognize(many_till(anychar, peek(tuple((space0, line_ending)))))(input) } fn greater_block_end<'c>(name: &'c str) -> impl ContextMatcher + 'c { From 2352636672a0ba82a64172186c14119d51a59eb2 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Mon, 2 Oct 2023 22:21:24 -0400 Subject: [PATCH 2/3] Split GreaterBlock into CenterBlock, QuoteBlock, and SpecialBlock. Center and quote blocks do not have parameters nor do they store their name so I am separating them out. --- src/compare/diff.rs | 64 ++++++++++++++++-- src/compare/elisp_fact.rs | 32 ++++++--- src/iter/all_ast_node_iter.rs | 4 +- src/iter/ast_node_iter.rs | 26 ++++++-- src/parser/element_parser.rs | 2 +- src/parser/greater_block.rs | 119 ++++++++++++++++++++++++++-------- src/types/ast_node.rs | 20 ++++-- src/types/element.rs | 16 +++-- src/types/greater_element.rs | 28 +++++++- src/types/mod.rs | 4 +- 10 files changed, 255 insertions(+), 60 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 08c0e86a..dbd32785 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -17,6 +17,7 @@ use crate::types::AngleLink; use crate::types::AstNode; use crate::types::BabelCall; use crate::types::Bold; +use crate::types::CenterBlock; use crate::types::CheckboxType; use crate::types::Citation; use crate::types::CitationReference; @@ -40,7 +41,6 @@ use crate::types::FixedWidthArea; use crate::types::FootnoteDefinition; use crate::types::FootnoteReference; use crate::types::GetStandardProperties; -use crate::types::GreaterBlock; use crate::types::Heading; use crate::types::HorizontalRule; use crate::types::Hour; @@ -69,12 +69,14 @@ use crate::types::PlainText; use crate::types::Planning; use crate::types::PriorityCookie; use crate::types::PropertyDrawer; +use crate::types::QuoteBlock; use crate::types::RadioLink; use crate::types::RadioTarget; use crate::types::RegularLink; use crate::types::RepeaterType; use crate::types::RepeaterWarningDelayValueType; use crate::types::Section; +use crate::types::SpecialBlock; use crate::types::SrcBlock; use crate::types::StandardProperties; use crate::types::StatisticsCookie; @@ -329,7 +331,9 @@ fn compare_ast_node<'b, 's>( AstNode::Paragraph(node) => compare_paragraph(source, emacs, node), AstNode::PlainList(node) => compare_plain_list(source, emacs, node), AstNode::PlainListItem(node) => compare_plain_list_item(source, emacs, node), - AstNode::GreaterBlock(node) => compare_greater_block(source, emacs, node), + AstNode::CenterBlock(node) => compare_center_block(source, emacs, node), + AstNode::QuoteBlock(node) => compare_quote_block(source, emacs, node), + AstNode::SpecialBlock(node) => compare_special_block(source, emacs, node), AstNode::DynamicBlock(node) => compare_dynamic_block(source, emacs, node), AstNode::FootnoteDefinition(node) => compare_footnote_definition(source, emacs, node), AstNode::Comment(node) => compare_comment(source, emacs, node), @@ -1011,10 +1015,60 @@ fn compare_plain_list_item<'b, 's>( .into()) } -fn compare_greater_block<'b, 's>( +fn compare_center_block<'b, 's>( source: &'s str, emacs: &'b Token<'s>, - rust: &'b GreaterBlock<'s>, + rust: &'b CenterBlock<'s>, +) -> Result, Box> { + let children = emacs.as_list()?; + let mut child_status = Vec::new(); + let this_status = DiffStatus::Good; + let message = None; + + for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { + child_status.push(compare_ast_node(source, emacs_child, rust_child.into())?); + } + + Ok(DiffResult { + status: this_status, + name: rust.get_elisp_name(), + message, + children: child_status, + rust_source: rust.get_source(), + emacs_token: emacs, + } + .into()) +} + +fn compare_quote_block<'b, 's>( + source: &'s str, + emacs: &'b Token<'s>, + rust: &'b QuoteBlock<'s>, +) -> Result, Box> { + let children = emacs.as_list()?; + let mut child_status = Vec::new(); + let this_status = DiffStatus::Good; + let message = None; + + for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { + child_status.push(compare_ast_node(source, emacs_child, rust_child.into())?); + } + + Ok(DiffResult { + status: this_status, + name: rust.get_elisp_name(), + message, + children: child_status, + rust_source: rust.get_source(), + emacs_token: emacs, + } + .into()) +} + +fn compare_special_block<'b, 's>( + source: &'s str, + emacs: &'b Token<'s>, + rust: &'b SpecialBlock<'s>, ) -> Result, Box> { let children = emacs.as_list()?; let mut child_status = Vec::new(); @@ -1023,6 +1077,8 @@ fn compare_greater_block<'b, 's>( // TODO: Special block compare :type :parameters // Center and quote block has no additional properties + let special_block_type = get_property_quoted_string(emacs, ":type")?; + for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { child_status.push(compare_ast_node(source, emacs_child, rust_child.into())?); } diff --git a/src/compare/elisp_fact.rs b/src/compare/elisp_fact.rs index 6256023b..fd2810b0 100644 --- a/src/compare/elisp_fact.rs +++ b/src/compare/elisp_fact.rs @@ -4,6 +4,7 @@ use crate::types::AngleLink; use crate::types::AstNode; use crate::types::BabelCall; use crate::types::Bold; +use crate::types::CenterBlock; use crate::types::Citation; use crate::types::CitationReference; use crate::types::Clock; @@ -22,7 +23,6 @@ use crate::types::ExportSnippet; use crate::types::FixedWidthArea; use crate::types::FootnoteDefinition; use crate::types::FootnoteReference; -use crate::types::GreaterBlock; use crate::types::Heading; use crate::types::HorizontalRule; use crate::types::InlineBabelCall; @@ -42,10 +42,12 @@ use crate::types::PlainListItem; use crate::types::PlainText; use crate::types::Planning; use crate::types::PropertyDrawer; +use crate::types::QuoteBlock; use crate::types::RadioLink; use crate::types::RadioTarget; use crate::types::RegularLink; use crate::types::Section; +use crate::types::SpecialBlock; use crate::types::SrcBlock; use crate::types::StatisticsCookie; use crate::types::StrikeThrough; @@ -83,7 +85,9 @@ impl<'r, 's> GetElispFact<'s> for AstNode<'r, 's> { AstNode::Paragraph(inner) => *inner, AstNode::PlainList(inner) => *inner, AstNode::PlainListItem(inner) => *inner, - AstNode::GreaterBlock(inner) => *inner, + AstNode::CenterBlock(inner) => *inner, + AstNode::QuoteBlock(inner) => *inner, + AstNode::SpecialBlock(inner) => *inner, AstNode::DynamicBlock(inner) => *inner, AstNode::FootnoteDefinition(inner) => *inner, AstNode::Comment(inner) => *inner, @@ -142,7 +146,9 @@ impl<'s> GetElispFact<'s> for Element<'s> { match self { Element::Paragraph(inner) => inner, Element::PlainList(inner) => inner, - Element::GreaterBlock(inner) => inner, + Element::CenterBlock(inner) => inner, + Element::QuoteBlock(inner) => inner, + Element::SpecialBlock(inner) => inner, Element::DynamicBlock(inner) => inner, Element::FootnoteDefinition(inner) => inner, Element::Comment(inner) => inner, @@ -230,13 +236,21 @@ impl<'s> ElispFact<'s> for PlainListItem<'s> { } } -impl<'s> ElispFact<'s> for GreaterBlock<'s> { +impl<'s> ElispFact<'s> for CenterBlock<'s> { fn get_elisp_name<'b>(&'b self) -> Cow<'s, str> { - match self.name.to_lowercase().as_str() { - "center" => "center-block".into(), - "quote" => "quote-block".into(), - _ => "special-block".into(), - } + "center-block".into() + } +} + +impl<'s> ElispFact<'s> for QuoteBlock<'s> { + fn get_elisp_name<'b>(&'b self) -> Cow<'s, str> { + "quote-block".into() + } +} + +impl<'s> ElispFact<'s> for SpecialBlock<'s> { + fn get_elisp_name<'b>(&'b self) -> Cow<'s, str> { + "special-block".into() } } diff --git a/src/iter/all_ast_node_iter.rs b/src/iter/all_ast_node_iter.rs index 9d6b091b..e4e6c2cc 100644 --- a/src/iter/all_ast_node_iter.rs +++ b/src/iter/all_ast_node_iter.rs @@ -24,7 +24,9 @@ impl<'r, 's> Iterator for AllAstNodeIter<'r, 's> { AstNodeIter::Paragraph(ref mut i) => i.next(), AstNodeIter::PlainList(ref mut i) => i.next(), AstNodeIter::PlainListItem(ref mut i) => i.next(), - AstNodeIter::GreaterBlock(ref mut i) => i.next(), + AstNodeIter::CenterBlock(ref mut i) => i.next(), + AstNodeIter::QuoteBlock(ref mut i) => i.next(), + AstNodeIter::SpecialBlock(ref mut i) => i.next(), AstNodeIter::DynamicBlock(ref mut i) => i.next(), AstNodeIter::FootnoteDefinition(ref mut i) => i.next(), AstNodeIter::Comment(ref mut i) => i.next(), diff --git a/src/iter/ast_node_iter.rs b/src/iter/ast_node_iter.rs index 2da6e224..1c4210d7 100644 --- a/src/iter/ast_node_iter.rs +++ b/src/iter/ast_node_iter.rs @@ -7,6 +7,7 @@ use crate::types::AngleLink; use crate::types::AstNode; use crate::types::BabelCall; use crate::types::Bold; +use crate::types::CenterBlock; use crate::types::Citation; use crate::types::CitationReference; use crate::types::Clock; @@ -26,7 +27,6 @@ use crate::types::ExportSnippet; use crate::types::FixedWidthArea; use crate::types::FootnoteDefinition; use crate::types::FootnoteReference; -use crate::types::GreaterBlock; use crate::types::Heading; use crate::types::HorizontalRule; use crate::types::InlineBabelCall; @@ -46,10 +46,12 @@ use crate::types::PlainListItem; use crate::types::PlainText; use crate::types::Planning; use crate::types::PropertyDrawer; +use crate::types::QuoteBlock; use crate::types::RadioLink; use crate::types::RadioTarget; use crate::types::RegularLink; use crate::types::Section; +use crate::types::SpecialBlock; use crate::types::SrcBlock; use crate::types::StatisticsCookie; use crate::types::StrikeThrough; @@ -78,7 +80,9 @@ pub(crate) enum AstNodeIter<'r, 's> { Paragraph(ParagraphIter<'r, 's>), PlainList(PlainListIter<'r, 's>), PlainListItem(PlainListItemIter<'r, 's>), - GreaterBlock(GreaterBlockIter<'r, 's>), + CenterBlock(CenterBlockIter<'r, 's>), + QuoteBlock(QuoteBlockIter<'r, 's>), + SpecialBlock(SpecialBlockIter<'r, 's>), DynamicBlock(DynamicBlockIter<'r, 's>), FootnoteDefinition(FootnoteDefinitionIter<'r, 's>), Comment(CommentIter<'r, 's>), @@ -140,7 +144,9 @@ impl<'r, 's> AstNodeIter<'r, 's> { AstNode::Paragraph(inner) => AstNodeIter::Paragraph(inner.into_iter()), AstNode::PlainList(inner) => AstNodeIter::PlainList(inner.into_iter()), AstNode::PlainListItem(inner) => AstNodeIter::PlainListItem(inner.into_iter()), - AstNode::GreaterBlock(inner) => AstNodeIter::GreaterBlock(inner.into_iter()), + AstNode::CenterBlock(inner) => AstNodeIter::CenterBlock(inner.into_iter()), + AstNode::QuoteBlock(inner) => AstNodeIter::QuoteBlock(inner.into_iter()), + AstNode::SpecialBlock(inner) => AstNodeIter::SpecialBlock(inner.into_iter()), AstNode::DynamicBlock(inner) => AstNodeIter::DynamicBlock(inner.into_iter()), AstNode::FootnoteDefinition(inner) => { AstNodeIter::FootnoteDefinition(inner.into_iter()) @@ -232,8 +238,18 @@ multi_field_iter!( std::slice::Iter<'r, Element<'s>> ); children_iter!( - GreaterBlock<'s>, - GreaterBlockIter, + CenterBlock<'s>, + CenterBlockIter, + std::slice::Iter<'r, Element<'s>> +); +children_iter!( + QuoteBlock<'s>, + QuoteBlockIter, + std::slice::Iter<'r, Element<'s>> +); +children_iter!( + SpecialBlock<'s>, + SpecialBlockIter, std::slice::Iter<'r, Element<'s>> ); children_iter!( diff --git a/src/parser/element_parser.rs b/src/parser/element_parser.rs index e847da51..2fd0f6c7 100644 --- a/src/parser/element_parser.rs +++ b/src/parser/element_parser.rs @@ -81,7 +81,7 @@ fn _element<'b, 'g, 'r, 's>( 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), + greater_block_matcher, map(dynamic_block_matcher, Element::DynamicBlock), map(footnote_definition_matcher, Element::FootnoteDefinition), map(comment_matcher, Element::Comment), diff --git a/src/parser/greater_block.rs b/src/parser/greater_block.rs index 961da9ea..7ce198de 100644 --- a/src/parser/greater_block.rs +++ b/src/parser/greater_block.rs @@ -19,7 +19,6 @@ use nom::sequence::tuple; use super::org_source::OrgSource; use super::util::in_section; -use super::util::org_line_ending; use crate::context::parser_with_context; use crate::context::ContextElement; use crate::context::ContextMatcher; @@ -34,17 +33,18 @@ use crate::parser::util::blank_line; use crate::parser::util::exit_matcher_parser; use crate::parser::util::get_consumed; use crate::parser::util::start_of_line; +use crate::types::CenterBlock; use crate::types::Element; -use crate::types::GreaterBlock; use crate::types::Paragraph; +use crate::types::QuoteBlock; use crate::types::SetSource; +use crate::types::SpecialBlock; #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] pub(crate) fn greater_block<'b, 'g, 'r, 's>( context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, -) -> Res, GreaterBlock<'s>> { - // TODO: Do I need to differentiate between different greater block types. +) -> Res, Element<'s>> { start_of_line(input)?; let (remaining, _leading_whitespace) = space0(input)?; let (remaining, (_begin, name)) = tuple(( @@ -56,22 +56,98 @@ pub(crate) fn greater_block<'b, 'g, 'r, 's>( } }), ))(remaining)?; - let context_name = match Into::<&str>::into(name).to_lowercase().as_str() { - "center" => "center block".to_owned(), - "quote" => "quote block".to_owned(), - name @ _ => format!("special block {}", name), + let name = Into::<&str>::into(name); + let (remaining, element) = match name.to_lowercase().as_str() { + "center" => center_block(context, remaining, input)?, + "quote" => quote_block(context, remaining, input)?, + _ => special_block(name)(context, remaining, input)?, }; - if in_section(context, context_name.as_str()) { + Ok((remaining, element)) +} + +#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] +fn center_block<'b, 'g, 'r, 's>( + context: RefContext<'b, 'g, 'r, 's>, + input: OrgSource<'s>, + original_input: OrgSource<'s>, +) -> Res, Element<'s>> { + let (remaining, (source, children)) = + greater_block_body(context, input, original_input, "center", "center block")?; + Ok(( + remaining, + Element::CenterBlock(CenterBlock { source, children }), + )) +} + +#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] +fn quote_block<'b, 'g, 'r, 's>( + context: RefContext<'b, 'g, 'r, 's>, + input: OrgSource<'s>, + original_input: OrgSource<'s>, +) -> Res, Element<'s>> { + let (remaining, (source, children)) = + greater_block_body(context, input, original_input, "quote", "quote block")?; + Ok(( + remaining, + Element::QuoteBlock(QuoteBlock { source, children }), + )) +} + +#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] +fn special_block<'s>( + name: &'s str, +) -> impl for<'b, 'g, 'r> Fn( + RefContext<'b, 'g, 'r, 's>, + OrgSource<'s>, + OrgSource<'s>, +) -> Res, Element<'s>> + + 's { + let context_name = format!("special block {}", name); + move |context, input, original_input| { + _special_block(context, input, original_input, name, context_name.as_str()) + } +} + +#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] +fn _special_block<'c, 'b, 'g, 'r, 's>( + context: RefContext<'b, 'g, 'r, 's>, + input: OrgSource<'s>, + original_input: OrgSource<'s>, + name: &'s str, + context_name: &'c str, +) -> Res, Element<'s>> { + let (remaining, parameters) = opt(tuple((space1, parameters)))(input)?; + let (remaining, (source, children)) = + greater_block_body(context, remaining, original_input, name, context_name)?; + Ok(( + remaining, + Element::SpecialBlock(SpecialBlock { + source, + children, + name, + parameters: parameters.map(|(_, parameters)| Into::<&str>::into(parameters)), + }), + )) +} + +#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] +fn greater_block_body<'c, 'b, 'g, 'r, 's>( + context: RefContext<'b, 'g, 'r, 's>, + input: OrgSource<'s>, + original_input: OrgSource<'s>, + name: &'c str, + context_name: &'c str, +) -> Res, (&'s str, Vec>)> { + if in_section(context, context_name) { return Err(nom::Err::Error(CustomError::MyError(MyError( "Cannot nest objects of the same element".into(), )))); } - let exit_with_name = greater_block_end(name.into()); - let (remaining, parameters) = opt(tuple((space1, parameters)))(remaining)?; - let (remaining, _nl) = tuple((space0, line_ending))(remaining)?; + let exit_with_name = greater_block_end(name); + let (remaining, _nl) = tuple((space0, line_ending))(input)?; let contexts = [ ContextElement::ConsumeTrailingWhitespace(true), - ContextElement::Context(context_name.as_str()), + ContextElement::Context(context_name), ContextElement::ExitMatcherNode(ExitMatcherNode { class: ExitClass::Alpha, exit_matcher: &exit_with_name, @@ -80,11 +156,6 @@ pub(crate) fn greater_block<'b, 'g, 'r, 's>( let parser_context = context.with_additional_node(&contexts[0]); let parser_context = parser_context.with_additional_node(&contexts[1]); let parser_context = parser_context.with_additional_node(&contexts[2]); - let parameters = match parameters { - Some((_ws, parameters)) => Some(parameters), - None => None, - }; - let element_matcher = parser_with_context!(element(true))(&parser_context); let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context); not(exit_matcher)(remaining)?; @@ -108,16 +179,8 @@ pub(crate) fn greater_block<'b, 'g, 'r, 's>( // Not checking if parent exit matcher is causing exit because the greater_block_end matcher asserts we matched a full greater block - let source = get_consumed(input, remaining); - Ok(( - remaining, - GreaterBlock { - source: source.into(), - name: name.into(), - parameters: parameters.map(|val| Into::<&str>::into(val)), - children, - }, - )) + let source = get_consumed(original_input, remaining); + Ok((remaining, (Into::<&str>::into(source), children))) } #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] diff --git a/src/types/ast_node.rs b/src/types/ast_node.rs index e925f746..c9a17294 100644 --- a/src/types/ast_node.rs +++ b/src/types/ast_node.rs @@ -1,4 +1,7 @@ use super::macros::to_ast_node; +use super::CenterBlock; +use super::QuoteBlock; +use super::SpecialBlock; use crate::types::AngleLink; use crate::types::BabelCall; use crate::types::Bold; @@ -22,7 +25,6 @@ use crate::types::FixedWidthArea; use crate::types::FootnoteDefinition; use crate::types::FootnoteReference; use crate::types::GetStandardProperties; -use crate::types::GreaterBlock; use crate::types::Heading; use crate::types::HorizontalRule; use crate::types::InlineBabelCall; @@ -69,7 +71,9 @@ pub enum AstNode<'r, 's> { Paragraph(&'r Paragraph<'s>), PlainList(&'r PlainList<'s>), PlainListItem(&'r PlainListItem<'s>), - GreaterBlock(&'r GreaterBlock<'s>), + CenterBlock(&'r CenterBlock<'s>), + QuoteBlock(&'r QuoteBlock<'s>), + SpecialBlock(&'r SpecialBlock<'s>), DynamicBlock(&'r DynamicBlock<'s>), FootnoteDefinition(&'r FootnoteDefinition<'s>), Comment(&'r Comment<'s>), @@ -136,7 +140,9 @@ impl<'r, 's> From<&'r Element<'s>> for AstNode<'r, 's> { match value { Element::Paragraph(inner) => inner.into(), Element::PlainList(inner) => inner.into(), - Element::GreaterBlock(inner) => inner.into(), + Element::CenterBlock(inner) => inner.into(), + Element::QuoteBlock(inner) => inner.into(), + Element::SpecialBlock(inner) => inner.into(), Element::DynamicBlock(inner) => inner.into(), Element::FootnoteDefinition(inner) => inner.into(), Element::Comment(inner) => inner.into(), @@ -200,7 +206,9 @@ to_ast_node!(&'r Section<'s>, AstNode::Section); to_ast_node!(&'r Paragraph<'s>, AstNode::Paragraph); to_ast_node!(&'r PlainList<'s>, AstNode::PlainList); to_ast_node!(&'r PlainListItem<'s>, AstNode::PlainListItem); -to_ast_node!(&'r GreaterBlock<'s>, AstNode::GreaterBlock); +to_ast_node!(&'r CenterBlock<'s>, AstNode::CenterBlock); +to_ast_node!(&'r QuoteBlock<'s>, AstNode::QuoteBlock); +to_ast_node!(&'r SpecialBlock<'s>, AstNode::SpecialBlock); to_ast_node!(&'r DynamicBlock<'s>, AstNode::DynamicBlock); to_ast_node!(&'r FootnoteDefinition<'s>, AstNode::FootnoteDefinition); to_ast_node!(&'r Comment<'s>, AstNode::Comment); @@ -260,7 +268,9 @@ impl<'r, 's> GetStandardProperties<'s> for AstNode<'r, 's> { AstNode::Paragraph(inner) => *inner, AstNode::PlainList(inner) => *inner, AstNode::PlainListItem(inner) => *inner, - AstNode::GreaterBlock(inner) => *inner, + AstNode::CenterBlock(inner) => *inner, + AstNode::QuoteBlock(inner) => *inner, + AstNode::SpecialBlock(inner) => *inner, AstNode::DynamicBlock(inner) => *inner, AstNode::FootnoteDefinition(inner) => *inner, AstNode::Comment(inner) => *inner, diff --git a/src/types/element.rs b/src/types/element.rs index 020b2d1e..d9f20e53 100644 --- a/src/types/element.rs +++ b/src/types/element.rs @@ -1,6 +1,5 @@ use super::greater_element::DynamicBlock; use super::greater_element::FootnoteDefinition; -use super::greater_element::GreaterBlock; use super::greater_element::PlainList; use super::greater_element::PropertyDrawer; use super::greater_element::Table; @@ -19,16 +18,21 @@ use super::lesser_element::Paragraph; use super::lesser_element::Planning; use super::lesser_element::SrcBlock; use super::lesser_element::VerseBlock; +use super::CenterBlock; use super::Drawer; use super::GetStandardProperties; +use super::QuoteBlock; use super::SetSource; +use super::SpecialBlock; use super::StandardProperties; #[derive(Debug)] pub enum Element<'s> { Paragraph(Paragraph<'s>), PlainList(PlainList<'s>), - GreaterBlock(GreaterBlock<'s>), + CenterBlock(CenterBlock<'s>), + QuoteBlock(QuoteBlock<'s>), + SpecialBlock(SpecialBlock<'s>), DynamicBlock(DynamicBlock<'s>), FootnoteDefinition(FootnoteDefinition<'s>), Comment(Comment<'s>), @@ -56,7 +60,9 @@ impl<'s> SetSource<'s> for Element<'s> { match self { Element::Paragraph(obj) => obj.source = source, Element::PlainList(obj) => obj.source = source, - Element::GreaterBlock(obj) => obj.source = source, + Element::CenterBlock(obj) => obj.source = source, + Element::QuoteBlock(obj) => obj.source = source, + Element::SpecialBlock(obj) => obj.source = source, Element::DynamicBlock(obj) => obj.source = source, Element::FootnoteDefinition(obj) => obj.source = source, Element::Comment(obj) => obj.source = source, @@ -85,7 +91,9 @@ impl<'s> GetStandardProperties<'s> for Element<'s> { match self { Element::Paragraph(inner) => inner, Element::PlainList(inner) => inner, - Element::GreaterBlock(inner) => inner, + Element::CenterBlock(inner) => inner, + Element::QuoteBlock(inner) => inner, + Element::SpecialBlock(inner) => inner, Element::DynamicBlock(inner) => inner, Element::FootnoteDefinition(inner) => inner, Element::Comment(inner) => inner, diff --git a/src/types/greater_element.rs b/src/types/greater_element.rs index 9285d989..ec1f2818 100644 --- a/src/types/greater_element.rs +++ b/src/types/greater_element.rs @@ -44,7 +44,19 @@ pub enum CheckboxType { } #[derive(Debug)] -pub struct GreaterBlock<'s> { +pub struct CenterBlock<'s> { + pub source: &'s str, + pub children: Vec>, +} + +#[derive(Debug)] +pub struct QuoteBlock<'s> { + pub source: &'s str, + pub children: Vec>, +} + +#[derive(Debug)] +pub struct SpecialBlock<'s> { pub source: &'s str, pub name: &'s str, pub parameters: Option<&'s str>, @@ -110,7 +122,19 @@ impl<'s> StandardProperties<'s> for PlainListItem<'s> { } } -impl<'s> StandardProperties<'s> for GreaterBlock<'s> { +impl<'s> StandardProperties<'s> for CenterBlock<'s> { + fn get_source<'b>(&'b self) -> &'s str { + self.source + } +} + +impl<'s> StandardProperties<'s> for QuoteBlock<'s> { + fn get_source<'b>(&'b self) -> &'s str { + self.source + } +} + +impl<'s> StandardProperties<'s> for SpecialBlock<'s> { fn get_source<'b>(&'b self) -> &'s str { self.source } diff --git a/src/types/mod.rs b/src/types/mod.rs index 89d50151..d95adcbd 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -18,11 +18,11 @@ pub use document::Section; pub use document::TodoKeywordType; pub use element::Element; pub use get_standard_properties::GetStandardProperties; +pub use greater_element::CenterBlock; pub use greater_element::CheckboxType; pub use greater_element::Drawer; pub use greater_element::DynamicBlock; pub use greater_element::FootnoteDefinition; -pub use greater_element::GreaterBlock; pub use greater_element::IndentationLevel; pub use greater_element::NodeProperty; pub use greater_element::PlainList; @@ -31,6 +31,8 @@ pub use greater_element::PlainListItemCounter; pub use greater_element::PlainListItemPreBlank; pub use greater_element::PlainListType; pub use greater_element::PropertyDrawer; +pub use greater_element::QuoteBlock; +pub use greater_element::SpecialBlock; pub use greater_element::Table; pub use greater_element::TableRow; pub use lesser_element::BabelCall; From 4a72747dc9513fc00d349f9588610ba0113e395d Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Mon, 2 Oct 2023 22:30:42 -0400 Subject: [PATCH 3/3] Compare name and parameters. --- src/compare/diff.rs | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index dbd32785..4cb05e7e 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -1072,12 +1072,33 @@ fn compare_special_block<'b, 's>( ) -> Result, Box> { let children = emacs.as_list()?; let mut child_status = Vec::new(); - let this_status = DiffStatus::Good; - let message = None; - // TODO: Special block compare :type :parameters - // Center and quote block has no additional properties + let mut this_status = DiffStatus::Good; + let mut message = None; - let special_block_type = get_property_quoted_string(emacs, ":type")?; + // Compare type + let special_block_type = + get_property_quoted_string(emacs, ":type")?.ok_or("Special blocks should have a name.")?; + if special_block_type != rust.name { + this_status = DiffStatus::Bad; + message = Some(format!( + "Name mismatch (emacs != rust) {:?} != {:?}", + special_block_type, rust.name + )); + } + + // Compare parameters + let parameters = get_property_quoted_string(emacs, ":parameters")?; + match (parameters.as_ref(), rust.parameters) { + (None, None) => {} + (Some(emacs_parameters), Some(rust_parameters)) if emacs_parameters == rust_parameters => {} + _ => { + this_status = DiffStatus::Bad; + message = Some(format!( + "Parameters mismatch (emacs != rust) {:?} != {:?}", + parameters, rust.parameters + )); + } + } for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { child_status.push(compare_ast_node(source, emacs_child, rust_child.into())?);