Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 72 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ slug = "0.1.4"
clap = "2.33.3"
atom_syndication = "0.11.0"
chrono = "0.4.19"
url = { version = "2.2.2", features = ["serde"] }

[features]
fail-on-warnings = []
15 changes: 9 additions & 6 deletions src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::config::Config;
use crate::feed::{Error as FeedError, *};
use crate::post::{Error as ParseError, Parser as PostParser};
use crate::write::{Error as WriteError, *};
use crate::url::{Url, UrlBuf};
use gtmpl::Template;
use std::fmt;
use std::fs::File;
Expand All @@ -25,7 +26,8 @@ pub fn build_site(config: Config) -> Result<()> {
);

// collect all posts
let posts = post_parser.parse_posts(&config.posts_source_directory)?;
let (posts, static_files) =
post_parser.parse_posts(&config.posts_source_directory)?;

// Parse the template files.
let index_template = parse_template(config.index_template.iter())?;
Expand All @@ -48,13 +50,14 @@ pub fn build_site(config: Config) -> Result<()> {
posts_template: &posts_template,
index_template: &index_template,
index_page_size: config.index_page_size,
index_base_url: &config.index_url,
index_base_url: Url::from_url(&config.index_url),
index_output_directory: &config.index_output_directory,
home_page: &config.home_page,
static_url: &config.static_url,
atom_url: &config.atom_url,
home_page: Url::from_url(&config.home_page),
static_url: Url::from_url(&config.static_url),
atom_url: Url::from_url(&config.atom_url),
};
writer.write_posts(&posts)?;
writer.write_static_files(&static_files)?;

