diff --git a/.travis.yml b/.travis.yml index 6b61378e..dece0531 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,7 +21,7 @@ matrix: rust: nightly # The earliest stable Rust version that works - env: TARGET=x86_64-unknown-linux-gnu - rust: 1.23.0 + rust: 1.27.0 before_install: set -e diff --git a/CHANGELOG.md b/CHANGELOG.md index da995014..8f304847 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # Changelog +## 0.4.0 (unreleased) + +### Breaking + +- Taxonomies have been rewritten from scratch to allow custom ones with RSS and pagination +- `order` sorting has been removed in favour of only having `weight` +- `page.next/page.previous` have been renamed to `page.later/page.earlier` and `page.heavier/page.lighter` depending on the sort method + +### Others +- Fix `serve` not working with the config flag +- Websocket port on `live` will not get the first available port instead of a fixed one +- Rewrite markdown rendering to fix all known issues with shortcodes +- Add array arguments to shortcodes and allow single-quote/backtick strings +- Co-located assets are now permalinks +- Words are now counted using unicode rather than whitespaces +- Aliases can now be pointing directly to specific HTML files +- Add `year`, `month` and `day` variables to pages with a date +- Fix panic when live reloading a change on a file without extensions +- Add image resizing support +- Add a 404 template +- Enable preserve-order feature of Tera +- Add an external link checker +- Add `get_taxonomy` global function to return the full taxonomy + ## 0.3.4 (2018-06-22) - `cargo update` as some dependencies didn't compile with current Rust version diff --git a/Cargo.lock b/Cargo.lock index e79010da..d8cadc11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,98 @@ +[[package]] +name = "actix" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "actix_derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-codec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-signal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "trust-dns-resolver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "actix-web" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "actix 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "h2 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "htmlescape 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazycell 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", + "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "actix_derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "adler32" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "aho-corasick" -version = "0.6.4" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -8,15 +100,15 @@ dependencies = [ [[package]] name = "ammonia" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "html5ever 0.22.3 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -37,7 +129,7 @@ dependencies = [ [[package]] name = "atty" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", @@ -47,13 +139,27 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.8" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -62,25 +168,16 @@ name = "backtrace-sys" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "base64" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "base64" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -89,7 +186,7 @@ name = "base64" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -98,8 +195,8 @@ name = "bincode" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -122,9 +219,14 @@ name = "bitflags" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "build_const" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "byteorder" -version = "1.2.3" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -134,26 +236,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bytes" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cc" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "chrono" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", @@ -163,36 +265,41 @@ dependencies = [ [[package]] name = "clap" -version = "2.31.2" +version = "2.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "cmake" -version = "0.1.31" +name = "cloudabi" +version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "color_quant" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "config" version = "0.1.0" dependencies = [ - "chrono 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "errors 0.1.0", - "globset 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "globset 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "highlighting 0.1.0", - "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -200,20 +307,67 @@ dependencies = [ name = "content" version = "0.1.0" dependencies = [ + "chrono 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "config 0.1.0", "errors 0.1.0", "front_matter 0.1.0", - "globset 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "globset 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "rendering 0.1.0", - "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "slug 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tera 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tera 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "utils 0.1.0", ] +[[package]] +name = "cookie" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "core-foundation" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "core-foundation-sys" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crc" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-channel" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-epoch 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-deque" version = "0.2.0" @@ -223,28 +377,76 @@ dependencies = [ "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-deque" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-epoch 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-epoch" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-epoch" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-utils" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-utils" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-utils" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ctrlc" version = "3.1.1" @@ -255,21 +457,28 @@ dependencies = [ ] [[package]] -name = "dtoa" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "duct" -version = "0.10.0" +name = "dbghelp-sys" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "os_pipe 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "shared_child 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "deflate" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "dtoa" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "either" version = "1.5.0" @@ -280,46 +489,148 @@ name = "elasticlunr-rs" version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "rust-stemmers 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "strum 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "strum_macros 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "strum_macros 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "encoding" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "encoding-index-japanese 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)", + "encoding-index-korean 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)", + "encoding-index-simpchinese 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)", + "encoding-index-singlebyte 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)", + "encoding-index-tradchinese 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "encoding-index-japanese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "encoding_index_tests 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "encoding-index-korean" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "encoding_index_tests 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "encoding-index-simpchinese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "encoding_index_tests 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "encoding-index-singlebyte" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "encoding_index_tests 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "encoding-index-tradchinese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "encoding_index_tests 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "encoding_index_tests" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "encoding_rs" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "error-chain" -version = "0.11.0" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "error-chain" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "error-chain" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "errors" version = "0.1.0" dependencies = [ - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tera 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tera 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "failure" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure_derive" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "filetime" version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "flate2" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", @@ -331,17 +642,30 @@ name = "fnv" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "front_matter" version = "0.1.0" dependencies = [ - "chrono 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "errors 0.1.0", - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", - "tera 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "tera 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -391,6 +715,20 @@ dependencies = [ "new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "futures" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-cpupool" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "gcc" version = "0.3.54" @@ -398,8 +736,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "getopts" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gif" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "glob" @@ -408,53 +758,77 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "globset" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "gutenberg" -version = "0.3.4" +version = "0.4.0" dependencies = [ - "chrono 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)", + "actix-web 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "content 0.1.0", "ctrlc 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "errors 0.1.0", "front_matter 0.1.0", - "iron 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "mount 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "notify 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "rebuild 0.1.0", "site 0.1.0", - "staticfile 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "term-painter 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "utils 0.1.0", "ws 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "h2" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "highlighting" version = "0.1.0" dependencies = [ - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syntect 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "hostname" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "winutil 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "html5ever" version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "markup5ever 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -462,9 +836,24 @@ dependencies = [ "syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "htmlescape" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "http" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "httparse" -version = "1.2.4" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -474,32 +863,96 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "hyper" -version = "0.10.13" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "want 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hyper-tls" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)", + "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "idna" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "image" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "gif 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jpeg-decoder 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-derive 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "png 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "imageproc" +version = "0.1.0" +dependencies = [ + "errors 0.1.0", + "image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 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.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tera 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", + "utils 0.1.0", +] + +[[package]] +name = "indexmap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "inflate" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "inotify" version = "0.3.0" @@ -518,25 +971,31 @@ dependencies = [ ] [[package]] -name = "iron" -version = "0.6.0" +name = "ipconfig" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "mime_guess 1.8.4 (registry+https://github.com/rust-lang/crates.io-index)", - "modifier 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "widestring 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winreg 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "itoa" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "jpeg-decoder" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -553,7 +1012,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "1.0.1" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -561,32 +1025,82 @@ name = "lazycell" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "lazycell" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "libc" version = "0.2.42" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "libflate" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "link_checker" +version = "0.1.0" +dependencies = [ + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "reqwest 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "linked-hash-map" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "linked-hash-map" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "log" -version = "0.3.9" +name = "lock_api" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "log" -version = "0.4.2" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "log" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lru-cache" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lzw" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "mac" version = "0.1.1" @@ -604,9 +1118,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "phf 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", "phf_codegen 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_codegen 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -614,7 +1128,7 @@ dependencies = [ [[package]] name = "matches" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -632,18 +1146,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "mime" -version = "0.2.6" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "mime_guess" -version = "1.8.4" +version = "2.0.0-alpha.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "phf 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", "phf_codegen 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -654,7 +1168,7 @@ name = "miniz-sys" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -667,7 +1181,7 @@ dependencies = [ "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", @@ -676,7 +1190,7 @@ dependencies = [ [[package]] name = "mio" -version = "0.6.14" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -685,20 +1199,30 @@ dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "mio-uds" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "miow" version = "0.1.5" 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)", - "net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -709,31 +1233,31 @@ version = "0.2.1" 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)", - "net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "modifier" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "mount" -version = "0.4.0" +name = "native-tls" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "iron 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sequence_trie 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", + "schannel 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "net2" -version = "0.2.32" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -755,27 +1279,14 @@ dependencies = [ "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "nix" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "nix" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -802,6 +1313,17 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "num-derive" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-integer" version = "0.1.39" @@ -810,6 +1332,24 @@ dependencies = [ "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "num-iter" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-rational" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-traits" version = "0.2.5" @@ -829,29 +1369,50 @@ version = "3.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "onig_sys 68.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "onig_sys 68.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "onig_sys" -version = "68.0.1" +version = "68.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", - "duct 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "os_pipe" -version = "0.6.1" +name = "openssl" +version = "0.9.24" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "nix 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.33 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "openssl-sys" +version = "0.9.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "owning_ref" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -862,12 +1423,42 @@ dependencies = [ "content 0.1.0", "errors 0.1.0", "front_matter 0.1.0", - "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", - "tera 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "taxonomies 0.1.0", + "tera 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", "utils 0.1.0", ] +[[package]] +name = "parking_lot" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot_core" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "percent-encoding" version = "1.0.1" @@ -919,13 +1510,13 @@ name = "phf_shared" version = "0.7.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pkg-config" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -934,18 +1525,21 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "plugin" -version = "0.2.6" +name = "png" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "deflate 0.7.18 (registry+https://github.com/rust-lang/crates.io-index)", + "inflate 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -963,7 +1557,7 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "0.4.6" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -975,9 +1569,14 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "quick-error" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "quote" version = "0.3.15" @@ -993,10 +1592,10 @@ dependencies = [ [[package]] name = "quote" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1010,24 +1609,41 @@ dependencies = [ ] [[package]] -name = "rayon" -version = "1.0.1" +name = "rand" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rayon" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon-core" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1040,7 +1656,7 @@ dependencies = [ "fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "highlighting 0.1.0", "site 0.1.0", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1058,24 +1674,12 @@ dependencies = [ [[package]] name = "regex" -version = "0.2.11" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1087,18 +1691,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "regex-syntax" -version = "0.5.6" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "regex-syntax" -version = "0.6.1" +name = "relay" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1113,33 +1717,68 @@ dependencies = [ name = "rendering" version = "0.1.0" dependencies = [ + "config 0.1.0", "errors 0.1.0", "front_matter 0.1.0", "highlighting 0.1.0", - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "link_checker 0.1.0", + "pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pest_derive 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "slug 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "syntect 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "templates 0.1.0", - "tera 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tera 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", "utils 0.1.0", ] +[[package]] +name = "reqwest" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "encoding_rs 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libflate 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_urlencoded 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "resolv-conf" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hostname 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rust-stemmers" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-demangle" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1171,9 +1810,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "schannel" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "scoped-tls" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "scoped_threadpool" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "scopeguard" version = "0.3.3" @@ -1183,41 +1841,68 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "search" version = "0.1.0" dependencies = [ - "ammonia 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ammonia 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "content 0.1.0", "elasticlunr-rs 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "errors 0.1.0", - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "sequence_trie" -version = "0.3.5" +name = "security-framework" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "security-framework-sys" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "serde" -version = "1.0.66" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.66" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.21" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", + "dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_urlencoded" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1225,19 +1910,9 @@ name = "sha1" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "shared_child" -version = "0.3.2" -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.42 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "siphasher" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1249,16 +1924,17 @@ dependencies = [ "errors 0.1.0", "front_matter 0.1.0", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "imageproc 0.1.0", "pagination 0.1.0", - "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "sass-rs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "search 0.1.0", - "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "taxonomies 0.1.0", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "templates 0.1.0", - "tera 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tera 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", "utils 0.1.0", ] @@ -1286,26 +1962,44 @@ dependencies = [ ] [[package]] -name = "staticfile" -version = "0.5.0" +name = "smallvec" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "iron 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "mount 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "socket2" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "stable_deref_trait" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "string" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "string_cache" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", "precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_codegen 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1339,11 +2033,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "strum_macros" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1368,11 +2063,11 @@ dependencies = [ [[package]] name = "syn" -version = "0.14.2" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1384,6 +2079,17 @@ dependencies = [ "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "synstructure" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "syntect" version = "2.1.0" @@ -1391,15 +2097,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "onig 3.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "plist 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "yaml-rust 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1412,10 +2118,10 @@ dependencies = [ "content 0.1.0", "errors 0.1.0", "front_matter 0.1.0", - "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "slug 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tera 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tera 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", "utils 0.1.0", ] @@ -1428,6 +2134,18 @@ dependencies = [ "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tempfile" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "templates" version = "0.1.0" @@ -1436,10 +2154,11 @@ dependencies = [ "config 0.1.0", "content 0.1.0", "errors 0.1.0", - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "imageproc 0.1.0", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "taxonomies 0.1.0", - "tera 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tera 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", "utils 0.1.0", ] @@ -1450,26 +2169,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "utf-8 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "utf-8 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tera" -version = "0.11.8" +version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "chrono 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "pest_derive 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "slug 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unic-segment 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1501,7 +2221,7 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1512,7 +2232,7 @@ name = "thread_local" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1526,43 +2246,292 @@ dependencies = [ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tokio" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-fs 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-udp 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-codec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-core" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", + "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-executor" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-fs" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-io" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-reactor" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-service" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-signal" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", + "mio-uds 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-tcp" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-threadpool" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-timer" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-tls" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-udp" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-codec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "toml" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "traitobject" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "typeable" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "typemap" -version = "0.3.3" +name = "trust-dns-proto" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-udp 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "trust-dns-resolver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "ipconfig 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "resolv-conf 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "trust-dns-proto 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "try-lock" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ucd-util" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unic-char-property" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unic-char-range 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unic-char-range" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unic-common" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unic-segment" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unic-ucd-segment 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unic-ucd-segment" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unic-char-property 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unic-char-range 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unic-ucd-version 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unic-ucd-version" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unic-common 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicase" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicase" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1570,7 +2539,7 @@ name = "unicode-bidi" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1578,6 +2547,11 @@ name = "unicode-normalization" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-segmentation" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-width" version = "0.1.5" @@ -1606,27 +2580,20 @@ dependencies = [ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "unsafe-any" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "url" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "utf-8" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1639,11 +2606,26 @@ name = "utils" version = "0.1.0" dependencies = [ "errors 0.1.0", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tera 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tera 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "uuid" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "vcpkg" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "vec_map" version = "0.8.1" @@ -1651,7 +2633,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "version_check" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1668,6 +2650,21 @@ dependencies = [ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "want" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "try-lock 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "widestring" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "winapi" version = "0.2.8" @@ -1697,20 +2694,36 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "winreg" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winutil" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ws" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1739,14 +2752,18 @@ dependencies = [ ] [metadata] -"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" -"checksum ammonia 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd4c682378117e4186a492b2252b9537990e1617f44aed9788b9a1149de45477" +"checksum actix 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0470f5163ac229ed0329f6abbd6f775591b06ec5ecbf2f2589c16ab8bd6f76b8" +"checksum actix-web 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "79d66c9405feacf1ee8fc3cff25725270724be376e433fbd17c099c93156395f" +"checksum actix_derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b9d1525ef45e5e021f0b93dace157dcab5d792acb4cc78f3213787d65e2bb92" +"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" +"checksum aho-corasick 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c1c6d463cbe7ed28720b5b489e7c083eeb8f90d08be2a0d6bb9e1ffea9ce1afa" +"checksum ammonia 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8b93ecb80665873703bf3b0a77f369c96b183d8e0afaf30a3ff5ff07dfc6409" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" -"checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1" -"checksum backtrace 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbdd17cd962b570302f5297aea8648d5923e22e555c2ed2d8b2e34eca646bf6d" +"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" +"checksum backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "346d7644f0b5f9bc73082d3b2236b69a05fd35cce0cfa3724e184e6a5c9e2a2f" +"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" "checksum backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "bff67d0c06556c0b8e6b5f090f0eac52d950d9dfd1d35ba04e4ca3543eaf6a7e" -"checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" "checksum base64 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c4a342b450b268e1be8036311e2c613d7f8a7ed31214dff1cc3b60852a3168d" "checksum base64 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "85415d2594767338a74a30c1d370b2f3262ec1b4ed2d7bba5b3faf4de40467d9" "checksum bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f2fb9e29e72fd6bc12071533d5dc7664cb01480c59406f656d7ac25c7bd8ff7" @@ -1754,81 +2771,134 @@ dependencies = [ "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" -"checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9" +"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" +"checksum byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8389c509ec62b9fe8eca58c502a0acaf017737355615243496cde4994f8fa4f9" "checksum bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c129aff112dcc562970abb69e2508b40850dd24c274761bb50fb8a0067ba6c27" -"checksum bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dd32989a66957d3f0cba6588f15d4281a733f4e9ffc43fcd2385f57d3bf99ff" -"checksum cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "49ec142f5768efb5b7622aebc3fdbdbb8950a4b9ba996393cb76ef7466e8747d" -"checksum cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "405216fd8fe65f718daa7102ea808a946b6ce40c742998fbfd3463645552de18" -"checksum chrono 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a81892f0d5a53f46fc05ef0b917305a81c13f1f13bb59ac91ff595817f0764b1" -"checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536" -"checksum cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "95470235c31c726d72bf2e1f421adc1e65b9d561bf5529612cbe1a72da1467b3" +"checksum bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e178b8e0e239e844b083d5a0d4a156b2654e67f9f80144d48398fcd736a24fb8" +"checksum cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "2119ea4867bd2b8ed3aecab467709720b2d55b1bcfe09f772fd68066eaf15275" +"checksum cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efe5c877e17a9c717a0bf3613b2709f723202c4e4675cc8f12926ded29bcb17e" +"checksum chrono 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e48d85528df61dc964aa43c5f6ca681a19cfa74939b2348d204bd08a981f2fb0" +"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbb57365263e881e805dc77d94697c9118fd94d8da011240555aa7b23445bd" +"checksum cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1465f8134efa296b4c19db34d909637cb2bf0f7aaf21299e23e18fa29ac557cf" +"checksum core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67" +"checksum core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "065a5d7ffdcbc8fa145d6f0746f3555025b9097a9e9cda59f7467abae670c78d" +"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" +"checksum crossbeam-channel 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "efff2d411e0ac3731b9f6de882b2790fdd2de651577500a806ce78b95b2b9f31" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" +"checksum crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fe8153ef04a7594ded05b427ffad46ddeaf22e63fd48d42b3e1e3bb4db07cae7" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" +"checksum crossbeam-epoch 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2af0e75710d6181e234c8ecc79f14a97907850a541b13b0be1dd10992f2e4620" +"checksum crossbeam-epoch 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "285987a59c4d91388e749850e3cb7b3a92299668528caaacd08005b8f238c0ea" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" +"checksum crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d636a8b3bcc1b409d7ffd3facef8f21dcb4009626adbd0c5e6c4305c07253c7b" +"checksum crossbeam-utils 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ea52fab26a99d96cdff39d0ca75c9716125937f5dba2ab83923aaaf5928f684a" "checksum ctrlc 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "630391922b1b893692c6334369ff528dcc3a9d8061ccf4c803aa8f83cb13db5e" -"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" -"checksum duct 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "166298c17c5b4fe5997b962c2f22e887c7c5adc44308eb9103ce5b66af45a423" +"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" +"checksum deflate 0.7.18 (registry+https://github.com/rust-lang/crates.io-index)" = "32c8120d981901a9970a3a1c97cf8b630e0fa8c3ca31e75b6fd6fd5f9f427b31" +"checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" "checksum elasticlunr-rs 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4837d77a1e157489a3933b743fd774ae75074e0e390b2b7f071530048a0d87ee" -"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" +"checksum encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec" +"checksum encoding-index-japanese 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91" +"checksum encoding-index-korean 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81" +"checksum encoding-index-simpchinese 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7" +"checksum encoding-index-singlebyte 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a" +"checksum encoding-index-tradchinese 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18" +"checksum encoding_index_tests 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" +"checksum encoding_rs 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98fd0f24d1fb71a4a6b9330c8ca04cbd4e7cc5d846b54ca74ff376bc7c9f798d" +"checksum error-chain 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faa976b4fd2e4c2b2f3f486874b19e61944d3de3de8b61c9fcf835d583871bcc" +"checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" +"checksum error-chain 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6930e04918388a9a2e41d518c25cf679ccafe26733fb4127dbf21993f2575d46" +"checksum failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7efb22686e4a466b1ec1a15c2898f91fa9cb340452496dca654032de20ff95b9" +"checksum failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "946d0e98a50d9831f5d589038d2ca7f8f455b1c21028c0db0e84116a12696426" "checksum filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "714653f3e34871534de23771ac7b26e999651a0a228f47beb324dfdf1dd4b10f" -"checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909" +"checksum flate2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "37847f133aae7acf82bb9577ccd8bda241df836787642654286e79679826a54b" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" +"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" "checksum fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674" "checksum fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "c4bbbf71584aeed076100b5665ac14e3d85eeb31fdbb45fbd41ef9a682b5ec05" "checksum fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a772d36c338d07a032d5375a36f15f9a7043bf0cb8ce7cee658e037c6032874" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b" +"checksum futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "884dbe32a6ae4cd7da5c6db9b78114449df9953b8d490c9d7e1b51720b922c62" +"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" -"checksum getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "b900c08c1939860ce8b54dc6a89e26e00c04c380fd0e09796799bd7f12861e05" +"checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797" +"checksum gif 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff3414b424657317e708489d2857d9575f4403698428b040b609b9d1c1a84a2c" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" -"checksum globset 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "142754da2c9b3722affd909f9e27f2a6700a7a303f362971e0a74c652005a43d" +"checksum globset 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8e49edbcc9c7fc5beb8c0a54e7319ff8bed353a2b55e85811c6281188c2a6c84" +"checksum h2 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "35754349586639c6ff629abd19a605e5a42599b0da4aff7be67d63e48ef1ba4e" +"checksum hostname 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "21ceb46a83a85e824ef93669c8b390009623863b5c195d1ba747292c0c72f94e" "checksum html5ever 0.22.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b04478cf718862650a0bf66acaf8f2f8c906fbc703f35c916c1f4211b069a364" -"checksum httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2f407128745b78abc95c0ffbe4e5d37427fdc0d45470710cfef8c44522a2e37" +"checksum htmlescape 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163" +"checksum http 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0d7f7b919d476c052ff46833ac89aaf205726da8133dae61facad50ec4c9eaec" +"checksum httparse 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7b6288d7db100340ca12873fd4d08ad1b8f206a9457798dfb17c018a33fee540" "checksum humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6cab2627acfc432780848602f3f558f7e9dd427352224b0d9324025796d2a5e" -"checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2" -"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" +"checksum hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)" = "34a590ca09d341e94cddf8e5af0bbccde205d5fbc2fa3c09dd67c7f85cea59d7" +"checksum hyper-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ffb1bd5e518d3065840ab315dbbf44e4420e5f7d80e2cb93fa6ffffc50522378" +"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +"checksum image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebdff791af04e30089bde8ad2a632b86af433b40c04db8d70ad4b21487db7a6a" +"checksum indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08173ba1e906efb6538785a8844dd496f5d34f0a2d88038e95195172fc667220" +"checksum inflate 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6f53b811ee8e2057ccf9643ca6b4277de90efaf5e61e55fd5254576926bb4245" "checksum inotify 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887fcc180136e77a85e6a6128579a719027b1bab9b1c38ea4444244fe262c20c" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" -"checksum iron 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d8e17268922834707e1c29e8badbf9c712c9c43378e1b6a3388946baff10be2" -"checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682" +"checksum ipconfig 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9ec4e18c0a0d4340870c14284293632d8421f419008371422dd327892b88877c" +"checksum itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5adb58558dcd1d786b5f0bd15f3226ee23486e24b7b58304b60f64dc68e62606" +"checksum jpeg-decoder 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c8b7d43206b34b3f94ea9445174bda196e772049b9bddbc620c9d29b2d20110d" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" -"checksum lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e6412c5e2ad9584b0b8e979393122026cdd6d2a80b933f890dcd694ddbe73739" +"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" +"checksum lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fb497c35d362b6a331cfd94956a07fc2c78a4604cdbee844a81170386b996dd3" "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" +"checksum lazycell 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d33a48d0365c96081958cc663eef834975cb1e8d8bea3378513fc72bdbf11e50" "checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1" +"checksum libflate 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "7d4b4c7aff5bac19b956f693d0ea0eade8066deb092186ae954fa6ba14daab98" +"checksum linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7860ec297f7008ff7a1e3382d7f7e1dcd69efc94751a2284bafc3d013c2aa939" "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" +"checksum lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "949826a5ccf18c1b3a7c3d57692778d21768b79e46eb9dd07bfc4c2160036c54" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" -"checksum log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6fddaa003a65722a7fb9e26b0ce95921fe4ba590542ced664d8ce2fa26f9f3ac" +"checksum log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "61bd98ae7f7b754bc53dca7d44b604f733c6bba044ea6f41bc8d89272d8161d2" +"checksum lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4d06ff7ff06f729ce5f4e227876cb88d10bc59cd4ae1e09fbb2bde15c850dc21" +"checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084" "checksum mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" "checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43" "checksum markup5ever 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfedc97d5a503e96816d10fedcd5b42f760b2e525ce2f7ec71f6a41780548475" -"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" +"checksum matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "835511bab37c34c47da5cb44844bea2cfde0236db0b506f90ea4224482c9774a" "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" -"checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" -"checksum mime_guess 1.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b7e2b09d08313f84e0fb82d13a4d859109a17543fe9af3b6d941dc1431f7de79" +"checksum mime 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fe51c8699d2dc522bf8c1ebe26ea2193d151fb54bcdfd7d0318750c189994cd9" +"checksum mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30de2e4613efcba1ec63d8133f344076952090c122992a903359be5a4f99c3ed" "checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4" "checksum mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a637d1ca14eacae06296a008fa7ad955347e34efcb5891cfd8ba05491a37907e" -"checksum mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "6d771e3ef92d58a8da8df7d6976bfca9371ed1de6619d9d5a5ce5b1f29b85bfe" +"checksum mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)" = "4fcfcb32d63961fb6f367bfd5d21e4600b92cd310f71f9dca25acae196eb1560" +"checksum mio-uds 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "84c7b5caa3a118a6e34dbac36504503b1e8dc5835e833306b9d6af0e05929f79" "checksum miow 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3e690c5df6b2f60acd45d56378981e827ff8295562fc8d34f573deb267a59cd1" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum modifier 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "41f5c9112cb662acd3b204077e0de5bc66305fa8df65c8019d5adb10e9ab6e58" -"checksum mount 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e25c06012941aaf8c75f2eaf7ec5c48cf69f9fc489ab3eb3589edc107e386f0b" -"checksum net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "9044faf1413a1057267be51b5afba8eb1090bd2231c693664aa1db716fe1eae0" +"checksum native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f74dbadc8b43df7864539cedb7bc91345e532fdd913cfdc23ad94f4d2d40fbc0" +"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" "checksum new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0cdc457076c78ab54d5e0d6fa7c47981757f1e34dc39ff92787f217dede586c4" -"checksum nix 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b7fd5681d13fda646462cfbd4e5f2051279a89a544d50eb98c365b507246839f" "checksum nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d37e713a259ff641624b6cb20e3b12b2952313ba36b6823c0f16e6cfd9e5de17" "checksum nix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bfb3ddedaa14746434a02041940495bf11325c22f6d36125d3bdd56090d50a79" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum notify 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5c3812da3098f210a0bb440f9c008471a031aa4c1de07a264fdd75456c95a4eb" +"checksum num-derive 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d2c31b75c36a993d30c7a13d70513cb93f02acafdd5b7ba250f9b0e18615de7" "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-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e" "checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum onig 3.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f5eeb268a4620c74ea5768c6d2ccd492d60a47a8754666b91a46bfc35cd4d1ba" -"checksum onig_sys 68.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c6be7c4f985508684e54f18dd37f71e66f3e1ad9318336a520d7e42f0d3ea8e" -"checksum os_pipe 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934868c3f86ed7a39ef63d88edeac5bd49a0c843192651900e9ce1178cbbf157" +"checksum onig_sys 68.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "48b1fc88a091cf46a8ec67a3cd3ffd55f75d3bed741c76f253d78746ec43602b" +"checksum openssl 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)" = "a3605c298474a3aa69de92d21139fb5e2a81688d308262359d85cdd0d12a7985" +"checksum openssl-sys 0.9.33 (registry+https://github.com/rust-lang/crates.io-index)" = "d8abc04833dcedef24221a91852931df2f63e3369ae003134e70aff3645775cc" +"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" +"checksum parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4d05f1349491390b1730afba60bb20d55761bef489a954546b58b4b34e1e2ac" +"checksum parking_lot 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "69376b761943787ebd5cc85a5bc95958651a22609c5c1c2b65de21786baec72b" +"checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0fce5d8b5cc33983fc74f78ad552b5522ab41442c4ca91606e4236eb4b5ceefc" "checksum pest_derive 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ab94faafeb93f4c5e3ce81ca0e5a779529a602ad5d09ae6d21996bfb8b6a52bf" @@ -1836,92 +2906,132 @@ dependencies = [ "checksum phf_codegen 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "4e4048fe7dd7a06b8127ecd6d3803149126e9b33c7558879846da3a63f734f2b" "checksum phf_generator 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "05a079dd052e7b674d21cb31cbb6c05efd56a2cd2827db7692e2f1a507ebd998" "checksum phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "c2261d544c2bb6aa3b10022b0be371b9c7c64f762ef28c6f5d4f1ef6d97b5930" -"checksum pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "110d5ee3593dbb73f56294327fe5668bcc997897097cbc76b51e7aed3f52452f" +"checksum pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "6a52e4dbc8354505ee07e484ab07127e06d87ca6fa7f0a516a2b294e5ad5ad16" "checksum plist 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c61ac2afed2856590ae79d6f358a24b85ece246d2aa134741a66d589519b7503" -"checksum plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a6a0dc3910bc8db877ffed8e457763b317cf880df4ae19109b9f77d277cf6e0" +"checksum png 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f54b9600d584d3b8a739e1662a595fab051329eff43f20e7d8cc22872962145b" "checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" "checksum proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1b06e2f335f48d24442b35a19df506a835fb3547bc3c06ef27340da9acf5cae7" -"checksum proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "effdb53b25cdad54f8f48843d67398f7ef2e14f12c1b4cb4effc549a6462a4d6" +"checksum proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "cccdc7557a98fe98453030f077df7f3a042052fae465bb61d2c2c41435cfd9b6" "checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32" +"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8" -"checksum quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e44651a0dc4cdd99f71c83b561e221f714912d11af1a4dff0631f923d53af035" +"checksum quote 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b71f9f575d55555aa9c06188be9d4e2bfc83ed02537948ac0d520c24d0419f1a" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" -"checksum rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80e811e76f1dbf68abf87a759083d34600017fc4e10b6bd5ad84a700f9dba4b1" -"checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8" +"checksum rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "12397506224b2f93e6664ffc4f664b29be8208e5157d3d90b44f09b5fae470ea" +"checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2" +"checksum rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "df7a791f788cb4c516f0e091301a29c2b71ef680db5e644a7d68835c8ae6dbfa" +"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" "checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384" -"checksum regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13c93d55961981ba9226a213b385216f83ab43bd6ac53ab16b2eeb47e337cf4e" +"checksum regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5bbbea44c5490a1e84357ff28b7d518b4619a159fed5d25f6c1de2d19cc42814" "checksum regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8e931c58b93d86f080c734bfd2bce7dd0079ae2331235818133c8be7f422e20e" -"checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7" -"checksum regex-syntax 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05b06a75f5217880fc5e905952a42750bf44787e56a6c6d6852ed0992f5e1d54" +"checksum regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "747ba3b235651f6e2f67dfa8bcdcd073ddb7c243cb21c442fc12395dfcac212d" +"checksum relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1576e382688d7e9deecea24417e350d3062d97e32e45d70b1cde65994ff1489a" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" +"checksum reqwest 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e7e237e32c3bfa55c95e29af872c8f481471d70b8a5ec15d85f4d274ffd92dd9" +"checksum resolv-conf 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c62bd95a41841efdf7fca2ae9951e64a8d8eae7e5da196d8ce489a2241491a92" "checksum rust-stemmers 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fbf06149ec391025664a5634200ced1afb489f0f3f8a140d515ebc0eb04b4bc0" -"checksum rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "76d7ba1feafada44f2d38eed812bd2489a03c0f5abb975799251518b68848649" +"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" "checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637" "checksum sass-rs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90f8cf6e645aa843ffffcbdc1e8752b1f221dfa314c81895aeb229a77aea7e05" "checksum sass-sys 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "bae88baa915f59c39820e544cfd9296d815a6b8efc3f276a78a0505866d2b4e9" +"checksum schannel 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "dc1fabf2a7b6483a141426e1afd09ad543520a77ac49bd03c286e7696ccfd77f" +"checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" +"checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" -"checksum sequence_trie 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "32157204e5c9d3c04007bd7e56e96e987635ce0e8e23c085b1e403861b76c351" -"checksum serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "e9a2d9a9ac5120e0f768801ca2b58ad6eec929dc9d1d616c162f208869c2ce95" -"checksum serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "0a90213fa7e0f5eac3f7afe2d5ff6b088af515052cc7303bd68c7e3b91a3fb79" -"checksum serde_json 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "eb40600c756f02d7ea34943626cefa85732fdae5f95b90b31f9797b3c526d1e6" +"checksum security-framework 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "dfa44ee9c54ce5eecc9de7d5acbad112ee58755239381f687e564004ba4a2332" +"checksum security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "5421621e836278a0b139268f36eee0dc7e389b784dc3f79d8f11aabadf41bead" +"checksum serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "0c3adf19c07af6d186d91dae8927b83b0553d07ca56cbf7f2f32560455c91920" +"checksum serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "3525a779832b08693031b8ecfb0de81cd71cfd3812088fafe9a7496789572124" +"checksum serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c6908c7b925cd6c590358a4034de93dbddb20c45e1d021931459fd419bf0e2" +"checksum serde_urlencoded 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e703cef904312097cfceab9ce131ff6bbe09e8c964a0703345a5f49238757bc1" "checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" -"checksum shared_child 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bcd5e483b3475af9bc2a35311c2f3bbf0bd98fde91410ab15a0d4ba3c3127b4e" -"checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537" +"checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" "checksum slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d807fd58c4181bbabed77cb3b891ba9748241a552bcc5be698faaebefc54f46e" "checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" "checksum slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdeff4cd9ecff59ec7e3744cbca73dfe5ac35c2aedb2cfba8a1c715a18912e9d" "checksum slug 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "797bcb4d24e91239a8615415814f4afb2d8ca400c472de3c73f803a5a7689e11" -"checksum staticfile 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "babd3fa68bb7e3994ce181c5f21ff3ff5fffef7b18b8a10163b45e4dafc6fb86" +"checksum smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "26df3bb03ca5eac2e64192b723d51f56c1b1e0860e7c766281f4598f181acdc8" +"checksum socket2 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "962a516af4d3a7c272cb3a1d50a8cc4e5b41802e4ad54cfb7bee8ba61d37d703" +"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" +"checksum string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00caf261d6f90f588f8450b8e1230fa0d5be49ee6140fdfbcb55335aff350970" "checksum string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423" "checksum string_cache_codegen 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35293b05cf1494e8ddd042a7df6756bf18d07f42d234f32e71dce8a7aabb0191" "checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum strum 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "099e21b5dd6dd07b5adcf8c4b723a7c0b7efd7a9359bf963d58c0caae8532545" -"checksum strum_macros 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd9bd569e88028750e3ae5c25616b8278ac16a8e61aba4339195c72396d49e1" +"checksum strum_macros 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1292d85e688e4696ecb69b2db2648994fb8af266974e89be53cefdf003861a5d" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)" = "14f9bf6292f3a61d2c716723fdb789a41bbe104168e6f496dc6497e531ea1b9b" -"checksum syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c67da57e61ebc7b7b6fff56bb34440ca3a83db037320b0507af4c10368deda7d" +"checksum syn 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4e4b5274d4a0a3d2749d5c158dc64d3403e60554dc61194648787ada5212473d" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" +"checksum synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb9b7550d063ea184027c9b8c20ac167cd36d3e06b3a40bceb9d746dc1a7b7" "checksum syntect 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dc8a6f0db88d4afc340522c20d260411e746b2225b257c6b238a75de9d7cec78" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" +"checksum tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c4b103c6d08d323b92ff42c8ce62abcd83ca8efa7fd5bf7927efefec75f58c76" "checksum tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9de21546595a0873061940d994bbbc5c35f024ae4fd61ec5c5b159115684f508" -"checksum tera 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fc0624177c585227fee0c5021bd6be3a1acf66bdb6f412acb92373637aad728b" +"checksum tera 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "7917c3acffc0ad65c40ef4c357277354051c45ed17303ceb874bc58e03c9fce1" "checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" "checksum term-painter 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "dcaa948f0e3e38470cd8dc8dcfe561a75c9e43f28075bb183845be2b9b3c08cf" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" +"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" "checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" +"checksum tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8ee337e5f4e501fc32966fec6fe0ca0cc1c237b0b1b14a335f8bfe3c5f06e286" +"checksum tokio-codec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "881e9645b81c2ce95fcb799ded2c29ffb9f25ef5bef909089a420e5961dd8ccb" +"checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" +"checksum tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8cac2a7883ff3567e9d66bb09100d09b33d90311feca0206c7ca034bc0c55113" +"checksum tokio-fs 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "40697ecbea5660df15b15d50a077386477d2f6a35002adf01ce76ff9dd9dce48" +"checksum tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a5c9635ee806f26d302b8baa1e145689a280d8f5aa8d0552e7344808da54cc21" +"checksum tokio-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e00ec63bbec2c97ce1178cb0587b2c438b2f6b09d3ee54a33c45a9cf0d530810" +"checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" +"checksum tokio-signal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "342d088c63623f63eada591e065778038c63b516939530db2aa09a8df9118507" +"checksum tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec9b094851aadd2caf83ba3ad8e8c4ce65a42104f7b94d9e6550023f0407853f" +"checksum tokio-threadpool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "24ab84f574027b0e875378f31575cf175360891919e93a3490f07e76e00e4efb" +"checksum tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "028b94314065b90f026a21826cffd62a4e40a92cda3e5c069cc7b02e5945f5e9" +"checksum tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "772f4b04e560117fe3b0a53e490c16ddc8ba6ec437015d91fa385564996ed913" +"checksum tokio-udp 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "43eb534af6e8f37d43ab1b612660df14755c42bd003c5f8d2475ee78cc4600c0" "checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9" -"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" -"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" -"checksum typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "653be63c80a3296da5551e1bfd2cca35227e13cdd08c6668903ae2f4f77aa1f6" +"checksum trust-dns-proto 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "32d7c204ee231f802aa821f9dc2195aa0d0269ef7e9f8c844208565c9e3981e4" +"checksum trust-dns-resolver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "28b094ad60c4f51f36a493201d04d6605183c62bd5f0c73008a732f23950c156" +"checksum try-lock 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2aa4715743892880f70885373966c83d73ef1b0838a664ef0c76fffd35e7c2" "checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" +"checksum unic-char-property 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce36d3f7ce754afdbccccf8ff0dd0134e50fb44aaae579f96218856e9e5dbd1e" +"checksum unic-char-range 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9ab85fab42ad1b26cafc03bf891f69cb4d6e15f491030e89a0122197baa8ae8" +"checksum unic-common 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff8d4a7ade929ef7d971e16ced21a8cd56a63869aa6032dfb8cb083cf7d077bf" +"checksum unic-segment 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ca47cbb09fb5fcd066b5867d11dc528302fa465277882797d6a836e1ee6f9e" +"checksum unic-ucd-segment 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "48f1a08ce0409a9e391b88d1930118eec48af12742fc538bcec55f775865776e" +"checksum unic-ucd-version 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1f5e6c6c53c2d0ece4a5964bc55fcff8602153063cb4fab20958ff32998ff6" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" +"checksum unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284b6d3db520d67fbe88fd778c21510d1b0ba4a551e5d0fbb023d33405f6de8a" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" +"checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unidecode 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "402bb19d8e03f1d1a7450e2bd613980869438e0666331be3e073089124aa1adc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f30360d7979f5e9c6e6cea48af192ea8fab4afb3cf72597154b8f08935bc9c7f" -"checksum url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7" -"checksum utf-8 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1262dfab4c30d5cb7c07026be00ee343a6cf5027fdc0104a9160f354e5db75c" +"checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6" +"checksum utf-8 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bab35f71693630bb1953dce0f2bcd780e7cde025027124a202ac08a45ba25141" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" +"checksum uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363" +"checksum vcpkg 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cbe533e138811704c0e3cbde65a818b35d3240409b4346256c5ede403e082474" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" -"checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d" +"checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369" +"checksum want 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a05d9d966753fa4b5c8db73fcab5eed4549cfe0e1e4e66911e5564a0085c35d1" +"checksum widestring 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7157704c2e12e3d2189c507b7482c52820a16dfa4465ba91add92f266667cadb" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum winreg 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a" +"checksum winutil 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7daf138b6b14196e3830a588acf1e86966c694d3e8fb026fb105b8b5dca07e6e" "checksum ws 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ccf752fee5350ca505fdb0b34d503b17d1528bd867561b7aa91d6ea750d5e972" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" "checksum xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2" diff --git a/Cargo.toml b/Cargo.toml index 43b5269c..3d485e98 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gutenberg" -version = "0.3.4" +version = "0.4.0" authors = ["Vincent Prouillet "] license = "MIT" readme = "README.md" @@ -24,9 +24,7 @@ term-painter = "0.2" # Used in init to ensure the url given as base_url is a valid one url = "1.5" # Below is for the serve cmd -staticfile = "0.5" -iron = "0.6" -mount = "0.4" +actix-web = { version = "0.7", default-features = false, features = [] } notify = "4" ws = "0.7" ctrlc = "3" @@ -53,4 +51,6 @@ members = [ "components/templates", "components/utils", "components/search", + "components/imageproc", + "components/link_checker", ] diff --git a/README.md b/README.md index 9ac213fd..f0637ed9 100644 --- a/README.md +++ b/README.md @@ -14,21 +14,24 @@ in the `docs/content` folder of the repository. | Single binary | ✔ | ✔ | ✔ | ✕ | | Language | Rust | Rust | Go | Python | | Syntax highlighting | ✔ | ✔ | ✔ | ✔ | -| Sass compilation | ✔ | ✕ | ✔ | ✔ | +| Sass compilation | ✔ | ✔ | ✔ | ✔ | | Assets co-location | ✔ | ✔ | ✔ | ✔ | | i18n | ✕ | ✕ | ✔ | ✔ | -| Image processing | ✕ | ✕ | ✔ | ✔ | +| Image processing | ✔ | ✕ | ✔ | ✔ | | Sane template engine | ✔ | ✔ | ✕✕✕ | ✔ | | Themes | ✔ | ✕ | ✔ | ✔ | | Shortcodes | ✔ | ✕ | ✔ | ✔ | | Internal links | ✔ | ✕ | ✔ | ✔ | +| Link checker | ✔ | ✕ | ✕ | ✔ | | Table of contents | ✔ | ✕ | ✔ | ✔ | | Automatic header anchors | ✔ | ✕ | ✔ | ✔ | | Aliases | ✔ | ✕ | ✔ | ✔ | | Pagination | ✔ | ✕ | ✔ | ✔ | -| Custom taxonomies | ✕ | ✕ | ✔ | ✕ | +| Custom taxonomies | ✔ | ✕ | ✔ | ✕ | | Search | ✔ | ✕ | ✕ | ✔ | | Data files | ✕ | ✔ | ✔ | ✕ | +| LiveReload | ✔ | ✕ | ✔ | ✔ | +| Netlify support | ✔ | ✕ | ✔ | ✕ | Supported content formats: @@ -38,7 +41,8 @@ Supported content formats: - Pelican: reStructuredText, markdown, asciidoc, org-mode, whatever-you-want Note that many features of Pelican are coming from plugins, which might be tricky -to use because of version mismatch or lacking documentation. +to use because of version mismatch or lacking documentation. Netlify supports Python +and Pipenv but you still need to install your dependencies manually. ## Contributing As the documentation site is automatically built on commits to master, all development @@ -52,7 +56,7 @@ If you want a feature added or modified, please open an issue to discuss it befo Syntax highlighting depends on submodules so ensure you load them first: ```bash -$ git submodule update --init +$ git submodule update --init ``` Gutenberg only works with syntaxes in the `.sublime-syntax` format. If your syntax @@ -75,7 +79,7 @@ You can check for any updates to the current packages by running: $ git submodule update --remote --merge ``` -And finally from the root of the components/rendering crate run the following command: +And finally from the root of the components/highlighting crate run the following command: ```bash $ cargo run --example generate_sublime synpack ../../sublime_syntaxes ../../sublime_syntaxes/newlines.packdump ../../sublime_syntaxes/nonewlines.packdump diff --git a/appveyor.yml b/appveyor.yml index f39c6a8f..1f6418e7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,7 +10,7 @@ environment: matrix: - target: x86_64-pc-windows-msvc - RUST_VERSION: 1.25.0 + RUST_VERSION: 1.27.0 - target: x86_64-pc-windows-msvc RUST_VERSION: stable diff --git a/components/config/src/lib.rs b/components/config/src/lib.rs index 6c6951e2..40b4ff16 100644 --- a/components/config/src/lib.rs +++ b/components/config/src/lib.rs @@ -12,7 +12,7 @@ use std::fs::File; use std::io::prelude::*; use std::path::{Path, PathBuf}; -use toml::{Value as Toml}; +use toml::Value as Toml; use chrono::Utc; use globset::{Glob, GlobSet, GlobSetBuilder}; @@ -28,6 +28,40 @@ use theme::Theme; static DEFAULT_BASE_URL: &'static str = "http://a-website.com"; +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(default)] +pub struct Taxonomy { + /// The name used in the URL, usually the plural + pub name: String, + /// If this is set, the list of individual taxonomy term page will be paginated + /// by this much + pub paginate_by: Option, + pub paginate_path: Option, + /// Whether to generate a RSS feed only for each taxonomy term, defaults to false + pub rss: bool, +} + +impl Taxonomy { + pub fn is_paginated(&self) -> bool { + if let Some(paginate_by) = self.paginate_by { + paginate_by > 0 + } else { + false + } + } +} + +impl Default for Taxonomy { + fn default() -> Taxonomy { + Taxonomy { + name: String::new(), + paginate_by: None, + paginate_path: None, + rss: false, + } + } +} + #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(default)] pub struct Config { @@ -56,10 +90,8 @@ pub struct Config { pub generate_rss: bool, /// The number of articles to include in the RSS feed. Defaults to 10_000 pub rss_limit: usize, - /// Whether to generate tags and individual tag pages if some pages have them. Defaults to true - pub generate_tags_pages: bool, - /// Whether to generate categories and individual tag categories if some pages have them. Defaults to true - pub generate_categories_pages: bool, + + pub taxonomies: Vec, /// Whether to compile the `sass` directory and output the css files into the static folder pub compile_sass: bool, @@ -72,6 +104,9 @@ pub struct Config { #[serde(skip_serializing, skip_deserializing)] // not a typo, 2 are needed pub ignored_content_globset: Option, + /// Whether to check all external links for validity + pub check_external_links: bool, + /// All user params set in [extra] in the config pub extra: HashMap, @@ -191,9 +226,9 @@ impl Default for Config { default_language: "en".to_string(), generate_rss: false, rss_limit: 10_000, - generate_tags_pages: true, - generate_categories_pages: true, + taxonomies: Vec::new(), compile_sass: false, + check_external_links: false, build_search_index: false, ignored_content: Vec::new(), ignored_content_globset: None, diff --git a/components/config/src/theme.rs b/components/config/src/theme.rs index 7c054912..9d4c5ada 100644 --- a/components/config/src/theme.rs +++ b/components/config/src/theme.rs @@ -3,7 +3,7 @@ use std::fs::File; use std::io::prelude::*; use std::path::PathBuf; -use toml::{Value as Toml}; +use toml::Value as Toml; use errors::{Result, ResultExt}; @@ -37,7 +37,7 @@ impl Theme { } - Ok(Theme {extra}) + Ok(Theme { extra }) } /// Parses a theme file from the given path diff --git a/components/content/Cargo.toml b/components/content/Cargo.toml index 73aaabff..ca8cffed 100644 --- a/components/content/Cargo.toml +++ b/components/content/Cargo.toml @@ -8,6 +8,7 @@ tera = "0.11" serde = "1" slug = "0.1" rayon = "1" +chrono = "0.4" errors = { path = "../errors" } config = { path = "../config" } @@ -16,6 +17,6 @@ rendering = { path = "../rendering" } front_matter = { path = "../front_matter" } [dev-dependencies] -tempdir = "0.3" +tempfile = "3" toml = "0.4" globset = "0.4" diff --git a/components/content/benches/all.rs b/components/content/benches/all.rs index cb80fdbb..b6974d87 100644 --- a/components/content/benches/all.rs +++ b/components/content/benches/all.rs @@ -11,7 +11,7 @@ use std::collections::HashMap; use config::Config; use tera::Tera; use front_matter::{SortBy, InsertAnchor}; -use content::{Page, sort_pages, populate_previous_and_next_pages}; +use content::{Page, sort_pages, populate_siblings}; fn create_pages(number: usize, sort_by: SortBy) -> Vec { @@ -23,8 +23,8 @@ fn create_pages(number: usize, sort_by: SortBy) -> Vec { for i in 0..number { let mut page = Page::default(); match sort_by { - SortBy::Weight => { page.meta.weight = Some(i); }, - SortBy::Order => { page.meta.order = Some(i); }, + SortBy::Weight => { page.meta.weight = Some(i); } + SortBy::Order => { page.meta.order = Some(i); } _ => (), }; page.raw_content = r#" @@ -128,17 +128,17 @@ fn bench_sorting_order(b: &mut test::Bencher) { } #[bench] -fn bench_populate_previous_and_next_pages(b: &mut test::Bencher) { +fn bench_populate_siblings(b: &mut test::Bencher) { let pages = create_pages(250, SortBy::Order); let (sorted_pages, _) = sort_pages(pages, SortBy::Order); - b.iter(|| populate_previous_and_next_pages(&sorted_pages.clone())); + b.iter(|| populate_siblings(&sorted_pages.clone())); } #[bench] fn bench_page_render_html(b: &mut test::Bencher) { let pages = create_pages(10, SortBy::Order); let (mut sorted_pages, _) = sort_pages(pages, SortBy::Order); - sorted_pages = populate_previous_and_next_pages(&sorted_pages); + sorted_pages = populate_siblings(&sorted_pages); let config = Config::default(); let mut tera = Tera::default(); diff --git a/components/content/src/lib.rs b/components/content/src/lib.rs index b3a45183..11bfcc85 100644 --- a/components/content/src/lib.rs +++ b/components/content/src/lib.rs @@ -2,6 +2,7 @@ extern crate tera; extern crate slug; extern crate serde; extern crate rayon; +extern crate chrono; extern crate errors; extern crate config; @@ -10,7 +11,7 @@ extern crate rendering; extern crate utils; #[cfg(test)] -extern crate tempdir; +extern crate tempfile; #[cfg(test)] extern crate toml; #[cfg(test)] @@ -25,4 +26,4 @@ mod sorting; pub use file_info::FileInfo; pub use page::Page; pub use section::Section; -pub use sorting::{sort_pages, populate_previous_and_next_pages}; +pub use sorting::{sort_pages, populate_siblings}; diff --git a/components/content/src/page.rs b/components/content/src/page.rs index 7b403244..c0c6cb1c 100644 --- a/components/content/src/page.rs +++ b/components/content/src/page.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; use std::result::Result as StdResult; - +use chrono::Datelike; use tera::{Tera, Context as TeraContext}; use serde::ser::{SerializeStruct, self}; use slug::slugify; @@ -14,7 +14,7 @@ use utils::fs::{read_file, find_related_assets}; use utils::site::get_reading_analytics; use utils::templates::render_template; use front_matter::{PageFrontMatter, InsertAnchor, split_page_content}; -use rendering::{Context, Header, markdown_to_html}; +use rendering::{RenderContext, Header, render_content}; use file_info::FileInfo; @@ -44,10 +44,14 @@ pub struct Page { /// When is found in the text, will take the content up to that part /// as summary pub summary: Option, - /// The previous page, by whatever sorting is used for the index/section - pub previous: Option>, - /// The next page, by whatever sorting is used for the index/section - pub next: Option>, + /// The earlier page, for pages sorted by date + pub earlier: Option>, + /// The later page, for pages sorted by date + pub later: Option>, + /// The lighter page, for pages sorted by weight + pub lighter: Option>, + /// The heavier page, for pages sorted by weight + pub heavier: Option>, /// Toc made from the headers of the markdown file pub toc: Vec
, } @@ -68,8 +72,10 @@ impl Page { components: vec![], permalink: "".to_string(), summary: None, - previous: None, - next: None, + earlier: None, + later: None, + lighter: None, + heavier: None, toc: vec![], } } @@ -156,27 +162,32 @@ impl Page { } Ok(page) - } /// We need access to all pages url to render links relative to content /// so that can't happen at the same time as parsing pub fn render_markdown(&mut self, permalinks: &HashMap, tera: &Tera, config: &Config, anchor_insert: InsertAnchor) -> Result<()> { - let context = Context::new( + let mut context = RenderContext::new( tera, - config.highlight_code, - config.highlight_theme.clone(), + config, &self.permalink, permalinks, - anchor_insert + anchor_insert, ); - let res = markdown_to_html(&self.raw_content.replacen("", "", 1), &context)?; + + context.tera_context.add("page", self); + + let res = render_content( + &self.raw_content.replacen("", "", 1), + &context, + ).chain_err(|| format!("Failed to render content of {}", self.file.path.display()))?; self.content = res.0; self.toc = res.1; if self.raw_content.contains("") { self.summary = Some({ let summary = self.raw_content.splitn(2, "").collect::>()[0]; - markdown_to_html(summary, &context)?.0 + render_content(summary, &context) + .chain_err(|| format!("Failed to render content of {}", self.file.path.display()))?.0 }) } @@ -199,6 +210,15 @@ impl Page { render_template(&tpl_name, tera, &context, &config.theme) .chain_err(|| format!("Failed to render page '{}'", self.file.path.display())) } + + /// Creates a vectors of asset URLs. + fn serialize_assets(&self) -> Vec { + self.assets.iter() + .filter_map(|asset| asset.file_name()) + .filter_map(|filename| filename.to_str()) + .map(|filename| self.path.clone() + filename) + .collect() + } } impl Default for Page { @@ -214,8 +234,10 @@ impl Default for Page { components: vec![], permalink: "".to_string(), summary: None, - previous: None, - next: None, + earlier: None, + later: None, + lighter: None, + heavier: None, toc: vec![], } } @@ -223,26 +245,39 @@ impl Default for Page { impl ser::Serialize for Page { fn serialize(&self, serializer: S) -> StdResult where S: ser::Serializer { - let mut state = serializer.serialize_struct("page", 18)?; + let mut state = serializer.serialize_struct("page", 20)?; state.serialize_field("content", &self.content)?; state.serialize_field("title", &self.meta.title)?; state.serialize_field("description", &self.meta.description)?; state.serialize_field("date", &self.meta.date)?; + if let Some(chrono_datetime) = self.meta.date() { + let d = chrono_datetime.date(); + state.serialize_field("year", &d.year())?; + state.serialize_field("month", &d.month())?; + state.serialize_field("day", &d.day())?; + } else { + state.serialize_field::>("year", &None)?; + state.serialize_field::>("month", &None)?; + state.serialize_field::>("day", &None)?; + } state.serialize_field("slug", &self.slug)?; state.serialize_field("path", &self.path)?; state.serialize_field("components", &self.components)?; state.serialize_field("permalink", &self.permalink)?; state.serialize_field("summary", &self.summary)?; - state.serialize_field("tags", &self.meta.tags)?; - state.serialize_field("category", &self.meta.category)?; + state.serialize_field("taxonomies", &self.meta.taxonomies)?; state.serialize_field("extra", &self.meta.extra)?; let (word_count, reading_time) = get_reading_analytics(&self.raw_content); state.serialize_field("word_count", &word_count)?; state.serialize_field("reading_time", &reading_time)?; - state.serialize_field("previous", &self.previous)?; - state.serialize_field("next", &self.next)?; + state.serialize_field("earlier", &self.earlier)?; + state.serialize_field("later", &self.later)?; + state.serialize_field("lighter", &self.lighter)?; + state.serialize_field("heavier", &self.heavier)?; state.serialize_field("toc", &self.toc)?; state.serialize_field("draft", &self.is_draft())?; + let assets = self.serialize_assets(); + state.serialize_field("assets", &assets)?; state.end() } } @@ -255,7 +290,7 @@ mod tests { use std::path::Path; use tera::Tera; - use tempdir::TempDir; + use tempfile::tempdir; use globset::{Glob, GlobSetBuilder}; use config::Config; @@ -387,7 +422,7 @@ Hello world #[test] fn page_with_assets_gets_right_info() { - let tmp_dir = TempDir::new("example").expect("create temp dir"); + 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"); @@ -401,7 +436,7 @@ Hello world let res = Page::from_file( nested_path.join("index.md").as_path(), - &Config::default() + &Config::default(), ); assert!(res.is_ok()); let page = res.unwrap(); @@ -413,7 +448,7 @@ Hello world #[test] fn page_with_assets_and_slug_overrides_path() { - let tmp_dir = TempDir::new("example").expect("create temp dir"); + 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"); @@ -427,7 +462,7 @@ Hello world let res = Page::from_file( nested_path.join("index.md").as_path(), - &Config::default() + &Config::default(), ); assert!(res.is_ok()); let page = res.unwrap(); @@ -439,7 +474,7 @@ Hello world #[test] fn page_with_ignored_assets_filters_out_correct_files() { - let tmp_dir = TempDir::new("example").expect("create temp dir"); + 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"); @@ -458,7 +493,7 @@ Hello world let res = Page::from_file( nested_path.join("index.md").as_path(), - &config + &config, ); assert!(res.is_ok()); diff --git a/components/content/src/section.rs b/components/content/src/section.rs index b75581c6..58567f32 100644 --- a/components/content/src/section.rs +++ b/components/content/src/section.rs @@ -11,7 +11,7 @@ use errors::{Result, ResultExt}; use utils::fs::read_file; use utils::templates::render_template; use utils::site::get_reading_analytics; -use rendering::{Context, Header, markdown_to_html}; +use rendering::{RenderContext, Header, render_content}; use page::Page; use file_info::FileInfo; @@ -91,22 +91,25 @@ impl Section { return "index.html".to_string(); } "section.html".to_string() - }, + } } } /// We need access to all pages url to render links relative to content /// so that can't happen at the same time as parsing pub fn render_markdown(&mut self, permalinks: &HashMap, tera: &Tera, config: &Config) -> Result<()> { - let context = Context::new( + let mut context = RenderContext::new( tera, - config.highlight_code, - config.highlight_theme.clone(), + config, &self.permalink, permalinks, self.meta.insert_anchor_links, ); - let res = markdown_to_html(&self.raw_content, &context)?; + + context.tera_context.add("section", self); + + let res = render_content(&self.raw_content, &context) + .chain_err(|| format!("Failed to render content of {}", self.file.path.display()))?; self.content = res.0; self.toc = res.1; Ok(()) diff --git a/components/content/src/sorting.rs b/components/content/src/sorting.rs index b96c6b1d..bf1f1751 100644 --- a/components/content/src/sorting.rs +++ b/components/content/src/sorting.rs @@ -7,11 +7,11 @@ use front_matter::SortBy; /// Sort pages by the given criteria /// -/// Any pages that doesn't have a the required field when the sorting method is other than none +/// Any pages that doesn't have a required field when the sorting method is other than none /// will be ignored. pub fn sort_pages(pages: Vec, sort_by: SortBy) -> (Vec, Vec) { if sort_by == SortBy::None { - return (pages, vec![]); + return (pages, vec![]); } let (mut can_be_sorted, cannot_be_sorted): (Vec<_>, Vec<_>) = pages @@ -19,7 +19,6 @@ pub fn sort_pages(pages: Vec, sort_by: SortBy) -> (Vec, Vec) { .partition(|page| { match sort_by { SortBy::Date => page.meta.date.is_some(), - SortBy::Order => page.meta.order.is_some(), SortBy::Weight => page.meta.weight.is_some(), _ => unreachable!() } @@ -35,17 +34,7 @@ pub fn sort_pages(pages: Vec, sort_by: SortBy) -> (Vec, Vec) { ord } }) - }, - SortBy::Order => { - can_be_sorted.par_sort_unstable_by(|a, b| { - let ord = b.meta.order().cmp(&a.meta.order()); - if ord == Ordering::Equal { - a.permalink.cmp(&b.permalink) - } else { - ord - } - }) - }, + } SortBy::Weight => { can_be_sorted.par_sort_unstable_by(|a, b| { let ord = a.meta.weight().cmp(&b.meta.weight()); @@ -55,7 +44,7 @@ pub fn sort_pages(pages: Vec, sort_by: SortBy) -> (Vec, Vec) { ord } }) - }, + } _ => unreachable!() }; @@ -64,7 +53,7 @@ pub fn sort_pages(pages: Vec, sort_by: SortBy) -> (Vec, Vec) { /// Horribly inefficient way to set previous and next on each pages that skips drafts /// So many clones -pub fn populate_previous_and_next_pages(input: &[Page]) -> Vec { +pub fn populate_siblings(input: &[Page], sort_by: SortBy) -> Vec { let mut res = Vec::with_capacity(input.len()); // The input is already sorted @@ -91,9 +80,20 @@ pub fn populate_previous_and_next_pages(input: &[Page]) -> Vec { // Remove prev/next otherwise we serialise the whole thing... let mut next_page = input[j].clone(); - next_page.previous = None; - next_page.next = None; - new_page.next = Some(Box::new(next_page)); + + match sort_by { + SortBy::Weight => { + next_page.lighter = None; + next_page.heavier = None; + new_page.lighter = Some(Box::new(next_page)); + } + SortBy::Date => { + next_page.earlier = None; + next_page.later = None; + new_page.later = Some(Box::new(next_page)); + } + SortBy::None => () + } break; } } @@ -113,9 +113,19 @@ pub fn populate_previous_and_next_pages(input: &[Page]) -> Vec { // Remove prev/next otherwise we serialise the whole thing... let mut previous_page = input[j].clone(); - previous_page.previous = None; - previous_page.next = None; - new_page.previous = Some(Box::new(previous_page)); + match sort_by { + SortBy::Weight => { + previous_page.lighter = None; + previous_page.heavier = None; + new_page.heavier = Some(Box::new(previous_page)); + } + SortBy::Date => { + previous_page.earlier = None; + previous_page.later = None; + new_page.earlier = Some(Box::new(previous_page)); + } + SortBy::None => {} + } break; } } @@ -129,7 +139,7 @@ pub fn populate_previous_and_next_pages(input: &[Page]) -> Vec { mod tests { use front_matter::{PageFrontMatter, SortBy}; use page::Page; - use super::{sort_pages, populate_previous_and_next_pages}; + use super::{sort_pages, populate_siblings}; fn create_page_with_date(date: &str) -> Page { let mut front_matter = PageFrontMatter::default(); @@ -137,22 +147,6 @@ mod tests { Page::new("content/hello.md", front_matter) } - fn create_page_with_order(order: usize, filename: &str) -> Page { - let mut front_matter = PageFrontMatter::default(); - front_matter.order = Some(order); - let mut p = Page::new("content/".to_string() + filename, front_matter); - // Faking a permalink to test sorting with equal order - p.permalink = filename.to_string(); - p - } - - fn create_draft_page_with_order(order: usize) -> Page { - let mut front_matter = PageFrontMatter::default(); - front_matter.order = Some(order); - front_matter.draft = true; - Page::new("content/hello.md", front_matter) - } - fn create_page_with_weight(weight: usize) -> Page { let mut front_matter = PageFrontMatter::default(); front_matter.weight = Some(weight); @@ -173,37 +167,6 @@ mod tests { assert_eq!(pages[2].clone().meta.date.unwrap().to_string(), "2017-01-01"); } - #[test] - fn can_sort_by_order() { - let input = vec![ - create_page_with_order(2, "hello.md"), - create_page_with_order(3, "hello2.md"), - create_page_with_order(1, "hello3.md"), - ]; - let (pages, _) = sort_pages(input, SortBy::Order); - // Should be sorted by order - assert_eq!(pages[0].clone().meta.order.unwrap(), 3); - assert_eq!(pages[1].clone().meta.order.unwrap(), 2); - assert_eq!(pages[2].clone().meta.order.unwrap(), 1); - } - - #[test] - fn can_sort_by_order_uses_permalink_to_break_ties() { - let input = vec![ - create_page_with_order(3, "b.md"), - create_page_with_order(3, "a.md"), - create_page_with_order(3, "c.md"), - ]; - let (pages, _) = sort_pages(input, SortBy::Order); - // Should be sorted by order - assert_eq!(pages[0].clone().meta.order.unwrap(), 3); - assert_eq!(pages[0].clone().permalink, "a.md"); - assert_eq!(pages[1].clone().meta.order.unwrap(), 3); - assert_eq!(pages[1].clone().permalink, "b.md"); - assert_eq!(pages[2].clone().meta.order.unwrap(), 3); - assert_eq!(pages[2].clone().permalink, "c.md"); - } - #[test] fn can_sort_by_weight() { let input = vec![ @@ -221,80 +184,48 @@ mod tests { #[test] fn can_sort_by_none() { let input = vec![ - create_page_with_order(2, "a.md"), - create_page_with_order(3, "a.md"), - create_page_with_order(1, "a.md"), + create_page_with_weight(2), + create_page_with_weight(3), + create_page_with_weight(1), ]; let (pages, _) = sort_pages(input, SortBy::None); - // Should be sorted by date - assert_eq!(pages[0].clone().meta.order.unwrap(), 2); - assert_eq!(pages[1].clone().meta.order.unwrap(), 3); - assert_eq!(pages[2].clone().meta.order.unwrap(), 1); + assert_eq!(pages[0].clone().meta.weight.unwrap(), 2); + assert_eq!(pages[1].clone().meta.weight.unwrap(), 3); + assert_eq!(pages[2].clone().meta.weight.unwrap(), 1); } #[test] fn ignore_page_with_missing_field() { let input = vec![ - create_page_with_order(2, "a.md"), - create_page_with_order(3, "a.md"), + create_page_with_weight(2), + create_page_with_weight(3), create_page_with_date("2019-01-01"), ]; - let (pages, unsorted) = sort_pages(input, SortBy::Order); + let (pages, unsorted) = sort_pages(input, SortBy::Weight); assert_eq!(pages.len(), 2); assert_eq!(unsorted.len(), 1); } #[test] - fn can_populate_previous_and_next_pages() { + fn can_populate_siblings() { let input = vec![ - create_page_with_order(1, "a.md"), - create_page_with_order(2, "b.md"), - create_page_with_order(3, "a.md"), + create_page_with_weight(1), + create_page_with_weight(2), + create_page_with_weight(3), ]; - let pages = populate_previous_and_next_pages(&input); + let pages = populate_siblings(&input, SortBy::Weight); - assert!(pages[0].clone().next.is_none()); - assert!(pages[0].clone().previous.is_some()); - assert_eq!(pages[0].clone().previous.unwrap().meta.order.unwrap(), 2); + assert!(pages[0].clone().lighter.is_none()); + assert!(pages[0].clone().heavier.is_some()); + assert_eq!(pages[0].clone().heavier.unwrap().meta.weight.unwrap(), 2); - assert!(pages[1].clone().next.is_some()); - assert!(pages[1].clone().previous.is_some()); - assert_eq!(pages[1].clone().previous.unwrap().meta.order.unwrap(), 3); - assert_eq!(pages[1].clone().next.unwrap().meta.order.unwrap(), 1); + assert!(pages[1].clone().heavier.is_some()); + assert!(pages[1].clone().lighter.is_some()); + assert_eq!(pages[1].clone().lighter.unwrap().meta.weight.unwrap(), 1); + assert_eq!(pages[1].clone().heavier.unwrap().meta.weight.unwrap(), 3); - assert!(pages[2].clone().next.is_some()); - assert!(pages[2].clone().previous.is_none()); - assert_eq!(pages[2].clone().next.unwrap().meta.order.unwrap(), 2); - } - - #[test] - fn can_populate_previous_and_next_pages_skip_drafts() { - let input = vec![ - create_draft_page_with_order(0), - create_page_with_order(1, "a.md"), - create_page_with_order(2, "b.md"), - create_page_with_order(3, "c.md"), - create_draft_page_with_order(4), - ]; - let pages = populate_previous_and_next_pages(&input); - - assert!(pages[0].clone().next.is_none()); - assert!(pages[0].clone().previous.is_none()); - - assert!(pages[1].clone().next.is_none()); - assert!(pages[1].clone().previous.is_some()); - assert_eq!(pages[1].clone().previous.unwrap().meta.order.unwrap(), 2); - - assert!(pages[2].clone().next.is_some()); - assert!(pages[2].clone().previous.is_some()); - assert_eq!(pages[2].clone().previous.unwrap().meta.order.unwrap(), 3); - assert_eq!(pages[2].clone().next.unwrap().meta.order.unwrap(), 1); - - assert!(pages[3].clone().next.is_some()); - assert!(pages[3].clone().previous.is_none()); - assert_eq!(pages[3].clone().next.unwrap().meta.order.unwrap(), 2); - - assert!(pages[4].clone().next.is_none()); - assert!(pages[4].clone().previous.is_none()); + assert!(pages[2].clone().lighter.is_some()); + assert!(pages[2].clone().heavier.is_none()); + assert_eq!(pages[2].clone().lighter.unwrap().meta.weight.unwrap(), 2); } } diff --git a/components/errors/Cargo.toml b/components/errors/Cargo.toml index 285bfeda..977fa75f 100644 --- a/components/errors/Cargo.toml +++ b/components/errors/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors = ["Vincent Prouillet "] [dependencies] -error-chain = "0.11" +error-chain = "0.12" tera = "0.11" toml = "0.4" +image = "0.19.0" diff --git a/components/errors/src/lib.rs b/components/errors/src/lib.rs index cc698c61..9bc146f1 100755 --- a/components/errors/src/lib.rs +++ b/components/errors/src/lib.rs @@ -1,9 +1,10 @@ -#![allow(unused_doc_comment)] +#![allow(unused_doc_comments)] #[macro_use] extern crate error_chain; extern crate tera; extern crate toml; +extern crate image; error_chain! { errors {} @@ -15,6 +16,7 @@ error_chain! { foreign_links { Io(::std::io::Error); Toml(toml::de::Error); + Image(image::ImageError); } } diff --git a/components/front_matter/Cargo.toml b/components/front_matter/Cargo.toml index 7a952330..76c6a9fa 100644 --- a/components/front_matter/Cargo.toml +++ b/components/front_matter/Cargo.toml @@ -12,5 +12,4 @@ toml = "0.4" regex = "1" lazy_static = "1" - errors = { path = "../errors" } diff --git a/components/front_matter/src/lib.rs b/components/front_matter/src/lib.rs index 6cf79f0c..fd2739c3 100644 --- a/components/front_matter/src/lib.rs +++ b/components/front_matter/src/lib.rs @@ -30,8 +30,6 @@ lazy_static! { pub enum SortBy { /// Most recent to oldest Date, - /// Lower order comes last - Order, /// Lower weight comes first Weight, /// No sorting @@ -151,5 +149,4 @@ date = 2002-10-12"#; let res = split_page_content(Path::new(""), content); assert!(res.is_err()); } - } diff --git a/components/front_matter/src/page.rs b/components/front_matter/src/page.rs index 86cde2a9..fd8ebc98 100644 --- a/components/front_matter/src/page.rs +++ b/components/front_matter/src/page.rs @@ -1,4 +1,5 @@ -use std::result::{Result as StdResult}; +use std::collections::HashMap; +use std::result::Result as StdResult; use chrono::prelude::*; use tera::{Map, Value}; @@ -21,7 +22,7 @@ fn from_toml_datetime<'de, D>(deserializer: D) -> StdResult, D::E fn convert_toml_date(table: Map) -> Value { let mut new = Map::new(); - for (k, v) in table.into_iter() { + for (k, v) in table { if k == "$__toml_private_datetime" { return v; } @@ -34,7 +35,7 @@ fn convert_toml_date(table: Map) -> Value { return Value::Object(new); } new.insert(k, convert_toml_date(o)); - }, + } _ => { new.insert(k, v); } } } @@ -51,8 +52,8 @@ fn fix_toml_dates(table: Map) -> Value { match value { Value::Object(mut o) => { new.insert(key, convert_toml_date(o)); - }, - _ => { new.insert(key, value); }, + } + _ => { new.insert(key, value); } } } @@ -80,10 +81,7 @@ pub struct PageFrontMatter { /// otherwise is set after parsing front matter and sections /// Can't be an empty string if present pub path: Option, - /// Tags, not to be confused with categories - pub tags: Option>, - /// Only one category allowed. Can't be an empty string if present - pub category: Option, + pub taxonomies: HashMap>, /// Integer to use to order content. Lowest is at the bottom, highest first pub order: Option, /// Integer to use to order content. Highest is at the bottom, lowest first @@ -122,12 +120,6 @@ impl PageFrontMatter { } } - if let Some(ref category) = f.category { - if category == "" { - bail!("`category` can't be empty if present") - } - } - f.extra = match fix_toml_dates(f.extra) { Value::Object(o) => o, _ => unreachable!("Got something other than a table in page extra"), @@ -155,13 +147,6 @@ impl PageFrontMatter { pub fn weight(&self) -> usize { self.weight.unwrap() } - - pub fn has_tags(&self) -> bool { - match self.tags { - Some(ref t) => !t.is_empty(), - None => false - } - } } impl Default for PageFrontMatter { @@ -173,8 +158,7 @@ impl Default for PageFrontMatter { draft: false, slug: None, path: None, - tags: None, - category: None, + taxonomies: HashMap::new(), order: None, weight: None, aliases: Vec::new(), @@ -211,21 +195,6 @@ mod tests { assert_eq!(res.description.unwrap(), "hey there".to_string()) } - #[test] - fn can_parse_tags() { - let content = r#" - title = "Hello" - description = "hey there" - slug = "hello-world" - tags = ["rust", "html"]"#; - let res = PageFrontMatter::parse(content); - assert!(res.is_ok()); - let res = res.unwrap(); - - assert_eq!(res.title.unwrap(), "Hello".to_string()); - assert_eq!(res.slug.unwrap(), "hello-world".to_string()); - assert_eq!(res.tags.unwrap(), ["rust".to_string(), "html".to_string()]); - } #[test] fn errors_with_invalid_front_matter() { @@ -234,17 +203,6 @@ mod tests { assert!(res.is_err()); } - #[test] - fn errors_on_non_string_tag() { - let content = r#" - title = "Hello" - description = "hey there" - slug = "hello-world" - tags = ["rust", 1]"#; - let res = PageFrontMatter::parse(content); - assert!(res.is_err()); - } - #[test] fn errors_on_present_but_empty_slug() { let content = r#" @@ -344,4 +302,21 @@ mod tests { assert!(res.is_ok()); assert_eq!(res.unwrap().extra["something"]["some-date"], to_value("2002-14-01").unwrap()); } + + #[test] + fn can_parse_taxonomies() { + let content = r#" +title = "Hello World" + +[taxonomies] +tags = ["Rust", "JavaScript"] +categories = ["Dev"] +"#; + let res = PageFrontMatter::parse(content); + println!("{:?}", res); + assert!(res.is_ok()); + let res2 = res.unwrap(); + assert_eq!(res2.taxonomies["categories"], vec!["Dev"]); + assert_eq!(res2.taxonomies["tags"], vec!["Rust", "JavaScript"]); + } } diff --git a/components/rendering/examples/generate_sublime.rs b/components/highlighting/examples/generate_sublime.rs similarity index 100% rename from components/rendering/examples/generate_sublime.rs rename to components/highlighting/examples/generate_sublime.rs diff --git a/components/highlighting/src/lib.rs b/components/highlighting/src/lib.rs index f0a80b83..f8142790 100644 --- a/components/highlighting/src/lib.rs +++ b/components/highlighting/src/lib.rs @@ -4,9 +4,10 @@ extern crate syntect; use syntect::dumps::from_binary; use syntect::parsing::SyntaxSet; -use syntect::highlighting::ThemeSet; +use syntect::highlighting::{ThemeSet, Theme}; +use syntect::easy::HighlightLines; -thread_local!{ +thread_local! { pub static SYNTAX_SET: SyntaxSet = { let mut ss: SyntaxSet = from_binary(include_bytes!("../../../sublime_syntaxes/newlines.packdump")); ss.link_syntaxes(); @@ -14,6 +15,18 @@ thread_local!{ }; } -lazy_static!{ +lazy_static! { pub static ref THEME_SET: ThemeSet = from_binary(include_bytes!("../../../sublime_themes/all.themedump")); } + + +pub fn get_highlighter<'a>(theme: &'a Theme, info: &str) -> HighlightLines<'a> { + SYNTAX_SET.with(|ss| { + let syntax = info + .split(' ') + .next() + .and_then(|lang| ss.find_syntax_by_token(lang)) + .unwrap_or_else(|| ss.find_syntax_plain_text()); + HighlightLines::new(syntax, theme) + }) +} diff --git a/components/imageproc/Cargo.toml b/components/imageproc/Cargo.toml new file mode 100644 index 00000000..82d97400 --- /dev/null +++ b/components/imageproc/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "imageproc" +version = "0.1.0" +authors = ["Vojtěch Král "] + +[dependencies] +lazy_static = "1" +regex = "1.0" +tera = "0.11" +image = "0.19" +rayon = "1" + +errors = { path = "../errors" } +utils = { path = "../utils" } diff --git a/components/imageproc/src/lib.rs b/components/imageproc/src/lib.rs new file mode 100644 index 00000000..db553a6c --- /dev/null +++ b/components/imageproc/src/lib.rs @@ -0,0 +1,384 @@ +#[macro_use] +extern crate lazy_static; +extern crate regex; +extern crate image; +extern crate rayon; + +extern crate utils; +extern crate errors; + +use std::path::{Path, PathBuf}; +use std::hash::{Hash, Hasher}; +use std::collections::HashMap; +use std::collections::hash_map::Entry as HEntry; +use std::collections::hash_map::DefaultHasher; +use std::fs::{self, File}; + +use regex::Regex; +use image::{GenericImage, FilterType}; +use image::jpeg::JPEGEncoder; +use rayon::prelude::*; + +use utils::fs as ufs; +use errors::{Result, ResultExt}; + + +static RESIZED_SUBDIR: &'static str = "_processed_images"; + +lazy_static! { + pub static ref RESIZED_FILENAME: Regex = Regex::new(r#"([0-9a-f]{16})([0-9a-f]{2})[.]jpg"#).unwrap(); +} + +/// Describes the precise kind of a resize operation +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ResizeOp { + /// A simple scale operation that doesn't take aspect ratio into account + Scale(u32, u32), + /// Scales the image to a specified width with height computed such + /// that aspect ratio is preserved + FitWidth(u32), + /// Scales the image to a specified height with width computed such + /// that aspect ratio is preserved + FitHeight(u32), + /// Scales the image such that it fits within the specified width and + /// height preserving aspect ratio. + /// Either dimension may end up being smaller, but never larger than specified. + Fit(u32, u32), + /// Scales the image such that it fills the specified width and height. + /// Output will always have the exact dimensions specified. + /// The part of the image that doesn't fit in the thumbnail due to differing + /// aspect ratio will be cropped away, if any. + Fill(u32, u32), +} + +impl ResizeOp { + pub fn from_args(op: &str, width: Option, height: Option) -> Result { + use ResizeOp::*; + + // Validate args: + match op { + "fit_width" => if width.is_none() { + return Err("op=\"fit_width\" requires a `width` argument".to_string().into()); + }, + "fit_height" => if height.is_none() { + return Err("op=\"fit_height\" requires a `height` argument".to_string().into()); + }, + "scale" | "fit" | "fill" => if width.is_none() || height.is_none() { + return Err(format!("op={} requires a `width` and `height` argument", op).into()); + }, + _ => return Err(format!("Invalid image resize operation: {}", op).into()) + }; + + Ok(match op { + "scale" => Scale(width.unwrap(), height.unwrap()), + "fit_width" => FitWidth(width.unwrap()), + "fit_height" => FitHeight(height.unwrap()), + "fit" => Fit(width.unwrap(), height.unwrap()), + "fill" => Fill(width.unwrap(), height.unwrap()), + _ => unreachable!(), + }) + } + + pub fn width(self) -> Option { + use ResizeOp::*; + + match self { + Scale(w, _) => Some(w), + FitWidth(w) => Some(w), + FitHeight(_) => None, + Fit(w, _) => Some(w), + Fill(w, _) => Some(w), + } + } + + pub fn height(self) -> Option { + use ResizeOp::*; + + match self { + Scale(_, h) => Some(h), + FitWidth(_) => None, + FitHeight(h) => Some(h), + Fit(_, h) => Some(h), + Fill(_, h) => Some(h), + } + } +} + +impl From for u8 { + fn from(op: ResizeOp) -> u8 { + use ResizeOp::*; + + match op { + Scale(_, _) => 1, + FitWidth(_) => 2, + FitHeight(_) => 3, + Fit(_, _) => 4, + Fill(_, _) => 5, + } + } +} + +impl Hash for ResizeOp { + fn hash(&self, hasher: &mut H) { + hasher.write_u8(u8::from(*self)); + if let Some(w) = self.width() { hasher.write_u32(w); } + if let Some(h) = self.height() { hasher.write_u32(h); } + } +} + +/// Holds all data needed to perform a resize operation +#[derive(Debug, PartialEq, Eq)] +pub struct ImageOp { + source: String, + op: ResizeOp, + quality: u8, + /// Hash of the above parameters + hash: u64, + /// If there is a hash collision with another ImageOp, this contains a sequential ID > 1 + /// identifying the collision in the order as encountered (which is essentially random). + /// Therefore, ImageOps with collisions (ie. collision_id > 0) are always considered out of date. + /// Note that this is very unlikely to happen in practice + collision_id: u32, +} + +impl ImageOp { + pub fn new(source: String, op: ResizeOp, quality: u8) -> ImageOp { + let mut hasher = DefaultHasher::new(); + hasher.write(source.as_ref()); + op.hash(&mut hasher); + hasher.write_u8(quality); + let hash = hasher.finish(); + + ImageOp { source, op, quality, hash, collision_id: 0 } + } + + pub fn from_args( + source: String, + op: &str, + width: Option, + height: Option, + quality: u8, + ) -> Result { + let op = ResizeOp::from_args(op, width, height)?; + Ok(Self::new(source, op, quality)) + } + + fn perform(&self, content_path: &Path, target_path: &Path) -> Result<()> { + use ResizeOp::*; + + let src_path = content_path.join(&self.source); + if !ufs::file_stale(&src_path, target_path) { + return Ok(()); + } + + let mut img = image::open(&src_path)?; + let (img_w, img_h) = img.dimensions(); + + const RESIZE_FILTER: FilterType = FilterType::Gaussian; + const RATIO_EPSILLION: f32 = 0.1; + + let img = match self.op { + Scale(w, h) => img.resize_exact(w, h, RESIZE_FILTER), + FitWidth(w) => img.resize(w, u32::max_value(), RESIZE_FILTER), + FitHeight(h) => img.resize(u32::max_value(), h, RESIZE_FILTER), + Fit(w, h) => img.resize(w, h, RESIZE_FILTER), + Fill(w, h) => { + let factor_w = img_w as f32 / w as f32; + let factor_h = img_h as f32 / h as f32; + + if (factor_w - factor_h).abs() <= RATIO_EPSILLION { + // If the horizontal and vertical factor is very similar, + // that means the aspect is similar enough that there's not much point + // in cropping, so just perform a simple scale in this case. + img.resize_exact(w, h, RESIZE_FILTER) + } else { + // We perform the fill such that a crop is performed first + // and then resize_exact can be used, which should be cheaper than + // resizing and then cropping (smaller number of pixels to resize). + let (crop_w, crop_h) = if factor_w < factor_h { + (img_w, (factor_w * h as f32).round() as u32) + } else { + ((factor_h * w as f32).round() as u32, img_h) + }; + + let (offset_w, offset_h) = if factor_w < factor_h { + (0, (img_h - crop_h) / 2) + } else { + ((img_w - crop_w) / 2, 0) + }; + + img.crop(offset_w, offset_h, crop_w, crop_h) + .resize_exact(w, h, RESIZE_FILTER) + } + } + }; + + let mut f = File::create(target_path)?; + let mut enc = JPEGEncoder::new_with_quality(&mut f, self.quality); + let (img_w, img_h) = img.dimensions(); + enc.encode(&img.raw_pixels(), img_w, img_h, img.color())?; + Ok(()) + } +} + + +/// A strcture into which image operations can be enqueued and then performed. +/// All output is written in a subdirectory in `static_path`, +/// taking care of file stale status based on timestamps and possible hash collisions. +#[derive(Debug)] +pub struct Processor { + content_path: PathBuf, + resized_path: PathBuf, + resized_url: String, + /// A map of a ImageOps by their stored hash. + /// Note that this cannot be a HashSet, because hashset handles collisions and we don't want that, + /// we need to be aware of and handle collisions ourselves. + img_ops: HashMap, + /// Hash collisions go here: + img_ops_collisions: Vec, +} + +impl Processor { + pub fn new(content_path: PathBuf, static_path: &Path, base_url: &str) -> Processor { + Processor { + content_path, + resized_path: static_path.join(RESIZED_SUBDIR), + resized_url: Self::resized_url(base_url), + img_ops: HashMap::new(), + img_ops_collisions: Vec::new(), + } + } + + fn resized_url(base_url: &str) -> String { + if base_url.ends_with('/') { + format!("{}{}", base_url, RESIZED_SUBDIR) + } else { + format!("{}/{}", base_url, RESIZED_SUBDIR) + } + } + + pub fn set_base_url(&mut self, base_url: &str) { + self.resized_url = Self::resized_url(base_url); + } + + pub fn source_exists(&self, source: &str) -> bool { + self.content_path.join(source).exists() + } + + pub fn num_img_ops(&self) -> usize { + self.img_ops.len() + self.img_ops_collisions.len() + } + + fn insert_with_collisions(&mut self, mut img_op: ImageOp) -> u32 { + match self.img_ops.entry(img_op.hash) { + HEntry::Occupied(entry) => if *entry.get() == img_op { return 0; }, + HEntry::Vacant(entry) => { + entry.insert(img_op); + return 0; + } + } + + // If we get here, that means a hash collision. + // This is detected when there is an ImageOp with the same hash in the `img_ops` + // map but which is not equal to this one. + // To deal with this, all collisions get a (random) sequential ID number. + + // First try to look up this ImageOp in `img_ops_collisions`, maybe we've + // already seen the same ImageOp. + // At the same time, count IDs to figure out the next free one. + // Start with the ID of 2, because we'll need to use 1 for the ImageOp + // already present in the map: + let mut collision_id = 2; + for op in self.img_ops_collisions.iter().filter(|op| op.hash == img_op.hash) { + if *op == img_op { + // This is a colliding ImageOp, but we've already seen an equal one + // (not just by hash, but by content too), so just return its ID: + return collision_id; + } else { + collision_id += 1; + } + } + + // If we get here, that means this is a new colliding ImageOp and + // `collision_id` is the next free ID + if collision_id == 2 { + // This is the first collision found with this hash, update the ID + // of the matching ImageOp in the map. + self.img_ops.get_mut(&img_op.hash).unwrap().collision_id = 1; + } + img_op.collision_id = collision_id; + self.img_ops_collisions.push(img_op); + collision_id + } + + fn op_filename(hash: u64, collision_id: u32) -> String { + // Please keep this in sync with RESIZED_FILENAME + assert!(collision_id < 256, "Unexpectedly large number of collisions: {}", collision_id); + format!("{:016x}{:02x}.jpg", hash, collision_id) + } + + fn op_url(&self, hash: u64, collision_id: u32) -> String { + format!("{}/{}", &self.resized_url, Self::op_filename(hash, collision_id)) + } + + pub fn insert(&mut self, img_op: ImageOp) -> String { + let hash = img_op.hash; + let collision_id = self.insert_with_collisions(img_op); + self.op_url(hash, collision_id) + } + + pub fn prune(&self) -> Result<()> { + // Do not create folders if they don't exist + if !self.resized_path.exists() { + return Ok(()); + } + + ufs::ensure_directory_exists(&self.resized_path)?; + let entries = fs::read_dir(&self.resized_path)?; + for entry in entries { + let entry_path = entry?.path(); + if entry_path.is_file() { + let filename = entry_path.file_name().unwrap().to_string_lossy(); + if let Some(capts) = RESIZED_FILENAME.captures(filename.as_ref()) { + let hash = u64::from_str_radix(capts.get(1).unwrap().as_str(), 16).unwrap(); + let collision_id = u32::from_str_radix( + capts.get(2).unwrap().as_str(), 16, + ).unwrap(); + + if collision_id > 0 || !self.img_ops.contains_key(&hash) { + fs::remove_file(&entry_path)?; + } + } + } + } + Ok(()) + } + + pub fn do_process(&mut self) -> Result<()> { + if !self.img_ops.is_empty() { + ufs::ensure_directory_exists(&self.resized_path)?; + } + + self.img_ops.par_iter().map(|(hash, op)| { + let target = self.resized_path.join(Self::op_filename(*hash, op.collision_id)); + op.perform(&self.content_path, &target) + .chain_err(|| format!("Failed to process image: {}", op.source)) + }) + .fold(|| Ok(()), Result::and) + .reduce(|| Ok(()), Result::and) + } +} + + +/// Looks at file's extension and returns whether it's a supported image format +pub fn file_is_img>(p: P) -> bool { + p.as_ref().extension().and_then(|s| s.to_str()).map(|ext| { + match ext.to_lowercase().as_str() { + "jpg" | "jpeg" => true, + "png" => true, + "gif" => true, + "bmp" => true, + _ => false, + } + }).unwrap_or(false) +} diff --git a/components/link_checker/Cargo.toml b/components/link_checker/Cargo.toml new file mode 100644 index 00000000..92b49b02 --- /dev/null +++ b/components/link_checker/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "link_checker" +version = "0.1.0" +authors = ["Vincent Prouillet "] + +[dependencies] +reqwest = "0.8" +lazy_static = "1" diff --git a/components/link_checker/src/lib.rs b/components/link_checker/src/lib.rs new file mode 100644 index 00000000..4aa2d816 --- /dev/null +++ b/components/link_checker/src/lib.rs @@ -0,0 +1,88 @@ +extern crate reqwest; +#[macro_use] +extern crate lazy_static; + +use std::collections::HashMap; +use std::error::Error; +use std::sync::{Arc, RwLock}; +use reqwest::StatusCode; + + +#[derive(Clone, Debug, PartialEq)] +pub struct LinkResult { + pub code: Option, + /// Whether the HTTP request didn't make it to getting a HTTP code + pub error: Option, +} + +impl LinkResult { + pub fn is_valid(&self) -> bool { + if self.error.is_some() { + return false; + } + + if let Some(c) = self.code { + return c.is_success(); + } + + true + } + + pub fn message(&self) -> String { + if let Some(ref e) = self.error { + return e.clone(); + } + + if let Some(c) = self.code { + return format!("{}", c); + } + + "Unknown error".to_string() + } +} + +lazy_static! { + // Keep history of link checks so a rebuild doesn't have to check again + static ref LINKS: Arc>> = Arc::new(RwLock::new(HashMap::new())); +} + +pub fn check_url(url: &str) -> LinkResult { + { + let guard = LINKS.read().unwrap(); + if let Some(res) = guard.get(url) { + return res.clone(); + } + } + + // Need to actually do the link checking + let res = match reqwest::get(url) { + Ok(response) => LinkResult { code: Some(response.status()), error: None }, + Err(e) => LinkResult { code: None, error: Some(e.description().to_string()) }, + }; + + LINKS.write().unwrap().insert(url.to_string(), res.clone()); + return res; +} + +#[cfg(test)] +mod tests { + use super::{LINKS, check_url}; + + #[test] + fn can_validate_ok_links() { + let url = "https://google.com"; + let res = check_url(url); + assert!(res.is_valid()); + assert!(LINKS.read().unwrap().get(url).is_some()); + let res = check_url(url); + assert!(res.is_valid()); + } + + #[test] + fn can_fail_404_links() { + let res = check_url("https://google.comys"); + assert_eq!(res.is_valid(), false); + assert!(res.code.is_none()); + assert!(res.error.is_some()); + } +} diff --git a/components/pagination/Cargo.toml b/components/pagination/Cargo.toml index 0ee865f8..7fed69cb 100644 --- a/components/pagination/Cargo.toml +++ b/components/pagination/Cargo.toml @@ -12,6 +12,7 @@ errors = { path = "../errors" } config = { path = "../config" } content = { path = "../content" } utils = { path = "../utils" } +taxonomies = { path = "../taxonomies" } [dev-dependencies] front_matter = { path = "../front_matter" } diff --git a/components/pagination/src/lib.rs b/components/pagination/src/lib.rs index 42724c08..c93faade 100644 --- a/components/pagination/src/lib.rs +++ b/components/pagination/src/lib.rs @@ -6,6 +6,7 @@ extern crate errors; extern crate config; extern crate content; extern crate utils; +extern crate taxonomies; #[cfg(test)] extern crate front_matter; @@ -18,6 +19,14 @@ use errors::{Result, ResultExt}; use config::Config; use content::{Page, Section}; use utils::templates::render_template; +use taxonomies::{Taxonomy, TaxonomyItem}; + + +#[derive(Clone, Debug, PartialEq)] +enum PaginationRoot<'a> { + Section(&'a Section), + Taxonomy(&'a Taxonomy), +} /// A list of all the pages in the paginator with their index and links @@ -30,7 +39,7 @@ pub struct Pager<'a> { /// Path to that page path: String, /// All pages for the pager - pages: Vec<&'a Page> + pages: Vec<&'a Page>, } impl<'a> Pager<'a> { @@ -63,22 +72,62 @@ pub struct Paginator<'a> { pub pagers: Vec>, /// How many content pages on a paginated page at max paginate_by: usize, - /// The section struct we're building the paginator for - section: &'a Section, + /// The thing we are creating the paginator for: section or taxonomy + root: PaginationRoot<'a>, + // Those below can be obtained from the root but it would make the code more complex than needed + pub permalink: String, + path: String, + pub paginate_path: String, + is_index: bool, } impl<'a> Paginator<'a> { - /// Create a new paginator + /// Create a new paginator from a section /// It will always at least create one pager (the first) even if there are no pages to paginate - pub fn new(all_pages: &'a [Page], section: &'a Section) -> Paginator<'a> { + pub fn from_section(all_pages: &'a [Page], section: &'a Section) -> Paginator<'a> { let paginate_by = section.meta.paginate_by.unwrap(); + let mut paginator = Paginator { + all_pages, + pagers: vec![], + paginate_by, + root: PaginationRoot::Section(section), + permalink: section.permalink.clone(), + path: section.path.clone(), + paginate_path: section.meta.paginate_path.clone(), + is_index: section.is_index(), + }; + + paginator.fill_pagers(); + paginator + } + + /// Create a new paginator from a taxonomy + /// It will always at least create one pager (the first) even if there are no pages to paginate + pub fn from_taxonomy(taxonomy: &'a Taxonomy, item: &'a TaxonomyItem) -> Paginator<'a> { + let paginate_by = taxonomy.kind.paginate_by.unwrap(); + let mut paginator = Paginator { + all_pages: &item.pages, + pagers: vec![], + paginate_by, + root: PaginationRoot::Taxonomy(taxonomy), + permalink: item.permalink.clone(), + path: format!("{}/{}", taxonomy.kind.name, item.slug), + paginate_path: taxonomy.kind.paginate_path.clone().unwrap_or_else(|| "pages".to_string()), + is_index: false, + }; + + paginator.fill_pagers(); + paginator + } + + fn fill_pagers(&mut self) { let mut pages = vec![]; let mut current_page = vec![]; - for page in all_pages { + for page in self.all_pages { current_page.push(page); - if current_page.len() == paginate_by { + if current_page.len() == self.paginate_by { pages.push(current_page); current_page = vec![]; } @@ -91,17 +140,23 @@ impl<'a> Paginator<'a> { for (index, page) in pages.iter().enumerate() { // First page has no pagination path if index == 0 { - pagers.push(Pager::new(1, page.clone(), section.permalink.clone(), section.path.clone())); + pagers.push(Pager::new(1, page.clone(), self.permalink.clone(), self.path.clone())); continue; } - let page_path = format!("{}/{}/", section.meta.paginate_path, index + 1); - let permalink = format!("{}{}", section.permalink, page_path); - let pager_path = if section.is_index() { + let page_path = format!("{}/{}/", self.paginate_path, index + 1); + let permalink = format!("{}{}", self.permalink, page_path); + + let pager_path = if self.is_index { page_path } else { - format!("{}{}", section.path, page_path) + if self.path.ends_with("/") { + format!("{}{}", self.path, page_path) + } else { + format!("{}/{}", self.path, page_path) + } }; + pagers.push(Pager::new( index + 1, page.clone(), @@ -112,15 +167,10 @@ impl<'a> Paginator<'a> { // We always have the index one at least if pagers.is_empty() { - pagers.push(Pager::new(1, vec![], section.permalink.clone(), section.path.clone())); + pagers.push(Pager::new(1, vec![], self.permalink.clone(), self.path.clone())); } - Paginator { - all_pages, - pagers, - paginate_by, - section, - } + self.pagers = pagers; } pub fn build_paginator_context(&self, current_pager: &Pager) -> HashMap<&str, Value> { @@ -130,14 +180,14 @@ impl<'a> Paginator<'a> { // Global variables paginator.insert("paginate_by", to_value(self.paginate_by).unwrap()); - paginator.insert("first", to_value(&self.section.permalink).unwrap()); + paginator.insert("first", to_value(&self.permalink).unwrap()); let last_pager = &self.pagers[self.pagers.len() - 1]; paginator.insert("last", to_value(&last_pager.permalink).unwrap()); paginator.insert( "pagers", to_value( &self.pagers.iter().map(|p| p.clone_without_pages()).collect::>() - ).unwrap() + ).unwrap(), ); // Variables for this specific page @@ -163,13 +213,22 @@ impl<'a> Paginator<'a> { pub fn render_pager(&self, pager: &Pager, config: &Config, tera: &Tera) -> Result { let mut context = Context::new(); context.add("config", &config); - context.add("section", self.section); + let template_name = match self.root { + PaginationRoot::Section(s) => { + context.add("section", &s); + s.get_template_name() + } + PaginationRoot::Taxonomy(t) => { + context.add("taxonomy", &t.kind); + format!("{}/single.html", t.kind.name) + } + }; context.add("current_url", &pager.permalink); context.add("current_path", &pager.path); context.add("paginator", &self.build_paginator_context(pager)); - render_template(&self.section.get_template_name(), tera, &context, &config.theme) - .chain_err(|| format!("Failed to render pager {} of section '{}'", pager.index, self.section.file.path.display())) + render_template(&template_name, tera, &context, &config.theme) + .chain_err(|| format!("Failed to render pager {}", pager.index)) } } @@ -179,6 +238,8 @@ mod tests { use front_matter::SectionFrontMatter; use content::{Page, Section}; + use config::Taxonomy as TaxonomyConfig; + use taxonomies::{Taxonomy, TaxonomyItem}; use super::Paginator; @@ -205,7 +266,7 @@ mod tests { Page::default(), ]; let section = create_section(false); - let paginator = Paginator::new(pages.as_slice(), §ion); + let paginator = Paginator::from_section(pages.as_slice(), §ion); assert_eq!(paginator.pagers.len(), 2); assert_eq!(paginator.pagers[0].index, 1); @@ -227,7 +288,7 @@ mod tests { Page::default(), ]; let section = create_section(true); - let paginator = Paginator::new(pages.as_slice(), §ion); + let paginator = Paginator::from_section(pages.as_slice(), §ion); assert_eq!(paginator.pagers.len(), 2); assert_eq!(paginator.pagers[0].index, 1); @@ -249,7 +310,7 @@ mod tests { Page::default(), ]; let section = create_section(false); - let paginator = Paginator::new(pages.as_slice(), §ion); + let paginator = Paginator::from_section(pages.as_slice(), §ion); assert_eq!(paginator.pagers.len(), 2); let context = paginator.build_paginator_context(&paginator.pagers[0]); @@ -268,4 +329,37 @@ mod tests { assert_eq!(context["previous"], to_value("https://vincent.is/posts/").unwrap()); assert_eq!(context["current_index"], to_value(2).unwrap()); } + + #[test] + fn test_can_create_paginator_for_taxonomy() { + let pages = vec![ + Page::default(), + Page::default(), + Page::default(), + ]; + let taxonomy_def = TaxonomyConfig { + name: "tags".to_string(), + paginate_by: Some(2), + ..TaxonomyConfig::default() + }; + let taxonomy_item = TaxonomyItem { + name: "Something".to_string(), + slug: "something".to_string(), + permalink: "https://vincent.is/tags/something/".to_string(), + pages, + }; + let taxonomy = Taxonomy { kind: taxonomy_def, items: vec![taxonomy_item.clone()] }; + let paginator = Paginator::from_taxonomy(&taxonomy, &taxonomy_item); + assert_eq!(paginator.pagers.len(), 2); + + assert_eq!(paginator.pagers[0].index, 1); + assert_eq!(paginator.pagers[0].pages.len(), 2); + assert_eq!(paginator.pagers[0].permalink, "https://vincent.is/tags/something/"); + assert_eq!(paginator.pagers[0].path, "tags/something"); + + assert_eq!(paginator.pagers[1].index, 2); + assert_eq!(paginator.pagers[1].pages.len(), 1); + assert_eq!(paginator.pagers[1].permalink, "https://vincent.is/tags/something/pages/2/"); + assert_eq!(paginator.pagers[1].path, "tags/something/pages/2/"); + } } diff --git a/components/rebuild/Cargo.toml b/components/rebuild/Cargo.toml index a6ae5b70..b8f37e7d 100644 --- a/components/rebuild/Cargo.toml +++ b/components/rebuild/Cargo.toml @@ -11,5 +11,5 @@ content = { path = "../content" } site = { path = "../site" } [dev-dependencies] -tempdir = "0.3" +tempfile = "3" fs_extra = "1.1" diff --git a/components/rebuild/src/lib.rs b/components/rebuild/src/lib.rs index fac94802..a96c7fb0 100644 --- a/components/rebuild/src/lib.rs +++ b/components/rebuild/src/lib.rs @@ -16,7 +16,7 @@ use front_matter::{PageFrontMatter, SectionFrontMatter}; pub fn find_parent_section<'a>(site: &'a Site, page: &Page) -> Option<&'a Section> { for section in site.sections.values() { if section.is_child_page(&page.file.path) { - return Some(section) + return Some(section); } } @@ -26,10 +26,8 @@ pub fn find_parent_section<'a>(site: &'a Site, page: &Page) -> Option<&'a Sectio #[derive(Debug, Clone, Copy, PartialEq)] pub enum PageChangesNeeded { - /// Editing `tags` - Tags, - /// Editing `categories` - Categories, + /// Editing `taxonomies` + Taxonomies, /// Editing `date`, `order` or `weight` Sort, /// Editing anything causes a re-render of the page @@ -85,12 +83,8 @@ fn find_section_front_matter_changes(current: &SectionFrontMatter, new: &Section fn find_page_front_matter_changes(current: &PageFrontMatter, other: &PageFrontMatter) -> Vec { let mut changes_needed = vec![]; - if current.tags != other.tags { - changes_needed.push(PageChangesNeeded::Tags); - } - - if current.category != other.category { - changes_needed.push(PageChangesNeeded::Categories); + if current.taxonomies != other.taxonomies { + changes_needed.push(PageChangesNeeded::Taxonomies); } if current.date != other.date || current.order != other.order || current.weight != other.weight { @@ -117,8 +111,8 @@ fn delete_element(site: &mut Site, path: &Path, is_section: bool) -> Result<()> if let Some(p) = site.pages.remove(path) { site.permalinks.remove(&p.file.relative); - if p.meta.has_tags() || p.meta.category.is_some() { - site.populate_tags_and_categories(); + if !p.meta.taxonomies.is_empty() { + site.populate_taxonomies()?; } // if there is a parent section, we will need to re-render it @@ -155,18 +149,18 @@ fn handle_section_editing(site: &mut Site, path: &Path) -> Result<()> { SectionChangesNeeded::Sort => { site.sort_sections_pages(Some(path)); site.register_tera_global_fns(); - }, + } SectionChangesNeeded::Render => site.render_section(&site.sections[path], false)?, SectionChangesNeeded::RenderWithPages => site.render_section(&site.sections[path], true)?, // not a common enough operation to make it worth optimizing SectionChangesNeeded::Delete => { site.populate_sections(); site.build()?; - }, + } }; } return Ok(()); - }, + } // New section, only render that one None => { site.populate_sections(); @@ -204,31 +198,19 @@ fn handle_page_editing(site: &mut Site, path: &Path) -> Result<()> { // I can't think of a valid usecase where you would need the content // of a page through a global fn so it's commented out for now // site.register_tera_global_fns(); - return site.render_page(& site.pages[path]); + return site.render_page(&site.pages[path]); } // Front matter changed - let mut taxonomies_populated = false; let mut sections_populated = false; for changes in find_page_front_matter_changes(&site.pages[path].meta, &prev.meta) { // Sort always comes first if present so the rendering will be fine match changes { - PageChangesNeeded::Tags => { - if !taxonomies_populated { - site.populate_tags_and_categories(); - taxonomies_populated = true; - } + PageChangesNeeded::Taxonomies => { + site.populate_taxonomies()?; site.register_tera_global_fns(); - site.render_tags()?; - }, - PageChangesNeeded::Categories => { - if !taxonomies_populated { - site.populate_tags_and_categories(); - taxonomies_populated = true; - } - site.register_tera_global_fns(); - site.render_categories()?; - }, + site.render_taxonomies()?; + } PageChangesNeeded::Sort => { let section_path = match find_parent_section(site, &site.pages[path]) { Some(s) => s.file.path.clone(), @@ -241,7 +223,7 @@ fn handle_page_editing(site: &mut Site, path: &Path) -> Result<()> { site.sort_sections_pages(Some(§ion_path)); site.register_tera_global_fns(); site.render_index()?; - }, + } PageChangesNeeded::Render => { if !sections_populated { site.populate_sections(); @@ -250,15 +232,15 @@ fn handle_page_editing(site: &mut Site, path: &Path) -> Result<()> { site.register_tera_global_fns(); render_parent_section!(site, path); site.render_page(&site.pages[path])?; - }, + } }; } Ok(()) - }, + } // It's a new page! None => { site.populate_sections(); - site.populate_tags_and_categories(); + site.populate_taxonomies()?; site.register_tera_global_fns(); // No need to optimise that yet, we can revisit if it becomes an issue site.build() @@ -307,7 +289,7 @@ pub fn after_content_change(site: &mut Site, path: &Path) -> Result<()> { handle_page_editing(site, path) } } else { - if index.exists() { + if index.exists() { handle_page_editing(site, &index) } else { Ok(()) @@ -322,14 +304,13 @@ pub fn after_template_change(site: &mut Site, path: &Path) -> Result<()> { match filename { "sitemap.xml" => site.render_sitemap(), - "rss.xml" => site.render_rss_feed(), + "rss.xml" => site.render_rss_feed(None, None), "robots.txt" => site.render_robots(), - "categories.html" | "category.html" => site.render_categories(), - "tags.html" | "tag.html" => site.render_tags(), + "single.html" | "list.html" => site.render_taxonomies(), "page.html" => { site.render_sections()?; site.render_orphan_pages() - }, + } "section.html" => site.render_sections(), // Either the index or some unknown template changed // We can't really know what this change affects so rebuild all @@ -345,40 +326,38 @@ pub fn after_template_change(site: &mut Site, path: &Path) -> Result<()> { site.populate_sections(); site.render_sections()?; site.render_orphan_pages()?; - site.render_categories()?; - site.render_tags() - }, + site.render_taxonomies() + } } } #[cfg(test)] mod tests { + use std::collections::HashMap; + use front_matter::{PageFrontMatter, SectionFrontMatter, SortBy}; use super::{ find_page_front_matter_changes, find_section_front_matter_changes, - PageChangesNeeded, SectionChangesNeeded + PageChangesNeeded, SectionChangesNeeded, }; #[test] - fn can_find_tag_changes_in_page_frontmatter() { - let new = PageFrontMatter { tags: Some(vec!["a tag".to_string()]), ..PageFrontMatter::default() }; + fn can_find_taxonomy_changes_in_page_frontmatter() { + let mut taxonomies = HashMap::new(); + taxonomies.insert("tags".to_string(), vec!["a tag".to_string()]); + let new = PageFrontMatter { taxonomies, ..PageFrontMatter::default() }; let changes = find_page_front_matter_changes(&PageFrontMatter::default(), &new); - assert_eq!(changes, vec![PageChangesNeeded::Tags, PageChangesNeeded::Render]); - } - - #[test] - fn can_find_category_changes_in_page_frontmatter() { - let current = PageFrontMatter { category: Some("a category".to_string()), ..PageFrontMatter::default() }; - let changes = find_page_front_matter_changes(¤t, &PageFrontMatter::default()); - assert_eq!(changes, vec![PageChangesNeeded::Categories, PageChangesNeeded::Render]); + assert_eq!(changes, vec![PageChangesNeeded::Taxonomies, PageChangesNeeded::Render]); } #[test] fn can_find_multiple_changes_in_page_frontmatter() { - let current = PageFrontMatter { category: Some("a category".to_string()), order: Some(1), ..PageFrontMatter::default() }; + let mut taxonomies = HashMap::new(); + taxonomies.insert("categories".to_string(), vec!["a category".to_string()]); + let current = PageFrontMatter { taxonomies, order: Some(1), ..PageFrontMatter::default() }; let changes = find_page_front_matter_changes(¤t, &PageFrontMatter::default()); - assert_eq!(changes, vec![PageChangesNeeded::Categories, PageChangesNeeded::Sort, PageChangesNeeded::Render]); + assert_eq!(changes, vec![PageChangesNeeded::Taxonomies, PageChangesNeeded::Sort, PageChangesNeeded::Render]); } #[test] diff --git a/components/rebuild/tests/rebuild.rs b/components/rebuild/tests/rebuild.rs index 9aeabfbc..42bbae2e 100644 --- a/components/rebuild/tests/rebuild.rs +++ b/components/rebuild/tests/rebuild.rs @@ -1,6 +1,6 @@ extern crate rebuild; extern crate site; -extern crate tempdir; +extern crate tempfile; extern crate fs_extra; use std::env; @@ -8,7 +8,7 @@ use std::fs::{remove_dir_all, File}; use std::io::prelude::*; use fs_extra::dir; -use tempdir::TempDir; +use tempfile::tempdir; use site::Site; use rebuild::after_content_change; @@ -74,12 +74,12 @@ macro_rules! file_contains { #[test] fn can_rebuild_after_simple_change_to_page_content() { - let tmp_dir = TempDir::new("example").expect("create temp dir"); + let tmp_dir = tempdir().expect("create temp dir"); let (site_path, mut site) = load_and_build_site!(tmp_dir); let file_path = edit_file!(site_path, "content/rebuild/first.md", br#" +++ title = "first" -order = 1 +weight = 1 date = 2017-01-01 +++ @@ -92,12 +92,12 @@ Some content"#); #[test] fn can_rebuild_after_title_change_page_global_func_usage() { - let tmp_dir = TempDir::new("example").expect("create temp dir"); + let tmp_dir = tempdir().expect("create temp dir"); let (site_path, mut site) = load_and_build_site!(tmp_dir); let file_path = edit_file!(site_path, "content/rebuild/first.md", br#" +++ title = "Premier" -order = 10 +weight = 10 date = 2017-01-01 +++ @@ -110,17 +110,17 @@ date = 2017-01-01 #[test] fn can_rebuild_after_sort_change_in_section() { - let tmp_dir = TempDir::new("example").expect("create temp dir"); + let tmp_dir = tempdir().expect("create temp dir"); let (site_path, mut site) = load_and_build_site!(tmp_dir); let file_path = edit_file!(site_path, "content/rebuild/_index.md", br#" +++ paginate_by = 1 -sort_by = "order" +sort_by = "weight" template = "rebuild.html" +++ "#); let res = after_content_change(&mut site, &file_path); assert!(res.is_ok()); - assert!(file_contains!(site_path, "public/rebuild/index.html", "

