From eb03342506c5042e51b24494b721f96b8528153e Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 18 Jul 2023 23:46:10 -0400 Subject: [PATCH 1/3] Add test cases. --- .../export_snippet/paragraph_break_precedent.org | 9 +++++++++ org_mode_samples/export_snippet/simple.org | 4 ++++ 2 files changed, 13 insertions(+) create mode 100644 org_mode_samples/export_snippet/paragraph_break_precedent.org create mode 100644 org_mode_samples/export_snippet/simple.org diff --git a/org_mode_samples/export_snippet/paragraph_break_precedent.org b/org_mode_samples/export_snippet/paragraph_break_precedent.org new file mode 100644 index 0000000..9911329 --- /dev/null +++ b/org_mode_samples/export_snippet/paragraph_break_precedent.org @@ -0,0 +1,9 @@ +@@latex: + + + +\documentclass[margin,11pt]{res} % default is 10 pt + + + +@@ diff --git a/org_mode_samples/export_snippet/simple.org b/org_mode_samples/export_snippet/simple.org new file mode 100644 index 0000000..c550e63 --- /dev/null +++ b/org_mode_samples/export_snippet/simple.org @@ -0,0 +1,4 @@ +@@html:@@This text is only bold for the html exporter@@html:@@ +@@latex: +\documentclass[margin,11pt]{res} % default is 10 pt +@@ From 1fb8ce9af64e4aa1075accc91d4a57206178ad0a Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Wed, 19 Jul 2023 00:09:16 -0400 Subject: [PATCH 2/3] Create structure for export snippets. --- src/compare/diff.rs | 25 +++++++++++++++++++++++++ src/parser/export_snippet.rs | 13 +++++++++++++ src/parser/mod.rs | 2 ++ src/parser/object.rs | 15 +++++++++++++++ src/parser/token.rs | 1 + 5 files changed, 56 insertions(+) create mode 100644 src/parser/export_snippet.rs diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 3ec5328..61f0479 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -16,6 +16,7 @@ use crate::parser::Element; use crate::parser::Entity; use crate::parser::ExampleBlock; use crate::parser::ExportBlock; +use crate::parser::ExportSnippet; use crate::parser::FixedWidthArea; use crate::parser::FootnoteDefinition; use crate::parser::GreaterBlock; @@ -158,6 +159,7 @@ fn compare_object<'s>( Object::OrgMacro(obj) => compare_org_macro(source, emacs, obj), Object::Entity(obj) => compare_entity(source, emacs, obj), Object::LatexFragment(obj) => compare_latex_fragment(source, emacs, obj), + Object::ExportSnippet(obj) => compare_export_snippet(source, emacs, obj), } } @@ -1288,3 +1290,26 @@ fn compare_latex_fragment<'s>( children: Vec::new(), }) } + +fn compare_export_snippet<'s>( + source: &'s str, + emacs: &'s Token<'s>, + rust: &'s ExportSnippet<'s>, +) -> Result> { + let mut this_status = DiffStatus::Good; + let emacs_name = "export-snippet"; + if assert_name(emacs, emacs_name).is_err() { + this_status = DiffStatus::Bad; + } + + if assert_bounds(source, emacs, rust).is_err() { + this_status = DiffStatus::Bad; + } + + Ok(DiffResult { + status: this_status, + name: emacs_name.to_owned(), + message: None, + children: Vec::new(), + }) +} diff --git a/src/parser/export_snippet.rs b/src/parser/export_snippet.rs new file mode 100644 index 0000000..08ad0b7 --- /dev/null +++ b/src/parser/export_snippet.rs @@ -0,0 +1,13 @@ +use super::Context; +use crate::error::Res; +use crate::parser::util::not_yet_implemented; +use crate::parser::ExportSnippet; + +#[tracing::instrument(ret, level = "debug")] +pub fn export_snippet<'r, 's>( + context: Context<'r, 's>, + input: &'s str, +) -> Res<&'s str, ExportSnippet<'s>> { + not_yet_implemented()?; + todo!() +} diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 0f41c30..45d687b 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -9,6 +9,7 @@ mod element; mod element_parser; mod entity; mod exiting; +mod export_snippet; mod fixed_width_area; mod footnote_definition; mod greater_block; @@ -73,6 +74,7 @@ pub use object::AngleLink; pub use object::Bold; pub use object::Code; pub use object::Entity; +pub use object::ExportSnippet; pub use object::Italic; pub use object::LatexFragment; pub use object::Object; diff --git a/src/parser/object.rs b/src/parser/object.rs index 7aa01f5..1a48673 100644 --- a/src/parser/object.rs +++ b/src/parser/object.rs @@ -17,6 +17,7 @@ pub enum Object<'s> { OrgMacro(OrgMacro<'s>), Entity(Entity<'s>), LatexFragment(LatexFragment<'s>), + ExportSnippet(ExportSnippet<'s>), } #[derive(Debug, PartialEq)] @@ -109,6 +110,13 @@ pub struct LatexFragment<'s> { pub source: &'s str, } +#[derive(Debug, PartialEq)] +pub struct ExportSnippet<'s> { + pub source: &'s str, + pub backend: &'s str, + pub contents: &'s str, +} + impl<'s> Source<'s> for Object<'s> { fn get_source(&'s self) -> &'s str { match self { @@ -127,6 +135,7 @@ impl<'s> Source<'s> for Object<'s> { Object::OrgMacro(obj) => obj.source, Object::Entity(obj) => obj.source, Object::LatexFragment(obj) => obj.source, + Object::ExportSnippet(obj) => obj.source, } } } @@ -214,3 +223,9 @@ impl<'s> Source<'s> for LatexFragment<'s> { self.source } } + +impl<'s> Source<'s> for ExportSnippet<'s> { + fn get_source(&'s self) -> &'s str { + self.source + } +} diff --git a/src/parser/token.rs b/src/parser/token.rs index 04deabf..c97cbe1 100644 --- a/src/parser/token.rs +++ b/src/parser/token.rs @@ -54,6 +54,7 @@ impl<'r, 's> Token<'r, 's> { Object::OrgMacro(_) => Box::new(std::iter::empty()), Object::Entity(_) => Box::new(std::iter::empty()), Object::LatexFragment(_) => Box::new(std::iter::empty()), + Object::ExportSnippet(_) => Box::new(std::iter::empty()), }, Token::Element(elem) => match elem { Element::Paragraph(inner) => Box::new(inner.children.iter().map(Token::Object)), From 95e033a99b073d79ce2ab504ea8188a3d487bbf0 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Wed, 19 Jul 2023 00:37:51 -0400 Subject: [PATCH 3/3] Implement the export snippet parser. --- src/parser/export_snippet.rs | 54 ++++++++++++++++++++++++++++++++++-- src/parser/latex_fragment.rs | 4 +-- src/parser/object.rs | 2 +- src/parser/object_parser.rs | 11 +++++++- 4 files changed, 64 insertions(+), 7 deletions(-) diff --git a/src/parser/export_snippet.rs b/src/parser/export_snippet.rs index 08ad0b7..9e54118 100644 --- a/src/parser/export_snippet.rs +++ b/src/parser/export_snippet.rs @@ -1,6 +1,19 @@ +use nom::branch::alt; +use nom::bytes::complete::tag; +use nom::character::complete::anychar; +use nom::combinator::opt; +use nom::combinator::peek; +use nom::combinator::recognize; +use nom::combinator::verify; +use nom::multi::many1; +use nom::multi::many_till; +use nom::sequence::tuple; + use super::Context; use crate::error::Res; -use crate::parser::util::not_yet_implemented; +use crate::parser::parser_with_context::parser_with_context; +use crate::parser::util::exit_matcher_parser; +use crate::parser::util::get_consumed; use crate::parser::ExportSnippet; #[tracing::instrument(ret, level = "debug")] @@ -8,6 +21,41 @@ pub fn export_snippet<'r, 's>( context: Context<'r, 's>, input: &'s str, ) -> Res<&'s str, ExportSnippet<'s>> { - not_yet_implemented()?; - todo!() + let (remaining, _) = tag("@@")(input)?; + let (remaining, backend_name) = backend(context, remaining)?; + let (remaining, backend_contents) = + opt(tuple((tag(":"), parser_with_context!(contents)(context))))(remaining)?; + let (remaining, _) = tag("@@")(remaining)?; + let source = get_consumed(input, remaining); + Ok(( + remaining, + ExportSnippet { + source, + backend: backend_name, + contents: backend_contents.map(|(_colon, backend_contents)| backend_contents), + }, + )) +} + +#[tracing::instrument(ret, level = "debug")] +fn backend<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, &'s str> { + let (remaining, backend_name) = + recognize(many1(verify(anychar, |c| c.is_alphanumeric() || *c == '-')))(input)?; + + Ok((remaining, backend_name)) +} + +#[tracing::instrument(ret, level = "debug")] +fn contents<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, &'s str> { + let (remaining, source) = recognize(verify( + many_till( + anychar, + peek(alt(( + parser_with_context!(exit_matcher_parser)(context), + tag("@@"), + ))), + ), + |(children, _exit_contents)| !children.is_empty(), + ))(input)?; + Ok((remaining, source)) } diff --git a/src/parser/latex_fragment.rs b/src/parser/latex_fragment.rs index 7f4e9d7..f12daaf 100644 --- a/src/parser/latex_fragment.rs +++ b/src/parser/latex_fragment.rs @@ -6,10 +6,10 @@ use nom::character::complete::line_ending; use nom::character::complete::none_of; use nom::character::complete::one_of; use nom::character::complete::space0; -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; use nom::sequence::tuple; @@ -45,7 +45,7 @@ pub fn latex_fragment<'r, 's>( fn raw_latex_fragment<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, &'s str> { let (remaining, _) = tag("\\")(input)?; let (remaining, _) = name(context, remaining)?; - let (remaining, _) = opt(parser_with_context!(brackets)(context))(remaining)?; + let (remaining, _) = many0(parser_with_context!(brackets)(context))(remaining)?; let source = get_consumed(input, remaining); Ok((remaining, source)) diff --git a/src/parser/object.rs b/src/parser/object.rs index 1a48673..9bd56ef 100644 --- a/src/parser/object.rs +++ b/src/parser/object.rs @@ -114,7 +114,7 @@ pub struct LatexFragment<'s> { pub struct ExportSnippet<'s> { pub source: &'s str, pub backend: &'s str, - pub contents: &'s str, + pub contents: Option<&'s str>, } impl<'s> Source<'s> for Object<'s> { diff --git a/src/parser/object_parser.rs b/src/parser/object_parser.rs index 437869e..e84992b 100644 --- a/src/parser/object_parser.rs +++ b/src/parser/object_parser.rs @@ -9,6 +9,7 @@ use super::Context; use crate::error::Res; use crate::parser::angle_link::angle_link; use crate::parser::entity::entity; +use crate::parser::export_snippet::export_snippet; use crate::parser::latex_fragment::latex_fragment; use crate::parser::object::Object; use crate::parser::org_macro::org_macro; @@ -22,10 +23,14 @@ pub fn standard_set_object<'r, 's>( context: Context<'r, 's>, input: &'s str, ) -> Res<&'s str, Object<'s>> { - // TODO: export snippets, footnote references, citations (NOT citation references), inline babel calls, inline source blocks, line breaks, links, macros, targets and radio targets, statistics cookies, subscript and superscript, timestamps, and text markup. + // TODO: footnote references, citations (NOT citation references), inline babel calls, inline source blocks, line breaks, links, macros, targets and radio targets, statistics cookies, subscript and superscript, timestamps, and text markup. not(|i| context.check_exit_matcher(i))(input)?; alt(( + map( + parser_with_context!(export_snippet)(context), + Object::ExportSnippet, + ), map(parser_with_context!(entity)(context), Object::Entity), map( parser_with_context!(latex_fragment)(context), @@ -74,6 +79,10 @@ pub fn any_object_except_plain_text<'r, 's>( ) -> Res<&'s str, Object<'s>> { // Used for exit matchers so this does not check exit matcher condition. alt(( + map( + parser_with_context!(export_snippet)(context), + Object::ExportSnippet, + ), map(parser_with_context!(entity)(context), Object::Entity), map( parser_with_context!(latex_fragment)(context),