Compare commits
No commits in common. "5228851c0e605f18748d3f8561375e035e65db87" and "424a9700141ac4b6f6afbd9aeebda227abcd7995" have entirely different histories.
5228851c0e
...
424a970014
@ -10,7 +10,6 @@
|
|||||||
{#.page_header}{>page_header/}{/.page_header}
|
{#.page_header}{>page_header/}{/.page_header}
|
||||||
<main class="main_content">
|
<main class="main_content">
|
||||||
{@select key=.type}
|
{@select key=.type}
|
||||||
{@eq value="page"}{>page/}{/eq}
|
|
||||||
{@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}
|
{@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}
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
<article class="page">
|
|
||||||
{?.title}<h1 class="blog_post_title"><span>{.title}</span></h1>{/.title}
|
|
||||||
{! TODO: date? !}
|
|
||||||
|
|
||||||
{! TODO: Table of contents? !}
|
|
||||||
|
|
||||||
<div class="blog_post_body">
|
|
||||||
{#.children}
|
|
||||||
{>document_element/}
|
|
||||||
{/.children}
|
|
||||||
|
|
||||||
{?.footnotes}
|
|
||||||
<h2>Footnotes:</h2>
|
|
||||||
{#.footnotes}
|
|
||||||
{>real_footnote_definition/}
|
|
||||||
{/.footnotes}
|
|
||||||
{/.footnotes}
|
|
||||||
</div>
|
|
||||||
</article>
|
|
@ -13,11 +13,9 @@ 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;
|
||||||
|
|
||||||
@ -29,7 +27,6 @@ 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 {
|
||||||
@ -37,13 +34,11 @@ 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,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,29 +73,6 @@ 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,19 +1,12 @@
|
|||||||
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;
|
||||||
|
|
||||||
@ -24,16 +17,13 @@ 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?;
|
||||||
|
|
||||||
@ -84,62 +74,6 @@ 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,8 +92,4 @@ 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,7 +36,6 @@ 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;
|
||||||
@ -78,7 +77,6 @@ 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;
|
||||||
|
@ -1,102 +0,0 @@
|
|||||||
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::blog_post_page::BlogPostPageInput;
|
use crate::intermediate::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))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_org_files<P: AsRef<Path>>(
|
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)
|
||||||
|
@ -1,121 +0,0 @@
|
|||||||
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,7 +2,6 @@ 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;
|
||||||
@ -71,9 +70,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::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;
|
||||||
@ -108,8 +105,7 @@ 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::IPage;
|
pub(crate) use page::BlogPostPage;
|
||||||
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;
|
||||||
@ -121,7 +117,6 @@ 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,21 +1,39 @@
|
|||||||
use super::blog_post_page::get_date;
|
use std::path::PathBuf;
|
||||||
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 IPage {
|
pub(crate) struct BlogPostPageInput<'b, 'parse> {
|
||||||
/// Relative path from the root of the pages directory.
|
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) 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>,
|
||||||
@ -24,8 +42,8 @@ pub(crate) struct IPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
intermediate!(
|
intermediate!(
|
||||||
IPage,
|
BlogPostPage,
|
||||||
PageInput<'orig, 'parse>,
|
BlogPostPageInput<'orig, 'parse>,
|
||||||
original,
|
original,
|
||||||
intermediate_context,
|
intermediate_context,
|
||||||
{
|
{
|
||||||
@ -59,7 +77,7 @@ intermediate!(
|
|||||||
ret
|
ret
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(IPage {
|
Ok(BlogPostPage {
|
||||||
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),
|
||||||
@ -69,8 +87,8 @@ intermediate!(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
impl IPage {
|
impl BlogPostPage {
|
||||||
/// Get the output path relative to the pages 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();
|
||||||
ret.set_extension("html");
|
ret.set_extension("html");
|
||||||
@ -78,20 +96,26 @@ impl IPage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
fn get_title(document: &organic::types::Document<'_>) -> Option<String> {
|
||||||
pub(crate) struct PageInput<'b, 'parse> {
|
organic::types::AstNode::from(document)
|
||||||
path: PathBuf,
|
.iter_all_ast_nodes()
|
||||||
document: &'b organic::types::Document<'parse>,
|
.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())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b, 'parse> PageInput<'b, 'parse> {
|
fn get_date(document: &organic::types::Document<'_>) -> Option<String> {
|
||||||
pub(crate) fn new<P: Into<PathBuf>>(
|
organic::types::AstNode::from(document)
|
||||||
path: P,
|
.iter_all_ast_nodes()
|
||||||
document: &'b organic::types::Document<'parse>,
|
.filter_map(|node| match node {
|
||||||
) -> PageInput<'b, 'parse> {
|
organic::types::AstNode::Keyword(kw) if kw.key.eq_ignore_ascii_case("date") => Some(kw),
|
||||||
PageInput {
|
_ => None,
|
||||||
path: path.into(),
|
})
|
||||||
document,
|
.last()
|
||||||
}
|
.map(|kw| kw.value.to_owned())
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user