Compare commits
5 Commits
8fd37cbf22
...
3e952ef0f4
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3e952ef0f4 | ||
![]() |
4e0f66401d | ||
![]() |
3867f965d2 | ||
![]() |
5cac44c625 | ||
![]() |
463be34302 |
4
rust-toolchain.toml
Normal file
4
rust-toolchain.toml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[toolchain]
|
||||||
|
channel = "nightly"
|
||||||
|
profile = "default"
|
||||||
|
components = ["clippy", "rustfmt"]
|
@ -7,6 +7,7 @@ use tokio::fs::DirEntry;
|
|||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
|
use crate::context::DependencyManager;
|
||||||
use crate::context::RenderBlogPostPage;
|
use crate::context::RenderBlogPostPage;
|
||||||
use crate::context::RenderBlogPostPageInput;
|
use crate::context::RenderBlogPostPageInput;
|
||||||
use crate::context::RenderBlogStream;
|
use crate::context::RenderBlogStream;
|
||||||
@ -85,11 +86,14 @@ impl SiteRenderer {
|
|||||||
|
|
||||||
for page in &self.pages {
|
for page in &self.pages {
|
||||||
let output_path = self.output_directory.join(page.get_output_path());
|
let output_path = self.output_directory.join(page.get_output_path());
|
||||||
|
let dependency_manager =
|
||||||
|
std::sync::Arc::new(std::sync::Mutex::new(DependencyManager::new()));
|
||||||
let render_context = RenderContext::new(
|
let render_context = RenderContext::new(
|
||||||
config,
|
config,
|
||||||
self.output_directory.as_path(),
|
self.output_directory.as_path(),
|
||||||
output_path.as_path(),
|
output_path.as_path(),
|
||||||
None,
|
None,
|
||||||
|
dependency_manager,
|
||||||
)?;
|
)?;
|
||||||
let render_context = RenderPage::new(render_context, page)?;
|
let render_context = RenderPage::new(render_context, page)?;
|
||||||
let rendered_output = renderer_integration.render(render_context)?;
|
let rendered_output = renderer_integration.render(render_context)?;
|
||||||
@ -113,12 +117,15 @@ impl SiteRenderer {
|
|||||||
.join(config.get_relative_path_to_post(&blog_post.id))
|
.join(config.get_relative_path_to_post(&blog_post.id))
|
||||||
.join(blog_post_page.get_output_path());
|
.join(blog_post_page.get_output_path());
|
||||||
|
|
||||||
|
let dependency_manager =
|
||||||
|
std::sync::Arc::new(std::sync::Mutex::new(DependencyManager::new()));
|
||||||
let convert_input = RenderBlogPostPageInput::new(blog_post, blog_post_page);
|
let convert_input = RenderBlogPostPageInput::new(blog_post, blog_post_page);
|
||||||
let render_context = RenderContext::new(
|
let render_context = RenderContext::new(
|
||||||
config,
|
config,
|
||||||
self.output_directory.as_path(),
|
self.output_directory.as_path(),
|
||||||
output_path.as_path(),
|
output_path.as_path(),
|
||||||
None,
|
None,
|
||||||
|
dependency_manager,
|
||||||
)?;
|
)?;
|
||||||
let render_context = RenderBlogPostPage::new(render_context, &convert_input)?;
|
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)?;
|
||||||
@ -127,6 +134,9 @@ impl SiteRenderer {
|
|||||||
.ok_or("Output file should have a containing directory.")?;
|
.ok_or("Output file should have a containing directory.")?;
|
||||||
tokio::fs::create_dir_all(parent_directory).await?;
|
tokio::fs::create_dir_all(parent_directory).await?;
|
||||||
tokio::fs::write(output_path, rendered_output).await?;
|
tokio::fs::write(output_path, rendered_output).await?;
|
||||||
|
|
||||||
|
// TODO: Copy post files to output.
|
||||||
|
// TODO: Update link src to generate path correct for where the page is rendered.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,12 +204,15 @@ impl SiteRenderer {
|
|||||||
)?)
|
)?)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let dependency_manager =
|
||||||
|
std::sync::Arc::new(std::sync::Mutex::new(DependencyManager::new()));
|
||||||
let convert_input = RenderBlogStreamInput::new(chunk, older_link, newer_link);
|
let convert_input = RenderBlogStreamInput::new(chunk, older_link, newer_link);
|
||||||
let render_context = RenderContext::new(
|
let render_context = RenderContext::new(
|
||||||
config,
|
config,
|
||||||
self.output_directory.as_path(),
|
self.output_directory.as_path(),
|
||||||
output_file.as_path(),
|
output_file.as_path(),
|
||||||
None,
|
None,
|
||||||
|
dependency_manager,
|
||||||
)?;
|
)?;
|
||||||
let blog_stream = RenderBlogStream::new(render_context, &convert_input)?;
|
let blog_stream = RenderBlogStream::new(render_context, &convert_input)?;
|
||||||
|
|
||||||
|
@ -163,7 +163,7 @@ async fn load_pages(config: &Config) -> Result<Vec<IPage>, CustomError> {
|
|||||||
ret.push(
|
ret.push(
|
||||||
IPage::new(
|
IPage::new(
|
||||||
intermediate_context,
|
intermediate_context,
|
||||||
PageInput::new(relative_to_pages_dir_path, parsed_document),
|
PageInput::new(relative_to_pages_dir_path, real_path, parsed_document),
|
||||||
)
|
)
|
||||||
.await?,
|
.await?,
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::render_context::RenderContext;
|
use super::render_context::RenderContext;
|
||||||
|
use crate::context::macros::push_file;
|
||||||
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;
|
||||||
@ -49,6 +50,7 @@ render!(
|
|||||||
original,
|
original,
|
||||||
render_context,
|
render_context,
|
||||||
{
|
{
|
||||||
|
push_file!(render_context, &original.page.src, {
|
||||||
let css_files = vec![
|
let css_files = vec![
|
||||||
get_web_path(
|
get_web_path(
|
||||||
render_context.config,
|
render_context.config,
|
||||||
@ -69,7 +71,8 @@ render!(
|
|||||||
render_context.output_file,
|
render_context.output_file,
|
||||||
"blog_post.js",
|
"blog_post.js",
|
||||||
)?];
|
)?];
|
||||||
let global_settings = GlobalSettings::new(original.page.title.clone(), css_files, js_files);
|
let global_settings =
|
||||||
|
GlobalSettings::new(original.page.title.clone(), css_files, js_files);
|
||||||
let page_header = PageHeader::new(
|
let page_header = PageHeader::new(
|
||||||
render_context.config.get_site_title().map(str::to_string),
|
render_context.config.get_site_title().map(str::to_string),
|
||||||
Some(get_web_path(
|
Some(get_web_path(
|
||||||
@ -120,5 +123,6 @@ render!(
|
|||||||
footnotes,
|
footnotes,
|
||||||
};
|
};
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
36
src/context/dependency_manager.rs
Normal file
36
src/context/dependency_manager.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use crate::error::CustomError;
|
||||||
|
|
||||||
|
pub(crate) type RefDependencyManager = std::sync::Arc<std::sync::Mutex<DependencyManager>>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct DependencyManager {
|
||||||
|
/// A stack of paths for the files being visited.
|
||||||
|
///
|
||||||
|
/// The last entry is the current file being processed. This can be used for handling relative-path links.
|
||||||
|
file_stack: Vec<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DependencyManager {
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
|
DependencyManager {
|
||||||
|
file_stack: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn push_file<P>(&mut self, path: P) -> Result<(), CustomError>
|
||||||
|
where
|
||||||
|
P: Into<PathBuf>,
|
||||||
|
{
|
||||||
|
self.file_stack.push(path.into());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn pop_file(&mut self) -> Result<(), CustomError> {
|
||||||
|
self.file_stack
|
||||||
|
.pop()
|
||||||
|
.expect("Popped more files off the dependency manager file stack than exist.");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@ -35,3 +35,23 @@ macro_rules! rnoop {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) use rnoop;
|
pub(crate) use rnoop;
|
||||||
|
|
||||||
|
/// Push a file onto the render DependencyManager's file stack while inside the code block.
|
||||||
|
macro_rules! push_file {
|
||||||
|
($render_context:ident, $path:expr, $body:tt) => {{
|
||||||
|
$render_context
|
||||||
|
.dependency_manager
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.push_file($path)?;
|
||||||
|
let ret = (|| $body)();
|
||||||
|
$render_context
|
||||||
|
.dependency_manager
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.pop_file()?;
|
||||||
|
ret
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) use push_file;
|
||||||
|
@ -11,6 +11,7 @@ mod clock;
|
|||||||
mod code;
|
mod code;
|
||||||
mod comment;
|
mod comment;
|
||||||
mod comment_block;
|
mod comment_block;
|
||||||
|
mod dependency_manager;
|
||||||
mod diary_sexp;
|
mod diary_sexp;
|
||||||
mod document_element;
|
mod document_element;
|
||||||
mod drawer;
|
mod drawer;
|
||||||
@ -72,6 +73,7 @@ pub(crate) use blog_post_page::RenderBlogPostPage;
|
|||||||
pub(crate) use blog_post_page::RenderBlogPostPageInput;
|
pub(crate) use blog_post_page::RenderBlogPostPageInput;
|
||||||
pub(crate) use blog_stream::RenderBlogStream;
|
pub(crate) use blog_stream::RenderBlogStream;
|
||||||
pub(crate) use blog_stream::RenderBlogStreamInput;
|
pub(crate) use blog_stream::RenderBlogStreamInput;
|
||||||
|
pub(crate) use dependency_manager::DependencyManager;
|
||||||
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;
|
||||||
|
@ -3,6 +3,8 @@ use std::path::Path;
|
|||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
|
|
||||||
|
use super::dependency_manager::RefDependencyManager;
|
||||||
|
|
||||||
/// The supporting information used for converting the intermediate representation into the dust context for rendering.
|
/// The supporting information used for converting the intermediate representation into the dust context for rendering.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct RenderContext<'intermediate> {
|
pub(crate) struct RenderContext<'intermediate> {
|
||||||
@ -16,6 +18,13 @@ pub(crate) struct RenderContext<'intermediate> {
|
|||||||
/// IDs, for example, multiple blog posts with footnotes in a blog
|
/// IDs, for example, multiple blog posts with footnotes in a blog
|
||||||
/// stream.
|
/// stream.
|
||||||
pub(crate) id_addition: Option<&'intermediate str>,
|
pub(crate) id_addition: Option<&'intermediate str>,
|
||||||
|
|
||||||
|
/// Tracks dependencies from rendering Org document(s).
|
||||||
|
///
|
||||||
|
/// Examples of dependencies would be:
|
||||||
|
/// - Static files that need to be copied to the output folder
|
||||||
|
/// - Code blocks that need to be executed (for example, gnuplot graphs)
|
||||||
|
pub(crate) dependency_manager: RefDependencyManager,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'intermediate> RenderContext<'intermediate> {
|
impl<'intermediate> RenderContext<'intermediate> {
|
||||||
@ -24,12 +33,14 @@ impl<'intermediate> RenderContext<'intermediate> {
|
|||||||
output_directory: &'intermediate Path,
|
output_directory: &'intermediate Path,
|
||||||
output_file: &'intermediate Path,
|
output_file: &'intermediate Path,
|
||||||
id_addition: Option<&'intermediate str>,
|
id_addition: Option<&'intermediate str>,
|
||||||
|
dependency_manager: RefDependencyManager,
|
||||||
) -> Result<RenderContext<'intermediate>, CustomError> {
|
) -> Result<RenderContext<'intermediate>, CustomError> {
|
||||||
Ok(RenderContext {
|
Ok(RenderContext {
|
||||||
config,
|
config,
|
||||||
output_root_directory: output_directory,
|
output_root_directory: output_directory,
|
||||||
output_file,
|
output_file,
|
||||||
id_addition,
|
id_addition,
|
||||||
|
dependency_manager,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@ impl BlogPost {
|
|||||||
) -> Result<BlogPost, CustomError> {
|
) -> Result<BlogPost, CustomError> {
|
||||||
let post_id = post_dir.strip_prefix(posts_dir)?.as_os_str();
|
let post_id = post_dir.strip_prefix(posts_dir)?.as_os_str();
|
||||||
|
|
||||||
|
// Load all the *.org files under the post directory from disk into memory
|
||||||
let org_files = {
|
let org_files = {
|
||||||
let mut ret = Vec::new();
|
let mut ret = Vec::new();
|
||||||
let org_files_iter = get_org_files(post_dir).await?;
|
let org_files_iter = get_org_files(post_dir).await?;
|
||||||
@ -43,6 +44,8 @@ impl BlogPost {
|
|||||||
}
|
}
|
||||||
ret
|
ret
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Parse all the *.org files
|
||||||
let parsed_org_files = {
|
let parsed_org_files = {
|
||||||
let mut ret = Vec::new();
|
let mut ret = Vec::new();
|
||||||
for (path, contents) in org_files.iter() {
|
for (path, contents) in org_files.iter() {
|
||||||
@ -73,7 +76,11 @@ impl BlogPost {
|
|||||||
ret.push(
|
ret.push(
|
||||||
BlogPostPage::new(
|
BlogPostPage::new(
|
||||||
intermediate_context,
|
intermediate_context,
|
||||||
BlogPostPageInput::new(relative_to_post_dir_path, parsed_document),
|
BlogPostPageInput::new(
|
||||||
|
relative_to_post_dir_path,
|
||||||
|
real_path,
|
||||||
|
parsed_document,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.await?,
|
.await?,
|
||||||
);
|
);
|
||||||
|
@ -11,17 +11,23 @@ use super::ISection;
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct BlogPostPageInput<'b, 'parse> {
|
pub(crate) struct BlogPostPageInput<'b, 'parse> {
|
||||||
|
/// Relative path from the root of the blog post.
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
|
|
||||||
|
/// The path to the .org source for the file.
|
||||||
|
src: PathBuf,
|
||||||
document: &'b organic::types::Document<'parse>,
|
document: &'b organic::types::Document<'parse>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b, 'parse> BlogPostPageInput<'b, 'parse> {
|
impl<'b, 'parse> BlogPostPageInput<'b, 'parse> {
|
||||||
pub(crate) fn new<P: Into<PathBuf>>(
|
pub(crate) fn new<P: Into<PathBuf>, S: Into<PathBuf>>(
|
||||||
path: P,
|
path: P,
|
||||||
|
src: S,
|
||||||
document: &'b organic::types::Document<'parse>,
|
document: &'b organic::types::Document<'parse>,
|
||||||
) -> BlogPostPageInput<'b, 'parse> {
|
) -> BlogPostPageInput<'b, 'parse> {
|
||||||
BlogPostPageInput {
|
BlogPostPageInput {
|
||||||
path: path.into(),
|
path: path.into(),
|
||||||
|
src: src.into(),
|
||||||
document,
|
document,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -32,6 +38,9 @@ pub(crate) struct BlogPostPage {
|
|||||||
/// Relative path from the root of the blog post.
|
/// Relative path from the root of the blog post.
|
||||||
pub(crate) path: PathBuf,
|
pub(crate) path: PathBuf,
|
||||||
|
|
||||||
|
/// The path to the .org source for the file.
|
||||||
|
pub(crate) src: PathBuf,
|
||||||
|
|
||||||
pub(crate) title: Option<String>,
|
pub(crate) title: Option<String>,
|
||||||
|
|
||||||
pub(crate) date: Option<String>,
|
pub(crate) date: Option<String>,
|
||||||
@ -79,6 +88,7 @@ intermediate!(
|
|||||||
|
|
||||||
Ok(BlogPostPage {
|
Ok(BlogPostPage {
|
||||||
path: original.path,
|
path: original.path,
|
||||||
|
src: original.src,
|
||||||
title: get_title(original.document),
|
title: get_title(original.document),
|
||||||
date: get_date(original.document),
|
date: get_date(original.document),
|
||||||
children,
|
children,
|
||||||
|
@ -13,6 +13,9 @@ pub(crate) struct IPage {
|
|||||||
/// Relative path from the root of the pages directory.
|
/// Relative path from the root of the pages directory.
|
||||||
pub(crate) path: PathBuf,
|
pub(crate) path: PathBuf,
|
||||||
|
|
||||||
|
/// The path to the .org source for the file.
|
||||||
|
pub(crate) src: PathBuf,
|
||||||
|
|
||||||
pub(crate) title: Option<String>,
|
pub(crate) title: Option<String>,
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -61,6 +64,7 @@ intermediate!(
|
|||||||
|
|
||||||
Ok(IPage {
|
Ok(IPage {
|
||||||
path: original.path,
|
path: original.path,
|
||||||
|
src: original.src,
|
||||||
title: get_title(original.document),
|
title: get_title(original.document),
|
||||||
date: get_date(original.document),
|
date: get_date(original.document),
|
||||||
children,
|
children,
|
||||||
@ -80,17 +84,23 @@ impl IPage {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct PageInput<'b, 'parse> {
|
pub(crate) struct PageInput<'b, 'parse> {
|
||||||
|
/// Relative path from the root of the page.
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
|
|
||||||
|
/// The path to the .org source for the file.
|
||||||
|
src: PathBuf,
|
||||||
document: &'b organic::types::Document<'parse>,
|
document: &'b organic::types::Document<'parse>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b, 'parse> PageInput<'b, 'parse> {
|
impl<'b, 'parse> PageInput<'b, 'parse> {
|
||||||
pub(crate) fn new<P: Into<PathBuf>>(
|
pub(crate) fn new<P: Into<PathBuf>, S: Into<PathBuf>>(
|
||||||
path: P,
|
path: P,
|
||||||
|
src: S,
|
||||||
document: &'b organic::types::Document<'parse>,
|
document: &'b organic::types::Document<'parse>,
|
||||||
) -> PageInput<'b, 'parse> {
|
) -> PageInput<'b, 'parse> {
|
||||||
PageInput {
|
PageInput {
|
||||||
path: path.into(),
|
path: path.into(),
|
||||||
|
src: src.into(),
|
||||||
document,
|
document,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
#![feature(async_closure)]
|
|
||||||
use std::process::ExitCode;
|
use std::process::ExitCode;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user