Browse Source

Merge pull request #77 from Keats/next

v0.0.7
index-subcmd
Vincent Prouillet GitHub 7 years ago
parent
commit
264d1e3742
31 changed files with 614 additions and 263 deletions
  1. +10
    -0
      CHANGELOG.md
  2. +119
    -140
      Cargo.lock
  3. +1
    -1
      Cargo.toml
  4. +37
    -1
      README.md
  5. +1
    -4
      appveyor.yml
  6. +23
    -0
      src/bin/cmd/serve.rs
  7. +3
    -3
      src/bin/rebuild.rs
  8. +14
    -6
      src/config.rs
  9. +2
    -0
      src/content/mod.rs
  10. +20
    -8
      src/content/page.rs
  11. +26
    -25
      src/content/pagination.rs
  12. +12
    -4
      src/content/section.rs
  13. +166
    -0
      src/content/table_of_contents.rs
  14. +12
    -5
      src/content/taxonomies.rs
  15. +4
    -0
      src/front_matter/page.rs
  16. +9
    -1
      src/rendering/context.rs
  17. +92
    -45
      src/rendering/markdown.rs
  18. +29
    -4
      src/site.rs
  19. +7
    -0
      src/templates/builtins/shortcodes/streamable.html
  20. +1
    -0
      src/templates/mod.rs
  21. +1
    -1
      sublime_syntaxes/Elm.tmLanguage
  22. +1
    -1
      sublime_syntaxes/Julia-sublime
  23. +1
    -1
      sublime_syntaxes/Packages
  24. BIN
      sublime_syntaxes/newlines.packdump
  25. BIN
      sublime_syntaxes/nonewlines.packdump
  26. BIN
      sublime_themes/all.themedump
  27. +0
    -1
      test_site/config.toml
  28. +1
    -0
      test_site/content/posts/fixed-slug.md
  29. +2
    -0
      test_site/content/posts/simple.md
  30. +1
    -0
      test_site/templates/page.html
  31. +19
    -12
      tests/site.rs

+ 10
- 0
CHANGELOG.md View File

@@ -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


+ 119
- 140
Cargo.lock View File

@@ -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"

+ 1
- 1
Cargo.toml View File

@@ -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"


+ 37
- 1
README.md View File

@@ -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


+ 1
- 4
appveyor.yml View File

@@ -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:


+ 23
- 0
src/bin/cmd/serve.rs View File

@@ -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;


+ 3
- 3
src/bin/rebuild.rs View File

@@ -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(&current, find_parent_section(site, &current));
}

// 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, &current))?;
},
};
}


+ 14
- 6
src/config.rs View File

@@ -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/");
}
}

+ 2
- 0
src/content/mod.rs View File

@@ -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};


+ 20
- 8
src/content/page.rs View File

@@ -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", &section);

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"));
}



+ 26
- 25
src/content/pagination.rs View File

@@ -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());
}
}

+ 12
- 4
src/content/section.rs View File

@@ -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(&section.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![],
}
}
}

+ 166
- 0
src/content/table_of_contents.rs View File

@@ -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);
}
}

+ 12
- 5
src/content/taxonomies.rs View File

@@ -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));


+ 4
- 0
src/front_matter/page.rs View File

@@ -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,
}


+ 9
- 1
src/rendering/context.rs View File

@@ -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(),


+ 92
- 45
src/rendering/markdown.rs View File

@@ -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=&quot;w7Ft2ymGmfc&quot;) }}</code></p>\n");
assert_eq!(res.0, "<p><code>{{ youtube(id=&quot;w7Ft2ymGmfc&quot;) }}</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);

}
}

+ 29
- 4
src/site.rs View File

@@ -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(&current_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(&current_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 &section.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(())


+ 7
- 0
src/templates/builtins/shortcodes/streamable.html View File

@@ -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>

+ 1
- 0
src/templates/mod.rs View File

@@ -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
sublime_syntaxes/Elm.tmLanguage

@@ -1 +1 @@
Subproject commit ea36395b5191cfac1cef60e44c4ec1eacf8b648c
Subproject commit 6bbbca9ccd0bd3131575217b3780fa59d059fcba

+ 1
- 1
sublime_syntaxes/Julia-sublime

@@ -1 +1 @@
Subproject commit da05d942464943c27884e174a580fc5f879b0b60
Subproject commit ea597da94a17928019e05c3a177f1e972484eec0

+ 1
- 1
sublime_syntaxes/Packages

@@ -1 +1 @@
Subproject commit a10df6e24f90f5cd532a242c1be05416f846db02
Subproject commit 303816f09fe5534487c010082bcd96c408823671

BIN
sublime_syntaxes/newlines.packdump View File


BIN
sublime_syntaxes/nonewlines.packdump View File


BIN
sublime_themes/all.themedump View File


+ 0
- 1
test_site/config.toml View File

@@ -2,6 +2,5 @@ title = "My site"
base_url = "https://replace-this-with-your-url.com"
highlight_code = true


[extra.author]
name = "Vincent Prouillet"

+ 1
- 0
test_site/content/posts/fixed-slug.md View File

@@ -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


+ 2
- 0
test_site/content/posts/simple.md View File

@@ -11,4 +11,6 @@ A simple page

{{ vimeo(id="210073083") }}

{{ streamable(id="c0ic") }}

{{ gist(url="https://gist.github.com/Keats/32d26f699dcc13ebd41b") }}

+ 1
- 0
test_site/templates/page.html View File

@@ -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 %}


+ 19
- 12
tests/site.rs View File

@@ -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]


Loading…
Cancel
Save