Merge branch 'homepage'

This commit is contained in:
Tom Alexander 2023-12-19 18:08:50 -05:00
commit 050b426f6f
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
102 changed files with 1519 additions and 1405 deletions

View File

@ -1,6 +1,6 @@
<div class="blog_post"> <div class="blog_post">
<div class="blog_post_intro"> <div class="blog_post_intro">
{?.title}{?.self_link}<a class="blog_post_title" href="{.link}">{.title}</a>{:else}<div class="blog_post_title">{.title}</div>{/.self_link}{/.title} {?.title}{?.self_link}<a class="blog_post_title" href="{.self_link}">{.title}</a>{:else}<div class="blog_post_title">{.title}</div>{/.self_link}{/.title}
{! TODO: date? !} {! TODO: date? !}
</div> </div>

View File

@ -0,0 +1,31 @@
<div class="blog_stream">
{#.children}
<div class="blog_stream_post">
<div class="blog_post_intro">
{?.title}{?.self_link}<a class="blog_post_title" href="{.self_link}">{.title}</a>{:else}<div class="blog_post_title">{.title}</div>{/.self_link}{/.title}
{! TODO: date? !}
</div>
{! TODO: Table of contents? !}
<div class="blog_post_body">
{#.children}
{>document_element/}
{/.children}
{?.footnotes}
<h2>Footnotes:</h2>
{#.footnotes}
{>real_footnote_definition/}
{/.footnotes}
{/.footnotes}
</div>
</div>
{/.children}
{#.stream_pagination}
<div class="stream_nav">
{?.older_link}<a href="{.older_link}">Older</a>{/.older_link}
{?.newer_link}<a href="{.newer_link}">Newer</a>{/.newer_link}
</div>
{/.stream_pagination}
</div>

View File

@ -11,6 +11,7 @@
<div class="main_content"> <div class="main_content">
{@select key=.type} {@select key=.type}
{@eq value="blog_post_page"}{>blog_post_page/}{/eq} {@eq value="blog_post_page"}{>blog_post_page/}{/eq}
{@eq value="blog_stream"}{>blog_stream/}{/eq}
{@none}{!TODO: make this panic!}ERROR: Unrecognized page content type{/none} {@none}{!TODO: make this panic!}ERROR: Unrecognized page content type{/none}
{/select} {/select}
</div> </div>

View File

@ -5,8 +5,13 @@ use include_dir::include_dir;
use include_dir::Dir; use include_dir::Dir;
use crate::config::Config; use crate::config::Config;
use crate::context::RenderBlogPostPage;
use crate::context::RenderBlogPostPageInput;
use crate::context::RenderBlogStream;
use crate::context::RenderBlogStreamInput;
use crate::context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::convert_blog_post_page_to_render_context; use crate::intermediate::get_web_path;
use crate::intermediate::BlogPost; use crate::intermediate::BlogPost;
use crate::render::DusterRenderer; use crate::render::DusterRenderer;
use crate::render::RendererIntegration; use crate::render::RendererIntegration;
@ -34,7 +39,7 @@ impl SiteRenderer {
} }
} }
pub(crate) async fn render_blog_posts(&self, config: &Config) -> Result<(), CustomError> { fn init_renderer_integration(&self) -> Result<DusterRenderer<'_>, CustomError> {
let mut renderer_integration = DusterRenderer::new(); let mut renderer_integration = DusterRenderer::new();
let sources: Vec<_> = MAIN_TEMPLATES let sources: Vec<_> = MAIN_TEMPLATES
@ -62,21 +67,27 @@ impl SiteRenderer {
renderer_integration.load_template(name, contents)?; renderer_integration.load_template(name, contents)?;
} }
Ok(renderer_integration)
}
pub(crate) async fn render_blog_posts(&self, config: &Config) -> Result<(), CustomError> {
let renderer_integration = self.init_renderer_integration()?;
for blog_post in &self.blog_posts { for blog_post in &self.blog_posts {
for blog_post_page in &blog_post.pages { for blog_post_page in &blog_post.pages {
let output_path = self let output_path = self
.output_directory .output_directory
.join("posts") .join(config.get_relative_path_to_post(&blog_post.id))
.join(&blog_post.id)
.join(blog_post_page.get_output_path()); .join(blog_post_page.get_output_path());
let render_context = convert_blog_post_page_to_render_context( let convert_input = RenderBlogPostPageInput::new(blog_post, blog_post_page);
let render_context = RenderContext::new(
config, config,
&self.output_directory, self.output_directory.as_path(),
&output_path, output_path.as_path(),
blog_post, None,
blog_post_page,
)?; )?;
let render_context = RenderBlogPostPage::new(render_context, &convert_input)?;
let rendered_output = renderer_integration.render(render_context)?; let rendered_output = renderer_integration.render(render_context)?;
let parent_directory = output_path let parent_directory = output_path
.parent() .parent()
@ -89,6 +100,87 @@ impl SiteRenderer {
Ok(()) Ok(())
} }
pub(crate) async fn render_blog_stream(&self, config: &Config) -> Result<(), CustomError> {
let renderer_integration = self.init_renderer_integration()?;
// Sort blog posts by date, newest first.
let sorted_blog_posts = {
let mut sorted_blog_posts: Vec<_> = self.blog_posts.iter().collect();
sorted_blog_posts
.sort_by_key(|blog_post| (blog_post.get_date(), blog_post.id.as_str()));
sorted_blog_posts.reverse();
sorted_blog_posts
};
for blog_post in &sorted_blog_posts {
if blog_post.get_date().is_none() {
return Err(format!("Blog post {} does not have a date.", blog_post.id).into());
}
}
// Group blog posts based on # of posts per page.
let stream_chunks: Vec<_> = sorted_blog_posts
.chunks(config.get_stream_entries_per_page())
.collect();
// For each group, create a RenderBlogStream.
let num_stream_pages = stream_chunks.len();
for (page_num, chunk) in stream_chunks.into_iter().enumerate() {
let output_file = if page_num == 0 {
self.output_directory.join("index.html")
} else {
self.output_directory
.join("stream")
.join(format!("{}.html", page_num))
};
let newer_link = if page_num == 0 {
None
} else if page_num == 1 {
Some(get_web_path(
config,
&self.output_directory,
&output_file,
"index.html",
)?)
} else {
Some(get_web_path(
config,
&self.output_directory,
&output_file,
format!("stream/{}.html", page_num - 1),
)?)
};
let older_link = if page_num == (num_stream_pages - 1) {
None
} else {
Some(get_web_path(
config,
&self.output_directory,
&output_file,
format!("stream/{}.html", page_num + 1),
)?)
};
let convert_input = RenderBlogStreamInput::new(chunk, older_link, newer_link);
let render_context = RenderContext::new(
config,
self.output_directory.as_path(),
output_file.as_path(),
None,
)?;
let blog_stream = RenderBlogStream::new(render_context, &convert_input)?;
// Pass each RenderBlogStream to dust as the context to render index.html and any additional stream pages.
let rendered_output = renderer_integration.render(blog_stream)?;
let parent_directory = output_file
.parent()
.ok_or("Output file should have a containing directory.")?;
tokio::fs::create_dir_all(parent_directory).await?;
tokio::fs::write(output_file, rendered_output).await?;
}
Ok(())
}
pub(crate) async fn render_stylesheets(&self) -> Result<(), CustomError> { pub(crate) async fn render_stylesheets(&self) -> Result<(), CustomError> {
let stylesheet_output_directory = self.output_directory.join("stylesheet"); let stylesheet_output_directory = self.output_directory.join("stylesheet");
if !stylesheet_output_directory.exists() { if !stylesheet_output_directory.exists() {

View File

@ -23,6 +23,7 @@ pub(crate) async fn build_site(args: BuildArgs) -> Result<(), CustomError> {
stylesheets, stylesheets,
); );
renderer.render_blog_posts(&config).await?; renderer.render_blog_posts(&config).await?;
renderer.render_blog_stream(&config).await?;
renderer.render_stylesheets().await?; renderer.render_stylesheets().await?;
Ok(()) Ok(())

View File

@ -8,6 +8,7 @@ use crate::error::CustomError;
use super::raw::RawConfig; use super::raw::RawConfig;
/// This is the config struct used by most of the code, which is an interpreted version of the RawConfig struct which is the raw disk-representation of the config. /// This is the config struct used by most of the code, which is an interpreted version of the RawConfig struct which is the raw disk-representation of the config.
#[derive(Debug)]
pub(crate) struct Config { pub(crate) struct Config {
raw: RawConfig, raw: RawConfig,
config_path: PathBuf, config_path: PathBuf,
@ -56,6 +57,15 @@ impl Config {
self.get_root_directory().join("posts") self.get_root_directory().join("posts")
} }
/// Get the relative path to the folder containing a blog post.
///
/// This could be appended to the output root directory to get the
/// blog post output folder or it could be used to generate a link
/// to the blog post.
pub(crate) fn get_relative_path_to_post<P: AsRef<Path>>(&self, post_id: P) -> PathBuf {
Path::new("posts").join(post_id)
}
pub(crate) fn get_output_directory(&self) -> PathBuf { pub(crate) fn get_output_directory(&self) -> PathBuf {
self.get_root_directory().join("output") self.get_root_directory().join("output")
} }
@ -71,4 +81,13 @@ impl Config {
pub(crate) fn get_site_title(&self) -> Option<&str> { pub(crate) fn get_site_title(&self) -> Option<&str> {
self.raw.site_title.as_deref() self.raw.site_title.as_deref()
} }
pub(crate) fn get_stream_entries_per_page(&self) -> usize {
self.raw
.stream
.as_ref()
.map(|stream| stream.entries_per_page)
.flatten()
.unwrap_or(5)
}
} }

View File

@ -2,13 +2,14 @@ use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
/// This is the struct for the writer.toml config file that ends up in each site's root directory. /// This is the struct for the writer.toml config file that ends up in each site's root directory.
#[derive(Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
pub(crate) struct RawConfig { pub(crate) struct RawConfig {
pub(super) site_title: Option<String>, pub(super) site_title: Option<String>,
author: Option<String>, author: Option<String>,
email: Option<String>, email: Option<String>,
pub(super) use_relative_paths: Option<bool>, pub(super) use_relative_paths: Option<bool>,
pub(super) web_root: Option<String>, pub(super) web_root: Option<String>,
pub(super) stream: Option<RawConfigStream>,
} }
impl Default for RawConfig { impl Default for RawConfig {
@ -19,6 +20,20 @@ impl Default for RawConfig {
email: None, email: None,
use_relative_paths: None, use_relative_paths: None,
web_root: None, web_root: None,
stream: None,
}
}
}
#[derive(Debug, Deserialize, Serialize)]
pub(crate) struct RawConfigStream {
pub(super) entries_per_page: Option<usize>,
}
impl Default for RawConfigStream {
fn default() -> Self {
RawConfigStream {
entries_per_page: None,
} }
} }
} }

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IAngleLink; use crate::intermediate::IAngleLink;

View File

@ -1,8 +1,5 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IAstNode; use crate::intermediate::IAstNode;
@ -45,6 +42,7 @@ use super::quote_block::RenderQuoteBlock;
use super::radio_link::RenderRadioLink; use super::radio_link::RenderRadioLink;
use super::radio_target::RenderRadioTarget; use super::radio_target::RenderRadioTarget;
use super::regular_link::RenderRegularLink; use super::regular_link::RenderRegularLink;
use super::render_context::RenderContext;
use super::special_block::RenderSpecialBlock; use super::special_block::RenderSpecialBlock;
use super::src_block::RenderSrcBlock; use super::src_block::RenderSrcBlock;
use super::statistics_cookie::RenderStatisticsCookie; use super::statistics_cookie::RenderStatisticsCookie;
@ -121,285 +119,207 @@ pub(crate) enum RenderAstNode {
pub(crate) trait IntoRenderAstNode { pub(crate) trait IntoRenderAstNode {
fn into_render_ast_node( fn into_render_ast_node(
&self, &self,
config: &Config, render_context: RenderContext<'_>,
output_directory: &Path,
output_file: &Path,
) -> Result<RenderAstNode, CustomError>; ) -> Result<RenderAstNode, CustomError>;
} }
impl IntoRenderAstNode for IAstNode { impl IntoRenderAstNode for IAstNode {
fn into_render_ast_node( fn into_render_ast_node(
&self, &self,
config: &Config, render_context: RenderContext<'_>,
output_directory: &Path,
output_file: &Path,
) -> Result<RenderAstNode, CustomError> { ) -> Result<RenderAstNode, CustomError> {
match self { match self {
IAstNode::Heading(inner) => Ok(RenderAstNode::Heading(RenderHeading::new( IAstNode::Heading(inner) => Ok(RenderAstNode::Heading(RenderHeading::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::Section(inner) => Ok(RenderAstNode::Section(RenderSection::new( IAstNode::Section(inner) => Ok(RenderAstNode::Section(RenderSection::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::Paragraph(inner) => Ok(RenderAstNode::Paragraph(RenderParagraph::new( IAstNode::Paragraph(inner) => Ok(RenderAstNode::Paragraph(RenderParagraph::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::PlainList(inner) => Ok(RenderAstNode::PlainList(RenderPlainList::new( IAstNode::PlainList(inner) => Ok(RenderAstNode::PlainList(RenderPlainList::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::CenterBlock(inner) => Ok(RenderAstNode::CenterBlock(RenderCenterBlock::new( IAstNode::CenterBlock(inner) => Ok(RenderAstNode::CenterBlock(RenderCenterBlock::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::QuoteBlock(inner) => Ok(RenderAstNode::QuoteBlock(RenderQuoteBlock::new( IAstNode::QuoteBlock(inner) => Ok(RenderAstNode::QuoteBlock(RenderQuoteBlock::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::SpecialBlock(inner) => Ok(RenderAstNode::SpecialBlock( IAstNode::SpecialBlock(inner) => Ok(RenderAstNode::SpecialBlock(
RenderSpecialBlock::new(config, output_directory, output_file, inner)?, RenderSpecialBlock::new(render_context, inner)?,
)), )),
IAstNode::DynamicBlock(inner) => Ok(RenderAstNode::DynamicBlock( IAstNode::DynamicBlock(inner) => Ok(RenderAstNode::DynamicBlock(
RenderDynamicBlock::new(config, output_directory, output_file, inner)?, RenderDynamicBlock::new(render_context, inner)?,
)), )),
IAstNode::FootnoteDefinition(inner) => Ok(RenderAstNode::FootnoteDefinition( IAstNode::FootnoteDefinition(inner) => Ok(RenderAstNode::FootnoteDefinition(
RenderFootnoteDefinition::new(config, output_directory, output_file, inner)?, RenderFootnoteDefinition::new(render_context, inner)?,
)), )),
IAstNode::Comment(inner) => Ok(RenderAstNode::Comment(RenderComment::new( IAstNode::Comment(inner) => Ok(RenderAstNode::Comment(RenderComment::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::Drawer(inner) => Ok(RenderAstNode::Drawer(RenderDrawer::new( IAstNode::Drawer(inner) => Ok(RenderAstNode::Drawer(RenderDrawer::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::PropertyDrawer(inner) => Ok(RenderAstNode::PropertyDrawer( IAstNode::PropertyDrawer(inner) => Ok(RenderAstNode::PropertyDrawer(
RenderPropertyDrawer::new(config, output_directory, output_file, inner)?, RenderPropertyDrawer::new(render_context, inner)?,
)), )),
IAstNode::Table(inner) => Ok(RenderAstNode::Table(RenderTable::new( IAstNode::Table(inner) => Ok(RenderAstNode::Table(RenderTable::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::VerseBlock(inner) => Ok(RenderAstNode::VerseBlock(RenderVerseBlock::new( IAstNode::VerseBlock(inner) => Ok(RenderAstNode::VerseBlock(RenderVerseBlock::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::CommentBlock(inner) => Ok(RenderAstNode::CommentBlock( IAstNode::CommentBlock(inner) => Ok(RenderAstNode::CommentBlock(
RenderCommentBlock::new(config, output_directory, output_file, inner)?, RenderCommentBlock::new(render_context, inner)?,
)), )),
IAstNode::ExampleBlock(inner) => Ok(RenderAstNode::ExampleBlock( IAstNode::ExampleBlock(inner) => Ok(RenderAstNode::ExampleBlock(
RenderExampleBlock::new(config, output_directory, output_file, inner)?, RenderExampleBlock::new(render_context, inner)?,
)), )),
IAstNode::ExportBlock(inner) => Ok(RenderAstNode::ExportBlock(RenderExportBlock::new( IAstNode::ExportBlock(inner) => Ok(RenderAstNode::ExportBlock(RenderExportBlock::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::SrcBlock(inner) => Ok(RenderAstNode::SrcBlock(RenderSrcBlock::new( IAstNode::SrcBlock(inner) => Ok(RenderAstNode::SrcBlock(RenderSrcBlock::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::Clock(inner) => Ok(RenderAstNode::Clock(RenderClock::new( IAstNode::Clock(inner) => Ok(RenderAstNode::Clock(RenderClock::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::DiarySexp(inner) => Ok(RenderAstNode::DiarySexp(RenderDiarySexp::new( IAstNode::DiarySexp(inner) => Ok(RenderAstNode::DiarySexp(RenderDiarySexp::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::Planning(inner) => Ok(RenderAstNode::Planning(RenderPlanning::new( IAstNode::Planning(inner) => Ok(RenderAstNode::Planning(RenderPlanning::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::FixedWidthArea(inner) => Ok(RenderAstNode::FixedWidthArea( IAstNode::FixedWidthArea(inner) => Ok(RenderAstNode::FixedWidthArea(
RenderFixedWidthArea::new(config, output_directory, output_file, inner)?, RenderFixedWidthArea::new(render_context, inner)?,
)), )),
IAstNode::HorizontalRule(inner) => Ok(RenderAstNode::HorizontalRule( IAstNode::HorizontalRule(inner) => Ok(RenderAstNode::HorizontalRule(
RenderHorizontalRule::new(config, output_directory, output_file, inner)?, RenderHorizontalRule::new(render_context, inner)?,
)), )),
IAstNode::Keyword(inner) => Ok(RenderAstNode::Keyword(RenderKeyword::new( IAstNode::Keyword(inner) => Ok(RenderAstNode::Keyword(RenderKeyword::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::BabelCall(inner) => Ok(RenderAstNode::BabelCall(RenderBabelCall::new( IAstNode::BabelCall(inner) => Ok(RenderAstNode::BabelCall(RenderBabelCall::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::LatexEnvironment(inner) => Ok(RenderAstNode::LatexEnvironment( IAstNode::LatexEnvironment(inner) => Ok(RenderAstNode::LatexEnvironment(
RenderLatexEnvironment::new(config, output_directory, output_file, inner)?, RenderLatexEnvironment::new(render_context, inner)?,
)), )),
IAstNode::Bold(inner) => Ok(RenderAstNode::Bold(RenderBold::new( IAstNode::Bold(inner) => {
config, Ok(RenderAstNode::Bold(RenderBold::new(render_context, inner)?))
output_directory, }
output_file,
inner,
)?)),
IAstNode::Italic(inner) => Ok(RenderAstNode::Italic(RenderItalic::new( IAstNode::Italic(inner) => Ok(RenderAstNode::Italic(RenderItalic::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::Underline(inner) => Ok(RenderAstNode::Underline(RenderUnderline::new( IAstNode::Underline(inner) => Ok(RenderAstNode::Underline(RenderUnderline::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::StrikeThrough(inner) => Ok(RenderAstNode::StrikeThrough( IAstNode::StrikeThrough(inner) => Ok(RenderAstNode::StrikeThrough(
RenderStrikeThrough::new(config, output_directory, output_file, inner)?, RenderStrikeThrough::new(render_context, inner)?,
)), )),
IAstNode::Code(inner) => Ok(RenderAstNode::Code(RenderCode::new( IAstNode::Code(inner) => {
config, Ok(RenderAstNode::Code(RenderCode::new(render_context, inner)?))
output_directory, }
output_file,
inner,
)?)),
IAstNode::Verbatim(inner) => Ok(RenderAstNode::Verbatim(RenderVerbatim::new( IAstNode::Verbatim(inner) => Ok(RenderAstNode::Verbatim(RenderVerbatim::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::PlainText(inner) => Ok(RenderAstNode::PlainText(RenderPlainText::new( IAstNode::PlainText(inner) => Ok(RenderAstNode::PlainText(RenderPlainText::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::RegularLink(inner) => Ok(RenderAstNode::RegularLink(RenderRegularLink::new( IAstNode::RegularLink(inner) => Ok(RenderAstNode::RegularLink(RenderRegularLink::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::RadioLink(inner) => Ok(RenderAstNode::RadioLink(RenderRadioLink::new( IAstNode::RadioLink(inner) => Ok(RenderAstNode::RadioLink(RenderRadioLink::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::RadioTarget(inner) => Ok(RenderAstNode::RadioTarget(RenderRadioTarget::new( IAstNode::RadioTarget(inner) => Ok(RenderAstNode::RadioTarget(RenderRadioTarget::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::PlainLink(inner) => Ok(RenderAstNode::PlainLink(RenderPlainLink::new( IAstNode::PlainLink(inner) => Ok(RenderAstNode::PlainLink(RenderPlainLink::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::AngleLink(inner) => Ok(RenderAstNode::AngleLink(RenderAngleLink::new( IAstNode::AngleLink(inner) => Ok(RenderAstNode::AngleLink(RenderAngleLink::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::OrgMacro(inner) => Ok(RenderAstNode::OrgMacro(RenderOrgMacro::new( IAstNode::OrgMacro(inner) => Ok(RenderAstNode::OrgMacro(RenderOrgMacro::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::Entity(inner) => Ok(RenderAstNode::Entity(RenderEntity::new( IAstNode::Entity(inner) => Ok(RenderAstNode::Entity(RenderEntity::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::LatexFragment(inner) => Ok(RenderAstNode::LatexFragment( IAstNode::LatexFragment(inner) => Ok(RenderAstNode::LatexFragment(
RenderLatexFragment::new(config, output_directory, output_file, inner)?, RenderLatexFragment::new(render_context, inner)?,
)), )),
IAstNode::ExportSnippet(inner) => Ok(RenderAstNode::ExportSnippet( IAstNode::ExportSnippet(inner) => Ok(RenderAstNode::ExportSnippet(
RenderExportSnippet::new(config, output_directory, output_file, inner)?, RenderExportSnippet::new(render_context, inner)?,
)), )),
IAstNode::FootnoteReference(inner) => Ok(RenderAstNode::FootnoteReference( IAstNode::FootnoteReference(inner) => Ok(RenderAstNode::FootnoteReference(
RenderFootnoteReference::new(config, output_directory, output_file, inner)?, RenderFootnoteReference::new(render_context, inner)?,
)), )),
IAstNode::Citation(inner) => Ok(RenderAstNode::Citation(RenderCitation::new( IAstNode::Citation(inner) => Ok(RenderAstNode::Citation(RenderCitation::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::CitationReference(inner) => Ok(RenderAstNode::CitationReference( IAstNode::CitationReference(inner) => Ok(RenderAstNode::CitationReference(
RenderCitationReference::new(config, output_directory, output_file, inner)?, RenderCitationReference::new(render_context, inner)?,
)), )),
IAstNode::InlineBabelCall(inner) => Ok(RenderAstNode::InlineBabelCall( IAstNode::InlineBabelCall(inner) => Ok(RenderAstNode::InlineBabelCall(
RenderInlineBabelCall::new(config, output_directory, output_file, inner)?, RenderInlineBabelCall::new(render_context, inner)?,
)), )),
IAstNode::InlineSourceBlock(inner) => Ok(RenderAstNode::InlineSourceBlock( IAstNode::InlineSourceBlock(inner) => Ok(RenderAstNode::InlineSourceBlock(
RenderInlineSourceBlock::new(config, output_directory, output_file, inner)?, RenderInlineSourceBlock::new(render_context, inner)?,
)), )),
IAstNode::LineBreak(inner) => Ok(RenderAstNode::LineBreak(RenderLineBreak::new( IAstNode::LineBreak(inner) => Ok(RenderAstNode::LineBreak(RenderLineBreak::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::Target(inner) => Ok(RenderAstNode::Target(RenderTarget::new( IAstNode::Target(inner) => Ok(RenderAstNode::Target(RenderTarget::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::StatisticsCookie(inner) => Ok(RenderAstNode::StatisticsCookie( IAstNode::StatisticsCookie(inner) => Ok(RenderAstNode::StatisticsCookie(
RenderStatisticsCookie::new(config, output_directory, output_file, inner)?, RenderStatisticsCookie::new(render_context, inner)?,
)), )),
IAstNode::Subscript(inner) => Ok(RenderAstNode::Subscript(RenderSubscript::new( IAstNode::Subscript(inner) => Ok(RenderAstNode::Subscript(RenderSubscript::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::Superscript(inner) => Ok(RenderAstNode::Superscript(RenderSuperscript::new( IAstNode::Superscript(inner) => Ok(RenderAstNode::Superscript(RenderSuperscript::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
IAstNode::Timestamp(inner) => Ok(RenderAstNode::Timestamp(RenderTimestamp::new( IAstNode::Timestamp(inner) => Ok(RenderAstNode::Timestamp(RenderTimestamp::new(
config, render_context,
output_directory,
output_file,
inner, inner,
)?)), )?)),
} }

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IBabelCall; use crate::intermediate::IBabelCall;

View File

@ -1,10 +1,29 @@
use serde::Serialize; use serde::Serialize;
use super::render_context::RenderContext;
use crate::error::CustomError;
use crate::intermediate::get_web_path;
use crate::intermediate::BlogPost;
use crate::intermediate::BlogPostPage;
use super::footnote_definition::RenderRealFootnoteDefinition; use super::footnote_definition::RenderRealFootnoteDefinition;
use super::macros::render;
use super::GlobalSettings; use super::GlobalSettings;
use super::PageHeader; use super::PageHeader;
use super::RenderDocumentElement; use super::RenderDocumentElement;
#[derive(Debug)]
pub(crate) struct RenderBlogPostPageInput<'a> {
post: &'a BlogPost,
page: &'a BlogPostPage,
}
impl<'a> RenderBlogPostPageInput<'a> {
pub(crate) fn new(post: &'a BlogPost, page: &'a BlogPostPage) -> RenderBlogPostPageInput<'a> {
RenderBlogPostPageInput { post, page }
}
}
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
#[serde(tag = "type")] #[serde(tag = "type")]
#[serde(rename = "blog_post_page")] #[serde(rename = "blog_post_page")]
@ -23,23 +42,82 @@ pub(crate) struct RenderBlogPostPage {
footnotes: Vec<RenderRealFootnoteDefinition>, footnotes: Vec<RenderRealFootnoteDefinition>,
} }
impl RenderBlogPostPage { render!(
// TODO: Maybe these settings should be moved into a common struct so this can have the same type signature as the others. RenderBlogPostPage,
pub(crate) fn new( RenderBlogPostPageInput,
global_settings: GlobalSettings, original,
page_header: Option<PageHeader>, render_context,
title: Option<String>, {
self_link: Option<String>, let css_files = vec![
children: Vec<RenderDocumentElement>, get_web_path(
footnotes: Vec<RenderRealFootnoteDefinition>, render_context.config,
) -> RenderBlogPostPage { render_context.output_root_directory,
RenderBlogPostPage { render_context.output_file,
"stylesheet/reset.css",
)?,
get_web_path(
render_context.config,
render_context.output_root_directory,
render_context.output_file,
"stylesheet/main.css",
)?,
];
let js_files = vec![get_web_path(
render_context.config,
render_context.output_root_directory,
render_context.output_file,
"blog_post.js",
)?];
let global_settings = GlobalSettings::new(original.page.title.clone(), css_files, js_files);
let page_header = PageHeader::new(
render_context.config.get_site_title().map(str::to_string),
Some(get_web_path(
render_context.config,
render_context.output_root_directory,
render_context.output_file,
"",
)?),
);
let link_to_blog_post = get_web_path(
render_context.config,
render_context.output_root_directory,
render_context.output_file,
render_context
.output_file
.strip_prefix(render_context.output_root_directory)?,
)?;
let children = {
let mut children = Vec::new();
for child in original.page.children.iter() {
children.push(RenderDocumentElement::new(render_context.clone(), child)?);
}
children
};
let footnotes = {
let mut ret = Vec::new();
for footnote in original.page.footnotes.iter() {
ret.push(RenderRealFootnoteDefinition::new(
render_context.clone(),
footnote,
)?);
}
ret
};
let ret = RenderBlogPostPage {
global_settings, global_settings,
page_header, page_header: Some(page_header),
title, title: original.page.title.clone(),
self_link, self_link: Some(link_to_blog_post),
children, children,
footnotes, footnotes,
} };
Ok(ret)
} }
} );

213
src/context/blog_stream.rs Normal file
View File

@ -0,0 +1,213 @@
use serde::Serialize;
use super::macros::render;
use super::render_context::RenderContext;
use crate::context::RenderDocumentElement;
use crate::context::RenderRealFootnoteDefinition;
use crate::error::CustomError;
use crate::intermediate::get_web_path;
use crate::intermediate::BlogPost;
use super::GlobalSettings;
use super::PageHeader;
#[derive(Debug)]
pub(crate) struct RenderBlogStreamInput<'a, 'b> {
original: &'a [&'b BlogPost],
older_link: Option<String>,
newer_link: Option<String>,
}
impl<'a, 'b> RenderBlogStreamInput<'a, 'b> {
pub(crate) fn new(
original: &'a [&'b BlogPost],
older_link: Option<String>,
newer_link: Option<String>,
) -> RenderBlogStreamInput<'a, 'b> {
RenderBlogStreamInput {
original,
older_link,
newer_link,
}
}
}
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[serde(rename = "blog_stream")]
pub(crate) struct RenderBlogStream {
global_settings: GlobalSettings,
page_header: Option<PageHeader>,
children: Vec<RenderBlogStreamEntry>,
stream_pagination: Option<RenderBlogStreamPagination>,
}
render!(
RenderBlogStream,
RenderBlogStreamInput,
original,
render_context,
{
let css_files = vec![
get_web_path(
render_context.config,
render_context.output_root_directory,
render_context.output_file,
"stylesheet/reset.css",
)?,
get_web_path(
render_context.config,
render_context.output_root_directory,
render_context.output_file,
"stylesheet/main.css",
)?,
];
let js_files = vec![get_web_path(
render_context.config,
render_context.output_root_directory,
render_context.output_file,
"blog_post.js",
)?];
let global_settings = GlobalSettings::new(
render_context.config.get_site_title().map(str::to_string),
css_files,
js_files,
);
let page_header = PageHeader::new(
render_context.config.get_site_title().map(str::to_string),
Some(get_web_path(
render_context.config,
render_context.output_root_directory,
render_context.output_file,
"",
)?),
);
let children = original
.original
.into_iter()
.enumerate()
.map(|(i, blog_post)| {
RenderBlogStreamEntry::new(
render_context.clone(),
&RenderBlogStreamEntryInput::new(blog_post, i),
)
})
.collect::<Result<Vec<_>, _>>()?;
let stream_pagination = if original.older_link.is_some() || original.newer_link.is_some() {
Some(RenderBlogStreamPagination::new(
original.older_link.clone(),
original.newer_link.clone(),
)?)
} else {
None
};
Ok(RenderBlogStream {
global_settings,
page_header: Some(page_header),
children,
stream_pagination,
})
}
);
#[derive(Debug)]
pub(crate) struct RenderBlogStreamEntryInput<'a> {
original: &'a BlogPost,
offset: usize,
}
impl<'a> RenderBlogStreamEntryInput<'a> {
fn new(original: &'a BlogPost, offset: usize) -> RenderBlogStreamEntryInput<'a> {
RenderBlogStreamEntryInput { original, offset }
}
}
#[derive(Debug, Serialize)]
pub(crate) struct RenderBlogStreamEntry {
/// The title that will be shown visibly on the page.
title: Option<String>,
self_link: Option<String>,
children: Vec<RenderDocumentElement>,
footnotes: Vec<RenderRealFootnoteDefinition>,
}
render!(
RenderBlogStreamEntry,
RenderBlogStreamEntryInput,
original,
render_context,
{
let offset_string = original.offset.to_string();
let render_context = {
let mut render_context = render_context.clone();
render_context.id_addition = Some(offset_string.as_str());
render_context
};
let link_to_blog_post = get_web_path(
render_context.config,
render_context.output_root_directory,
render_context.output_file,
render_context
.config
.get_relative_path_to_post(&original.original.id),
)?;
// TODO: Should I guess an index page instead of erroring out?
let index_page = original
.original
.get_index_page()
.ok_or_else(|| format!("Blog post {} needs an index page.", original.original.id))?;
let title = index_page.title.clone();
let children = index_page
.children
.iter()
.map(|child| RenderDocumentElement::new(render_context.clone(), child))
.collect::<Result<Vec<_>, _>>()?;
let footnotes = {
let mut ret = Vec::new();
for footnote in index_page.footnotes.iter() {
ret.push(RenderRealFootnoteDefinition::new(
render_context.clone(),
footnote,
)?);
}
ret
};
Ok(RenderBlogStreamEntry {
title,
self_link: Some(link_to_blog_post),
children,
footnotes,
})
}
);
#[derive(Debug, Serialize)]
pub(crate) struct RenderBlogStreamPagination {
older_link: Option<String>,
newer_link: Option<String>,
}
impl RenderBlogStreamPagination {
fn new(
older_link: Option<String>,
newer_link: Option<String>,
) -> Result<RenderBlogStreamPagination, CustomError> {
Ok(RenderBlogStreamPagination {
older_link,
newer_link,
})
}
}

View File

@ -1,12 +1,10 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IBold; use crate::intermediate::IBold;
use super::macros::render; use super::macros::render;
use super::render_context::RenderContext;
use super::RenderObject; use super::RenderObject;
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
@ -16,27 +14,14 @@ pub(crate) struct RenderBold {
children: Vec<RenderObject>, children: Vec<RenderObject>,
} }
render!( render!(RenderBold, IBold, original, render_context, {
RenderBold, let children = {
IBold, let mut ret = Vec::new();
original, for obj in original.children.iter() {
config, ret.push(RenderObject::new(render_context.clone(), obj)?);
output_directory, }
output_file, ret
{ };
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderObject::new(
config,
output_directory,
output_file,
obj,
)?);
}
ret
};
Ok(RenderBold { children }) Ok(RenderBold { children })
} });
);

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::ICenterBlock; use crate::intermediate::ICenterBlock;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::ICitation; use crate::intermediate::ICitation;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::ICitationReference; use crate::intermediate::ICitationReference;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IClock; use crate::intermediate::IClock;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::ICode; use crate::intermediate::ICode;
@ -15,16 +13,8 @@ pub(crate) struct RenderCode {
contents: String, contents: String,
} }
render!( render!(RenderCode, ICode, original, _render_context, {
RenderCode, Ok(RenderCode {
ICode, contents: original.contents.clone(),
original, })
_config, });
_output_directory,
_output_file,
{
Ok(RenderCode {
contents: original.contents.clone(),
})
}
);

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IComment; use crate::intermediate::IComment;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::ICommentBlock; use crate::intermediate::ICommentBlock;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IDiarySexp; use crate::intermediate::IDiarySexp;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IDocumentElement; use crate::intermediate::IDocumentElement;
@ -21,16 +19,14 @@ render!(
RenderDocumentElement, RenderDocumentElement,
IDocumentElement, IDocumentElement,
original, original,
config, render_context,
output_directory,
output_file,
{ {
match original { match original {
IDocumentElement::Heading(inner) => Ok(RenderDocumentElement::Heading( IDocumentElement::Heading(inner) => Ok(RenderDocumentElement::Heading(
RenderHeading::new(config, output_directory, output_file, inner)?, RenderHeading::new(render_context.clone(), inner)?,
)), )),
IDocumentElement::Section(inner) => Ok(RenderDocumentElement::Section( IDocumentElement::Section(inner) => Ok(RenderDocumentElement::Section(
RenderSection::new(config, output_directory, output_file, inner)?, RenderSection::new(render_context.clone(), inner)?,
)), )),
} }
} }

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IDrawer; use crate::intermediate::IDrawer;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IDynamicBlock; use crate::intermediate::IDynamicBlock;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IElement; use crate::intermediate::IElement;
@ -61,132 +59,98 @@ pub(crate) enum RenderElement {
LatexEnvironment(RenderLatexEnvironment), LatexEnvironment(RenderLatexEnvironment),
} }
render!( render!(RenderElement, IElement, original, render_context, {
RenderElement, match original {
IElement, IElement::Paragraph(inner) => Ok(RenderElement::Paragraph(RenderParagraph::new(
original, render_context.clone(),
config, inner,
output_directory, )?)),
output_file, IElement::PlainList(inner) => Ok(RenderElement::PlainList(RenderPlainList::new(
{ render_context.clone(),
match original { inner,
IElement::Paragraph(inner) => Ok(RenderElement::Paragraph(RenderParagraph::new( )?)),
config, IElement::CenterBlock(inner) => Ok(RenderElement::CenterBlock(RenderCenterBlock::new(
output_directory, render_context.clone(),
output_file, inner,
inner, )?)),
)?)), IElement::QuoteBlock(inner) => Ok(RenderElement::QuoteBlock(RenderQuoteBlock::new(
IElement::PlainList(inner) => Ok(RenderElement::PlainList(RenderPlainList::new( render_context.clone(),
config, inner,
output_directory, )?)),
output_file, IElement::SpecialBlock(inner) => Ok(RenderElement::SpecialBlock(RenderSpecialBlock::new(
inner, render_context.clone(),
)?)), inner,
IElement::CenterBlock(inner) => Ok(RenderElement::CenterBlock(RenderCenterBlock::new( )?)),
config, IElement::DynamicBlock(inner) => Ok(RenderElement::DynamicBlock(RenderDynamicBlock::new(
output_directory, render_context.clone(),
output_file, inner,
inner, )?)),
)?)), IElement::FootnoteDefinition(inner) => Ok(RenderElement::FootnoteDefinition(
IElement::QuoteBlock(inner) => Ok(RenderElement::QuoteBlock(RenderQuoteBlock::new( RenderFootnoteDefinition::new(render_context.clone(), inner)?,
config, )),
output_directory, IElement::Comment(inner) => Ok(RenderElement::Comment(RenderComment::new(
output_file, render_context.clone(),
inner, inner,
)?)), )?)),
IElement::SpecialBlock(inner) => Ok(RenderElement::SpecialBlock( IElement::Drawer(inner) => Ok(RenderElement::Drawer(RenderDrawer::new(
RenderSpecialBlock::new(config, output_directory, output_file, inner)?, render_context.clone(),
)), inner,
IElement::DynamicBlock(inner) => Ok(RenderElement::DynamicBlock( )?)),
RenderDynamicBlock::new(config, output_directory, output_file, inner)?, IElement::PropertyDrawer(inner) => Ok(RenderElement::PropertyDrawer(
)), RenderPropertyDrawer::new(render_context.clone(), inner)?,
IElement::FootnoteDefinition(inner) => Ok(RenderElement::FootnoteDefinition( )),
RenderFootnoteDefinition::new(config, output_directory, output_file, inner)?, IElement::Table(inner) => Ok(RenderElement::Table(RenderTable::new(
)), render_context.clone(),
IElement::Comment(inner) => Ok(RenderElement::Comment(RenderComment::new( inner,
config, )?)),
output_directory, IElement::VerseBlock(inner) => Ok(RenderElement::VerseBlock(RenderVerseBlock::new(
output_file, render_context.clone(),
inner, inner,
)?)), )?)),
IElement::Drawer(inner) => Ok(RenderElement::Drawer(RenderDrawer::new( IElement::CommentBlock(inner) => Ok(RenderElement::CommentBlock(RenderCommentBlock::new(
config, render_context.clone(),
output_directory, inner,
output_file, )?)),
inner, IElement::ExampleBlock(inner) => Ok(RenderElement::ExampleBlock(RenderExampleBlock::new(
)?)), render_context.clone(),
IElement::PropertyDrawer(inner) => Ok(RenderElement::PropertyDrawer( inner,
RenderPropertyDrawer::new(config, output_directory, output_file, inner)?, )?)),
)), IElement::ExportBlock(inner) => Ok(RenderElement::ExportBlock(RenderExportBlock::new(
IElement::Table(inner) => Ok(RenderElement::Table(RenderTable::new( render_context.clone(),
config, inner,
output_directory, )?)),
output_file, IElement::SrcBlock(inner) => Ok(RenderElement::SrcBlock(RenderSrcBlock::new(
inner, render_context.clone(),
)?)), inner,
IElement::VerseBlock(inner) => Ok(RenderElement::VerseBlock(RenderVerseBlock::new( )?)),
config, IElement::Clock(inner) => Ok(RenderElement::Clock(RenderClock::new(
output_directory, render_context.clone(),
output_file, inner,
inner, )?)),
)?)), IElement::DiarySexp(inner) => Ok(RenderElement::DiarySexp(RenderDiarySexp::new(
IElement::CommentBlock(inner) => Ok(RenderElement::CommentBlock( render_context.clone(),
RenderCommentBlock::new(config, output_directory, output_file, inner)?, inner,
)), )?)),
IElement::ExampleBlock(inner) => Ok(RenderElement::ExampleBlock( IElement::Planning(inner) => Ok(RenderElement::Planning(RenderPlanning::new(
RenderExampleBlock::new(config, output_directory, output_file, inner)?, render_context.clone(),
)), inner,
IElement::ExportBlock(inner) => Ok(RenderElement::ExportBlock(RenderExportBlock::new( )?)),
config, IElement::FixedWidthArea(inner) => Ok(RenderElement::FixedWidthArea(
output_directory, RenderFixedWidthArea::new(render_context.clone(), inner)?,
output_file, )),
inner, IElement::HorizontalRule(inner) => Ok(RenderElement::HorizontalRule(
)?)), RenderHorizontalRule::new(render_context.clone(), inner)?,
IElement::SrcBlock(inner) => Ok(RenderElement::SrcBlock(RenderSrcBlock::new( )),
config, IElement::Keyword(inner) => Ok(RenderElement::Keyword(RenderKeyword::new(
output_directory, render_context.clone(),
output_file, inner,
inner, )?)),
)?)), IElement::BabelCall(inner) => Ok(RenderElement::BabelCall(RenderBabelCall::new(
IElement::Clock(inner) => Ok(RenderElement::Clock(RenderClock::new( render_context.clone(),
config, inner,
output_directory, )?)),
output_file, IElement::LatexEnvironment(inner) => Ok(RenderElement::LatexEnvironment(
inner, RenderLatexEnvironment::new(render_context.clone(), inner)?,
)?)), )),
IElement::DiarySexp(inner) => Ok(RenderElement::DiarySexp(RenderDiarySexp::new(
config,
output_directory,
output_file,
inner,
)?)),
IElement::Planning(inner) => Ok(RenderElement::Planning(RenderPlanning::new(
config,
output_directory,
output_file,
inner,
)?)),
IElement::FixedWidthArea(inner) => Ok(RenderElement::FixedWidthArea(
RenderFixedWidthArea::new(config, output_directory, output_file, inner)?,
)),
IElement::HorizontalRule(inner) => Ok(RenderElement::HorizontalRule(
RenderHorizontalRule::new(config, output_directory, output_file, inner)?,
)),
IElement::Keyword(inner) => Ok(RenderElement::Keyword(RenderKeyword::new(
config,
output_directory,
output_file,
inner,
)?)),
IElement::BabelCall(inner) => Ok(RenderElement::BabelCall(RenderBabelCall::new(
config,
output_directory,
output_file,
inner,
)?)),
IElement::LatexEnvironment(inner) => Ok(RenderElement::LatexEnvironment(
RenderLatexEnvironment::new(config, output_directory, output_file, inner)?,
)),
}
} }
); });

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IEntity; use crate::intermediate::IEntity;
@ -15,16 +13,8 @@ pub(crate) struct RenderEntity {
html: String, html: String,
} }
render!( render!(RenderEntity, IEntity, original, _render_context, {
RenderEntity, Ok(RenderEntity {
IEntity, html: original.html.clone(),
original, })
_config, });
_output_directory,
_output_file,
{
Ok(RenderEntity {
html: original.html.clone(),
})
}
);

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IExampleBlock; use crate::intermediate::IExampleBlock;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IExportBlock; use crate::intermediate::IExportBlock;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IExportSnippet; use crate::intermediate::IExportSnippet;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IFixedWidthArea; use crate::intermediate::IFixedWidthArea;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IFootnoteDefinition; use crate::intermediate::IFootnoteDefinition;
use crate::intermediate::IRealFootnoteDefinition; use crate::intermediate::IRealFootnoteDefinition;
@ -33,21 +31,19 @@ render!(
RenderRealFootnoteDefinition, RenderRealFootnoteDefinition,
IRealFootnoteDefinition, IRealFootnoteDefinition,
original, original,
config, render_context,
output_directory,
output_file,
{ {
let contents = { let contents = {
let mut ret = Vec::new(); let mut ret = Vec::new();
for obj in original.contents.iter() { for obj in original.contents.iter() {
ret.push(obj.into_render_ast_node(config, output_directory, output_file)?); ret.push(obj.into_render_ast_node(render_context.clone())?);
} }
ret ret
}; };
Ok(RenderRealFootnoteDefinition { Ok(RenderRealFootnoteDefinition {
definition_id: original.get_definition_id(), definition_id: original.get_definition_id(render_context.id_addition),
reference_link: format!("#{}", original.get_reference_id()), reference_link: format!("#{}", original.get_reference_id(render_context.id_addition)),
label: original.get_display_label(), label: original.get_display_label(),
contents, contents,
}) })

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IFootnoteReference; use crate::intermediate::IFootnoteReference;
@ -21,13 +19,14 @@ render!(
RenderFootnoteReference, RenderFootnoteReference,
IFootnoteReference, IFootnoteReference,
original, original,
_config, render_context,
_output_directory,
_output_file,
{ {
Ok(RenderFootnoteReference { Ok(RenderFootnoteReference {
reference_id: original.get_reference_id(), reference_id: original.get_reference_id(render_context.id_addition),
definition_link: format!("#{}", original.get_definition_id()), definition_link: format!(
"#{}",
original.get_definition_id(render_context.id_addition)
),
label: original.get_display_label(), label: original.get_display_label(),
}) })
} }

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IHeading; use crate::intermediate::IHeading;
@ -19,44 +17,26 @@ pub(crate) struct RenderHeading {
children: Vec<RenderDocumentElement>, children: Vec<RenderDocumentElement>,
} }
render!( render!(RenderHeading, IHeading, original, render_context, {
RenderHeading, let title = {
IHeading, let mut ret = Vec::new();
original, for obj in original.title.iter() {
config, ret.push(RenderObject::new(render_context.clone(), obj)?);
output_directory, }
output_file, ret
{ };
let title = {
let mut ret = Vec::new();
for obj in original.title.iter() {
ret.push(RenderObject::new(
config,
output_directory,
output_file,
obj,
)?);
}
ret
};
let children = { let children = {
let mut ret = Vec::new(); let mut ret = Vec::new();
for obj in original.children.iter() { for obj in original.children.iter() {
ret.push(RenderDocumentElement::new( ret.push(RenderDocumentElement::new(render_context.clone(), obj)?);
config, }
output_directory, ret
output_file, };
obj,
)?);
}
ret
};
Ok(RenderHeading { Ok(RenderHeading {
level: original.level + 1, // Adding 1 because the page title is going to be h1. level: original.level + 1, // Adding 1 because the page title is going to be h1.
title, title,
children, children,
}) })
} });
);

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IHorizontalRule; use crate::intermediate::IHorizontalRule;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IInlineBabelCall; use crate::intermediate::IInlineBabelCall;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IInlineSourceBlock; use crate::intermediate::IInlineSourceBlock;
@ -19,9 +17,7 @@ render!(
RenderInlineSourceBlock, RenderInlineSourceBlock,
IInlineSourceBlock, IInlineSourceBlock,
original, original,
_config, _render_context,
_output_directory,
_output_file,
{ {
Ok(RenderInlineSourceBlock { Ok(RenderInlineSourceBlock {
value: original.value.clone(), value: original.value.clone(),

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IItalic; use crate::intermediate::IItalic;
@ -16,27 +14,14 @@ pub(crate) struct RenderItalic {
children: Vec<RenderObject>, children: Vec<RenderObject>,
} }
render!( render!(RenderItalic, IItalic, original, render_context, {
RenderItalic, let children = {
IItalic, let mut ret = Vec::new();
original, for obj in original.children.iter() {
config, ret.push(RenderObject::new(render_context.clone(), obj)?);
output_directory, }
output_file, ret
{ };
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderObject::new(
config,
output_directory,
output_file,
obj,
)?);
}
ret
};
Ok(RenderItalic { children }) Ok(RenderItalic { children })
} });
);

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IKeyword; use crate::intermediate::IKeyword;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::ILatexEnvironment; use crate::intermediate::ILatexEnvironment;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::ILatexFragment; use crate::intermediate::ILatexFragment;
@ -19,9 +17,7 @@ render!(
RenderLatexFragment, RenderLatexFragment,
ILatexFragment, ILatexFragment,
original, original,
_config, _render_context,
_output_directory,
_output_file,
{ {
Ok(RenderLatexFragment { Ok(RenderLatexFragment {
value: original.value.clone(), value: original.value.clone(),

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::ILineBreak; use crate::intermediate::ILineBreak;

View File

@ -2,18 +2,12 @@
/// ///
/// This exists to make changing the type signature easier. /// This exists to make changing the type signature easier.
macro_rules! render { macro_rules! render {
($rstruct:ident, $istruct:ident, $original:ident, $config:ident, $output_directory:ident, $output_file:ident, $fnbody:tt) => { ($rstruct:ident, $istruct:ident, $original:ident, $render_context:ident, $fnbody:tt) => {
impl $rstruct { impl $rstruct {
pub(crate) fn new( pub(crate) fn new(
config: &Config, $render_context: RenderContext<'_>,
output_directory: &Path, $original: &$istruct,
output_file: &Path,
original: &$istruct,
) -> Result<$rstruct, CustomError> { ) -> Result<$rstruct, CustomError> {
let $original = original;
let $config = config;
let $output_directory = output_directory;
let $output_file = output_file;
$fnbody $fnbody
} }
} }
@ -29,9 +23,7 @@ macro_rules! rnoop {
($rstruct:ident, $istruct:ident) => { ($rstruct:ident, $istruct:ident) => {
impl $rstruct { impl $rstruct {
pub(crate) fn new( pub(crate) fn new(
_config: &Config, _render_context: RenderContext<'_>,
_output_directory: &Path,
_output_file: &Path,
_original: &$istruct, _original: &$istruct,
) -> Result<$rstruct, CustomError> { ) -> Result<$rstruct, CustomError> {
Ok($rstruct {}) Ok($rstruct {})

View File

@ -2,6 +2,7 @@ mod angle_link;
mod ast_node; mod ast_node;
mod babel_call; mod babel_call;
mod blog_post_page; mod blog_post_page;
mod blog_stream;
mod bold; mod bold;
mod center_block; mod center_block;
mod citation; mod citation;
@ -47,6 +48,7 @@ mod quote_block;
mod radio_link; mod radio_link;
mod radio_target; mod radio_target;
mod regular_link; mod regular_link;
mod render_context;
mod section; mod section;
mod special_block; mod special_block;
mod src_block; mod src_block;
@ -64,6 +66,9 @@ mod verbatim;
mod verse_block; mod verse_block;
pub(crate) use blog_post_page::RenderBlogPostPage; pub(crate) use blog_post_page::RenderBlogPostPage;
pub(crate) use blog_post_page::RenderBlogPostPageInput;
pub(crate) use blog_stream::RenderBlogStream;
pub(crate) use blog_stream::RenderBlogStreamInput;
pub(crate) use document_element::RenderDocumentElement; pub(crate) use document_element::RenderDocumentElement;
pub(crate) use element::RenderElement; pub(crate) use element::RenderElement;
pub(crate) use footnote_definition::RenderRealFootnoteDefinition; pub(crate) use footnote_definition::RenderRealFootnoteDefinition;
@ -71,4 +76,5 @@ pub(crate) use global_settings::GlobalSettings;
pub(crate) use heading::RenderHeading; pub(crate) use heading::RenderHeading;
pub(crate) use object::RenderObject; pub(crate) use object::RenderObject;
pub(crate) use page_header::PageHeader; pub(crate) use page_header::PageHeader;
pub(crate) use render_context::RenderContext;
pub(crate) use section::RenderSection; pub(crate) use section::RenderSection;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IObject; use crate::intermediate::IObject;
@ -67,153 +65,110 @@ pub(crate) enum RenderObject {
Timestamp(RenderTimestamp), Timestamp(RenderTimestamp),
} }
render!( render!(RenderObject, IObject, original, render_context, {
RenderObject, match original {
IObject, IObject::Bold(inner) => Ok(RenderObject::Bold(RenderBold::new(
original, render_context.clone(),
config, inner,
output_directory, )?)),
output_file, IObject::Italic(inner) => Ok(RenderObject::Italic(RenderItalic::new(
{ render_context.clone(),
match original { inner,
IObject::Bold(inner) => Ok(RenderObject::Bold(RenderBold::new( )?)),
config, IObject::Underline(inner) => Ok(RenderObject::Underline(RenderUnderline::new(
output_directory, render_context.clone(),
output_file, inner,
inner, )?)),
)?)), IObject::StrikeThrough(inner) => Ok(RenderObject::StrikeThrough(RenderStrikeThrough::new(
IObject::Italic(inner) => Ok(RenderObject::Italic(RenderItalic::new( render_context.clone(),
config, inner,
output_directory, )?)),
output_file, IObject::Code(inner) => Ok(RenderObject::Code(RenderCode::new(
inner, render_context.clone(),
)?)), inner,
IObject::Underline(inner) => Ok(RenderObject::Underline(RenderUnderline::new( )?)),
config, IObject::Verbatim(inner) => Ok(RenderObject::Verbatim(RenderVerbatim::new(
output_directory, render_context.clone(),
output_file, inner,
inner, )?)),
)?)), IObject::PlainText(inner) => Ok(RenderObject::PlainText(RenderPlainText::new(
IObject::StrikeThrough(inner) => Ok(RenderObject::StrikeThrough( render_context.clone(),
RenderStrikeThrough::new(config, output_directory, output_file, inner)?, inner,
)), )?)),
IObject::Code(inner) => Ok(RenderObject::Code(RenderCode::new( IObject::RegularLink(inner) => Ok(RenderObject::RegularLink(RenderRegularLink::new(
config, render_context.clone(),
output_directory, inner,
output_file, )?)),
inner, IObject::RadioLink(inner) => Ok(RenderObject::RadioLink(RenderRadioLink::new(
)?)), render_context.clone(),
IObject::Verbatim(inner) => Ok(RenderObject::Verbatim(RenderVerbatim::new( inner,
config, )?)),
output_directory, IObject::RadioTarget(inner) => Ok(RenderObject::RadioTarget(RenderRadioTarget::new(
output_file, render_context.clone(),
inner, inner,
)?)), )?)),
IObject::PlainText(inner) => Ok(RenderObject::PlainText(RenderPlainText::new( IObject::PlainLink(inner) => Ok(RenderObject::PlainLink(RenderPlainLink::new(
config, render_context.clone(),
output_directory, inner,
output_file, )?)),
inner, IObject::AngleLink(inner) => Ok(RenderObject::AngleLink(RenderAngleLink::new(
)?)), render_context.clone(),
IObject::RegularLink(inner) => Ok(RenderObject::RegularLink(RenderRegularLink::new( inner,
config, )?)),
output_directory, IObject::OrgMacro(inner) => Ok(RenderObject::OrgMacro(RenderOrgMacro::new(
output_file, render_context.clone(),
inner, inner,
)?)), )?)),
IObject::RadioLink(inner) => Ok(RenderObject::RadioLink(RenderRadioLink::new( IObject::Entity(inner) => Ok(RenderObject::Entity(RenderEntity::new(
config, render_context.clone(),
output_directory, inner,
output_file, )?)),
inner, IObject::LatexFragment(inner) => Ok(RenderObject::LatexFragment(RenderLatexFragment::new(
)?)), render_context.clone(),
IObject::RadioTarget(inner) => Ok(RenderObject::RadioTarget(RenderRadioTarget::new( inner,
config, )?)),
output_directory, IObject::ExportSnippet(inner) => Ok(RenderObject::ExportSnippet(RenderExportSnippet::new(
output_file, render_context.clone(),
inner, inner,
)?)), )?)),
IObject::PlainLink(inner) => Ok(RenderObject::PlainLink(RenderPlainLink::new( IObject::FootnoteReference(inner) => Ok(RenderObject::FootnoteReference(
config, RenderFootnoteReference::new(render_context.clone(), inner)?,
output_directory, )),
output_file, IObject::Citation(inner) => Ok(RenderObject::Citation(RenderCitation::new(
inner, render_context.clone(),
)?)), inner,
IObject::AngleLink(inner) => Ok(RenderObject::AngleLink(RenderAngleLink::new( )?)),
config, IObject::CitationReference(inner) => Ok(RenderObject::CitationReference(
output_directory, RenderCitationReference::new(render_context.clone(), inner)?,
output_file, )),
inner, IObject::InlineBabelCall(inner) => Ok(RenderObject::InlineBabelCall(
)?)), RenderInlineBabelCall::new(render_context.clone(), inner)?,
IObject::OrgMacro(inner) => Ok(RenderObject::OrgMacro(RenderOrgMacro::new( )),
config, IObject::InlineSourceBlock(inner) => Ok(RenderObject::InlineSourceBlock(
output_directory, RenderInlineSourceBlock::new(render_context.clone(), inner)?,
output_file, )),
inner, IObject::LineBreak(inner) => Ok(RenderObject::LineBreak(RenderLineBreak::new(
)?)), render_context.clone(),
IObject::Entity(inner) => Ok(RenderObject::Entity(RenderEntity::new( inner,
config, )?)),
output_directory, IObject::Target(inner) => Ok(RenderObject::Target(RenderTarget::new(
output_file, render_context.clone(),
inner, inner,
)?)), )?)),
IObject::LatexFragment(inner) => Ok(RenderObject::LatexFragment( IObject::StatisticsCookie(inner) => Ok(RenderObject::StatisticsCookie(
RenderLatexFragment::new(config, output_directory, output_file, inner)?, RenderStatisticsCookie::new(render_context.clone(), inner)?,
)), )),
IObject::ExportSnippet(inner) => Ok(RenderObject::ExportSnippet( IObject::Subscript(inner) => Ok(RenderObject::Subscript(RenderSubscript::new(
RenderExportSnippet::new(config, output_directory, output_file, inner)?, render_context.clone(),
)), inner,
IObject::FootnoteReference(inner) => Ok(RenderObject::FootnoteReference( )?)),
RenderFootnoteReference::new(config, output_directory, output_file, inner)?, IObject::Superscript(inner) => Ok(RenderObject::Superscript(RenderSuperscript::new(
)), render_context.clone(),
IObject::Citation(inner) => Ok(RenderObject::Citation(RenderCitation::new( inner,
config, )?)),
output_directory, IObject::Timestamp(inner) => Ok(RenderObject::Timestamp(RenderTimestamp::new(
output_file, render_context.clone(),
inner, inner,
)?)), )?)),
IObject::CitationReference(inner) => Ok(RenderObject::CitationReference(
RenderCitationReference::new(config, output_directory, output_file, inner)?,
)),
IObject::InlineBabelCall(inner) => Ok(RenderObject::InlineBabelCall(
RenderInlineBabelCall::new(config, output_directory, output_file, inner)?,
)),
IObject::InlineSourceBlock(inner) => Ok(RenderObject::InlineSourceBlock(
RenderInlineSourceBlock::new(config, output_directory, output_file, inner)?,
)),
IObject::LineBreak(inner) => Ok(RenderObject::LineBreak(RenderLineBreak::new(
config,
output_directory,
output_file,
inner,
)?)),
IObject::Target(inner) => Ok(RenderObject::Target(RenderTarget::new(
config,
output_directory,
output_file,
inner,
)?)),
IObject::StatisticsCookie(inner) => Ok(RenderObject::StatisticsCookie(
RenderStatisticsCookie::new(config, output_directory, output_file, inner)?,
)),
IObject::Subscript(inner) => Ok(RenderObject::Subscript(RenderSubscript::new(
config,
output_directory,
output_file,
inner,
)?)),
IObject::Superscript(inner) => Ok(RenderObject::Superscript(RenderSuperscript::new(
config,
output_directory,
output_file,
inner,
)?)),
IObject::Timestamp(inner) => Ok(RenderObject::Timestamp(RenderTimestamp::new(
config,
output_directory,
output_file,
inner,
)?)),
}
} }
); });

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IOrgMacro; use crate::intermediate::IOrgMacro;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IParagraph; use crate::intermediate::IParagraph;
@ -16,27 +14,14 @@ pub(crate) struct RenderParagraph {
children: Vec<RenderObject>, children: Vec<RenderObject>,
} }
render!( render!(RenderParagraph, IParagraph, original, render_context, {
RenderParagraph, let children = {
IParagraph, let mut ret = Vec::new();
original, for obj in original.children.iter() {
config, ret.push(RenderObject::new(render_context.clone(), obj)?);
output_directory, }
output_file, ret
{ };
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderObject::new(
config,
output_directory,
output_file,
obj,
)?);
}
ret
};
Ok(RenderParagraph { children }) Ok(RenderParagraph { children })
} });
);

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IPlainLink; use crate::intermediate::IPlainLink;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IPlainList; use crate::intermediate::IPlainList;
@ -17,35 +15,22 @@ pub(crate) struct RenderPlainList {
children: Vec<RenderPlainListItem>, children: Vec<RenderPlainListItem>,
} }
render!( render!(RenderPlainList, IPlainList, original, render_context, {
RenderPlainList, let list_type = match original.list_type {
IPlainList, organic::types::PlainListType::Unordered => "unordered".to_owned(),
original, organic::types::PlainListType::Ordered => "ordered".to_owned(),
config, organic::types::PlainListType::Descriptive => "descriptive".to_owned(),
output_directory, };
output_file, let children = {
{ let mut ret = Vec::new();
let list_type = match original.list_type { for obj in original.children.iter() {
organic::types::PlainListType::Unordered => "unordered".to_owned(), ret.push(RenderPlainListItem::new(render_context.clone(), obj)?);
organic::types::PlainListType::Ordered => "ordered".to_owned(), }
organic::types::PlainListType::Descriptive => "descriptive".to_owned(), ret
}; };
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderPlainListItem::new(
config,
output_directory,
output_file,
obj,
)?);
}
ret
};
Ok(RenderPlainList { Ok(RenderPlainList {
list_type, list_type,
children, children,
}) })
} });
);

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IPlainListItem; use crate::intermediate::IPlainListItem;
@ -22,19 +20,12 @@ render!(
RenderPlainListItem, RenderPlainListItem,
IPlainListItem, IPlainListItem,
original, original,
config, render_context,
output_directory,
output_file,
{ {
let tag = { let tag = {
let mut ret = Vec::new(); let mut ret = Vec::new();
for obj in original.tag.iter() { for obj in original.tag.iter() {
ret.push(RenderObject::new( ret.push(RenderObject::new(render_context.clone(), obj)?);
config,
output_directory,
output_file,
obj,
)?);
} }
ret ret
}; };
@ -42,12 +33,7 @@ render!(
let children = { let children = {
let mut ret = Vec::new(); let mut ret = Vec::new();
for obj in original.children.iter() { for obj in original.children.iter() {
ret.push(RenderElement::new( ret.push(RenderElement::new(render_context.clone(), obj)?);
config,
output_directory,
output_file,
obj,
)?);
} }
ret ret
}; };

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IPlainText; use crate::intermediate::IPlainText;
@ -15,16 +13,8 @@ pub(crate) struct RenderPlainText {
source: String, source: String,
} }
render!( render!(RenderPlainText, IPlainText, original, _render_context, {
RenderPlainText, Ok(RenderPlainText {
IPlainText, source: original.source.clone(),
original, })
_config, });
_output_directory,
_output_file,
{
Ok(RenderPlainText {
source: original.source.clone(),
})
}
);

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IPlanning; use crate::intermediate::IPlanning;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IPropertyDrawer; use crate::intermediate::IPropertyDrawer;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IQuoteBlock; use crate::intermediate::IQuoteBlock;
@ -16,27 +14,14 @@ pub(crate) struct RenderQuoteBlock {
children: Vec<RenderElement>, children: Vec<RenderElement>,
} }
render!( render!(RenderQuoteBlock, IQuoteBlock, original, render_context, {
RenderQuoteBlock, let children = {
IQuoteBlock, let mut ret = Vec::new();
original, for obj in original.children.iter() {
config, ret.push(RenderElement::new(render_context.clone(), obj)?);
output_directory, }
output_file, ret
{ };
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderElement::new(
config,
output_directory,
output_file,
obj,
)?);
}
ret
};
Ok(RenderQuoteBlock { children }) Ok(RenderQuoteBlock { children })
} });
);

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IRadioLink; use crate::intermediate::IRadioLink;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IRadioTarget; use crate::intermediate::IRadioTarget;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IRegularLink; use crate::intermediate::IRegularLink;
@ -17,30 +15,17 @@ pub(crate) struct RenderRegularLink {
children: Vec<RenderObject>, children: Vec<RenderObject>,
} }
render!( render!(RenderRegularLink, IRegularLink, original, render_context, {
RenderRegularLink, let children = {
IRegularLink, let mut ret = Vec::new();
original, for obj in original.children.iter() {
config, ret.push(RenderObject::new(render_context.clone(), obj)?);
output_directory, }
output_file, ret
{ };
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderObject::new(
config,
output_directory,
output_file,
obj,
)?);
}
ret
};
Ok(RenderRegularLink { Ok(RenderRegularLink {
raw_link: original.raw_link.clone(), raw_link: original.raw_link.clone(),
children, children,
}) })
} });
);

View File

@ -0,0 +1,36 @@
use std::path::Path;
use crate::config::Config;
use crate::error::CustomError;
/// The supporting information used for converting the intermediate representation into the dust context for rendering.
#[derive(Debug, Clone)]
pub(crate) struct RenderContext<'intermediate> {
pub(crate) config: &'intermediate Config,
// TODO: Perhaps rename to output_root_directory.
pub(crate) output_root_directory: &'intermediate Path,
pub(crate) output_file: &'intermediate Path,
/// An optional string that gets added to IDs in HTML.
///
/// This is useful for cases where you may have conflicting HTML
/// IDs, for example, multiple blog posts with footnotes in a blog
/// stream.
pub(crate) id_addition: Option<&'intermediate str>,
}
impl<'intermediate> RenderContext<'intermediate> {
pub(crate) fn new(
config: &'intermediate Config,
output_directory: &'intermediate Path,
output_file: &'intermediate Path,
id_addition: Option<&'intermediate str>,
) -> Result<RenderContext<'intermediate>, CustomError> {
Ok(RenderContext {
config,
output_root_directory: output_directory,
output_file,
id_addition,
})
}
}

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::ISection; use crate::intermediate::ISection;
@ -16,27 +14,14 @@ pub(crate) struct RenderSection {
children: Vec<RenderElement>, children: Vec<RenderElement>,
} }
render!( render!(RenderSection, ISection, original, render_context, {
RenderSection, let children = {
ISection, let mut ret = Vec::new();
original, for obj in original.children.iter() {
config, ret.push(RenderElement::new(render_context.clone(), obj)?);
output_directory, }
output_file, ret
{ };
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderElement::new(
config,
output_directory,
output_file,
obj,
)?);
}
ret
};
Ok(RenderSection { children }) Ok(RenderSection { children })
} });
);

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::ISpecialBlock; use crate::intermediate::ISpecialBlock;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::ISrcBlock; use crate::intermediate::ISrcBlock;
@ -15,16 +13,8 @@ pub(crate) struct RenderSrcBlock {
lines: Vec<String>, lines: Vec<String>,
} }
render!( render!(RenderSrcBlock, ISrcBlock, original, _render_context, {
RenderSrcBlock, Ok(RenderSrcBlock {
ISrcBlock, lines: original.lines.clone(),
original, })
_config, });
_output_directory,
_output_file,
{
Ok(RenderSrcBlock {
lines: original.lines.clone(),
})
}
);

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IStatisticsCookie; use crate::intermediate::IStatisticsCookie;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IStrikeThrough; use crate::intermediate::IStrikeThrough;
@ -20,19 +18,12 @@ render!(
RenderStrikeThrough, RenderStrikeThrough,
IStrikeThrough, IStrikeThrough,
original, original,
config, render_context,
output_directory,
output_file,
{ {
let children = { let children = {
let mut ret = Vec::new(); let mut ret = Vec::new();
for obj in original.children.iter() { for obj in original.children.iter() {
ret.push(RenderObject::new( ret.push(RenderObject::new(render_context.clone(), obj)?);
config,
output_directory,
output_file,
obj,
)?);
} }
ret ret
}; };

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::ISubscript; use crate::intermediate::ISubscript;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::ISuperscript; use crate::intermediate::ISuperscript;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::ITable; use crate::intermediate::ITable;
@ -16,27 +14,14 @@ pub(crate) struct RenderTable {
children: Vec<RenderTableRow>, children: Vec<RenderTableRow>,
} }
render!( render!(RenderTable, ITable, original, render_context, {
RenderTable, let children = {
ITable, let mut ret = Vec::new();
original, for obj in original.children.iter() {
config, ret.push(RenderTableRow::new(render_context.clone(), obj)?);
output_directory, }
output_file, ret
{ };
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderTableRow::new(
config,
output_directory,
output_file,
obj,
)?);
}
ret
};
Ok(RenderTable { children }) Ok(RenderTable { children })
} });
);

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::ITableCell; use crate::intermediate::ITableCell;
@ -16,27 +14,14 @@ pub(crate) struct RenderTableCell {
children: Vec<RenderObject>, children: Vec<RenderObject>,
} }
render!( render!(RenderTableCell, ITableCell, original, render_context, {
RenderTableCell, let children = {
ITableCell, let mut ret = Vec::new();
original, for obj in original.children.iter() {
config, ret.push(RenderObject::new(render_context.clone(), obj)?);
output_directory, }
output_file, ret
{ };
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderObject::new(
config,
output_directory,
output_file,
obj,
)?);
}
ret
};
Ok(RenderTableCell { children }) Ok(RenderTableCell { children })
} });
);

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::ITableRow; use crate::intermediate::ITableRow;
@ -16,27 +14,14 @@ pub(crate) struct RenderTableRow {
children: Vec<RenderTableCell>, children: Vec<RenderTableCell>,
} }
render!( render!(RenderTableRow, ITableRow, original, render_context, {
RenderTableRow, let children = {
ITableRow, let mut ret = Vec::new();
original, for obj in original.children.iter() {
config, ret.push(RenderTableCell::new(render_context.clone(), obj)?);
output_directory, }
output_file, ret
{ };
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderTableCell::new(
config,
output_directory,
output_file,
obj,
)?);
}
ret
};
Ok(RenderTableRow { children }) Ok(RenderTableRow { children })
} });
);

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::ITarget; use crate::intermediate::ITarget;
@ -15,16 +13,8 @@ pub(crate) struct RenderTarget {
id: String, id: String,
} }
render!( render!(RenderTarget, ITarget, original, _render_context, {
RenderTarget, Ok(RenderTarget {
ITarget, id: original.id.clone(),
original, })
_config, });
_output_directory,
_output_file,
{
Ok(RenderTarget {
id: original.id.clone(),
})
}
);

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::ITimestamp; use crate::intermediate::ITimestamp;

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IUnderline; use crate::intermediate::IUnderline;
@ -16,27 +14,14 @@ pub(crate) struct RenderUnderline {
children: Vec<RenderObject>, children: Vec<RenderObject>,
} }
render!( render!(RenderUnderline, IUnderline, original, render_context, {
RenderUnderline, let children = {
IUnderline, let mut ret = Vec::new();
original, for obj in original.children.iter() {
config, ret.push(RenderObject::new(render_context.clone(), obj)?);
output_directory, }
output_file, ret
{ };
let children = {
let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(RenderObject::new(
config,
output_directory,
output_file,
obj,
)?);
}
ret
};
Ok(RenderUnderline { children }) Ok(RenderUnderline { children })
} });
);

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IVerbatim; use crate::intermediate::IVerbatim;
@ -15,16 +13,8 @@ pub(crate) struct RenderVerbatim {
contents: String, contents: String,
} }
render!( render!(RenderVerbatim, IVerbatim, original, _render_context, {
RenderVerbatim, Ok(RenderVerbatim {
IVerbatim, contents: original.contents.clone(),
original, })
_config, });
_output_directory,
_output_file,
{
Ok(RenderVerbatim {
contents: original.contents.clone(),
})
}
);

View File

@ -1,8 +1,6 @@
use std::path::Path;
use serde::Serialize; use serde::Serialize;
use crate::config::Config; use super::render_context::RenderContext;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::IVerseBlock; use crate::intermediate::IVerseBlock;

View File

@ -4,6 +4,7 @@ use std::string::FromUtf8Error;
#[derive(Debug)] #[derive(Debug)]
pub(crate) enum CustomError { pub(crate) enum CustomError {
Static(&'static str), Static(&'static str),
String(String),
IO(std::io::Error), IO(std::io::Error),
TomlSerialize(toml::ser::Error), TomlSerialize(toml::ser::Error),
TomlDeserialize(toml::de::Error), TomlDeserialize(toml::de::Error),
@ -29,6 +30,12 @@ impl From<&'static str> for CustomError {
} }
} }
impl From<String> for CustomError {
fn from(value: String) -> Self {
CustomError::String(value)
}
}
impl From<toml::ser::Error> for CustomError { impl From<toml::ser::Error> for CustomError {
fn from(value: toml::ser::Error) -> Self { fn from(value: toml::ser::Error) -> Self {
CustomError::TomlSerialize(value) CustomError::TomlSerialize(value)

View File

@ -7,6 +7,7 @@ use tokio::task::JoinHandle;
use walkdir::WalkDir; use walkdir::WalkDir;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::page::BlogPostPageInput;
use crate::intermediate::registry::Registry; use crate::intermediate::registry::Registry;
use super::BlogPostPage; use super::BlogPostPage;
@ -63,8 +64,11 @@ impl BlogPost {
let registry = Arc::new(Mutex::new(registry)); let registry = Arc::new(Mutex::new(registry));
let relative_to_post_dir_path = real_path.strip_prefix(post_dir)?; let relative_to_post_dir_path = real_path.strip_prefix(post_dir)?;
ret.push( ret.push(
BlogPostPage::new(relative_to_post_dir_path, registry, parsed_document) BlogPostPage::new(
.await?, registry,
BlogPostPageInput::new(relative_to_post_dir_path, parsed_document),
)
.await?,
); );
} }
ret ret
@ -77,6 +81,37 @@ impl BlogPost {
} }
inner(root_dir.as_ref(), post_dir.as_ref()).await inner(root_dir.as_ref(), post_dir.as_ref()).await
} }
/// Get the date for a blog post.
///
/// The date is set by the "#+date" export setting. This will
/// first attempt to read the date from an index.org if such a
/// file exists. If that file does not exist or that file does not
/// contain a date export setting, then this will iterate through
/// all the pages under the blog post looking for any page that
/// contains a date export setting. It will return the first date
/// found.
pub(crate) fn get_date(&self) -> Option<&str> {
let index_page_date = self
.get_index_page()
.map(|index_page| index_page.date.as_ref().map(String::as_str))
.flatten();
if index_page_date.is_some() {
return index_page_date;
}
self.pages
.iter()
.filter_map(|page| page.date.as_ref().map(String::as_str))
.next()
}
/// Get the blog post page for index.org
pub(crate) fn get_index_page(&self) -> Option<&BlogPostPage> {
self.pages
.iter()
.find(|page| page.path == Path::new("index.org"))
}
} }
async fn read_file(path: PathBuf) -> std::io::Result<(PathBuf, String)> { async fn read_file(path: PathBuf) -> std::io::Result<(PathBuf, String)> {

View File

@ -8,14 +8,20 @@ pub(crate) struct IBold {
pub(crate) children: Vec<IObject>, pub(crate) children: Vec<IObject>,
} }
intermediate!(IBold, Bold, original, registry, { intermediate!(
let children = { IBold,
let mut ret = Vec::new(); &'orig organic::types::Bold<'parse>,
for obj in original.children.iter() { original,
ret.push(IObject::new(registry.clone(), obj).await?); registry,
} {
ret let children = {
}; let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(IObject::new(registry.clone(), obj).await?);
}
ret
};
Ok(IBold { children }) Ok(IBold { children })
}); }
);

View File

@ -7,9 +7,15 @@ pub(crate) struct ICode {
pub(crate) contents: String, pub(crate) contents: String,
} }
intermediate!(ICode, Code, original, _registry, { intermediate!(
Ok(ICode { ICode,
// TODO: Should this coalesce whitespace like PlainText? &'orig organic::types::Code<'parse>,
contents: original.contents.to_owned(), original,
}) _registry,
}); {
Ok(ICode {
// TODO: Should this coalesce whitespace like PlainText?
contents: original.contents.to_owned(),
})
}
);

View File

@ -3,94 +3,9 @@ use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use crate::config::Config; use crate::config::Config;
use crate::context::GlobalSettings;
use crate::context::PageHeader;
use crate::context::RenderBlogPostPage;
use crate::context::RenderDocumentElement;
use crate::context::RenderRealFootnoteDefinition;
use crate::error::CustomError; use crate::error::CustomError;
use super::BlogPost; pub(crate) fn get_web_path<D: AsRef<Path>, F: AsRef<Path>, P: AsRef<Path>>(
use super::BlogPostPage;
pub(crate) fn convert_blog_post_page_to_render_context<D: AsRef<Path>, F: AsRef<Path>>(
config: &Config,
output_directory: D,
output_file: F,
_post: &BlogPost,
page: &BlogPostPage,
) -> Result<RenderBlogPostPage, CustomError> {
let output_directory = output_directory.as_ref();
let output_file = output_file.as_ref();
let css_files = vec![
get_web_path(
config,
output_directory,
output_file,
"stylesheet/reset.css",
)?,
get_web_path(config, output_directory, output_file, "stylesheet/main.css")?,
];
let js_files = vec![get_web_path(
config,
output_directory,
output_file,
"blog_post.js",
)?];
let global_settings = GlobalSettings::new(page.title.clone(), css_files, js_files);
let page_header = PageHeader::new(
config.get_site_title().map(str::to_string),
Some(get_web_path(config, output_directory, output_file, "")?),
);
let link_to_blog_post = get_web_path(
config,
output_directory,
output_file,
output_file.strip_prefix(output_directory)?,
)?;
let children = {
let mut children = Vec::new();
for child in page.children.iter() {
children.push(RenderDocumentElement::new(
config,
output_directory,
output_file,
child,
)?);
}
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,
Some(page_header),
page.title.clone(),
Some(link_to_blog_post),
children,
footnotes,
);
Ok(ret)
}
fn get_web_path<D: AsRef<Path>, F: AsRef<Path>, P: AsRef<Path>>(
config: &Config, config: &Config,
output_directory: D, output_directory: D,
containing_file: F, containing_file: F,

View File

@ -7,8 +7,14 @@ pub(crate) struct IEntity {
pub(crate) html: String, pub(crate) html: String,
} }
intermediate!(IEntity, Entity, original, _registry, { intermediate!(
Ok(IEntity { IEntity,
html: original.html.to_owned(), &'orig organic::types::Entity<'parse>,
}) original,
}); _registry,
{
Ok(IEntity {
html: original.html.to_owned(),
})
}
);

View File

@ -10,7 +10,7 @@ pub(crate) struct IFootnoteDefinition {}
intermediate!( intermediate!(
IFootnoteDefinition, IFootnoteDefinition,
FootnoteDefinition, &'orig organic::types::FootnoteDefinition<'parse>,
original, original,
registry, registry,
{ {
@ -44,14 +44,22 @@ impl IRealFootnoteDefinition {
/// Get an ID to refer to the first reference to this footnote definition. /// 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. /// 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 { pub(crate) fn get_reference_id(&self, id_addition: Option<&str>) -> String {
format!("fnr.{}", self.get_display_label()) let id_addition = id_addition
.map(|id_addition| format!("sec{}.", id_addition))
.unwrap_or(String::default());
format!("{}fnr.{}", id_addition, self.get_display_label())
} }
/// Get an ID to refer to the footnote definition. /// 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. /// 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 { pub(crate) fn get_definition_id(&self, id_addition: Option<&str>) -> String {
format!("fn.{}", self.get_display_label()) let id_addition = id_addition
.map(|id_addition| format!("sec{}.", id_addition))
.unwrap_or(String::default());
format!("{}fn.{}", id_addition, self.get_display_label())
} }
} }

View File

@ -9,14 +9,20 @@ pub(crate) struct IFootnoteReference {
duplicate_offset: usize, duplicate_offset: usize,
} }
intermediate!(IFootnoteReference, FootnoteReference, original, registry, { intermediate!(
let (footnote_id, reference_count) = IFootnoteReference,
get_footnote_reference_id(registry, original.label, &original.definition).await?; &'orig organic::types::FootnoteReference<'parse>,
Ok(IFootnoteReference { original,
footnote_id, registry,
duplicate_offset: reference_count, {
}) 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 { impl IFootnoteReference {
pub(crate) fn get_display_label(&self) -> String { pub(crate) fn get_display_label(&self) -> String {
@ -26,20 +32,28 @@ impl IFootnoteReference {
/// Get an ID to refer to this footnote reference. /// 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. /// 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 { pub(crate) fn get_reference_id(&self, id_addition: Option<&str>) -> String {
let id_addition = id_addition
.map(|id_addition| format!("sec{}.", id_addition))
.unwrap_or(String::default());
if self.duplicate_offset == 0 { if self.duplicate_offset == 0 {
format!("fnr.{}", self.get_display_label()) format!("{}fnr.{}", id_addition, self.get_display_label())
} else { } else {
// Org-mode makes all duplicates use "100" but I figure there is no harm in giving each a unique ID. // 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; let append = 100 + self.duplicate_offset - 1;
format!("fnr.{}.{}", self.get_display_label(), append) format!("{}fnr.{}.{}", id_addition, self.get_display_label(), append)
} }
} }
/// Get an ID to refer to the footnote definition this footnote reference references. /// 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. /// 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 { pub(crate) fn get_definition_id(&self, id_addition: Option<&str>) -> String {
format!("fn.{}", self.get_display_label()) let id_addition = id_addition
.map(|id_addition| format!("sec{}.", id_addition))
.unwrap_or(String::default());
format!("{}fn.{}", id_addition, self.get_display_label())
} }
} }

View File

@ -11,24 +11,30 @@ pub(crate) struct IHeading {
pub(crate) children: Vec<IDocumentElement>, pub(crate) children: Vec<IDocumentElement>,
} }
intermediate!(IHeading, Heading, original, registry, { intermediate!(
let title = { IHeading,
let mut ret = Vec::new(); &'orig organic::types::Heading<'parse>,
for obj in original.title.iter() { original,
ret.push(IObject::new(registry.clone(), obj).await?); registry,
} {
ret let title = {
}; let mut ret = Vec::new();
let children = { for obj in original.title.iter() {
let mut ret = Vec::new(); ret.push(IObject::new(registry.clone(), obj).await?);
for obj in original.children.iter() { }
ret.push(IDocumentElement::new(registry.clone(), obj).await?); ret
} };
ret let children = {
}; let mut ret = Vec::new();
Ok(IHeading { for obj in original.children.iter() {
title, ret.push(IDocumentElement::new(registry.clone(), obj).await?);
level: original.level, }
children, ret
}) };
}); Ok(IHeading {
title,
level: original.level,
children,
})
}
);

View File

@ -7,8 +7,14 @@ pub(crate) struct IInlineSourceBlock {
pub(crate) value: String, pub(crate) value: String,
} }
intermediate!(IInlineSourceBlock, InlineSourceBlock, original, _registry, { intermediate!(
Ok(IInlineSourceBlock { IInlineSourceBlock,
value: original.value.to_owned(), &'orig organic::types::InlineSourceBlock<'parse>,
}) original,
}); _registry,
{
Ok(IInlineSourceBlock {
value: original.value.to_owned(),
})
}
);

View File

@ -8,14 +8,20 @@ pub(crate) struct IItalic {
pub(crate) children: Vec<IObject>, pub(crate) children: Vec<IObject>,
} }
intermediate!(IItalic, Italic, original, registry, { intermediate!(
let children = { IItalic,
let mut ret = Vec::new(); &'orig organic::types::Italic<'parse>,
for obj in original.children.iter() { original,
ret.push(IObject::new(registry.clone(), obj).await?); registry,
} {
ret let children = {
}; let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(IObject::new(registry.clone(), obj).await?);
}
ret
};
Ok(IItalic { children }) Ok(IItalic { children })
}); }
);

View File

@ -7,13 +7,19 @@ pub(crate) struct ILatexFragment {
pub(crate) value: String, pub(crate) value: String,
} }
intermediate!(ILatexFragment, LatexFragment, original, _registry, { intermediate!(
let value: String = if original.value.starts_with("$$") && original.value.ends_with("$$") { ILatexFragment,
format!("\\[{}\\]", &original.value[2..(original.value.len() - 2)]) &'orig organic::types::LatexFragment<'parse>,
} else if original.value.starts_with("$") && original.value.ends_with("$") { original,
format!("\\({}\\)", &original.value[1..(original.value.len() - 1)]) _registry,
} else { {
original.value.to_owned() let value: String = if original.value.starts_with("$$") && original.value.ends_with("$$") {
}; format!("\\[{}\\]", &original.value[2..(original.value.len() - 2)])
Ok(ILatexFragment { value }) } else if original.value.starts_with("$") && original.value.ends_with("$") {
}); format!("\\({}\\)", &original.value[1..(original.value.len() - 1)])
} else {
original.value.to_owned()
};
Ok(ILatexFragment { value })
}
);

View File

@ -23,14 +23,12 @@ pub(crate) use inoop;
/// ///
/// This exists to make changing the type signature easier. /// This exists to make changing the type signature easier.
macro_rules! intermediate { macro_rules! intermediate {
($istruct:ident, $pstruct:ident, $original:ident, $registry:ident, $fnbody:tt) => { ($istruct:ident, $pstruct:ty, $original:ident, $registry:ident, $fnbody:tt) => {
impl $istruct { impl $istruct {
pub(crate) async fn new<'orig, 'parse>( pub(crate) async fn new<'orig, 'parse>(
registry: crate::intermediate::RefRegistry<'orig, 'parse>, $registry: crate::intermediate::RefRegistry<'orig, 'parse>,
original: &'orig organic::types::$pstruct<'parse>, $original: $pstruct,
) -> Result<$istruct, CustomError> { ) -> Result<$istruct, CustomError> {
let $original = original;
let $registry = registry;
$fnbody $fnbody
} }
} }

View File

@ -1,6 +1,7 @@
mod angle_link; mod angle_link;
mod ast_node; mod ast_node;
mod babel_call; mod babel_call;
mod blog_post;
mod bold; mod bold;
mod center_block; mod center_block;
mod citation; mod citation;
@ -10,7 +11,6 @@ mod code;
mod comment; mod comment;
mod comment_block; mod comment_block;
mod convert; mod convert;
mod definition;
mod diary_sexp; mod diary_sexp;
mod document_element; mod document_element;
mod drawer; mod drawer;
@ -67,6 +67,7 @@ mod verse_block;
pub(crate) use angle_link::IAngleLink; pub(crate) use angle_link::IAngleLink;
pub(crate) use ast_node::IAstNode; pub(crate) use ast_node::IAstNode;
pub(crate) use babel_call::IBabelCall; pub(crate) use babel_call::IBabelCall;
pub(crate) use blog_post::BlogPost;
pub(crate) use bold::IBold; pub(crate) use bold::IBold;
pub(crate) use center_block::ICenterBlock; pub(crate) use center_block::ICenterBlock;
pub(crate) use citation::ICitation; pub(crate) use citation::ICitation;
@ -75,8 +76,7 @@ pub(crate) use clock::IClock;
pub(crate) use code::ICode; pub(crate) use code::ICode;
pub(crate) use comment::IComment; pub(crate) use comment::IComment;
pub(crate) use comment_block::ICommentBlock; pub(crate) use comment_block::ICommentBlock;
pub(crate) use convert::convert_blog_post_page_to_render_context; pub(crate) use convert::get_web_path;
pub(crate) use definition::BlogPost;
pub(crate) use diary_sexp::IDiarySexp; pub(crate) use diary_sexp::IDiarySexp;
pub(crate) use document_element::IDocumentElement; pub(crate) use document_element::IDocumentElement;
pub(crate) use drawer::IDrawer; pub(crate) use drawer::IDrawer;

View File

@ -4,10 +4,28 @@ use crate::error::CustomError;
use super::footnote_definition::IRealFootnoteDefinition; use super::footnote_definition::IRealFootnoteDefinition;
use super::macros::intermediate;
use super::IDocumentElement; use super::IDocumentElement;
use super::IHeading; use super::IHeading;
use super::ISection; use super::ISection;
use super::RefRegistry;
#[derive(Debug)]
pub(crate) struct BlogPostPageInput<'b, 'parse> {
path: PathBuf,
document: &'b organic::types::Document<'parse>,
}
impl<'b, 'parse> BlogPostPageInput<'b, 'parse> {
pub(crate) fn new<P: Into<PathBuf>>(
path: P,
document: &'b organic::types::Document<'parse>,
) -> BlogPostPageInput<'b, 'parse> {
BlogPostPageInput {
path: path.into(),
document,
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct BlogPostPage { pub(crate) struct BlogPostPage {
@ -16,26 +34,26 @@ pub(crate) struct BlogPostPage {
pub(crate) title: Option<String>, pub(crate) title: Option<String>,
pub(crate) date: Option<String>,
pub(crate) children: Vec<IDocumentElement>, pub(crate) children: Vec<IDocumentElement>,
pub(crate) footnotes: Vec<IRealFootnoteDefinition>, pub(crate) footnotes: Vec<IRealFootnoteDefinition>,
} }
impl BlogPostPage { intermediate!(
// TODO: Move path into the registry so I can give this a standard interface like the others. BlogPostPage,
pub(crate) async fn new<'a, 'b, 'parse, P: Into<PathBuf>>( BlogPostPageInput<'orig, 'parse>,
path: P, original,
registry: RefRegistry<'b, 'parse>, registry,
document: &'b organic::types::Document<'parse>, {
) -> Result<BlogPostPage, CustomError> {
let path = path.into();
let mut children = Vec::new(); let mut children = Vec::new();
if let Some(section) = document.zeroth_section.as_ref() { if let Some(section) = original.document.zeroth_section.as_ref() {
children.push(IDocumentElement::Section( children.push(IDocumentElement::Section(
ISection::new(registry.clone(), section).await?, ISection::new(registry.clone(), section).await?,
)); ));
} }
for heading in document.children.iter() { for heading in original.document.children.iter() {
children.push(IDocumentElement::Heading( children.push(IDocumentElement::Heading(
IHeading::new(registry.clone(), heading).await?, IHeading::new(registry.clone(), heading).await?,
)); ));
@ -58,13 +76,16 @@ impl BlogPostPage {
}; };
Ok(BlogPostPage { Ok(BlogPostPage {
path, path: original.path,
title: get_title(&document), title: get_title(original.document),
date: get_date(original.document),
children, children,
footnotes, footnotes,
}) })
} }
);
impl BlogPostPage {
/// Get the output path relative to the post directory. /// Get the output path relative to the post directory.
pub(crate) fn get_output_path(&self) -> PathBuf { pub(crate) fn get_output_path(&self) -> PathBuf {
let mut ret = self.path.clone(); let mut ret = self.path.clone();
@ -85,3 +106,14 @@ fn get_title(document: &organic::types::Document<'_>) -> Option<String> {
.last() .last()
.map(|kw| kw.value.to_owned()) .map(|kw| kw.value.to_owned())
} }
fn get_date(document: &organic::types::Document<'_>) -> Option<String> {
organic::types::AstNode::from(document)
.iter_all_ast_nodes()
.filter_map(|node| match node {
organic::types::AstNode::Keyword(kw) if kw.key.eq_ignore_ascii_case("date") => Some(kw),
_ => None,
})
.last()
.map(|kw| kw.value.to_owned())
}

View File

@ -8,14 +8,20 @@ pub(crate) struct IParagraph {
pub(crate) children: Vec<IObject>, pub(crate) children: Vec<IObject>,
} }
intermediate!(IParagraph, Paragraph, original, registry, { intermediate!(
let children = { IParagraph,
let mut ret = Vec::new(); &'orig organic::types::Paragraph<'parse>,
for obj in original.children.iter() { original,
ret.push(IObject::new(registry.clone(), obj).await?); registry,
} {
ret 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 })
}); }
);

View File

@ -9,17 +9,23 @@ pub(crate) struct IPlainList {
pub(crate) children: Vec<IPlainListItem>, pub(crate) children: Vec<IPlainListItem>,
} }
intermediate!(IPlainList, PlainList, original, registry, { intermediate!(
let children = { IPlainList,
let mut ret = Vec::new(); &'orig organic::types::PlainList<'parse>,
for obj in original.children.iter() { original,
ret.push(IPlainListItem::new(registry.clone(), obj).await?); registry,
} {
ret let children = {
}; let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(IPlainListItem::new(registry.clone(), obj).await?);
}
ret
};
Ok(IPlainList { Ok(IPlainList {
list_type: original.list_type, list_type: original.list_type,
children, children,
}) })
}); }
);

View File

@ -10,22 +10,28 @@ pub(crate) struct IPlainListItem {
pub(crate) children: Vec<IElement>, pub(crate) children: Vec<IElement>,
} }
intermediate!(IPlainListItem, PlainListItem, original, registry, { intermediate!(
let tag = { IPlainListItem,
let mut ret = Vec::new(); &'orig organic::types::PlainListItem<'parse>,
for obj in original.tag.iter() { original,
ret.push(IObject::new(registry.clone(), obj).await?); registry,
} {
ret 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 children = {
let mut ret = Vec::new(); let mut ret = Vec::new();
for elem in original.children.iter() { for elem in original.children.iter() {
ret.push(IElement::new(registry.clone(), elem).await?); ret.push(IElement::new(registry.clone(), elem).await?);
} }
ret ret
}; };
Ok(IPlainListItem { tag, children }) Ok(IPlainListItem { tag, children })
}); }
);

View File

@ -8,8 +8,14 @@ pub(crate) struct IPlainText {
pub(crate) source: String, pub(crate) source: String,
} }
intermediate!(IPlainText, PlainText, original, _registry, { intermediate!(
Ok(IPlainText { IPlainText,
source: coalesce_whitespace(original.source).into_owned(), &'orig organic::types::PlainText<'parse>,
}) original,
}); _registry,
{
Ok(IPlainText {
source: coalesce_whitespace(original.source).into_owned(),
})
}
);

View File

@ -8,14 +8,20 @@ pub(crate) struct IQuoteBlock {
pub(crate) children: Vec<IElement>, pub(crate) children: Vec<IElement>,
} }
intermediate!(IQuoteBlock, QuoteBlock, original, registry, { intermediate!(
let children = { IQuoteBlock,
let mut ret = Vec::new(); &'orig organic::types::QuoteBlock<'parse>,
for obj in original.children.iter() { original,
ret.push(IElement::new(registry.clone(), obj).await?); registry,
} {
ret 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 })
}); }
);

View File

@ -9,16 +9,22 @@ pub(crate) struct IRegularLink {
pub(crate) children: Vec<IObject>, pub(crate) children: Vec<IObject>,
} }
intermediate!(IRegularLink, RegularLink, original, registry, { intermediate!(
let children = { IRegularLink,
let mut ret = Vec::new(); &'orig organic::types::RegularLink<'parse>,
for obj in original.children.iter() { original,
ret.push(IObject::new(registry.clone(), obj).await?); registry,
} {
ret let children = {
}; let mut ret = Vec::new();
Ok(IRegularLink { for obj in original.children.iter() {
raw_link: original.get_raw_link().into_owned(), ret.push(IObject::new(registry.clone(), obj).await?);
children, }
}) ret
}); };
Ok(IRegularLink {
raw_link: original.get_raw_link().into_owned(),
children,
})
}
);

View File

@ -8,14 +8,20 @@ pub(crate) struct ISection {
pub(crate) children: Vec<IElement>, pub(crate) children: Vec<IElement>,
} }
intermediate!(ISection, Section, original, registry, { intermediate!(
let children = { ISection,
let mut ret = Vec::new(); &'orig organic::types::Section<'parse>,
for elem in original.children.iter() { original,
ret.push(IElement::new(registry.clone(), elem).await?); registry,
} {
ret let children = {
}; let mut ret = Vec::new();
for elem in original.children.iter() {
ret.push(IElement::new(registry.clone(), elem).await?);
}
ret
};
Ok(ISection { children }) Ok(ISection { children })
}); }
);

View File

@ -7,11 +7,17 @@ pub(crate) struct ISrcBlock {
pub(crate) lines: Vec<String>, pub(crate) lines: Vec<String>,
} }
intermediate!(ISrcBlock, SrcBlock, original, _registry, { intermediate!(
let lines = original ISrcBlock,
.get_value() &'orig organic::types::SrcBlock<'parse>,
.split_inclusive('\n') original,
.map(|s| s.to_owned()) _registry,
.collect(); {
Ok(ISrcBlock { lines }) let lines = original
}); .get_value()
.split_inclusive('\n')
.map(|s| s.to_owned())
.collect();
Ok(ISrcBlock { lines })
}
);

View File

@ -8,14 +8,20 @@ pub(crate) struct IStrikeThrough {
pub(crate) children: Vec<IObject>, pub(crate) children: Vec<IObject>,
} }
intermediate!(IStrikeThrough, StrikeThrough, original, registry, { intermediate!(
let children = { IStrikeThrough,
let mut ret = Vec::new(); &'orig organic::types::StrikeThrough<'parse>,
for obj in original.children.iter() { original,
ret.push(IObject::new(registry.clone(), obj).await?); registry,
} {
ret let children = {
}; let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(IObject::new(registry.clone(), obj).await?);
}
ret
};
Ok(IStrikeThrough { children }) Ok(IStrikeThrough { children })
}); }
);

View File

@ -8,14 +8,20 @@ pub(crate) struct ITable {
pub(crate) children: Vec<ITableRow>, pub(crate) children: Vec<ITableRow>,
} }
intermediate!(ITable, Table, original, registry, { intermediate!(
let children = { ITable,
let mut ret = Vec::new(); &'orig organic::types::Table<'parse>,
for obj in original.children.iter() { original,
ret.push(ITableRow::new(registry.clone(), obj).await?); registry,
} {
ret let children = {
}; let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(ITableRow::new(registry.clone(), obj).await?);
}
ret
};
Ok(ITable { children }) Ok(ITable { children })
}); }
);

View File

@ -8,14 +8,20 @@ pub(crate) struct ITableCell {
pub(crate) children: Vec<IObject>, pub(crate) children: Vec<IObject>,
} }
intermediate!(ITableCell, TableCell, original, registry, { intermediate!(
let children = { ITableCell,
let mut ret = Vec::new(); &'orig organic::types::TableCell<'parse>,
for obj in original.children.iter() { original,
ret.push(IObject::new(registry.clone(), obj).await?); registry,
} {
ret let children = {
}; let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(IObject::new(registry.clone(), obj).await?);
}
ret
};
Ok(ITableCell { children }) Ok(ITableCell { children })
}); }
);

View File

@ -1,5 +1,4 @@
use super::macros::intermediate; use super::macros::intermediate;
use super::table_cell::ITableCell; use super::table_cell::ITableCell;
use crate::error::CustomError; use crate::error::CustomError;
@ -8,14 +7,20 @@ pub(crate) struct ITableRow {
pub(crate) children: Vec<ITableCell>, pub(crate) children: Vec<ITableCell>,
} }
intermediate!(ITableRow, TableRow, original, registry, { intermediate!(
let children = { ITableRow,
let mut ret = Vec::new(); &'orig organic::types::TableRow<'parse>,
for obj in original.children.iter() { original,
ret.push(ITableCell::new(registry.clone(), obj).await?); registry,
} {
ret let children = {
}; let mut ret = Vec::new();
for obj in original.children.iter() {
ret.push(ITableCell::new(registry.clone(), obj).await?);
}
ret
};
Ok(ITableRow { children }) Ok(ITableRow { children })
}); }
);

View File

@ -8,11 +8,17 @@ pub(crate) struct ITarget {
value: String, value: String,
} }
intermediate!(ITarget, Target, original, registry, { intermediate!(
let mut registry = registry.lock().unwrap(); ITarget,
let id = registry.get_target(original.value); &'orig organic::types::Target<'parse>,
Ok(ITarget { original,
id: id.clone(), registry,
value: original.value.to_owned(), {
}) let mut registry = registry.lock().unwrap();
}); let id = registry.get_target(original.value);
Ok(ITarget {
id: id.clone(),
value: original.value.to_owned(),
})
}
);

Some files were not shown because too many files have changed in this diff Show More