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
+@@
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..9e54118
--- /dev/null
+++ b/src/parser/export_snippet.rs
@@ -0,0 +1,61 @@
+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::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")]
+pub fn export_snippet<'r, 's>(
+ context: Context<'r, 's>,
+ input: &'s str,
+) -> Res<&'s str, ExportSnippet<'s>> {
+ 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/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..9bd56ef 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: Option<&'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/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),
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)),