diff --git a/default_environment/templates/html/ast_node.dust b/default_environment/templates/html/ast_node.dust
new file mode 100644
index 0000000..cb3b7a9
--- /dev/null
+++ b/default_environment/templates/html/ast_node.dust
@@ -0,0 +1,57 @@
+{@select key=.type}
+ {@eq value="heading"}{>heading/}{/eq}
+ {@eq value="section"}{>section/}{/eq}
+ {@eq value="paragraph"}{>paragraph/}{/eq}
+ {@eq value="plain_list"}{>plain_list/}{/eq}
+ {@eq value="center_block"}{>center_block/}{/eq}
+ {@eq value="quote_block"}{>quote_block/}{/eq}
+ {@eq value="special_block"}{>special_block/}{/eq}
+ {@eq value="dynamic_block"}{>dynamic_block/}{/eq}
+ {@eq value="footnote_definition"}{>footnote_definition/}{/eq}
+ {@eq value="comment"}{>comment/}{/eq}
+ {@eq value="drawer"}{>drawer/}{/eq}
+ {@eq value="property_drawer"}{>property_drawer/}{/eq}
+ {@eq value="table"}{>table/}{/eq}
+ {@eq value="verse_block"}{>verse_block/}{/eq}
+ {@eq value="comment_block"}{>comment_block/}{/eq}
+ {@eq value="example_block"}{>example_block/}{/eq}
+ {@eq value="export_block"}{>export_block/}{/eq}
+ {@eq value="src_block"}{>src_block/}{/eq}
+ {@eq value="clock"}{>clock/}{/eq}
+ {@eq value="diary_sexp"}{>diary_sexp/}{/eq}
+ {@eq value="planning"}{>planning/}{/eq}
+ {@eq value="fixed_width_area"}{>fixed_width_area/}{/eq}
+ {@eq value="horizontal_rule"}{>horizontal_rule/}{/eq}
+ {@eq value="keyword"}{>keyword/}{/eq}
+ {@eq value="babel_call"}{>babel_call/}{/eq}
+ {@eq value="latex_environment"}{>latex_environment/}{/eq}
+ {@eq value="bold"}{>bold/}{/eq}
+ {@eq value="italic"}{>italic/}{/eq}
+ {@eq value="underline"}{>underline/}{/eq}
+ {@eq value="strike_through"}{>strike_through/}{/eq}
+ {@eq value="code"}{>code/}{/eq}
+ {@eq value="verbatim"}{>verbatim/}{/eq}
+ {@eq value="plain_text"}{>plain_text/}{/eq}
+ {@eq value="regular_link"}{>regular_link/}{/eq}
+ {@eq value="radio_link"}{>radio_link/}{/eq}
+ {@eq value="radio_target"}{>radio_target/}{/eq}
+ {@eq value="plain_link"}{>plain_link/}{/eq}
+ {@eq value="angle_link"}{>angle_link/}{/eq}
+ {@eq value="org_macro"}{>org_macro/}{/eq}
+ {@eq value="entity"}{>entity/}{/eq}
+ {@eq value="latex_fragment"}{>latex_fragment/}{/eq}
+ {@eq value="export_snippet"}{>export_snippet/}{/eq}
+ {@eq value="footnote_reference"}{>footnote_reference/}{/eq}
+ {@eq value="citation"}{>citation/}{/eq}
+ {@eq value="citation_reference"}{>citation_reference/}{/eq}
+ {@eq value="inline_babel_call"}{>inline_babel_call/}{/eq}
+ {@eq value="inline_source_block"}{>inline_source_block/}{/eq}
+ {@eq value="line_break"}{>line_break/}{/eq}
+ {@eq value="target"}{>target/}{/eq}
+ {@eq value="statistics_cookie"}{>statistics_cookie/}{/eq}
+ {@eq value="subscript"}{>subscript/}{/eq}
+ {@eq value="superscript"}{>superscript/}{/eq}
+ {@eq value="timestamp"}{>timestamp/}{/eq}
+ {@none}{!TODO: make this panic!}ERROR: Unrecognized type {.type}.{/none}
+{/select}
+{! TODO: Maybe the final space should be conditional on end blank in the org source !}
diff --git a/default_environment/templates/html/blog_post_page.dust b/default_environment/templates/html/blog_post_page.dust
index 361823b..067b223 100644
--- a/default_environment/templates/html/blog_post_page.dust
+++ b/default_environment/templates/html/blog_post_page.dust
@@ -10,5 +10,12 @@
{#.children}
{>document_element/}
{/.children}
+
+ {?.footnotes}
+
Footnotes:
+ {#.footnotes}
+ {>real_footnote_definition/}
+ {/.footnotes}
+ {/.footnotes}
diff --git a/default_environment/templates/html/footnote_definition.dust b/default_environment/templates/html/footnote_definition.dust
index 037c32c..9cf5738 100644
--- a/default_environment/templates/html/footnote_definition.dust
+++ b/default_environment/templates/html/footnote_definition.dust
@@ -1 +1 @@
-!!!!!!!! footnote_definition
+{! noop !}
diff --git a/default_environment/templates/html/footnote_reference.dust b/default_environment/templates/html/footnote_reference.dust
index ae1f616..a218064 100644
--- a/default_environment/templates/html/footnote_reference.dust
+++ b/default_environment/templates/html/footnote_reference.dust
@@ -1 +1 @@
-!!!!!!!! footnote_reference
+{.label}
diff --git a/default_environment/templates/html/real_footnote_definition.dust b/default_environment/templates/html/real_footnote_definition.dust
new file mode 100644
index 0000000..9c6be4b
--- /dev/null
+++ b/default_environment/templates/html/real_footnote_definition.dust
@@ -0,0 +1 @@
+{.label}{#.contents}{>ast_node/}{/.contents}
diff --git a/org_test_documents/footnotes/reference_in_definition.org b/org_test_documents/footnotes/reference_in_definition.org
new file mode 100644
index 0000000..01f8b5e
--- /dev/null
+++ b/org_test_documents/footnotes/reference_in_definition.org
@@ -0,0 +1,21 @@
+# This test shows that footnote references only count if the definition containing them is rendered.
+
+foo[fn:a:bar]
+
+[fn:a] lorem
+
+[fn:b] ipsum
+
+[fn:d] fizz
+
+[fn:c] dolar
+
+yo[fn:b]
+
+
+hello[fn:c]
+
+
+[fn:e] buzz
+
+sup[fn:d]
diff --git a/org_test_documents/footnotes/simple.org b/org_test_documents/footnotes/simple.org
new file mode 100644
index 0000000..8a15e71
--- /dev/null
+++ b/org_test_documents/footnotes/simple.org
@@ -0,0 +1,25 @@
+# Test proves that:
+#
+# - Anonymous references with identical content get unique IDs.
+# - Unreferenced footnote definitions are dropped.
+# - Footnote definitions that come before their first reference are dropped.
+
+foo[fn:2:something]
+
+bar[fn::something]
+
+baz[fn::something]
+
+cat[fn::something]
+
+dog[fn:3]
+
+[fn:3] ipsum
+
+[fn:4] lorem
+
+[fn:3] dolar
+
+[fn:5] not referenced
+
+stuff[fn:4] and things
diff --git a/src/context/ast_node.rs b/src/context/ast_node.rs
new file mode 100644
index 0000000..7a2ffcd
--- /dev/null
+++ b/src/context/ast_node.rs
@@ -0,0 +1,407 @@
+use std::path::Path;
+
+use serde::Serialize;
+
+use crate::config::Config;
+use crate::error::CustomError;
+use crate::intermediate::IAstNode;
+
+use super::angle_link::RenderAngleLink;
+use super::babel_call::RenderBabelCall;
+use super::bold::RenderBold;
+use super::center_block::RenderCenterBlock;
+use super::citation::RenderCitation;
+use super::citation_reference::RenderCitationReference;
+use super::clock::RenderClock;
+use super::code::RenderCode;
+use super::comment::RenderComment;
+use super::comment_block::RenderCommentBlock;
+use super::diary_sexp::RenderDiarySexp;
+use super::drawer::RenderDrawer;
+use super::dynamic_block::RenderDynamicBlock;
+use super::entity::RenderEntity;
+use super::example_block::RenderExampleBlock;
+use super::export_block::RenderExportBlock;
+use super::export_snippet::RenderExportSnippet;
+use super::fixed_width_area::RenderFixedWidthArea;
+use super::footnote_definition::RenderFootnoteDefinition;
+use super::footnote_reference::RenderFootnoteReference;
+use super::horizontal_rule::RenderHorizontalRule;
+use super::inline_babel_call::RenderInlineBabelCall;
+use super::inline_source_block::RenderInlineSourceBlock;
+use super::italic::RenderItalic;
+use super::keyword::RenderKeyword;
+use super::latex_environment::RenderLatexEnvironment;
+use super::latex_fragment::RenderLatexFragment;
+use super::line_break::RenderLineBreak;
+use super::org_macro::RenderOrgMacro;
+use super::paragraph::RenderParagraph;
+use super::plain_link::RenderPlainLink;
+use super::plain_list::RenderPlainList;
+use super::plain_text::RenderPlainText;
+use super::planning::RenderPlanning;
+use super::property_drawer::RenderPropertyDrawer;
+use super::quote_block::RenderQuoteBlock;
+use super::radio_link::RenderRadioLink;
+use super::radio_target::RenderRadioTarget;
+use super::regular_link::RenderRegularLink;
+use super::special_block::RenderSpecialBlock;
+use super::src_block::RenderSrcBlock;
+use super::statistics_cookie::RenderStatisticsCookie;
+use super::strike_through::RenderStrikeThrough;
+use super::subscript::RenderSubscript;
+use super::superscript::RenderSuperscript;
+use super::table::RenderTable;
+use super::target::RenderTarget;
+use super::timestamp::RenderTimestamp;
+use super::underline::RenderUnderline;
+use super::verbatim::RenderVerbatim;
+use super::verse_block::RenderVerseBlock;
+use super::RenderHeading;
+use super::RenderSection;
+
+#[derive(Debug, Serialize)]
+#[serde(untagged)]
+pub(crate) enum RenderAstNode {
+ Heading(RenderHeading),
+ Section(RenderSection),
+ Paragraph(RenderParagraph),
+ PlainList(RenderPlainList),
+ CenterBlock(RenderCenterBlock),
+ QuoteBlock(RenderQuoteBlock),
+ SpecialBlock(RenderSpecialBlock),
+ DynamicBlock(RenderDynamicBlock),
+ FootnoteDefinition(RenderFootnoteDefinition),
+ Comment(RenderComment),
+ Drawer(RenderDrawer),
+ PropertyDrawer(RenderPropertyDrawer),
+ Table(RenderTable),
+ VerseBlock(RenderVerseBlock),
+ CommentBlock(RenderCommentBlock),
+ ExampleBlock(RenderExampleBlock),
+ ExportBlock(RenderExportBlock),
+ SrcBlock(RenderSrcBlock),
+ Clock(RenderClock),
+ DiarySexp(RenderDiarySexp),
+ Planning(RenderPlanning),
+ FixedWidthArea(RenderFixedWidthArea),
+ HorizontalRule(RenderHorizontalRule),
+ Keyword(RenderKeyword),
+ BabelCall(RenderBabelCall),
+ LatexEnvironment(RenderLatexEnvironment),
+ Bold(RenderBold),
+ Italic(RenderItalic),
+ Underline(RenderUnderline),
+ StrikeThrough(RenderStrikeThrough),
+ Code(RenderCode),
+ Verbatim(RenderVerbatim),
+ PlainText(RenderPlainText),
+ RegularLink(RenderRegularLink),
+ RadioLink(RenderRadioLink),
+ RadioTarget(RenderRadioTarget),
+ PlainLink(RenderPlainLink),
+ AngleLink(RenderAngleLink),
+ OrgMacro(RenderOrgMacro),
+ Entity(RenderEntity),
+ LatexFragment(RenderLatexFragment),
+ ExportSnippet(RenderExportSnippet),
+ FootnoteReference(RenderFootnoteReference),
+ Citation(RenderCitation),
+ CitationReference(RenderCitationReference),
+ InlineBabelCall(RenderInlineBabelCall),
+ InlineSourceBlock(RenderInlineSourceBlock),
+ LineBreak(RenderLineBreak),
+ Target(RenderTarget),
+ StatisticsCookie(RenderStatisticsCookie),
+ Subscript(RenderSubscript),
+ Superscript(RenderSuperscript),
+ Timestamp(RenderTimestamp),
+}
+
+pub(crate) trait IntoRenderAstNode {
+ fn into_render_ast_node(
+ &self,
+ config: &Config,
+ output_directory: &Path,
+ output_file: &Path,
+ ) -> Result;
+}
+
+impl IntoRenderAstNode for IAstNode {
+ fn into_render_ast_node(
+ &self,
+ config: &Config,
+ output_directory: &Path,
+ output_file: &Path,
+ ) -> Result {
+ match self {
+ IAstNode::Heading(inner) => Ok(RenderAstNode::Heading(RenderHeading::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::Section(inner) => Ok(RenderAstNode::Section(RenderSection::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::Paragraph(inner) => Ok(RenderAstNode::Paragraph(RenderParagraph::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::PlainList(inner) => Ok(RenderAstNode::PlainList(RenderPlainList::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::CenterBlock(inner) => Ok(RenderAstNode::CenterBlock(RenderCenterBlock::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::QuoteBlock(inner) => Ok(RenderAstNode::QuoteBlock(RenderQuoteBlock::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::SpecialBlock(inner) => Ok(RenderAstNode::SpecialBlock(
+ RenderSpecialBlock::new(config, output_directory, output_file, inner)?,
+ )),
+ IAstNode::DynamicBlock(inner) => Ok(RenderAstNode::DynamicBlock(
+ RenderDynamicBlock::new(config, output_directory, output_file, inner)?,
+ )),
+ IAstNode::FootnoteDefinition(inner) => Ok(RenderAstNode::FootnoteDefinition(
+ RenderFootnoteDefinition::new(config, output_directory, output_file, inner)?,
+ )),
+ IAstNode::Comment(inner) => Ok(RenderAstNode::Comment(RenderComment::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::Drawer(inner) => Ok(RenderAstNode::Drawer(RenderDrawer::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::PropertyDrawer(inner) => Ok(RenderAstNode::PropertyDrawer(
+ RenderPropertyDrawer::new(config, output_directory, output_file, inner)?,
+ )),
+ IAstNode::Table(inner) => Ok(RenderAstNode::Table(RenderTable::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::VerseBlock(inner) => Ok(RenderAstNode::VerseBlock(RenderVerseBlock::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::CommentBlock(inner) => Ok(RenderAstNode::CommentBlock(
+ RenderCommentBlock::new(config, output_directory, output_file, inner)?,
+ )),
+ IAstNode::ExampleBlock(inner) => Ok(RenderAstNode::ExampleBlock(
+ RenderExampleBlock::new(config, output_directory, output_file, inner)?,
+ )),
+ IAstNode::ExportBlock(inner) => Ok(RenderAstNode::ExportBlock(RenderExportBlock::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::SrcBlock(inner) => Ok(RenderAstNode::SrcBlock(RenderSrcBlock::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::Clock(inner) => Ok(RenderAstNode::Clock(RenderClock::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::DiarySexp(inner) => Ok(RenderAstNode::DiarySexp(RenderDiarySexp::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::Planning(inner) => Ok(RenderAstNode::Planning(RenderPlanning::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::FixedWidthArea(inner) => Ok(RenderAstNode::FixedWidthArea(
+ RenderFixedWidthArea::new(config, output_directory, output_file, inner)?,
+ )),
+ IAstNode::HorizontalRule(inner) => Ok(RenderAstNode::HorizontalRule(
+ RenderHorizontalRule::new(config, output_directory, output_file, inner)?,
+ )),
+ IAstNode::Keyword(inner) => Ok(RenderAstNode::Keyword(RenderKeyword::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::BabelCall(inner) => Ok(RenderAstNode::BabelCall(RenderBabelCall::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::LatexEnvironment(inner) => Ok(RenderAstNode::LatexEnvironment(
+ RenderLatexEnvironment::new(config, output_directory, output_file, inner)?,
+ )),
+ IAstNode::Bold(inner) => Ok(RenderAstNode::Bold(RenderBold::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::Italic(inner) => Ok(RenderAstNode::Italic(RenderItalic::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::Underline(inner) => Ok(RenderAstNode::Underline(RenderUnderline::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::StrikeThrough(inner) => Ok(RenderAstNode::StrikeThrough(
+ RenderStrikeThrough::new(config, output_directory, output_file, inner)?,
+ )),
+ IAstNode::Code(inner) => Ok(RenderAstNode::Code(RenderCode::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::Verbatim(inner) => Ok(RenderAstNode::Verbatim(RenderVerbatim::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::PlainText(inner) => Ok(RenderAstNode::PlainText(RenderPlainText::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::RegularLink(inner) => Ok(RenderAstNode::RegularLink(RenderRegularLink::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::RadioLink(inner) => Ok(RenderAstNode::RadioLink(RenderRadioLink::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::RadioTarget(inner) => Ok(RenderAstNode::RadioTarget(RenderRadioTarget::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::PlainLink(inner) => Ok(RenderAstNode::PlainLink(RenderPlainLink::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::AngleLink(inner) => Ok(RenderAstNode::AngleLink(RenderAngleLink::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::OrgMacro(inner) => Ok(RenderAstNode::OrgMacro(RenderOrgMacro::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::Entity(inner) => Ok(RenderAstNode::Entity(RenderEntity::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::LatexFragment(inner) => Ok(RenderAstNode::LatexFragment(
+ RenderLatexFragment::new(config, output_directory, output_file, inner)?,
+ )),
+ IAstNode::ExportSnippet(inner) => Ok(RenderAstNode::ExportSnippet(
+ RenderExportSnippet::new(config, output_directory, output_file, inner)?,
+ )),
+ IAstNode::FootnoteReference(inner) => Ok(RenderAstNode::FootnoteReference(
+ RenderFootnoteReference::new(config, output_directory, output_file, inner)?,
+ )),
+ IAstNode::Citation(inner) => Ok(RenderAstNode::Citation(RenderCitation::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::CitationReference(inner) => Ok(RenderAstNode::CitationReference(
+ RenderCitationReference::new(config, output_directory, output_file, inner)?,
+ )),
+ IAstNode::InlineBabelCall(inner) => Ok(RenderAstNode::InlineBabelCall(
+ RenderInlineBabelCall::new(config, output_directory, output_file, inner)?,
+ )),
+ IAstNode::InlineSourceBlock(inner) => Ok(RenderAstNode::InlineSourceBlock(
+ RenderInlineSourceBlock::new(config, output_directory, output_file, inner)?,
+ )),
+ IAstNode::LineBreak(inner) => Ok(RenderAstNode::LineBreak(RenderLineBreak::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::Target(inner) => Ok(RenderAstNode::Target(RenderTarget::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::StatisticsCookie(inner) => Ok(RenderAstNode::StatisticsCookie(
+ RenderStatisticsCookie::new(config, output_directory, output_file, inner)?,
+ )),
+ IAstNode::Subscript(inner) => Ok(RenderAstNode::Subscript(RenderSubscript::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::Superscript(inner) => Ok(RenderAstNode::Superscript(RenderSuperscript::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ IAstNode::Timestamp(inner) => Ok(RenderAstNode::Timestamp(RenderTimestamp::new(
+ config,
+ output_directory,
+ output_file,
+ inner,
+ )?)),
+ }
+ }
+}
diff --git a/src/context/blog_post_page.rs b/src/context/blog_post_page.rs
index 9f607ce..a8720f7 100644
--- a/src/context/blog_post_page.rs
+++ b/src/context/blog_post_page.rs
@@ -1,5 +1,6 @@
use serde::Serialize;
+use super::footnote_definition::RenderRealFootnoteDefinition;
use super::GlobalSettings;
use super::RenderDocumentElement;
@@ -15,6 +16,8 @@ pub(crate) struct RenderBlogPostPage {
self_link: Option,
children: Vec,
+
+ footnotes: Vec,
}
impl RenderBlogPostPage {
@@ -23,12 +26,14 @@ impl RenderBlogPostPage {
title: Option,
self_link: Option,
children: Vec,
+ footnotes: Vec,
) -> RenderBlogPostPage {
RenderBlogPostPage {
global_settings,
title,
self_link,
children,
+ footnotes,
}
}
}
diff --git a/src/context/footnote_definition.rs b/src/context/footnote_definition.rs
index 589658e..877ec42 100644
--- a/src/context/footnote_definition.rs
+++ b/src/context/footnote_definition.rs
@@ -5,6 +5,10 @@ use serde::Serialize;
use crate::config::Config;
use crate::error::CustomError;
use crate::intermediate::IFootnoteDefinition;
+use crate::intermediate::IRealFootnoteDefinition;
+
+use super::ast_node::IntoRenderAstNode;
+use super::ast_node::RenderAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
@@ -21,3 +25,37 @@ impl RenderFootnoteDefinition {
Ok(RenderFootnoteDefinition {})
}
}
+
+#[derive(Debug, Serialize)]
+#[serde(tag = "type")]
+#[serde(rename = "footnote_reference")]
+pub(crate) struct RenderRealFootnoteDefinition {
+ definition_id: String,
+ reference_link: String,
+ label: String,
+ contents: Vec,
+}
+
+impl RenderRealFootnoteDefinition {
+ pub(crate) fn new(
+ config: &Config,
+ output_directory: &Path,
+ output_file: &Path,
+ original: &IRealFootnoteDefinition,
+ ) -> Result {
+ let contents = {
+ let mut ret = Vec::new();
+ for obj in original.contents.iter() {
+ ret.push(obj.into_render_ast_node(config, output_directory, output_file)?);
+ }
+ ret
+ };
+
+ Ok(RenderRealFootnoteDefinition {
+ definition_id: original.get_definition_id(),
+ reference_link: format!("#{}", original.get_reference_id()),
+ label: original.get_display_label(),
+ contents,
+ })
+ }
+}
diff --git a/src/context/footnote_reference.rs b/src/context/footnote_reference.rs
index 300517e..11d1622 100644
--- a/src/context/footnote_reference.rs
+++ b/src/context/footnote_reference.rs
@@ -9,15 +9,23 @@ use crate::intermediate::IFootnoteReference;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "footnote_reference")]
-pub(crate) struct RenderFootnoteReference {}
+pub(crate) struct RenderFootnoteReference {
+ reference_id: String,
+ definition_link: String,
+ label: String,
+}
impl RenderFootnoteReference {
pub(crate) fn new(
config: &Config,
output_directory: &Path,
output_file: &Path,
- comment: &IFootnoteReference,
+ original: &IFootnoteReference,
) -> Result {
- Ok(RenderFootnoteReference {})
+ Ok(RenderFootnoteReference {
+ reference_id: original.get_reference_id(),
+ definition_link: format!("#{}", original.get_definition_id()),
+ label: original.get_display_label(),
+ })
}
}
diff --git a/src/context/heading.rs b/src/context/heading.rs
index ec6399f..d69f659 100644
--- a/src/context/heading.rs
+++ b/src/context/heading.rs
@@ -30,8 +30,8 @@ impl RenderHeading {
for obj in heading.title.iter() {
ret.push(RenderObject::new(
config,
- &output_directory,
- &output_file,
+ output_directory,
+ output_file,
obj,
)?);
}
@@ -43,8 +43,8 @@ impl RenderHeading {
for obj in heading.children.iter() {
ret.push(RenderDocumentElement::new(
config,
- &output_directory,
- &output_file,
+ output_directory,
+ output_file,
obj,
)?);
}
diff --git a/src/context/mod.rs b/src/context/mod.rs
index 25ae64c..129ebca 100644
--- a/src/context/mod.rs
+++ b/src/context/mod.rs
@@ -1,4 +1,5 @@
mod angle_link;
+mod ast_node;
mod babel_call;
mod blog_post_page;
mod bold;
@@ -61,6 +62,7 @@ mod verse_block;
pub(crate) use blog_post_page::RenderBlogPostPage;
pub(crate) use document_element::RenderDocumentElement;
pub(crate) use element::RenderElement;
+pub(crate) use footnote_definition::RenderRealFootnoteDefinition;
pub(crate) use global_settings::GlobalSettings;
pub(crate) use heading::RenderHeading;
pub(crate) use object::RenderObject;
diff --git a/src/context/paragraph.rs b/src/context/paragraph.rs
index 2e0e1c3..c211535 100644
--- a/src/context/paragraph.rs
+++ b/src/context/paragraph.rs
@@ -27,8 +27,8 @@ impl RenderParagraph {
for obj in paragraph.children.iter() {
ret.push(RenderObject::new(
config,
- &output_directory,
- &output_file,
+ output_directory,
+ output_file,
obj,
)?);
}
diff --git a/src/context/plain_list.rs b/src/context/plain_list.rs
index b6b61b9..25840b8 100644
--- a/src/context/plain_list.rs
+++ b/src/context/plain_list.rs
@@ -33,8 +33,8 @@ impl RenderPlainList {
for obj in original.children.iter() {
ret.push(RenderPlainListItem::new(
config,
- &output_directory,
- &output_file,
+ output_directory,
+ output_file,
obj,
)?);
}
diff --git a/src/context/plain_list_item.rs b/src/context/plain_list_item.rs
index 0cfe106..df18dee 100644
--- a/src/context/plain_list_item.rs
+++ b/src/context/plain_list_item.rs
@@ -29,8 +29,8 @@ impl RenderPlainListItem {
for obj in original.tag.iter() {
ret.push(RenderObject::new(
config,
- &output_directory,
- &output_file,
+ output_directory,
+ output_file,
obj,
)?);
}
@@ -42,8 +42,8 @@ impl RenderPlainListItem {
for obj in original.children.iter() {
ret.push(RenderElement::new(
config,
- &output_directory,
- &output_file,
+ output_directory,
+ output_file,
obj,
)?);
}
diff --git a/src/context/quote_block.rs b/src/context/quote_block.rs
index 8a5d7f0..5866442 100644
--- a/src/context/quote_block.rs
+++ b/src/context/quote_block.rs
@@ -27,8 +27,8 @@ impl RenderQuoteBlock {
for obj in original.children.iter() {
ret.push(RenderElement::new(
config,
- &output_directory,
- &output_file,
+ output_directory,
+ output_file,
obj,
)?);
}
diff --git a/src/context/regular_link.rs b/src/context/regular_link.rs
index 0cecb38..58ccd4a 100644
--- a/src/context/regular_link.rs
+++ b/src/context/regular_link.rs
@@ -28,8 +28,8 @@ impl RenderRegularLink {
for obj in regular_link.children.iter() {
ret.push(RenderObject::new(
config,
- &output_directory,
- &output_file,
+ output_directory,
+ output_file,
obj,
)?);
}
diff --git a/src/context/section.rs b/src/context/section.rs
index 45d66bf..87c5a12 100644
--- a/src/context/section.rs
+++ b/src/context/section.rs
@@ -27,8 +27,8 @@ impl RenderSection {
for obj in section.children.iter() {
ret.push(RenderElement::new(
config,
- &output_directory,
- &output_file,
+ output_directory,
+ output_file,
obj,
)?);
}
diff --git a/src/intermediate/angle_link.rs b/src/intermediate/angle_link.rs
index bd84243..736def0 100644
--- a/src/intermediate/angle_link.rs
+++ b/src/intermediate/angle_link.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct IAngleLink {}
-
-impl IAngleLink {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::AngleLink<'parse>,
- ) -> Result {
- Ok(IAngleLink {})
- }
-}
+inoop!(IAngleLink, AngleLink);
diff --git a/src/intermediate/ast_node.rs b/src/intermediate/ast_node.rs
new file mode 100644
index 0000000..c205e19
--- /dev/null
+++ b/src/intermediate/ast_node.rs
@@ -0,0 +1,319 @@
+use super::angle_link::IAngleLink;
+use super::bold::IBold;
+use super::citation::ICitation;
+use super::citation_reference::ICitationReference;
+use super::code::ICode;
+use super::comment::IComment;
+use super::entity::IEntity;
+use super::export_snippet::IExportSnippet;
+use super::footnote_reference::IFootnoteReference;
+use super::inline_babel_call::IInlineBabelCall;
+use super::inline_source_block::IInlineSourceBlock;
+use super::italic::IItalic;
+use super::keyword::IKeyword;
+use super::latex_fragment::ILatexFragment;
+use super::line_break::ILineBreak;
+use super::org_macro::IOrgMacro;
+use super::plain_link::IPlainLink;
+use super::plain_text::IPlainText;
+use super::radio_link::IRadioLink;
+use super::radio_target::IRadioTarget;
+use super::registry::Registry;
+use super::regular_link::IRegularLink;
+use super::statistics_cookie::IStatisticsCookie;
+use super::strike_through::IStrikeThrough;
+use super::subscript::ISubscript;
+use super::superscript::ISuperscript;
+use super::IBabelCall;
+use super::ICenterBlock;
+use super::IClock;
+use super::ICommentBlock;
+use super::IDiarySexp;
+use super::IDrawer;
+use super::IDynamicBlock;
+use super::IExampleBlock;
+use super::IExportBlock;
+use super::IFixedWidthArea;
+use super::IFootnoteDefinition;
+use super::IHeading;
+use super::IHorizontalRule;
+use super::ILatexEnvironment;
+use super::IParagraph;
+use super::IPlainList;
+use super::IPlanning;
+use super::IPropertyDrawer;
+use super::IQuoteBlock;
+use super::ISection;
+use super::ISpecialBlock;
+use super::ISrcBlock;
+use super::ITable;
+use super::ITarget;
+use super::ITimestamp;
+use super::IUnderline;
+use super::IVerbatim;
+use super::IVerseBlock;
+use super::RefRegistry;
+use crate::error::CustomError;
+use futures::future::{BoxFuture, FutureExt};
+
+#[derive(Debug, Clone)]
+pub(crate) enum IAstNode {
+ Heading(IHeading),
+ Section(ISection),
+ Paragraph(IParagraph),
+ PlainList(IPlainList),
+ CenterBlock(ICenterBlock),
+ QuoteBlock(IQuoteBlock),
+ SpecialBlock(ISpecialBlock),
+ DynamicBlock(IDynamicBlock),
+ FootnoteDefinition(IFootnoteDefinition),
+ Comment(IComment),
+ Drawer(IDrawer),
+ PropertyDrawer(IPropertyDrawer),
+ Table(ITable),
+ VerseBlock(IVerseBlock),
+ CommentBlock(ICommentBlock),
+ ExampleBlock(IExampleBlock),
+ ExportBlock(IExportBlock),
+ SrcBlock(ISrcBlock),
+ Clock(IClock),
+ DiarySexp(IDiarySexp),
+ Planning(IPlanning),
+ FixedWidthArea(IFixedWidthArea),
+ HorizontalRule(IHorizontalRule),
+ Keyword(IKeyword),
+ BabelCall(IBabelCall),
+ LatexEnvironment(ILatexEnvironment),
+ Bold(IBold),
+ Italic(IItalic),
+ Underline(IUnderline),
+ StrikeThrough(IStrikeThrough),
+ Code(ICode),
+ Verbatim(IVerbatim),
+ PlainText(IPlainText),
+ RegularLink(IRegularLink),
+ RadioLink(IRadioLink),
+ RadioTarget(IRadioTarget),
+ PlainLink(IPlainLink),
+ AngleLink(IAngleLink),
+ OrgMacro(IOrgMacro),
+ Entity(IEntity),
+ LatexFragment(ILatexFragment),
+ ExportSnippet(IExportSnippet),
+ FootnoteReference(IFootnoteReference),
+ Citation(ICitation),
+ CitationReference(ICitationReference),
+ InlineBabelCall(IInlineBabelCall),
+ InlineSourceBlock(IInlineSourceBlock),
+ LineBreak(ILineBreak),
+ Target(ITarget),
+ StatisticsCookie(IStatisticsCookie),
+ Subscript(ISubscript),
+ Superscript(ISuperscript),
+ Timestamp(ITimestamp),
+}
+
+pub(crate) trait IntoIAstNode<'parse> {
+ fn into_ast_node<'orig>(
+ &'orig self,
+ registry: RefRegistry<'orig, 'parse>,
+ ) -> BoxFuture<'orig, Result>;
+}
+
+impl<'parse> IntoIAstNode<'parse> for organic::types::DocumentElement<'parse> {
+ fn into_ast_node<'orig>(
+ &'orig self,
+ registry: RefRegistry<'orig, 'parse>,
+ ) -> BoxFuture<'orig, Result> {
+ async move {
+ match self {
+ organic::types::DocumentElement::Heading(inner) => {
+ Ok(IAstNode::Heading(IHeading::new(registry, inner).await?))
+ }
+ organic::types::DocumentElement::Section(inner) => {
+ Ok(IAstNode::Section(ISection::new(registry, inner).await?))
+ }
+ }
+ }
+ .boxed()
+ }
+}
+
+impl<'parse> IntoIAstNode<'parse> for organic::types::Element<'parse> {
+ fn into_ast_node<'orig>(
+ &'orig self,
+ registry: RefRegistry<'orig, 'parse>,
+ ) -> BoxFuture<'orig, Result> {
+ async move {
+ match self {
+ organic::types::Element::Paragraph(inner) => {
+ Ok(IAstNode::Paragraph(IParagraph::new(registry, inner).await?))
+ }
+ organic::types::Element::PlainList(inner) => {
+ Ok(IAstNode::PlainList(IPlainList::new(registry, inner).await?))
+ }
+ organic::types::Element::CenterBlock(inner) => Ok(IAstNode::CenterBlock(
+ ICenterBlock::new(registry, inner).await?,
+ )),
+ organic::types::Element::QuoteBlock(inner) => Ok(IAstNode::QuoteBlock(
+ IQuoteBlock::new(registry, inner).await?,
+ )),
+ organic::types::Element::SpecialBlock(inner) => Ok(IAstNode::SpecialBlock(
+ ISpecialBlock::new(registry, inner).await?,
+ )),
+ organic::types::Element::DynamicBlock(inner) => Ok(IAstNode::DynamicBlock(
+ IDynamicBlock::new(registry, inner).await?,
+ )),
+ organic::types::Element::FootnoteDefinition(inner) => Ok(
+ IAstNode::FootnoteDefinition(IFootnoteDefinition::new(registry, inner).await?),
+ ),
+ organic::types::Element::Comment(inner) => {
+ Ok(IAstNode::Comment(IComment::new(registry, inner).await?))
+ }
+ organic::types::Element::Drawer(inner) => {
+ Ok(IAstNode::Drawer(IDrawer::new(registry, inner).await?))
+ }
+ organic::types::Element::PropertyDrawer(inner) => Ok(IAstNode::PropertyDrawer(
+ IPropertyDrawer::new(registry, inner).await?,
+ )),
+ organic::types::Element::Table(inner) => {
+ Ok(IAstNode::Table(ITable::new(registry, inner).await?))
+ }
+ organic::types::Element::VerseBlock(inner) => Ok(IAstNode::VerseBlock(
+ IVerseBlock::new(registry, inner).await?,
+ )),
+ organic::types::Element::CommentBlock(inner) => Ok(IAstNode::CommentBlock(
+ ICommentBlock::new(registry, inner).await?,
+ )),
+ organic::types::Element::ExampleBlock(inner) => Ok(IAstNode::ExampleBlock(
+ IExampleBlock::new(registry, inner).await?,
+ )),
+ organic::types::Element::ExportBlock(inner) => Ok(IAstNode::ExportBlock(
+ IExportBlock::new(registry, inner).await?,
+ )),
+ organic::types::Element::SrcBlock(inner) => {
+ Ok(IAstNode::SrcBlock(ISrcBlock::new(registry, inner).await?))
+ }
+ organic::types::Element::Clock(inner) => {
+ Ok(IAstNode::Clock(IClock::new(registry, inner).await?))
+ }
+ organic::types::Element::DiarySexp(inner) => {
+ Ok(IAstNode::DiarySexp(IDiarySexp::new(registry, inner).await?))
+ }
+ organic::types::Element::Planning(inner) => {
+ Ok(IAstNode::Planning(IPlanning::new(registry, inner).await?))
+ }
+ organic::types::Element::FixedWidthArea(inner) => Ok(IAstNode::FixedWidthArea(
+ IFixedWidthArea::new(registry, inner).await?,
+ )),
+ organic::types::Element::HorizontalRule(inner) => Ok(IAstNode::HorizontalRule(
+ IHorizontalRule::new(registry, inner).await?,
+ )),
+ organic::types::Element::Keyword(inner) => {
+ Ok(IAstNode::Keyword(IKeyword::new(registry, inner).await?))
+ }
+ organic::types::Element::BabelCall(inner) => {
+ Ok(IAstNode::BabelCall(IBabelCall::new(registry, inner).await?))
+ }
+ organic::types::Element::LatexEnvironment(inner) => Ok(IAstNode::LatexEnvironment(
+ ILatexEnvironment::new(registry, inner).await?,
+ )),
+ }
+ }
+ .boxed()
+ }
+}
+
+impl<'parse> IntoIAstNode<'parse> for organic::types::Object<'parse> {
+ fn into_ast_node<'orig>(
+ &'orig self,
+ registry: RefRegistry<'orig, 'parse>,
+ ) -> BoxFuture<'orig, Result> {
+ async move {
+ match self {
+ organic::types::Object::Bold(inner) => {
+ Ok(IAstNode::Bold(IBold::new(registry, inner).await?))
+ }
+ organic::types::Object::Italic(inner) => {
+ Ok(IAstNode::Italic(IItalic::new(registry, inner).await?))
+ }
+ organic::types::Object::Underline(inner) => {
+ Ok(IAstNode::Underline(IUnderline::new(registry, inner).await?))
+ }
+ organic::types::Object::StrikeThrough(inner) => Ok(IAstNode::StrikeThrough(
+ IStrikeThrough::new(registry, inner).await?,
+ )),
+ organic::types::Object::Code(inner) => {
+ Ok(IAstNode::Code(ICode::new(registry, inner).await?))
+ }
+ organic::types::Object::Verbatim(inner) => {
+ Ok(IAstNode::Verbatim(IVerbatim::new(registry, inner).await?))
+ }
+ organic::types::Object::PlainText(inner) => {
+ Ok(IAstNode::PlainText(IPlainText::new(registry, inner).await?))
+ }
+ organic::types::Object::RegularLink(inner) => Ok(IAstNode::RegularLink(
+ IRegularLink::new(registry, inner).await?,
+ )),
+ organic::types::Object::RadioLink(inner) => {
+ Ok(IAstNode::RadioLink(IRadioLink::new(registry, inner).await?))
+ }
+ organic::types::Object::RadioTarget(inner) => Ok(IAstNode::RadioTarget(
+ IRadioTarget::new(registry, inner).await?,
+ )),
+ organic::types::Object::PlainLink(inner) => {
+ Ok(IAstNode::PlainLink(IPlainLink::new(registry, inner).await?))
+ }
+ organic::types::Object::AngleLink(inner) => {
+ Ok(IAstNode::AngleLink(IAngleLink::new(registry, inner).await?))
+ }
+ organic::types::Object::OrgMacro(inner) => {
+ Ok(IAstNode::OrgMacro(IOrgMacro::new(registry, inner).await?))
+ }
+ organic::types::Object::Entity(inner) => {
+ Ok(IAstNode::Entity(IEntity::new(registry, inner).await?))
+ }
+ organic::types::Object::LatexFragment(inner) => Ok(IAstNode::LatexFragment(
+ ILatexFragment::new(registry, inner).await?,
+ )),
+ organic::types::Object::ExportSnippet(inner) => Ok(IAstNode::ExportSnippet(
+ IExportSnippet::new(registry, inner).await?,
+ )),
+ organic::types::Object::FootnoteReference(inner) => Ok(
+ IAstNode::FootnoteReference(IFootnoteReference::new(registry, inner).await?),
+ ),
+ organic::types::Object::Citation(inner) => {
+ Ok(IAstNode::Citation(ICitation::new(registry, inner).await?))
+ }
+ organic::types::Object::CitationReference(inner) => Ok(
+ IAstNode::CitationReference(ICitationReference::new(registry, inner).await?),
+ ),
+ organic::types::Object::InlineBabelCall(inner) => Ok(IAstNode::InlineBabelCall(
+ IInlineBabelCall::new(registry, inner).await?,
+ )),
+ organic::types::Object::InlineSourceBlock(inner) => Ok(
+ IAstNode::InlineSourceBlock(IInlineSourceBlock::new(registry, inner).await?),
+ ),
+ organic::types::Object::LineBreak(inner) => {
+ Ok(IAstNode::LineBreak(ILineBreak::new(registry, inner).await?))
+ }
+ organic::types::Object::Target(inner) => {
+ Ok(IAstNode::Target(ITarget::new(registry, inner).await?))
+ }
+ organic::types::Object::StatisticsCookie(inner) => Ok(IAstNode::StatisticsCookie(
+ IStatisticsCookie::new(registry, inner).await?,
+ )),
+ organic::types::Object::Subscript(inner) => {
+ Ok(IAstNode::Subscript(ISubscript::new(registry, inner).await?))
+ }
+ organic::types::Object::Superscript(inner) => Ok(IAstNode::Superscript(
+ ISuperscript::new(registry, inner).await?,
+ )),
+ organic::types::Object::Timestamp(inner) => {
+ Ok(IAstNode::Timestamp(ITimestamp::new(registry, inner).await?))
+ }
+ }
+ }
+ .boxed()
+ }
+}
diff --git a/src/intermediate/babel_call.rs b/src/intermediate/babel_call.rs
index a8d542c..cffc2e5 100644
--- a/src/intermediate/babel_call.rs
+++ b/src/intermediate/babel_call.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct IBabelCall {}
-
-impl IBabelCall {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::BabelCall<'parse>,
- ) -> Result {
- Ok(IBabelCall {})
- }
-}
+inoop!(IBabelCall, BabelCall);
diff --git a/src/intermediate/bold.rs b/src/intermediate/bold.rs
index c00f94b..bee42d1 100644
--- a/src/intermediate/bold.rs
+++ b/src/intermediate/bold.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct IBold {}
-
-impl IBold {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::Bold<'parse>,
- ) -> Result {
- Ok(IBold {})
- }
-}
+inoop!(IBold, Bold);
diff --git a/src/intermediate/center_block.rs b/src/intermediate/center_block.rs
index 2e4d777..3b93a29 100644
--- a/src/intermediate/center_block.rs
+++ b/src/intermediate/center_block.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct ICenterBlock {}
-
-impl ICenterBlock {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::CenterBlock<'parse>,
- ) -> Result {
- Ok(ICenterBlock {})
- }
-}
+inoop!(ICenterBlock, CenterBlock);
diff --git a/src/intermediate/citation.rs b/src/intermediate/citation.rs
index 1209241..916ff72 100644
--- a/src/intermediate/citation.rs
+++ b/src/intermediate/citation.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct ICitation {}
-
-impl ICitation {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::Citation<'parse>,
- ) -> Result {
- Ok(ICitation {})
- }
-}
+inoop!(ICitation, Citation);
diff --git a/src/intermediate/citation_reference.rs b/src/intermediate/citation_reference.rs
index 1030158..f7b2e9b 100644
--- a/src/intermediate/citation_reference.rs
+++ b/src/intermediate/citation_reference.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct ICitationReference {}
-
-impl ICitationReference {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::CitationReference<'parse>,
- ) -> Result {
- Ok(ICitationReference {})
- }
-}
+inoop!(ICitationReference, CitationReference);
diff --git a/src/intermediate/clock.rs b/src/intermediate/clock.rs
index 5f3b8eb..056d582 100644
--- a/src/intermediate/clock.rs
+++ b/src/intermediate/clock.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct IClock {}
-
-impl IClock {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::Clock<'parse>,
- ) -> Result {
- Ok(IClock {})
- }
-}
+inoop!(IClock, Clock);
diff --git a/src/intermediate/code.rs b/src/intermediate/code.rs
index 6a137ba..01d7dbe 100644
--- a/src/intermediate/code.rs
+++ b/src/intermediate/code.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct ICode {}
-
-impl ICode {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::Code<'parse>,
- ) -> Result {
- Ok(ICode {})
- }
-}
+inoop!(ICode, Code);
diff --git a/src/intermediate/comment.rs b/src/intermediate/comment.rs
index 70649f2..19c706a 100644
--- a/src/intermediate/comment.rs
+++ b/src/intermediate/comment.rs
@@ -1,16 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-/// Essentially a no-op since the comment is not rendered.
-#[derive(Debug)]
-pub(crate) struct IComment {}
-
-impl IComment {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- comment: &organic::types::Comment<'parse>,
- ) -> Result {
- Ok(IComment {})
- }
-}
+inoop!(IComment, Comment);
diff --git a/src/intermediate/comment_block.rs b/src/intermediate/comment_block.rs
index 71602eb..89f4bc3 100644
--- a/src/intermediate/comment_block.rs
+++ b/src/intermediate/comment_block.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct ICommentBlock {}
-
-impl ICommentBlock {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::CommentBlock<'parse>,
- ) -> Result {
- Ok(ICommentBlock {})
- }
-}
+inoop!(ICommentBlock, CommentBlock);
diff --git a/src/intermediate/convert.rs b/src/intermediate/convert.rs
index ee9bdfa..6bdb654 100644
--- a/src/intermediate/convert.rs
+++ b/src/intermediate/convert.rs
@@ -6,6 +6,7 @@ use crate::config::Config;
use crate::context::GlobalSettings;
use crate::context::RenderBlogPostPage;
use crate::context::RenderDocumentElement;
+use crate::context::RenderRealFootnoteDefinition;
use crate::error::CustomError;
use super::BlogPost;
@@ -55,11 +56,27 @@ pub(crate) fn convert_blog_post_page_to_render_context, F: AsRef<
children
};
+ let footnotes = {
+ let mut ret = Vec::new();
+
+ for footnote in page.footnotes.iter() {
+ ret.push(RenderRealFootnoteDefinition::new(
+ config,
+ output_directory,
+ output_file,
+ footnote,
+ )?);
+ }
+
+ ret
+ };
+
let ret = RenderBlogPostPage::new(
global_settings,
page.title.clone(),
Some(link_to_blog_post),
children,
+ footnotes,
);
Ok(ret)
}
diff --git a/src/intermediate/definition.rs b/src/intermediate/definition.rs
index 2f62ca7..4b58d8e 100644
--- a/src/intermediate/definition.rs
+++ b/src/intermediate/definition.rs
@@ -1,5 +1,7 @@
use std::path::Path;
use std::path::PathBuf;
+use std::sync::Arc;
+use std::sync::Mutex;
use tokio::task::JoinHandle;
use walkdir::WalkDir;
@@ -43,31 +45,26 @@ impl BlogPost {
ret
};
- let mut registry = Registry::new();
-
- // Assign IDs to the targets
- for (_real_path, _contents, parsed_document) in parsed_org_files.iter() {
- organic::types::AstNode::from(parsed_document)
- .iter_all_ast_nodes()
- .for_each(|node| match node {
- organic::types::AstNode::Target(target) => {
- registry.get_target(target.value);
- }
- _ => {}
- });
- }
-
let pages = {
let mut ret = Vec::new();
for (real_path, _contents, parsed_document) in parsed_org_files.iter() {
+ let mut registry = Registry::new();
+
+ // Assign IDs to the targets
+ organic::types::AstNode::from(parsed_document)
+ .iter_all_ast_nodes()
+ .for_each(|node| match node {
+ organic::types::AstNode::Target(target) => {
+ registry.get_target(target.value);
+ }
+ _ => {}
+ });
+
+ let registry = Arc::new(Mutex::new(registry));
let relative_to_post_dir_path = real_path.strip_prefix(post_dir)?;
ret.push(
- BlogPostPage::new(
- relative_to_post_dir_path,
- &mut registry,
- parsed_document,
- )
- .await?,
+ BlogPostPage::new(relative_to_post_dir_path, registry, parsed_document)
+ .await?,
);
}
ret
diff --git a/src/intermediate/diary_sexp.rs b/src/intermediate/diary_sexp.rs
index 5f4d4a4..ebc7b3b 100644
--- a/src/intermediate/diary_sexp.rs
+++ b/src/intermediate/diary_sexp.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct IDiarySexp {}
-
-impl IDiarySexp {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::DiarySexp<'parse>,
- ) -> Result {
- Ok(IDiarySexp {})
- }
-}
+inoop!(IDiarySexp, DiarySexp);
diff --git a/src/intermediate/document_element.rs b/src/intermediate/document_element.rs
index d348269..8f6b608 100644
--- a/src/intermediate/document_element.rs
+++ b/src/intermediate/document_element.rs
@@ -1,31 +1,30 @@
-use crate::error::CustomError;
-
+use super::macros::iitem;
+use super::macros::iselector;
use super::registry::Registry;
use super::IHeading;
use super::ISection;
+use crate::error::CustomError;
use futures::future::{BoxFuture, FutureExt};
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub(crate) enum IDocumentElement {
Heading(IHeading),
Section(ISection),
}
-impl IDocumentElement {
- pub(crate) fn new<'parse, 'b>(
- registry: &'b mut Registry<'parse>,
- original: &'b organic::types::DocumentElement<'parse>,
- ) -> BoxFuture<'b, Result> {
- async move {
- match original {
- organic::types::DocumentElement::Heading(inner) => Ok(IDocumentElement::Heading(
- IHeading::new(registry, inner).await?,
- )),
- organic::types::DocumentElement::Section(inner) => Ok(IDocumentElement::Section(
- ISection::new(registry, inner).await?,
- )),
- }
- }
- .boxed()
- }
-}
+iselector!(IDocumentElement, DocumentElement, original, registry, {
+ iitem!(
+ registry,
+ original,
+ (
+ organic::types::DocumentElement::Heading,
+ IDocumentElement::Heading,
+ IHeading
+ ),
+ (
+ organic::types::DocumentElement::Section,
+ IDocumentElement::Section,
+ ISection
+ ),
+ )
+});
diff --git a/src/intermediate/drawer.rs b/src/intermediate/drawer.rs
index b55fd71..4a1c0a3 100644
--- a/src/intermediate/drawer.rs
+++ b/src/intermediate/drawer.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct IDrawer {}
-
-impl IDrawer {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::Drawer<'parse>,
- ) -> Result {
- Ok(IDrawer {})
- }
-}
+inoop!(IDrawer, Drawer);
diff --git a/src/intermediate/dynamic_block.rs b/src/intermediate/dynamic_block.rs
index 6086e9d..fc8cbaf 100644
--- a/src/intermediate/dynamic_block.rs
+++ b/src/intermediate/dynamic_block.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct IDynamicBlock {}
-
-impl IDynamicBlock {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::DynamicBlock<'parse>,
- ) -> Result {
- Ok(IDynamicBlock {})
- }
-}
+inoop!(IDynamicBlock, DynamicBlock);
diff --git a/src/intermediate/element.rs b/src/intermediate/element.rs
index 1fe3360..1e1f2ae 100644
--- a/src/intermediate/element.rs
+++ b/src/intermediate/element.rs
@@ -1,7 +1,6 @@
-use crate::error::CustomError;
-
use super::comment::IComment;
use super::keyword::IKeyword;
+use super::macros::iselector;
use super::registry::Registry;
use super::IBabelCall;
use super::ICenterBlock;
@@ -25,9 +24,11 @@ use super::ISpecialBlock;
use super::ISrcBlock;
use super::ITable;
use super::IVerseBlock;
+use crate::error::CustomError;
+use crate::intermediate::macros::iitem;
use futures::future::{BoxFuture, FutureExt};
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub(crate) enum IElement {
Paragraph(IParagraph),
PlainList(IPlainList),
@@ -55,87 +56,117 @@ pub(crate) enum IElement {
LatexEnvironment(ILatexEnvironment),
}
-impl IElement {
- pub(crate) fn new<'parse, 'b>(
- registry: &'b mut Registry<'parse>,
- elem: &'b organic::types::Element<'parse>,
- ) -> BoxFuture<'b, Result> {
- async move {
- match elem {
- organic::types::Element::Paragraph(inner) => {
- Ok(IElement::Paragraph(IParagraph::new(registry, inner).await?))
- }
- organic::types::Element::PlainList(inner) => {
- Ok(IElement::PlainList(IPlainList::new(registry, inner).await?))
- }
- organic::types::Element::CenterBlock(inner) => Ok(IElement::CenterBlock(
- ICenterBlock::new(registry, inner).await?,
- )),
- organic::types::Element::QuoteBlock(inner) => Ok(IElement::QuoteBlock(
- IQuoteBlock::new(registry, inner).await?,
- )),
- organic::types::Element::SpecialBlock(inner) => Ok(IElement::SpecialBlock(
- ISpecialBlock::new(registry, inner).await?,
- )),
- organic::types::Element::DynamicBlock(inner) => Ok(IElement::DynamicBlock(
- IDynamicBlock::new(registry, inner).await?,
- )),
- organic::types::Element::FootnoteDefinition(inner) => Ok(
- IElement::FootnoteDefinition(IFootnoteDefinition::new(registry, inner).await?),
- ),
- organic::types::Element::Comment(inner) => {
- Ok(IElement::Comment(IComment::new(registry, inner).await?))
- }
- organic::types::Element::Drawer(inner) => {
- Ok(IElement::Drawer(IDrawer::new(registry, inner).await?))
- }
- organic::types::Element::PropertyDrawer(inner) => Ok(IElement::PropertyDrawer(
- IPropertyDrawer::new(registry, inner).await?,
- )),
- organic::types::Element::Table(inner) => {
- Ok(IElement::Table(ITable::new(registry, inner).await?))
- }
- organic::types::Element::VerseBlock(inner) => Ok(IElement::VerseBlock(
- IVerseBlock::new(registry, inner).await?,
- )),
- organic::types::Element::CommentBlock(inner) => Ok(IElement::CommentBlock(
- ICommentBlock::new(registry, inner).await?,
- )),
- organic::types::Element::ExampleBlock(inner) => Ok(IElement::ExampleBlock(
- IExampleBlock::new(registry, inner).await?,
- )),
- organic::types::Element::ExportBlock(inner) => Ok(IElement::ExportBlock(
- IExportBlock::new(registry, inner).await?,
- )),
- organic::types::Element::SrcBlock(inner) => {
- Ok(IElement::SrcBlock(ISrcBlock::new(registry, inner).await?))
- }
- organic::types::Element::Clock(inner) => {
- Ok(IElement::Clock(IClock::new(registry, inner).await?))
- }
- organic::types::Element::DiarySexp(inner) => {
- Ok(IElement::DiarySexp(IDiarySexp::new(registry, inner).await?))
- }
- organic::types::Element::Planning(inner) => {
- Ok(IElement::Planning(IPlanning::new(registry, inner).await?))
- }
- organic::types::Element::FixedWidthArea(inner) => Ok(IElement::FixedWidthArea(
- IFixedWidthArea::new(registry, inner).await?,
- )),
- organic::types::Element::HorizontalRule(inner) => Ok(IElement::HorizontalRule(
- IHorizontalRule::new(registry, inner).await?,
- )),
- organic::types::Element::Keyword(inner) => {
- Ok(IElement::Keyword(IKeyword::new(registry, inner).await?))
- }
- organic::types::Element::BabelCall(inner) => {
- Ok(IElement::BabelCall(IBabelCall::new(registry, inner).await?))
- }
- organic::types::Element::LatexEnvironment(inner) => Ok(IElement::LatexEnvironment(
- ILatexEnvironment::new(registry, inner).await?,
- )),
- }
- }
- .boxed()
- }
-}
+iselector!(IElement, Element, original, registry, {
+ iitem!(
+ registry,
+ original,
+ (
+ organic::types::Element::Paragraph,
+ IElement::Paragraph,
+ IParagraph
+ ),
+ (
+ organic::types::Element::PlainList,
+ IElement::PlainList,
+ IPlainList
+ ),
+ (
+ organic::types::Element::CenterBlock,
+ IElement::CenterBlock,
+ ICenterBlock
+ ),
+ (
+ organic::types::Element::QuoteBlock,
+ IElement::QuoteBlock,
+ IQuoteBlock
+ ),
+ (
+ organic::types::Element::SpecialBlock,
+ IElement::SpecialBlock,
+ ISpecialBlock
+ ),
+ (
+ organic::types::Element::DynamicBlock,
+ IElement::DynamicBlock,
+ IDynamicBlock
+ ),
+ (
+ organic::types::Element::FootnoteDefinition,
+ IElement::FootnoteDefinition,
+ IFootnoteDefinition
+ ),
+ (
+ organic::types::Element::Comment,
+ IElement::Comment,
+ IComment
+ ),
+ (organic::types::Element::Drawer, IElement::Drawer, IDrawer),
+ (
+ organic::types::Element::PropertyDrawer,
+ IElement::PropertyDrawer,
+ IPropertyDrawer
+ ),
+ (organic::types::Element::Table, IElement::Table, ITable),
+ (
+ organic::types::Element::VerseBlock,
+ IElement::VerseBlock,
+ IVerseBlock
+ ),
+ (
+ organic::types::Element::CommentBlock,
+ IElement::CommentBlock,
+ ICommentBlock
+ ),
+ (
+ organic::types::Element::ExampleBlock,
+ IElement::ExampleBlock,
+ IExampleBlock
+ ),
+ (
+ organic::types::Element::ExportBlock,
+ IElement::ExportBlock,
+ IExportBlock
+ ),
+ (
+ organic::types::Element::SrcBlock,
+ IElement::SrcBlock,
+ ISrcBlock
+ ),
+ (organic::types::Element::Clock, IElement::Clock, IClock),
+ (
+ organic::types::Element::DiarySexp,
+ IElement::DiarySexp,
+ IDiarySexp
+ ),
+ (
+ organic::types::Element::Planning,
+ IElement::Planning,
+ IPlanning
+ ),
+ (
+ organic::types::Element::FixedWidthArea,
+ IElement::FixedWidthArea,
+ IFixedWidthArea
+ ),
+ (
+ organic::types::Element::HorizontalRule,
+ IElement::HorizontalRule,
+ IHorizontalRule
+ ),
+ (
+ organic::types::Element::Keyword,
+ IElement::Keyword,
+ IKeyword
+ ),
+ (
+ organic::types::Element::BabelCall,
+ IElement::BabelCall,
+ IBabelCall
+ ),
+ (
+ organic::types::Element::LatexEnvironment,
+ IElement::LatexEnvironment,
+ ILatexEnvironment
+ ),
+ )
+});
diff --git a/src/intermediate/entity.rs b/src/intermediate/entity.rs
index 088a8e5..0f47742 100644
--- a/src/intermediate/entity.rs
+++ b/src/intermediate/entity.rs
@@ -1,19 +1,14 @@
+use super::macros::intermediate;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub(crate) struct IEntity {
pub(crate) html: String,
}
-impl IEntity {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::Entity<'parse>,
- ) -> Result {
- Ok(IEntity {
- html: original.html.to_owned(),
- })
- }
-}
+intermediate!(IEntity, Entity, original, registry, {
+ Ok(IEntity {
+ html: original.html.to_owned(),
+ })
+});
diff --git a/src/intermediate/example_block.rs b/src/intermediate/example_block.rs
index 2c65752..953c4d5 100644
--- a/src/intermediate/example_block.rs
+++ b/src/intermediate/example_block.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct IExampleBlock {}
-
-impl IExampleBlock {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::ExampleBlock<'parse>,
- ) -> Result {
- Ok(IExampleBlock {})
- }
-}
+inoop!(IExampleBlock, ExampleBlock);
diff --git a/src/intermediate/export_block.rs b/src/intermediate/export_block.rs
index ff24258..2792eda 100644
--- a/src/intermediate/export_block.rs
+++ b/src/intermediate/export_block.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct IExportBlock {}
-
-impl IExportBlock {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::ExportBlock<'parse>,
- ) -> Result {
- Ok(IExportBlock {})
- }
-}
+inoop!(IExportBlock, ExportBlock);
diff --git a/src/intermediate/export_snippet.rs b/src/intermediate/export_snippet.rs
index 6a2c331..7f23280 100644
--- a/src/intermediate/export_snippet.rs
+++ b/src/intermediate/export_snippet.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct IExportSnippet {}
-
-impl IExportSnippet {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::ExportSnippet<'parse>,
- ) -> Result {
- Ok(IExportSnippet {})
- }
-}
+inoop!(IExportSnippet, ExportSnippet);
diff --git a/src/intermediate/fixed_width_area.rs b/src/intermediate/fixed_width_area.rs
index 6cdf376..6bed813 100644
--- a/src/intermediate/fixed_width_area.rs
+++ b/src/intermediate/fixed_width_area.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct IFixedWidthArea {}
-
-impl IFixedWidthArea {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::FixedWidthArea<'parse>,
- ) -> Result {
- Ok(IFixedWidthArea {})
- }
-}
+inoop!(IFixedWidthArea, FixedWidthArea);
diff --git a/src/intermediate/footnote_definition.rs b/src/intermediate/footnote_definition.rs
index 35964bb..4d0ae61 100644
--- a/src/intermediate/footnote_definition.rs
+++ b/src/intermediate/footnote_definition.rs
@@ -1,15 +1,57 @@
-use crate::error::CustomError;
-
+use super::macros::intermediate;
+use super::registry::register_footnote_definition;
use super::registry::Registry;
+use super::IAstNode;
+use crate::error::CustomError;
+use crate::intermediate::RefRegistry;
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub(crate) struct IFootnoteDefinition {}
-impl IFootnoteDefinition {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::FootnoteDefinition<'parse>,
- ) -> Result {
+intermediate!(
+ IFootnoteDefinition,
+ FootnoteDefinition,
+ original,
+ registry,
+ {
+ register_footnote_definition(registry, original.label, &original.children).await?;
Ok(IFootnoteDefinition {})
}
+);
+
+#[derive(Debug)]
+pub(crate) struct IRealFootnoteDefinition {
+ pub(crate) footnote_id: usize,
+ pub(crate) contents: Vec,
+}
+
+impl IRealFootnoteDefinition {
+ pub(crate) async fn new<'orig, 'parse>(
+ registry: RefRegistry<'orig, 'parse>,
+ footnote_id: usize,
+ contents: Vec,
+ ) -> Result {
+ Ok(IRealFootnoteDefinition {
+ footnote_id,
+ contents,
+ })
+ }
+
+ pub(crate) fn get_display_label(&self) -> String {
+ format!("{}", self.footnote_id + 1)
+ }
+
+ /// Get an ID to refer to the first reference to this footnote definition.
+ ///
+ /// This ID could, for example, be used for the id attribute in HTML for the reference anchor tag.
+ pub(crate) fn get_reference_id(&self) -> String {
+ format!("fnr.{}", self.get_display_label())
+ }
+
+ /// Get an ID to refer to the footnote definition.
+ ///
+ /// This ID could, for example, be used for the id attribute in HTML for the definition anchor tag.
+ pub(crate) fn get_definition_id(&self) -> String {
+ format!("fn.{}", self.get_display_label())
+ }
}
diff --git a/src/intermediate/footnote_reference.rs b/src/intermediate/footnote_reference.rs
index cb393c2..aa473d2 100644
--- a/src/intermediate/footnote_reference.rs
+++ b/src/intermediate/footnote_reference.rs
@@ -1,15 +1,45 @@
+use super::macros::intermediate;
+use super::registry::get_footnote_reference_id;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
+#[derive(Debug, Clone)]
+pub(crate) struct IFootnoteReference {
+ footnote_id: usize,
+ duplicate_offset: usize,
+}
-#[derive(Debug)]
-pub(crate) struct IFootnoteReference {}
+intermediate!(IFootnoteReference, FootnoteReference, original, registry, {
+ let (footnote_id, reference_count) =
+ get_footnote_reference_id(registry, original.label, &original.definition).await?;
+ Ok(IFootnoteReference {
+ footnote_id,
+ duplicate_offset: reference_count,
+ })
+});
impl IFootnoteReference {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::FootnoteReference<'parse>,
- ) -> Result {
- Ok(IFootnoteReference {})
+ pub(crate) fn get_display_label(&self) -> String {
+ format!("{}", self.footnote_id + 1)
+ }
+
+ /// Get an ID to refer to this footnote reference.
+ ///
+ /// This ID could, for example, be used for the id attribute in HTML for the reference anchor tag.
+ pub(crate) fn get_reference_id(&self) -> String {
+ if self.duplicate_offset == 0 {
+ format!("fnr.{}", self.get_display_label())
+ } else {
+ // Org-mode makes all duplicates use "100" but I figure there is no harm in giving each a unique ID.
+ let append = 100 + self.duplicate_offset - 1;
+ format!("fnr.{}.{}", self.get_display_label(), append)
+ }
+ }
+
+ /// Get an ID to refer to the footnote definition this footnote reference references.
+ ///
+ /// This ID could, for example, be used for the id attribute in HTML for the definition anchor tag.
+ pub(crate) fn get_definition_id(&self) -> String {
+ format!("fn.{}", self.get_display_label())
}
}
diff --git a/src/intermediate/heading.rs b/src/intermediate/heading.rs
index 4ed510e..716545f 100644
--- a/src/intermediate/heading.rs
+++ b/src/intermediate/heading.rs
@@ -1,39 +1,34 @@
-use crate::error::CustomError;
-
+use super::macros::intermediate;
use super::registry::Registry;
use super::IDocumentElement;
use super::IObject;
+use crate::error::CustomError;
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub(crate) struct IHeading {
pub(crate) level: organic::types::HeadlineLevel,
pub(crate) title: Vec,
pub(crate) children: Vec,
}
-impl IHeading {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- heading: &organic::types::Heading<'parse>,
- ) -> Result {
- let title = {
- let mut ret = Vec::new();
- for obj in heading.title.iter() {
- ret.push(IObject::new(registry, obj).await?);
- }
- ret
- };
- let children = {
- let mut ret = Vec::new();
- for obj in heading.children.iter() {
- ret.push(IDocumentElement::new(registry, obj).await?);
- }
- ret
- };
- Ok(IHeading {
- title,
- level: heading.level,
- children,
- })
- }
-}
+intermediate!(IHeading, Heading, original, registry, {
+ let title = {
+ let mut ret = Vec::new();
+ for obj in original.title.iter() {
+ ret.push(IObject::new(registry.clone(), obj).await?);
+ }
+ ret
+ };
+ let children = {
+ let mut ret = Vec::new();
+ for obj in original.children.iter() {
+ ret.push(IDocumentElement::new(registry.clone(), obj).await?);
+ }
+ ret
+ };
+ Ok(IHeading {
+ title,
+ level: original.level,
+ children,
+ })
+});
diff --git a/src/intermediate/horizontal_rule.rs b/src/intermediate/horizontal_rule.rs
index 0be08c6..bc9e323 100644
--- a/src/intermediate/horizontal_rule.rs
+++ b/src/intermediate/horizontal_rule.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct IHorizontalRule {}
-
-impl IHorizontalRule {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::HorizontalRule<'parse>,
- ) -> Result {
- Ok(IHorizontalRule {})
- }
-}
+inoop!(IHorizontalRule, HorizontalRule);
diff --git a/src/intermediate/inline_babel_call.rs b/src/intermediate/inline_babel_call.rs
index 874f5c4..cf1137a 100644
--- a/src/intermediate/inline_babel_call.rs
+++ b/src/intermediate/inline_babel_call.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct IInlineBabelCall {}
-
-impl IInlineBabelCall {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::InlineBabelCall<'parse>,
- ) -> Result {
- Ok(IInlineBabelCall {})
- }
-}
+inoop!(IInlineBabelCall, InlineBabelCall);
diff --git a/src/intermediate/inline_source_block.rs b/src/intermediate/inline_source_block.rs
index 29071b3..700f2fd 100644
--- a/src/intermediate/inline_source_block.rs
+++ b/src/intermediate/inline_source_block.rs
@@ -1,19 +1,14 @@
+use super::macros::intermediate;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub(crate) struct IInlineSourceBlock {
pub(crate) value: String,
}
-impl IInlineSourceBlock {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::InlineSourceBlock<'parse>,
- ) -> Result {
- Ok(IInlineSourceBlock {
- value: original.value.to_owned(),
- })
- }
-}
+intermediate!(IInlineSourceBlock, InlineSourceBlock, original, registry, {
+ Ok(IInlineSourceBlock {
+ value: original.value.to_owned(),
+ })
+});
diff --git a/src/intermediate/italic.rs b/src/intermediate/italic.rs
index 79ce541..1c20c55 100644
--- a/src/intermediate/italic.rs
+++ b/src/intermediate/italic.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct IItalic {}
-
-impl IItalic {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::Italic<'parse>,
- ) -> Result {
- Ok(IItalic {})
- }
-}
+inoop!(IItalic, Italic);
diff --git a/src/intermediate/keyword.rs b/src/intermediate/keyword.rs
index bd26939..3f510f3 100644
--- a/src/intermediate/keyword.rs
+++ b/src/intermediate/keyword.rs
@@ -1,16 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-/// Essentially a no-op since the keyword is not rendered and any relevant impact on other elements is pulled from the parsed form of keyword.
-#[derive(Debug)]
-pub(crate) struct IKeyword {}
-
-impl IKeyword {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- keyword: &organic::types::Keyword<'parse>,
- ) -> Result {
- Ok(IKeyword {})
- }
-}
+inoop!(IKeyword, Keyword);
diff --git a/src/intermediate/latex_environment.rs b/src/intermediate/latex_environment.rs
index c6ccaac..361ae3e 100644
--- a/src/intermediate/latex_environment.rs
+++ b/src/intermediate/latex_environment.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct ILatexEnvironment {}
-
-impl ILatexEnvironment {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::LatexEnvironment<'parse>,
- ) -> Result {
- Ok(ILatexEnvironment {})
- }
-}
+inoop!(ILatexEnvironment, LatexEnvironment);
diff --git a/src/intermediate/latex_fragment.rs b/src/intermediate/latex_fragment.rs
index bf8d2af..89aa832 100644
--- a/src/intermediate/latex_fragment.rs
+++ b/src/intermediate/latex_fragment.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct ILatexFragment {}
-
-impl ILatexFragment {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::LatexFragment<'parse>,
- ) -> Result {
- Ok(ILatexFragment {})
- }
-}
+inoop!(ILatexFragment, LatexFragment);
diff --git a/src/intermediate/line_break.rs b/src/intermediate/line_break.rs
index da94610..8436553 100644
--- a/src/intermediate/line_break.rs
+++ b/src/intermediate/line_break.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct ILineBreak {}
-
-impl ILineBreak {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::LineBreak<'parse>,
- ) -> Result {
- Ok(ILineBreak {})
- }
-}
+inoop!(ILineBreak, LineBreak);
diff --git a/src/intermediate/macros.rs b/src/intermediate/macros.rs
new file mode 100644
index 0000000..f7b6236
--- /dev/null
+++ b/src/intermediate/macros.rs
@@ -0,0 +1,74 @@
+/// Write the implementation for the intermediate ast node for a type that is a noop or is not yet implemented.
+///
+/// This exists to make changing the type signature easier.
+macro_rules! inoop {
+ ($istruct:ident, $pstruct:ident) => {
+ #[derive(Debug, Clone)]
+ pub(crate) struct $istruct {}
+
+ impl $istruct {
+ pub(crate) async fn new<'reg, 'orig, 'parse>(
+ registry: crate::intermediate::RefRegistry<'orig, 'parse>,
+ original: &'orig organic::types::$pstruct<'parse>,
+ ) -> Result<$istruct, CustomError> {
+ Ok($istruct {})
+ }
+ }
+ };
+}
+
+pub(crate) use inoop;
+
+/// Write the implementation for the intermediate ast node.
+///
+/// This exists to make changing the type signature easier.
+macro_rules! intermediate {
+ ($istruct:ident, $pstruct:ident, $original:ident, $registry:ident, $fnbody:tt) => {
+ impl $istruct {
+ pub(crate) async fn new<'orig, 'parse>(
+ registry: crate::intermediate::RefRegistry<'orig, 'parse>,
+ original: &'orig organic::types::$pstruct<'parse>,
+ ) -> Result<$istruct, CustomError> {
+ let $original = original;
+ let $registry = registry;
+ $fnbody
+ }
+ }
+ };
+}
+
+pub(crate) use intermediate;
+
+/// Write the implementation for the intermediate ast node.
+///
+/// This exists to make changing the type signature easier.
+macro_rules! iselector {
+ ($istruct:ident, $pstruct:ident, $original:ident, $registry:ident, $fnbody:tt) => {
+ impl $istruct {
+ pub(crate) fn new<'orig, 'parse>(
+ registry: crate::intermediate::RefRegistry<'orig, 'parse>,
+ original: &'orig organic::types::$pstruct<'parse>,
+ ) -> BoxFuture<'orig, Result<$istruct, CustomError>> {
+ let $registry = registry;
+ let $original = original;
+ async move { $fnbody }.boxed()
+ }
+ }
+ };
+}
+
+pub(crate) use iselector;
+
+macro_rules! iitem {
+ ($registry:expr, $original:expr, $(($penum:path, $ienum:path, $istruct:ident),)*) => {
+ match $original {
+$(
+ $penum(inner) => Ok($ienum(
+ $istruct::new($registry.clone(), inner).await?,
+ )),
+)*
+ }
+ };
+}
+
+pub(crate) use iitem;
diff --git a/src/intermediate/mod.rs b/src/intermediate/mod.rs
index ac1f411..f228fdb 100644
--- a/src/intermediate/mod.rs
+++ b/src/intermediate/mod.rs
@@ -1,4 +1,5 @@
mod angle_link;
+mod ast_node;
mod babel_call;
mod bold;
mod center_block;
@@ -31,6 +32,7 @@ mod keyword;
mod latex_environment;
mod latex_fragment;
mod line_break;
+mod macros;
mod object;
mod org_macro;
mod page;
@@ -61,6 +63,7 @@ mod util;
mod verbatim;
mod verse_block;
pub(crate) use angle_link::IAngleLink;
+pub(crate) use ast_node::IAstNode;
pub(crate) use babel_call::IBabelCall;
pub(crate) use bold::IBold;
pub(crate) use center_block::ICenterBlock;
@@ -83,6 +86,7 @@ pub(crate) use export_block::IExportBlock;
pub(crate) use export_snippet::IExportSnippet;
pub(crate) use fixed_width_area::IFixedWidthArea;
pub(crate) use footnote_definition::IFootnoteDefinition;
+pub(crate) use footnote_definition::IRealFootnoteDefinition;
pub(crate) use footnote_reference::IFootnoteReference;
pub(crate) use heading::IHeading;
pub(crate) use horizontal_rule::IHorizontalRule;
@@ -120,3 +124,6 @@ pub(crate) use timestamp::ITimestamp;
pub(crate) use underline::IUnderline;
pub(crate) use verbatim::IVerbatim;
pub(crate) use verse_block::IVerseBlock;
+
+pub(crate) type RefRegistry<'orig, 'parse> =
+ std::sync::Arc>>;
diff --git a/src/intermediate/object.rs b/src/intermediate/object.rs
index c51584a..a0b05a2 100644
--- a/src/intermediate/object.rs
+++ b/src/intermediate/object.rs
@@ -1,4 +1,5 @@
use crate::error::CustomError;
+use crate::intermediate::macros::iitem;
use super::angle_link::IAngleLink;
use super::bold::IBold;
@@ -13,6 +14,7 @@ use super::inline_source_block::IInlineSourceBlock;
use super::italic::IItalic;
use super::latex_fragment::ILatexFragment;
use super::line_break::ILineBreak;
+use super::macros::iselector;
use super::org_macro::IOrgMacro;
use super::plain_link::IPlainLink;
use super::plain_text::IPlainText;
@@ -30,7 +32,7 @@ use super::verbatim::IVerbatim;
use super::ITarget;
use futures::future::{BoxFuture, FutureExt};
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub(crate) enum IObject {
Bold(IBold),
Italic(IItalic),
@@ -61,96 +63,124 @@ pub(crate) enum IObject {
Timestamp(ITimestamp),
}
-impl IObject {
- pub(crate) fn new<'parse, 'b>(
- registry: &'b mut Registry<'parse>,
- obj: &'b organic::types::Object<'parse>,
- ) -> BoxFuture<'b, Result> {
- async move {
- match obj {
- organic::types::Object::Bold(inner) => {
- Ok(IObject::Bold(IBold::new(registry, inner).await?))
- }
- organic::types::Object::Italic(inner) => {
- Ok(IObject::Italic(IItalic::new(registry, inner).await?))
- }
- organic::types::Object::Underline(inner) => {
- Ok(IObject::Underline(IUnderline::new(registry, inner).await?))
- }
- organic::types::Object::StrikeThrough(inner) => Ok(IObject::StrikeThrough(
- IStrikeThrough::new(registry, inner).await?,
- )),
- organic::types::Object::Code(inner) => {
- Ok(IObject::Code(ICode::new(registry, inner).await?))
- }
- organic::types::Object::Verbatim(inner) => {
- Ok(IObject::Verbatim(IVerbatim::new(registry, inner).await?))
- }
- organic::types::Object::PlainText(inner) => {
- Ok(IObject::PlainText(IPlainText::new(registry, inner).await?))
- }
- organic::types::Object::RegularLink(inner) => Ok(IObject::RegularLink(
- IRegularLink::new(registry, inner).await?,
- )),
- organic::types::Object::RadioLink(inner) => {
- Ok(IObject::RadioLink(IRadioLink::new(registry, inner).await?))
- }
- organic::types::Object::RadioTarget(inner) => Ok(IObject::RadioTarget(
- IRadioTarget::new(registry, inner).await?,
- )),
- organic::types::Object::PlainLink(inner) => {
- Ok(IObject::PlainLink(IPlainLink::new(registry, inner).await?))
- }
- organic::types::Object::AngleLink(inner) => {
- Ok(IObject::AngleLink(IAngleLink::new(registry, inner).await?))
- }
- organic::types::Object::OrgMacro(inner) => {
- Ok(IObject::OrgMacro(IOrgMacro::new(registry, inner).await?))
- }
- organic::types::Object::Entity(inner) => {
- Ok(IObject::Entity(IEntity::new(registry, inner).await?))
- }
- organic::types::Object::LatexFragment(inner) => Ok(IObject::LatexFragment(
- ILatexFragment::new(registry, inner).await?,
- )),
- organic::types::Object::ExportSnippet(inner) => Ok(IObject::ExportSnippet(
- IExportSnippet::new(registry, inner).await?,
- )),
- organic::types::Object::FootnoteReference(inner) => Ok(IObject::FootnoteReference(
- IFootnoteReference::new(registry, inner).await?,
- )),
- organic::types::Object::Citation(inner) => {
- Ok(IObject::Citation(ICitation::new(registry, inner).await?))
- }
- organic::types::Object::CitationReference(inner) => Ok(IObject::CitationReference(
- ICitationReference::new(registry, inner).await?,
- )),
- organic::types::Object::InlineBabelCall(inner) => Ok(IObject::InlineBabelCall(
- IInlineBabelCall::new(registry, inner).await?,
- )),
- organic::types::Object::InlineSourceBlock(inner) => Ok(IObject::InlineSourceBlock(
- IInlineSourceBlock::new(registry, inner).await?,
- )),
- organic::types::Object::LineBreak(inner) => {
- Ok(IObject::LineBreak(ILineBreak::new(registry, inner).await?))
- }
- organic::types::Object::Target(inner) => {
- Ok(IObject::Target(ITarget::new(registry, inner).await?))
- }
- organic::types::Object::StatisticsCookie(inner) => Ok(IObject::StatisticsCookie(
- IStatisticsCookie::new(registry, inner).await?,
- )),
- organic::types::Object::Subscript(inner) => {
- Ok(IObject::Subscript(ISubscript::new(registry, inner).await?))
- }
- organic::types::Object::Superscript(inner) => Ok(IObject::Superscript(
- ISuperscript::new(registry, inner).await?,
- )),
- organic::types::Object::Timestamp(inner) => {
- Ok(IObject::Timestamp(ITimestamp::new(registry, inner).await?))
- }
- }
- }
- .boxed()
- }
-}
+iselector!(IObject, Object, original, registry, {
+ iitem!(
+ registry,
+ original,
+ (organic::types::Object::Bold, IObject::Bold, IBold),
+ (organic::types::Object::Italic, IObject::Italic, IItalic),
+ (
+ organic::types::Object::Underline,
+ IObject::Underline,
+ IUnderline
+ ),
+ (
+ organic::types::Object::StrikeThrough,
+ IObject::StrikeThrough,
+ IStrikeThrough
+ ),
+ (organic::types::Object::Code, IObject::Code, ICode),
+ (
+ organic::types::Object::Verbatim,
+ IObject::Verbatim,
+ IVerbatim
+ ),
+ (
+ organic::types::Object::PlainText,
+ IObject::PlainText,
+ IPlainText
+ ),
+ (
+ organic::types::Object::RegularLink,
+ IObject::RegularLink,
+ IRegularLink
+ ),
+ (
+ organic::types::Object::RadioLink,
+ IObject::RadioLink,
+ IRadioLink
+ ),
+ (
+ organic::types::Object::RadioTarget,
+ IObject::RadioTarget,
+ IRadioTarget
+ ),
+ (
+ organic::types::Object::PlainLink,
+ IObject::PlainLink,
+ IPlainLink
+ ),
+ (
+ organic::types::Object::AngleLink,
+ IObject::AngleLink,
+ IAngleLink
+ ),
+ (
+ organic::types::Object::OrgMacro,
+ IObject::OrgMacro,
+ IOrgMacro
+ ),
+ (organic::types::Object::Entity, IObject::Entity, IEntity),
+ (
+ organic::types::Object::LatexFragment,
+ IObject::LatexFragment,
+ ILatexFragment
+ ),
+ (
+ organic::types::Object::ExportSnippet,
+ IObject::ExportSnippet,
+ IExportSnippet
+ ),
+ (
+ organic::types::Object::FootnoteReference,
+ IObject::FootnoteReference,
+ IFootnoteReference
+ ),
+ (
+ organic::types::Object::Citation,
+ IObject::Citation,
+ ICitation
+ ),
+ (
+ organic::types::Object::CitationReference,
+ IObject::CitationReference,
+ ICitationReference
+ ),
+ (
+ organic::types::Object::InlineBabelCall,
+ IObject::InlineBabelCall,
+ IInlineBabelCall
+ ),
+ (
+ organic::types::Object::InlineSourceBlock,
+ IObject::InlineSourceBlock,
+ IInlineSourceBlock
+ ),
+ (
+ organic::types::Object::LineBreak,
+ IObject::LineBreak,
+ ILineBreak
+ ),
+ (organic::types::Object::Target, IObject::Target, ITarget),
+ (
+ organic::types::Object::StatisticsCookie,
+ IObject::StatisticsCookie,
+ IStatisticsCookie
+ ),
+ (
+ organic::types::Object::Subscript,
+ IObject::Subscript,
+ ISubscript
+ ),
+ (
+ organic::types::Object::Superscript,
+ IObject::Superscript,
+ ISuperscript
+ ),
+ (
+ organic::types::Object::Timestamp,
+ IObject::Timestamp,
+ ITimestamp
+ ),
+ )
+});
diff --git a/src/intermediate/org_macro.rs b/src/intermediate/org_macro.rs
index 328d89a..bae7384 100644
--- a/src/intermediate/org_macro.rs
+++ b/src/intermediate/org_macro.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct IOrgMacro {}
-
-impl IOrgMacro {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::OrgMacro<'parse>,
- ) -> Result {
- Ok(IOrgMacro {})
- }
-}
+inoop!(IOrgMacro, OrgMacro);
diff --git a/src/intermediate/page.rs b/src/intermediate/page.rs
index c512d46..404852e 100644
--- a/src/intermediate/page.rs
+++ b/src/intermediate/page.rs
@@ -2,10 +2,12 @@ use std::path::PathBuf;
use crate::error::CustomError;
+use super::footnote_definition::IRealFootnoteDefinition;
use super::registry::Registry;
use super::IDocumentElement;
use super::IHeading;
use super::ISection;
+use super::RefRegistry;
#[derive(Debug)]
pub(crate) struct BlogPostPage {
@@ -15,31 +17,51 @@ pub(crate) struct BlogPostPage {
pub(crate) title: Option,
pub(crate) children: Vec,
+
+ pub(crate) footnotes: Vec,
}
impl BlogPostPage {
- pub(crate) async fn new<'parse, P: Into>(
+ // TODO: Move path into the registry so I can give this a standard interface like the others.
+ pub(crate) async fn new<'a, 'b, 'parse, P: Into>(
path: P,
- registry: &mut Registry<'parse>,
- document: &organic::types::Document<'parse>,
+ registry: RefRegistry<'b, 'parse>,
+ document: &'b organic::types::Document<'parse>,
) -> Result {
let path = path.into();
let mut children = Vec::new();
if let Some(section) = document.zeroth_section.as_ref() {
children.push(IDocumentElement::Section(
- ISection::new(registry, section).await?,
+ ISection::new(registry.clone(), section).await?,
));
}
for heading in document.children.iter() {
children.push(IDocumentElement::Heading(
- IHeading::new(registry, heading).await?,
+ IHeading::new(registry.clone(), heading).await?,
));
}
+ let footnotes = {
+ let footnote_definitions: Vec<_> = {
+ let registry = registry.lock().unwrap();
+ let ret = registry
+ .get_footnote_ids()
+ .map(|(id, def)| (id, def.clone()))
+ .collect();
+ ret
+ };
+ let mut ret = Vec::new();
+ for (id, def) in footnote_definitions.into_iter() {
+ ret.push(IRealFootnoteDefinition::new(registry.clone(), id, def).await?);
+ }
+ ret
+ };
+
Ok(BlogPostPage {
path,
title: get_title(&document),
children,
+ footnotes,
})
}
diff --git a/src/intermediate/paragraph.rs b/src/intermediate/paragraph.rs
index 09cf1be..675f22e 100644
--- a/src/intermediate/paragraph.rs
+++ b/src/intermediate/paragraph.rs
@@ -1,26 +1,21 @@
-use crate::error::CustomError;
-
+use super::macros::intermediate;
use super::registry::Registry;
use super::IObject;
+use crate::error::CustomError;
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub(crate) struct IParagraph {
pub(crate) children: Vec,
}
-impl IParagraph {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- paragraph: &organic::types::Paragraph<'parse>,
- ) -> Result {
- let children = {
- let mut ret = Vec::new();
- for obj in paragraph.children.iter() {
- ret.push(IObject::new(registry, obj).await?);
- }
- ret
- };
+intermediate!(IParagraph, Paragraph, original, registry, {
+ let children = {
+ let mut ret = Vec::new();
+ for obj in original.children.iter() {
+ ret.push(IObject::new(registry.clone(), obj).await?);
+ }
+ ret
+ };
- Ok(IParagraph { children })
- }
-}
+ Ok(IParagraph { children })
+});
diff --git a/src/intermediate/plain_link.rs b/src/intermediate/plain_link.rs
index 8e702ed..68d0861 100644
--- a/src/intermediate/plain_link.rs
+++ b/src/intermediate/plain_link.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct IPlainLink {}
-
-impl IPlainLink {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::PlainLink<'parse>,
- ) -> Result {
- Ok(IPlainLink {})
- }
-}
+inoop!(IPlainLink, PlainLink);
diff --git a/src/intermediate/plain_list.rs b/src/intermediate/plain_list.rs
index 2065403..5a4e62b 100644
--- a/src/intermediate/plain_list.rs
+++ b/src/intermediate/plain_list.rs
@@ -1,30 +1,25 @@
-use crate::error::CustomError;
-
+use super::macros::intermediate;
use super::registry::Registry;
use super::IPlainListItem;
+use crate::error::CustomError;
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub(crate) struct IPlainList {
pub(crate) list_type: organic::types::PlainListType,
pub(crate) children: Vec,
}
-impl IPlainList {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- plain_list: &organic::types::PlainList<'parse>,
- ) -> Result {
- let children = {
- let mut ret = Vec::new();
- for obj in plain_list.children.iter() {
- ret.push(IPlainListItem::new(registry, obj).await?);
- }
- ret
- };
+intermediate!(IPlainList, PlainList, original, registry, {
+ let children = {
+ let mut ret = Vec::new();
+ for obj in original.children.iter() {
+ ret.push(IPlainListItem::new(registry.clone(), obj).await?);
+ }
+ ret
+ };
- Ok(IPlainList {
- list_type: plain_list.list_type,
- children,
- })
- }
-}
+ Ok(IPlainList {
+ list_type: original.list_type,
+ children,
+ })
+});
diff --git a/src/intermediate/plain_list_item.rs b/src/intermediate/plain_list_item.rs
index 8a77b9a..8bb03da 100644
--- a/src/intermediate/plain_list_item.rs
+++ b/src/intermediate/plain_list_item.rs
@@ -1,36 +1,31 @@
-use crate::error::CustomError;
-
+use super::macros::intermediate;
use super::registry::Registry;
use super::IElement;
use super::IObject;
+use crate::error::CustomError;
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub(crate) struct IPlainListItem {
pub(crate) tag: Vec,
pub(crate) children: Vec,
}
-impl IPlainListItem {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- plain_list_item: &organic::types::PlainListItem<'parse>,
- ) -> Result {
- let tag = {
- let mut ret = Vec::new();
- for obj in plain_list_item.tag.iter() {
- ret.push(IObject::new(registry, obj).await?);
- }
- ret
- };
+intermediate!(IPlainListItem, PlainListItem, original, registry, {
+ let tag = {
+ let mut ret = Vec::new();
+ for obj in original.tag.iter() {
+ ret.push(IObject::new(registry.clone(), obj).await?);
+ }
+ ret
+ };
- let children = {
- let mut ret = Vec::new();
- for elem in plain_list_item.children.iter() {
- ret.push(IElement::new(registry, elem).await?);
- }
- ret
- };
+ let children = {
+ let mut ret = Vec::new();
+ for elem in original.children.iter() {
+ ret.push(IElement::new(registry.clone(), elem).await?);
+ }
+ ret
+ };
- Ok(IPlainListItem { tag, children })
- }
-}
+ Ok(IPlainListItem { tag, children })
+});
diff --git a/src/intermediate/plain_text.rs b/src/intermediate/plain_text.rs
index d8d5558..1dceef4 100644
--- a/src/intermediate/plain_text.rs
+++ b/src/intermediate/plain_text.rs
@@ -1,20 +1,15 @@
-use crate::error::CustomError;
-use crate::intermediate::util::coalesce_whitespace;
-
+use super::macros::intermediate;
use super::registry::Registry;
+use super::util::coalesce_whitespace;
+use crate::error::CustomError;
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub(crate) struct IPlainText {
pub(crate) source: String,
}
-impl IPlainText {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- plain_text: &organic::types::PlainText<'parse>,
- ) -> Result {
- Ok(IPlainText {
- source: coalesce_whitespace(plain_text.source).into_owned(),
- })
- }
-}
+intermediate!(IPlainText, PlainText, original, registry, {
+ Ok(IPlainText {
+ source: coalesce_whitespace(original.source).into_owned(),
+ })
+});
diff --git a/src/intermediate/planning.rs b/src/intermediate/planning.rs
index d34c607..7de9746 100644
--- a/src/intermediate/planning.rs
+++ b/src/intermediate/planning.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct IPlanning {}
-
-impl IPlanning {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::Planning<'parse>,
- ) -> Result {
- Ok(IPlanning {})
- }
-}
+inoop!(IPlanning, Planning);
diff --git a/src/intermediate/property_drawer.rs b/src/intermediate/property_drawer.rs
index 422ab0d..9a42001 100644
--- a/src/intermediate/property_drawer.rs
+++ b/src/intermediate/property_drawer.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct IPropertyDrawer {}
-
-impl IPropertyDrawer {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::PropertyDrawer<'parse>,
- ) -> Result {
- Ok(IPropertyDrawer {})
- }
-}
+inoop!(IPropertyDrawer, PropertyDrawer);
diff --git a/src/intermediate/quote_block.rs b/src/intermediate/quote_block.rs
index 7d471b2..82ad4ed 100644
--- a/src/intermediate/quote_block.rs
+++ b/src/intermediate/quote_block.rs
@@ -1,26 +1,21 @@
-use crate::error::CustomError;
-
+use super::macros::intermediate;
use super::registry::Registry;
use super::IElement;
+use crate::error::CustomError;
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub(crate) struct IQuoteBlock {
pub(crate) children: Vec,
}
-impl IQuoteBlock {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::QuoteBlock<'parse>,
- ) -> Result {
- let children = {
- let mut ret = Vec::new();
- for obj in original.children.iter() {
- ret.push(IElement::new(registry, obj).await?);
- }
- ret
- };
+intermediate!(IQuoteBlock, QuoteBlock, original, registry, {
+ let children = {
+ let mut ret = Vec::new();
+ for obj in original.children.iter() {
+ ret.push(IElement::new(registry.clone(), obj).await?);
+ }
+ ret
+ };
- Ok(IQuoteBlock { children })
- }
-}
+ Ok(IQuoteBlock { children })
+});
diff --git a/src/intermediate/radio_link.rs b/src/intermediate/radio_link.rs
index 6886169..6dfea17 100644
--- a/src/intermediate/radio_link.rs
+++ b/src/intermediate/radio_link.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct IRadioLink {}
-
-impl IRadioLink {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::RadioLink<'parse>,
- ) -> Result {
- Ok(IRadioLink {})
- }
-}
+inoop!(IRadioLink, RadioLink);
diff --git a/src/intermediate/radio_target.rs b/src/intermediate/radio_target.rs
index 4077c29..01b20e9 100644
--- a/src/intermediate/radio_target.rs
+++ b/src/intermediate/radio_target.rs
@@ -1,15 +1,5 @@
+use super::macros::inoop;
+use super::registry::Registry;
use crate::error::CustomError;
-use super::registry::Registry;
-
-#[derive(Debug)]
-pub(crate) struct IRadioTarget {}
-
-impl IRadioTarget {
- pub(crate) async fn new<'parse>(
- registry: &mut Registry<'parse>,
- original: &organic::types::RadioTarget<'parse>,
- ) -> Result {
- Ok(IRadioTarget {})
- }
-}
+inoop!(IRadioTarget, RadioTarget);
diff --git a/src/intermediate/registry.rs b/src/intermediate/registry.rs
index d53e2ba..3ae276e 100644
--- a/src/intermediate/registry.rs
+++ b/src/intermediate/registry.rs
@@ -1,24 +1,201 @@
+use crate::error::CustomError;
+use organic::types::Element;
+use organic::types::Object;
use std::collections::HashMap;
+use super::ast_node::IAstNode;
+use super::ast_node::IntoIAstNode;
+use super::RefRegistry;
+
type IdCounter = u16;
-pub(crate) struct Registry<'parse> {
+pub(crate) struct Registry<'orig, 'parse> {
id_counter: IdCounter,
targets: HashMap<&'parse str, String>,
+ footnote_ids: Vec<(Option<&'parse str>, Vec)>,
+ footnote_reference_counts: HashMap<&'parse str, usize>,
+ on_deck_footnote_ids: HashMap<&'parse str, &'orig Vec>>,
}
-impl<'parse> Registry<'parse> {
- pub(crate) fn new() -> Registry<'parse> {
+impl<'orig, 'parse> Registry<'orig, 'parse> {
+ pub(crate) fn new() -> Registry<'orig, 'parse> {
Registry {
id_counter: 0,
targets: HashMap::new(),
+ footnote_ids: Vec::new(),
+ footnote_reference_counts: HashMap::new(),
+ on_deck_footnote_ids: HashMap::new(),
}
}
- pub(crate) fn get_target<'b>(&'b mut self, body: &'parse str) -> &'b String {
+ pub(crate) fn get_target<'reg>(&'reg mut self, body: &'parse str) -> &'reg String {
self.targets.entry(body).or_insert_with(|| {
self.id_counter += 1;
format!("target_{}", self.id_counter)
})
}
+
+ pub(crate) fn get_footnote_ids(&self) -> impl Iterator- )> {
+ self.footnote_ids
+ .iter()
+ .map(|(_label, definition)| definition)
+ .enumerate()
+ }
+}
+
+/// Get a 0-indexed ID for a footnote.
+///
+/// This needs to be incremented to be 1-indexed for render.
+pub(crate) async fn get_footnote_reference_id<'orig, 'parse>(
+ registry: RefRegistry<'orig, 'parse>,
+ label: Option<&'parse str>,
+ definition: &'orig Vec