second

first

")); + assert!(file_contains!(site_path, "public/rebuild/index.html", "

first

second

")); } diff --git a/components/rendering/Cargo.toml b/components/rendering/Cargo.toml index e9a19e29..22a6e6fa 100644 --- a/components/rendering/Cargo.toml +++ b/components/rendering/Cargo.toml @@ -4,19 +4,22 @@ version = "0.1.0" authors = ["Vincent Prouillet "] [dependencies] -tera = "0.11" -regex = "1" -lazy_static = "1" +tera = { version = "0.11", features = ["preserve_order"] } syntect = "2" pulldown-cmark = "0" slug = "0.1" serde = "1" serde_derive = "1" +pest = "1" +pest_derive = "1" errors = { path = "../errors" } front_matter = { path = "../front_matter" } highlighting = { path = "../highlighting"} utils = { path = "../utils" } +config = { path = "../config" } +link_checker = { path = "../link_checker" } [dev-dependencies] templates = { path = "../templates" } + diff --git a/components/rendering/benches/all.rs b/components/rendering/benches/all.rs index 999268cf..e996a256 100644 --- a/components/rendering/benches/all.rs +++ b/components/rendering/benches/all.rs @@ -3,13 +3,15 @@ extern crate test; extern crate tera; extern crate rendering; +extern crate config; extern crate front_matter; use std::collections::HashMap; use tera::Tera; -use rendering::{Context, markdown_to_html}; +use rendering::{RenderContext, render_content, render_shortcodes}; use front_matter::InsertAnchor; +use config::Config; static CONTENT: &'static str = r#" # Modus cognitius profanam ne duae virtutis mundi @@ -84,17 +86,46 @@ if __name__ == "__main__": "#; #[bench] -fn bench_markdown_to_html_with_highlighting(b: &mut test::Bencher) { - let tera_ctx = Tera::default(); +fn bench_render_content_with_highlighting(b: &mut test::Bencher) { + let mut tera = Tera::default(); + tera.add_raw_template("shortcodes/youtube.html", "{{id}}").unwrap(); let permalinks_ctx = HashMap::new(); - let context = Context::new(&tera_ctx, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None); - b.iter(|| markdown_to_html(CONTENT, &context)); + let config = Config::default(); + let context = RenderContext::new(&tera, &config, "", &permalinks_ctx, InsertAnchor::None); + b.iter(|| render_content(CONTENT, &context).unwrap()); } #[bench] -fn bench_markdown_to_html_without_highlighting(b: &mut test::Bencher) { - let tera_ctx = Tera::default(); +fn bench_render_content_without_highlighting(b: &mut test::Bencher) { + let mut tera = Tera::default(); + tera.add_raw_template("shortcodes/youtube.html", "{{id}}").unwrap(); let permalinks_ctx = HashMap::new(); - let context = Context::new(&tera_ctx, false, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None); - b.iter(|| markdown_to_html(CONTENT, &context)); + let mut config = Config::default(); + config.highlight_code = false; + let context = RenderContext::new(&tera, &config, "", &permalinks_ctx, InsertAnchor::None); + b.iter(|| render_content(CONTENT, &context).unwrap()); } + +#[bench] +fn bench_render_content_no_shortcode(b: &mut test::Bencher) { + let tera = Tera::default(); + let content2 = CONTENT.replace(r#"{{ youtube(id="my_youtube_id") }}"#, ""); + let mut config = Config::default(); + config.highlight_code = false; + let permalinks_ctx = HashMap::new(); + let context = RenderContext::new(&tera, &config, "", &permalinks_ctx, InsertAnchor::None); + + b.iter(|| render_content(&content2, &context).unwrap()); +} + +#[bench] +fn bench_render_shortcodes_one_present(b: &mut test::Bencher) { + let mut tera = Tera::default(); + tera.add_raw_template("shortcodes/youtube.html", "{{id}}").unwrap(); + let config = Config::default(); + let permalinks_ctx = HashMap::new(); + let context = RenderContext::new(&tera, &config, "", &permalinks_ctx, InsertAnchor::None); + + b.iter(|| render_shortcodes(CONTENT, &context)); +} + diff --git a/components/rendering/src/content.pest b/components/rendering/src/content.pest new file mode 100644 index 00000000..662ac3aa --- /dev/null +++ b/components/rendering/src/content.pest @@ -0,0 +1,72 @@ +// Partly taken from Tera + +whitespace = _{ " " | "\t" | "\r" | "\n" } + +/// LITERALS +int = @{ "-" ? ~ ("0" | '1'..'9' ~ '0'..'9' * ) } +float = @{ + "-" ? ~ + ( + "0" ~ "." ~ '0'..'9' + | + '1'..'9' ~ '0'..'9' * ~ "." ~ '0'..'9' + + ) +} +// matches anything between 2 double quotes +double_quoted_string = @{ "\"" ~ (!("\"") ~ any)* ~ "\""} +// matches anything between 2 single quotes +single_quoted_string = @{ "\'" ~ (!("\'") ~ any)* ~ "\'"} +// matches anything between 2 backquotes\backticks +backquoted_quoted_string = @{ "`" ~ (!("`") ~ any)* ~ "`"} + +string = @{ + double_quoted_string | + single_quoted_string | + backquoted_quoted_string +} + +boolean = { "true" | "false" } + +literal = { boolean | string | float | int } +array = { "[" ~ (literal ~ ",")* ~ literal? ~ "]"} + +/// Idents + +all_chars = _{'a'..'z' | 'A'..'Z' | "_" | '0'..'9'} +ident = @{ + ('a'..'z' | 'A'..'Z' | "_") ~ + all_chars* +} + +/// Now specific to Gutenberg + +// shortcode is abbreviated to sc to keep things short + +kwarg = { ident ~ "=" ~ (literal | array) } +kwargs = _{ kwarg ~ ("," ~ kwarg )* } +sc_def = _{ ident ~ "(" ~ kwargs* ~ ")" } + +inline_shortcode = !{ "{{" ~ sc_def ~ "}}" } +ignored_inline_shortcode = !{ "{{/*" ~ sc_def ~ "*/}}" } + +sc_body_start = !{ "{%" ~ sc_def ~ "%}" } +sc_body_end = !{ "{%" ~ "end" ~ "%}" } +ignored_sc_body_start = !{ "{%/*" ~ sc_def ~ "*/%}" } +ignored_sc_body_end = !{ "{%/*" ~ "end" ~ "*/%}" } + +shortcode_with_body = !{ sc_body_start ~ text_in_body_sc ~ sc_body_end } +ignored_shortcode_with_body = !{ ignored_sc_body_start ~ text_in_ignored_body_sc ~ ignored_sc_body_end } + +text_in_body_sc = ${ (!(sc_body_end) ~ any)+ } +text_in_ignored_body_sc = ${ (!(ignored_sc_body_end) ~ any)+ } +text = ${ (!(inline_shortcode | ignored_inline_shortcode | sc_body_start | ignored_sc_body_start) ~ any)+ } + +content = _{ + ignored_inline_shortcode | + inline_shortcode | + ignored_shortcode_with_body | + shortcode_with_body | + text +} + + +page = ${ soi ~ content* ~ eoi } diff --git a/components/rendering/src/context.rs b/components/rendering/src/context.rs index aa866be6..68bc215b 100644 --- a/components/rendering/src/context.rs +++ b/components/rendering/src/context.rs @@ -1,41 +1,38 @@ use std::collections::HashMap; -use tera::Tera; - +use tera::{Tera, Context}; use front_matter::InsertAnchor; +use config::Config; /// All the information from the gutenberg site that is needed to render HTML from markdown #[derive(Debug)] -pub struct Context<'a> { +pub struct RenderContext<'a> { pub tera: &'a Tera, - pub highlight_code: bool, - pub highlight_theme: String, - pub current_page_permalink: String, + pub config: &'a Config, + pub tera_context: Context, + pub current_page_permalink: &'a str, pub permalinks: &'a HashMap, pub insert_anchor: InsertAnchor, } -impl<'a> Context<'a> { +impl<'a> RenderContext<'a> { pub fn new( tera: &'a Tera, - highlight_code: bool, - highlight_theme: String, - current_page_permalink: &str, + config: &'a Config, + current_page_permalink: &'a str, permalinks: &'a HashMap, insert_anchor: InsertAnchor, - ) -> Context<'a> { - Context { + ) -> RenderContext<'a> { + let mut tera_context = Context::new(); + tera_context.insert("config", config); + RenderContext { tera, - current_page_permalink: current_page_permalink.to_string(), + tera_context, + current_page_permalink, permalinks, insert_anchor, - highlight_code, - highlight_theme, + config, } } - - pub fn should_insert_anchor(&self) -> bool { - self.insert_anchor != InsertAnchor::None - } } diff --git a/components/rendering/src/lib.rs b/components/rendering/src/lib.rs index 1dfd39b5..9e6d7257 100644 --- a/components/rendering/src/lib.rs +++ b/components/rendering/src/lib.rs @@ -1,6 +1,3 @@ -#[macro_use] -extern crate lazy_static; -extern crate regex; extern crate tera; extern crate syntect; extern crate pulldown_cmark; @@ -8,20 +5,39 @@ extern crate slug; #[macro_use] extern crate serde_derive; extern crate serde; +extern crate pest; +#[macro_use] +extern crate pest_derive; +#[macro_use] extern crate errors; extern crate front_matter; extern crate highlighting; extern crate utils; +extern crate config; +extern crate link_checker; #[cfg(test)] extern crate templates; mod context; mod markdown; -mod short_code; mod table_of_contents; +mod shortcode; -pub use context::Context; -pub use markdown::markdown_to_html; +use errors::Result; + +use markdown::markdown_to_html; pub use table_of_contents::Header; +pub use shortcode::render_shortcodes; +pub use context::RenderContext; + +pub fn render_content(content: &str, context: &RenderContext) -> Result<(String, Vec
)> { + // Don't do anything if there is nothing like a shortcode in the content + if content.contains("{{") || content.contains("{%") { + let rendered = render_shortcodes(content, context)?; + return markdown_to_html(&rendered, context); + } + + markdown_to_html(&content, context) +} diff --git a/components/rendering/src/markdown.rs b/components/rendering/src/markdown.rs index b993dd70..60ea6725 100644 --- a/components/rendering/src/markdown.rs +++ b/components/rendering/src/markdown.rs @@ -8,37 +8,42 @@ use syntect::html::{start_coloured_html_snippet, styles_to_coloured_html, Includ use errors::Result; use utils::site::resolve_internal_link; -use context::Context; -use highlighting::{SYNTAX_SET, THEME_SET}; -use short_code::{SHORTCODE_RE, ShortCode, parse_shortcode, render_simple_shortcode}; +use highlighting::{get_highlighter, THEME_SET}; +use link_checker::check_url; + use table_of_contents::{TempHeader, Header, make_table_of_contents}; +use context::RenderContext; + +// We might have cases where the slug is already present in our list of anchor +// for example an article could have several titles named Example +// We add a counter after the slug if the slug is already present, which +// means we will have example, example-1, example-2 etc +fn find_anchor(anchors: &[String], name: String, level: u8) -> String { + if level == 0 && !anchors.contains(&name) { + return name.to_string(); + } + + let new_anchor = format!("{}-{}", name, level + 1); + if !anchors.contains(&new_anchor) { + return new_anchor; + } + + find_anchor(anchors, name, level + 1) +} + +fn is_colocated_asset_link(link: &str) -> bool { + !link.contains("/") // http://, ftp://, ../ etc + && !link.starts_with("mailto:") +} -pub fn markdown_to_html(content: &str, context: &Context) -> Result<(String, Vec
)> { - // We try to be smart about highlighting code as it can be time-consuming - // If the global config disables it, then we do nothing. However, - // if we see a code block in the content, we assume that this page needs - // to be highlighted. It could potentially have false positive if the content - // has ``` in it but that seems kind of unlikely - let should_highlight = if context.highlight_code { - content.contains("```") - } else { - false - }; +pub fn markdown_to_html(content: &str, context: &RenderContext) -> Result<(String, Vec
)> { + // the rendered html + let mut html = String::with_capacity(content.len()); // Set while parsing let mut error = None; + let mut highlighter: Option = None; - // the markdown parser will send several Text event if a markdown character - // is present in it, for example `hello_test` will be split in 2: hello and _test. - // Since we can use those chars in shortcode arguments, we need to collect - // the full shortcode somehow first - let mut current_shortcode = String::new(); - let mut shortcode_block = None; - // shortcodes live outside of paragraph so we need to ensure we don't close - // a paragraph that has already been closed - let mut added_shortcode = false; - // Don't transform things that look like shortcodes in code blocks - let mut in_code_block = false; // If we get text in header, we need to insert the id and a anchor let mut in_header = false; // pulldown_cmark can send several text events for a title if there are markdown @@ -46,254 +51,169 @@ pub fn markdown_to_html(content: &str, context: &Context) -> Result<(String, Vec let mut header_created = false; let mut anchors: Vec = vec![]; - // the rendered html - let mut html = String::new(); - - // We might have cases where the slug is already present in our list of anchor - // for example an article could have several titles named Example - // We add a counter after the slug if the slug is already present, which - // means we will have example, example-1, example-2 etc - fn find_anchor(anchors: &[String], name: String, level: u8) -> String { - if level == 0 && !anchors.contains(&name) { - return name.to_string(); - } - - let new_anchor = format!("{}-{}", name, level + 1); - if !anchors.contains(&new_anchor) { - return new_anchor; - } - - find_anchor(anchors, name, level + 1) - } - let mut headers = vec![]; // Defaults to a 0 level so not a real header // It should be an Option ideally but not worth the hassle to update let mut temp_header = TempHeader::default(); - let mut clear_shortcode_block = false; let mut opts = Options::empty(); opts.insert(OPTION_ENABLE_TABLES); opts.insert(OPTION_ENABLE_FOOTNOTES); { - let parser = Parser::new_ext(content, opts).map(|event| { - if clear_shortcode_block { - clear_shortcode_block = false; - shortcode_block = None; - } - match event { - Event::Text(mut text) => { - // Header first - if in_header { - if header_created { - temp_header.push(&text); + Event::Text(text) => { + // Header first + if in_header { + if header_created { + temp_header.push(&text); + return Event::Html(Owned(String::new())); + } + let id = find_anchor(&anchors, slugify(&text), 0); + anchors.push(id.clone()); + // update the header and add it to the list + temp_header.permalink = format!("{}#{}", context.current_page_permalink, id); + temp_header.id = id; + // += as we might have some or other things already there + temp_header.title += &text; + header_created = true; return Event::Html(Owned(String::new())); } - let id = find_anchor(&anchors, slugify(&text), 0); - anchors.push(id.clone()); - // update the header and add it to the list - temp_header.id = id.clone(); - // += as we might have some or other things already there - temp_header.title += &text; - temp_header.permalink = format!("{}#{}", context.current_page_permalink, id); - header_created = true; - return Event::Html(Owned(String::new())); - } - // if we are in the middle of a code block - if let Some(ref mut highlighter) = highlighter { - let highlighted = &highlighter.highlight(&text); - let html = styles_to_coloured_html(highlighted, IncludeBackground::Yes); - return Event::Html(Owned(html)); - } - - if in_code_block { - return Event::Text(text); - } - - // Are we in the middle of a shortcode that somehow got cut off - // by the markdown parser? - if current_shortcode.is_empty() { - if text.starts_with("{{") && !text.ends_with("}}") { - current_shortcode += &text; - } else if text.starts_with("{%") && !text.ends_with("%}") { - current_shortcode += &text; + // if we are in the middle of a code block + if let Some(ref mut highlighter) = highlighter { + let highlighted = &highlighter.highlight(&text); + let html = styles_to_coloured_html(highlighted, IncludeBackground::Yes); + return Event::Html(Owned(html)); } - } else { - current_shortcode += &text; + + // Business as usual + Event::Text(text) } + Event::Start(Tag::CodeBlock(ref info)) => { + if !context.config.highlight_code { + return Event::Html(Owned("
".to_string()));
+                    }
 
