Compare commits

...

5 Commits

Author SHA1 Message Date
Tom Alexander
2413923b3f
Render the page title and self link. 2023-10-23 23:06:14 -04:00
Tom Alexander
ab36a60545
Generate the minimum relative path by chopping off the shared stem. 2023-10-23 23:04:05 -04:00
Tom Alexander
68cae57f16
Add a function to get the shared portion of a path. 2023-10-23 22:50:43 -04:00
Tom Alexander
11bfb6836f
Include a self-link for the blog. 2023-10-23 22:38:00 -04:00
Tom Alexander
3ac7826d2c
Move the logic into convert_blog_post_page_to_render_context.
I was writing it in the build command's rust files for convenience, but now its getting long enough to warrant moving it into its final location.
2023-10-23 22:10:26 -04:00
6 changed files with 135 additions and 63 deletions

View File

@ -1,5 +1,5 @@
<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}
</div> </div>
</div> </div>

View File

@ -1,12 +1,132 @@
use std::path::Component;
use std::path::Path;
use std::path::PathBuf;
use crate::config::Config;
use crate::error::CustomError;
use super::render_context::GlobalSettings; use super::render_context::GlobalSettings;
use super::render_context::RenderBlogPostPage; use super::render_context::RenderBlogPostPage;
use super::BlogPost; use super::BlogPost;
use super::BlogPostPage; use super::BlogPostPage;
pub(crate) fn convert_blog_post_page_to_render_context( 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, _post: &BlogPost,
page: &BlogPostPage, page: &BlogPostPage,
global_settings: GlobalSettings, ) -> Result<RenderBlogPostPage, CustomError> {
) -> RenderBlogPostPage { let output_directory = output_directory.as_ref();
RenderBlogPostPage::new(global_settings, page.title.clone()) let output_file = output_file.as_ref();
let css_files = vec![get_web_path(
config,
output_directory,
output_file,
"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 link_to_blog_post = get_web_path(
config,
output_directory,
output_file,
output_file.strip_prefix(output_directory)?,
)?;
let ret = RenderBlogPostPage::new(global_settings, page.title.clone(), Some(link_to_blog_post));
Ok(ret)
}
fn get_web_path<D: AsRef<Path>, F: AsRef<Path>, P: AsRef<Path>>(
config: &Config,
output_directory: D,
containing_file: F,
path_from_web_root: P,
) -> Result<String, CustomError> {
let path_from_web_root = path_from_web_root.as_ref();
if config.use_relative_paths() {
let output_directory = output_directory.as_ref();
let containing_file = containing_file.as_ref();
let containing_file_relative_to_output_directory =
containing_file.strip_prefix(output_directory)?;
let shared_stem = get_shared_steps(
containing_file_relative_to_output_directory
.parent()
.ok_or("File should exist in a folder.")?,
path_from_web_root
.parent()
.ok_or("File should exist in a folder.")?,
)
.collect::<PathBuf>();
// Subtracting 1 from the depth to "remove" the file name.
let depth_from_shared_stem = containing_file_relative_to_output_directory
.strip_prefix(&shared_stem)?
.components()
.count()
- 1;
let final_path = PathBuf::from("../".repeat(depth_from_shared_stem))
.join(path_from_web_root.strip_prefix(shared_stem)?);
let final_string = final_path
.as_path()
.to_str()
.map(str::to_string)
.ok_or("Path should be valid utf-8.")?;
Ok(final_string)
} else {
let web_root = config
.get_web_root()
.ok_or("Must either use_relative_paths or set the web_root in the config.")?;
let final_path = PathBuf::from(web_root).join(path_from_web_root);
let final_string = final_path
.as_path()
.to_str()
.map(str::to_string)
.ok_or("Path should be valid utf-8.")?;
Ok(final_string)
}
}
fn get_shared_steps<'a>(left: &'a Path, right: &'a Path) -> impl Iterator<Item = Component<'a>> {
let shared_stem = left
.components()
.zip(right.components())
.take_while(|(l, r)| l == r)
.map(|(l, _r)| l);
shared_stem
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_shared_steps() {
assert_eq!(
get_shared_steps(Path::new(""), Path::new("")).collect::<PathBuf>(),
PathBuf::from("")
);
assert_eq!(
get_shared_steps(Path::new("foo.txt"), Path::new("foo.txt")).collect::<PathBuf>(),
PathBuf::from("foo.txt")
);
assert_eq!(
get_shared_steps(Path::new("cat/foo.txt"), Path::new("dog/foo.txt"))
.collect::<PathBuf>(),
PathBuf::from("")
);
assert_eq!(
get_shared_steps(
Path::new("foo/bar/baz/lorem.txt"),
Path::new("foo/bar/ipsum/dolar.txt")
)
.collect::<PathBuf>(),
PathBuf::from("foo/bar")
);
}
} }

View File

