From d05a1559d9e087184b80eb3330e156b363c585e7 Mon Sep 17 00:00:00 2001 From: Vincent Prouillet Date: Wed, 22 Mar 2017 20:59:49 +0900 Subject: [PATCH] Add prev/next hack --- Cargo.lock | 30 +++++------ benches/gutenberg.rs | 48 +++++++++++++++++ examples/generate_themes.rs | 2 +- src/config.rs | 5 -- src/lib.rs | 5 +- src/markdown.rs | 4 +- src/page.rs | 51 ++++++++++++++++++- src/site.rs | 44 ++++++++-------- src/utils.rs | 1 - test_site/content/posts/fixed-slug.md | 1 + test_site/content/posts/fixed-url.md | 1 + test_site/content/posts/python.md | 1 + test_site/content/posts/simple.md | 1 + .../content/posts/tutorials/devops/docker.md | 1 + .../content/posts/tutorials/devops/nix.md | 1 + tests/site.rs | 4 +- 16 files changed, 148 insertions(+), 52 deletions(-) create mode 100644 benches/gutenberg.rs diff --git a/Cargo.lock b/Cargo.lock index b76548a6..44244ac2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,7 +3,7 @@ name = "gutenberg" version = "0.0.1" dependencies = [ "chrono 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.21.2 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "iron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -137,7 +137,7 @@ dependencies = [ [[package]] name = "clap" -version = "2.21.1" +version = "2.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -152,7 +152,7 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", @@ -543,21 +543,21 @@ dependencies = [ [[package]] name = "onig" -version = "1.2.0" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "onig_sys 61.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "onig_sys 61.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "onig_sys" -version = "61.1.0" +version = "61.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -616,7 +616,7 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -779,7 +779,7 @@ dependencies = [ "flate2 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "onig 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "onig 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "plist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", @@ -848,7 +848,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1041,8 +1041,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c" "checksum chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "9213f7cd7c27e95c2b57c49f0e69b1ea65b27138da84a170133fd21b07659c00" "checksum chrono 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "158b0bd7d75cbb6bf9c25967a48a2e9f77da95876b858eadfabaa99cd069de6e" -"checksum clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "74a80f603221c9cd9aa27a28f52af452850051598537bb6b359c38a7d61e5cda" -"checksum cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "e1acc68a3f714627af38f9f5d09706a28584ba60dfe2cca68f40bf779f941b25" +"checksum clap 2.21.2 (registry+https://github.com/rust-lang/crates.io-index)" = "58ad5e8142f3a5eab0c1cba5011aa383e009842936107fe4d94f1a8d380a1aec" +"checksum cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "d18d68987ed4c516dcc3e7913659bfa4076f5182eea4a7e0038bb060953e76ac" "checksum conduit-mime-types 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "95ca30253581af809925ef68c2641cc140d6183f43e12e0af4992d53768bd7b8" "checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" "checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" @@ -1088,8 +1088,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num-iter 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d1891bd7b936f12349b7d1403761c8a0b85a18b148e9da4429d5d102c1a41e" "checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99" "checksum num_cpus 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a18c392466409c50b87369414a2680c93e739aedeb498eb2bff7d7eb569744e2" -"checksum onig 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5f586e53fa11ead18582956ea282c30baea1f25d3ee4c5fb85803f98727cb7" -"checksum onig_sys 61.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a35f2cca300f0945538564da6052a449db55e65870cf0e9d443c1bce3d5dda47" +"checksum onig 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1f59adfdb1810e061fcd1cf5dd2792730f8226e5d23c51a52f243714cc8fe676" +"checksum onig_sys 61.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "be2eb43cab0eed1bdeec174b96967cf5636634adc2b6ba8fcc875aa3d5fc4118" "checksum pest 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e823a5967bb4cdc6d3e46f47baaf4ecfeae44413a642b74ad44e59e49c7f6" "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" "checksum plist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6ab9bef2781bcdac1baf3e29eb297344cd24263e22fd9436d3a21215b7d8aa" @@ -1097,7 +1097,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum pulldown-cmark 0.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "b0b0f7b64fd9ff618da552df85b0d356a1487e5ef41df8b5727b0f73bd1215a1" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d" -"checksum redox_syscall 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd35cc9a8bdec562c757e3d43c1526b5c6d2653e23e2315065bc25556550753" +"checksum redox_syscall 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "29dbdfd4b9df8ab31dec47c6087b7b13cbf4a776f335e4de8efba8288dda075b" "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" "checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457" "checksum rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95" diff --git a/benches/gutenberg.rs b/benches/gutenberg.rs new file mode 100644 index 00000000..20865769 --- /dev/null +++ b/benches/gutenberg.rs @@ -0,0 +1,48 @@ +#![feature(test)] +extern crate test; +extern crate gutenberg; +extern crate tempdir; + +use std::env; + +use tempdir::TempDir; +use gutenberg::{Site, populate_previous_and_next_pages}; + +// TODO: add bench with ~1000 pages for all cases + +#[bench] +fn bench_loading_test_site(b: &mut test::Bencher) { + let mut path = env::current_dir().unwrap().to_path_buf(); + path.push("test_site"); + let mut site = Site::new(&path).unwrap(); + + + b.iter(|| site.load().unwrap()); +} + + +#[bench] +fn bench_building_test_site(b: &mut test::Bencher) { + let mut path = env::current_dir().unwrap().to_path_buf(); + path.push("test_site"); + let mut site = Site::new(&path).unwrap(); + site.load().unwrap(); + let tmp_dir = TempDir::new("example").expect("create temp dir"); + let public = &tmp_dir.path().join("public"); + site.set_output_path(&public); + + + b.iter(|| site.build().unwrap()); +} + +#[bench] +fn bench_populate_previous_and_next_pages(b: &mut test::Bencher) { + let mut path = env::current_dir().unwrap().to_path_buf(); + path.push("test_site"); + let mut site = Site::new(&path).unwrap(); + site.load().unwrap(); + let mut pages = site.pages.values().map(|p| p.clone()).collect::>(); + pages.sort_by(|a, b| a.partial_cmp(b).unwrap()); + + b.iter(|| populate_previous_and_next_pages(pages.as_slice(), false)); +} diff --git a/examples/generate_themes.rs b/examples/generate_themes.rs index 880bb96d..bd19cae9 100644 --- a/examples/generate_themes.rs +++ b/examples/generate_themes.rs @@ -35,7 +35,7 @@ fn main() { } (Some(ref s), Some(ref theme_dir), Some(ref packpath), None) if s == "themepack" => { let ts = ThemeSet::load_from_folder(theme_dir).unwrap(); - for (path, _) in &ts.themes { + for path in ts.themes.keys() { println!("{:?}", path); } dump_to_file(&ts, packpath).unwrap(); diff --git a/src/config.rs b/src/config.rs index 9048d1f2..5f24bae8 100644 --- a/src/config.rs +++ b/src/config.rs @@ -9,11 +9,6 @@ use errors::{Result, ResultExt}; use markdown::SETUP; -// TO ADD: -// highlight code theme -// generate_tags_pages -// generate_categories_pages - #[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct Config { /// Title of the site diff --git a/src/lib.rs b/src/lib.rs index 3c5fe81b..75f1ecc2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,6 +29,7 @@ mod section; pub use site::Site; pub use config::Config; pub use front_matter::{FrontMatter, split_content}; -pub use page::{Page}; +pub use page::{Page, populate_previous_and_next_pages}; pub use section::{Section}; -pub use utils::create_file; +pub use utils::{create_file}; +pub use markdown::markdown_to_html; diff --git a/src/markdown.rs b/src/markdown.rs index 873047fe..2c3d3f4f 100644 --- a/src/markdown.rs +++ b/src/markdown.rs @@ -77,9 +77,9 @@ impl<'a> Iterator for CodeHighlightingParser<'a> { .and_then(|lang| SETUP.syntax_set.find_syntax_by_token(lang)) .unwrap_or_else(|| SETUP.syntax_set.find_syntax_plain_text()); self.highlighter = Some( - HighlightLines::new(syntax, &theme) + HighlightLines::new(syntax, theme) ); - let snippet = start_coloured_html_snippet(&theme); + let snippet = start_coloured_html_snippet(theme); Some(Event::Html(Owned(snippet))) }, Event::End(Tag::CodeBlock(_)) => { diff --git a/src/page.rs b/src/page.rs index f788aba3..721e8f11 100644 --- a/src/page.rs +++ b/src/page.rs @@ -73,10 +73,14 @@ pub struct Page { /// as summary pub summary: String, - /// The previous page, by date + /// The previous page, by date globally pub previous: Option>, + /// The previous page, by date only for the section the page is in + pub previous_in_section: Option>, /// The next page, by date pub next: Option>, + /// The next page, by date only for the section the page is in + pub next_in_section: Option>, } @@ -96,10 +100,16 @@ impl Page { summary: "".to_string(), meta: meta, previous: None, + previous_in_section: None, next: None, + next_in_section: None, } } + pub fn has_date(&self) -> bool { + self.meta.date.is_some() + } + /// Get word count and estimated reading time pub fn get_reading_analytics(&self) -> (usize, usize) { // Only works for latin language but good enough for a start @@ -257,6 +267,45 @@ impl PartialOrd for Page { } +/// Horribly inefficient way to set previous and next on each pages +/// So many clones +pub fn populate_previous_and_next_pages(input: &[Page], in_section: bool) -> Vec { + let pages = input.to_vec(); + let mut res = Vec::new(); + + // the input is sorted from most recent to least recent already + for (i, page) in input.iter().enumerate() { + let mut new_page = page.clone(); + + if new_page.has_date() { + if i > 0 { + let next = &pages[i - 1]; + if next.has_date() { + if in_section { + new_page.next_in_section = Some(Box::new(next.clone())); + } else { + new_page.next = Some(Box::new(next.clone())); + } + } + } + + if i < input.len() - 1 { + let previous = &pages[i + 1]; + if previous.has_date() { + if in_section { + new_page.previous_in_section = Some(Box::new(previous.clone())); + } else { + new_page.previous = Some(Box::new(previous.clone())); + } + } + } + } + res.push(new_page); + } + + res +} + #[cfg(test)] mod tests { use tempdir::TempDir; diff --git a/src/site.rs b/src/site.rs index c2914708..52bb76e7 100644 --- a/src/site.rs +++ b/src/site.rs @@ -10,7 +10,7 @@ use walkdir::WalkDir; use errors::{Result, ResultExt}; use config::{Config, get_config}; -use page::{Page}; +use page::{Page, populate_previous_and_next_pages}; use utils::{create_file, create_directory}; use section::{Section}; @@ -113,9 +113,9 @@ impl Site { let path = entry.as_path(); if path.file_name().unwrap() == "_index.md" { - self.add_section(&path)?; + self.add_section(path)?; } else { - self.add_page(&path)?; + self.add_page(path)?; } } @@ -156,6 +156,7 @@ impl Site { for (parent_path, section) in &mut self.sections { section.pages.sort_by(|a, b| a.partial_cmp(b).unwrap()); + section.pages = populate_previous_and_next_pages(section.pages.as_slice(), true); match grandparent_paths.get(parent_path) { Some(paths) => section.subsections.extend(paths.clone()), @@ -299,7 +300,7 @@ impl Site { copy(&asset_path, ¤t_path.join(asset_path.file_name().unwrap()))?; } - pages.push(page); + pages.push(page.clone()); } // Outputting categories and pages @@ -313,7 +314,8 @@ impl Site { // And finally the index page let mut context = Context::new(); pages.sort_by(|a, b| a.partial_cmp(b).unwrap()); - context.add("pages", &pages); + + context.add("pages", &populate_previous_and_next_pages(&pages, false)); context.add("config", &self.config); let index = self.templates.render("index.html", &context)?; create_file(public.join("index.html"), &self.inject_livereload(index))?; @@ -372,7 +374,7 @@ impl Site { // We sort by number of page in that category/tag let mut sorted_items = vec![]; for (item, count) in Vec::from_iter(items).into_iter().map(|(a, b)| (a, b.len())) { - sorted_items.push(ListItem::new(&item, count)); + sorted_items.push(ListItem::new(item, count)); } sorted_items.sort_by(|a, b| b.count.cmp(&a.count)); let mut context = Context::new(); @@ -386,7 +388,7 @@ impl Site { for (item_name, pages_paths) in items.iter() { let mut pages: Vec<&Page> = self.pages .iter() - .filter(|&(path, _)| pages_paths.contains(&path)) + .filter(|&(path, _)| pages_paths.contains(path)) .map(|(_, page)| page) .collect(); pages.sort_by(|a, b| a.partial_cmp(b).unwrap()); @@ -415,27 +417,23 @@ impl Site { context.add("sections", &self.sections.values().collect::>()); let mut categories = vec![]; - if self.config.generate_categories_pages.unwrap() { - if !self.categories.is_empty() { - categories.push(self.config.make_permalink("categories")); - for category in self.categories.keys() { - categories.push( - self.config.make_permalink(&format!("categories/{}", slugify(category))) - ); - } + if self.config.generate_categories_pages.unwrap() && !self.categories.is_empty() { + categories.push(self.config.make_permalink("categories")); + for category in self.categories.keys() { + categories.push( + self.config.make_permalink(&format!("categories/{}", slugify(category))) + ); } } context.add("categories", &categories); let mut tags = vec![]; - if self.config.generate_tags_pages.unwrap() { - if !self.tags.is_empty() { - tags.push(self.config.make_permalink("tags")); - for tag in self.tags.keys() { - tags.push( - self.config.make_permalink(&format!("tags/{}", slugify(tag))) - ); - } + if self.config.generate_tags_pages.unwrap() && !self.tags.is_empty() { + tags.push(self.config.make_permalink("tags")); + for tag in self.tags.keys() { + tags.push( + self.config.make_permalink(&format!("tags/{}", slugify(tag))) + ); } } context.add("tags", &tags); diff --git a/src/utils.rs b/src/utils.rs index 3068112d..6574c6fc 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -4,7 +4,6 @@ use std::path::Path; use errors::{Result, ResultExt}; - pub fn create_file>(path: P, content: &str) -> Result<()> { let mut file = File::create(&path)?; file.write_all(content.as_bytes())?; diff --git a/test_site/content/posts/fixed-slug.md b/test_site/content/posts/fixed-slug.md index 3eff97db..3f1216ff 100644 --- a/test_site/content/posts/fixed-slug.md +++ b/test_site/content/posts/fixed-slug.md @@ -2,6 +2,7 @@ title = "Fixed slug" description = "" slug = "something-else" +date = "2017-01-01" +++ A simple page with a slug defined diff --git a/test_site/content/posts/fixed-url.md b/test_site/content/posts/fixed-url.md index e51171ea..aed1d033 100644 --- a/test_site/content/posts/fixed-url.md +++ b/test_site/content/posts/fixed-url.md @@ -2,6 +2,7 @@ title = "Fixed URL" description = "" url = "a-fixed-url" +date = "2017-02-01" +++ A simple page with fixed url diff --git a/test_site/content/posts/python.md b/test_site/content/posts/python.md index ae5f25f2..b8d99b5a 100644 --- a/test_site/content/posts/python.md +++ b/test_site/content/posts/python.md @@ -1,6 +1,7 @@ +++ title = "Python in posts" description = "" +date = "2017-03-01" +++ Same filename but different path diff --git a/test_site/content/posts/simple.md b/test_site/content/posts/simple.md index 43bfcc60..53ce0ad6 100644 --- a/test_site/content/posts/simple.md +++ b/test_site/content/posts/simple.md @@ -1,6 +1,7 @@ +++ title = "Simple" description = "" +date = "2017-04-01" +++ A simple page diff --git a/test_site/content/posts/tutorials/devops/docker.md b/test_site/content/posts/tutorials/devops/docker.md index eb0073a9..85796b1a 100644 --- a/test_site/content/posts/tutorials/devops/docker.md +++ b/test_site/content/posts/tutorials/devops/docker.md @@ -1,6 +1,7 @@ +++ title = "Docker" description = "" +date = "2017-02-01" +++ A simple page diff --git a/test_site/content/posts/tutorials/devops/nix.md b/test_site/content/posts/tutorials/devops/nix.md index f12ccb62..4fdf3515 100644 --- a/test_site/content/posts/tutorials/devops/nix.md +++ b/test_site/content/posts/tutorials/devops/nix.md @@ -1,6 +1,7 @@ +++ title = "Nix" description = "" +date = "2017-03-01" +++ A simple page diff --git a/tests/site.rs b/tests/site.rs index 3c550ae7..2bb305fa 100644 --- a/tests/site.rs +++ b/tests/site.rs @@ -7,7 +7,6 @@ use std::path::Path; use std::fs::File; use std::io::prelude::*; -// use glob::glob; use tempdir::TempDir; use gutenberg::{Site}; @@ -41,6 +40,7 @@ fn test_can_parse_site() { // And that the sections are correct let posts_section = &site.sections[&posts_path]; assert_eq!(posts_section.subsections.len(), 1); + //println!("{:#?}", posts_section.pages); assert_eq!(posts_section.pages.len(), 5); let tutorials_section = &site.sections[&posts_path.join("tutorials")]; @@ -242,7 +242,7 @@ fn test_can_build_site_with_tags() { assert!(file_exists!(public, "sitemap.xml")); assert!(file_exists!(public, "robots.txt")); assert!(file_exists!(public, "a-fixed-url/index.html")); - + assert!(false); assert!(file_exists!(public, "posts/python/index.html")); assert!(file_exists!(public, "posts/tutorials/devops/nix/index.html")); assert!(file_exists!(public, "posts/with-assets/index.html"));