@@ -1,5 +1,15 @@ | |||
# Changelog | |||
## 0.0.7 (unreleased) | |||
- Sort individual tag/category pages by date | |||
- Add extra builtin shortcode for Streamable videos | |||
- `path` and `permalink` now end with a `/` | |||
- Generate table of contents for each page | |||
- Add `section` to a page Tera context if there is one | |||
- Add `aliases` to pages for when you are changing urls but want to redirect | |||
to the new one | |||
## 0.0.6 (2017-05-24) | |||
- Fix missing serialized data for sections | |||
@@ -2,7 +2,7 @@ | |||
name = "gutenberg" | |||
version = "0.0.6" | |||
dependencies = [ | |||
"base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"chrono 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"clap 2.24.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
@@ -17,13 +17,13 @@ dependencies = [ | |||
"serde_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"slug 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"staticfile 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"syntect 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"syntect 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"tera 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"term-painter 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"toml 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"ws 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"ws 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
@@ -54,8 +54,8 @@ name = "backtrace" | |||
version = "0.3.2" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"backtrace-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"backtrace-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"cfg-if 0.1.1 (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.23 (registry+https://github.com/rust-lang/crates.io-index)", | |||
@@ -65,10 +65,10 @@ dependencies = [ | |||
[[package]] | |||
name = "backtrace-sys" | |||
version = "0.1.10" | |||
version = "0.1.11" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
@@ -80,15 +80,23 @@ dependencies = [ | |||
"byteorder 1.0.0 (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.0.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
name = "bincode" | |||
version = "0.6.1" | |||
version = "0.8.0" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
@@ -106,11 +114,6 @@ name = "bitflags" | |||
version = "0.8.2" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
[[package]] | |||
name = "byteorder" | |||
version = "0.5.3" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
[[package]] | |||
name = "byteorder" | |||
version = "1.0.0" | |||
@@ -123,7 +126,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
[[package]] | |||
name = "bytes" | |||
version = "0.4.3" | |||
version = "0.4.4" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
@@ -132,24 +135,15 @@ dependencies = [ | |||
[[package]] | |||
name = "cfg-if" | |||
version = "0.1.0" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
[[package]] | |||
name = "chrono" | |||
version = "0.2.25" | |||
version = "0.1.1" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"num 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
name = "chrono" | |||
version = "0.3.1" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"num 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"num 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
@@ -170,10 +164,10 @@ dependencies = [ | |||
[[package]] | |||
name = "cmake" | |||
version = "0.1.23" | |||
version = "0.1.24" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
@@ -257,7 +251,7 @@ dependencies = [ | |||
[[package]] | |||
name = "gcc" | |||
version = "0.3.46" | |||
version = "0.3.50" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
[[package]] | |||
@@ -272,7 +266,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
[[package]] | |||
name = "httparse" | |||
version = "1.2.2" | |||
version = "1.2.3" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
[[package]] | |||
@@ -282,21 +276,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
[[package]] | |||
name = "hyper" | |||
version = "0.10.10" | |||
version = "0.10.12" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"httparse 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"httparse 1.2.3 (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.8 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"mime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"rustc_version 0.1.7 (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.5.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"time 0.1.37 (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.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"url 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
@@ -304,8 +297,8 @@ name = "idna" | |||
version = "0.1.2" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"unicode-bidi 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"unicode-bidi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
@@ -333,14 +326,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"conduit-mime-types 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"error 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"hyper 0.10.10 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"hyper 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"log 0.3.8 (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.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"num_cpus 1.5.1 (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.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"url 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
@@ -384,7 +377,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
[[package]] | |||
name = "matches" | |||
version = "0.1.4" | |||
version = "0.1.6" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
[[package]] | |||
@@ -397,7 +390,7 @@ dependencies = [ | |||
[[package]] | |||
name = "mime" | |||
version = "0.2.4" | |||
version = "0.2.6" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", | |||
@@ -408,7 +401,7 @@ name = "miniz-sys" | |||
version = "0.1.9" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
@@ -430,7 +423,7 @@ dependencies = [ | |||
[[package]] | |||
name = "mio" | |||
version = "0.6.7" | |||
version = "0.6.9" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
@@ -485,7 +478,7 @@ name = "net2" | |||
version = "0.2.29" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"cfg-if 0.1.1 (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.23 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", | |||
@@ -520,12 +513,12 @@ dependencies = [ | |||
[[package]] | |||
name = "num" | |||
version = "0.1.37" | |||
version = "0.1.39" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"num-iter 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
@@ -533,7 +526,7 @@ name = "num-integer" | |||
version = "0.1.34" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
@@ -542,17 +535,17 @@ version = "0.1.33" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
name = "num-traits" | |||
version = "0.1.37" | |||
version = "0.1.39" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
[[package]] | |||
name = "num_cpus" | |||
version = "1.4.0" | |||
version = "1.5.1" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", | |||
@@ -560,21 +553,21 @@ dependencies = [ | |||
[[package]] | |||
name = "onig" | |||
version = "1.2.2" | |||
version = "1.3.0" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"onig_sys 61.3.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"onig_sys 63.0.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
name = "onig_sys" | |||
version = "61.3.0" | |||
version = "63.0.2" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"cmake 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
@@ -591,14 +584,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
[[package]] | |||
name = "plist" | |||
version = "0.1.3" | |||
version = "0.2.2" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"xml-rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"chrono 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"xml-rs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
@@ -633,7 +626,7 @@ dependencies = [ | |||
[[package]] | |||
name = "redox_syscall" | |||
version = "0.1.17" | |||
version = "0.1.18" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
[[package]] | |||
@@ -664,12 +657,9 @@ version = "0.3.24" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
[[package]] | |||
name = "rustc_version" | |||
version = "0.1.7" | |||
name = "safemem" | |||
version = "0.2.0" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
name = "same-file" | |||
@@ -680,26 +670,11 @@ dependencies = [ | |||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
name = "semver" | |||
version = "0.1.20" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
[[package]] | |||
name = "sequence_trie" | |||
version = "0.2.1" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
[[package]] | |||
name = "serde" | |||
version = "0.8.23" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
[[package]] | |||
name = "serde" | |||
version = "0.9.15" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
[[package]] | |||
name = "serde" | |||
version = "1.0.8" | |||
@@ -731,7 +706,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
@@ -766,7 +741,7 @@ dependencies = [ | |||
"iron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"mount 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"url 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
@@ -794,18 +769,20 @@ dependencies = [ | |||
[[package]] | |||
name = "syntect" | |||
version = "1.3.0" | |||
version = "1.5.0" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"bincode 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"onig 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"plist 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"onig 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"plist 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"serde_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
@@ -833,7 +810,7 @@ dependencies = [ | |||
"serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"slug 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"url 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
@@ -888,7 +865,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"redox_syscall 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"redox_syscall 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
@@ -915,23 +892,23 @@ name = "typemap" | |||
version = "0.3.3" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"unsafe-any 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
name = "unicase" | |||
version = "1.4.0" | |||
version = "1.4.2" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"version_check 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
name = "unicode-bidi" | |||
version = "0.3.2" | |||
version = "0.3.3" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"matches 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)", | |||
] | |||
[[package]] | |||
@@ -969,7 +946,7 @@ dependencies = [ | |||
[[package]] | |||
name = "unsafe-any" | |||
version = "0.4.1" | |||
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)", | |||
@@ -977,11 +954,11 @@ dependencies = [ | |||
[[package]] | |||
name = "url" | |||
version = "1.4.0" | |||
version = "1.4.1" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"idna 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"matches 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)", | |||
] | |||
[[package]] | |||
@@ -994,6 +971,11 @@ name = "vec_map" | |||
version = "0.8.0" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
[[package]] | |||
name = "version_check" | |||
version = "0.1.2" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
[[package]] | |||
name = "void" | |||
version = "1.0.2" | |||
@@ -1030,18 +1012,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
[[package]] | |||
name = "ws" | |||
version = "0.7.1" | |||
version = "0.7.3" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"bytes 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"httparse 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"bytes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"mio 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"mio 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"sha1 0.2.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.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"url 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
@@ -1055,7 +1037,7 @@ dependencies = [ | |||
[[package]] | |||
name = "xml-rs" | |||
version = "0.3.6" | |||
version = "0.4.1" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
@@ -1071,21 +1053,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" | |||
"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159" | |||
"checksum backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "72f9b4182546f4b04ebc4ab7f84948953a118bd6021a1b6a6c909e3e94f6be76" | |||
"checksum backtrace-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d192fd129132fbc97497c1f2ec2c2c5174e376b95f535199ef4fe0a293d33842" | |||
"checksum backtrace-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3a0d842ea781ce92be2bf78a9b38883948542749640b8378b3b2f03d1fd9f1ff" | |||
"checksum base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30e93c03064e7590d0466209155251b90c22e37fab1daf2771582598b5827557" | |||
"checksum bincode 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "55eb0b7fd108527b0c77860f75eca70214e11a8b4c6ef05148c54c05a25d48ad" | |||
"checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" | |||
"checksum bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e103c8b299b28a9c6990458b7013dc4a8356a9b854c51b9883241f5866fac36e" | |||
"checksum bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dead7461c1127cf637931a1e50934eb6eee8bff2f74433ac7909e9afcee04a3" | |||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" | |||
"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4" | |||
"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" | |||
"checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8" | |||
"checksum bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c129aff112dcc562970abb69e2508b40850dd24c274761bb50fb8a0067ba6c27" | |||
"checksum bytes 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f9edb851115d67d1f18680f9326901768a91d37875b87015518357c6ce22b553" | |||
"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c" | |||
"checksum chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "9213f7cd7c27e95c2b57c49f0e69b1ea65b27138da84a170133fd21b07659c00" | |||
"checksum bytes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8b24f16593f445422331a5eed46b72f7f171f910fead4f2ea8f17e727e9c5c14" | |||
"checksum cfg-if 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c47d456a36ebf0536a6705c83c1cbbcb9255fbc1d905a6ded104f479268a29" | |||
"checksum chrono 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d9123be86fd2a8f627836c235ecdf331fdd067ecf7ac05aa1a68fbcf2429f056" | |||
"checksum clap 2.24.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b8f69e518f967224e628896b54e41ff6acfb4dcfefc5076325c36525dac900f" | |||
"checksum cmake 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "92278eb79412c8f75cfc89e707a1bb3a6490b68f7f2e78d15c774f30fe701122" | |||
"checksum cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ebbb35d3dc9cd09497168f33de1acb79b265d350ab0ac34133b98f8509af1f" | |||
"checksum conduit-mime-types 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "95ca30253581af809925ef68c2641cc140d6183f43e12e0af4992d53768bd7b8" | |||
"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" | |||
"checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" | |||
@@ -1096,12 +1077,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
"checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344" | |||
"checksum fsevent 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "dfe593ebcfc76884138b25426999890b10da8e6a46d01b499d7c54c604672c38" | |||
"checksum fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a772d36c338d07a032d5375a36f15f9a7043bf0cb8ce7cee658e037c6032874" | |||
"checksum gcc 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)" = "181e3cebba1d663bd92eb90e2da787e10597e027eb00de8d742b260a7850948f" | |||
"checksum gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)" = "5f837c392f2ea61cb1576eac188653df828c861b7137d74ea4a5caa89621f9e6" | |||
"checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" | |||
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" | |||
"checksum httparse 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77f756bed9ee3a83ce98774f4155b42a31b787029013f3a7d83eca714e500e21" | |||
"checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07" | |||
"checksum humansize 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "92d211e6e70b05749dce515b47684f29a3c8c38bbbb21c50b30aff9eca1b0bd3" | |||
"checksum hyper 0.10.10 (registry+https://github.com/rust-lang/crates.io-index)" = "36e108e0b1fa2d17491cbaac4bc460dc0956029d10ccf83c913dd0e5db3e7f07" | |||
"checksum hyper 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)" = "0f01e4a20f5dfa5278d7762b7bdb7cab96e24378b9eca3889fbd4b5e94dc7063" | |||
"checksum idna 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2233d4940b1f19f0418c158509cd7396b8d70a5db5705ce410914dc8fa603b37" | |||
"checksum inotify 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887fcc180136e77a85e6a6128579a719027b1bab9b1c38ea4444244fe262c20c" | |||
"checksum iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29d062ee61fccdf25be172e70f34c9f6efc597e1fb8f6526e8437b2046ab26be" | |||
@@ -1113,12 +1094,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
"checksum lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce12306c4739d86ee97c23139f3a34ddf0387bbf181bc7929d287025a8c3ef6b" | |||
"checksum libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)" = "e7eb6b826bfc1fdea7935d46556250d1799b7fe2d9f7951071f4291710665e3e" | |||
"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" | |||
"checksum matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efd7622e3022e1a6eaa602c4cea8912254e5582c9c692e9167714182244801b1" | |||
"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" | |||
"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" | |||
"checksum mime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9d69889cdc6336ed56b174514ce876c4c3dc564cc23dd872e7bca589bb2a36c8" | |||
"checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" | |||
"checksum miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "28eaee17666671fa872e567547e8428e83308ebe5808cdf6a0e28397dbe2c726" | |||
"checksum mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a637d1ca14eacae06296a008fa7ad955347e34efcb5891cfd8ba05491a37907e" | |||
"checksum mio 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6d19442734abd7d780b981c590c325680d933e99795fe1f693f0686c9ed48022" | |||
"checksum mio 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9e965267d4d58496fc4f740e9861118367f13570cadf66316ed2c3f2f14d87c7" | |||
"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" | |||
@@ -1126,31 +1107,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
"checksum net2 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "bc01404e7568680f1259aa5729539f221cb1e6d047a0d9053cab4be8a73b5d67" | |||
"checksum nix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bfb3ddedaa14746434a02041940495bf11325c22f6d36125d3bdd56090d50a79" | |||
"checksum notify 4.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "298d4401ff2c6cebb7f8944c90288647c89ce59029d43b439444cf1067df55e1" | |||
"checksum num 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "98b15ba84e910ea7a1973bccd3df7b31ae282bf9d8bd2897779950c9b8303d40" | |||
"checksum num 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "2c3a3dc9f30bf824141521b30c908a859ab190b76e20435fcd89f35eb6583887" | |||
"checksum num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "ef1a4bf6f9174aa5783a9b4cc892cacd11aebad6c69ad027a0b65c6ca5f8aa37" | |||
"checksum num-iter 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d1891bd7b936f12349b7d1403761c8a0b85a18b148e9da4429d5d102c1a41e" | |||
"checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99" | |||
"checksum num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca313f1862c7ec3e0dfe8ace9fa91b1d9cb5c84ace3d00f5ec4216238e93c167" | |||
"checksum onig 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1f59adfdb1810e061fcd1cf5dd2792730f8226e5d23c51a52f243714cc8fe676" | |||
"checksum onig_sys 61.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "be2eb43cab0eed1bdeec174b96967cf5636634adc2b6ba8fcc875aa3d5fc4118" | |||
"checksum num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "1708c0628602a98b52fad936cf3edb9a107af06e52e49fdf0707e884456a6af6" | |||
"checksum num_cpus 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6e416ba127a4bb3ff398cb19546a8d0414f73352efe2857f4060d36f5fe5983a" | |||
"checksum onig 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee619da9cf707b167098e84fb00f10db61d5a662d1d29b59822bcac3a81553dd" | |||
"checksum onig_sys 63.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "531682ab45a2cd40eff91f29340dae975f25336d2b61e624adabed39e61d7fb3" | |||
"checksum pest 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e823a5967bb4cdc6d3e46f47baaf4ecfeae44413a642b74ad44e59e49c7f6" | |||
"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" | |||
"checksum plist 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0f6c4f04356eb9ad7fb1d004eb19369324daa46db1fc7ee89246a2fc224a9ce9" | |||
"checksum plist 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1e2f7e9574aabcf57bc5e9f602caabdffffa8179b0c130a039f7895fea3dbdb5" | |||
"checksum plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a6a0dc3910bc8db877ffed8e457763b317cf880df4ae19109b9f77d277cf6e0" | |||
"checksum pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9ab1e588ef8efd702c7ed9d2bd774db5e6f4d878bb5a1a9f371828fbdff6973" | |||
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" | |||
"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d" | |||
"checksum redox_syscall 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "29dbdfd4b9df8ab31dec47c6087b7b13cbf4a776f335e4de8efba8288dda075b" | |||
"checksum redox_syscall 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "3041aeb6000db123d2c9c751433f526e1f404b23213bd733167ab770c3989b4d" | |||
"checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" | |||
"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" | |||
"checksum rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95" | |||
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" | |||
"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" | |||
"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" | |||
"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" | |||
"checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" | |||
"checksum sequence_trie 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c915714ca833b1d4d6b8f6a9d72a3ff632fe45b40a8d184ef79c81bec6327eed" | |||
"checksum serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" | |||
"checksum serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)" = "34b623917345a631dc9608d5194cc206b3fe6c3554cd1c75b937e55e285254af" | |||
"checksum serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c2f530d36fb84ec48fb7146936881f026cdbf4892028835fd9398475f82c1bb4" | |||
"checksum serde_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "10552fad5500771f3902d0c5ba187c5881942b811b7ba0d8fbbfbf84d80806d3" | |||
"checksum serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37aee4e0da52d801acfbc0cc219eb1eda7142112339726e427926a6f6ee65d3a" | |||
@@ -1163,7 +1141,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" | |||
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" | |||
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" | |||
"checksum syntect 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24204b1f4bdd49f84e5f4b219d0bf1dc45ac2fd7fc46320ab6627b537d6d4b69" | |||
"checksum syntect 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fed7a5661c5c42fe998c561efb12137381a4486702f41c95a1d7269f3cc8ca6a" | |||
"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" | |||
"checksum tera 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c931ade2857155d5e55115375d4d2b8a441536e2b9e44643a8b67e235e09030" | |||
"checksum term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d168af3930b369cfe245132550579d47dfd873d69470755a19c2c6568dbbd989" | |||
@@ -1176,24 +1154,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
"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 unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "13a5906ca2b98c799f4b1ab4557b76367ebd6ae5ef14930ec841c74aed5f3764" | |||
"checksum unicode-bidi 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "916219eb752dd865717c9b21064401c6ee843dc91ed659c144591e0c87c56d59" | |||
"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" | |||
"checksum unicode-bidi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a6a2c4e3710edd365cd7e78383153ed739fa31af19f9172f72d3575060f5a43a" | |||
"checksum unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e28fa37426fceeb5cf8f41ee273faa7c82c47dc8fba5853402841e665fcd86ff" | |||
"checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946" | |||
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" | |||
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" | |||
"checksum unidecode 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2adb95ee07cd579ed18131f2d9e7a17c25a4b76022935c7f2460d2bfae89fd2" | |||
"checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91" | |||
"checksum unsafe-any 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b351086021ebc264aea3ab4f94d61d889d98e5e9ec2d985d993f50133537fd3a" | |||
"checksum url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5ba8a749fb4479b043733416c244fa9d1d3af3d7c23804944651c8a448cb87e" | |||
"checksum unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f30360d7979f5e9c6e6cea48af192ea8fab4afb3cf72597154b8f08935bc9c7f" | |||
"checksum url 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2ba3456fbe5c0098cb877cf08b92b76c3e18e0be9e47c35b487220d377d24e" | |||
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" | |||
"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c" | |||
"checksum version_check 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2bb3950bf29e36796dea723df1747619dd331881aefef75b7cf1c58fdd738afe" | |||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" | |||
"checksum walkdir 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c66c0b9792f0a765345452775f3adbd28dde9d33f30d13e5dcc5ae17cf6f3780" | |||
"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff" | |||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" | |||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" | |||
"checksum ws 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d639380f50ad271c719cec5c9f78f09dd9d5c064b2c2231784c45f4ae70b87ae" | |||
"checksum ws 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "89c48c53bf9dee34411a08993c10b879c36e105d609b46e25673befe3a5c1320" | |||
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" | |||
"checksum xml-rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7ec6c39eaa68382c8e31e35239402c0a9489d4141a8ceb0c716099a0b515b562" | |||
"checksum xml-rs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b46ee689ba7a669c08a1170c2348d2516c62dc461135c9e86b2f1f476e07be4a" | |||
"checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" |
@@ -30,7 +30,7 @@ syntect = { version = "1", features = ["static-onig"] } | |||
chrono = "0.3" | |||
toml = "0.4" | |||
term-painter = "0.2" | |||
base64 = "0.5" | |||
base64 = "0.6" | |||
# Below is for the serve cmd | |||
staticfile = "0.4" | |||
@@ -91,6 +91,7 @@ A front-matter has only optional variables: | |||
- category: only one category is allowed | |||
- draft: whether the post is a draft or not | |||
- template: if you want to change the template used to render that specific page | |||
- aliases: which URL to redirect to the new: useful when you changed a page URL and don't want to 404 | |||
Even if your front-matter is empty, you will need to put the `+++`. | |||
You can also, like in the config, add your own variables in a `[extra]` table. | |||
@@ -135,6 +136,38 @@ You can also paginate section, including the index by setting the `paginate_by` | |||
This represents the number of pages for each pager of the paginator. | |||
You will need to access pages through the `paginator` object. (TODO: document that). | |||
### Table of contents | |||
Each page/section will generate a table of content based on the title. It is accessible through `section.toc` and | |||
`page.toc`. It is a list of headers that contains a `permalink`, a `title` and `children`. | |||
Here is an example on how to make a ToC using that: | |||
```jinja2 | |||
<ul> | |||
{% for h1 in page.toc %} | |||
<li> | |||
<a href="{{h1.permalink}}">{{ h1.title }}</a> | |||
{% if h1.children %} | |||
<ul> | |||
{% for h2 in h1.children %} | |||
<li> | |||
<a href="{{h2.permalink}}">{{ h2.title }}</a> | |||
</li> | |||
{% endfor %} | |||
</ul> | |||
{% endfor %} | |||
</li> | |||
{% endfor %} | |||
</ul> | |||
``` | |||
While headers are neatly ordered in that example, you can a table of contents looking like h2, h2, h1, h3 without | |||
any issues. | |||
### Taxonomies: tags and categories | |||
Individual tag/category pages are only supported for pages having a date. | |||
### Code highlighting themes | |||
Code highlighting can be turned on by setting `highlight_code = true` in `config.toml`. | |||
@@ -208,7 +241,8 @@ Gutenberg comes with a few built-in shortcodes: | |||
- YouTube: embeds a YouTube player for the given YouTube `id`. Also takes an optional `autoplay` argument that can be set to `true` | |||
if wanted | |||
- Vimeo: embeds a Vimeo player for the given Vimeo `id` | |||
- Gist: embeds a Github gist from the `url` given. Also takes an optional `file` argument if you only want to show one of the files. | |||
- Streamable: embeds a Streamable player for the given Streamable `id` | |||
- Gist: embeds a Github gist from the `url` given. Also takes an optional `file` argument if you only want to show one of the files | |||
#### Defining a shortcode | |||
All shortcodes need to be in the `templates/shortcodes` folder and their files to end with `.html`. | |||
@@ -220,9 +254,11 @@ In case of shortcodes with a body, the body will be passed as the `body` variabl | |||
## Example sites | |||
- [vincent.is](https://vincent.is): https://gitlab.com/Keats/vincent.is | |||
- [code<future](http://www.codelessfuture.com/) | |||
## Adding syntax highlighting languages and themes | |||
### Adding a syntax | |||
Syntax highlighting depends on submodules so ensure you load them first: | |||
```bash | |||
@@ -35,10 +35,7 @@ install: | |||
test_script: | |||
# we don't run the "test phase" when doing deploys | |||
- if [%APPVEYOR_REPO_TAG%]==[false] ( | |||
cargo build --target %TARGET% && | |||
cargo build --target %TARGET% --release && | |||
cargo test --target %TARGET% && | |||
cargo test --target %TARGET% --release | |||
cargo test --target %TARGET% | |||
) | |||
before_deploy: | |||
@@ -1,3 +1,26 @@ | |||
// Contains an embedded version of livereload-js | |||
// | |||
// Copyright (c) 2010-2012 Andrey Tarantsov | |||
// | |||
// Permission is hereby granted, free of charge, to any person obtaining | |||
// a copy of this software and associated documentation files (the | |||
// "Software"), to deal in the Software without restriction, including | |||
// without limitation the rights to use, copy, modify, merge, publish, | |||
// distribute, sublicense, and/or sell copies of the Software, and to | |||
// permit persons to whom the Software is furnished to do so, subject to | |||
// the following conditions: | |||
// | |||
// The above copyright notice and this permission notice shall be | |||
// included in all copies or substantial portions of the Software. | |||
// | |||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | |||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | |||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
use std::env; | |||
use std::path::Path; | |||
use std::sync::mpsc::channel; | |||
@@ -172,9 +172,9 @@ pub fn after_content_change(site: &mut Site, path: &Path) -> Result<()> { | |||
// Updating a page | |||
let current = site.pages[path].clone(); | |||
// Front matter didn't change, only content did | |||
// so we render only the section page, not its pages | |||
// so we render only the section page, not its content | |||
if current.meta == prev.meta { | |||
return site.render_page(&site.pages[path]); | |||
return site.render_page(¤t, find_parent_section(site, ¤t)); | |||
} | |||
// Front matter changed | |||
@@ -199,7 +199,7 @@ pub fn after_content_change(site: &mut Site, path: &Path) -> Result<()> { | |||
site.render_index()?; | |||
}, | |||
PageChangesNeeded::Render => { | |||
site.render_page(&site.pages[path])?; | |||
site.render_page(&site.pages[path], find_parent_section(site, ¤t))?; | |||
}, | |||
}; | |||
} | |||
@@ -90,12 +90,20 @@ impl Config { | |||
/// Makes a url, taking into account that the base url might have a trailing slash | |||
pub fn make_permalink(&self, path: &str) -> String { | |||
if self.base_url.ends_with('/') && path.starts_with('/') { | |||
format!("{}{}", self.base_url, &path[1..]) | |||
let trailing_bit = if path.ends_with('/') { "" } else { "/" }; | |||
// Index section with a base url that has a trailing slash | |||
if self.base_url.ends_with('/') && path == "/" { | |||
self.base_url.clone() | |||
} else if path == "/" { | |||
// index section with a base url that doesn't have a trailing slash | |||
format!("{}/", self.base_url) | |||
} else if self.base_url.ends_with('/') && path.starts_with('/') { | |||
format!("{}{}{}", self.base_url, &path[1..], trailing_bit) | |||
} else if self.base_url.ends_with('/') { | |||
format!("{}{}", self.base_url, path) | |||
format!("{}{}{}", self.base_url, path, trailing_bit) | |||
} else { | |||
format!("{}/{}", self.base_url, path) | |||
format!("{}/{}{}", self.base_url, path, trailing_bit) | |||
} | |||
} | |||
} | |||
@@ -192,13 +200,13 @@ hello = "world" | |||
fn can_make_url_with_non_trailing_slash_base_url() { | |||
let mut config = Config::default(); | |||
config.base_url = "http://vincent.is".to_string(); | |||
assert_eq!(config.make_permalink("hello"), "http://vincent.is/hello"); | |||
assert_eq!(config.make_permalink("hello"), "http://vincent.is/hello/"); | |||
} | |||
#[test] | |||
fn can_make_url_with_trailing_slash_path() { | |||
let mut config = Config::default(); | |||
config.base_url = "http://vincent.is/".to_string(); | |||
assert_eq!(config.make_permalink("/hello"), "http://vincent.is/hello"); | |||
assert_eq!(config.make_permalink("/hello"), "http://vincent.is/hello/"); | |||
} | |||
} |
@@ -5,10 +5,12 @@ mod sorting; | |||
mod utils; | |||
mod file_info; | |||
mod taxonomies; | |||
mod table_of_contents; | |||
pub use self::page::{Page}; | |||
pub use self::section::{Section}; | |||
pub use self::pagination::{Paginator, Pager}; | |||
pub use self::sorting::{SortBy, sort_pages, populate_previous_and_next_pages}; | |||
pub use self::taxonomies::{Taxonomy, TaxonomyItem}; | |||
pub use self::table_of_contents::{TempHeader, Header, make_table_of_contents}; | |||
@@ -16,6 +16,7 @@ use rendering::context::Context; | |||
use fs::{read_file}; | |||
use content::utils::{find_related_assets, get_reading_analytics}; | |||
use content::file_info::FileInfo; | |||
use content::{Header, Section}; | |||
#[derive(Clone, Debug, PartialEq)] | |||
@@ -45,6 +46,8 @@ pub struct Page { | |||
pub previous: Option<Box<Page>>, | |||
/// The next page, by whatever sorting is used for the index/section | |||
pub next: Option<Box<Page>>, | |||
/// Toc made from the headers of the markdown file | |||
pub toc: Vec<Header>, | |||
} | |||
@@ -64,6 +67,7 @@ impl Page { | |||
summary: None, | |||
previous: None, | |||
next: None, | |||
toc: vec![], | |||
} | |||
} | |||
@@ -91,6 +95,9 @@ impl Page { | |||
format!("{}/{}", page.file.components.join("/"), page.slug) | |||
}; | |||
} | |||
if !page.path.ends_with('/') { | |||
page.path = format!("{}/", page.path); | |||
} | |||
page.permalink = config.make_permalink(&page.path); | |||
Ok(page) | |||
@@ -114,12 +121,14 @@ impl 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<String, String>, tera: &Tera, config: &Config, anchor_insert: InsertAnchor) -> Result<()> { | |||
let context = Context::new(tera, config, permalinks, anchor_insert); | |||
self.content = markdown_to_html(&self.raw_content, &context)?; | |||
let context = Context::new(tera, config, &self.permalink, permalinks, anchor_insert); | |||
let res = markdown_to_html(&self.raw_content, &context)?; | |||
self.content = res.0; | |||
self.toc = res.1; | |||
if self.raw_content.contains("<!-- more -->") { | |||
self.summary = Some({ | |||
let summary = self.raw_content.splitn(2, "<!-- more -->").collect::<Vec<&str>>()[0]; | |||
markdown_to_html(summary, &context)? | |||
markdown_to_html(summary, &context)?.0 | |||
}) | |||
} | |||
@@ -127,7 +136,7 @@ impl Page { | |||
} | |||
/// Renders the page using the default layout, unless specified in front-matter | |||
pub fn render_html(&self, tera: &Tera, config: &Config) -> Result<String> { | |||
pub fn render_html(&self, tera: &Tera, config: &Config, section: Option<&Section>) -> Result<String> { | |||
let tpl_name = match self.meta.template { | |||
Some(ref l) => l.to_string(), | |||
None => "page.html".to_string() | |||
@@ -138,6 +147,7 @@ impl Page { | |||
context.add("page", self); | |||
context.add("current_url", &self.permalink); | |||
context.add("current_path", &self.path); | |||
context.add("section", §ion); | |||
tera.render(&tpl_name, &context) | |||
.chain_err(|| format!("Failed to render page '{}'", self.file.path.display())) | |||
@@ -158,13 +168,14 @@ impl Default for Page { | |||
summary: None, | |||
previous: None, | |||
next: None, | |||
toc: vec![], | |||
} | |||
} | |||
} | |||
impl ser::Serialize for Page { | |||
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error> where S: ser::Serializer { | |||
let mut state = serializer.serialize_struct("page", 15)?; | |||
let mut state = serializer.serialize_struct("page", 16)?; | |||
state.serialize_field("content", &self.content)?; | |||
state.serialize_field("title", &self.meta.title)?; | |||
state.serialize_field("description", &self.meta.description)?; | |||
@@ -181,6 +192,7 @@ impl ser::Serialize for Page { | |||
state.serialize_field("reading_time", &reading_time)?; | |||
state.serialize_field("previous", &self.previous)?; | |||
state.serialize_field("next", &self.next)?; | |||
state.serialize_field("toc", &self.toc)?; | |||
state.end() | |||
} | |||
} | |||
@@ -231,8 +243,8 @@ Hello world"#; | |||
let res = Page::parse(Path::new("content/posts/intro/start.md"), content, &conf); | |||
assert!(res.is_ok()); | |||
let page = res.unwrap(); | |||
assert_eq!(page.path, "posts/intro/hello-world"); | |||
assert_eq!(page.permalink, "http://hello.com/posts/intro/hello-world"); | |||
assert_eq!(page.path, "posts/intro/hello-world/"); | |||
assert_eq!(page.permalink, "http://hello.com/posts/intro/hello-world/"); | |||
} | |||
#[test] | |||
@@ -246,7 +258,7 @@ Hello world"#; | |||
let res = Page::parse(Path::new("start.md"), content, &config); | |||
assert!(res.is_ok()); | |||
let page = res.unwrap(); | |||
assert_eq!(page.path, "hello-world"); | |||
assert_eq!(page.path, "hello-world/"); | |||
assert_eq!(page.permalink, config.make_permalink("hello-world")); | |||
} | |||
@@ -74,17 +74,18 @@ impl<'a> Paginator<'a> { | |||
continue; | |||
} | |||
let page_path = format!("{}/{}", paginate_path, index + 1); | |||
let permalink = if section.permalink.ends_with('/') { | |||
format!("{}{}", section.permalink, page_path) | |||
let page_path = format!("{}/{}/", paginate_path, index + 1); | |||
let permalink = format!("{}{}", section.permalink, page_path); | |||
let pager_path = if section.is_index() { | |||
page_path | |||
} else { | |||
format!("{}/{}", section.permalink, page_path) | |||
format!("{}{}", section.path, page_path) | |||
}; | |||
pagers.push(Pager::new( | |||
index + 1, | |||
page.clone(), | |||
permalink, | |||
if section.is_index() { page_path } else { format!("{}/{}", section.path, page_path) } | |||
pager_path, | |||
)); | |||
} | |||
@@ -94,10 +95,10 @@ impl<'a> Paginator<'a> { | |||
} | |||
Paginator { | |||
all_pages: all_pages, | |||
pagers: pagers, | |||
paginate_by: paginate_by, | |||
section: section, | |||
all_pages, | |||
pagers, | |||
paginate_by, | |||
section, | |||
} | |||
} | |||
@@ -164,11 +165,11 @@ mod tests { | |||
f.paginate_path = Some("page".to_string()); | |||
let mut s = Section::new("content/_index.md", f); | |||
if !is_index { | |||
s.path = "posts".to_string(); | |||
s.permalink = "https://vincent.is/posts".to_string(); | |||
s.path = "posts/".to_string(); | |||
s.permalink = "https://vincent.is/posts/".to_string(); | |||
s.file.components = vec!["posts".to_string()]; | |||
} else { | |||
s.permalink = "https://vincent.is".to_string(); | |||
s.permalink = "https://vincent.is/".to_string(); | |||
} | |||
s | |||
} | |||
@@ -186,13 +187,13 @@ mod tests { | |||
assert_eq!(paginator.pagers[0].index, 1); | |||
assert_eq!(paginator.pagers[0].pages.len(), 2); | |||
assert_eq!(paginator.pagers[0].permalink, "https://vincent.is/posts"); | |||
assert_eq!(paginator.pagers[0].path, "posts"); | |||
assert_eq!(paginator.pagers[0].permalink, "https://vincent.is/posts/"); | |||
assert_eq!(paginator.pagers[0].path, "posts/"); | |||
assert_eq!(paginator.pagers[1].index, 2); | |||
assert_eq!(paginator.pagers[1].pages.len(), 1); | |||
assert_eq!(paginator.pagers[1].permalink, "https://vincent.is/posts/page/2"); | |||
assert_eq!(paginator.pagers[1].path, "posts/page/2"); | |||
assert_eq!(paginator.pagers[1].permalink, "https://vincent.is/posts/page/2/"); | |||
assert_eq!(paginator.pagers[1].path, "posts/page/2/"); | |||
} | |||
#[test] | |||
@@ -208,13 +209,13 @@ mod tests { | |||
assert_eq!(paginator.pagers[0].index, 1); | |||
assert_eq!(paginator.pagers[0].pages.len(), 2); | |||
assert_eq!(paginator.pagers[0].permalink, "https://vincent.is"); | |||
assert_eq!(paginator.pagers[0].permalink, "https://vincent.is/"); | |||
assert_eq!(paginator.pagers[0].path, ""); | |||
assert_eq!(paginator.pagers[1].index, 2); | |||
assert_eq!(paginator.pagers[1].pages.len(), 1); | |||
assert_eq!(paginator.pagers[1].permalink, "https://vincent.is/page/2"); | |||
assert_eq!(paginator.pagers[1].path, "page/2"); | |||
assert_eq!(paginator.pagers[1].permalink, "https://vincent.is/page/2/"); | |||
assert_eq!(paginator.pagers[1].path, "page/2/"); | |||
} | |||
#[test] | |||
@@ -230,18 +231,18 @@ mod tests { | |||
let context = paginator.build_paginator_context(&paginator.pagers[0]); | |||
assert_eq!(context["paginate_by"], to_value(2).unwrap()); | |||
assert_eq!(context["first"], to_value("https://vincent.is/posts").unwrap()); | |||
assert_eq!(context["last"], to_value("https://vincent.is/posts/page/2").unwrap()); | |||
assert_eq!(context["first"], to_value("https://vincent.is/posts/").unwrap()); | |||
assert_eq!(context["last"], to_value("https://vincent.is/posts/page/2/").unwrap()); | |||
assert_eq!(context["previous"], to_value::<Option<()>>(None).unwrap()); | |||
assert_eq!(context["next"], to_value("https://vincent.is/posts/page/2").unwrap()); | |||
assert_eq!(context["next"], to_value("https://vincent.is/posts/page/2/").unwrap()); | |||
assert_eq!(context["current_index"], to_value(1).unwrap()); | |||
let context = paginator.build_paginator_context(&paginator.pagers[1]); | |||
assert_eq!(context["paginate_by"], to_value(2).unwrap()); | |||
assert_eq!(context["first"], to_value("https://vincent.is/posts").unwrap()); | |||
assert_eq!(context["last"], to_value("https://vincent.is/posts/page/2").unwrap()); | |||
assert_eq!(context["first"], to_value("https://vincent.is/posts/").unwrap()); | |||
assert_eq!(context["last"], to_value("https://vincent.is/posts/page/2/").unwrap()); | |||
assert_eq!(context["next"], to_value::<Option<()>>(None).unwrap()); | |||
assert_eq!(context["previous"], to_value("https://vincent.is/posts").unwrap()); | |||
assert_eq!(context["previous"], to_value("https://vincent.is/posts/").unwrap()); | |||
assert_eq!(context["current_index"], to_value(2).unwrap()); | |||
} | |||
} |
@@ -13,6 +13,7 @@ use rendering::markdown::markdown_to_html; | |||
use rendering::context::Context; | |||
use content::Page; | |||
use content::file_info::FileInfo; | |||
use content::Header; | |||
#[derive(Clone, Debug, PartialEq)] | |||
@@ -35,6 +36,8 @@ pub struct Section { | |||
pub ignored_pages: Vec<Page>, | |||
/// All direct subsections | |||
pub subsections: Vec<Section>, | |||
/// Toc made from the headers of the markdown file | |||
pub toc: Vec<Header>, | |||
} | |||
impl Section { | |||
@@ -51,6 +54,7 @@ impl Section { | |||
pages: vec![], | |||
ignored_pages: vec![], | |||
subsections: vec![], | |||
toc: vec![], | |||
} | |||
} | |||
@@ -58,7 +62,7 @@ impl Section { | |||
let (meta, content) = split_section_content(file_path, content)?; | |||
let mut section = Section::new(file_path, meta); | |||
section.raw_content = content.clone(); | |||
section.path = section.file.components.join("/"); | |||
section.path = format!("{}/", section.file.components.join("/")); | |||
section.permalink = config.make_permalink(§ion.path); | |||
Ok(section) | |||
} | |||
@@ -86,8 +90,10 @@ impl Section { | |||
/// 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<String, String>, tera: &Tera, config: &Config) -> Result<()> { | |||
let context = Context::new(tera, config, permalinks, self.meta.insert_anchor.unwrap()); | |||
self.content = markdown_to_html(&self.raw_content, &context)?; | |||
let context = Context::new(tera, config, &self.permalink, permalinks, self.meta.insert_anchor.unwrap()); | |||
let res = markdown_to_html(&self.raw_content, &context)?; | |||
self.content = res.0; | |||
self.toc = res.1; | |||
Ok(()) | |||
} | |||
@@ -129,7 +135,7 @@ impl Section { | |||
impl ser::Serialize for Section { | |||
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error> where S: ser::Serializer { | |||
let mut state = serializer.serialize_struct("section", 9)?; | |||
let mut state = serializer.serialize_struct("section", 10)?; | |||
state.serialize_field("content", &self.content)?; | |||
state.serialize_field("permalink", &self.permalink)?; | |||
state.serialize_field("title", &self.meta.title)?; | |||
@@ -139,6 +145,7 @@ impl ser::Serialize for Section { | |||
state.serialize_field("permalink", &self.permalink)?; | |||
state.serialize_field("pages", &self.pages)?; | |||
state.serialize_field("subsections", &self.subsections)?; | |||
state.serialize_field("toc", &self.toc)?; | |||
state.end() | |||
} | |||
} | |||
@@ -156,6 +163,7 @@ impl Default for Section { | |||
pages: vec![], | |||
ignored_pages: vec![], | |||
subsections: vec![], | |||
toc: vec![], | |||
} | |||
} | |||
} |
@@ -0,0 +1,166 @@ | |||
#[derive(Debug, PartialEq, Clone, Serialize)] | |||
pub struct Header { | |||
#[serde(skip_serializing)] | |||
pub level: i32, | |||
pub id: String, | |||
pub title: String, | |||
pub permalink: String, | |||
pub children: Vec<Header>, | |||
} | |||
impl Header { | |||
pub fn from_temp_header(tmp: &TempHeader, children: Vec<Header>) -> Header { | |||
Header { | |||
level: tmp.level, | |||
id: tmp.id.clone(), | |||
title: tmp.title.clone(), | |||
permalink: tmp.permalink.clone(), | |||
children, | |||
} | |||
} | |||
} | |||
/// Used in | |||
#[derive(Debug, PartialEq, Clone)] | |||
pub struct TempHeader { | |||
pub level: i32, | |||
pub id: String, | |||
pub permalink: String, | |||
pub title: String, | |||
} | |||
impl TempHeader { | |||
pub fn new(level: i32) -> TempHeader { | |||
TempHeader { | |||
level, | |||
id: String::new(), | |||
permalink: String::new(), | |||
title: String::new(), | |||
} | |||
} | |||
} | |||
impl Default for TempHeader { | |||
fn default() -> Self { | |||
TempHeader::new(0) | |||
} | |||
} | |||
/// Recursively finds children of a header | |||
fn find_children(parent_level: i32, start_at: usize, temp_headers: &[TempHeader]) -> (usize, Vec<Header>) { | |||
let mut headers = vec![]; | |||
let mut start_at = start_at; | |||
// If we have children, we will need to skip some headers since they are already inserted | |||
let mut to_skip = 0; | |||
for h in &temp_headers[start_at..] { | |||
// stop when we encounter a title at the same level or higher | |||
// than the parent one. Here a lower integer is considered higher as we are talking about | |||
// HTML headers: h1, h2, h3, h4, h5 and h6 | |||
if h.level <= parent_level { | |||
return (start_at, headers); | |||
} | |||
// Do we need to skip some headers? | |||
if to_skip > 0 { | |||
to_skip -= 1; | |||
continue; | |||
} | |||
let (end, children) = find_children(h.level, start_at + 1, &temp_headers); | |||
headers.push(Header::from_temp_header(h, children)); | |||
// we didn't find any children | |||
if end == start_at { | |||
start_at += 1; | |||
to_skip = 0; | |||
} else { | |||
// calculates how many we need to skip. Since the find_children start_at starts at 1, | |||
// we need to remove 1 to ensure correctness | |||
to_skip = end - start_at - 1; | |||
start_at = end; | |||
} | |||
// we don't want to index out of bounds | |||
if start_at + 1 > temp_headers.len() { | |||
return (start_at, headers); | |||
} | |||
} | |||
(start_at, headers) | |||
} | |||
/// Converts the flat temp headers into a nested set of headers | |||
/// representing the hierarchy | |||
pub fn make_table_of_contents(temp_headers: Vec<TempHeader>) -> Vec<Header> { | |||
let mut toc = vec![]; | |||
let mut start_idx = 0; | |||
for (i, h) in temp_headers.iter().enumerate() { | |||
if i < start_idx { | |||
continue; | |||
} | |||
let (end_idx, children) = find_children(h.level, start_idx + 1, &temp_headers); | |||
start_idx = end_idx; | |||
toc.push(Header::from_temp_header(h, children)); | |||
} | |||
toc | |||
} | |||
#[cfg(test)] | |||
mod tests { | |||
use super::*; | |||
#[test] | |||
fn can_make_basic_toc() { | |||
let input = vec![ | |||
TempHeader::new(1), | |||
TempHeader::new(1), | |||
TempHeader::new(1), | |||
]; | |||
let toc = make_table_of_contents(input); | |||
assert_eq!(toc.len(), 3); | |||
} | |||
#[test] | |||
fn can_make_more_complex_toc() { | |||
let input = vec![ | |||
TempHeader::new(1), | |||
TempHeader::new(2), | |||
TempHeader::new(2), | |||
TempHeader::new(3), | |||
TempHeader::new(2), | |||
TempHeader::new(1), | |||
TempHeader::new(2), | |||
TempHeader::new(3), | |||
TempHeader::new(3), | |||
]; | |||
let toc = make_table_of_contents(input); | |||
assert_eq!(toc.len(), 2); | |||
assert_eq!(toc[0].children.len(), 3); | |||
assert_eq!(toc[1].children.len(), 1); | |||
assert_eq!(toc[0].children[1].children.len(), 1); | |||
assert_eq!(toc[1].children[0].children.len(), 2); | |||
} | |||
#[test] | |||
fn can_make_messy_toc() { | |||
let input = vec![ | |||
TempHeader::new(3), | |||
TempHeader::new(2), | |||
TempHeader::new(2), | |||
TempHeader::new(3), | |||
TempHeader::new(2), | |||
TempHeader::new(1), | |||
TempHeader::new(4), | |||
]; | |||
let toc = make_table_of_contents(input); | |||
assert_eq!(toc.len(), 5); | |||
assert_eq!(toc[2].children.len(), 1); | |||
assert_eq!(toc[4].children.len(), 1); | |||
} | |||
} |
@@ -6,6 +6,7 @@ use tera::{Context, Tera}; | |||
use config::Config; | |||
use errors::{Result, ResultExt}; | |||
use content::Page; | |||
use content::sorting::{SortBy, sort_pages}; | |||
#[derive(Debug, Copy, Clone, PartialEq)] | |||
@@ -24,10 +25,12 @@ pub struct TaxonomyItem { | |||
impl TaxonomyItem { | |||
pub fn new(name: &str, pages: Vec<Page>) -> TaxonomyItem { | |||
// We shouldn't have any pages without dates there | |||
let (sorted_pages, _) = sort_pages(pages, SortBy::Date); | |||
TaxonomyItem { | |||
name: name.to_string(), | |||
slug: slugify(name), | |||
pages, | |||
pages: sorted_pages, | |||
} | |||
} | |||
} | |||
@@ -48,6 +51,14 @@ impl Taxonomy { | |||
// Find all the tags/categories first | |||
for page in all_pages { | |||
// Don't consider pages without pages for tags/categories as that's the only thing | |||
// we can sort pages with across sections | |||
// If anyone sees that comment and wonder wtf, please open an issue as I can't think of | |||
// usecases other than blog posts for built-in taxonomies | |||
if page.meta.date.is_none() { | |||
continue; | |||
} | |||
if let Some(ref category) = page.meta.category { | |||
categories | |||
.entry(category.to_string()) | |||
@@ -109,10 +120,6 @@ impl Taxonomy { | |||
let name = self.get_single_item_name(); | |||
let mut context = Context::new(); | |||
context.add("config", config); | |||
// TODO: how to sort categories and tag content? | |||
// Have a setting in config.toml or a _category.md and _tag.md | |||
// The latter is more in line with the rest of Gutenberg but order ordering | |||
// doesn't really work across sections. | |||
context.add(&name, item); | |||
context.add("current_url", &config.make_permalink(&format!("{}/{}", name, item.slug))); | |||
context.add("current_path", &format!("/{}/{}", name, item.slug)); | |||
@@ -28,6 +28,9 @@ pub struct PageFrontMatter { | |||
pub category: Option<String>, | |||
/// Integer to use to order content. Lowest is at the bottom, highest first | |||
pub order: Option<usize>, | |||
/// All aliases for that page. Gutenberg will create HTML templates that will | |||
#[serde(skip_serializing)] | |||
pub aliases: Option<Vec<String>>, | |||
/// Specify a template different from `page.html` to use for that page | |||
#[serde(skip_serializing)] | |||
pub template: Option<String>, | |||
@@ -100,6 +103,7 @@ impl Default for PageFrontMatter { | |||
tags: None, | |||
category: None, | |||
order: None, | |||
aliases: None, | |||
template: None, | |||
extra: None, | |||
} | |||
@@ -12,14 +12,22 @@ pub struct Context<'a> { | |||
pub tera: &'a Tera, | |||
pub highlight_code: bool, | |||
pub highlight_theme: String, | |||
pub current_page_permalink: String, | |||
pub permalinks: &'a HashMap<String, String>, | |||
pub insert_anchor: InsertAnchor, | |||
} | |||
impl<'a> Context<'a> { | |||
pub fn new(tera: &'a Tera, config: &'a Config, permalinks: &'a HashMap<String, String>, insert_anchor: InsertAnchor) -> Context<'a> { | |||
pub fn new( | |||
tera: &'a Tera, | |||
config: &'a Config, | |||
current_page_permalink: &str, | |||
permalinks: &'a HashMap<String, String>, | |||
insert_anchor: InsertAnchor, | |||
) -> Context<'a> { | |||
Context { | |||
tera, | |||
current_page_permalink: current_page_permalink.to_string(), | |||
permalinks, | |||
insert_anchor, | |||
highlight_code: config.highlight_code.unwrap(), | |||
@@ -16,6 +16,7 @@ use front_matter::InsertAnchor; | |||
use rendering::context::Context; | |||
use rendering::highlighting::THEME_SET; | |||
use rendering::short_code::{ShortCode, parse_shortcode, render_simple_shortcode}; | |||
use content::{TempHeader, Header, make_table_of_contents}; | |||
// We need to put those in a struct to impl Send and sync | |||
pub struct Setup { | |||
@@ -37,7 +38,7 @@ lazy_static!{ | |||
} | |||
pub fn markdown_to_html(content: &str, context: &Context) -> Result<String> { | |||
pub fn markdown_to_html(content: &str, context: &Context) -> Result<(String, Vec<Header>)> { | |||
// 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 | |||
@@ -62,9 +63,10 @@ pub fn markdown_to_html(content: &str, context: &Context) -> Result<String> { | |||
// pulldown_cmark can send several text events for a title if there are markdown | |||
// specific characters like `!` in them. We only want to insert the anchor the first time | |||
let mut header_already_inserted = false; | |||
let mut anchors: Vec<String> = vec![]; | |||
// the rendered html | |||
let mut html = String::new(); | |||
let mut anchors: Vec<String> = vec![]; | |||
// 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 | |||
@@ -83,6 +85,11 @@ pub fn markdown_to_html(content: &str, context: &Context) -> Result<String> { | |||
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 opts = Options::empty(); | |||
opts.insert(OPTION_ENABLE_TABLES); | |||
opts.insert(OPTION_ENABLE_FOOTNOTES); | |||
@@ -158,6 +165,13 @@ pub fn markdown_to_html(content: &str, context: &Context) -> Result<String> { | |||
} else { | |||
String::new() | |||
}; | |||
// update the header and add it to the list | |||
temp_header.id = id.clone(); | |||
temp_header.title = text.clone().into_owned(); | |||
temp_header.permalink = format!("{}#{}", context.current_page_permalink, id); | |||
headers.push(temp_header.clone()); | |||
temp_header = TempHeader::default(); | |||
header_already_inserted = true; | |||
let event = match context.insert_anchor { | |||
InsertAnchor::Left => Event::Html(Owned(format!(r#"id="{}">{}{}"#, id, anchor_link, text))), | |||
@@ -230,6 +244,7 @@ pub fn markdown_to_html(content: &str, context: &Context) -> Result<String> { | |||
}, | |||
Event::Start(Tag::Header(num)) => { | |||
in_header = true; | |||
temp_header = TempHeader::new(num); | |||
// ugly eh | |||
Event::Html(Owned(format!("<h{} ", num))) | |||
}, | |||
@@ -264,7 +279,7 @@ pub fn markdown_to_html(content: &str, context: &Context) -> Result<String> { | |||
match error { | |||
Some(e) => Err(e), | |||
None => Ok(html.replace("<p></p>", "")), | |||
None => Ok((html.replace("<p></p>", ""), make_table_of_contents(headers))), | |||
} | |||
} | |||
@@ -287,9 +302,9 @@ mod tests { | |||
let tera_ctx = Tera::default(); | |||
let permalinks_ctx = HashMap::new(); | |||
let config_ctx = Config::default(); | |||
let context = Context::new(&tera_ctx, &config_ctx, &permalinks_ctx, InsertAnchor::None); | |||
let context = Context::new(&tera_ctx, &config_ctx, "", &permalinks_ctx, InsertAnchor::None); | |||
let res = markdown_to_html("hello", &context).unwrap(); | |||
assert_eq!(res, "<p>hello</p>\n"); | |||
assert_eq!(res.0, "<p>hello</p>\n"); | |||
} | |||
#[test] | |||
@@ -297,11 +312,11 @@ mod tests { | |||
let tera_ctx = Tera::default(); | |||
let permalinks_ctx = HashMap::new(); | |||
let config_ctx = Config::default(); | |||
let mut context = Context::new(&tera_ctx, &config_ctx, &permalinks_ctx, InsertAnchor::None); | |||
let mut context = Context::new(&tera_ctx, &config_ctx, "", &permalinks_ctx, InsertAnchor::None); | |||
context.highlight_code = false; | |||
let res = markdown_to_html("```\n$ gutenberg server\n```", &context).unwrap(); | |||
assert_eq!( | |||
res, | |||
res.0, | |||
"<pre><code>$ gutenberg server\n</code></pre>\n" | |||
); | |||
} | |||
@@ -311,10 +326,10 @@ mod tests { | |||
let tera_ctx = Tera::default(); | |||
let permalinks_ctx = HashMap::new(); | |||
let config_ctx = Config::default(); | |||
let context = Context::new(&tera_ctx, &config_ctx, &permalinks_ctx, InsertAnchor::None); | |||
let context = Context::new(&tera_ctx, &config_ctx, "", &permalinks_ctx, InsertAnchor::None); | |||
let res = markdown_to_html("```\n$ gutenberg server\n$ ping\n```", &context).unwrap(); | |||
assert_eq!( | |||
res, | |||
res.0, | |||
"<pre style=\"background-color:#2b303b\">\n<span style=\"background-color:#2b303b;color:#c0c5ce;\">$ gutenberg server\n</span><span style=\"background-color:#2b303b;color:#c0c5ce;\">$ ping\n</span></pre>" | |||
); | |||
} | |||
@@ -324,10 +339,10 @@ mod tests { | |||
let tera_ctx = Tera::default(); | |||
let permalinks_ctx = HashMap::new(); | |||
let config_ctx = Config::default(); | |||
let context = Context::new(&tera_ctx, &config_ctx, &permalinks_ctx, InsertAnchor::None); | |||
let context = Context::new(&tera_ctx, &config_ctx, "", &permalinks_ctx, InsertAnchor::None); | |||
let res = markdown_to_html("```python\nlist.append(1)\n```", &context).unwrap(); | |||
assert_eq!( | |||
res, | |||
res.0, | |||
"<pre style=\"background-color:#2b303b\">\n<span style=\"background-color:#2b303b;color:#c0c5ce;\">list</span><span style=\"background-color:#2b303b;color:#c0c5ce;\">.</span><span style=\"background-color:#2b303b;color:#bf616a;\">append</span><span style=\"background-color:#2b303b;color:#c0c5ce;\">(</span><span style=\"background-color:#2b303b;color:#d08770;\">1</span><span style=\"background-color:#2b303b;color:#c0c5ce;\">)</span><span style=\"background-color:#2b303b;color:#c0c5ce;\">\n</span></pre>" | |||
); | |||
} | |||
@@ -337,11 +352,11 @@ mod tests { | |||
let tera_ctx = Tera::default(); | |||
let permalinks_ctx = HashMap::new(); | |||
let config_ctx = Config::default(); | |||
let context = Context::new(&tera_ctx, &config_ctx, &permalinks_ctx, InsertAnchor::None); | |||
let context = Context::new(&tera_ctx, &config_ctx, "", &permalinks_ctx, InsertAnchor::None); | |||
let res = markdown_to_html("```yolo\nlist.append(1)\n```", &context).unwrap(); | |||
// defaults to plain text | |||
assert_eq!( | |||
res, | |||
res.0, | |||
"<pre style=\"background-color:#2b303b\">\n<span style=\"background-color:#2b303b;color:#c0c5ce;\">list.append(1)\n</span></pre>" | |||
); | |||
} | |||
@@ -350,21 +365,21 @@ mod tests { | |||
fn can_render_shortcode() { | |||
let permalinks_ctx = HashMap::new(); | |||
let config_ctx = Config::default(); | |||
let context = Context::new(&GUTENBERG_TERA, &config_ctx, &permalinks_ctx, InsertAnchor::None); | |||
let context = Context::new(&GUTENBERG_TERA, &config_ctx, "", &permalinks_ctx, InsertAnchor::None); | |||
let res = markdown_to_html(r#" | |||
Hello | |||
{{ youtube(id="ub36ffWAqgQ") }} | |||
"#, &context).unwrap(); | |||
assert!(res.contains("<p>Hello</p>\n<div >")); | |||
assert!(res.contains(r#"<iframe src="https://www.youtube.com/embed/ub36ffWAqgQ""#)); | |||
assert!(res.0.contains("<p>Hello</p>\n<div >")); | |||
assert!(res.0.contains(r#"<iframe src="https://www.youtube.com/embed/ub36ffWAqgQ""#)); | |||
} | |||
#[test] | |||
fn can_render_several_shortcode_in_row() { | |||
let permalinks_ctx = HashMap::new(); | |||
let config_ctx = Config::default(); | |||
let context = Context::new(&GUTENBERG_TERA, &config_ctx, &permalinks_ctx, InsertAnchor::None); | |||
let context = Context::new(&GUTENBERG_TERA, &config_ctx, "", &permalinks_ctx, InsertAnchor::None); | |||
let res = markdown_to_html(r#" | |||
Hello | |||
@@ -374,22 +389,25 @@ Hello | |||
{{ vimeo(id="210073083") }} | |||
{{ streamable(id="c0ic") }} | |||
{{ gist(url="https://gist.github.com/Keats/32d26f699dcc13ebd41b") }} | |||
"#, &context).unwrap(); | |||
assert!(res.contains("<p>Hello</p>\n<div >")); | |||
assert!(res.contains(r#"<iframe src="https://www.youtube.com/embed/ub36ffWAqgQ""#)); | |||
assert!(res.contains(r#"<iframe src="https://www.youtube.com/embed/ub36ffWAqgQ?autoplay=1""#)); | |||
assert!(res.contains(r#"//player.vimeo.com/video/210073083""#)); | |||
assert!(res.0.contains("<p>Hello</p>\n<div >")); | |||
assert!(res.0.contains(r#"<iframe src="https://www.youtube.com/embed/ub36ffWAqgQ""#)); | |||
assert!(res.0.contains(r#"<iframe src="https://www.youtube.com/embed/ub36ffWAqgQ?autoplay=1""#)); | |||
assert!(res.0.contains(r#"<iframe src="https://www.streamable.com/e/c0ic""#)); | |||
assert!(res.0.contains(r#"//player.vimeo.com/video/210073083""#)); | |||
} | |||
#[test] | |||
fn doesnt_render_shortcode_in_code_block() { | |||
let permalinks_ctx = HashMap::new(); | |||
let config_ctx = Config::default(); | |||
let context = Context::new(&GUTENBERG_TERA, &config_ctx, &permalinks_ctx, InsertAnchor::None); | |||
let context = Context::new(&GUTENBERG_TERA, &config_ctx, "", &permalinks_ctx, InsertAnchor::None); | |||
let res = markdown_to_html(r#"```{{ youtube(id="w7Ft2ymGmfc") }}```"#, &context).unwrap(); | |||
assert_eq!(res, "<p><code>{{ youtube(id="w7Ft2ymGmfc") }}</code></p>\n"); | |||
assert_eq!(res.0, "<p><code>{{ youtube(id="w7Ft2ymGmfc") }}</code></p>\n"); | |||
} | |||
#[test] | |||
@@ -399,7 +417,7 @@ Hello | |||
tera.add_raw_template("shortcodes/quote.html", "<blockquote>{{ body }} - {{ author}}</blockquote>").unwrap(); | |||
let permalinks_ctx = HashMap::new(); | |||
let config_ctx = Config::default(); | |||
let context = Context::new(&tera, &config_ctx, &permalinks_ctx, InsertAnchor::None); | |||
let context = Context::new(&tera, &config_ctx, "", &permalinks_ctx, InsertAnchor::None); | |||
let res = markdown_to_html(r#" | |||
Hello | |||
@@ -407,7 +425,7 @@ Hello | |||
A quote | |||
{% end %} | |||
"#, &context).unwrap(); | |||
assert_eq!(res, "<p>Hello\n</p><blockquote>A quote - Keats</blockquote>"); | |||
assert_eq!(res.0, "<p>Hello\n</p><blockquote>A quote - Keats</blockquote>"); | |||
} | |||
#[test] | |||
@@ -415,7 +433,7 @@ A quote | |||
let tera_ctx = Tera::default(); | |||
let permalinks_ctx = HashMap::new(); | |||
let config_ctx = Config::default(); | |||
let context = Context::new(&tera_ctx, &config_ctx, &permalinks_ctx, InsertAnchor::None); | |||
let context = Context::new(&tera_ctx, &config_ctx, "", &permalinks_ctx, InsertAnchor::None); | |||
let res = markdown_to_html("{{ hello(flash=true) }}", &context); | |||
assert!(res.is_err()); | |||
} | |||
@@ -426,14 +444,14 @@ A quote | |||
permalinks.insert("pages/about.md".to_string(), "https://vincent.is/about".to_string()); | |||
let tera_ctx = Tera::default(); | |||
let config_ctx = Config::default(); | |||
let context = Context::new(&tera_ctx, &config_ctx, &permalinks, InsertAnchor::None); | |||
let context = Context::new(&tera_ctx, &config_ctx, "", &permalinks, InsertAnchor::None); | |||
let res = markdown_to_html( | |||
r#"[rel link](./pages/about.md), [abs link](https://vincent.is/about)"#, | |||
&context | |||
).unwrap(); | |||
assert!( | |||
res.contains(r#"<p><a href="https://vincent.is/about">rel link</a>, <a href="https://vincent.is/about">abs link</a></p>"#) | |||
res.0.contains(r#"<p><a href="https://vincent.is/about">rel link</a>, <a href="https://vincent.is/about">abs link</a></p>"#) | |||
); | |||
} | |||
@@ -443,11 +461,11 @@ A quote | |||
permalinks.insert("pages/about.md".to_string(), "https://vincent.is/about".to_string()); | |||
let tera_ctx = Tera::default(); | |||
let config_ctx = Config::default(); | |||
let context = Context::new(&tera_ctx, &config_ctx, &permalinks, InsertAnchor::None); | |||
let context = Context::new(&tera_ctx, &config_ctx, "", &permalinks, InsertAnchor::None); | |||
let res = markdown_to_html(r#"[rel link](./pages/about.md#cv)"#, &context).unwrap(); | |||
assert!( | |||
res.contains(r#"<p><a href="https://vincent.is/about#cv">rel link</a></p>"#) | |||
res.0.contains(r#"<p><a href="https://vincent.is/about#cv">rel link</a></p>"#) | |||
); | |||
} | |||
@@ -456,7 +474,7 @@ A quote | |||
let tera_ctx = Tera::default(); | |||
let permalinks_ctx = HashMap::new(); | |||
let config_ctx = Config::default(); | |||
let context = Context::new(&tera_ctx, &config_ctx, &permalinks_ctx, InsertAnchor::None); | |||
let context = Context::new(&tera_ctx, &config_ctx, "", &permalinks_ctx, InsertAnchor::None); | |||
let res = markdown_to_html("[rel link](./pages/about.md)", &context); | |||
assert!(res.is_err()); | |||
} | |||
@@ -466,9 +484,9 @@ A quote | |||
let tera_ctx = Tera::default(); | |||
let permalinks_ctx = HashMap::new(); | |||
let config_ctx = Config::default(); | |||
let context = Context::new(&tera_ctx, &config_ctx, &permalinks_ctx, InsertAnchor::None); | |||
let context = Context::new(&tera_ctx, &config_ctx, "", &permalinks_ctx, InsertAnchor::None); | |||
let res = markdown_to_html(r#"# Hello"#, &context).unwrap(); | |||
assert_eq!(res, "<h1 id=\"hello\">Hello</h1>\n"); | |||
assert_eq!(res.0, "<h1 id=\"hello\">Hello</h1>\n"); | |||
} | |||
#[test] | |||
@@ -476,19 +494,19 @@ A quote | |||
let tera_ctx = Tera::default(); | |||
let permalinks_ctx = HashMap::new(); | |||
let config_ctx = Config::default(); | |||
let context = Context::new(&tera_ctx, &config_ctx, &permalinks_ctx, InsertAnchor::None); | |||
let context = Context::new(&tera_ctx, &config_ctx, "", &permalinks_ctx, InsertAnchor::None); | |||
let res = markdown_to_html("# Hello\n# Hello", &context).unwrap(); | |||
assert_eq!(res, "<h1 id=\"hello\">Hello</h1>\n<h1 id=\"hello-1\">Hello</h1>\n"); | |||
assert_eq!(res.0, "<h1 id=\"hello\">Hello</h1>\n<h1 id=\"hello-1\">Hello</h1>\n"); | |||
} | |||
#[test] | |||
fn can_insert_anchor_left() { | |||
let permalinks_ctx = HashMap::new(); | |||
let config_ctx = Config::default(); | |||
let context = Context::new(&GUTENBERG_TERA, &config_ctx, &permalinks_ctx, InsertAnchor::Left); | |||
let context = Context::new(&GUTENBERG_TERA, &config_ctx, "", &permalinks_ctx, InsertAnchor::Left); | |||
let res = markdown_to_html("# Hello", &context).unwrap(); | |||
assert_eq!( | |||
res, | |||
res.0, | |||
"<h1 id=\"hello\"><a class=\"gutenberg-anchor\" href=\"#hello\" aria-label=\"Anchor link for: hello\">đź”—</a>\nHello</h1>\n" | |||
); | |||
} | |||
@@ -497,10 +515,10 @@ A quote | |||
fn can_insert_anchor_right() { | |||
let permalinks_ctx = HashMap::new(); | |||
let config_ctx = Config::default(); | |||
let context = Context::new(&GUTENBERG_TERA, &config_ctx, &permalinks_ctx, InsertAnchor::Right); | |||
let context = Context::new(&GUTENBERG_TERA, &config_ctx, "", &permalinks_ctx, InsertAnchor::Right); | |||
let res = markdown_to_html("# Hello", &context).unwrap(); | |||
assert_eq!( | |||
res, | |||
res.0, | |||
"<h1 id=\"hello\">Hello<a class=\"gutenberg-anchor\" href=\"#hello\" aria-label=\"Anchor link for: hello\">đź”—</a>\n</h1>\n" | |||
); | |||
} | |||
@@ -510,10 +528,10 @@ A quote | |||
fn can_insert_anchor_with_exclamation_mark() { | |||
let permalinks_ctx = HashMap::new(); | |||
let config_ctx = Config::default(); | |||
let context = Context::new(&GUTENBERG_TERA, &config_ctx, &permalinks_ctx, InsertAnchor::Left); | |||
let context = Context::new(&GUTENBERG_TERA, &config_ctx, "", &permalinks_ctx, InsertAnchor::Left); | |||
let res = markdown_to_html("# Hello!", &context).unwrap(); | |||
assert_eq!( | |||
res, | |||
res.0, | |||
"<h1 id=\"hello\"><a class=\"gutenberg-anchor\" href=\"#hello\" aria-label=\"Anchor link for: hello\">đź”—</a>\nHello!</h1>\n" | |||
); | |||
} | |||
@@ -523,10 +541,10 @@ A quote | |||
fn can_insert_anchor_with_link() { | |||
let permalinks_ctx = HashMap::new(); | |||
let config_ctx = Config::default(); | |||
let context = Context::new(&GUTENBERG_TERA, &config_ctx, &permalinks_ctx, InsertAnchor::Left); | |||
let context = Context::new(&GUTENBERG_TERA, &config_ctx, "", &permalinks_ctx, InsertAnchor::Left); | |||
let res = markdown_to_html("## [](#xresources)Xresources", &context).unwrap(); | |||
assert_eq!( | |||
res, | |||
res.0, | |||
"<h2 id=\"xresources\"><a class=\"gutenberg-anchor\" href=\"#xresources\" aria-label=\"Anchor link for: xresources\">đź”—</a>\nXresources</h2>\n" | |||
); | |||
} | |||
@@ -535,11 +553,40 @@ A quote | |||
fn can_insert_anchor_with_other_special_chars() { | |||
let permalinks_ctx = HashMap::new(); | |||
let config_ctx = Config::default(); | |||
let context = Context::new(&GUTENBERG_TERA, &config_ctx, &permalinks_ctx, InsertAnchor::Left); | |||
let context = Context::new(&GUTENBERG_TERA, &config_ctx, "", &permalinks_ctx, InsertAnchor::Left); | |||
let res = markdown_to_html("# Hello*_()", &context).unwrap(); | |||
assert_eq!( | |||
res, | |||
res.0, | |||
"<h1 id=\"hello\"><a class=\"gutenberg-anchor\" href=\"#hello\" aria-label=\"Anchor link for: hello\">đź”—</a>\nHello*_()</h1>\n" | |||
); | |||
} | |||
#[test] | |||
fn can_make_toc() { | |||
let permalinks_ctx = HashMap::new(); | |||
let config_ctx = Config::default(); | |||
let context = Context::new( | |||
&GUTENBERG_TERA, | |||
&config_ctx, | |||
"https://mysite.com/something", | |||
&permalinks_ctx, | |||
InsertAnchor::Left | |||
); | |||
let res = markdown_to_html(r#" | |||
# Header 1 | |||
## Header 2 | |||
## Another Header 2 | |||
### Last one | |||
"#, &context).unwrap(); | |||
let toc = res.1; | |||
assert_eq!(toc.len(), 1); | |||
assert_eq!(toc[0].children.len(), 2); | |||
assert_eq!(toc[0].children[1].children.len(), 1); | |||
} | |||
} |
@@ -304,7 +304,7 @@ impl Site { | |||
} | |||
/// Renders a single content page | |||
pub fn render_page(&self, page: &Page) -> Result<()> { | |||
pub fn render_page(&self, page: &Page, section: Option<&Section>) -> Result<()> { | |||
ensure_directory_exists(&self.output_path)?; | |||
// Copy the nesting of the content directory if we have sections for that page | |||
@@ -322,7 +322,7 @@ impl Site { | |||
create_directory(¤t_path)?; | |||
// Finally, create a index.html file there with the page rendered | |||
let output = page.render_html(&self.tera, &self.config)?; | |||
let output = page.render_html(&self.tera, &self.config, section)?; | |||
create_file(¤t_path.join("index.html"), &self.inject_livereload(output))?; | |||
// Copy any asset we found previously into the same directory as the index.html | |||
@@ -337,6 +337,8 @@ impl Site { | |||
/// Deletes the `public` directory and builds the site | |||
pub fn build(&self) -> Result<()> { | |||
self.clean()?; | |||
// Render aliases first to allow overwriting | |||
self.render_aliases()?; | |||
self.render_sections()?; | |||
self.render_orphan_pages()?; | |||
self.render_sitemap()?; | |||
@@ -352,6 +354,25 @@ impl Site { | |||
self.copy_static_directory() | |||
} | |||
pub fn render_aliases(&self) -> Result<()> { | |||
for page in self.pages.values() { | |||
if let Some(ref aliases) = page.meta.aliases { | |||
for alias in aliases { | |||
let mut output_path = self.output_path.to_path_buf(); | |||
for component in alias.split("/") { | |||
output_path.push(&component); | |||
if !output_path.exists() { | |||
create_directory(&output_path)?; | |||
} | |||
} | |||
create_file(&output_path.join("index.html"), &render_redirect_template(&page.permalink, &self.tera)?)?; | |||
} | |||
} | |||
} | |||
Ok(()) | |||
} | |||
/// Renders robots.txt | |||
pub fn render_robots(&self) -> Result<()> { | |||
ensure_directory_exists(&self.output_path)?; | |||
@@ -380,6 +401,10 @@ impl Site { | |||
} | |||
fn render_taxonomy(&self, taxonomy: &Taxonomy) -> Result<()> { | |||
if taxonomy.items.is_empty() { | |||
return Ok(()) | |||
} | |||
ensure_directory_exists(&self.output_path)?; | |||
let output_path = self.output_path.join(&taxonomy.get_list_name()); | |||
@@ -497,7 +522,7 @@ impl Site { | |||
if render_pages { | |||
for page in §ion.pages { | |||
self.render_page(page)?; | |||
self.render_page(page, Some(section))?; | |||
} | |||
} | |||
@@ -536,7 +561,7 @@ impl Site { | |||
ensure_directory_exists(&self.output_path)?; | |||
for page in self.get_all_orphan_pages() { | |||
self.render_page(page)?; | |||
self.render_page(page, None)?; | |||
} | |||
Ok(()) | |||
@@ -0,0 +1,7 @@ | |||
<div {% if class %}class="{{class}}"{% endif %}> | |||
<iframe src="https://www.streamable.com/e/{{id}}" | |||
scrolling="no" | |||
frameborder="0" | |||
allowfullscreen mozallowfullscreen webkitallowfullscreen> | |||
</iframe> | |||
</div> |
@@ -17,6 +17,7 @@ lazy_static! { | |||
("shortcodes/youtube.html", include_str!("builtins/shortcodes/youtube.html")), | |||
("shortcodes/vimeo.html", include_str!("builtins/shortcodes/vimeo.html")), | |||
("shortcodes/gist.html", include_str!("builtins/shortcodes/gist.html")), | |||
("shortcodes/streamable.html", include_str!("builtins/shortcodes/streamable.html")), | |||
("internal/alias.html", include_str!("builtins/internal/alias.html")), | |||
]).unwrap(); | |||
@@ -1 +1 @@ | |||
Subproject commit ea36395b5191cfac1cef60e44c4ec1eacf8b648c | |||
Subproject commit 6bbbca9ccd0bd3131575217b3780fa59d059fcba |
@@ -1 +1 @@ | |||
Subproject commit da05d942464943c27884e174a580fc5f879b0b60 | |||
Subproject commit ea597da94a17928019e05c3a177f1e972484eec0 |
@@ -1 +1 @@ | |||
Subproject commit a10df6e24f90f5cd532a242c1be05416f846db02 | |||
Subproject commit 303816f09fe5534487c010082bcd96c408823671 |
@@ -2,6 +2,5 @@ title = "My site" | |||
base_url = "https://replace-this-with-your-url.com" | |||
highlight_code = true | |||
[extra.author] | |||
name = "Vincent Prouillet" |
@@ -3,6 +3,7 @@ title = "Fixed slug" | |||
description = "" | |||
slug = "something-else" | |||
date = "2017-01-01" | |||
aliases = ["/an-old-url/old-page"] | |||
+++ | |||
A simple page with a slug defined | |||
@@ -11,4 +11,6 @@ A simple page | |||
{{ vimeo(id="210073083") }} | |||
{{ streamable(id="c0ic") }} | |||
{{ gist(url="https://gist.github.com/Keats/32d26f699dcc13ebd41b") }} |
@@ -1,6 +1,7 @@ | |||
{% extends "index.html" %} | |||
{% block content %} | |||
{% if section %}Section:{{ section.permalink }}{% endif %} | |||
{{ page.content | safe }} | |||
{% if page.previous %}Previous article: {{ page.previous.permalink }}{% endif %} | |||
@@ -28,7 +28,7 @@ fn can_parse_site() { | |||
// Make sure the page with a url doesn't have any sections | |||
let url_post = &site.pages[&posts_path.join("fixed-url.md")]; | |||
assert_eq!(url_post.path, "a-fixed-url"); | |||
assert_eq!(url_post.path, "a-fixed-url/"); | |||
// Make sure the article in a folder with only asset doesn't get counted as a section | |||
let asset_folder_post = &site.pages[&posts_path.join("with-assets").join("index.md")]; | |||
@@ -118,6 +118,10 @@ fn can_build_site_without_live_reload() { | |||
assert!(file_exists!(public, "posts/tutorials/programming/index.html")); | |||
// TODO: add assertion for syntax highlighting | |||
// aliases work | |||
assert!(file_exists!(public, "an-old-url/old-page/index.html")); | |||
assert!(file_contains!(public, "an-old-url/old-page/index.html", "something-else")); | |||
// No tags or categories | |||
assert_eq!(file_exists!(public, "categories/index.html"), false); | |||
assert_eq!(file_exists!(public, "tags/index.html"), false); | |||
@@ -126,8 +130,11 @@ fn can_build_site_without_live_reload() { | |||
assert_eq!(file_contains!(public, "index.html", "/livereload.js?port=1112&mindelay=10"), false); | |||
// Both pages and sections are in the sitemap | |||
assert!(file_contains!(public, "sitemap.xml", "<loc>https://replace-this-with-your-url.com/posts/simple</loc>")); | |||
assert!(file_contains!(public, "sitemap.xml", "<loc>https://replace-this-with-your-url.com/posts</loc>")); | |||
assert!(file_contains!(public, "sitemap.xml", "<loc>https://replace-this-with-your-url.com/posts/simple/</loc>")); | |||
assert!(file_contains!(public, "sitemap.xml", "<loc>https://replace-this-with-your-url.com/posts/</loc>")); | |||
// section is in the page context | |||
assert!(file_contains!(public, "posts/python/index.html", "Section:")); | |||
} | |||
#[test] | |||
@@ -216,8 +223,8 @@ fn can_build_site_with_categories() { | |||
assert_eq!(file_exists!(public, "tags/index.html"), false); | |||
// Categories are in the sitemap | |||
assert!(file_contains!(public, "sitemap.xml", "<loc>https://replace-this-with-your-url.com/categories</loc>")); | |||
assert!(file_contains!(public, "sitemap.xml", "<loc>https://replace-this-with-your-url.com/categories/a</loc>")); | |||
assert!(file_contains!(public, "sitemap.xml", "<loc>https://replace-this-with-your-url.com/categories/</loc>")); | |||
assert!(file_contains!(public, "sitemap.xml", "<loc>https://replace-this-with-your-url.com/categories/a/</loc>")); | |||
} | |||
#[test] | |||
@@ -268,8 +275,8 @@ fn can_build_site_with_tags() { | |||
// Categories aren't | |||
assert_eq!(file_exists!(public, "categories/index.html"), false); | |||
// Tags are in the sitemap | |||
assert!(file_contains!(public, "sitemap.xml", "<loc>https://replace-this-with-your-url.com/tags</loc>")); | |||
assert!(file_contains!(public, "sitemap.xml", "<loc>https://replace-this-with-your-url.com/tags/tag-with-space</loc>")); | |||
assert!(file_contains!(public, "sitemap.xml", "<loc>https://replace-this-with-your-url.com/tags/</loc>")); | |||
assert!(file_contains!(public, "sitemap.xml", "<loc>https://replace-this-with-your-url.com/tags/tag-with-space/</loc>")); | |||
} | |||
#[test] | |||
@@ -327,14 +334,14 @@ fn can_build_site_with_pagination_for_section() { | |||
assert!(file_contains!( | |||
public, | |||
"posts/page/1/index.html", | |||
"http-equiv=\"refresh\" content=\"0;url=https://replace-this-with-your-url.com/posts\"" | |||
"http-equiv=\"refresh\" content=\"0;url=https://replace-this-with-your-url.com/posts/\"" | |||
)); | |||
assert!(file_contains!(public, "posts/index.html", "Num pagers: 3")); | |||
assert!(file_contains!(public, "posts/index.html", "Page size: 2")); | |||
assert!(file_contains!(public, "posts/index.html", "Current index: 1")); | |||
assert!(file_contains!(public, "posts/index.html", "has_next")); | |||
assert!(file_contains!(public, "posts/index.html", "First: https://replace-this-with-your-url.com/posts")); | |||
assert!(file_contains!(public, "posts/index.html", "Last: https://replace-this-with-your-url.com/posts/page/3")); | |||
assert!(file_contains!(public, "posts/index.html", "First: https://replace-this-with-your-url.com/posts/")); | |||
assert!(file_contains!(public, "posts/index.html", "Last: https://replace-this-with-your-url.com/posts/page/3/")); | |||
assert_eq!(file_contains!(public, "posts/index.html", "has_prev"), false); | |||
assert!(file_exists!(public, "posts/page/2/index.html")); | |||
@@ -343,8 +350,8 @@ fn can_build_site_with_pagination_for_section() { | |||
assert!(file_contains!(public, "posts/page/2/index.html", "Current index: 2")); | |||
assert!(file_contains!(public, "posts/page/2/index.html", "has_prev")); | |||
assert!(file_contains!(public, "posts/page/2/index.html", "has_next")); | |||
assert!(file_contains!(public, "posts/page/2/index.html", "First: https://replace-this-with-your-url.com/posts")); | |||
assert!(file_contains!(public, "posts/page/2/index.html", "Last: https://replace-this-with-your-url.com/posts/page/3")); | |||
assert!(file_contains!(public, "posts/page/2/index.html", "First: https://replace-this-with-your-url.com/posts/")); | |||
assert!(file_contains!(public, "posts/page/2/index.html", "Last: https://replace-this-with-your-url.com/posts/page/3/")); | |||
} | |||
#[test] | |||