@@ -36,6 +36,7 @@ sections up to the index to be used with the `get_section` Tera function | |||||
- `serve` will now try to find other ports than 1111 rather than panicking | - `serve` will now try to find other ports than 1111 rather than panicking | ||||
- Ensure content directory exists before rendering aliases | - Ensure content directory exists before rendering aliases | ||||
- Do not include drafts in pagination | - Do not include drafts in pagination | ||||
- Pages filenames starting by a date will now use that date as page date if there isn't one defined in frontmatter | |||||
## 0.4.2 (2018-09-03) | ## 0.4.2 (2018-09-03) | ||||
@@ -1080,7 +1080,9 @@ dependencies = [ | |||||
"errors 0.1.0", | "errors 0.1.0", | ||||
"front_matter 0.1.0", | "front_matter 0.1.0", | ||||
"globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", | "globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
"rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", | "rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
"rendering 0.1.0", | "rendering 0.1.0", | ||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", | "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", | "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
@@ -11,6 +11,8 @@ tera = "0.11" | |||||
serde = "1" | serde = "1" | ||||
serde_derive = "1" | serde_derive = "1" | ||||
slug = "0.1" | slug = "0.1" | ||||
regex = "1" | |||||
lazy_static = "1" | |||||
front_matter = { path = "../front_matter" } | front_matter = { path = "../front_matter" } | ||||
config = { path = "../config" } | config = { path = "../config" } | ||||
@@ -5,6 +5,7 @@ use std::path::{Path, PathBuf}; | |||||
use tera::{Tera, Context as TeraContext}; | use tera::{Tera, Context as TeraContext}; | ||||
use slug::slugify; | use slug::slugify; | ||||
use slotmap::{Key}; | use slotmap::{Key}; | ||||
use regex::Regex; | |||||
use errors::{Result, ResultExt}; | use errors::{Result, ResultExt}; | ||||
use config::Config; | use config::Config; | ||||
@@ -18,6 +19,11 @@ use library::Library; | |||||
use content::file_info::FileInfo; | use content::file_info::FileInfo; | ||||
use content::ser::SerializingPage; | use content::ser::SerializingPage; | ||||
lazy_static! { | |||||
// Check whether a string starts with yyyy-mm-dd{-,_} | |||||
static ref DATE_IN_FILENAME: Regex = Regex::new(r"^^([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))(_|-)").unwrap(); | |||||
} | |||||
#[derive(Clone, Debug, PartialEq)] | #[derive(Clone, Debug, PartialEq)] | ||||
pub struct Page { | pub struct Page { | ||||
@@ -103,10 +109,20 @@ impl Page { | |||||
pub fn parse(file_path: &Path, content: &str, config: &Config) -> Result<Page> { | pub fn parse(file_path: &Path, content: &str, config: &Config) -> Result<Page> { | ||||
let (meta, content) = split_page_content(file_path, content)?; | let (meta, content) = split_page_content(file_path, content)?; | ||||
let mut page = Page::new(file_path, meta); | let mut page = Page::new(file_path, meta); | ||||
page.raw_content = content; | page.raw_content = content; | ||||
let (word_count, reading_time) = get_reading_analytics(&page.raw_content); | let (word_count, reading_time) = get_reading_analytics(&page.raw_content); | ||||
page.word_count = Some(word_count); | page.word_count = Some(word_count); | ||||
page.reading_time = Some(reading_time); | page.reading_time = Some(reading_time); | ||||
let mut has_date_in_name = false; | |||||
if DATE_IN_FILENAME.is_match(&page.file.name) { | |||||
has_date_in_name = true; | |||||
if page.meta.date.is_none() { | |||||
page.meta.date = Some(page.file.name[..10].to_string()); | |||||
} | |||||
} | |||||
page.slug = { | page.slug = { | ||||
if let Some(ref slug) = page.meta.slug { | if let Some(ref slug) = page.meta.slug { | ||||
slug.trim().to_string() | slug.trim().to_string() | ||||
@@ -114,10 +130,15 @@ impl Page { | |||||
if let Some(parent) = page.file.path.parent() { | if let Some(parent) = page.file.path.parent() { | ||||
slugify(parent.file_name().unwrap().to_str().unwrap()) | slugify(parent.file_name().unwrap().to_str().unwrap()) | ||||
} else { | } else { | ||||
slugify(page.file.name.clone()) | |||||
slugify(&page.file.name) | |||||
} | } | ||||
} else { | } else { | ||||
slugify(page.file.name.clone()) | |||||
if has_date_in_name { | |||||
// skip the date + the {_,-} | |||||
slugify(&page.file.name[11..]) | |||||
} else { | |||||
slugify(&page.file.name) | |||||
} | |||||
} | } | ||||
}; | }; | ||||
@@ -499,4 +520,38 @@ Hello world | |||||
assert_eq!(page.assets.len(), 1); | assert_eq!(page.assets.len(), 1); | ||||
assert_eq!(page.assets[0].file_name().unwrap().to_str(), Some("graph.jpg")); | assert_eq!(page.assets[0].file_name().unwrap().to_str(), Some("graph.jpg")); | ||||
} | } | ||||
#[test] | |||||
fn can_get_date_from_filename() { | |||||
let config = Config::default(); | |||||
let content = r#" | |||||
+++ | |||||
+++ | |||||
Hello world | |||||
<!-- more -->"#.to_string(); | |||||
let res = Page::parse(Path::new("2018-10-08_hello.md"), &content, &config); | |||||
assert!(res.is_ok()); | |||||
let page = res.unwrap(); | |||||
assert_eq!(page.meta.date, Some("2018-10-08".to_string())); | |||||
assert_eq!(page.slug, "hello"); | |||||
} | |||||
#[test] | |||||
fn frontmatter_date_override_filename_date() { | |||||
let config = Config::default(); | |||||
let content = r#" | |||||
+++ | |||||
date = 2018-09-09 | |||||
+++ | |||||
Hello world | |||||
<!-- more -->"#.to_string(); | |||||
let res = Page::parse(Path::new("2018-10-08_hello.md"), &content, &config); | |||||
assert!(res.is_ok()); | |||||
let page = res.unwrap(); | |||||
assert_eq!(page.meta.date, Some("2018-09-09".to_string())); | |||||
assert_eq!(page.slug, "hello"); | |||||
} | |||||
} | } |
@@ -6,6 +6,9 @@ extern crate serde_derive; | |||||
extern crate chrono; | extern crate chrono; | ||||
extern crate slotmap; | extern crate slotmap; | ||||
extern crate rayon; | extern crate rayon; | ||||
#[macro_use] | |||||
extern crate lazy_static; | |||||
extern crate regex; | |||||
#[cfg(test)] | #[cfg(test)] | ||||
extern crate tempfile; | extern crate tempfile; | ||||
@@ -16,6 +16,10 @@ create a **page** at `[base_url]/about`). | |||||
If the file is given any name *other* than `index.md` or `_index.md`, then it will | If the file is given any name *other* than `index.md` or `_index.md`, then it will | ||||
create a page with that name (without the `.md`). So naming a file in the root of your | create a page with that name (without the `.md`). So naming a file in the root of your | ||||
content directory `about.md` would also create a page at `[base_url]/about`. | content directory `about.md` would also create a page at `[base_url]/about`. | ||||
Another exception to that rule is that a filename starting with a YYYY-mm-dd date followed by | |||||
an underscore (`_`) or a dash (`-`) will use that date as the page date, unless already set | |||||
in the front-matter. The page name will be anything after `_`/`-` so a filename like `2018-10-10-hello-world.md` will | |||||
be available at `[base_url]/hello-world` | |||||
As you can see, creating an `about.md` file is exactly equivalent to creating an | As you can see, creating an `about.md` file is exactly equivalent to creating an | ||||
`about/index.md` file. The only difference between the two methods is that creating | `about/index.md` file. The only difference between the two methods is that creating | ||||
@@ -42,6 +46,7 @@ description = "" | |||||
# Do not wrap dates in quotes, the line below only indicates that there is no default date. | # Do not wrap dates in quotes, the line below only indicates that there is no default date. | ||||
# If the section variable `sort_by` is set to `date`, then any page that lacks a `date` | # If the section variable `sort_by` is set to `date`, then any page that lacks a `date` | ||||
# will not be rendered. | # will not be rendered. | ||||
# Setting this overrides a date set in the filename. | |||||
date = | date = | ||||
# The weight as defined in the Section page | # The weight as defined in the Section page | ||||