From f046b16c110d7c8b7a34abfd71d23d837bf1ad97 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Wed, 4 Oct 2023 18:02:50 -0400 Subject: [PATCH] Compare src block parameters. --- src/compare/diff.rs | 20 +++++++++ src/parser/lesser_block.rs | 81 ++++++++++++++++++++++++++++--------- src/types/lesser_element.rs | 3 +- 3 files changed, 83 insertions(+), 21 deletions(-) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index f630e39..cb02531 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -1731,6 +1731,8 @@ fn compare_src_block<'b, 's>( let mut this_status = DiffStatus::Good; let mut message = None; + // TODO: Compare :parameters + // Compare language let language = get_property_quoted_string(emacs, ":language")?; if language.as_ref().map(String::as_str) != rust.language { @@ -1769,6 +1771,24 @@ fn compare_src_block<'b, 's>( } } + // Compare switches + let parameters = get_property_quoted_string(emacs, ":parameters")?; + match (parameters.as_ref().map(String::as_str), rust.parameters) { + (None, None) => {} + (Some(""), None) => {} + (None, Some("")) => { + unreachable!("The organic parser would return a None instead of an empty string."); + } + (Some(e), Some(r)) if e == r => {} + _ => { + this_status = DiffStatus::Bad; + message = Some(format!( + "Parameters mismatch (emacs != rust) {:?} != {:?}", + parameters, rust.parameters + )); + } + } + // Compare number-lines let number_lines = get_property(emacs, ":number-lines")?; match (number_lines, &rust.number_lines) { diff --git a/src/parser/lesser_block.rs b/src/parser/lesser_block.rs index 5f909a6..a04e562 100644 --- a/src/parser/lesser_block.rs +++ b/src/parser/lesser_block.rs @@ -9,6 +9,7 @@ use nom::character::complete::space1; use nom::combinator::consumed; use nom::combinator::eof; use nom::combinator::map; +use nom::combinator::not; use nom::combinator::opt; use nom::combinator::peek; use nom::combinator::recognize; @@ -24,6 +25,7 @@ use crate::context::ContextElement; use crate::context::ContextMatcher; use crate::context::ExitClass; use crate::context::ExitMatcherNode; +use crate::context::Matcher; use crate::context::RefContext; use crate::error::Res; use crate::parser::object_parser::standard_set_object; @@ -238,7 +240,10 @@ pub(crate) fn src_block<'b, 'g, 'r, 's>( ) -> Res, SrcBlock<'s>> { let (remaining, _name) = lesser_block_begin("src")(context, input)?; // https://orgmode.org/worg/org-syntax.html#Blocks claims that data is mandatory and must follow the LANGUAGE SWITCHES ARGUMENTS pattern but testing has shown that no data and incorrect data here will still parse to a src block. - let (remaining, parameters) = opt(tuple((space1, src_switches)))(remaining)?; + let (remaining, switches) = opt(tuple((space1, src_switches)))(remaining)?; + let (remaining, parameters) = opt(map(tuple((space0, src_parameters)), |(_, parameters)| { + parameters + }))(remaining)?; let (remaining, _nl) = recognize(tuple((space0, line_ending)))(remaining)?; let lesser_block_end_specialized = lesser_block_end("src"); let contexts = [ @@ -252,8 +257,8 @@ pub(crate) fn src_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), + let switches = match switches { + Some((_ws, switches)) => Some(switches), None => None, }; @@ -262,18 +267,18 @@ pub(crate) fn src_block<'b, 'g, 'r, 's>( let source = get_consumed(input, remaining); let (switches, language, number_lines, retain_labels, use_labels, label_format) = { - if let Some(parameters) = parameters { + if let Some(switches) = switches { ( - if parameters.source.len() == 0 { + if switches.source.len() == 0 { None } else { - Some(parameters.source) + Some(switches.source) }, - parameters.language, - parameters.number_lines, - parameters.retain_labels, - parameters.use_labels, - parameters.label_format, + switches.language, + switches.number_lines, + switches.retain_labels, + switches.use_labels, + switches.label_format, ) } else { (None, None, None, RetainLabels::Yes, true, None) @@ -283,8 +288,9 @@ pub(crate) fn src_block<'b, 'g, 'r, 's>( remaining, SrcBlock { source: source.into(), - switches, language, + switches, + parameters: parameters.map(Into::<&str>::into), number_lines, retain_labels, use_labels, @@ -371,28 +377,35 @@ enum SwitchState { LabelFormat, } +#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] +fn src_parameters<'s>(input: OrgSource<'s>) -> Res, OrgSource<'s>> { + recognize(is_not("\r\n"))(input) +} + #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] fn src_switches<'s>(input: OrgSource<'s>) -> Res, ExampleSrcSwitches<'s>> { - example_src_switches(true)(input) + example_src_switches(true, true)(input) } #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] fn example_switches<'s>(input: OrgSource<'s>) -> Res, ExampleSrcSwitches<'s>> { - let (remaining, switches) = example_src_switches(false)(input)?; + let (remaining, switches) = example_src_switches(false, false)(input)?; debug_assert!(switches.language.is_none()); Ok((remaining, switches)) } fn example_src_switches( grab_language: bool, + stop_at_parameters: bool, ) -> impl for<'s> Fn(OrgSource<'s>) -> Res, ExampleSrcSwitches<'s>> { - move |input| _example_src_switches(input, grab_language) + move |input| _example_src_switches(input, grab_language, stop_at_parameters) } #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] fn _example_src_switches<'s>( input: OrgSource<'s>, grab_language: bool, + stop_at_parameters: bool, ) -> Res, ExampleSrcSwitches<'s>> { let mut number_lines = None; let mut retain_labels = RetainLabels::Yes; @@ -402,17 +415,23 @@ fn _example_src_switches<'s>( let mut language = None; let remaining = if grab_language { - let (remain, first_word) = opt(map(tuple((switch_word, space0)), |(word, _)| word))(input)?; + let (remain, first_word) = opt(switch_word(stop_at_parameters))(input)?; language = first_word.map(Into::<&str>::into); remain } else { input }; - let (remaining, (source, (words, _))) = if language.is_none() { - consumed(tuple((separated_list1(space1, switch_word), space0)))(remaining)? + let (remaining, (source, words)) = if language.is_none() { + consumed(separated_list1(space1, switch_word(stop_at_parameters)))(remaining)? } else { - consumed(tuple((separated_list0(space1, switch_word), space0)))(remaining)? + map( + tuple(( + space1, + consumed(separated_list0(space1, switch_word(stop_at_parameters))), + )), + |(_, words)| words, + )(remaining)? }; let mut state = SwitchState::Normal; @@ -489,6 +508,18 @@ fn _example_src_switches<'s>( } } + // Handle state that didn't get processed because we ran out of words. + match state { + SwitchState::Normal => {} + SwitchState::NewLineNumber => { + number_lines = Some(SwitchNumberLines::New(0)); + } + SwitchState::ContinuedLineNumber => { + number_lines = Some(SwitchNumberLines::Continued(0)); + } + SwitchState::LabelFormat => {} + } + let retain_labels = match retain_labels { RetainLabels::Keep(_) if !saw_r => RetainLabels::Yes, _ => retain_labels, @@ -507,8 +538,18 @@ fn _example_src_switches<'s>( )) } +fn switch_word<'s>(stop_at_parameters: bool) -> impl Matcher { + move |input| _switch_word(input, stop_at_parameters) +} + #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] -fn switch_word<'s>(input: OrgSource<'s>) -> Res, OrgSource<'s>> { +fn _switch_word<'s>( + input: OrgSource<'s>, + stop_at_parameters: bool, +) -> Res, OrgSource<'s>> { + if stop_at_parameters { + not(tag(":"))(input)?; + } alt(( map( tuple((tag(r#"""#), is_not("\"\r\n"), tag(r#"""#))), diff --git a/src/types/lesser_element.rs b/src/types/lesser_element.rs index d8e21d6..572626e 100644 --- a/src/types/lesser_element.rs +++ b/src/types/lesser_element.rs @@ -67,8 +67,9 @@ pub struct ExportBlock<'s> { #[derive(Debug)] pub struct SrcBlock<'s> { pub source: &'s str, - pub switches: Option<&'s str>, pub language: Option<&'s str>, + pub switches: Option<&'s str>, + pub parameters: Option<&'s str>, pub number_lines: Option, pub retain_labels: RetainLabels, pub use_labels: bool,