// copy static directory
copy_dir(
Expand All @@ -74,7 +77,7 @@ pub fn build_site(config: Config) -> Result<()> {
title: config.title,
id: config.home_page.to_string(),
author: config.author,
home_page: config.home_page,
home_page: UrlBuf::from(&config.home_page),
},
&posts,
File::create(config.root_output_directory.join("feed.atom"))?,
Expand Down
40 changes: 26 additions & 14 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
//! Contains the logic for collecting and consolidating the program's
//! configuration.

use crate::url::UrlBuf;
use serde::Deserialize;
use std::fmt;
use std::fs::File;
use std::path::{Path, PathBuf};
use url::Url;

#[derive(Deserialize)]
struct PageSize(usize);
Expand All @@ -28,9 +28,8 @@ pub struct Author {
#[derive(Deserialize)]
struct Profile {
pub name: String,
#[serde(default)]
pub site_root: UrlBuf,
pub home_page: UrlBuf,
pub site_root: Url,
pub home_page: String,
pub author: Option<Author>,
pub title: String,

Expand Down Expand Up @@ -70,13 +69,13 @@ pub struct Config {
/// The fully-qualified URL to the site's home page. This comes from the
/// `futhorc.yaml` project file and is intended to be provided to the
/// index and post templates, e.g., to create a site-header link.
pub home_page: UrlBuf,
pub home_page: Url,

/// The fully-qualified base URL for the index pages. The main index pages
/// will live at `{index_url}/index.html`, `{index_url}/1.html`, etc. The
/// tag index pages will live at `{index_url}/{tag_name}/index.html`,
/// `{index_url}/{tag_name}/1.html`, etc.
pub index_url: UrlBuf,
pub index_url: Url,

/// The paths to index template files which will be concatenated and the
/// result parsed into a [`gtmpl::Template`] object.
Expand All @@ -96,7 +95,7 @@ pub struct Config {
/// The fully-qualified base URL for post pages. E.g., for a post whose
/// source file is located at `{posts_source_directory}/foo/bar.md`, the
/// URL will be `{posts_url}/foo/bar.html`.
pub posts_url: UrlBuf,
pub posts_url: Url,

/// The paths to post template files which will be concatenated and the
/// result parsed into a [`gtmpl::Template`] object.
Expand All @@ -110,7 +109,7 @@ pub struct Config {
/// The fully-qualified base URL for static assets. E.g., a static asset
/// whose source file is located at `{static_source_directory}/style.css`
/// will have the URL, `{static_url}/style.css`.
pub static_url: UrlBuf,
pub static_url: Url,

/// The absolute path to the source directory for static assets.
pub static_source_directory: PathBuf,
Expand All @@ -119,7 +118,7 @@ pub struct Config {
pub static_output_directory: PathBuf,

/// The fully-qualified URL for the atom feed.
pub atom_url: UrlBuf,
pub atom_url: Url,

/// The absolute path to the atom output file.
pub atom_output_path: PathBuf,
Expand Down Expand Up @@ -188,10 +187,10 @@ impl Config {
title: profile.title,
author: profile.author,
root_output_directory: output_directory.to_owned(),
home_page: profile.site_root.join(&profile.home_page),
home_page: profile.site_root.join(&profile.home_page)?,
posts_source_directory: project_root.join("posts"),
index_url: (&profile.site_root).join("pages"),
posts_url: (&profile.site_root).join("posts"),
index_url: (&profile.site_root).join("pages/")?,
posts_url: (&profile.site_root).join("posts/")?,
index_template: theme
.index_template
.iter()
Expand All @@ -204,11 +203,11 @@ impl Config {
.collect(),
index_output_directory: output_directory.join("pages"),
posts_output_directory: output_directory.join("posts"),
static_url: (&profile.site_root).join("static"),
static_url: (&profile.site_root).join("static/")?,
static_source_directory: theme_dir.join("static"),
static_output_directory: output_directory.join("static"),
index_page_size: profile.index_page_size.0,
atom_url: profile.site_root.join("feed.atom"),
atom_url: profile.site_root.join("feed.atom")?,
atom_output_path: output_directory.join("feed.atom"),
})
}
Expand Down Expand Up @@ -243,6 +242,9 @@ pub enum Error {
/// Returned when there is a problem opening the project file.
OpenProjectFile { path: PathBuf, err: std::io::Error },

/// Returned when there is a problem parsing URLs.
UrlParse(url::ParseError),

/// Returned for other I/O errors.
Io(std::io::Error),
}
Expand Down Expand Up @@ -275,6 +277,7 @@ impl fmt::Display for Error {
Error::OpenProjectFile { path, err } => {
write!(f, "Opening project file '{}': {}", path.display(), err)
}
Error::UrlParse(err) => err.fmt(f),
Error::Io(err) => err.fmt(f),
}
}
Expand All @@ -290,11 +293,20 @@ impl std::error::Error for Error {
Error::UnknownProfile(_) => None,
Error::OpenThemeFile { path: _, err } => Some(err),
Error::OpenProjectFile { path: _, err } => Some(err),
Error::UrlParse(err) => Some(err),
Error::Io(err) => Some(err),
}
}
}

impl From<url::ParseError> for Error {
/// Converts [`url::ParseError`] into [`Error`]. This allows us to use
/// the `?` operator on fallible config parsing operations.
fn from(err: url::ParseError) -> Error {
Error::UrlParse(err)
}
}

impl From<serde_yaml::Error> for Error {
/// Converts [`serde_yaml::Error`] into [`Error`]. This allows us to use
/// the `?` operator on fallible config parsing operations.
Expand Down
15 changes: 8 additions & 7 deletions src/htmlrenderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ enum TableState {
/// Renders markdown [`Event`]s into HTML. This is largely modeled after
/// [`pulldown_cmark`]'s private [`HtmlWriter`
/// struct](https://github.com/raphlinus/pulldown-cmark/blob/bf0a1a4938dbd2ec41c3add069b3d361d11731f4/src/html.rs#L36-L50).
struct HtmlRenderer {
pub struct HtmlRenderer {
table_alignments: Vec<Alignment>,
table_state: TableState,
table_cell_index: usize,
Expand All @@ -84,7 +84,7 @@ struct HtmlRenderer {
}

impl<'a> HtmlRenderer {
fn on_event<W: StrWrite>(
pub fn on_event<W: StrWrite>(
&mut self,
w: &mut W,
event: Event<'a>,
Expand Down Expand Up @@ -113,7 +113,7 @@ impl<'a> HtmlRenderer {
}

impl<'a> HtmlRenderer {
fn new() -> Self {
pub fn new() -> Self {
HtmlRenderer {
table_alignments: Vec::default(),
table_state: TableState::Head,
Expand Down Expand Up @@ -304,17 +304,18 @@ impl<'a> HtmlRenderer {
/// Converts [`Event`]s into an HTML string much like
/// `pulldown_cmark::html::push_html` except that this also supports footnote
/// prefixes. See the module description for more details.
pub fn push_html<'a, I>(
pub fn push_html<'a, I, E>(
out: &mut String,
events: I,
footnote_prefix: &str,
) -> io::Result<()>
) -> Result<(), E>
where
I: Iterator<Item = Event<'a>>,
E: From<io::Error>,
I: Iterator<Item = Result<Event<'a>, E>>,
{
let mut renderer = HtmlRenderer::with_footnote_prefix(footnote_prefix);
for event in events {
renderer.on_event(out, event)?;
renderer.on_event(out, event?)?;
}
Ok(())
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub mod build;
pub mod config;
pub mod feed;
pub mod htmlrenderer;
pub mod normalize_url;
pub mod post;
pub mod tag;
pub mod url;
Expand Down
Loading