Compare src block parameters.

This commit is contained in:
Tom Alexander 2023-10-04 18:02:50 -04:00
parent 1ab7d2f2d7
commit f046b16c11
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
3 changed files with 83 additions and 21 deletions

View File

@ -1731,6 +1731,8 @@ fn compare_src_block<'b, 's>(
let mut this_status = DiffStatus::Good; let mut this_status = DiffStatus::Good;
let mut message = None; let mut message = None;
// TODO: Compare :parameters
// Compare language // Compare language
let language = get_property_quoted_string(emacs, ":language")?; let language = get_property_quoted_string(emacs, ":language")?;
if language.as_ref().map(String::as_str) != rust.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 // Compare number-lines
let number_lines = get_property(emacs, ":number-lines")?; let number_lines = get_property(emacs, ":number-lines")?;
match (number_lines, &rust.number_lines) { match (number_lines, &rust.number_lines) {

View File

@ -9,6 +9,7 @@ use nom::character::complete::space1;
use nom::combinator::consumed; use nom::combinator::consumed;
use nom::combinator::eof; use nom::combinator::eof;
use nom::combinator::map; use nom::combinator::map;
use nom::combinator::not;
use nom::combinator::opt; use nom::combinator::opt;
use nom::combinator::peek; use nom::combinator::peek;
use nom::combinator::recognize; use nom::combinator::recognize;
@ -24,6 +25,7 @@ use crate::context::ContextElement;
use crate::context::ContextMatcher; use crate::context::ContextMatcher;
use crate::context::ExitClass; use crate::context::ExitClass;
use crate::context::ExitMatcherNode; use crate::context::ExitMatcherNode;
use crate::context::Matcher;
use crate::context::RefContext; use crate::context::RefContext;
use crate::error::Res; use crate::error::Res;
use crate::parser::object_parser::standard_set_object; use crate::parser::object_parser::standard_set_object;
@ -238,7 +240,10 @@ pub(crate) fn src_block<'b, 'g, 'r, 's>(
) -> Res<OrgSource<'s>, SrcBlock<'s>> { ) -> Res<OrgSource<'s>, SrcBlock<'s>> {
let (remaining, _name) = lesser_block_begin("src")(context, input)?; 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. // 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 (remaining, _nl) = recognize(tuple((space0, line_ending)))(remaining)?;
let lesser_block_end_specialized = lesser_block_end("src"); let lesser_block_end_specialized = lesser_block_end("src");
let contexts = [ 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 = 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[1]);
let parser_context = parser_context.with_additional_node(&contexts[2]); let parser_context = parser_context.with_additional_node(&contexts[2]);
let parameters = match parameters { let switches = match switches {
Some((_ws, parameters)) => Some(parameters), Some((_ws, switches)) => Some(switches),
None => None, None => None,
}; };
@ -262,18 +267,18 @@ pub(crate) fn src_block<'b, 'g, 'r, 's>(
let source = get_consumed(input, remaining); let source = get_consumed(input, remaining);
let (switches, language, number_lines, retain_labels, use_labels, label_format) = { 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 None
} else { } else {
Some(parameters.source) Some(switches.source)
}, },
parameters.language, switches.language,
parameters.number_lines, switches.number_lines,
parameters.retain_labels, switches.retain_labels,
parameters.use_labels, switches.use_labels,
parameters.label_format, switches.label_format,
) )
} else { } else {
(None, None, None, RetainLabels::Yes, true, None) (None, None, None, RetainLabels::Yes, true, None)
@ -283,8 +288,9 @@ pub(crate) fn src_block<'b, 'g, 'r, 's>(
remaining, remaining,
SrcBlock { SrcBlock {
source: source.into(), source: source.into(),
switches,
language, language,
switches,
parameters: parameters.map(Into::<&str>::into),
number_lines, number_lines,
retain_labels, retain_labels,
use_labels, use_labels,
@ -371,28 +377,35 @@ enum SwitchState {
LabelFormat, LabelFormat,
} }
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
fn src_parameters<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
recognize(is_not("\r\n"))(input)
}
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
fn src_switches<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, ExampleSrcSwitches<'s>> { fn src_switches<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, ExampleSrcSwitches<'s>> {
example_src_switches(true)(input) example_src_switches(true, true)(input)
} }
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
fn example_switches<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, ExampleSrcSwitches<'s>> { fn example_switches<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, 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()); debug_assert!(switches.language.is_none());
Ok((remaining, switches)) Ok((remaining, switches))
} }
fn example_src_switches( fn example_src_switches(
grab_language: bool, grab_language: bool,
stop_at_parameters: bool,
) -> impl for<'s> Fn(OrgSource<'s>) -> Res<OrgSource<'s>, ExampleSrcSwitches<'s>> { ) -> impl for<'s> Fn(OrgSource<'s>) -> Res<OrgSource<'s>, 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"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
fn _example_src_switches<'s>( fn _example_src_switches<'s>(
input: OrgSource<'s>, input: OrgSource<'s>,
grab_language: bool, grab_language: bool,
stop_at_parameters: bool,
) -> Res<OrgSource<'s>, ExampleSrcSwitches<'s>> { ) -> Res<OrgSource<'s>, ExampleSrcSwitches<'s>> {
let mut number_lines = None; let mut number_lines = None;
let mut retain_labels = RetainLabels::Yes; let mut retain_labels = RetainLabels::Yes;
@ -402,17 +415,23 @@ fn _example_src_switches<'s>(
let mut language = None; let mut language = None;
let remaining = if grab_language { 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); language = first_word.map(Into::<&str>::into);
remain remain
} else { } else {
input input
}; };
let (remaining, (source, (words, _))) = if language.is_none() { let (remaining, (source, words)) = if language.is_none() {
consumed(tuple((separated_list1(space1, switch_word), space0)))(remaining)? consumed(separated_list1(space1, switch_word(stop_at_parameters)))(remaining)?
} else { } 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; 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 { let retain_labels = match retain_labels {
RetainLabels::Keep(_) if !saw_r => RetainLabels::Yes, RetainLabels::Keep(_) if !saw_r => RetainLabels::Yes,
_ => retain_labels, _ => 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"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
fn switch_word<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> { fn _switch_word<'s>(
input: OrgSource<'s>,
stop_at_parameters: bool,
) -> Res<OrgSource<'s>, OrgSource<'s>> {
if stop_at_parameters {
not(tag(":"))(input)?;
}
alt(( alt((
map( map(
tuple((tag(r#"""#), is_not("\"\r\n"), tag(r#"""#))), tuple((tag(r#"""#), is_not("\"\r\n"), tag(r#"""#))),

View File

@ -67,8 +67,9 @@ pub struct ExportBlock<'s> {
#[derive(Debug)] #[derive(Debug)]
pub struct SrcBlock<'s> { pub struct SrcBlock<'s> {
pub source: &'s str, pub source: &'s str,
pub switches: Option<&'s str>,
pub language: Option<&'s str>, pub language: Option<&'s str>,
pub switches: Option<&'s str>,
pub parameters: Option<&'s str>,
pub number_lines: Option<SwitchNumberLines>, pub number_lines: Option<SwitchNumberLines>,
pub retain_labels: RetainLabels, pub retain_labels: RetainLabels,
pub use_labels: bool, pub use_labels: bool,