parent
a42e6dfec4
commit
9bc675f2a7
13
Cargo.lock
generated
13
Cargo.lock
generated
@ -229,9 +229,10 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bincode"
|
name = "bincode"
|
||||||
version = "1.0.1"
|
version = "1.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@ -1372,7 +1373,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "notify"
|
name = "notify"
|
||||||
version = "4.0.8"
|
version = "4.0.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -2260,7 +2261,7 @@ name = "syntect"
|
|||||||
version = "3.0.2"
|
version = "3.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bincode 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -3040,7 +3041,7 @@ dependencies = [
|
|||||||
"errors 0.1.0",
|
"errors 0.1.0",
|
||||||
"front_matter 0.1.0",
|
"front_matter 0.1.0",
|
||||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"notify 4.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"notify 4.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rebuild 0.1.0",
|
"rebuild 0.1.0",
|
||||||
"site 0.1.0",
|
"site 0.1.0",
|
||||||
"termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -3069,7 +3070,7 @@ dependencies = [
|
|||||||
"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
|
"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
|
||||||
"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
|
"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
|
||||||
"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
|
"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
|
||||||
"checksum bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f2fb9e29e72fd6bc12071533d5dc7664cb01480c59406f656d7ac25c7bd8ff7"
|
"checksum bincode 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "58470ad6460f0b0e89b0df5f17b8bd77ebae26af69dca0bd9ddc8b9e38abb2ff"
|
||||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
||||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||||
"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab"
|
"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab"
|
||||||
@ -3191,7 +3192,7 @@ dependencies = [
|
|||||||
"checksum nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d37e713a259ff641624b6cb20e3b12b2952313ba36b6823c0f16e6cfd9e5de17"
|
"checksum nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d37e713a259ff641624b6cb20e3b12b2952313ba36b6823c0f16e6cfd9e5de17"
|
||||||
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
|
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
|
||||||
"checksum nom 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b30adc557058ce00c9d0d7cb3c6e0b5bc6f36e2e2eabe74b0ba726d194abd588"
|
"checksum nom 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b30adc557058ce00c9d0d7cb3c6e0b5bc6f36e2e2eabe74b0ba726d194abd588"
|
||||||
"checksum notify 4.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c9b605e417814e88bb051c88a84f83655d6ad4fa32fc36d9a96296d86087692d"
|
"checksum notify 4.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9cc7ed2bd4b7edad3ee93b659c38e53dabb619f7274e127a0fab054ad2bb998d"
|
||||||
"checksum num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d9fe8fcafd1b86a37ce8a1cfa15ae504817e0c8c2e7ad42767371461ac1d316d"
|
"checksum num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d9fe8fcafd1b86a37ce8a1cfa15ae504817e0c8c2e7ad42767371461ac1d316d"
|
||||||
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
|
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
|
||||||
"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
|
"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
|
||||||
|
@ -32,10 +32,8 @@ impl StdError for Error {
|
|||||||
let mut source = self.source.as_ref().map(|c| &**c);
|
let mut source = self.source.as_ref().map(|c| &**c);
|
||||||
if source.is_none() {
|
if source.is_none() {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
ErrorKind::Tera(ref err) => {
|
ErrorKind::Tera(ref err) => source = err.source(),
|
||||||
source = err.source()
|
_ => (),
|
||||||
},
|
|
||||||
_ => ()
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +66,6 @@ impl Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl From<&str> for Error {
|
impl From<&str> for Error {
|
||||||
fn from(e: &str) -> Self {
|
fn from(e: &str) -> Self {
|
||||||
Self::msg(e)
|
Self::msg(e)
|
||||||
|
@ -12,7 +12,7 @@ extern crate toml;
|
|||||||
extern crate errors;
|
extern crate errors;
|
||||||
extern crate utils;
|
extern crate utils;
|
||||||
|
|
||||||
use errors::{Result, Error};
|
use errors::{Error, Result};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
@ -72,7 +72,10 @@ pub fn split_section_content(
|
|||||||
) -> Result<(SectionFrontMatter, String)> {
|
) -> Result<(SectionFrontMatter, String)> {
|
||||||
let (front_matter, content) = split_content(file_path, content)?;
|
let (front_matter, content) = split_content(file_path, content)?;
|
||||||
let meta = SectionFrontMatter::parse(&front_matter).map_err(|e| {
|
let meta = SectionFrontMatter::parse(&front_matter).map_err(|e| {
|
||||||
Error::chain(format!("Error when parsing front matter of section `{}`", file_path.to_string_lossy()), e)
|
Error::chain(
|
||||||
|
format!("Error when parsing front matter of section `{}`", file_path.to_string_lossy()),
|
||||||
|
e,
|
||||||
|
)
|
||||||
})?;
|
})?;
|
||||||
Ok((meta, content))
|
Ok((meta, content))
|
||||||
}
|
}
|
||||||
@ -82,7 +85,10 @@ pub fn split_section_content(
|
|||||||
pub fn split_page_content(file_path: &Path, content: &str) -> Result<(PageFrontMatter, String)> {
|
pub fn split_page_content(file_path: &Path, content: &str) -> Result<(PageFrontMatter, String)> {
|
||||||
let (front_matter, content) = split_content(file_path, content)?;
|
let (front_matter, content) = split_content(file_path, content)?;
|
||||||
let meta = PageFrontMatter::parse(&front_matter).map_err(|e| {
|
let meta = PageFrontMatter::parse(&front_matter).map_err(|e| {
|
||||||
Error::chain(format!("Error when parsing front matter of page `{}`", file_path.to_string_lossy()), e)
|
Error::chain(
|
||||||
|
format!("Error when parsing front matter of page `{}`", file_path.to_string_lossy()),
|
||||||
|
e,
|
||||||
|
)
|
||||||
})?;
|
})?;
|
||||||
Ok((meta, content))
|
Ok((meta, content))
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ use image::{FilterType, GenericImageView};
|
|||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
use errors::{Result, Error};
|
use errors::{Error, Result};
|
||||||
use utils::fs as ufs;
|
use utils::fs as ufs;
|
||||||
|
|
||||||
static RESIZED_SUBDIR: &'static str = "processed_images";
|
static RESIZED_SUBDIR: &'static str = "processed_images";
|
||||||
|
@ -8,7 +8,7 @@ use slug::slugify;
|
|||||||
use tera::{Context as TeraContext, Tera};
|
use tera::{Context as TeraContext, Tera};
|
||||||
|
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use errors::{Result, Error};
|
use errors::{Error, Result};
|
||||||
use front_matter::{split_page_content, InsertAnchor, PageFrontMatter};
|
use front_matter::{split_page_content, InsertAnchor, PageFrontMatter};
|
||||||
use library::Library;
|
use library::Library;
|
||||||
use rendering::{render_content, Header, RenderContext};
|
use rendering::{render_content, Header, RenderContext};
|
||||||
@ -126,7 +126,16 @@ impl Page {
|
|||||||
page.reading_time = Some(reading_time);
|
page.reading_time = Some(reading_time);
|
||||||
|
|
||||||
let mut slug_from_dated_filename = None;
|
let mut slug_from_dated_filename = None;
|
||||||
if let Some(ref caps) = RFC3339_DATE.captures(&page.file.name.replace(".md", "")) {
|
let file_path = if page.file.name == "index" {
|
||||||
|
if let Some(parent) = page.file.path.parent() {
|
||||||
|
parent.file_name().unwrap().to_str().unwrap().to_string()
|
||||||
|
} else {
|
||||||
|
page.file.name.replace(".md", "")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
page.file.name.replace(".md", "")
|
||||||
|
};
|
||||||
|
if let Some(ref caps) = RFC3339_DATE.captures(&file_path) {
|
||||||
slug_from_dated_filename = Some(caps.name("slug").unwrap().as_str().to_string());
|
slug_from_dated_filename = Some(caps.name("slug").unwrap().as_str().to_string());
|
||||||
if page.meta.date.is_none() {
|
if page.meta.date.is_none() {
|
||||||
page.meta.date = Some(caps.name("datetime").unwrap().as_str().to_string());
|
page.meta.date = Some(caps.name("datetime").unwrap().as_str().to_string());
|
||||||
@ -139,7 +148,11 @@ impl Page {
|
|||||||
slug.trim().to_string()
|
slug.trim().to_string()
|
||||||
} else if page.file.name == "index" {
|
} else if page.file.name == "index" {
|
||||||
if let Some(parent) = page.file.path.parent() {
|
if let Some(parent) = page.file.path.parent() {
|
||||||
slugify(parent.file_name().unwrap().to_str().unwrap())
|
if let Some(slug) = slug_from_dated_filename {
|
||||||
|
slugify(&slug)
|
||||||
|
} else {
|
||||||
|
slugify(parent.file_name().unwrap().to_str().unwrap())
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
slugify(&page.file.name)
|
slugify(&page.file.name)
|
||||||
}
|
}
|
||||||
@ -233,8 +246,9 @@ impl Page {
|
|||||||
|
|
||||||
context.tera_context.insert("page", &SerializingPage::from_page_basic(self, None));
|
context.tera_context.insert("page", &SerializingPage::from_page_basic(self, None));
|
||||||
|
|
||||||
let res = render_content(&self.raw_content, &context)
|
let res = render_content(&self.raw_content, &context).map_err(|e| {
|
||||||
.map_err(|e| Error::chain(format!("Failed to render content of {}", self.file.path.display()), e))?;
|
Error::chain(format!("Failed to render content of {}", self.file.path.display()), e)
|
||||||
|
})?;
|
||||||
|
|
||||||
self.summary = res.summary_len.map(|l| res.body[0..l].to_owned());
|
self.summary = res.summary_len.map(|l| res.body[0..l].to_owned());
|
||||||
self.content = res.body;
|
self.content = res.body;
|
||||||
@ -257,8 +271,9 @@ impl Page {
|
|||||||
context.insert("page", &self.to_serialized(library));
|
context.insert("page", &self.to_serialized(library));
|
||||||
context.insert("lang", &self.lang);
|
context.insert("lang", &self.lang);
|
||||||
|
|
||||||
render_template(&tpl_name, tera, context, &config.theme)
|
render_template(&tpl_name, tera, context, &config.theme).map_err(|e| {
|
||||||
.map_err(|e| Error::chain(format!("Failed to render page '{}'", self.file.path.display()), e))
|
Error::chain(format!("Failed to render page '{}'", self.file.path.display()), e)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a vectors of asset URLs.
|
/// Creates a vectors of asset URLs.
|
||||||
@ -499,6 +514,31 @@ Hello world
|
|||||||
assert_eq!(page.permalink, "http://a-website.com/posts/hey/");
|
assert_eq!(page.permalink, "http://a-website.com/posts/hey/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/getzola/zola/issues/607
|
||||||
|
#[test]
|
||||||
|
fn page_with_assets_and_date_in_folder_name() {
|
||||||
|
let tmp_dir = tempdir().expect("create temp dir");
|
||||||
|
let path = tmp_dir.path();
|
||||||
|
create_dir(&path.join("content")).expect("create content temp dir");
|
||||||
|
create_dir(&path.join("content").join("posts")).expect("create posts temp dir");
|
||||||
|
let nested_path = path.join("content").join("posts").join("2013-06-02_with-assets");
|
||||||
|
create_dir(&nested_path).expect("create nested temp dir");
|
||||||
|
let mut f = File::create(nested_path.join("index.md")).unwrap();
|
||||||
|
f.write_all(b"+++\n\n+++\n").unwrap();
|
||||||
|
File::create(nested_path.join("example.js")).unwrap();
|
||||||
|
File::create(nested_path.join("graph.jpg")).unwrap();
|
||||||
|
File::create(nested_path.join("fail.png")).unwrap();
|
||||||
|
|
||||||
|
let res = Page::from_file(nested_path.join("index.md").as_path(), &Config::default());
|
||||||
|
assert!(res.is_ok());
|
||||||
|
let page = res.unwrap();
|
||||||
|
assert_eq!(page.file.parent, path.join("content").join("posts"));
|
||||||
|
assert_eq!(page.slug, "with-assets");
|
||||||
|
assert_eq!(page.meta.date, Some("2013-06-02".to_string()));
|
||||||
|
assert_eq!(page.assets.len(), 3);
|
||||||
|
assert_eq!(page.permalink, "http://a-website.com/posts/with-assets/");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn page_with_ignored_assets_filters_out_correct_files() {
|
fn page_with_ignored_assets_filters_out_correct_files() {
|
||||||
let tmp_dir = tempdir().expect("create temp dir");
|
let tmp_dir = tempdir().expect("create temp dir");
|
||||||
|
@ -5,7 +5,7 @@ use slotmap::Key;
|
|||||||
use tera::{Context as TeraContext, Tera};
|
use tera::{Context as TeraContext, Tera};
|
||||||
|
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use errors::{Result, Error};
|
use errors::{Error, Result};
|
||||||
use front_matter::{split_section_content, SectionFrontMatter};
|
use front_matter::{split_section_content, SectionFrontMatter};
|
||||||
use rendering::{render_content, Header, RenderContext};
|
use rendering::{render_content, Header, RenderContext};
|
||||||
use utils::fs::{find_related_assets, read_file};
|
use utils::fs::{find_related_assets, read_file};
|
||||||
@ -171,8 +171,9 @@ impl Section {
|
|||||||
|
|
||||||
context.tera_context.insert("section", &SerializingSection::from_section_basic(self, None));
|
context.tera_context.insert("section", &SerializingSection::from_section_basic(self, None));
|
||||||
|
|
||||||
let res = render_content(&self.raw_content, &context)
|
let res = render_content(&self.raw_content, &context).map_err(|e| {
|
||||||
.map_err(|e| Error::chain(format!("Failed to render content of {}", self.file.path.display()), e))?;
|
Error::chain(format!("Failed to render content of {}", self.file.path.display()), e)
|
||||||
|
})?;
|
||||||
self.content = res.body;
|
self.content = res.body;
|
||||||
self.toc = res.toc;
|
self.toc = res.toc;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -189,8 +190,9 @@ impl Section {
|
|||||||
context.insert("section", &self.to_serialized(library));
|
context.insert("section", &self.to_serialized(library));
|
||||||
context.insert("lang", &self.lang);
|
context.insert("lang", &self.lang);
|
||||||
|
|
||||||
render_template(tpl_name, tera, context, &config.theme)
|
render_template(tpl_name, tera, context, &config.theme).map_err(|e| {
|
||||||
.map_err(|e| Error::chain(format!("Failed to render section '{}'", self.file.path.display()), e))
|
Error::chain(format!("Failed to render section '{}'", self.file.path.display()), e)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is this the index section?
|
/// Is this the index section?
|
||||||
|
@ -5,9 +5,9 @@ use slotmap::{DenseSlotMap, Key};
|
|||||||
|
|
||||||
use front_matter::SortBy;
|
use front_matter::SortBy;
|
||||||
|
|
||||||
|
use config::Config;
|
||||||
use content::{Page, Section};
|
use content::{Page, Section};
|
||||||
use sorting::{find_siblings, sort_pages_by_date, sort_pages_by_weight};
|
use sorting::{find_siblings, sort_pages_by_date, sort_pages_by_weight};
|
||||||
use config::Config;
|
|
||||||
|
|
||||||
/// Houses everything about pages and sections
|
/// Houses everything about pages and sections
|
||||||
/// Think of it as a database where each page and section has an id (Key here)
|
/// Think of it as a database where each page and section has an id (Key here)
|
||||||
|
@ -4,7 +4,7 @@ use slotmap::Key;
|
|||||||
use tera::{to_value, Context, Tera, Value};
|
use tera::{to_value, Context, Tera, Value};
|
||||||
|
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use errors::{Result, Error};
|
use errors::{Error, Result};
|
||||||
use utils::templates::render_template;
|
use utils::templates::render_template;
|
||||||
|
|
||||||
use content::{Section, SerializingPage, SerializingSection};
|
use content::{Section, SerializingPage, SerializingSection};
|
||||||
|
@ -5,7 +5,7 @@ use slug::slugify;
|
|||||||
use tera::{Context, Tera};
|
use tera::{Context, Tera};
|
||||||
|
|
||||||
use config::{Config, Taxonomy as TaxonomyConfig};
|
use config::{Config, Taxonomy as TaxonomyConfig};
|
||||||
use errors::{Result, Error};
|
use errors::{Error, Result};
|
||||||
use utils::templates::render_template;
|
use utils::templates::render_template;
|
||||||
|
|
||||||
use content::SerializingPage;
|
use content::SerializingPage;
|
||||||
@ -48,7 +48,13 @@ pub struct TaxonomyItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TaxonomyItem {
|
impl TaxonomyItem {
|
||||||
pub fn new(name: &str, taxonomy: &TaxonomyConfig, config: &Config, keys: Vec<Key>, library: &Library) -> Self {
|
pub fn new(
|
||||||
|
name: &str,
|
||||||
|
taxonomy: &TaxonomyConfig,
|
||||||
|
config: &Config,
|
||||||
|
keys: Vec<Key>,
|
||||||
|
library: &Library,
|
||||||
|
) -> Self {
|
||||||
// Taxonomy are almost always used for blogs so we filter by dates
|
// Taxonomy are almost always used for blogs so we filter by dates
|
||||||
// and it's not like we can sort things across sections by anything other
|
// and it's not like we can sort things across sections by anything other
|
||||||
// than dates
|
// than dates
|
||||||
@ -145,7 +151,9 @@ impl Taxonomy {
|
|||||||
context.insert("current_path", &format!("/{}/{}", self.kind.name, item.slug));
|
context.insert("current_path", &format!("/{}/{}", self.kind.name, item.slug));
|
||||||
|
|
||||||
render_template(&format!("{}/single.html", self.kind.name), tera, context, &config.theme)
|
render_template(&format!("{}/single.html", self.kind.name), tera, context, &config.theme)
|
||||||
.map_err(|e| Error::chain(format!("Failed to render single term {} page.", self.kind.name), e))
|
.map_err(|e| {
|
||||||
|
Error::chain(format!("Failed to render single term {} page.", self.kind.name), e)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_all_terms(
|
pub fn render_all_terms(
|
||||||
@ -164,7 +172,9 @@ impl Taxonomy {
|
|||||||
context.insert("current_path", &self.kind.name);
|
context.insert("current_path", &self.kind.name);
|
||||||
|
|
||||||
render_template(&format!("{}/list.html", self.kind.name), tera, context, &config.theme)
|
render_template(&format!("{}/list.html", self.kind.name), tera, context, &config.theme)
|
||||||
.map_err(|e| Error::chain(format!("Failed to render a list of {} page.", self.kind.name), e))
|
.map_err(|e| {
|
||||||
|
Error::chain(format!("Failed to render a list of {} page.", self.kind.name), e)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_serialized<'a>(&'a self, library: &'a Library) -> SerializedTaxonomy<'a> {
|
pub fn to_serialized<'a>(&'a self, library: &'a Library) -> SerializedTaxonomy<'a> {
|
||||||
@ -232,7 +242,7 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use config::{Config, Taxonomy as TaxonomyConfig, Language};
|
use config::{Config, Language, Taxonomy as TaxonomyConfig};
|
||||||
use content::Page;
|
use content::Page;
|
||||||
use library::Library;
|
use library::Library;
|
||||||
|
|
||||||
@ -242,9 +252,21 @@ mod tests {
|
|||||||
let mut library = Library::new(2, 0, false);
|
let mut library = Library::new(2, 0, false);
|
||||||
|
|
||||||
config.taxonomies = vec![
|
config.taxonomies = vec![
|
||||||
TaxonomyConfig { name: "categories".to_string(), lang: config.default_language.clone(), ..TaxonomyConfig::default() },
|
TaxonomyConfig {
|
||||||
TaxonomyConfig { name: "tags".to_string(), lang: config.default_language.clone(), ..TaxonomyConfig::default() },
|
name: "categories".to_string(),
|
||||||
TaxonomyConfig { name: "authors".to_string(), lang: config.default_language.clone(), ..TaxonomyConfig::default() },
|
lang: config.default_language.clone(),
|
||||||
|
..TaxonomyConfig::default()
|
||||||
|
},
|
||||||
|
TaxonomyConfig {
|
||||||
|
name: "tags".to_string(),
|
||||||
|
lang: config.default_language.clone(),
|
||||||
|
..TaxonomyConfig::default()
|
||||||
|
},
|
||||||
|
TaxonomyConfig {
|
||||||
|
name: "authors".to_string(),
|
||||||
|
lang: config.default_language.clone(),
|
||||||
|
..TaxonomyConfig::default()
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut page1 = Page::default();
|
let mut page1 = Page::default();
|
||||||
@ -324,8 +346,11 @@ mod tests {
|
|||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
let mut library = Library::new(2, 0, false);
|
let mut library = Library::new(2, 0, false);
|
||||||
|
|
||||||
config.taxonomies =
|
config.taxonomies = vec![TaxonomyConfig {
|
||||||
vec![TaxonomyConfig { name: "authors".to_string(), lang: config.default_language.clone(), ..TaxonomyConfig::default() }];
|
name: "authors".to_string(),
|
||||||
|
lang: config.default_language.clone(),
|
||||||
|
..TaxonomyConfig::default()
|
||||||
|
}];
|
||||||
let mut page1 = Page::default();
|
let mut page1 = Page::default();
|
||||||
let mut taxo_page1 = HashMap::new();
|
let mut taxo_page1 = HashMap::new();
|
||||||
taxo_page1.insert("tags".to_string(), vec!["rust".to_string(), "db".to_string()]);
|
taxo_page1.insert("tags".to_string(), vec!["rust".to_string(), "db".to_string()]);
|
||||||
@ -346,13 +371,25 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn can_make_taxonomies_in_multiple_languages() {
|
fn can_make_taxonomies_in_multiple_languages() {
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.languages.push(Language {rss: false, code: "fr".to_string()});
|
config.languages.push(Language { rss: false, code: "fr".to_string() });
|
||||||
let mut library = Library::new(2, 0, true);
|
let mut library = Library::new(2, 0, true);
|
||||||
|
|
||||||
config.taxonomies = vec![
|
config.taxonomies = vec![
|
||||||
TaxonomyConfig { name: "categories".to_string(), lang: config.default_language.clone(), ..TaxonomyConfig::default() },
|
TaxonomyConfig {
|
||||||
TaxonomyConfig { name: "tags".to_string(), lang: config.default_language.clone(), ..TaxonomyConfig::default() },
|
name: "categories".to_string(),
|
||||||
TaxonomyConfig { name: "auteurs".to_string(), lang: "fr".to_string(), ..TaxonomyConfig::default() },
|
lang: config.default_language.clone(),
|
||||||
|
..TaxonomyConfig::default()
|
||||||
|
},
|
||||||
|
TaxonomyConfig {
|
||||||
|
name: "tags".to_string(),
|
||||||
|
lang: config.default_language.clone(),
|
||||||
|
..TaxonomyConfig::default()
|
||||||
|
},
|
||||||
|
TaxonomyConfig {
|
||||||
|
name: "auteurs".to_string(),
|
||||||
|
lang: "fr".to_string(),
|
||||||
|
..TaxonomyConfig::default()
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut page1 = Page::default();
|
let mut page1 = Page::default();
|
||||||
@ -410,7 +447,10 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(authors.items[0].name, "Vincent Prouillet");
|
assert_eq!(authors.items[0].name, "Vincent Prouillet");
|
||||||
assert_eq!(authors.items[0].slug, "vincent-prouillet");
|
assert_eq!(authors.items[0].slug, "vincent-prouillet");
|
||||||
assert_eq!(authors.items[0].permalink, "http://a-website.com/fr/auteurs/vincent-prouillet/");
|
assert_eq!(
|
||||||
|
authors.items[0].permalink,
|
||||||
|
"http://a-website.com/fr/auteurs/vincent-prouillet/"
|
||||||
|
);
|
||||||
assert_eq!(authors.items[0].pages.len(), 1);
|
assert_eq!(authors.items[0].pages.len(), 1);
|
||||||
|
|
||||||
assert_eq!(categories.items[0].name, "Other");
|
assert_eq!(categories.items[0].name, "Other");
|
||||||
@ -430,7 +470,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn errors_on_taxonomy_of_different_language() {
|
fn errors_on_taxonomy_of_different_language() {
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.languages.push(Language {rss: false, code: "fr".to_string()});
|
config.languages.push(Language { rss: false, code: "fr".to_string() });
|
||||||
let mut library = Library::new(2, 0, false);
|
let mut library = Library::new(2, 0, false);
|
||||||
|
|
||||||
config.taxonomies =
|
config.taxonomies =
|
||||||
|
@ -155,12 +155,14 @@ fn handle_section_editing(site: &mut Site, path: &Path) -> Result<()> {
|
|||||||
SectionChangesNeeded::Sort => {
|
SectionChangesNeeded::Sort => {
|
||||||
site.register_tera_global_fns();
|
site.register_tera_global_fns();
|
||||||
}
|
}
|
||||||
SectionChangesNeeded::Render => {
|
SectionChangesNeeded::Render => site.render_section(
|
||||||
site.render_section(&site.library.read().unwrap().get_section(&pathbuf).unwrap(), false)?
|
&site.library.read().unwrap().get_section(&pathbuf).unwrap(),
|
||||||
}
|
false,
|
||||||
SectionChangesNeeded::RenderWithPages => {
|
)?,
|
||||||
site.render_section(&site.library.read().unwrap().get_section(&pathbuf).unwrap(), true)?
|
SectionChangesNeeded::RenderWithPages => site.render_section(
|
||||||
}
|
&site.library.read().unwrap().get_section(&pathbuf).unwrap(),
|
||||||
|
true,
|
||||||
|
)?,
|
||||||
// not a common enough operation to make it worth optimizing
|
// not a common enough operation to make it worth optimizing
|
||||||
SectionChangesNeeded::Delete | SectionChangesNeeded::Transparent => {
|
SectionChangesNeeded::Delete | SectionChangesNeeded::Transparent => {
|
||||||
site.build()?;
|
site.build()?;
|
||||||
@ -182,7 +184,7 @@ macro_rules! render_parent_sections {
|
|||||||
($site: expr, $path: expr) => {
|
($site: expr, $path: expr) => {
|
||||||
for s in $site.library.read().unwrap().find_parent_sections($path) {
|
for s in $site.library.read().unwrap().find_parent_sections($path) {
|
||||||
$site.render_section(s, false)?;
|
$site.render_section(s, false)?;
|
||||||
};
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,7 +232,9 @@ fn handle_page_editing(site: &mut Site, path: &Path) -> Result<()> {
|
|||||||
}
|
}
|
||||||
PageChangesNeeded::Render => {
|
PageChangesNeeded::Render => {
|
||||||
render_parent_sections!(site, path);
|
render_parent_sections!(site, path);
|
||||||
site.render_page(&site.library.read().unwrap().get_page(&path.to_path_buf()).unwrap())?;
|
site.render_page(
|
||||||
|
&site.library.read().unwrap().get_page(&path.to_path_buf()).unwrap(),
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use pulldown_cmark as cmark;
|
|||||||
use slug::slugify;
|
use slug::slugify;
|
||||||
use syntect::easy::HighlightLines;
|
use syntect::easy::HighlightLines;
|
||||||
use syntect::html::{
|
use syntect::html::{
|
||||||
IncludeBackground, start_highlighted_html_snippet, styled_line_to_highlighted_html,
|
start_highlighted_html_snippet, styled_line_to_highlighted_html, IncludeBackground,
|
||||||
};
|
};
|
||||||
|
|
||||||
use config::highlighting::{get_highlighter, SYNTAX_SET, THEME_SET};
|
use config::highlighting::{get_highlighter, SYNTAX_SET, THEME_SET};
|
||||||
@ -12,13 +12,14 @@ use context::RenderContext;
|
|||||||
use errors::{Error, Result};
|
use errors::{Error, Result};
|
||||||
use front_matter::InsertAnchor;
|
use front_matter::InsertAnchor;
|
||||||
use link_checker::check_url;
|
use link_checker::check_url;
|
||||||
use table_of_contents::{Header, make_table_of_contents};
|
use table_of_contents::{make_table_of_contents, Header};
|
||||||
use utils::site::resolve_internal_link;
|
use utils::site::resolve_internal_link;
|
||||||
use utils::vec::InsertMany;
|
use utils::vec::InsertMany;
|
||||||
|
|
||||||
use self::cmark::{Event, Options, Parser, Tag};
|
use self::cmark::{Event, Options, Parser, Tag};
|
||||||
|
|
||||||
const CONTINUE_READING: &str = "<p id=\"zola-continue-reading\"><a name=\"continue-reading\"></a></p>\n";
|
const CONTINUE_READING: &str =
|
||||||
|
"<p id=\"zola-continue-reading\"><a name=\"continue-reading\"></a></p>\n";
|
||||||
const ANCHOR_LINK_TEMPLATE: &str = "anchor-link.html";
|
const ANCHOR_LINK_TEMPLATE: &str = "anchor-link.html";
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -88,9 +89,7 @@ fn fix_link(link: &str, context: &RenderContext) -> Result<String> {
|
|||||||
if res.is_valid() {
|
if res.is_valid() {
|
||||||
link.to_string()
|
link.to_string()
|
||||||
} else {
|
} else {
|
||||||
return Err(
|
return Err(format!("Link {} is not valid: {}", link, res.message()).into());
|
||||||
format!("Link {} is not valid: {}", link, res.message()).into(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
link.to_string()
|
link.to_string()
|
||||||
@ -148,78 +147,84 @@ pub fn markdown_to_html(content: &str, context: &RenderContext) -> Result<Render
|
|||||||
opts.insert(Options::ENABLE_FOOTNOTES);
|
opts.insert(Options::ENABLE_FOOTNOTES);
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut events = Parser::new_ext(content, opts).map(|event| {
|
let mut events = Parser::new_ext(content, opts)
|
||||||
match event {
|
.map(|event| {
|
||||||
Event::Text(text) => {
|
match event {
|
||||||
// if we are in the middle of a code block
|
Event::Text(text) => {
|
||||||
if let Some((ref mut highlighter, in_extra)) = highlighter {
|
// if we are in the middle of a code block
|
||||||
let highlighted = if in_extra {
|
if let Some((ref mut highlighter, in_extra)) = highlighter {
|
||||||
if let Some(ref extra) = context.config.extra_syntax_set {
|
let highlighted = if in_extra {
|
||||||
highlighter.highlight(&text, &extra)
|
if let Some(ref extra) = context.config.extra_syntax_set {
|
||||||
|
highlighter.highlight(&text, &extra)
|
||||||
|
} else {
|
||||||
|
unreachable!(
|
||||||
|
"Got a highlighter from extra syntaxes but no extra?"
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
unreachable!("Got a highlighter from extra syntaxes but no extra?");
|
highlighter.highlight(&text, &SYNTAX_SET)
|
||||||
}
|
};
|
||||||
} else {
|
//let highlighted = &highlighter.highlight(&text, ss);
|
||||||
highlighter.highlight(&text, &SYNTAX_SET)
|
let html = styled_line_to_highlighted_html(&highlighted, background);
|
||||||
};
|
return Event::Html(Owned(html));
|
||||||
//let highlighted = &highlighter.highlight(&text, ss);
|
|
||||||
let html = styled_line_to_highlighted_html(&highlighted, background);
|
|
||||||
return Event::Html(Owned(html));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Business as usual
|
|
||||||
Event::Text(text)
|
|
||||||
}
|
|
||||||
Event::Start(Tag::CodeBlock(ref info)) => {
|
|
||||||
if !context.config.highlight_code {
|
|
||||||
return Event::Html(Borrowed("<pre><code>"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let theme = &THEME_SET.themes[&context.config.highlight_theme];
|
|
||||||
highlighter = Some(get_highlighter(info, &context.config));
|
|
||||||
// This selects the background color the same way that start_coloured_html_snippet does
|
|
||||||
let color =
|
|
||||||
theme.settings.background.unwrap_or(::syntect::highlighting::Color::WHITE);
|
|
||||||
background = IncludeBackground::IfDifferent(color);
|
|
||||||
let snippet = start_highlighted_html_snippet(theme);
|
|
||||||
Event::Html(Owned(snippet.0))
|
|
||||||
}
|
|
||||||
Event::End(Tag::CodeBlock(_)) => {
|
|
||||||
if !context.config.highlight_code {
|
|
||||||
return Event::Html(Borrowed("</code></pre>\n"));
|
|
||||||
}
|
|
||||||
// reset highlight and close the code block
|
|
||||||
highlighter = None;
|
|
||||||
Event::Html(Borrowed("</pre>"))
|
|
||||||
}
|
|
||||||
Event::Start(Tag::Image(src, title)) => {
|
|
||||||
if is_colocated_asset_link(&src) {
|
|
||||||
return Event::Start(Tag::Image(
|
|
||||||
Owned(format!("{}{}", context.current_page_permalink, src)),
|
|
||||||
title,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
Event::Start(Tag::Image(src, title))
|
|
||||||
}
|
|
||||||
Event::Start(Tag::Link(link, title)) => {
|
|
||||||
let fixed_link = match fix_link(&link, context) {
|
|
||||||
Ok(fixed_link) => fixed_link,
|
|
||||||
Err(err) => {
|
|
||||||
error = Some(err);
|
|
||||||
return Event::Html(Borrowed(""))
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
Event::Start(Tag::Link(Owned(fixed_link), title))
|
// Business as usual
|
||||||
|
Event::Text(text)
|
||||||
|
}
|
||||||
|
Event::Start(Tag::CodeBlock(ref info)) => {
|
||||||
|
if !context.config.highlight_code {
|
||||||
|
return Event::Html(Borrowed("<pre><code>"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let theme = &THEME_SET.themes[&context.config.highlight_theme];
|
||||||
|
highlighter = Some(get_highlighter(info, &context.config));
|
||||||
|
// This selects the background color the same way that start_coloured_html_snippet does
|
||||||
|
let color = theme
|
||||||
|
.settings
|
||||||
|
.background
|
||||||
|
.unwrap_or(::syntect::highlighting::Color::WHITE);
|
||||||
|
background = IncludeBackground::IfDifferent(color);
|
||||||
|
let snippet = start_highlighted_html_snippet(theme);
|
||||||
|
Event::Html(Owned(snippet.0))
|
||||||
|
}
|
||||||
|
Event::End(Tag::CodeBlock(_)) => {
|
||||||
|
if !context.config.highlight_code {
|
||||||
|
return Event::Html(Borrowed("</code></pre>\n"));
|
||||||
|
}
|
||||||
|
// reset highlight and close the code block
|
||||||
|
highlighter = None;
|
||||||
|
Event::Html(Borrowed("</pre>"))
|
||||||
|
}
|
||||||
|
Event::Start(Tag::Image(src, title)) => {
|
||||||
|
if is_colocated_asset_link(&src) {
|
||||||
|
return Event::Start(Tag::Image(
|
||||||
|
Owned(format!("{}{}", context.current_page_permalink, src)),
|
||||||
|
title,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Event::Start(Tag::Image(src, title))
|
||||||
|
}
|
||||||
|
Event::Start(Tag::Link(link, title)) => {
|
||||||
|
let fixed_link = match fix_link(&link, context) {
|
||||||
|
Ok(fixed_link) => fixed_link,
|
||||||
|
Err(err) => {
|
||||||
|
error = Some(err);
|
||||||
|
return Event::Html(Borrowed(""));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Event::Start(Tag::Link(Owned(fixed_link), title))
|
||||||
|
}
|
||||||
|
Event::Html(ref markup) if markup.contains("<!-- more -->") => {
|
||||||
|
has_summary = true;
|
||||||
|
Event::Html(Borrowed(CONTINUE_READING))
|
||||||
|
}
|
||||||
|
_ => event,
|
||||||
}
|
}
|
||||||
Event::Html(ref markup) if markup.contains("<!-- more -->") => {
|
})
|
||||||
has_summary = true;
|
.collect::<Vec<_>>(); // We need to collect the events to make a second pass
|
||||||
Event::Html(Borrowed(CONTINUE_READING))
|
|
||||||
}
|
|
||||||
_ => event,
|
|
||||||
}
|
|
||||||
}).collect::<Vec<_>>(); // We need to collect the events to make a second pass
|
|
||||||
|
|
||||||
let header_refs = get_header_refs(&events);
|
let header_refs = get_header_refs(&events);
|
||||||
|
|
||||||
@ -228,7 +233,7 @@ pub fn markdown_to_html(content: &str, context: &RenderContext) -> Result<Render
|
|||||||
for header_ref in header_refs {
|
for header_ref in header_refs {
|
||||||
let start_idx = header_ref.start_idx;
|
let start_idx = header_ref.start_idx;
|
||||||
let end_idx = header_ref.end_idx;
|
let end_idx = header_ref.end_idx;
|
||||||
let title = get_text(&events[start_idx + 1 .. end_idx]);
|
let title = get_text(&events[start_idx + 1..end_idx]);
|
||||||
let id = find_anchor(&inserted_anchors, slugify(&title), 0);
|
let id = find_anchor(&inserted_anchors, slugify(&title), 0);
|
||||||
inserted_anchors.push(id.clone());
|
inserted_anchors.push(id.clone());
|
||||||
|
|
||||||
@ -246,8 +251,13 @@ pub fn markdown_to_html(content: &str, context: &RenderContext) -> Result<Render
|
|||||||
let mut c = tera::Context::new();
|
let mut c = tera::Context::new();
|
||||||
c.insert("id", &id);
|
c.insert("id", &id);
|
||||||
|
|
||||||
let anchor_link = utils::templates::render_template(&ANCHOR_LINK_TEMPLATE, context.tera, c, &None)
|
let anchor_link = utils::templates::render_template(
|
||||||
.map_err(|e| Error::chain("Failed to render anchor link template", e))?;
|
&ANCHOR_LINK_TEMPLATE,
|
||||||
|
context.tera,
|
||||||
|
c,
|
||||||
|
&None,
|
||||||
|
)
|
||||||
|
.map_err(|e| Error::chain("Failed to render anchor link template", e))?;
|
||||||
anchors_to_insert.push((anchor_idx, Event::Html(Owned(anchor_link))));
|
anchors_to_insert.push((anchor_idx, Event::Html(Owned(anchor_link))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,9 +114,8 @@ fn render_shortcode(
|
|||||||
|
|
||||||
let template_name = format!("shortcodes/{}.html", name);
|
let template_name = format!("shortcodes/{}.html", name);
|
||||||
|
|
||||||
let res =
|
let res = utils::templates::render_template(&template_name, &context.tera, tera_context, &None)
|
||||||
utils::templates::render_template(&template_name, &context.tera, tera_context, &None)
|
.map_err(|e| Error::chain(format!("Failed to render {} shortcode", name), e))?;
|
||||||
.map_err(|e| Error::chain(format!("Failed to render {} shortcode", name), e))?;
|
|
||||||
|
|
||||||
// Small hack to avoid having multiple blank lines because of Tera tags for example
|
// Small hack to avoid having multiple blank lines because of Tera tags for example
|
||||||
// A blank like will cause the markdown parser to think we're out of HTML and start looking
|
// A blank like will cause the markdown parser to think we're out of HTML and start looking
|
||||||
|
@ -30,7 +30,7 @@ use sass_rs::{compile_file, Options as SassOptions, OutputStyle};
|
|||||||
use tera::{Context, Tera};
|
use tera::{Context, Tera};
|
||||||
|
|
||||||
use config::{get_config, Config};
|
use config::{get_config, Config};
|
||||||
use errors::{Result, Error};
|
use errors::{Error, Result};
|
||||||
use front_matter::InsertAnchor;
|
use front_matter::InsertAnchor;
|
||||||
use library::{
|
use library::{
|
||||||
find_taxonomies, sort_actual_pages_by_date, Library, Page, Paginator, Section, Taxonomy,
|
find_taxonomies, sort_actual_pages_by_date, Library, Page, Paginator, Section, Taxonomy,
|
||||||
@ -87,7 +87,8 @@ impl Site {
|
|||||||
format!("{}/{}", path.to_string_lossy().replace("\\", "/"), "templates/**/*.*ml");
|
format!("{}/{}", path.to_string_lossy().replace("\\", "/"), "templates/**/*.*ml");
|
||||||
// Only parsing as we might be extending templates from themes and that would error
|
// Only parsing as we might be extending templates from themes and that would error
|
||||||
// as we haven't loaded them yet
|
// as we haven't loaded them yet
|
||||||
let mut tera = Tera::parse(&tpl_glob).map_err(|e| Error::chain("Error parsing templates", e))?;
|
let mut tera =
|
||||||
|
Tera::parse(&tpl_glob).map_err(|e| Error::chain("Error parsing templates", e))?;
|
||||||
if let Some(theme) = config.theme.clone() {
|
if let Some(theme) = config.theme.clone() {
|
||||||
// Grab data from the extra section of the theme
|
// Grab data from the extra section of the theme
|
||||||
config.merge_with_theme(&path.join("themes").join(&theme).join("theme.toml"))?;
|
config.merge_with_theme(&path.join("themes").join(&theme).join("theme.toml"))?;
|
||||||
@ -103,8 +104,8 @@ impl Site {
|
|||||||
path.to_string_lossy().replace("\\", "/"),
|
path.to_string_lossy().replace("\\", "/"),
|
||||||
format!("themes/{}/templates/**/*.*ml", theme)
|
format!("themes/{}/templates/**/*.*ml", theme)
|
||||||
);
|
);
|
||||||
let mut tera_theme =
|
let mut tera_theme = Tera::parse(&theme_tpl_glob)
|
||||||
Tera::parse(&theme_tpl_glob).map_err(|e| Error::chain("Error parsing templates from themes", e))?;
|
.map_err(|e| Error::chain("Error parsing templates from themes", e))?;
|
||||||
rewrite_theme_paths(&mut tera_theme, &theme);
|
rewrite_theme_paths(&mut tera_theme, &theme);
|
||||||
// TODO: we do that twice, make it dry?
|
// TODO: we do that twice, make it dry?
|
||||||
if theme_path.join("templates").join("robots.txt").exists() {
|
if theme_path.join("templates").join("robots.txt").exists() {
|
||||||
@ -196,8 +197,11 @@ impl Site {
|
|||||||
entry.as_path().file_name().unwrap().to_str().unwrap().starts_with("_index.")
|
entry.as_path().file_name().unwrap().to_str().unwrap().starts_with("_index.")
|
||||||
});
|
});
|
||||||
|
|
||||||
self.library =
|
self.library = Arc::new(RwLock::new(Library::new(
|
||||||
Arc::new(RwLock::new(Library::new(page_entries.len(), section_entries.len(), self.config.is_multilingual())));
|
page_entries.len(),
|
||||||
|
section_entries.len(),
|
||||||
|
self.config.is_multilingual(),
|
||||||
|
)));
|
||||||
|
|
||||||
let sections = {
|
let sections = {
|
||||||
let config = &self.config;
|
let config = &self.config;
|
||||||
@ -349,8 +353,14 @@ impl Site {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_tera_global_fns(&mut self) {
|
pub fn register_tera_global_fns(&mut self) {
|
||||||
self.tera.register_function("get_page", global_fns::GetPage::new(self.base_path.clone(), self.library.clone()));
|
self.tera.register_function(
|
||||||
self.tera.register_function("get_section", global_fns::GetSection::new(self.base_path.clone(), self.library.clone()));
|
"get_page",
|
||||||
|
global_fns::GetPage::new(self.base_path.clone(), self.library.clone()),
|
||||||
|
);
|
||||||
|
self.tera.register_function(
|
||||||
|
"get_section",
|
||||||
|
global_fns::GetSection::new(self.base_path.clone(), self.library.clone()),
|
||||||
|
);
|
||||||
self.tera.register_function(
|
self.tera.register_function(
|
||||||
"get_taxonomy",
|
"get_taxonomy",
|
||||||
global_fns::GetTaxonomy::new(self.taxonomies.clone(), self.library.clone()),
|
global_fns::GetTaxonomy::new(self.taxonomies.clone(), self.library.clone()),
|
||||||
@ -475,7 +485,8 @@ impl Site {
|
|||||||
pub fn clean(&self) -> Result<()> {
|
pub fn clean(&self) -> Result<()> {
|
||||||
if self.output_path.exists() {
|
if self.output_path.exists() {
|
||||||
// Delete current `public` directory so we can start fresh
|
// Delete current `public` directory so we can start fresh
|
||||||
remove_dir_all(&self.output_path).map_err(|e| Error::chain("Couldn't delete output directory", e))?;
|
remove_dir_all(&self.output_path)
|
||||||
|
.map_err(|e| Error::chain("Couldn't delete output directory", e))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -544,12 +555,8 @@ impl Site {
|
|||||||
if !lang.rss {
|
if !lang.rss {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let pages = library
|
let pages =
|
||||||
.pages_values()
|
library.pages_values().iter().filter(|p| p.lang == lang.code).map(|p| *p).collect();
|
||||||
.iter()
|
|
||||||
.filter(|p| p.lang == lang.code)
|
|
||||||
.map(|p| *p)
|
|
||||||
.collect();
|
|
||||||
self.render_rss_feed(pages, Some(&PathBuf::from(lang.code.clone())))?;
|
self.render_rss_feed(pages, Some(&PathBuf::from(lang.code.clone())))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -735,7 +742,8 @@ impl Site {
|
|||||||
} else {
|
} else {
|
||||||
self.output_path.join(&taxonomy.kind.name)
|
self.output_path.join(&taxonomy.kind.name)
|
||||||
};
|
};
|
||||||
let list_output = taxonomy.render_all_terms(&self.tera, &self.config, &self.library.read().unwrap())?;
|
let list_output =
|
||||||
|
taxonomy.render_all_terms(&self.tera, &self.config, &self.library.read().unwrap())?;
|
||||||
create_directory(&output_path)?;
|
create_directory(&output_path)?;
|
||||||
create_file(&output_path.join("index.html"), &self.inject_livereload(list_output))?;
|
create_file(&output_path.join("index.html"), &self.inject_livereload(list_output))?;
|
||||||
let library = self.library.read().unwrap();
|
let library = self.library.read().unwrap();
|
||||||
@ -794,14 +802,20 @@ impl Site {
|
|||||||
|
|
||||||
let mut sections = self
|
let mut sections = self
|
||||||
.library
|
.library
|
||||||
.read().unwrap()
|
.read()
|
||||||
|
.unwrap()
|
||||||
.sections_values()
|
.sections_values()
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|s| s.meta.render)
|
.filter(|s| s.meta.render)
|
||||||
.map(|s| SitemapEntry::new(s.permalink.clone(), None))
|
.map(|s| SitemapEntry::new(s.permalink.clone(), None))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
for section in
|
for section in self
|
||||||
self.library.read().unwrap().sections_values().iter().filter(|s| s.meta.paginate_by.is_some())
|
.library
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.sections_values()
|
||||||
|
.iter()
|
||||||
|
.filter(|s| s.meta.paginate_by.is_some())
|
||||||
{
|
{
|
||||||
let number_pagers = (section.pages.len() as f64
|
let number_pagers = (section.pages.len() as f64
|
||||||
/ section.meta.paginate_by.unwrap() as f64)
|
/ section.meta.paginate_by.unwrap() as f64)
|
||||||
@ -971,9 +985,13 @@ impl Site {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if section.meta.is_paginated() {
|
if section.meta.is_paginated() {
|
||||||
self.render_paginated(&output_path, &Paginator::from_section(§ion, &self.library.read().unwrap()))?;
|
self.render_paginated(
|
||||||
|
&output_path,
|
||||||
|
&Paginator::from_section(§ion, &self.library.read().unwrap()),
|
||||||
|
)?;
|
||||||
} else {
|
} else {
|
||||||
let output = section.render_html(&self.tera, &self.config, &self.library.read().unwrap())?;
|
let output =
|
||||||
|
section.render_html(&self.tera, &self.config, &self.library.read().unwrap())?;
|
||||||
create_file(&output_path.join("index.html"), &self.inject_livereload(output))?;
|
create_file(&output_path.join("index.html"), &self.inject_livereload(output))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -985,7 +1003,8 @@ impl Site {
|
|||||||
self.render_section(
|
self.render_section(
|
||||||
&self
|
&self
|
||||||
.library
|
.library
|
||||||
.read().unwrap()
|
.read()
|
||||||
|
.unwrap()
|
||||||
.get_section(&self.content_path.join("_index.md"))
|
.get_section(&self.content_path.join("_index.md"))
|
||||||
.expect("Failed to get index section"),
|
.expect("Failed to get index section"),
|
||||||
false,
|
false,
|
||||||
@ -995,7 +1014,8 @@ impl Site {
|
|||||||
/// Renders all sections
|
/// Renders all sections
|
||||||
pub fn render_sections(&self) -> Result<()> {
|
pub fn render_sections(&self) -> Result<()> {
|
||||||
self.library
|
self.library
|
||||||
.read().unwrap()
|
.read()
|
||||||
|
.unwrap()
|
||||||
.sections_values()
|
.sections_values()
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.map(|s| self.render_section(s, true))
|
.map(|s| self.render_section(s, true))
|
||||||
@ -1026,8 +1046,12 @@ impl Site {
|
|||||||
.map(|pager| {
|
.map(|pager| {
|
||||||
let page_path = folder_path.join(&format!("{}", pager.index));
|
let page_path = folder_path.join(&format!("{}", pager.index));
|
||||||
create_directory(&page_path)?;
|
create_directory(&page_path)?;
|
||||||
let output =
|
let output = paginator.render_pager(
|
||||||
paginator.render_pager(pager, &self.config, &self.tera, &self.library.read().unwrap())?;
|
pager,
|
||||||
|
&self.config,
|
||||||
|
&self.tera,
|
||||||
|
&self.library.read().unwrap(),
|
||||||
|
)?;
|
||||||
if pager.index > 1 {
|
if pager.index > 1 {
|
||||||
create_file(&page_path.join("index.html"), &self.inject_livereload(output))?;
|
create_file(&page_path.join("index.html"), &self.inject_livereload(output))?;
|
||||||
} else {
|
} else {
|
||||||
|
@ -631,9 +631,8 @@ fn can_apply_page_templates() {
|
|||||||
assert_eq!(changed_recursively.meta.title, Some("Changed recursively".into()));
|
assert_eq!(changed_recursively.meta.title, Some("Changed recursively".into()));
|
||||||
|
|
||||||
// But it should not have override a children page_template
|
// But it should not have override a children page_template
|
||||||
let yet_another_section = library
|
let yet_another_section =
|
||||||
.get_section(&template_path.join("yet_another_section").join("_index.md"))
|
library.get_section(&template_path.join("yet_another_section").join("_index.md")).unwrap();
|
||||||
.unwrap();
|
|
||||||
assert_eq!(yet_another_section.subsections.len(), 0);
|
assert_eq!(yet_another_section.subsections.len(), 0);
|
||||||
assert_eq!(yet_another_section.pages.len(), 1);
|
assert_eq!(yet_another_section.pages.len(), 1);
|
||||||
|
|
||||||
|
@ -23,8 +23,7 @@ fn can_parse_multilingual_site() {
|
|||||||
assert_eq!(default_index_section.pages.len(), 1);
|
assert_eq!(default_index_section.pages.len(), 1);
|
||||||
assert!(default_index_section.ancestors.is_empty());
|
assert!(default_index_section.ancestors.is_empty());
|
||||||
|
|
||||||
let fr_index_section =
|
let fr_index_section = library.get_section(&path.join("content").join("_index.fr.md")).unwrap();
|
||||||
library.get_section(&path.join("content").join("_index.fr.md")).unwrap();
|
|
||||||
assert_eq!(fr_index_section.pages.len(), 1);
|
assert_eq!(fr_index_section.pages.len(), 1);
|
||||||
assert!(fr_index_section.ancestors.is_empty());
|
assert!(fr_index_section.ancestors.is_empty());
|
||||||
|
|
||||||
@ -139,5 +138,4 @@ fn can_build_multilingual_site() {
|
|||||||
assert!(!file_contains!(public, "fr/auteurs/index.html", "Queen"));
|
assert!(!file_contains!(public, "fr/auteurs/index.html", "Queen"));
|
||||||
assert!(file_contains!(public, "fr/auteurs/index.html", "Vincent"));
|
assert!(file_contains!(public, "fr/auteurs/index.html", "Vincent"));
|
||||||
assert!(!file_exists!(public, "fr/auteurs/vincent-prouillet/rss.xml"));
|
assert!(!file_exists!(public, "fr/auteurs/vincent-prouillet/rss.xml"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -183,7 +183,7 @@ impl LoadData {
|
|||||||
pub fn new(content_path: PathBuf, base_path: PathBuf) -> Self {
|
pub fn new(content_path: PathBuf, base_path: PathBuf) -> Self {
|
||||||
let client = Arc::new(Mutex::new(Client::builder().build().expect("reqwest client build")));
|
let client = Arc::new(Mutex::new(Client::builder().build().expect("reqwest client build")));
|
||||||
let result_cache = Arc::new(Mutex::new(HashMap::new()));
|
let result_cache = Arc::new(Mutex::new(HashMap::new()));
|
||||||
Self {content_path, base_path, client, result_cache}
|
Self { content_path, base_path, client, result_cache }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,7 +310,7 @@ fn load_csv(csv_data: String) -> Result<Value> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{LoadData, DataSource, OutputFormat};
|
use super::{DataSource, LoadData, OutputFormat};
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -15,7 +15,7 @@ mod macros;
|
|||||||
|
|
||||||
mod load_data;
|
mod load_data;
|
||||||
|
|
||||||
pub use self::load_data::LoadData;
|
pub use self::load_data::LoadData;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Trans {
|
pub struct Trans {
|
||||||
@ -23,7 +23,7 @@ pub struct Trans {
|
|||||||
}
|
}
|
||||||
impl Trans {
|
impl Trans {
|
||||||
pub fn new(config: Config) -> Self {
|
pub fn new(config: Config) -> Self {
|
||||||
Self {config}
|
Self { config }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl TeraFn for Trans {
|
impl TeraFn for Trans {
|
||||||
@ -43,7 +43,7 @@ pub struct GetUrl {
|
|||||||
}
|
}
|
||||||
impl GetUrl {
|
impl GetUrl {
|
||||||
pub fn new(config: Config, permalinks: HashMap<String, String>) -> Self {
|
pub fn new(config: Config, permalinks: HashMap<String, String>) -> Self {
|
||||||
Self {config, permalinks}
|
Self { config, permalinks }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl TeraFn for GetUrl {
|
impl TeraFn for GetUrl {
|
||||||
@ -88,7 +88,7 @@ pub struct ResizeImage {
|
|||||||
}
|
}
|
||||||
impl ResizeImage {
|
impl ResizeImage {
|
||||||
pub fn new(imageproc: Arc<Mutex<imageproc::Processor>>) -> Self {
|
pub fn new(imageproc: Arc<Mutex<imageproc::Processor>>) -> Self {
|
||||||
Self {imageproc}
|
Self { imageproc }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +154,7 @@ impl GetTaxonomyUrl {
|
|||||||
}
|
}
|
||||||
taxonomies.insert(taxonomy.kind.name.clone(), items);
|
taxonomies.insert(taxonomy.kind.name.clone(), items);
|
||||||
}
|
}
|
||||||
Self {taxonomies}
|
Self { taxonomies }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl TeraFn for GetTaxonomyUrl {
|
impl TeraFn for GetTaxonomyUrl {
|
||||||
@ -188,7 +188,6 @@ impl TeraFn for GetTaxonomyUrl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GetPage {
|
pub struct GetPage {
|
||||||
base_path: PathBuf,
|
base_path: PathBuf,
|
||||||
@ -196,7 +195,7 @@ pub struct GetPage {
|
|||||||
}
|
}
|
||||||
impl GetPage {
|
impl GetPage {
|
||||||
pub fn new(base_path: PathBuf, library: Arc<RwLock<Library>>) -> Self {
|
pub fn new(base_path: PathBuf, library: Arc<RwLock<Library>>) -> Self {
|
||||||
Self {base_path: base_path.join("content"), library}
|
Self { base_path: base_path.join("content"), library }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl TeraFn for GetPage {
|
impl TeraFn for GetPage {
|
||||||
@ -209,9 +208,7 @@ impl TeraFn for GetPage {
|
|||||||
let full_path = self.base_path.join(&path);
|
let full_path = self.base_path.join(&path);
|
||||||
let library = self.library.read().unwrap();
|
let library = self.library.read().unwrap();
|
||||||
match library.get_page(&full_path) {
|
match library.get_page(&full_path) {
|
||||||
Some(p) => {
|
Some(p) => Ok(to_value(p.to_serialized(&library)).unwrap()),
|
||||||
Ok(to_value(p.to_serialized(&library)).unwrap())
|
|
||||||
},
|
|
||||||
None => Err(format!("Page `{}` not found.", path).into()),
|
None => Err(format!("Page `{}` not found.", path).into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -224,7 +221,7 @@ pub struct GetSection {
|
|||||||
}
|
}
|
||||||
impl GetSection {
|
impl GetSection {
|
||||||
pub fn new(base_path: PathBuf, library: Arc<RwLock<Library>>) -> Self {
|
pub fn new(base_path: PathBuf, library: Arc<RwLock<Library>>) -> Self {
|
||||||
Self {base_path: base_path.join("content"), library}
|
Self { base_path: base_path.join("content"), library }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl TeraFn for GetSection {
|
impl TeraFn for GetSection {
|
||||||
@ -249,13 +246,12 @@ impl TeraFn for GetSection {
|
|||||||
} else {
|
} else {
|
||||||
Ok(to_value(s.to_serialized(&library)).unwrap())
|
Ok(to_value(s.to_serialized(&library)).unwrap())
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
None => Err(format!("Section `{}` not found.", path).into()),
|
None => Err(format!("Section `{}` not found.", path).into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GetTaxonomy {
|
pub struct GetTaxonomy {
|
||||||
library: Arc<RwLock<Library>>,
|
library: Arc<RwLock<Library>>,
|
||||||
@ -267,7 +263,7 @@ impl GetTaxonomy {
|
|||||||
for taxo in all_taxonomies {
|
for taxo in all_taxonomies {
|
||||||
taxonomies.insert(taxo.kind.name.clone(), taxo);
|
taxonomies.insert(taxo.kind.name.clone(), taxo);
|
||||||
}
|
}
|
||||||
Self {taxonomies, library}
|
Self { taxonomies, library }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl TeraFn for GetTaxonomy {
|
impl TeraFn for GetTaxonomy {
|
||||||
@ -278,16 +274,10 @@ impl TeraFn for GetTaxonomy {
|
|||||||
"`get_taxonomy` requires a `kind` argument with a string value"
|
"`get_taxonomy` requires a `kind` argument with a string value"
|
||||||
);
|
);
|
||||||
|
|
||||||
match self.taxonomies.get(&kind) {
|
match self.taxonomies.get(&kind) {
|
||||||
Some(t) => {
|
Some(t) => Ok(to_value(t.to_serialized(&self.library.read().unwrap())).unwrap()),
|
||||||
Ok(to_value(t.to_serialized(&self.library.read().unwrap())).unwrap())
|
|
||||||
},
|
|
||||||
None => {
|
None => {
|
||||||
Err(format!(
|
Err(format!("`get_taxonomy` received an unknown taxonomy as kind: {}", kind).into())
|
||||||
"`get_taxonomy` received an unknown taxonomy as kind: {}",
|
|
||||||
kind
|
|
||||||
)
|
|
||||||
.into())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -298,9 +288,9 @@ mod tests {
|
|||||||
use super::{GetTaxonomy, GetTaxonomyUrl, GetUrl, Trans};
|
use super::{GetTaxonomy, GetTaxonomyUrl, GetUrl, Trans};
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::{RwLock, Arc};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use tera::{to_value, Value, Function};
|
use tera::{to_value, Function, Value};
|
||||||
|
|
||||||
use config::{Config, Taxonomy as TaxonomyConfig};
|
use config::{Config, Taxonomy as TaxonomyConfig};
|
||||||
use library::{Library, Taxonomy, TaxonomyItem};
|
use library::{Library, Taxonomy, TaxonomyItem};
|
||||||
@ -348,9 +338,19 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn can_get_taxonomy() {
|
fn can_get_taxonomy() {
|
||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
let taxo_config = TaxonomyConfig { name: "tags".to_string(), lang: config.default_language.clone(), ..TaxonomyConfig::default() };
|
let taxo_config = TaxonomyConfig {
|
||||||
|
name: "tags".to_string(),
|
||||||
|
lang: config.default_language.clone(),
|
||||||
|
..TaxonomyConfig::default()
|
||||||
|
};
|
||||||
let library = Arc::new(RwLock::new(Library::new(0, 0, false)));
|
let library = Arc::new(RwLock::new(Library::new(0, 0, false)));
|
||||||
let tag = TaxonomyItem::new("Programming", &taxo_config, &config, vec![], &library.read().unwrap());
|
let tag = TaxonomyItem::new(
|
||||||
|
"Programming",
|
||||||
|
&taxo_config,
|
||||||
|
&config,
|
||||||
|
vec![],
|
||||||
|
&library.read().unwrap(),
|
||||||
|
);
|
||||||
let tags = Taxonomy { kind: taxo_config, items: vec![tag] };
|
let tags = Taxonomy { kind: taxo_config, items: vec![tag] };
|
||||||
|
|
||||||
let taxonomies = vec![tags.clone()];
|
let taxonomies = vec![tags.clone()];
|
||||||
@ -388,7 +388,11 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn can_get_taxonomy_url() {
|
fn can_get_taxonomy_url() {
|
||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
let taxo_config = TaxonomyConfig { name: "tags".to_string(), lang: config.default_language.clone(), ..TaxonomyConfig::default() };
|
let taxo_config = TaxonomyConfig {
|
||||||
|
name: "tags".to_string(),
|
||||||
|
lang: config.default_language.clone(),
|
||||||
|
..TaxonomyConfig::default()
|
||||||
|
};
|
||||||
let library = Library::new(0, 0, false);
|
let library = Library::new(0, 0, false);
|
||||||
let tag = TaxonomyItem::new("Programming", &taxo_config, &config, vec![], &library);
|
let tag = TaxonomyItem::new("Programming", &taxo_config, &config, vec![], &library);
|
||||||
let tags = Taxonomy { kind: taxo_config, items: vec![tag] };
|
let tags = Taxonomy { kind: taxo_config, items: vec![tag] };
|
||||||
|
@ -25,7 +25,7 @@ pub mod global_fns;
|
|||||||
|
|
||||||
use tera::{Context, Tera};
|
use tera::{Context, Tera};
|
||||||
|
|
||||||
use errors::{Result, Error};
|
use errors::{Error, Result};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref ZOLA_TERA: Tera = {
|
pub static ref ZOLA_TERA: Tera = {
|
||||||
|
@ -4,7 +4,7 @@ use std::path::{Path, PathBuf};
|
|||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
use errors::{Result, Error};
|
use errors::{Error, Result};
|
||||||
|
|
||||||
pub fn is_path_in_directory(parent: &Path, path: &Path) -> Result<bool> {
|
pub fn is_path_in_directory(parent: &Path, path: &Path) -> Result<bool> {
|
||||||
let canonical_path = path
|
let canonical_path = path
|
||||||
@ -19,8 +19,8 @@ pub fn is_path_in_directory(parent: &Path, path: &Path) -> Result<bool> {
|
|||||||
|
|
||||||
/// Create a file with the content given
|
/// Create a file with the content given
|
||||||
pub fn create_file(path: &Path, content: &str) -> Result<()> {
|
pub fn create_file(path: &Path, content: &str) -> Result<()> {
|
||||||
let mut file = File::create(&path)
|
let mut file =
|
||||||
.map_err(|e| Error::chain(format!("Failed to create {:?}", path), e))?;
|
File::create(&path).map_err(|e| Error::chain(format!("Failed to create {:?}", path), e))?;
|
||||||
file.write_all(content.as_bytes())?;
|
file.write_all(content.as_bytes())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -37,8 +37,9 @@ pub fn ensure_directory_exists(path: &Path) -> Result<()> {
|
|||||||
/// exists before creating it
|
/// exists before creating it
|
||||||
pub fn create_directory(path: &Path) -> Result<()> {
|
pub fn create_directory(path: &Path) -> Result<()> {
|
||||||
if !path.exists() {
|
if !path.exists() {
|
||||||
create_dir_all(path)
|
create_dir_all(path).map_err(|e| {
|
||||||
.map_err(|e| Error::chain(format!("Was not able to create folder {}", path.display()), e))?;
|
Error::chain(format!("Was not able to create folder {}", path.display()), e)
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ impl<T> InsertMany for Vec<T> {
|
|||||||
|
|
||||||
for (idx, elem) in elem_to_insert.into_iter() {
|
for (idx, elem) in elem_to_insert.into_iter() {
|
||||||
let head_len = idx - last_idx;
|
let head_len = idx - last_idx;
|
||||||
inserted.extend(self.splice(0 .. head_len, std::iter::empty()));
|
inserted.extend(self.splice(0..head_len, std::iter::empty()));
|
||||||
inserted.push(elem);
|
inserted.push(elem);
|
||||||
last_idx = idx;
|
last_idx = idx;
|
||||||
}
|
}
|
||||||
@ -41,4 +41,4 @@ mod test {
|
|||||||
v2.insert_many(vec![(0, 0), (2, -1)]);
|
v2.insert_many(vec![(0, 0), (2, -1)]);
|
||||||
assert_eq!(v2, &[0, 1, 2, -1, 3, 4, 5]);
|
assert_eq!(v2, &[0, 1, 2, -1, 3, 4, 5]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ use ctrlc;
|
|||||||
use notify::{watcher, RecursiveMode, Watcher};
|
use notify::{watcher, RecursiveMode, Watcher};
|
||||||
use ws::{Message, Sender, WebSocket};
|
use ws::{Message, Sender, WebSocket};
|
||||||
|
|
||||||
use errors::{Result, Error as ZolaError};
|
use errors::{Error as ZolaError, Result};
|
||||||
use site::Site;
|
use site::Site;
|
||||||
use utils::fs::copy_file;
|
use utils::fs::copy_file;
|
||||||
|
|
||||||
@ -296,11 +296,7 @@ pub fn serve(
|
|||||||
};
|
};
|
||||||
console::info(&msg);
|
console::info(&msg);
|
||||||
// Force refresh
|
// Force refresh
|
||||||
rebuild_done_handling(
|
rebuild_done_handling(&broadcaster, rebuild::after_template_change(site, &path), "/x.js");
|
||||||
&broadcaster,
|
|
||||||
rebuild::after_template_change(site, &path),
|
|
||||||
"/x.js",
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let reload_sass = |site: &Site, path: &Path, partial_path: &Path| {
|
let reload_sass = |site: &Site, path: &Path, partial_path: &Path| {
|
||||||
|
@ -7,8 +7,8 @@ use atty;
|
|||||||
use chrono::Duration;
|
use chrono::Duration;
|
||||||
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
|
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
|
||||||
|
|
||||||
use site::Site;
|
|
||||||
use errors::Error;
|
use errors::Error;
|
||||||
|
use site::Site;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// Termcolor color choice.
|
/// Termcolor color choice.
|
||||||
@ -64,9 +64,7 @@ pub fn warn_about_ignored_pages(site: &Site) {
|
|||||||
let ignored_pages: Vec<_> = library
|
let ignored_pages: Vec<_> = library
|
||||||
.sections_values()
|
.sections_values()
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|s| {
|
.flat_map(|s| s.ignored_pages.iter().map(|k| library.get_page_by_key(*k).file.path.clone()))
|
||||||
s.ignored_pages.iter().map(|k| library.get_page_by_key(*k).file.path.clone())
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if !ignored_pages.is_empty() {
|
if !ignored_pages.is_empty() {
|
||||||
|
Loading…
Reference in New Issue
Block a user