-                if current_shortcode.ends_with("}}") || current_shortcode.ends_with("%}") {
-                    text = Owned(current_shortcode.clone());
-                    current_shortcode = String::new();
+                    let theme = &THEME_SET.themes[&context.config.highlight_theme];
+                    highlighter = Some(get_highlighter(&theme, info));
+                    let snippet = start_coloured_html_snippet(theme);
+                    Event::Html(Owned(snippet))
                 }
+                Event::End(Tag::CodeBlock(_)) => {
+                    if !context.config.highlight_code {
+                        return Event::Html(Owned("
\n".to_string())); + } + // reset highlight and close the code block + highlighter = None; + Event::Html(Owned("".to_string())) + } + 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, + ) + ); + } - // Shortcode without body - if shortcode_block.is_none() && text.starts_with("{{") && text.ends_with("}}") && SHORTCODE_RE.is_match(&text) { - let (name, args) = parse_shortcode(&text); - - added_shortcode = true; - match render_simple_shortcode(context.tera, &name, &args) { - // Make before and after cleaning up of extra

/

tags more parallel. - // Or, in other words: - // TERRIBLE HORRIBLE NO GOOD VERY BAD HACK - Ok(s) => return Event::Html(Owned(format!("

{}

", s))), - Err(e) => { - error = Some(e); - return Event::Html(Owned(String::new())); + Event::Start(Tag::Image(src, title)) + } + Event::Start(Tag::Link(link, title)) => { + // A few situations here: + // - it could be a relative link (starting with `./`) + // - it could be a link to a co-located asset + // - it could be a normal link + // - any of those can be in a header or not: if it's in a header + // we need to append to a string + let fixed_link = if link.starts_with("./") { + match resolve_internal_link(&link, context.permalinks) { + Ok(url) => url, + Err(_) => { + error = Some(format!("Relative link {} not found.", link).into()); + return Event::Html(Owned(String::new())); + } } - } - } - - // Shortcode with a body - if shortcode_block.is_none() && text.starts_with("{%") && text.ends_with("%}") { - if SHORTCODE_RE.is_match(&text) { - let (name, args) = parse_shortcode(&text); - shortcode_block = Some(ShortCode::new(&name, args)); - } - // Don't return anything - return Event::Text(Owned(String::new())); - } - - // If we have some text while in a shortcode, it's either the body - // or the end tag - if shortcode_block.is_some() { - if let Some(ref mut shortcode) = shortcode_block { - if text.trim() == "{% end %}" { - added_shortcode = true; - clear_shortcode_block = true; - match shortcode.render(context.tera) { - Ok(s) => return Event::Html(Owned(format!("

{}", s))), - Err(e) => { - error = Some(e); - return Event::Html(Owned(String::new())); - } + } else if is_colocated_asset_link(&link) { + format!("{}{}", context.current_page_permalink, link) + } else { + if context.config.check_external_links && !link.starts_with('#') { + let res = check_url(&link); + if res.is_valid() { + link.to_string() + } else { + error = Some( + format!("Link {} is not valid: {}", link, res.message()).into() + ); + String::new() } } else { - shortcode.append(&text); - return Event::Html(Owned(String::new())); - } - } - } - - // Business as usual - Event::Text(text) - }, - Event::Start(Tag::CodeBlock(ref info)) => { - in_code_block = true; - if !should_highlight { - return Event::Html(Owned("
".to_owned()));
-                }
-                let theme = &THEME_SET.themes[&context.highlight_theme];
-                highlighter = SYNTAX_SET.with(|ss| {
-                    let syntax = info
-                        .split(' ')
-                        .next()
-                        .and_then(|lang| ss.find_syntax_by_token(lang))
-                        .unwrap_or_else(|| ss.find_syntax_plain_text());
-                    Some(HighlightLines::new(syntax, theme))
-                });
-                let snippet = start_coloured_html_snippet(theme);
-                Event::Html(Owned(snippet))
-            },
-            Event::End(Tag::CodeBlock(_)) => {
-                in_code_block = false;
-                if !should_highlight{
-                    return Event::Html(Owned("
\n".to_owned())) - } - // reset highlight and close the code block - highlighter = None; - Event::Html(Owned("".to_owned())) - }, - // Need to handle relative links - Event::Start(Tag::Link(ref link, ref title)) => { - if in_header { - return Event::Html(Owned("".to_owned())); - } - if link.starts_with("./") { - match resolve_internal_link(link, context.permalinks) { - Ok(url) => { - return Event::Start(Tag::Link(Owned(url), title.clone())); - }, - Err(_) => { - error = Some(format!("Relative link {} not found.", link).into()); - return Event::Html(Owned("".to_string())); + link.to_string() } }; - } - Event::Start(Tag::Link(link.clone(), title.clone())) - }, - Event::End(Tag::Link(_, _)) => { - if in_header { - return Event::Html(Owned("".to_owned())); + if in_header { + let html = if title.is_empty() { + format!("", fixed_link) + } else { + format!("", fixed_link, title) + }; + temp_header.push(&html); + return Event::Html(Owned(String::new())); + } + + Event::Start(Tag::Link(Owned(fixed_link), title)) } - event + Event::End(Tag::Link(_, _)) => { + if in_header { + temp_header.push(""); + return Event::Html(Owned(String::new())); + } + event + } + Event::Start(Tag::Code) => { + if in_header { + temp_header.push(""); + return Event::Html(Owned(String::new())); + } + event + } + Event::End(Tag::Code) => { + if in_header { + temp_header.push(""); + return Event::Html(Owned(String::new())); + } + event + } + Event::Start(Tag::Header(num)) => { + in_header = true; + temp_header = TempHeader::new(num); + Event::Html(Owned(String::new())) + } + Event::End(Tag::Header(_)) => { + // End of a header, reset all the things and return the stringified + // version of the header + in_header = false; + header_created = false; + let val = temp_header.to_string(context.tera, context.insert_anchor); + headers.push(temp_header.clone()); + temp_header = TempHeader::default(); + Event::Html(Owned(val)) + } + _ => event, } - // need to know when we are in a code block to disable shortcodes in them - Event::Start(Tag::Code) => { - in_code_block = true; - if in_header { - temp_header.push(""); - return Event::Html(Owned(String::new())); - } - event - }, - Event::End(Tag::Code) => { - in_code_block = false; - if in_header { - temp_header.push(""); - return Event::Html(Owned(String::new())); - } - event - }, - Event::Start(Tag::Header(num)) => { - in_header = true; - temp_header = TempHeader::new(num); - Event::Html(Owned(String::new())) - }, - Event::End(Tag::Header(_)) => { - // End of a header, reset all the things and return the stringified version of the header - in_header = false; - header_created = false; - let val = temp_header.to_string(context); - headers.push(temp_header.clone()); - temp_header = TempHeader::default(); - Event::Html(Owned(val)) - }, - // If we added shortcodes, don't close a paragraph since there's none - Event::End(Tag::Paragraph) => { - if added_shortcode { - added_shortcode = false; - return Event::Html(Owned("".to_owned())); - } - event - }, - // Ignore softbreaks inside shortcodes - Event::SoftBreak => { - if shortcode_block.is_some() { - return Event::Html(Owned("".to_owned())); - } - event - }, - _ => { - // println!("event = {:?}", event); - event - }, - }}); + }); cmark::html::push_html(&mut html, parser); } - if !current_shortcode.is_empty() { - return Err(format!("A shortcode was not closed properly:\n{:?}", current_shortcode).into()); - } - match error { Some(e) => Err(e), - None => Ok((html.replace("

", "").replace("

", "

"), make_table_of_contents(&headers))), + None => Ok(( + html.replace("

", "").replace("

", "

"), + make_table_of_contents(&headers) + )), } } diff --git a/components/rendering/src/short_code.rs b/components/rendering/src/short_code.rs deleted file mode 100644 index f1cd3fbb..00000000 --- a/components/rendering/src/short_code.rs +++ /dev/null @@ -1,190 +0,0 @@ -use std::collections::HashMap; - -use regex::Regex; -use tera::{Tera, Context, Value, to_value}; - -use errors::{Result, ResultExt}; - -lazy_static!{ - // Does this look like a shortcode? - pub static ref SHORTCODE_RE: Regex = Regex::new( - r#"\{(?:%|\{)\s+(\w+?)\((\w+?="?(?:.|\n)+?"?)?\)\s+(?:%|\})\}"# - ).unwrap(); - - // Parse the shortcode args with capture groups named after their type - pub static ref SHORTCODE_ARGS_RE: Regex = Regex::new( - r#"(?P\w+)=\s*((?P".*?")|(?P[-+]?[0-9]+\.[0-9]+)|(?P[-+]?[0-9]+)|(?Ptrue|false))"# - ).unwrap(); -} - -/// A shortcode that has a body -/// Called by having some content like {% ... %} body {% end %} -/// We need the struct to hold the data while we're processing the markdown -#[derive(Debug)] -pub struct ShortCode { - name: String, - args: HashMap, - body: String, -} - -impl ShortCode { - pub fn new(name: &str, args: HashMap) -> ShortCode { - ShortCode { - name: name.to_string(), - args, - body: String::new(), - } - } - - pub fn append(&mut self, text: &str) { - self.body.push_str(text) - } - - pub fn render(&self, tera: &Tera) -> Result { - let mut context = Context::new(); - for (key, value) in &self.args { - context.add(key, value); - } - context.add("body", &self.body); - let tpl_name = format!("shortcodes/{}.html", self.name); - tera.render(&tpl_name, &context) - .chain_err(|| format!("Failed to render {} shortcode", self.name)) - } -} - -/// Parse a shortcode without a body -pub fn parse_shortcode(input: &str) -> (String, HashMap) { - let mut args = HashMap::new(); - let caps = SHORTCODE_RE.captures(input).unwrap(); - // caps[0] is the full match - let name = &caps[1]; - - if let Some(arg_list) = caps.get(2) { - for arg_cap in SHORTCODE_ARGS_RE.captures_iter(arg_list.as_str()) { - let arg_name = arg_cap["name"].trim().to_string(); - - if let Some(arg_val) = arg_cap.name("str") { - args.insert(arg_name, to_value(arg_val.as_str().replace("\"", "")).unwrap()); - continue; - } - - if let Some(arg_val) = arg_cap.name("int") { - args.insert(arg_name, to_value(arg_val.as_str().parse::().unwrap()).unwrap()); - continue; - } - - if let Some(arg_val) = arg_cap.name("float") { - args.insert(arg_name, to_value(arg_val.as_str().parse::().unwrap()).unwrap()); - continue; - } - - if let Some(arg_val) = arg_cap.name("bool") { - args.insert(arg_name, to_value(arg_val.as_str() == "true").unwrap()); - continue; - } - } - } - - (name.to_string(), args) -} - -/// Renders a shortcode or return an error -pub fn render_simple_shortcode(tera: &Tera, name: &str, args: &HashMap) -> Result { - let mut context = Context::new(); - for (key, value) in args.iter() { - context.add(key, value); - } - let tpl_name = format!("shortcodes/{}.html", name); - - tera.render(&tpl_name, &context).chain_err(|| format!("Failed to render {} shortcode", name)) -} - - -#[cfg(test)] -mod tests { - use super::{parse_shortcode, SHORTCODE_RE}; - - #[test] - fn can_match_all_kinds_of_shortcode() { - let inputs = vec![ - "{{ basic() }}", - "{{ basic(ho=1) }}", - "{{ basic(ho=\"hey\") }}", - "{{ basic(ho=\"hey_underscore\") }}", - "{{ basic(ho=\"hey-dash\") }}", - "{% basic(ho=\"hey-dash\") %}", - "{% basic(ho=\"hey_underscore\") %}", - "{% basic() %}", - "{% quo_te(author=\"Bob\") %}", - "{{ quo_te(author=\"Bob\") }}", - // https://github.com/Keats/gutenberg/issues/229 - r#"{{ youtube(id="dQw4w9WgXcQ", - - autoplay=true) }}"#, - ]; - - for i in inputs { - println!("{}", i); - assert!(SHORTCODE_RE.is_match(i)); - } - } - - // https://github.com/Keats/gutenberg/issues/228 - #[test] - fn doesnt_panic_on_invalid_shortcode() { - let (name, args) = parse_shortcode(r#"{{ youtube(id="dQw4w9WgXcQ", autoplay) }}"#); - assert_eq!(name, "youtube"); - assert_eq!(args["id"], "dQw4w9WgXcQ"); - assert!(args.get("autoplay").is_none()); - } - - #[test] - fn can_parse_simple_shortcode_no_arg() { - let (name, args) = parse_shortcode(r#"{{ basic() }}"#); - assert_eq!(name, "basic"); - assert!(args.is_empty()); - } - - #[test] - fn can_parse_simple_shortcode_one_arg() { - let (name, args) = parse_shortcode(r#"{{ youtube(id="w7Ft2ymGmfc") }}"#); - assert_eq!(name, "youtube"); - assert_eq!(args["id"], "w7Ft2ymGmfc"); - } - - #[test] - fn can_parse_simple_shortcode_several_arg() { - let (name, args) = parse_shortcode(r#"{{ youtube(id="w7Ft2ymGmfc", autoplay=true) }}"#); - assert_eq!(name, "youtube"); - assert_eq!(args["id"], "w7Ft2ymGmfc"); - assert_eq!(args["autoplay"], true); - } - - #[test] - fn can_parse_block_shortcode_several_arg() { - let (name, args) = parse_shortcode(r#"{% youtube(id="w7Ft2ymGmfc", autoplay=true) %}"#); - assert_eq!(name, "youtube"); - assert_eq!(args["id"], "w7Ft2ymGmfc"); - assert_eq!(args["autoplay"], true); - } - - #[test] - fn can_parse_shortcode_number() { - let (name, args) = parse_shortcode(r#"{% test(int=42, float=42.0, autoplay=false) %}"#); - assert_eq!(name, "test"); - assert_eq!(args["int"], 42); - assert_eq!(args["float"], 42.0); - assert_eq!(args["autoplay"], false); - } - - // https://github.com/Keats/gutenberg/issues/249 - #[test] - fn can_parse_shortcode_with_comma_in_it() { - let (name, args) = parse_shortcode( - r#"{% quote(author="C++ Standard Core Language Defect Reports and Accepted Issues, Revision 82, delete and user-written deallocation function", href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#348") %}"# - ); - assert_eq!(name, "quote"); - assert_eq!(args["author"], "C++ Standard Core Language Defect Reports and Accepted Issues, Revision 82, delete and user-written deallocation function"); - assert_eq!(args["href"], "http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#348"); - } -} diff --git a/components/rendering/src/shortcode.rs b/components/rendering/src/shortcode.rs new file mode 100644 index 00000000..94ec3827 --- /dev/null +++ b/components/rendering/src/shortcode.rs @@ -0,0 +1,362 @@ +use pest::Parser; +use pest::iterators::Pair; +use tera::{Map, Context, Value, to_value}; + +use errors::{Result, ResultExt}; +use ::context::RenderContext; + +// This include forces recompiling this source file if the grammar file changes. +// Uncomment it when doing changes to the .pest file +const _GRAMMAR: &str = include_str!("content.pest"); + +#[derive(Parser)] +#[grammar = "content.pest"] +pub struct ContentParser; + + +fn replace_string_markers(input: &str) -> String { + match input.chars().next().unwrap() { + '"' => input.replace('"', "").to_string(), + '\'' => input.replace('\'', "").to_string(), + '`' => input.replace('`', "").to_string(), + _ => unreachable!("How did you even get there"), + } +} + +fn parse_literal(pair: Pair) -> Value { + let mut val = None; + for p in pair.into_inner() { + match p.as_rule() { + Rule::boolean => match p.as_str() { + "true" => val = Some(Value::Bool(true)), + "false" => val = Some(Value::Bool(false)), + _ => unreachable!(), + }, + Rule::string => val = Some(Value::String(replace_string_markers(p.as_str()))), + Rule::float => { + val = Some(to_value(p.as_str().parse::().unwrap()).unwrap()); + } + Rule::int => { + val = Some(to_value(p.as_str().parse::().unwrap()).unwrap()); + } + _ => unreachable!("Unknown literal: {:?}", p) + }; + } + + val.unwrap() +} + +/// Returns (shortcode_name, kwargs) +fn parse_shortcode_call(pair: Pair) -> (String, Map) { + let mut name = None; + let mut args = Map::new(); + + for p in pair.into_inner() { + match p.as_rule() { + Rule::ident => { name = Some(p.into_span().as_str().to_string()); } + Rule::kwarg => { + let mut arg_name = None; + let mut arg_val = None; + for p2 in p.into_inner() { + match p2.as_rule() { + Rule::ident => { arg_name = Some(p2.into_span().as_str().to_string()); } + Rule::literal => { arg_val = Some(parse_literal(p2)); } + Rule::array => { + let mut vals = vec![]; + for p3 in p2.into_inner() { + match p3.as_rule() { + Rule::literal => vals.push(parse_literal(p3)), + _ => unreachable!("Got something other than literal in an array: {:?}", p3), + } + } + arg_val = Some(Value::Array(vals)); + } + _ => unreachable!("Got something unexpected in a kwarg: {:?}", p2), + } + } + + args.insert(arg_name.unwrap(), arg_val.unwrap()); + } + _ => unreachable!("Got something unexpected in a shortcode: {:?}", p) + } + } + (name.unwrap(), args) +} + + +fn render_shortcode(name: String, args: Map, context: &RenderContext, body: Option<&str>) -> Result { + let mut tera_context = Context::new(); + for (key, value) in args.iter() { + tera_context.insert(key, value); + } + if let Some(ref b) = body { + // Trimming right to avoid most shortcodes with bodies ending up with a HTML new line + tera_context.insert("body", b.trim_right()); + } + tera_context.extend(context.tera_context.clone()); + let tpl_name = format!("shortcodes/{}.html", name); + + let res = context.tera + .render(&tpl_name, &tera_context) + .chain_err(|| format!("Failed to render {} shortcode", name))?; + + // We trim left every single line of a shortcode to avoid the accidental + // shortcode counted as code block because of 4 spaces left padding + Ok(res.lines().map(|s| s.trim_left()).collect()) +} + +pub fn render_shortcodes(content: &str, context: &RenderContext) -> Result { + let mut res = String::with_capacity(content.len()); + + let mut pairs = match ContentParser::parse(Rule::page, content) { + Ok(p) => p, + Err(e) => { + let fancy_e = e.renamed_rules(|rule| { + match *rule { + Rule::int => "an integer".to_string(), + Rule::float => "a float".to_string(), + Rule::string => "a string".to_string(), + Rule::literal => "a literal (int, float, string, bool)".to_string(), + Rule::array => "an array".to_string(), + Rule::kwarg => "a keyword argument".to_string(), + Rule::ident => "an identifier".to_string(), + Rule::inline_shortcode => "an inline shortcode".to_string(), + Rule::ignored_inline_shortcode => "an ignored inline shortcode".to_string(), + Rule::sc_body_start => "the start of a shortcode".to_string(), + Rule::ignored_sc_body_start => "the start of an ignored shortcode".to_string(), + Rule::text => "some text".to_string(), + _ => format!("TODO error: {:?}", rule).to_string(), + } + }); + bail!("{}", fancy_e); + } + }; + + // We have at least a `page` pair + for p in pairs.next().unwrap().into_inner() { + match p.as_rule() { + Rule::text | Rule::text_in_ignored_body_sc | Rule::text_in_body_sc => res.push_str(p.into_span().as_str()), + Rule::inline_shortcode => { + let (name, args) = parse_shortcode_call(p); + res.push_str(&render_shortcode(name, args, context, None)?); + } + Rule::shortcode_with_body => { + let mut inner = p.into_inner(); + // 3 items in inner: call, body, end + // we don't care about the closing tag + let (name, args) = parse_shortcode_call(inner.next().unwrap()); + let body = inner.next().unwrap().into_span().as_str(); + res.push_str(&render_shortcode(name, args, context, Some(body))?); + } + Rule::ignored_inline_shortcode => { + res.push_str( + &p.into_span().as_str() + .replacen("{{/*", "{{", 1) + .replacen("*/}}", "}}", 1) + ); + } + Rule::ignored_shortcode_with_body => { + for p2 in p.into_inner() { + match p2.as_rule() { + Rule::ignored_sc_body_start | Rule::ignored_sc_body_end => { + res.push_str( + &p2.into_span().as_str() + .replacen("{%/*", "{%", 1) + .replacen("*/%}", "%}", 1) + ); + } + Rule::text_in_ignored_body_sc => res.push_str(p2.into_span().as_str()), + _ => unreachable!("Got something weird in an ignored shortcode: {:?}", p2), + } + } + } + _ => unreachable!("unexpected page rule: {:?}", p.as_rule()), + } + } + + Ok(res) +} + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + use tera::Tera; + use config::Config; + use front_matter::InsertAnchor; + use super::*; + + macro_rules! assert_lex_rule { + ($rule: expr, $input: expr) => { + let res = ContentParser::parse($rule, $input); + println!("{:?}", $input); + println!("{:#?}", res); + if res.is_err() { + println!("{}", res.unwrap_err()); + panic!(); + } + assert!(res.is_ok()); + assert_eq!(res.unwrap().last().unwrap().into_span().end(), $input.len()); + }; + } + + fn render_shortcodes(code: &str, tera: &Tera) -> String { + let config = Config::default(); + let permalinks = HashMap::new(); + let context = RenderContext::new(&tera, &config, "", &permalinks, InsertAnchor::None); + super::render_shortcodes(code, &context).unwrap() + } + + #[test] + fn lex_text() { + let inputs = vec!["Hello world", "HEllo \n world", "Hello 1 2 true false 'hey'"]; + for i in inputs { + assert_lex_rule!(Rule::text, i); + } + } + + #[test] + fn lex_inline_shortcode() { + let inputs = vec![ + "{{ youtube() }}", + "{{ youtube(id=1, autoplay=true, url='hey') }}", + "{{ youtube(id=1, \nautoplay=true, url='hey') }}", + ]; + for i in inputs { + assert_lex_rule!(Rule::inline_shortcode, i); + } + } + + #[test] + fn lex_inline_ignored_shortcode() { + let inputs = vec![ + "{{/* youtube() */}}", + "{{/* youtube(id=1, autoplay=true, url='hey') */}}", + "{{/* youtube(id=1, \nautoplay=true, \nurl='hey') */}}", + ]; + for i in inputs { + assert_lex_rule!(Rule::ignored_inline_shortcode, i); + } + } + + #[test] + fn lex_shortcode_with_body() { + let inputs = vec![ + r#"{% youtube() %} + Some text + {% end %}"#, + r#"{% youtube(id=1, + autoplay=true, url='hey') %} + Some text + {% end %}"#, + ]; + for i in inputs { + assert_lex_rule!(Rule::shortcode_with_body, i); + } + } + + #[test] + fn lex_ignored_shortcode_with_body() { + let inputs = vec![ + r#"{%/* youtube() */%} + Some text + {%/* end */%}"#, + r#"{%/* youtube(id=1, + autoplay=true, url='hey') */%} + Some text + {%/* end */%}"#, + ]; + for i in inputs { + assert_lex_rule!(Rule::ignored_shortcode_with_body, i); + } + } + + #[test] + fn lex_page() { + let inputs = vec![ + "Some text and a shortcode `{{/* youtube() */}}`", + "{{ youtube(id=1, autoplay=true, url='hey') }}", + "{{ youtube(id=1, \nautoplay=true, url='hey') }} that's it", + r#" + This is a test + {% hello() %} + Body {{ var }} + {% end %} + "# + ]; + for i in inputs { + assert_lex_rule!(Rule::page, i); + } + } + + #[test] + fn does_nothing_with_no_shortcodes() { + let res = render_shortcodes("Hello World", &Tera::default()); + assert_eq!(res, "Hello World"); + } + + #[test] + fn can_unignore_inline_shortcode() { + let res = render_shortcodes("Hello World {{/* youtube() */}}", &Tera::default()); + assert_eq!(res, "Hello World {{ youtube() }}"); + } + + #[test] + fn can_unignore_shortcode_with_body() { + let res = render_shortcodes(r#" +Hello World +{%/* youtube() */%}Some body {{ hello() }}{%/* end */%}"#, &Tera::default()); + assert_eq!(res, "\nHello World\n{% youtube() %}Some body {{ hello() }}{% end %}"); + } + + #[test] + fn can_parse_shortcode_arguments() { + let inputs = vec![ + ("{{ youtube() }}", "youtube", Map::new()), + ( + "{{ youtube(id=1, autoplay=true, hello='salut', float=1.2) }}", + "youtube", + { + let mut m = Map::new(); + m.insert("id".to_string(), to_value(1).unwrap()); + m.insert("autoplay".to_string(), to_value(true).unwrap()); + m.insert("hello".to_string(), to_value("salut").unwrap()); + m.insert("float".to_string(), to_value(1.2).unwrap()); + m + } + ), + ( + "{{ gallery(photos=['something', 'else'], fullscreen=true) }}", + "gallery", + { + let mut m = Map::new(); + m.insert("photos".to_string(), to_value(["something", "else"]).unwrap()); + m.insert("fullscreen".to_string(), to_value(true).unwrap()); + m + } + ), + ]; + + for (i, n, a) in inputs { + let mut res = ContentParser::parse(Rule::inline_shortcode, i).unwrap(); + let (name, args) = parse_shortcode_call(res.next().unwrap()); + assert_eq!(name, n); + assert_eq!(args, a); + } + } + + #[test] + fn can_render_inline_shortcodes() { + let mut tera = Tera::default(); + tera.add_raw_template("shortcodes/youtube.html", "Hello {{id}}").unwrap(); + let res = render_shortcodes("Inline {{ youtube(id=1) }}.", &tera); + assert_eq!(res, "Inline Hello 1."); + } + + #[test] + fn can_render_shortcodes_with_body() { + let mut tera = Tera::default(); + tera.add_raw_template("shortcodes/youtube.html", "{{body}}").unwrap(); + let res = render_shortcodes("Body\n {% youtube() %}Hey!{% end %}", &tera); + assert_eq!(res, "Body\n Hey!"); + } +} diff --git a/components/rendering/src/table_of_contents.rs b/components/rendering/src/table_of_contents.rs index 70f75954..e6bd5dc5 100644 --- a/components/rendering/src/table_of_contents.rs +++ b/components/rendering/src/table_of_contents.rs @@ -1,8 +1,6 @@ -use tera::{Context as TeraContext}; +use tera::{Tera, Context as TeraContext}; use front_matter::InsertAnchor; -use context::Context; - #[derive(Debug, PartialEq, Clone, Serialize)] pub struct Header { @@ -50,19 +48,19 @@ impl TempHeader { } /// Transform all the information we have about this header into the HTML string for it - pub fn to_string(&self, context: &Context) -> String { - let anchor_link = if context.should_insert_anchor() { + pub fn to_string(&self, tera: &Tera, insert_anchor: InsertAnchor) -> String { + let anchor_link = if insert_anchor != InsertAnchor::None { let mut c = TeraContext::new(); c.add("id", &self.id); - context.tera.render("anchor-link.html", &c).unwrap() + tera.render("anchor-link.html", &c).unwrap() } else { String::new() }; - match context.insert_anchor { - InsertAnchor::None => format!("{t}\n", lvl=self.level, t=self.title, id=self.id), - InsertAnchor::Left => format!("{a}{t}\n", lvl=self.level, a=anchor_link, t=self.title, id=self.id), - InsertAnchor::Right => format!("{t}{a}\n", lvl=self.level, a=anchor_link, t=self.title, id=self.id), + match insert_anchor { + InsertAnchor::None => format!("{t}\n", lvl = self.level, t = self.title, id = self.id), + InsertAnchor::Left => format!("{a}{t}\n", lvl = self.level, a = anchor_link, t = self.title, id = self.id), + InsertAnchor::Right => format!("{t}{a}\n", lvl = self.level, a = anchor_link, t = self.title, id = self.id), } } } diff --git a/components/rendering/tests/markdown.rs b/components/rendering/tests/markdown.rs index 8dbdcc73..e4d50c1a 100644 --- a/components/rendering/tests/markdown.rs +++ b/components/rendering/tests/markdown.rs @@ -2,22 +2,25 @@ extern crate tera; extern crate front_matter; extern crate templates; extern crate rendering; +extern crate config; use std::collections::HashMap; use tera::Tera; +use config::Config; use front_matter::InsertAnchor; use templates::GUTENBERG_TERA; -use rendering::{Context, markdown_to_html}; +use rendering::{RenderContext, render_content}; #[test] -fn can_do_markdown_to_html_simple() { +fn can_do_render_content_simple() { let tera_ctx = Tera::default(); let permalinks_ctx = HashMap::new(); - let context = Context::new(&tera_ctx, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None); - let res = markdown_to_html("hello", &context).unwrap(); + let config = Config::default(); + let context = RenderContext::new(&tera_ctx, &config, "", &permalinks_ctx, InsertAnchor::None); + let res = render_content("hello", &context).unwrap(); assert_eq!(res.0, "