@ -19,7 +19,7 @@ impl BlogPost {
root_dir: R, root_dir: R,
post_dir: P, post_dir: P,
) -> Result<BlogPost, CustomError> { ) -> Result<BlogPost, CustomError> {
async fn inner(root_dir: &Path, post_dir: &Path) -> Result<BlogPost, CustomError> { async fn inner(_root_dir: &Path, post_dir: &Path) -> Result<BlogPost, CustomError> {
let post_id = post_dir let post_id = post_dir
.file_name() .file_name()
.expect("The post directory should have a name."); .expect("The post directory should have a name.");

View File

@ -5,4 +5,3 @@ mod render_context;
pub(crate) use convert::convert_blog_post_page_to_render_context; pub(crate) use convert::convert_blog_post_page_to_render_context;
pub(crate) use definition::BlogPost; pub(crate) use definition::BlogPost;
pub(crate) use page::BlogPostPage; pub(crate) use page::BlogPostPage;
pub(crate) use render_context::GlobalSettings;

View File

@ -31,16 +31,20 @@ pub(crate) struct RenderBlogPostPage {
/// The title that will be shown visibly on the page. /// The title that will be shown visibly on the page.
title: Option<String>, title: Option<String>,
self_link: Option<String>,
} }
impl RenderBlogPostPage { impl RenderBlogPostPage {
pub(crate) fn new( pub(crate) fn new(
global_settings: GlobalSettings, global_settings: GlobalSettings,
title: Option<String>, title: Option<String>,
self_link: Option<String>,
) -> RenderBlogPostPage { ) -> RenderBlogPostPage {
RenderBlogPostPage { RenderBlogPostPage {
global_settings, global_settings,
title, title,
self_link,
} }
} }
} }

View File

@ -1,5 +1,4 @@
use std::ffi::OsStr; use std::ffi::OsStr;
use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use include_dir::include_dir; use include_dir::include_dir;
@ -7,7 +6,6 @@ use include_dir::Dir;
use crate::blog_post::convert_blog_post_page_to_render_context; use crate::blog_post::convert_blog_post_page_to_render_context;
use crate::blog_post::BlogPost; use crate::blog_post::BlogPost;
use crate::blog_post::GlobalSettings;
use crate::config::Config; use crate::config::Config;
use crate::error::CustomError; use crate::error::CustomError;
use crate::render::DusterRenderer; use crate::render::DusterRenderer;
@ -65,25 +63,14 @@ impl SiteRenderer {
.join("posts") .join("posts")
.join(&blog_post.id) .join(&blog_post.id)
.join(blog_post_page.get_output_path()); .join(blog_post_page.get_output_path());
let css_files = vec![get_web_path(
config,
&self.output_directory,
&output_path,
"main.css",
)?];
let js_files = vec![get_web_path(
config,
&self.output_directory,
&output_path,
"blog_post.js",
)?];
let global_settings =
GlobalSettings::new(blog_post_page.title.clone(), css_files, js_files);
let render_context = convert_blog_post_page_to_render_context( let render_context = convert_blog_post_page_to_render_context(
config,
&self.output_directory,
&output_path,
blog_post, blog_post,
blog_post_page, blog_post_page,
global_settings, )?;
);
let rendered_output = renderer_integration.render(render_context)?; let rendered_output = renderer_integration.render(render_context)?;
println!("Rendered: {}", rendered_output); println!("Rendered: {}", rendered_output);
let parent_directory = output_path let parent_directory = output_path
@ -110,41 +97,3 @@ fn build_name_contents_pairs<'a>(
let contents = std::str::from_utf8(entry.contents())?; let contents = std::str::from_utf8(entry.contents())?;
Ok((name, contents)) Ok((name, contents))
} }
fn get_web_path<D: AsRef<Path>, F: AsRef<Path>, P: AsRef<Path>>(
config: &Config,
output_directory: D,
containing_file: F,
path_from_web_root: P,
) -> Result<String, CustomError> {
let path_from_web_root = path_from_web_root.as_ref();
if config.use_relative_paths() {
let output_directory = output_directory.as_ref();
let containing_file = containing_file.as_ref();
// Subtracting 1 from the depth to "remove" the file name.
let depth_from_web_root = containing_file
.strip_prefix(output_directory)?
.components()
.count()
- 1;
let prefix = "../".repeat(depth_from_web_root);
let final_path = PathBuf::from(prefix).join(path_from_web_root);
let final_string = final_path
.as_path()
.to_str()
.map(str::to_string)
.ok_or("Path should be valid utf-8.")?;
Ok(final_string)
} else {
let web_root = config
.get_web_root()
.ok_or("Must either use_relative_paths or set the web_root in the config.")?;
let final_path = PathBuf::from(web_root).join(path_from_web_root);
let final_string = final_path
.as_path()
.to_str()
.map(str::to_string)
.ok_or("Path should be valid utf-8.")?;
Ok(final_string)
}
}