Add a build for regular non-blog-post pages from org source.
This commit is contained in:
parent
424a970014
commit
8905c9356b
@ -13,9 +13,11 @@ use crate::context::RenderBlogPostPageInput;
|
|||||||
use crate::context::RenderBlogStream;
|
use crate::context::RenderBlogStream;
|
||||||
use crate::context::RenderBlogStreamInput;
|
use crate::context::RenderBlogStreamInput;
|
||||||
use crate::context::RenderContext;
|
use crate::context::RenderContext;
|
||||||
|
use crate::context::RenderPage;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::intermediate::get_web_path;
|
use crate::intermediate::get_web_path;
|
||||||
use crate::intermediate::BlogPost;
|
use crate::intermediate::BlogPost;
|
||||||
|
use crate::intermediate::IPage;
|
||||||
use crate::render::DusterRenderer;
|
use crate::render::DusterRenderer;
|
||||||
use crate::render::RendererIntegration;
|
use crate::render::RendererIntegration;
|
||||||
|
|
||||||
@ -27,6 +29,7 @@ pub(crate) struct SiteRenderer {
|
|||||||
output_directory: PathBuf,
|
output_directory: PathBuf,
|
||||||
blog_posts: Vec<BlogPost>,
|
blog_posts: Vec<BlogPost>,
|
||||||
stylesheets: Vec<Stylesheet>,
|
stylesheets: Vec<Stylesheet>,
|
||||||
|
pages: Vec<IPage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SiteRenderer {
|
impl SiteRenderer {
|
||||||
@ -34,11 +37,13 @@ impl SiteRenderer {
|
|||||||
output_directory: P,
|
output_directory: P,
|
||||||
blog_posts: Vec<BlogPost>,
|
blog_posts: Vec<BlogPost>,
|
||||||
stylesheets: Vec<Stylesheet>,
|
stylesheets: Vec<Stylesheet>,
|
||||||
|
pages: Vec<IPage>,
|
||||||
) -> SiteRenderer {
|
) -> SiteRenderer {
|
||||||
SiteRenderer {
|
SiteRenderer {
|
||||||
output_directory: output_directory.into(),
|
output_directory: output_directory.into(),
|
||||||
blog_posts,
|
blog_posts,
|
||||||
stylesheets,
|
stylesheets,
|
||||||
|
pages,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,6 +78,29 @@ impl SiteRenderer {
|
|||||||
Ok(renderer_integration)
|
Ok(renderer_integration)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn render_pages(&self, config: &Config) -> Result<(), CustomError> {
|
||||||
|
let renderer_integration = self.init_renderer_integration()?;
|
||||||
|
|
||||||
|
for page in &self.pages {
|
||||||
|
let output_path = self.output_directory.join(page.get_output_path());
|
||||||
|
let render_context = RenderContext::new(
|
||||||
|
config,
|
||||||
|
self.output_directory.as_path(),
|
||||||
|
output_path.as_path(),
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
let render_context = RenderPage::new(render_context, page)?;
|
||||||
|
let rendered_output = renderer_integration.render(render_context)?;
|
||||||
|
let parent_directory = output_path
|
||||||
|
.parent()
|
||||||
|
.ok_or("Output file should have a containing directory.")?;
|
||||||
|
tokio::fs::create_dir_all(parent_directory).await?;
|
||||||
|
tokio::fs::write(output_path, rendered_output).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) async fn render_blog_posts(&self, config: &Config) -> Result<(), CustomError> {
|
pub(crate) async fn render_blog_posts(&self, config: &Config) -> Result<(), CustomError> {
|
||||||
let renderer_integration = self.init_renderer_integration()?;
|
let renderer_integration = self.init_renderer_integration()?;
|
||||||
|
|
||||||
|
@ -1,12 +1,19 @@
|
|||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use super::stylesheet::Stylesheet;
|
use super::stylesheet::Stylesheet;
|
||||||
use crate::cli::parameters::BuildArgs;
|
use crate::cli::parameters::BuildArgs;
|
||||||
use crate::command::build::render::SiteRenderer;
|
use crate::command::build::render::SiteRenderer;
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
|
use crate::intermediate::get_org_files;
|
||||||
use crate::intermediate::BlogPost;
|
use crate::intermediate::BlogPost;
|
||||||
|
use crate::intermediate::IPage;
|
||||||
|
use crate::intermediate::IntermediateContext;
|
||||||
|
use crate::intermediate::PageInput;
|
||||||
|
use crate::intermediate::Registry;
|
||||||
use include_dir::include_dir;
|
use include_dir::include_dir;
|
||||||
use include_dir::Dir;
|
use include_dir::Dir;
|
||||||
|
|
||||||
@ -17,13 +24,16 @@ pub(crate) async fn build_site(args: BuildArgs) -> Result<(), CustomError> {
|
|||||||
let config = Config::load_from_file(args.config).await?;
|
let config = Config::load_from_file(args.config).await?;
|
||||||
let blog_posts = load_blog_posts(&config).await?;
|
let blog_posts = load_blog_posts(&config).await?;
|
||||||
let stylesheets = load_stylesheets().await?;
|
let stylesheets = load_stylesheets().await?;
|
||||||
|
let pages = load_pages(&config).await?;
|
||||||
let renderer = SiteRenderer::new(
|
let renderer = SiteRenderer::new(
|
||||||
get_output_directory(&config).await?,
|
get_output_directory(&config).await?,
|
||||||
blog_posts,
|
blog_posts,
|
||||||
stylesheets,
|
stylesheets,
|
||||||
|
pages,
|
||||||
);
|
);
|
||||||
renderer.render_blog_posts(&config).await?;
|
renderer.render_blog_posts(&config).await?;
|
||||||
renderer.render_blog_stream(&config).await?;
|
renderer.render_blog_stream(&config).await?;
|
||||||
|
renderer.render_pages(&config).await?;
|
||||||
renderer.render_stylesheets().await?;
|
renderer.render_stylesheets().await?;
|
||||||
renderer.copy_static_files(&config).await?;
|
renderer.copy_static_files(&config).await?;
|
||||||
|
|
||||||
@ -74,6 +84,62 @@ async fn load_blog_posts(config: &Config) -> Result<Vec<BlogPost>, CustomError>
|
|||||||
Ok(blog_posts)
|
Ok(blog_posts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn load_pages(config: &Config) -> Result<Vec<IPage>, CustomError> {
|
||||||
|
let pages_source = config
|
||||||
|
.get_root_directory()
|
||||||
|
.join(config.get_relative_path_to_pages());
|
||||||
|
if !pages_source.exists() {
|
||||||
|
return Ok(Vec::new());
|
||||||
|
}
|
||||||
|
let page_files = get_org_files(&pages_source)?;
|
||||||
|
let org_files = {
|
||||||
|
let mut ret = Vec::new();
|
||||||
|
for page in page_files {
|
||||||
|
ret.push(page.await??);
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
};
|
||||||
|
let parsed_org_files = {
|
||||||
|
let mut ret = Vec::new();
|
||||||
|
for (path, contents) in org_files.iter() {
|
||||||
|
let parsed = organic::parser::parse_file(contents.as_str(), Some(path))
|
||||||
|
.map_err(|_| CustomError::Static("Failed to parse org-mode document."))?;
|
||||||
|
ret.push((path, contents, parsed));
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
};
|
||||||
|
|
||||||
|
let pages = {
|
||||||
|
let mut ret = Vec::new();
|
||||||
|
for (real_path, _contents, parsed_document) in parsed_org_files.iter() {
|
||||||
|
let mut registry = Registry::new();
|
||||||
|
|
||||||
|
// Assign IDs to the targets
|
||||||
|
organic::types::AstNode::from(parsed_document)
|
||||||
|
.iter_all_ast_nodes()
|
||||||
|
.for_each(|node| {
|
||||||
|
if let organic::types::AstNode::Target(target) = node {
|
||||||
|
registry.get_target(target.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let registry = Arc::new(Mutex::new(registry));
|
||||||
|
let intermediate_context = IntermediateContext::new(registry)?;
|
||||||
|
let relative_to_pages_dir_path = real_path.strip_prefix(&pages_source)?;
|
||||||
|
ret.push(
|
||||||
|
IPage::new(
|
||||||
|
intermediate_context,
|
||||||
|
PageInput::new(relative_to_pages_dir_path, parsed_document),
|
||||||
|
)
|
||||||
|
.await?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(pages)
|
||||||
|
}
|
||||||
|
|
||||||
async fn load_stylesheets() -> Result<Vec<Stylesheet>, CustomError> {
|
async fn load_stylesheets() -> Result<Vec<Stylesheet>, CustomError> {
|
||||||
let sources: Vec<_> = DEFAULT_STYLESHEETS
|
let sources: Vec<_> = DEFAULT_STYLESHEETS
|
||||||
.files()
|
.files()
|
||||||
|
@ -92,4 +92,8 @@ impl Config {
|
|||||||
pub(crate) fn get_relative_path_to_static_files(&self) -> PathBuf {
|
pub(crate) fn get_relative_path_to_static_files(&self) -> PathBuf {
|
||||||
Path::new("static").into()
|
Path::new("static").into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_relative_path_to_pages(&self) -> PathBuf {
|
||||||
|
Path::new("pages").into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ mod line_break;
|
|||||||
mod macros;
|
mod macros;
|
||||||
mod object;
|
mod object;
|
||||||
mod org_macro;
|
mod org_macro;
|
||||||
|
mod page;
|
||||||
mod page_header;
|
mod page_header;
|
||||||
mod paragraph;
|
mod paragraph;
|
||||||
mod plain_link;
|
mod plain_link;
|
||||||
@ -77,6 +78,7 @@ pub(crate) use footnote_definition::RenderRealFootnoteDefinition;
|
|||||||
pub(crate) use global_settings::GlobalSettings;
|
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::RenderPage;
|
||||||
pub(crate) use page_header::PageHeader;
|
pub(crate) use page_header::PageHeader;
|
||||||
pub(crate) use render_context::RenderContext;
|
pub(crate) use render_context::RenderContext;
|
||||||
pub(crate) use section::RenderSection;
|
pub(crate) use section::RenderSection;
|
||||||
|
102
src/context/page.rs
Normal file
102
src/context/page.rs
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
use super::footnote_definition::RenderRealFootnoteDefinition;
|
||||||
|
use super::macros::render;
|
||||||
|
use super::render_context::RenderContext;
|
||||||
|
use super::GlobalSettings;
|
||||||
|
use super::PageHeader;
|
||||||
|
use super::RenderDocumentElement;
|
||||||
|
use crate::error::CustomError;
|
||||||
|
use crate::intermediate::get_web_path;
|
||||||
|
use crate::intermediate::IPage;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
#[serde(tag = "type")]
|
||||||
|
#[serde(rename = "page")]
|
||||||
|
pub(crate) struct RenderPage {
|
||||||
|
global_settings: GlobalSettings,
|
||||||
|
|
||||||
|
page_header: Option<PageHeader>,
|
||||||
|
|
||||||
|
/// The title that will be shown visibly on the page.
|
||||||
|
title: Option<String>,
|
||||||
|
|
||||||
|
self_link: Option<String>,
|
||||||
|
|
||||||
|
children: Vec<RenderDocumentElement>,
|
||||||
|
|
||||||
|
footnotes: Vec<RenderRealFootnoteDefinition>,
|
||||||
|
}
|
||||||
|
|
||||||
|
render!(RenderPage, IPage, 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(original.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.children.iter() {
|
||||||
|
children.push(RenderDocumentElement::new(render_context.clone(), child)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
children
|
||||||
|
};
|
||||||
|
|
||||||
|
let footnotes = {
|
||||||
|
let mut ret = Vec::new();
|
||||||
|
|
||||||
|
for footnote in original.footnotes.iter() {
|
||||||
|
ret.push(RenderRealFootnoteDefinition::new(
|
||||||
|
render_context.clone(),
|
||||||
|
footnote,
|
||||||
|
)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret
|
||||||
|
};
|
||||||
|
|
||||||
|
let ret = RenderPage {
|
||||||
|
global_settings,
|
||||||
|
page_header: Some(page_header),
|
||||||
|
title: original.title.clone(),
|
||||||
|
self_link: Some(link_to_blog_post),
|
||||||
|
children,
|
||||||
|
footnotes,
|
||||||
|
};
|
||||||
|
Ok(ret)
|
||||||
|
});
|
@ -7,7 +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::blog_post_page::BlogPostPageInput;
|
||||||
use crate::intermediate::registry::Registry;
|
use crate::intermediate::registry::Registry;
|
||||||
use crate::intermediate::IntermediateContext;
|
use crate::intermediate::IntermediateContext;
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ async fn read_file(path: PathBuf) -> std::io::Result<(PathBuf, String)> {
|
|||||||
Ok((path, contents))
|
Ok((path, contents))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_org_files<P: AsRef<Path>>(
|
pub(crate) fn get_org_files<P: AsRef<Path>>(
|
||||||
root_dir: P,
|
root_dir: P,
|
||||||
) -> Result<impl Iterator<Item = JoinHandle<std::io::Result<(PathBuf, String)>>>, walkdir::Error> {
|
) -> Result<impl Iterator<Item = JoinHandle<std::io::Result<(PathBuf, String)>>>, walkdir::Error> {
|
||||||
let org_files = WalkDir::new(root_dir)
|
let org_files = WalkDir::new(root_dir)
|
||||||
|
121
src/intermediate/blog_post_page.rs
Normal file
121
src/intermediate/blog_post_page.rs
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use crate::error::CustomError;
|
||||||
|
|
||||||
|
use super::footnote_definition::IRealFootnoteDefinition;
|
||||||
|
|
||||||
|
use super::macros::intermediate;
|
||||||
|
use super::IDocumentElement;
|
||||||
|
use super::IHeading;
|
||||||
|
use super::ISection;
|
||||||
|
|
||||||
|
#[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)]
|
||||||
|
pub(crate) struct BlogPostPage {
|
||||||
|
/// Relative path from the root of the blog post.
|
||||||
|
pub(crate) path: PathBuf,
|
||||||
|
|
||||||
|
pub(crate) title: Option<String>,
|
||||||
|
|
||||||
|
pub(crate) date: Option<String>,
|
||||||
|
|
||||||
|
pub(crate) children: Vec<IDocumentElement>,
|
||||||
|
|
||||||
|
pub(crate) footnotes: Vec<IRealFootnoteDefinition>,
|
||||||
|
}
|
||||||
|
|
||||||
|
intermediate!(
|
||||||
|
BlogPostPage,
|
||||||
|
BlogPostPageInput<'orig, 'parse>,
|
||||||
|
original,
|
||||||
|
intermediate_context,
|
||||||
|
{
|
||||||
|
let mut children = Vec::new();
|
||||||
|
if let Some(section) = original.document.zeroth_section.as_ref() {
|
||||||
|
children.push(IDocumentElement::Section(
|
||||||
|
ISection::new(intermediate_context.clone(), section).await?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
for heading in original.document.children.iter() {
|
||||||
|
children.push(IDocumentElement::Heading(
|
||||||
|
IHeading::new(intermediate_context.clone(), heading).await?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let footnotes = {
|
||||||
|
let footnote_definitions: Vec<_> = {
|
||||||
|
let registry = intermediate_context.registry.lock().unwrap();
|
||||||
|
let ret = registry
|
||||||
|
.get_footnote_ids()
|
||||||
|
.map(|(id, def)| (id, def.clone()))
|
||||||
|
.collect();
|
||||||
|
ret
|
||||||
|
};
|
||||||
|
let mut ret = Vec::new();
|
||||||
|
for (id, def) in footnote_definitions.into_iter() {
|
||||||
|
ret.push(
|
||||||
|
IRealFootnoteDefinition::new(intermediate_context.clone(), id, def).await?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(BlogPostPage {
|
||||||
|
path: original.path,
|
||||||
|
title: get_title(original.document),
|
||||||
|
date: get_date(original.document),
|
||||||
|
children,
|
||||||
|
footnotes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
impl BlogPostPage {
|
||||||
|
/// Get the output path relative to the post directory.
|
||||||
|
pub(crate) fn get_output_path(&self) -> PathBuf {
|
||||||
|
let mut ret = self.path.clone();
|
||||||
|
ret.set_extension("html");
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_title(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("title") => {
|
||||||
|
Some(kw)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.last()
|
||||||
|
.map(|kw| kw.value.to_owned())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) 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())
|
||||||
|
}
|
@ -2,6 +2,7 @@ mod angle_link;
|
|||||||
mod ast_node;
|
mod ast_node;
|
||||||
mod babel_call;
|
mod babel_call;
|
||||||
mod blog_post;
|
mod blog_post;
|
||||||
|
mod blog_post_page;
|
||||||
mod bold;
|
mod bold;
|
||||||
mod center_block;
|
mod center_block;
|
||||||
mod citation;
|
mod citation;
|
||||||
@ -70,7 +71,9 @@ 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::get_org_files;
|
||||||
pub(crate) use blog_post::BlogPost;
|
pub(crate) use blog_post::BlogPost;
|
||||||
|
pub(crate) use blog_post_page::BlogPostPage;
|
||||||
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;
|
||||||
@ -105,7 +108,8 @@ pub(crate) use latex_fragment::ILatexFragment;
|
|||||||
pub(crate) use line_break::ILineBreak;
|
pub(crate) use line_break::ILineBreak;
|
||||||
pub(crate) use object::IObject;
|
pub(crate) use object::IObject;
|
||||||
pub(crate) use org_macro::IOrgMacro;
|
pub(crate) use org_macro::IOrgMacro;
|
||||||
pub(crate) use page::BlogPostPage;
|
pub(crate) use page::IPage;
|
||||||
|
pub(crate) use page::PageInput;
|
||||||
pub(crate) use paragraph::IParagraph;
|
pub(crate) use paragraph::IParagraph;
|
||||||
pub(crate) use plain_link::IPlainLink;
|
pub(crate) use plain_link::IPlainLink;
|
||||||
pub(crate) use plain_list::IPlainList;
|
pub(crate) use plain_list::IPlainList;
|
||||||
@ -117,6 +121,7 @@ pub(crate) use property_drawer::IPropertyDrawer;
|
|||||||
pub(crate) use quote_block::IQuoteBlock;
|
pub(crate) use quote_block::IQuoteBlock;
|
||||||
pub(crate) use radio_link::IRadioLink;
|
pub(crate) use radio_link::IRadioLink;
|
||||||
pub(crate) use radio_target::IRadioTarget;
|
pub(crate) use radio_target::IRadioTarget;
|
||||||
|
pub(crate) use registry::Registry;
|
||||||
pub(crate) use regular_link::IRegularLink;
|
pub(crate) use regular_link::IRegularLink;
|
||||||
pub(crate) use section::ISection;
|
pub(crate) use section::ISection;
|
||||||
pub(crate) use special_block::ISpecialBlock;
|
pub(crate) use special_block::ISpecialBlock;
|
||||||
|
@ -1,39 +1,21 @@
|
|||||||
use std::path::PathBuf;
|
use super::blog_post_page::get_date;
|
||||||
|
use super::blog_post_page::get_title;
|
||||||
use crate::error::CustomError;
|
|
||||||
|
|
||||||
use super::footnote_definition::IRealFootnoteDefinition;
|
use super::footnote_definition::IRealFootnoteDefinition;
|
||||||
|
|
||||||
use super::macros::intermediate;
|
use super::macros::intermediate;
|
||||||
use super::IDocumentElement;
|
use super::IDocumentElement;
|
||||||
use super::IHeading;
|
use super::IHeading;
|
||||||
use super::ISection;
|
use super::ISection;
|
||||||
|
use crate::error::CustomError;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct BlogPostPageInput<'b, 'parse> {
|
pub(crate) struct IPage {
|
||||||
path: PathBuf,
|
/// Relative path from the root of the pages directory.
|
||||||
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)]
|
|
||||||
pub(crate) struct BlogPostPage {
|
|
||||||
/// Relative path from the root of the blog post.
|
|
||||||
pub(crate) path: PathBuf,
|
pub(crate) path: PathBuf,
|
||||||
|
|
||||||
pub(crate) title: Option<String>,
|
pub(crate) title: Option<String>,
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub(crate) date: Option<String>,
|
pub(crate) date: Option<String>,
|
||||||
|
|
||||||
pub(crate) children: Vec<IDocumentElement>,
|
pub(crate) children: Vec<IDocumentElement>,
|
||||||
@ -42,8 +24,8 @@ pub(crate) struct BlogPostPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
intermediate!(
|
intermediate!(
|
||||||
BlogPostPage,
|
IPage,
|
||||||
BlogPostPageInput<'orig, 'parse>,
|
PageInput<'orig, 'parse>,
|
||||||
original,
|
original,
|
||||||
intermediate_context,
|
intermediate_context,
|
||||||
{
|
{
|
||||||
@ -77,7 +59,7 @@ intermediate!(
|
|||||||
ret
|
ret
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(BlogPostPage {
|
Ok(IPage {
|
||||||
path: original.path,
|
path: original.path,
|
||||||
title: get_title(original.document),
|
title: get_title(original.document),
|
||||||
date: get_date(original.document),
|
date: get_date(original.document),
|
||||||
@ -87,8 +69,8 @@ intermediate!(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
impl BlogPostPage {
|
impl IPage {
|
||||||
/// Get the output path relative to the post directory.
|
/// Get the output path relative to the pages 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();
|
||||||
ret.set_extension("html");
|
ret.set_extension("html");
|
||||||
@ -96,26 +78,20 @@ impl BlogPostPage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_title(document: &organic::types::Document<'_>) -> Option<String> {
|
#[derive(Debug)]
|
||||||
organic::types::AstNode::from(document)
|
pub(crate) struct PageInput<'b, 'parse> {
|
||||||
.iter_all_ast_nodes()
|
path: PathBuf,
|
||||||
.filter_map(|node| match node {
|
document: &'b organic::types::Document<'parse>,
|
||||||
organic::types::AstNode::Keyword(kw) if kw.key.eq_ignore_ascii_case("title") => {
|
|
||||||
Some(kw)
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.last()
|
|
||||||
.map(|kw| kw.value.to_owned())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_date(document: &organic::types::Document<'_>) -> Option<String> {
|
impl<'b, 'parse> PageInput<'b, 'parse> {
|
||||||
organic::types::AstNode::from(document)
|
pub(crate) fn new<P: Into<PathBuf>>(
|
||||||
.iter_all_ast_nodes()
|
path: P,
|
||||||
.filter_map(|node| match node {
|
document: &'b organic::types::Document<'parse>,
|
||||||
organic::types::AstNode::Keyword(kw) if kw.key.eq_ignore_ascii_case("date") => Some(kw),
|
) -> PageInput<'b, 'parse> {
|
||||||
_ => None,
|
PageInput {
|
||||||
})
|
path: path.into(),
|
||||||
.last()
|
document,
|
||||||
.map(|kw| kw.value.to_owned())
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user