hello

\n"); } @@ -25,9 +28,10 @@ fn can_do_markdown_to_html_simple() { fn doesnt_highlight_code_block_with_highlighting_off() { let tera_ctx = Tera::default(); let permalinks_ctx = HashMap::new(); - let mut context = Context::new(&tera_ctx, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None); - context.highlight_code = false; - let res = markdown_to_html("```\n$ gutenberg server\n```", &context).unwrap(); + let mut config = Config::default(); + config.highlight_code = false; + let context = RenderContext::new(&tera_ctx, &config, "", &permalinks_ctx, InsertAnchor::None); + let res = render_content("```\n$ gutenberg server\n```", &context).unwrap(); assert_eq!( res.0, "
$ gutenberg server\n
\n" @@ -38,8 +42,9 @@ fn doesnt_highlight_code_block_with_highlighting_off() { fn can_highlight_code_block_no_lang() { let tera_ctx = Tera::default(); let permalinks_ctx = HashMap::new(); - let context = Context::new(&tera_ctx, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None); - let res = markdown_to_html("```\n$ gutenberg server\n$ ping\n```", &context).unwrap(); + let config = Config::default(); + let context = RenderContext::new(&tera_ctx, &config, "", &permalinks_ctx, InsertAnchor::None); + let res = render_content("```\n$ gutenberg server\n$ ping\n```", &context).unwrap(); assert_eq!( res.0, "
\n$ gutenberg server\n$ ping\n
" @@ -50,8 +55,9 @@ fn can_highlight_code_block_no_lang() { fn can_highlight_code_block_with_lang() { let tera_ctx = Tera::default(); let permalinks_ctx = HashMap::new(); - let context = Context::new(&tera_ctx, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None); - let res = markdown_to_html("```python\nlist.append(1)\n```", &context).unwrap(); + let config = Config::default(); + let context = RenderContext::new(&tera_ctx, &config, "", &permalinks_ctx, InsertAnchor::None); + let res = render_content("```python\nlist.append(1)\n```", &context).unwrap(); assert_eq!( res.0, "
\nlist.append(1)\n
" @@ -62,8 +68,9 @@ fn can_highlight_code_block_with_lang() { fn can_higlight_code_block_with_unknown_lang() { let tera_ctx = Tera::default(); let permalinks_ctx = HashMap::new(); - let context = Context::new(&tera_ctx, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None); - let res = markdown_to_html("```yolo\nlist.append(1)\n```", &context).unwrap(); + let config = Config::default(); + let context = RenderContext::new(&tera_ctx, &config, "", &permalinks_ctx, InsertAnchor::None); + let res = render_content("```yolo\nlist.append(1)\n```", &context).unwrap(); // defaults to plain text assert_eq!( res.0, @@ -74,8 +81,9 @@ fn can_higlight_code_block_with_unknown_lang() { #[test] fn can_render_shortcode() { let permalinks_ctx = HashMap::new(); - let context = Context::new(&GUTENBERG_TERA, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None); - let res = markdown_to_html(r#" + let config = Config::default(); + let context = RenderContext::new(&GUTENBERG_TERA, &config, "", &permalinks_ctx, InsertAnchor::None); + let res = render_content(r#" Hello {{ youtube(id="ub36ffWAqgQ") }} @@ -87,7 +95,8 @@ Hello #[test] fn can_render_shortcode_with_markdown_char_in_args_name() { let permalinks_ctx = HashMap::new(); - let context = Context::new(&GUTENBERG_TERA, true, "base16-ocean-dark".to_string(), "", &permalinks_ctx, InsertAnchor::None); + let config = Config::default(); + let context = RenderContext::new(&GUTENBERG_TERA, &config, "", &permalinks_ctx, InsertAnchor::None); let input = vec![ "name", "na_me", @@ -95,7 +104,7 @@ fn can_render_shortcode_with_markdown_char_in_args_name() { "n1", ]; for i in input { - let res = markdown_to_html(&format!("{{{{ youtube(id=\"hey\", {}=1) }}}}", i), &context).unwrap(); + let res = render_content(&format!("{{{{ youtube(id=\"hey\", {}=1) }}}}", i), &context).unwrap(); assert!(res.0.contains(r#" @@ -32,45 +32,54 @@ are in a `if` statement, we can assume they are optional. That's it, Gutenberg will now recognise this template as a shortcode named `youtube` (the filename minus the `.html` extension). +The markdown renderer will wrap an inline HTML node like `` or `` into a paragraph. If you want to disable that, +simply wrap your shortcode in a `div`. + ## Using shortcodes -There are two kinds of shortcodes: +There are two kinds of shortcodes: - ones that do not take a body like the YouTube example above - ones that do, a quote for example In both cases, their arguments must be named and they will all be passed to the template. -Any shortcodes in code blocks will be ignored. - -Lastly, a shortcode name (and thus the corresponding `.html` file) as well as the arguments name +Lastly, a shortcode name (and thus the corresponding `.html` file) as well as the arguments name can only contain numbers, letters and underscores, or in Regex terms the following: `[0-9A-Za-z_]`. While theoretically an argument name could be a number, it will not be possible to use it in the template in that case. -Argument values can be of 4 types: +Argument values can be of 5 types: -- string: surrounded by double quotes `"..."` +- string: surrounded by double quotes, single quotes or backticks - bool: `true` or `false` - float: a number with a `.` in it - integer: a number without a `.` in it +- array: an array of any kind of values, except arrays Malformed values will be silently ignored. +Both type of shortcodes will also get either a `page` or `section` variable depending on where they were used and a `config` +one. Those values will overwrite any arguments passed to a shortcode so shortcodes should not use arguments called like one +of these. + ### Shortcodes without body -On a new line, call the shortcode as if it was a Tera function in a variable block. All the examples below are valid +Simply call the shortcode as if it was a Tera function in a variable block. All the examples below are valid calls of the YouTube shortcode. ```md Here is a YouTube video: -{{ youtube(id="dQw4w9WgXcQ") }} +{{/* youtube(id="dQw4w9WgXcQ") */}} -{{ youtube(id="dQw4w9WgXcQ", autoplay=true) }} +{{/* youtube(id="dQw4w9WgXcQ", autoplay=true) */}} -{{ youtube(id="dQw4w9WgXcQ", autoplay=true, class="youtube") }} +An inline {{/* youtube(id="dQw4w9WgXcQ", autoplay=true, class="youtube") */}} shortcode ``` +Note that if you want to have some content that looks like a shortcode but not have Gutenberg try to render it, +you will need to escape it by using `{{/*` and `*/}}` instead of `{{` and `}}`. + ### Shortcodes with body For example, let's imagine we have the following shortcode `quote.html` template: @@ -86,14 +95,18 @@ We could use it in our markup file like so: ```md As someone said: -{% quote(author="Vincent") %} +{%/* quote(author="Vincent") */%} A quote -{% end %} +{%/* end */%} ``` The body of the shortcode will be automatically passed down to the rendering context as the `body` variable and needs to be in a newline. +If you want to have some content that looks like a shortcode but not have Gutenberg try to render it, +you will need to escape it by using `{%/*` and `*/%}` instead of `{%` and `%}`. You won't need to escape +anything else until the closing tag. + ## Built-in shortcodes Gutenberg comes with a few built-in shortcodes. If you want to override a default shortcode template, @@ -112,11 +125,11 @@ The arguments are: Usage example: ```md -{{ youtube(id="dQw4w9WgXcQ") }} +{{/* youtube(id="dQw4w9WgXcQ") */}} -{{ youtube(id="dQw4w9WgXcQ", autoplay=true) }} +{{/* youtube(id="dQw4w9WgXcQ", autoplay=true) */}} -{{ youtube(id="dQw4w9WgXcQ", autoplay=true, class="youtube") }} +{{/* youtube(id="dQw4w9WgXcQ", autoplay=true, class="youtube") */}} ``` Result example: @@ -134,9 +147,9 @@ The arguments are: Usage example: ```md -{{ vimeo(id="124313553") }} +{{/* vimeo(id="124313553") */}} -{{ vimeo(id="124313553", class="vimeo") }} +{{/* vimeo(id="124313553", class="vimeo") */}} ``` Result example: @@ -145,7 +158,7 @@ Result example: ### Streamable Embed a player for a Streamable video. - + The arguments are: - `id`: the video id (mandatory) @@ -154,17 +167,17 @@ The arguments are: Usage example: ```md -{{ streamable(id="2zt0") }} +{{/* streamable(id="92ok4") */}} -{{ streamable(id="2zt0", class="streamble") }} +{{/* streamable(id="92ok4", class="streamble") */}} ``` Result example: -{{ streamable(id="2zt0") }} +{{ streamable(id="92ok4") }} ### Gist -Embed a [Github gist](). +Embed a [Github gist](https://gist.github.com). The arguments are: @@ -175,9 +188,9 @@ The arguments are: Usage example: ```md -{{ gist(url="https://gist.github.com/Keats/e5fb6aad409f28721c0ba14161644c57") }} +{{/* gist(url="https://gist.github.com/Keats/e5fb6aad409f28721c0ba14161644c57") */}} -{{ gist(url="https://gist.github.com/Keats/e5fb6aad409f28721c0ba14161644c57", class="gist") }} +{{/* gist(url="https://gist.github.com/Keats/e5fb6aad409f28721c0ba14161644c57", class="gist") */}} ``` Result example: diff --git a/docs/content/documentation/content/tags-categories.md b/docs/content/documentation/content/tags-categories.md deleted file mode 100644 index 20eae9e8..00000000 --- a/docs/content/documentation/content/tags-categories.md +++ /dev/null @@ -1,23 +0,0 @@ -+++ -title = "Tags & Categories" -weight = 90 -+++ - -Gutenberg has built-in support for basic taxonomies: tags and categories. - -Those taxonomies are automatically built across the whole site based on -the `tags` and `category` fields of the front-matter: you do not need to define -that a tag or a category exists. You have to set `generate_tags_pages` and/or -`generate_categories_pages` in your [config.toml](./documentation/getting-started/configuration.md). - -The taxonomy pages will only be created if at least one item is found and -are available at the following paths: - -```plain -$BASE_URL/tags/ -$BASE_URL/tags/$TAG_SLUG -$BASE_URL/categories/ -$BASE_URL/categories/$CATEGORY_SLUG -``` - -It is currently not possible to change those paths or to create custom taxonomies. diff --git a/docs/content/documentation/content/taxonomies.md b/docs/content/documentation/content/taxonomies.md new file mode 100644 index 00000000..7ddad6b3 --- /dev/null +++ b/docs/content/documentation/content/taxonomies.md @@ -0,0 +1,36 @@ ++++ +title = "Taxonomies" +weight = 90 ++++ + +Gutenberg has built-in support for taxonomies. + +The first step is to define the taxonomies in your [config.toml](./documentation/getting-started/configuration.md). + +A taxonomy has 4 variables: + +- `name`: a required string that will be used in the URLs, usually the plural version (i.e. tags, categories etc) +- `paginate_by`: if this is set to a number, each term page will be paginated by this much. +- `paginate_path`: if set, will be the path used by paginated page and the page number will be appended after it. +For example the default would be page/1 +- `rss`: if set to `true`, a RSS feed will be generated for each individual term. + +Once this is done, you can then set taxonomies in your content and Gutenberg will pick +them up: + +```toml ++++ +... +[taxonomies] +tags = ["rust", "web"] +categories = ["programming"] ++++ +``` + +The taxonomy pages will only be created if at least one non-draft page is found and +are available at the following paths: + +```plain +$BASE_URL/$NAME/ +$BASE_URL/$NAME/$SLUG +``` diff --git a/docs/content/documentation/getting-started/configuration.md b/docs/content/documentation/getting-started/configuration.md index 0cf21b79..f8eecb32 100644 --- a/docs/content/documentation/getting-started/configuration.md +++ b/docs/content/documentation/getting-started/configuration.md @@ -40,13 +40,15 @@ generate_rss = false # The number of articles to include in the RSS feed rss_limit = 20 -# Whether to generate a tags page and individual -# tag pages for pages with tags -generate_tags_pages = false - -# Whether to generate a categories page and individual -# category pages for pages with a category -generate_categories_pages = false +# The taxonomies to be rendered for that site and their configuration +# Example: +# taxonomies = [ +# {name: "tags", rss: true}, # each tag will have its own RSS feed +# {name: "categories", paginate_by: 5}, # 5 items per page for a term +# {name: "authors"}, # Basic definition: no RSS or pagination +# ] +# +taxonomies = [] # Whether to compile the Sass files found in the `sass` directory compile_sass = false @@ -55,6 +57,12 @@ compile_sass = false # content for the `default_language` build_search_index = false +# Go through every links in all content and check if the links are valid +# If a link is invalid (404, 500, etc), the build will error. +# Link checking can take a very long time if you have many links so this should +# only enabled once in a while to catch any dead links. +check_external_links = false + # A list of glob patterns specifying asset files to ignore when # processing the content directory. # Defaults to none, which means all asset files are copied over to the public folder. diff --git a/docs/content/documentation/templates/404.md b/docs/content/documentation/templates/404.md new file mode 100644 index 00000000..8a55b800 --- /dev/null +++ b/docs/content/documentation/templates/404.md @@ -0,0 +1,8 @@ ++++ +title = "404 error page" +weight = 80 ++++ + +Gutenberg will look for a `404.html` file in the `templates` directory or +use the built-in one. The default template is very basic and gets a simple +variable in the context: the site `config`. diff --git a/docs/content/documentation/templates/archive.md b/docs/content/documentation/templates/archive.md new file mode 100644 index 00000000..cf04c061 --- /dev/null +++ b/docs/content/documentation/templates/archive.md @@ -0,0 +1,23 @@ ++++ +title = "Archive" +weight = 90 ++++ + +Gutenberg doesn't have a built-in way to display an archive page, a page showing +all post titles ordered by year. However, this can be accomplished directly in the templates: + +```jinja2 +{% for year, posts in section.pages | group_by(attribute="year") %} +

{{ year }}

+ +
+{% endfor %} +``` + +This snippet assumes that posts are sorted by date and that you want to display the archive +in a descending order. If you want to show articles in a ascending order, simply add a `reverse` filter +after the `group_by`. diff --git a/docs/content/documentation/templates/overview.md b/docs/content/documentation/templates/overview.md index 01810e65..a9ab635b 100644 --- a/docs/content/documentation/templates/overview.md +++ b/docs/content/documentation/templates/overview.md @@ -20,21 +20,21 @@ A few variables are available on all templates minus RSS and sitemap: - `current_url`: the full URL for that page ## Standard Templates -By default, Gutenberg will look for three templates: `index.html`, which is applied -to the site homepage; `section.html`, which is applied to all sections (any HTML -page generated by creating a directory within your `content` directory); and -`page.html`, which is applied to all pages (any HTML page generated by creating a +By default, Gutenberg will look for three templates: `index.html`, which is applied +to the site homepage; `section.html`, which is applied to all sections (any HTML +page generated by creating a directory within your `content` directory); and +`page.html`, which is applied to all pages (any HTML page generated by creating a `.md` file within your `content` directory). The homepage is always a section (regardless of whether it contains other pages). -Thus, the `index.html` and `section.html` templates both have access to the +Thus, the `index.html` and `section.html` templates both have access to the section variables. The `page.html` template has access to the page variables. The page and section variables are described in more detail in the next section of this documentation. ## Built-in Templates -Gutenberg comes with three built-in templates: `rss.xml`, `sitemap.xml`, and +Gutenberg comes with three built-in templates: `rss.xml`, `sitemap.xml`, and `robots.txt` (each described in their own section of this documentation). -Additionally, themes can add their own templates, which will be applied if not +Additionally, themes can add their own templates, which will be applied if not overridden. You can override built-in or theme templates by creating a template with same name in the correct path. For example, you can override the RSS template by creating a `templates/rss.xml` file. @@ -105,14 +105,14 @@ This can also be used to get the permalinks for static assets for example if we want to link to the file that is located at `static/css/app.css`: ```jinja2 -{{ get_url(path="css/app.css") }} +{{/* get_url(path="css/app.css") */}} ``` For assets it is reccommended that you pass `trailing_slash=false` to the `get_url` function. This prevents errors when dealing with certain hosting providers. An example is: ```jinja2 -{{ get_url(path="css/app.css", trailing_slash=false) }} +{{/* get_url(path="css/app.css", trailing_slash=false) */}} ``` In the case of non-internal links, you can also add a cachebust of the format `?t=1290192` at the end of a URL @@ -120,19 +120,30 @@ by passing `cachebust=true` to the `get_url` function. ### `get_taxonomy_url` -Gets the permalink for the tag or category given. +Gets the permalink for the taxonomy item found. ```jinja2 -{% set url = get_taxonomy_url(kind="category", name=page.category) %} +{% set url = get_taxonomy_url(kind="categories", name=page.taxonomies.category) %} ``` The `name` will almost come from a variable but in case you want to do it manually, the value should be the same as the one in the front-matter, not the slugified version. +### `get_taxonomy` +Gets the whole taxonomy of a specific kind. + +```jinja2 +{% set categories = get_taxonomy_url(kind="categories") %} +``` + ### `trans` Gets the translation of the given `key`, for the `default_language` or the `language given ```jinja2 -{{ trans(key="title") }} -{{ trans(key="title", lang="fr") }} +{{/* trans(key="title") */}} +{{/* trans(key="title", lang="fr") */}} ``` + +### `resize_image` +Resizes an image file. +Pease refer to [_Content / Image Processing_](./documentation/content/image-processing/index.md) for complete documentation. diff --git a/docs/content/documentation/templates/pages-sections.md b/docs/content/documentation/templates/pages-sections.md index f09c777c..297c95b3 100644 --- a/docs/content/documentation/templates/pages-sections.md +++ b/docs/content/documentation/templates/pages-sections.md @@ -32,15 +32,24 @@ extra: HashMap; word_count: Number; // Based on https://help.medium.com/hc/en-us/articles/214991667-Read-time reading_time: Number; -// `previous` and `next` are only filled if the content can be sorted -previous: Page?; -next: Page?; +// `earlier` and `later` are only populated if the section variable `sort_by` is set to `date` +earlier: Page?; +later: Page?; +// `heavier` and `lighter` are only populated if the section variable `sort_by` is set to `weight` +heavier: Page?; +lighter: Page?; // See the Table of contents section below for more details toc: Array
; +// Year/month/day is only set if the page has a date and month/day are 1-indexed +year: Number?; +month: Number?; +day: Number?; +// Paths of colocated assets, relative to the content directory +assets: Array; ``` ## Section variables -By default, Gutenberg will try to load `templates/index.html` for `content/_index.md` +By default, Gutenberg will try to load `templates/index.html` for `content/_index.md` and `templates/section.html` for others `_index.md` files. If there isn't one, it will render the built-in template: a blank page. @@ -63,7 +72,7 @@ extra: HashMap; pages: Array; // Direct subsections to this section, sorted by subsections weight subsections: Array
; -// Naive word count, will not work for languages without whitespace +// Unicode word count word_count: Number; // Based on https://help.medium.com/hc/en-us/articles/214991667-Read-time reading_time: Number; diff --git a/docs/content/documentation/templates/pagination.md b/docs/content/documentation/templates/pagination.md index e9561c0b..ccbf6ab9 100644 --- a/docs/content/documentation/templates/pagination.md +++ b/docs/content/documentation/templates/pagination.md @@ -3,9 +3,14 @@ title = "Pagination" weight = 30 +++ +Two things can get paginated: a section or a taxonomy term. + A paginated section gets the same `section` variable as a normal -[section page](./documentation/templates/pages-sections.md#section-variables). -In addition, a paginated section gets a `paginator` variable of the `Pager` type: +[section page](./documentation/templates/pages-sections.md#section-variables) +while a paginated taxonomy gets the a `taxonomy` variable of type `TaxonomyConfig`, equivalent +to the taxonomy definition in the `config.toml`. + +In addition, a paginated page gets a `paginator` variable of the `Pager` type: ```ts // How many items per page diff --git a/docs/content/documentation/templates/tags-categories.md b/docs/content/documentation/templates/tags-categories.md deleted file mode 100644 index db5adf33..00000000 --- a/docs/content/documentation/templates/tags-categories.md +++ /dev/null @@ -1,31 +0,0 @@ -+++ -title = "Tags & Categories" -weight = 40 -+++ - -Tags and categories actually get the same data but with different variable names. -The default templates for those pages are the following: - -- `tags.html`: list of tags, gets variable `tags` sorted alphabetically -- `tag.html`: individual tag, gets variable `tag` -- `categories.html`: list of categories, gets variable `categories` sorted alphabetically -- `category.html`: individual category, gets variable `category` - -You can override any of those templates by putting one with the same name in the `templates` directory. -`tags` and `categories` both are an array of `TaxonomyItem` sorted alphabetically, while `tag` and `category` -are a `TaxonomyItem`. - -A `TaxonomyItem` has the following fields: - -```ts -name: String; -slug: String; -permalink: String; -pages: Array; -``` - -As `pages` can span many sections, the `pages` array is sorted by date. - -Currently, there is no way to define different taxonomy templates per section, change -the path used for them or paginate them. - diff --git a/docs/content/documentation/templates/taxonomies.md b/docs/content/documentation/templates/taxonomies.md new file mode 100644 index 00000000..66cf3add --- /dev/null +++ b/docs/content/documentation/templates/taxonomies.md @@ -0,0 +1,51 @@ ++++ +title = "Taxonomies" +weight = 40 ++++ + +Gutenberg will look up the following files in the `templates` directory: + +- `$TAXONOMY_NAME/single.html` +- `$TAXONOMY_NAME/list.html` + +First, a `TaxonomyTerm` has the following fields: + +```ts +name: String; +slug: String; +permalink: String; +pages: Array; +``` + +## Non-paginated taxonomies +If a taxonomy is not paginated, the templates get the following variables: + +### Single term (`single.html`) +```ts +// The site config +config: Config; +// The data of the taxonomy, from the config +taxonomy: TaxonomyConfig; +// The current full permalink for that page +current_url: String; +// The current path for that page +current_path: String; +// The current term being rendered +term: TaxonomyTerm; +``` + +### Taxonomy list (`list.html`) +```ts +// The site config +config: Config; +// The data of the taxonomy, from the config +taxonomy: TaxonomyConfig; +// The current full permalink for that page +current_url: String; +// The current path for that page +current_path: String; +// All terms for that taxonomy +terms: Array; +``` + +## Paginated taxonomies diff --git a/docs/static/_processed_images/0478482c742970ac00.jpg b/docs/static/_processed_images/0478482c742970ac00.jpg new file mode 100644 index 00000000..0096f3ee Binary files /dev/null and b/docs/static/_processed_images/0478482c742970ac00.jpg differ diff --git a/docs/static/_processed_images/2b6a3e5a28bab1f100.jpg b/docs/static/_processed_images/2b6a3e5a28bab1f100.jpg new file mode 100644 index 00000000..30e1fdbc Binary files /dev/null and b/docs/static/_processed_images/2b6a3e5a28bab1f100.jpg differ diff --git a/docs/static/_processed_images/3dba59a146f3bc0900.jpg b/docs/static/_processed_images/3dba59a146f3bc0900.jpg new file mode 100644 index 00000000..944db1d2 Binary files /dev/null and b/docs/static/_processed_images/3dba59a146f3bc0900.jpg differ diff --git a/docs/static/_processed_images/5e399fa94c88057a00.jpg b/docs/static/_processed_images/5e399fa94c88057a00.jpg new file mode 100644 index 00000000..202a9c2f Binary files /dev/null and b/docs/static/_processed_images/5e399fa94c88057a00.jpg differ diff --git a/docs/static/_processed_images/63d5c27341a9885c00.jpg b/docs/static/_processed_images/63d5c27341a9885c00.jpg new file mode 100644 index 00000000..7073c0a7 Binary files /dev/null and b/docs/static/_processed_images/63d5c27341a9885c00.jpg differ diff --git a/docs/static/_processed_images/63fe884d13fd318d00.jpg b/docs/static/_processed_images/63fe884d13fd318d00.jpg new file mode 100644 index 00000000..72cc2c59 Binary files /dev/null and b/docs/static/_processed_images/63fe884d13fd318d00.jpg differ diff --git a/docs/static/_processed_images/8b446e542d0b692d00.jpg b/docs/static/_processed_images/8b446e542d0b692d00.jpg new file mode 100644 index 00000000..7073c0a7 Binary files /dev/null and b/docs/static/_processed_images/8b446e542d0b692d00.jpg differ diff --git a/docs/static/_processed_images/ab39b603591b3e3300.jpg b/docs/static/_processed_images/ab39b603591b3e3300.jpg new file mode 100644 index 00000000..d52d902b Binary files /dev/null and b/docs/static/_processed_images/ab39b603591b3e3300.jpg differ diff --git a/docs/static/_processed_images/d91d0751df06edce00.jpg b/docs/static/_processed_images/d91d0751df06edce00.jpg new file mode 100644 index 00000000..8c7b2e77 Binary files /dev/null and b/docs/static/_processed_images/d91d0751df06edce00.jpg differ diff --git a/docs/static/_processed_images/e690cdfaf053bbd700.jpg b/docs/static/_processed_images/e690cdfaf053bbd700.jpg new file mode 100644 index 00000000..81faf5f1 Binary files /dev/null and b/docs/static/_processed_images/e690cdfaf053bbd700.jpg differ diff --git a/docs/templates/shortcodes/gallery.html b/docs/templates/shortcodes/gallery.html new file mode 100644 index 00000000..d2afc716 --- /dev/null +++ b/docs/templates/shortcodes/gallery.html @@ -0,0 +1,8 @@ +{% for asset in page.assets %} + {% if asset is ending_with(".jpg") %} + + + +   + {% endif %} +{% endfor %} diff --git a/docs/templates/shortcodes/resize_image.html b/docs/templates/shortcodes/resize_image.html new file mode 100644 index 00000000..f33bc3b5 --- /dev/null +++ b/docs/templates/shortcodes/resize_image.html @@ -0,0 +1 @@ + diff --git a/src/cmd/serve.rs b/src/cmd/serve.rs index 67486d69..68fd1a36 100644 --- a/src/cmd/serve.rs +++ b/src/cmd/serve.rs @@ -22,16 +22,16 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. use std::env; -use std::fs::remove_dir_all; -use std::path::Path; +use std::fs::{remove_dir_all, File}; +use std::io::{self, Read}; +use std::path::{Path, PathBuf}; use std::sync::mpsc::channel; use std::time::{Instant, Duration}; use std::thread; use chrono::prelude::*; -use iron::{Iron, Request, IronResult, Response, status}; -use mount::Mount; -use staticfile::Static; +use actix_web::{self, fs, http, server, App, HttpRequest, HttpResponse, Responder}; +use actix_web::middleware::{Middleware, Started, Response}; use notify::{Watcher, RecursiveMode, watcher}; use ws::{WebSocket, Sender, Message}; use ctrlc; @@ -58,9 +58,36 @@ enum ChangeKind { // errors const LIVE_RELOAD: &'static str = include_str!("livereload.js"); +struct NotFoundHandler { + rendered_template: PathBuf, +} -fn livereload_handler(_: &mut Request) -> IronResult { - Ok(Response::with((status::Ok, LIVE_RELOAD.to_string()))) +impl Middleware for NotFoundHandler { + fn start(&self, _req: &HttpRequest) -> actix_web::Result { + Ok(Started::Done) + } + + fn response( + &self, + _req: &HttpRequest, + mut resp: HttpResponse, + ) -> actix_web::Result { + if http::StatusCode::NOT_FOUND == resp.status() { + let mut fh = File::open(&self.rendered_template)?; + let mut buf: Vec = vec![]; + let _ = fh.read_to_end(&mut buf)?; + resp.replace_body(buf); + resp.headers_mut().insert( + http::header::CONTENT_TYPE, + http::header::HeaderValue::from_static("text/html"), + ); + } + Ok(Response::Done(resp)) + } +} + +fn livereload_handler(_: &HttpRequest) -> &'static str { + LIVE_RELOAD } fn rebuild_done_handling(broadcaster: &Sender, res: Result<()>, reload_path: &str) { @@ -86,13 +113,13 @@ fn create_new_site(interface: &str, port: &str, output_dir: &str, base_url: &str let base_address = format!("{}:{}", base_url, port); let address = format!("{}:{}", interface, port); - - site.config.base_url = if site.config.base_url.ends_with('/') { + let base_url = if site.config.base_url.ends_with('/') { format!("http://{}/", base_address) } else { format!("http://{}", base_address) }; + site.set_base_url(base_url); site.set_output_path(output_dir); site.load()?; site.enable_live_reload(); @@ -102,6 +129,24 @@ fn create_new_site(interface: &str, port: &str, output_dir: &str, base_url: &str Ok((site, address)) } +/// Attempt to render `index.html` when a directory is requested. +/// +/// The default "batteries included" mechanisms for actix to handle directory +/// listings rely on redirection which behaves oddly (the location headers +/// seem to use relative paths for some reason). +/// They also mean that the address in the browser will include the +/// `index.html` on a successful redirect (rare), which is unsightly. +/// +/// Rather than deal with all of that, we can hijack a hook for presenting a +/// custom directory listing response and serve it up using their +/// `NamedFile` responder. +fn handle_directory<'a, 'b>(dir: &'a fs::Directory, req: &'b HttpRequest) -> io::Result { + let mut path = PathBuf::from(&dir.base); + path.push(&dir.path); + path.push("index.html"); + fs::NamedFile::open(path)?.respond_to(req) +} + pub fn serve(interface: &str, port: &str, output_dir: &str, base_url: &str, config_file: &str) -> Result<()> { let start = Instant::now(); let (mut site, address) = create_new_site(interface, port, output_dir, base_url, config_file)?; @@ -115,8 +160,8 @@ pub fn serve(interface: &str, port: &str, output_dir: &str, base_url: &str, conf .chain_err(|| "Can't watch the `content` folder. Does it exist?")?; watcher.watch("templates/", RecursiveMode::Recursive) .chain_err(|| "Can't watch the `templates` folder. Does it exist?")?; - watcher.watch("config.toml", RecursiveMode::Recursive) - .chain_err(|| "Can't watch the `config.toml` file. Does it exist?")?; + watcher.watch(config_file, RecursiveMode::Recursive) + .chain_err(|| "Can't watch the `config` file. Does it exist?")?; if Path::new("static").exists() { watching_static = true; @@ -127,16 +172,32 @@ pub fn serve(interface: &str, port: &str, output_dir: &str, base_url: &str, conf // Sass support is optional so don't make it an error to no have a sass folder let _ = watcher.watch("sass/", RecursiveMode::Recursive); - let ws_address = format!("{}:{}", interface, "1112"); + let ws_address = format!("{}:{}", interface, site.live_reload.unwrap()); + let output_path = Path::new(output_dir).to_path_buf(); - // Start a webserver that serves the `output_dir` directory - let mut mount = Mount::new(); - mount.mount("/", Static::new(Path::new(output_dir))); - mount.mount("/livereload.js", livereload_handler); - // Starts with a _ to not trigger the unused lint - // we need to assign to a variable otherwise it will block - let _iron = Iron::new(mount).http(address.as_str()) - .chain_err(|| "Can't start the webserver")?; + // output path is going to need to be moved later on, so clone it for the + // http closure to avoid contention. + let static_root = output_path.clone(); + thread::spawn(move || { + let s = server::new(move || { + App::new() + .middleware(NotFoundHandler { rendered_template: static_root.join("404.html") }) + .resource(r"/livereload.js", |r| r.f(livereload_handler)) + // Start a webserver that serves the `output_dir` directory + .handler( + r"/", + fs::StaticFiles::new(&static_root) + .unwrap() + .show_files_listing() + .files_listing_renderer(handle_directory) + ) + }) + .bind(&address) + .expect("Can't start the webserver") + .shutdown_timeout(20); + println!("Web server is available at http://{}", &address); + s.run(); + }); // The websocket for livereload let ws_server = WebSocket::new(|output: Sender| { @@ -169,10 +230,9 @@ pub fn serve(interface: &str, port: &str, output_dir: &str, base_url: &str, conf } println!("Listening for changes in {}/{{{}}}", pwd, watchers.join(", ")); - println!("Web server is available at http://{}", address); + println!("Press Ctrl+C to stop\n"); // Delete the output folder on ctrl+C - let output_path = Path::new(output_dir).to_path_buf(); ctrlc::set_handler(move || { remove_dir_all(&output_path).expect("Failed to delete output directory"); ::std::process::exit(0); @@ -253,7 +313,7 @@ fn is_temp_file(path: &Path) -> bool { } }, None => { - path.ends_with(".DS_STORE") + true }, } } @@ -263,7 +323,8 @@ fn is_temp_file(path: &Path) -> bool { fn detect_change_kind(pwd: &str, path: &Path) -> (ChangeKind, String) { let path_str = format!("{}", path.display()) .replace(pwd, "") - .replace("\\", "/"); + .replace("\\", ""); + let change_kind = if path_str.starts_with("/templates") { ChangeKind::Templates } else if path_str.starts_with("/content") { diff --git a/src/console.rs b/src/console.rs index 9f0b5f0d..e28caa9d 100644 --- a/src/console.rs +++ b/src/console.rs @@ -27,10 +27,11 @@ pub fn error(message: &str) { /// Display in the console the number of pages/sections in the site pub fn notify_site_size(site: &Site) { println!( - "-> Creating {} pages ({} orphan) and {} sections", + "-> Creating {} pages ({} orphan), {} sections, and processing {} images", site.pages.len(), site.get_all_orphan_pages().len(), site.sections.len() - 1, // -1 since we do not the index as a section + site.num_img_ops(), ); } @@ -43,7 +44,7 @@ pub fn warn_about_ignored_pages(site: &Site) { if !ignored_pages.is_empty() { warn(&format!( - "{} page(s) ignored (missing date or order in a sorted section):", + "{} page(s) ignored (missing date or weight in a sorted section):", ignored_pages.len() )); for path in ignored_pages { diff --git a/src/main.rs b/src/main.rs index 2c2ea23f..30f13b1b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,9 @@ +extern crate actix_web; #[macro_use] extern crate clap; extern crate chrono; -extern crate term_painter; -extern crate staticfile; -extern crate iron; -extern crate mount; extern crate notify; +extern crate term_painter; extern crate url; extern crate ws; extern crate ctrlc; diff --git a/sublime_syntaxes/newlines.packdump b/sublime_syntaxes/newlines.packdump index 22456f8b..de6d0d35 100644 Binary files a/sublime_syntaxes/newlines.packdump and b/sublime_syntaxes/newlines.packdump differ diff --git a/sublime_syntaxes/nonewlines.packdump b/sublime_syntaxes/nonewlines.packdump index 333a81d7..913cdb6b 100644 Binary files a/sublime_syntaxes/nonewlines.packdump and b/sublime_syntaxes/nonewlines.packdump differ diff --git a/test_site/config.staging.toml b/test_site/config.staging.toml index 123bc892..b15e8dae 100644 --- a/test_site/config.staging.toml +++ b/test_site/config.staging.toml @@ -1,7 +1,8 @@ title = "My site" base_url = "https://staging.com" highlight_code = true - +theme = "sample" [extra.author] name = "Vincent Prouillet" + diff --git a/test_site/config.toml b/test_site/config.toml index 4b1caeda..b667b9b8 100644 --- a/test_site/config.toml +++ b/test_site/config.toml @@ -6,5 +6,9 @@ generate_rss = true rss_limit = 2 theme = "sample" +taxonomies = [ + {name = "categories", rss = true}, +] + [extra.author] name = "Vincent Prouillet" diff --git a/test_site/content/posts/fixed-slug.md b/test_site/content/posts/fixed-slug.md index ace8ae13..afec24bc 100644 --- a/test_site/content/posts/fixed-slug.md +++ b/test_site/content/posts/fixed-slug.md @@ -3,7 +3,7 @@ title = "Fixed slug" description = "" slug = "something-else" date = 2017-01-01 -aliases = ["/an-old-url/old-page"] +aliases = ["/an-old-url/old-page", "/an-old-url/an-old-alias.html"] +++ A simple page with a slug defined diff --git a/test_site/content/posts/tutorials/devops/_index.md b/test_site/content/posts/tutorials/devops/_index.md index 8e996741..29223641 100644 --- a/test_site/content/posts/tutorials/devops/_index.md +++ b/test_site/content/posts/tutorials/devops/_index.md @@ -1,6 +1,6 @@ +++ title = "DevOps" -sort_by = "order" +sort_by = "weight" redirect_to = "posts/tutorials/devops/docker" weight = 10 +++ diff --git a/test_site/content/posts/tutorials/devops/docker.md b/test_site/content/posts/tutorials/devops/docker.md index ad19af5c..46aea980 100644 --- a/test_site/content/posts/tutorials/devops/docker.md +++ b/test_site/content/posts/tutorials/devops/docker.md @@ -1,6 +1,6 @@ +++ title = "Docker" -order = 1 +weight = 1 date = 2017-01-01 +++ diff --git a/test_site/content/posts/tutorials/devops/nix.md b/test_site/content/posts/tutorials/devops/nix.md index 004ad58d..bc808530 100644 --- a/test_site/content/posts/tutorials/devops/nix.md +++ b/test_site/content/posts/tutorials/devops/nix.md @@ -1,6 +1,6 @@ +++ title = "Nix" -order = 2 +weight = 2 date = 2017-01-01 +++ diff --git a/test_site/content/posts/tutorials/programming/_index.md b/test_site/content/posts/tutorials/programming/_index.md index 4a2c76fb..6515620e 100644 --- a/test_site/content/posts/tutorials/programming/_index.md +++ b/test_site/content/posts/tutorials/programming/_index.md @@ -1,5 +1,5 @@ +++ title = "Programming" -sort_by = "order" +sort_by = "weight" weight = 1 +++ diff --git a/test_site/content/posts/tutorials/programming/python.md b/test_site/content/posts/tutorials/programming/python.md index d65d52fb..891ff299 100644 --- a/test_site/content/posts/tutorials/programming/python.md +++ b/test_site/content/posts/tutorials/programming/python.md @@ -1,6 +1,6 @@ +++ title = "Python tutorial" -order = 1 +weight = 1 date = 2017-01-01 +++ diff --git a/test_site/content/posts/tutorials/programming/rust.md b/test_site/content/posts/tutorials/programming/rust.md index 3582c4bc..a409b439 100644 --- a/test_site/content/posts/tutorials/programming/rust.md +++ b/test_site/content/posts/tutorials/programming/rust.md @@ -1,6 +1,6 @@ +++ title = "Rust" -order = 2 +weight = 2 date = 2017-01-01 +++ diff --git a/test_site/content/rebuild/_index.md b/test_site/content/rebuild/_index.md index c617948a..46570a3c 100644 --- a/test_site/content/rebuild/_index.md +++ b/test_site/content/rebuild/_index.md @@ -1,5 +1,5 @@ +++ paginate_by = 1 -sort_by = "order" +sort_by = "weight" template = "rebuild.html" +++ diff --git a/test_site/content/rebuild/first.md b/test_site/content/rebuild/first.md index a3bd65e6..213fa4bb 100644 --- a/test_site/content/rebuild/first.md +++ b/test_site/content/rebuild/first.md @@ -1,6 +1,6 @@ +++ title = "first" -order = 10 +weight = 10 date = 2017-01-01 +++ diff --git a/test_site/content/rebuild/second.md b/test_site/content/rebuild/second.md index 4a849192..2ee56019 100644 --- a/test_site/content/rebuild/second.md +++ b/test_site/content/rebuild/second.md @@ -1,6 +1,6 @@ +++ title = "second" -order = 100 +weight = 100 date = 2016-01-01 +++ diff --git a/test_site/templates/categories.html b/test_site/templates/categories.html deleted file mode 100644 index 59813456..00000000 --- a/test_site/templates/categories.html +++ /dev/null @@ -1,3 +0,0 @@ -{% for category in categories %} - {{ category.name }} {{ category.slug }} {{ category.pages | length }} -{% endfor %} diff --git a/test_site/templates/categories/list.html b/test_site/templates/categories/list.html new file mode 100644 index 00000000..3b8116f1 --- /dev/null +++ b/test_site/templates/categories/list.html @@ -0,0 +1,3 @@ +{% for term in terms %} + {{ term.name }} {{ term.slug }} {{ term.pages | length }} +{% endfor %} diff --git a/test_site/templates/category.html b/test_site/templates/categories/single.html similarity index 54% rename from test_site/templates/category.html rename to test_site/templates/categories/single.html index f7904310..23dd537c 100644 --- a/test_site/templates/category.html +++ b/test_site/templates/categories/single.html @@ -1,4 +1,4 @@ -{% extends "sample/templates/category.html" %} +{% extends "sample/templates/categories/single.html" %} {% block extra_category %} EXTENDED diff --git a/test_site/themes/sample/templates/category.html b/test_site/themes/sample/templates/categories/single.html similarity index 75% rename from test_site/themes/sample/templates/category.html rename to test_site/themes/sample/templates/categories/single.html index 7a016ae2..cd3df713 100644 --- a/test_site/themes/sample/templates/category.html +++ b/test_site/themes/sample/templates/categories/single.html @@ -1,7 +1,7 @@ -Category: {{ category.name }} +Category: {{ term.name }} -{% for page in category.pages %} +{% for page in term.pages %}