mirror of
https://github.com/rust-lang/mdBook.git
synced 2025-12-28 15:01:45 -05:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c4d2070f7 | ||
|
|
50d5917530 | ||
|
|
9cd47eb80f | ||
|
|
4932df2570 | ||
|
|
11d31c989c | ||
|
|
e5ace6d6a4 | ||
|
|
e7c3d02c61 | ||
|
|
d8a68ba3f6 | ||
|
|
d29a79349c | ||
|
|
d6088c8a57 | ||
|
|
b91e5c8807 | ||
|
|
6199e4df79 | ||
|
|
2d11eb05fe | ||
|
|
3d45e40693 | ||
|
|
228e99ba11 | ||
|
|
4b569edadd | ||
|
|
3e652b5bfc | ||
|
|
ba41d73dc3 | ||
|
|
1ce1401263 | ||
|
|
00b3d9cf86 | ||
|
|
bb3398bdbb | ||
|
|
19c26217c0 | ||
|
|
a2029f0a78 | ||
|
|
7c33ac800c | ||
|
|
d371001ab8 | ||
|
|
d73504eb23 | ||
|
|
abddd7c6f7 | ||
|
|
31e36f85e7 | ||
|
|
92a7b0cdcd | ||
|
|
592140db5b | ||
|
|
3a0eeb4bbb | ||
|
|
a9dae326fa | ||
|
|
abba959add | ||
|
|
ea15e55829 | ||
|
|
d07bd9fed4 | ||
|
|
b83c55f7ef | ||
|
|
4f7c299de7 |
32
.travis.yml
32
.travis.yml
@@ -4,8 +4,6 @@ cache:
|
||||
directories:
|
||||
- "$HOME/.cargo"
|
||||
- "$HOME/.cache/sccache"
|
||||
before_cache:
|
||||
- rm -rf "$HOME/.cargo/registry"
|
||||
|
||||
env:
|
||||
global:
|
||||
@@ -19,34 +17,36 @@ matrix:
|
||||
env: TARGET=x86_64-unknown-linux-gnu
|
||||
- rust: nightly
|
||||
env: TARGET=x86_64-unknown-linux-gnu
|
||||
- rust: 1.34.0 # Minimum required Rust version
|
||||
env: TARGET=x86_64-unknown-linux-gnu
|
||||
|
||||
- rust: stable
|
||||
os: osx
|
||||
env: TARGET=x86_64-apple-darwin
|
||||
|
||||
before_install:
|
||||
- export SCCACHE_VER=0.2.8 RUSTC_WRAPPER=sccache
|
||||
- case "$TRAVIS_OS_NAME" in
|
||||
- |
|
||||
export RUSTC_WRAPPER=sccache;
|
||||
cd "$(mktemp -d)";
|
||||
case "$TRAVIS_OS_NAME" in
|
||||
linux )
|
||||
cd /tmp
|
||||
&& travis_retry curl -sSL "https://github.com/mozilla/sccache/releases/download/${SCCACHE_VER}/sccache-${SCCACHE_VER}-x86_64-unknown-linux-musl.tar.gz" | tar xzf -
|
||||
&& sudo mv "sccache-${SCCACHE_VER}-x86_64-unknown-linux-musl/sccache" /usr/local/bin/sccache;
|
||||
travis_retry curl -sSL 'https://github.com/mozilla/sccache/releases/download/0.2.9/sccache-0.2.9-x86_64-unknown-linux-musl.tar.gz' | tar -xzf - --strip-components=1 &&
|
||||
sudo cp sccache /usr/local/bin/sccache;
|
||||
;;
|
||||
osx )
|
||||
cd "${TMPDIR}"
|
||||
&& travis_retry curl -sSL "https://github.com/mozilla/sccache/releases/download/${SCCACHE_VER}/sccache-${SCCACHE_VER}-x86_64-apple-darwin.tar.gz" | tar xzf -
|
||||
&& sudo mv "sccache-${SCCACHE_VER}-x86_64-apple-darwin/sccache" /usr/local/bin/sccache;
|
||||
travis_retry curl -sSL 'https://github.com/mozilla/sccache/releases/download/0.2.9/sccache-0.2.9-x86_64-apple-darwin.tar.gz' | tar -xzf - --strip-components=1 &&
|
||||
sudo cp sccache /usr/local/bin/sccache;
|
||||
;;
|
||||
* ) unset RUSTC_WRAPPER;;
|
||||
esac
|
||||
- cd "$TRAVIS_BUILD_DIR"
|
||||
esac;
|
||||
cd "$TRAVIS_BUILD_DIR";
|
||||
|
||||
script:
|
||||
- cargo test --all
|
||||
- cargo test --all --no-default-features
|
||||
- if [ "$TARGET" = x86_64-unknown-linux-gnu ] && [ "$TRAVIS_RUST_VERSION" = stable ]; then
|
||||
rustup component add rustfmt;
|
||||
rustfmt -vV;
|
||||
- |
|
||||
if [ "$TARGET" = x86_64-unknown-linux-gnu ] && [ "$TRAVIS_RUST_VERSION" = stable ]; then
|
||||
rustup component add rustfmt && \
|
||||
cargo fmt --all -- --check;
|
||||
fi
|
||||
|
||||
@@ -67,7 +67,7 @@ deploy:
|
||||
local_dir: book-example/book
|
||||
skip_cleanup: true
|
||||
github_token: "$GITHUB_TOKEN"
|
||||
keep_history: true
|
||||
keep_history: false
|
||||
on:
|
||||
condition: $TRAVIS_OS_NAME = "linux" && $TRAVIS_RUST_VERSION = "stable"
|
||||
tags: true
|
||||
|
||||
24
CHANGELOG.md
24
CHANGELOG.md
@@ -1,7 +1,29 @@
|
||||
# Changelog
|
||||
|
||||
## mdBook 0.3.1
|
||||
[69a08ef...9cd47eb](https://github.com/rust-lang-nursery/mdBook/compare/69a08ef...9cd47eb)
|
||||
|
||||
### Added
|
||||
- 🔥 Added ability to include files using anchor points instead of line numbers.
|
||||
[#851](https://github.com/rust-lang-nursery/mdBook/pull/851)
|
||||
- Added `language` configuration value to set the language of the book, which
|
||||
will affect things like the `<html lang="en">` tag.
|
||||
[#941](https://github.com/rust-lang-nursery/mdBook/pull/941)
|
||||
|
||||
### Changed
|
||||
- Updated to handlebars 2.0.
|
||||
[#977](https://github.com/rust-lang-nursery/mdBook/pull/977)
|
||||
|
||||
### Fixed
|
||||
- Fixed memory leak warning.
|
||||
[#967](https://github.com/rust-lang-nursery/mdBook/pull/967)
|
||||
- Fix more print.html links.
|
||||
[#963](https://github.com/rust-lang-nursery/mdBook/pull/963)
|
||||
- Fixed crash on some unicode input.
|
||||
[#978](https://github.com/rust-lang-nursery/mdBook/pull/978)
|
||||
|
||||
## mdBook 0.3.0
|
||||
[6cbc41d...84d4063](https://github.com/rust-lang-nursery/mdBook/compare/6cbc41d...84d4063)
|
||||
[6cbc41d...69a08ef](https://github.com/rust-lang-nursery/mdBook/compare/6cbc41d...69a08ef)
|
||||
|
||||
### Added
|
||||
- Added ability to resize the sidebar.
|
||||
|
||||
42
Cargo.lock
generated
42
Cargo.lock
generated
@@ -10,7 +10,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ammonia"
|
||||
version = "2.1.1"
|
||||
version = "2.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"html5ever 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -240,7 +240,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "elasticlunr-rs"
|
||||
version = "2.3.4"
|
||||
version = "2.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -248,8 +248,8 @@ dependencies = [
|
||||
"serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strum 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strum_macros 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strum 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strum_macros 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -376,9 +376,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "handlebars"
|
||||
version = "1.1.0"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pest 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -389,6 +390,14 @@ dependencies = [
|
||||
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.1"
|
||||
@@ -624,15 +633,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "mdbook"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
dependencies = [
|
||||
"ammonia 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ammonia 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"elasticlunr-rs 2.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"elasticlunr-rs 2.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"handlebars 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"handlebars 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iron 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1263,12 +1272,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.11.0"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.11.0"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1646,7 +1655,7 @@ dependencies = [
|
||||
|
||||
[metadata]
|
||||
"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c"
|
||||
"checksum ammonia 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c799ecf1ad77acb48b643e2f45b12d60ee41576287fc575031aa020de88b8f45"
|
||||
"checksum ammonia 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "384d704f242a0a9faf793fff775a0be6ab9aa27edabffa097331d73779142520"
|
||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
||||
"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf"
|
||||
@@ -1674,7 +1683,7 @@ dependencies = [
|
||||
"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
|
||||
"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c"
|
||||
"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b"
|
||||
"checksum elasticlunr-rs 2.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a99a310cd1f9770e7bf8e48810c7bcbb0e078c8fb23a8c7bcf0da4c2bf61a455"
|
||||
"checksum elasticlunr-rs 2.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f66a620976c38dbbbcd6355910432cef8b0911b3af86332029752379f0ff7924"
|
||||
"checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a"
|
||||
"checksum error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9"
|
||||
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
|
||||
@@ -1690,7 +1699,8 @@ dependencies = [
|
||||
"checksum futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b"
|
||||
"checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592"
|
||||
"checksum getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "72327b15c228bfe31f1390f93dd5e9279587f0463836393c9df719ce62a3e450"
|
||||
"checksum handlebars 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d82e5750d8027a97b9640e3fefa66bbaf852a35228e1c90790efd13c4b09c166"
|
||||
"checksum handlebars 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "df044dd42cdb7e32f28557b661406fc0f2494be75199779998810dbc35030e0d"
|
||||
"checksum hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1de41fb8dba9714efd92241565cdff73f78508c95697dd56787d3cba27e2353"
|
||||
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||
"checksum html5ever 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a49d5001dd1bddf042ea41ed4e0a671d50b1bf187e66b349d7ec613bdce4ad90"
|
||||
"checksum html5ever 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ce65ac8028cf5a287a7dbf6c4e0a6cf2dcf022ed5b167a81bae66ebf599a8b7"
|
||||
@@ -1791,8 +1801,8 @@ dependencies = [
|
||||
"checksum string_cache_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eea1eee654ef80933142157fdad9dd8bc43cf7c74e999e369263496f04ff4da"
|
||||
"checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc"
|
||||
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
"checksum strum 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c3a2071519ab6a48f465808c4c1ffdd00dfc8e93111d02b4fc5abab177676e"
|
||||
"checksum strum_macros 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8baacebd7b7c9b864d83a6ba7a246232983e277b86fa5cdec77f565715a4b136"
|
||||
"checksum strum 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e5d1c33039533f051704951680f1adfd468fd37ac46816ded0d9ee068e60f05f"
|
||||
"checksum strum_macros 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "47cd23f5c7dee395a00fa20135e2ec0fffcdfa151c56182966d7a3261343432e"
|
||||
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
|
||||
"checksum syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe"
|
||||
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mdbook"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
authors = [
|
||||
"Mathieu David <mathieudavid@mathieudavid.org>",
|
||||
"Michael-F-Bryan <michaelfbryan@gmail.com>",
|
||||
@@ -20,7 +20,7 @@ chrono = "0.4"
|
||||
clap = "2.24"
|
||||
env_logger = "0.6"
|
||||
error-chain = "0.12"
|
||||
handlebars = { version = "1.0", default-features = false, features = ["no_dir_source"] }
|
||||
handlebars = { version = "2.0", default-features = false, features = ["no_dir_source"] }
|
||||
itertools = "0.8"
|
||||
lazy_static = "1.0"
|
||||
log = "0.4"
|
||||
@@ -46,7 +46,7 @@ ws = { version = "0.8", optional = true}
|
||||
|
||||
# Search feature
|
||||
elasticlunr-rs = { version = "2.3", optional = true, default-features = false }
|
||||
ammonia = { version = "2.1", optional = true }
|
||||
ammonia = { version = "2.1.2", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
select = "0.4"
|
||||
|
||||
@@ -41,7 +41,7 @@ There are multiple ways to install mdBook.
|
||||
|
||||
2. **From Crates.io**
|
||||
|
||||
This requires at least [Rust] 1.20 and Cargo to be installed. Once you have installed
|
||||
This requires at least [Rust] 1.34 and Cargo to be installed. Once you have installed
|
||||
Rust, type the following in the terminal:
|
||||
|
||||
```
|
||||
@@ -239,6 +239,6 @@ All the code in this repository is released under the ***Mozilla Public License
|
||||
[releases]: https://github.com/rust-lang-nursery/mdBook/releases
|
||||
[Rust]: https://www.rust-lang.org/
|
||||
[CLI docs]: http://rust-lang-nursery.github.io/mdBook/cli/init.html
|
||||
[master-docs]: http://rust-lang-nursery.github.io/mdBook/mdbook/
|
||||
[master-docs]: http://rust-lang-nursery.github.io/mdBook/
|
||||
[`linkcheck`]: https://crates.io/crates/mdbook-linkcheck
|
||||
[`epub`]: https://crates.io/crates/mdbook-epub
|
||||
[`epub`]: https://crates.io/crates/mdbook-epub
|
||||
|
||||
@@ -13,6 +13,9 @@ environment:
|
||||
|
||||
# Install Rust and Cargo
|
||||
install:
|
||||
# Since rust-lang-libs is currently sharing 1 builder, only run 1 job when a
|
||||
# PR is opened. Merges to master or tags will run all jobs.
|
||||
- ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -gt 0 -and ($env:TARGET -ne "x86_64-pc-windows-msvc" -or $env:RUST_CHANNEL -ne "stable") ) {Exit-AppveyorBuild}
|
||||
- ps: >-
|
||||
If ($Env:TARGET -eq 'x86_64-pc-windows-gnu') {
|
||||
$Env:PATH += ';C:\msys64\mingw64\bin'
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
title = "mdBook Documentation"
|
||||
description = "Create book from markdown files. Like Gitbook but implemented in Rust"
|
||||
authors = ["Mathieu David", "Michael-F-Bryan"]
|
||||
language = "en"
|
||||
|
||||
[output.html]
|
||||
mathjax-support = true
|
||||
|
||||
@@ -19,7 +19,7 @@ The two main ways a developer can hook into the book's build process is via,
|
||||
|
||||
The process of rendering a book project goes through several steps.
|
||||
|
||||
1. Load the book
|
||||
1. Load the book
|
||||
- Parse the `book.toml`, falling back to the default `Config` if it doesn't
|
||||
exist
|
||||
- Load the book chapters into memory
|
||||
@@ -41,6 +41,6 @@ The easiest way to find out how to use the `mdbook` crate is by looking at the
|
||||
explanation on the configuration system.
|
||||
|
||||
|
||||
[`MDBook`]: http://rust-lang-nursery.github.io/mdBook/mdbook/book/struct.MDBook.html
|
||||
[`MDBook`]: https://docs.rs/mdbook/*/mdbook/book/struct.MDBook.html
|
||||
[API Docs]: https://docs.rs/mdbook/*/mdbook/
|
||||
[config]: file:///home/michael/Documents/forks/mdBook/target/doc/mdbook/config/index.html
|
||||
[config]: https://docs.rs/mdbook/*/mdbook/config/index.html
|
||||
|
||||
@@ -342,10 +342,10 @@ the source code or ask questions.
|
||||
[mdbook-epub]: https://github.com/Michael-F-Bryan/mdbook-epub
|
||||
[mdbook-test]: https://github.com/Michael-F-Bryan/mdbook-test
|
||||
[rust-skeptic]: https://github.com/budziq/rust-skeptic
|
||||
[`RenderContext`]: http://rust-lang-nursery.github.io/mdBook/mdbook/renderer/struct.RenderContext.html
|
||||
[`RenderContext::from_json()`]: http://rust-lang-nursery.github.io/mdBook/mdbook/renderer/struct.RenderContext.html#method.from_json
|
||||
[`RenderContext`]: https://docs.rs/mdbook/*/mdbook/renderer/struct.RenderContext.html
|
||||
[`RenderContext::from_json()`]: https://docs.rs/mdbook/*/mdbook/renderer/struct.RenderContext.html#method.from_json
|
||||
[`semver`]: https://crates.io/crates/semver
|
||||
[`Book`]: http://rust-lang-nursery.github.io/mdBook/mdbook/book/struct.Book.html
|
||||
[`Book::iter()`]: http://rust-lang-nursery.github.io/mdBook/mdbook/book/struct.Book.html#method.iter
|
||||
[`Config`]: http://rust-lang-nursery.github.io/mdBook/mdbook/config/struct.Config.html
|
||||
[`Book`]: https://docs.rs/mdbook/*/mdbook/book/struct.Book.html
|
||||
[`Book::iter()`]: https://docs.rs/mdbook/*/mdbook/book/struct.Book.html#method.iter
|
||||
[`Config`]: https://docs.rs/mdbook/*/mdbook/config/struct.Config.html
|
||||
[issue tracker]: https://github.com/rust-lang-nursery/mdBook/issues
|
||||
|
||||
@@ -42,6 +42,7 @@ This is general information about your book.
|
||||
- **src:** By default, the source directory is found in the directory named
|
||||
`src` directly under the root folder. But this is configurable with the `src`
|
||||
key in the configuration file.
|
||||
- **language:** The main language of the book, which is used as a language attribute `<html lang="en">` for example.
|
||||
|
||||
**book.toml**
|
||||
```toml
|
||||
@@ -50,6 +51,7 @@ title = "Example book"
|
||||
authors = ["John Doe", "Jane Doe"]
|
||||
description = "The example book covers examples."
|
||||
src = "my-src" # the source files will be found in `root/my-src` instead of `root/src`
|
||||
language = "en"
|
||||
```
|
||||
|
||||
### Build options
|
||||
|
||||
@@ -63,6 +63,50 @@ the file are omitted. The third command includes all lines from line 2, i.e. the
|
||||
first line is omitted. The last command includes the excerpt of `file.rs`
|
||||
consisting of lines 2 to 10.
|
||||
|
||||
To avoid breaking your book when modifying included files, you can also
|
||||
include a specific section using anchors instead of line numbers.
|
||||
An anchor is a pair of matching lines. The line beginning an anchor must
|
||||
match the regex "ANCHOR:\s*[\w_-]+" and similarly the ending line must match
|
||||
the regex "ANCHOR_END:\s*[\w_-]+". This allows you to put anchors in
|
||||
any kind of commented line.
|
||||
|
||||
Consider the following file to include:
|
||||
```rs
|
||||
/* ANCHOR: all */
|
||||
|
||||
// ANCHOR: component
|
||||
struct Paddle {
|
||||
hello: f32,
|
||||
}
|
||||
// ANCHOR_END: component
|
||||
|
||||
////////// ANCHOR: system
|
||||
impl System for MySystem { ... }
|
||||
////////// ANCHOR_END: system
|
||||
|
||||
/* ANCHOR_END: all */
|
||||
```
|
||||
|
||||
Then in the book, all you have to do is:
|
||||
````hbs
|
||||
Here is a component:
|
||||
```rust,no_run,noplaypen
|
||||
\{{#include file.rs:component}}
|
||||
```
|
||||
|
||||
Here is a system:
|
||||
```rust,no_run,noplaypen
|
||||
\{{#include file.rs:system}}
|
||||
```
|
||||
|
||||
This is the full file.
|
||||
```rust,no_run,noplaypen
|
||||
\{{#include file.rs:all}}
|
||||
```
|
||||
````
|
||||
|
||||
Lines containing anchor patterns inside the included anchor are ignored.
|
||||
|
||||
## Inserting runnable Rust files
|
||||
|
||||
With the following syntax, you can insert runnable Rust files into your book:
|
||||
|
||||
@@ -17,9 +17,8 @@ handlebars template you can access this information by using
|
||||
|
||||
Here is a list of the properties that are exposed:
|
||||
|
||||
- ***language*** Language of the book in the form `en`. To use in <code
|
||||
class="language-html">\<html lang="{{ language }}"></code> for example. At the
|
||||
moment it is hardcoded.
|
||||
- ***language*** Language of the book in the form `en`, as specified in `book.toml` (if not specified, defaults to `en`). To use in <code
|
||||
class="language-html">\<html lang="{{ language }}"></code> for example.
|
||||
- ***title*** Title of the book, as specified in `book.toml`
|
||||
- ***chapter_title*** Title of the current chapter, as listed in `SUMMARY.md`
|
||||
|
||||
|
||||
@@ -343,18 +343,16 @@ impl MDBook {
|
||||
|
||||
/// Look at the `Config` and try to figure out what renderers to use.
|
||||
fn determine_renderers(config: &Config) -> Vec<Box<dyn Renderer>> {
|
||||
let mut renderers: Vec<Box<dyn Renderer>> = Vec::new();
|
||||
let mut renderers = Vec::new();
|
||||
|
||||
if let Some(output_table) = config.get("output").and_then(Value::as_table) {
|
||||
for (key, table) in output_table.iter() {
|
||||
// the "html" backend has its own Renderer
|
||||
renderers.extend(output_table.iter().map(|(key, table)| {
|
||||
if key == "html" {
|
||||
renderers.push(Box::new(HtmlHandlebars::new()));
|
||||
Box::new(HtmlHandlebars::new()) as Box<dyn Renderer>
|
||||
} else {
|
||||
let renderer = interpret_custom_renderer(key, table);
|
||||
renderers.push(renderer);
|
||||
interpret_custom_renderer(key, table)
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
// if we couldn't find anything, add the HTML renderer as a default
|
||||
|
||||
@@ -131,10 +131,8 @@ impl Config {
|
||||
pub fn update_from_env(&mut self) {
|
||||
debug!("Updating the config from environment variables");
|
||||
|
||||
let overrides = env::vars().filter_map(|(key, value)| match parse_env(&key) {
|
||||
Some(index) => Some((index, value)),
|
||||
None => None,
|
||||
});
|
||||
let overrides =
|
||||
env::vars().filter_map(|(key, value)| parse_env(&key).map(|index| (index, value)));
|
||||
|
||||
for (key, value) in overrides {
|
||||
trace!("{} => {}", key, value);
|
||||
@@ -151,14 +149,11 @@ impl Config {
|
||||
/// `output.html.playpen` will fetch the "playpen" out of the html output
|
||||
/// table).
|
||||
pub fn get(&self, key: &str) -> Option<&Value> {
|
||||
match self.rest.read(key) {
|
||||
Ok(inner) => inner,
|
||||
Err(_) => None,
|
||||
}
|
||||
self.rest.read(key).unwrap_or(None)
|
||||
}
|
||||
|
||||
/// Fetch a value from the `Config` so you can mutate it.
|
||||
pub fn get_mut<'a>(&'a mut self, key: &str) -> Option<&'a mut Value> {
|
||||
pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
|
||||
match self.rest.read_mut(key) {
|
||||
Ok(inner) => inner,
|
||||
Err(_) => None,
|
||||
@@ -208,7 +203,7 @@ impl Config {
|
||||
} else {
|
||||
self.rest
|
||||
.insert(index, value)
|
||||
.map_err(|e| ErrorKind::TomlQueryError(e))?;
|
||||
.map_err(ErrorKind::TomlQueryError)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -376,6 +371,8 @@ pub struct BookConfig {
|
||||
pub src: PathBuf,
|
||||
/// Does this book support more than one language?
|
||||
pub multilingual: bool,
|
||||
/// The main language of the book.
|
||||
pub language: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for BookConfig {
|
||||
@@ -386,6 +383,7 @@ impl Default for BookConfig {
|
||||
description: None,
|
||||
src: PathBuf::from("src"),
|
||||
multilingual: false,
|
||||
language: Some(String::from("en")),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -545,12 +543,10 @@ trait Updateable<'de>: Serialize + Deserialize<'de> {
|
||||
fn update_value<S: Serialize>(&mut self, key: &str, value: S) {
|
||||
let mut raw = Value::try_from(&self).expect("unreachable");
|
||||
|
||||
{
|
||||
if let Ok(value) = Value::try_from(value) {
|
||||
let _ = raw.insert(key, value);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if let Ok(value) = Value::try_from(value) {
|
||||
let _ = raw.insert(key, value);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Ok(updated) = raw.try_into() {
|
||||
@@ -572,6 +568,7 @@ mod tests {
|
||||
description = "A completely useless book"
|
||||
multilingual = true
|
||||
src = "source"
|
||||
language = "ja"
|
||||
|
||||
[build]
|
||||
build-dir = "outputs"
|
||||
@@ -606,6 +603,7 @@ mod tests {
|
||||
description: Some(String::from("A completely useless book")),
|
||||
multilingual: true,
|
||||
src: PathBuf::from("source"),
|
||||
language: Some(String::from("ja")),
|
||||
};
|
||||
let build_should_be = BuildConfig {
|
||||
build_dir: PathBuf::from("outputs"),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::errors::*;
|
||||
use crate::utils::fs::file_to_string;
|
||||
use crate::utils::take_lines;
|
||||
use crate::utils::{take_anchored_lines, take_lines};
|
||||
use regex::{CaptureMatches, Captures, Regex};
|
||||
use std::fs;
|
||||
use std::ops::{Range, RangeFrom, RangeFull, RangeTo};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
@@ -63,13 +63,13 @@ where
|
||||
let mut previous_end_index = 0;
|
||||
let mut replaced = String::new();
|
||||
|
||||
for playpen in find_links(s) {
|
||||
replaced.push_str(&s[previous_end_index..playpen.start_index]);
|
||||
for link in find_links(s) {
|
||||
replaced.push_str(&s[previous_end_index..link.start_index]);
|
||||
|
||||
match playpen.render_with_path(&path) {
|
||||
match link.render_with_path(&path) {
|
||||
Ok(new_content) => {
|
||||
if depth < MAX_LINK_NESTED_DEPTH {
|
||||
if let Some(rel_path) = playpen.link.relative_path(path) {
|
||||
if let Some(rel_path) = link.link_type.relative_path(path) {
|
||||
replaced.push_str(&replace_all(&new_content, rel_path, source, depth + 1));
|
||||
} else {
|
||||
replaced.push_str(&new_content);
|
||||
@@ -80,17 +80,17 @@ where
|
||||
source.display()
|
||||
);
|
||||
}
|
||||
previous_end_index = playpen.end_index;
|
||||
previous_end_index = link.end_index;
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Error updating \"{}\", {}", playpen.link_text, e);
|
||||
error!("Error updating \"{}\", {}", link.link_text, e);
|
||||
for cause in e.iter().skip(1) {
|
||||
warn!("Caused By: {}", cause);
|
||||
}
|
||||
|
||||
// This should make sure we include the raw `{{# ... }}` snippet
|
||||
// in the page content if there are any errors.
|
||||
previous_end_index = playpen.start_index;
|
||||
previous_end_index = link.start_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,6 +106,7 @@ enum LinkType<'a> {
|
||||
IncludeRangeFrom(PathBuf, RangeFrom<usize>),
|
||||
IncludeRangeTo(PathBuf, RangeTo<usize>),
|
||||
IncludeRangeFull(PathBuf, RangeFull),
|
||||
IncludeAnchor(PathBuf, String),
|
||||
Playpen(PathBuf, Vec<&'a str>),
|
||||
}
|
||||
|
||||
@@ -118,6 +119,7 @@ impl<'a> LinkType<'a> {
|
||||
LinkType::IncludeRangeFrom(p, _) => Some(return_relative_path(base, &p)),
|
||||
LinkType::IncludeRangeTo(p, _) => Some(return_relative_path(base, &p)),
|
||||
LinkType::IncludeRangeFull(p, _) => Some(return_relative_path(base, &p)),
|
||||
LinkType::IncludeAnchor(p, _) => Some(return_relative_path(base, &p)),
|
||||
LinkType::Playpen(p, _) => Some(return_relative_path(base, &p)),
|
||||
}
|
||||
}
|
||||
@@ -133,11 +135,21 @@ fn return_relative_path<P: AsRef<Path>>(base: P, relative: P) -> PathBuf {
|
||||
fn parse_include_path(path: &str) -> LinkType<'static> {
|
||||
let mut parts = path.split(':');
|
||||
let path = parts.next().unwrap().into();
|
||||
// subtract 1 since line numbers usually begin with 1
|
||||
let start = parts
|
||||
.next()
|
||||
.and_then(|s| s.parse::<usize>().ok())
|
||||
.map(|val| val.saturating_sub(1));
|
||||
|
||||
let next_element = parts.next();
|
||||
let start = if let Some(value) = next_element.and_then(|s| s.parse::<usize>().ok()) {
|
||||
// subtract 1 since line numbers usually begin with 1
|
||||
Some(value.saturating_sub(1))
|
||||
} else if let Some(anchor) = next_element {
|
||||
if anchor == "" {
|
||||
None
|
||||
} else {
|
||||
return LinkType::IncludeAnchor(path, String::from(anchor));
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let end = parts.next();
|
||||
let has_end = end.is_some();
|
||||
let end = end.and_then(|s| s.parse::<usize>().ok());
|
||||
@@ -169,7 +181,7 @@ fn parse_include_path(path: &str) -> LinkType<'static> {
|
||||
struct Link<'a> {
|
||||
start_index: usize,
|
||||
end_index: usize,
|
||||
link: LinkType<'a>,
|
||||
link_type: LinkType<'a>,
|
||||
link_text: &'a str,
|
||||
}
|
||||
|
||||
@@ -193,11 +205,11 @@ impl<'a> Link<'a> {
|
||||
_ => None,
|
||||
};
|
||||
|
||||
link_type.and_then(|lnk| {
|
||||
link_type.and_then(|lnk_type| {
|
||||
cap.get(0).map(|mat| Link {
|
||||
start_index: mat.start(),
|
||||
end_index: mat.end(),
|
||||
link: lnk,
|
||||
link_type: lnk_type,
|
||||
link_text: mat.as_str(),
|
||||
})
|
||||
})
|
||||
@@ -205,13 +217,13 @@ impl<'a> Link<'a> {
|
||||
|
||||
fn render_with_path<P: AsRef<Path>>(&self, base: P) -> Result<String> {
|
||||
let base = base.as_ref();
|
||||
match self.link {
|
||||
match self.link_type {
|
||||
// omit the escape char
|
||||
LinkType::Escaped => Ok((&self.link_text[1..]).to_owned()),
|
||||
LinkType::IncludeRange(ref pat, ref range) => {
|
||||
let target = base.join(pat);
|
||||
|
||||
file_to_string(&target)
|
||||
fs::read_to_string(&target)
|
||||
.map(|s| take_lines(&s, range.clone()))
|
||||
.chain_err(|| {
|
||||
format!(
|
||||
@@ -224,7 +236,7 @@ impl<'a> Link<'a> {
|
||||
LinkType::IncludeRangeFrom(ref pat, ref range) => {
|
||||
let target = base.join(pat);
|
||||
|
||||
file_to_string(&target)
|
||||
fs::read_to_string(&target)
|
||||
.map(|s| take_lines(&s, range.clone()))
|
||||
.chain_err(|| {
|
||||
format!(
|
||||
@@ -237,7 +249,7 @@ impl<'a> Link<'a> {
|
||||
LinkType::IncludeRangeTo(ref pat, ref range) => {
|
||||
let target = base.join(pat);
|
||||
|
||||
file_to_string(&target)
|
||||
fs::read_to_string(&target)
|
||||
.map(|s| take_lines(&s, *range))
|
||||
.chain_err(|| {
|
||||
format!(
|
||||
@@ -250,7 +262,7 @@ impl<'a> Link<'a> {
|
||||
LinkType::IncludeRangeFull(ref pat, _) => {
|
||||
let target = base.join(pat);
|
||||
|
||||
file_to_string(&target).chain_err(|| {
|
||||
fs::read_to_string(&target).chain_err(|| {
|
||||
format!(
|
||||
"Could not read file for link {} ({})",
|
||||
self.link_text,
|
||||
@@ -258,10 +270,23 @@ impl<'a> Link<'a> {
|
||||
)
|
||||
})
|
||||
}
|
||||
LinkType::IncludeAnchor(ref pat, ref anchor) => {
|
||||
let target = base.join(pat);
|
||||
|
||||
fs::read_to_string(&target)
|
||||
.map(|s| take_anchored_lines(&s, anchor))
|
||||
.chain_err(|| {
|
||||
format!(
|
||||
"Could not read file for link {} ({})",
|
||||
self.link_text,
|
||||
target.display(),
|
||||
)
|
||||
})
|
||||
}
|
||||
LinkType::Playpen(ref pat, ref attrs) => {
|
||||
let target = base.join(pat);
|
||||
|
||||
let contents = file_to_string(&target).chain_err(|| {
|
||||
let contents = fs::read_to_string(&target).chain_err(|| {
|
||||
format!(
|
||||
"Could not read file for link {} ({})",
|
||||
self.link_text,
|
||||
@@ -373,13 +398,13 @@ mod tests {
|
||||
Link {
|
||||
start_index: 22,
|
||||
end_index: 42,
|
||||
link: LinkType::Playpen(PathBuf::from("file.rs"), vec![]),
|
||||
link_type: LinkType::Playpen(PathBuf::from("file.rs"), vec![]),
|
||||
link_text: "{{#playpen file.rs}}",
|
||||
},
|
||||
Link {
|
||||
start_index: 47,
|
||||
end_index: 68,
|
||||
link: LinkType::Playpen(PathBuf::from("test.rs"), vec![]),
|
||||
link_type: LinkType::Playpen(PathBuf::from("test.rs"), vec![]),
|
||||
link_text: "{{#playpen test.rs }}",
|
||||
},
|
||||
]
|
||||
@@ -396,7 +421,7 @@ mod tests {
|
||||
vec![Link {
|
||||
start_index: 22,
|
||||
end_index: 48,
|
||||
link: LinkType::IncludeRange(PathBuf::from("file.rs"), 9..20),
|
||||
link_type: LinkType::IncludeRange(PathBuf::from("file.rs"), 9..20),
|
||||
link_text: "{{#include file.rs:10:20}}",
|
||||
}]
|
||||
);
|
||||
@@ -412,7 +437,7 @@ mod tests {
|
||||
vec![Link {
|
||||
start_index: 22,
|
||||
end_index: 45,
|
||||
link: LinkType::IncludeRange(PathBuf::from("file.rs"), 9..10),
|
||||
link_type: LinkType::IncludeRange(PathBuf::from("file.rs"), 9..10),
|
||||
link_text: "{{#include file.rs:10}}",
|
||||
}]
|
||||
);
|
||||
@@ -428,7 +453,7 @@ mod tests {
|
||||
vec![Link {
|
||||
start_index: 22,
|
||||
end_index: 46,
|
||||
link: LinkType::IncludeRangeFrom(PathBuf::from("file.rs"), 9..),
|
||||
link_type: LinkType::IncludeRangeFrom(PathBuf::from("file.rs"), 9..),
|
||||
link_text: "{{#include file.rs:10:}}",
|
||||
}]
|
||||
);
|
||||
@@ -444,7 +469,7 @@ mod tests {
|
||||
vec![Link {
|
||||
start_index: 22,
|
||||
end_index: 46,
|
||||
link: LinkType::IncludeRangeTo(PathBuf::from("file.rs"), ..20),
|
||||
link_type: LinkType::IncludeRangeTo(PathBuf::from("file.rs"), ..20),
|
||||
link_text: "{{#include file.rs::20}}",
|
||||
}]
|
||||
);
|
||||
@@ -460,7 +485,7 @@ mod tests {
|
||||
vec![Link {
|
||||
start_index: 22,
|
||||
end_index: 44,
|
||||
link: LinkType::IncludeRangeFull(PathBuf::from("file.rs"), ..),
|
||||
link_type: LinkType::IncludeRangeFull(PathBuf::from("file.rs"), ..),
|
||||
link_text: "{{#include file.rs::}}",
|
||||
}]
|
||||
);
|
||||
@@ -476,12 +501,31 @@ mod tests {
|
||||
vec![Link {
|
||||
start_index: 22,
|
||||
end_index: 42,
|
||||
link: LinkType::IncludeRangeFull(PathBuf::from("file.rs"), ..),
|
||||
link_type: LinkType::IncludeRangeFull(PathBuf::from("file.rs"), ..),
|
||||
link_text: "{{#include file.rs}}",
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_links_with_anchor() {
|
||||
let s = "Some random text with {{#include file.rs:anchor}}...";
|
||||
let res = find_links(s).collect::<Vec<_>>();
|
||||
println!("\nOUTPUT: {:?}\n", res);
|
||||
assert_eq!(
|
||||
res,
|
||||
vec![Link {
|
||||
start_index: 22,
|
||||
end_index: 49,
|
||||
link_type: LinkType::IncludeAnchor(
|
||||
PathBuf::from("file.rs"),
|
||||
String::from("anchor")
|
||||
),
|
||||
link_text: "{{#include file.rs:anchor}}",
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_links_escaped_link() {
|
||||
let s = "Some random text with escaped playpen \\{{#playpen file.rs editable}} ...";
|
||||
@@ -494,7 +538,7 @@ mod tests {
|
||||
vec![Link {
|
||||
start_index: 38,
|
||||
end_index: 68,
|
||||
link: LinkType::Escaped,
|
||||
link_type: LinkType::Escaped,
|
||||
link_text: "\\{{#playpen file.rs editable}}",
|
||||
}]
|
||||
);
|
||||
@@ -513,13 +557,13 @@ mod tests {
|
||||
Link {
|
||||
start_index: 38,
|
||||
end_index: 68,
|
||||
link: LinkType::Playpen(PathBuf::from("file.rs"), vec!["editable"]),
|
||||
link_type: LinkType::Playpen(PathBuf::from("file.rs"), vec!["editable"]),
|
||||
link_text: "{{#playpen file.rs editable }}",
|
||||
},
|
||||
Link {
|
||||
start_index: 89,
|
||||
end_index: 136,
|
||||
link: LinkType::Playpen(
|
||||
link_type: LinkType::Playpen(
|
||||
PathBuf::from("my.rs"),
|
||||
vec!["editable", "no_run", "should_panic"],
|
||||
),
|
||||
@@ -543,7 +587,7 @@ mod tests {
|
||||
Link {
|
||||
start_index: 38,
|
||||
end_index: 58,
|
||||
link: LinkType::IncludeRangeFull(PathBuf::from("file.rs"), ..),
|
||||
link_type: LinkType::IncludeRangeFull(PathBuf::from("file.rs"), ..),
|
||||
link_text: "{{#include file.rs}}",
|
||||
}
|
||||
);
|
||||
@@ -552,7 +596,7 @@ mod tests {
|
||||
Link {
|
||||
start_index: 63,
|
||||
end_index: 112,
|
||||
link: LinkType::Escaped,
|
||||
link_type: LinkType::Escaped,
|
||||
link_text: "\\{{#contents are insignifficant in escaped link}}",
|
||||
}
|
||||
);
|
||||
@@ -561,7 +605,7 @@ mod tests {
|
||||
Link {
|
||||
start_index: 130,
|
||||
end_index: 177,
|
||||
link: LinkType::Playpen(
|
||||
link_type: LinkType::Playpen(
|
||||
PathBuf::from("my.rs"),
|
||||
vec!["editable", "no_run", "should_panic"]
|
||||
),
|
||||
|
||||
@@ -33,12 +33,10 @@ impl HtmlHandlebars {
|
||||
let content = ch.content.clone();
|
||||
let content = utils::render_markdown(&content, ctx.html_config.curly_quotes);
|
||||
|
||||
let string_path = ch.path.parent().unwrap().display().to_string();
|
||||
|
||||
let fixed_content = utils::render_markdown_with_base(
|
||||
let fixed_content = utils::render_markdown_with_path(
|
||||
&ch.content,
|
||||
ctx.html_config.curly_quotes,
|
||||
&string_path,
|
||||
Some(&ch.path),
|
||||
);
|
||||
print_content.push_str(&fixed_content);
|
||||
|
||||
@@ -381,7 +379,10 @@ fn make_data(
|
||||
let html = config.html_config().unwrap_or_default();
|
||||
|
||||
let mut data = serde_json::Map::new();
|
||||
data.insert("language".to_owned(), json!("en"));
|
||||
data.insert(
|
||||
"language".to_owned(),
|
||||
json!(config.book.language.clone().unwrap_or_default()),
|
||||
);
|
||||
data.insert(
|
||||
"book_title".to_owned(),
|
||||
json!(config.book.title.clone().unwrap_or_default()),
|
||||
|
||||
@@ -51,13 +51,14 @@ fn find_chapter(
|
||||
) -> Result<Option<StringMap>, RenderError> {
|
||||
debug!("Get data from context");
|
||||
|
||||
let chapters = rc.evaluate_absolute(ctx, "chapters", true).and_then(|c| {
|
||||
serde_json::value::from_value::<Vec<StringMap>>(c.clone())
|
||||
let chapters = rc.evaluate(ctx, "@root/chapters").and_then(|c| {
|
||||
serde_json::value::from_value::<Vec<StringMap>>(c.as_json().clone())
|
||||
.map_err(|_| RenderError::new("Could not decode the JSON data"))
|
||||
})?;
|
||||
|
||||
let base_path = rc
|
||||
.evaluate_absolute(ctx, "path", true)?
|
||||
.evaluate(ctx, "@root/path")?
|
||||
.as_json()
|
||||
.as_str()
|
||||
.ok_or_else(|| RenderError::new("Type error for `path`, string expected"))?
|
||||
.replace("\"", "");
|
||||
@@ -96,7 +97,8 @@ fn render(
|
||||
|
||||
let mut context = BTreeMap::new();
|
||||
let base_path = rc
|
||||
.evaluate_absolute(ctx, "path", false)?
|
||||
.evaluate(ctx, "@root/path")?
|
||||
.as_json()
|
||||
.as_str()
|
||||
.ok_or_else(|| RenderError::new("Type error for `path`, string expected"))?
|
||||
.replace("\"", "");
|
||||
|
||||
@@ -13,13 +13,14 @@ pub fn theme_option(
|
||||
RenderError::new("Param 0 with String type is required for theme_option helper.")
|
||||
})?;
|
||||
|
||||
let theme_name = rc
|
||||
.evaluate_absolute(ctx, "default_theme", true)?
|
||||
let default_theme = rc.evaluate(ctx, "@root/default_theme")?;
|
||||
let default_theme_name = default_theme
|
||||
.as_json()
|
||||
.as_str()
|
||||
.ok_or_else(|| RenderError::new("Type error for `default_theme`, string expected"))?;
|
||||
|
||||
out.write(param)?;
|
||||
if param.to_lowercase() == theme_name.to_lowercase() {
|
||||
if param.to_lowercase() == default_theme_name.to_lowercase() {
|
||||
out.write(" (default)")?;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,12 +24,13 @@ impl HelperDef for RenderToc {
|
||||
// get value from context data
|
||||
// rc.get_path() is current json parent path, you should always use it like this
|
||||
// param is the key of value you want to display
|
||||
let chapters = rc.evaluate_absolute(ctx, "chapters", true).and_then(|c| {
|
||||
serde_json::value::from_value::<Vec<BTreeMap<String, String>>>(c.clone())
|
||||
let chapters = rc.evaluate(ctx, "@root/chapters").and_then(|c| {
|
||||
serde_json::value::from_value::<Vec<BTreeMap<String, String>>>(c.as_json().clone())
|
||||
.map_err(|_| RenderError::new("Could not decode the JSON data"))
|
||||
})?;
|
||||
let current = rc
|
||||
.evaluate_absolute(ctx, "path", true)?
|
||||
.evaluate(ctx, "@root/path")?
|
||||
.as_json()
|
||||
.as_str()
|
||||
.ok_or_else(|| RenderError::new("Type error for `path`, string expected"))?
|
||||
.replace("\"", "");
|
||||
|
||||
@@ -1,22 +1,9 @@
|
||||
use crate::errors::*;
|
||||
use std::convert::Into;
|
||||
use std::fs::{self, File};
|
||||
use std::io::{Read, Write};
|
||||
use std::io::Write;
|
||||
use std::path::{Component, Path, PathBuf};
|
||||
|
||||
/// Takes a path to a file and try to read the file into a String
|
||||
pub fn file_to_string<P: AsRef<Path>>(path: P) -> Result<String> {
|
||||
let path = path.as_ref();
|
||||
|
||||
let mut content = String::new();
|
||||
File::open(path)
|
||||
.chain_err(|| "Unable to open the file")?
|
||||
.read_to_string(&mut content)
|
||||
.chain_err(|| "Unable to read the file")?;
|
||||
|
||||
Ok(content)
|
||||
}
|
||||
|
||||
/// Naively replaces any path seperator with a forward-slash '/'
|
||||
pub fn normalize_path(path: &str) -> String {
|
||||
use std::path::is_separator;
|
||||
|
||||
@@ -8,8 +8,10 @@ use regex::Regex;
|
||||
use pulldown_cmark::{html, CowStr, Event, Options, Parser, Tag};
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::Write;
|
||||
use std::path::Path;
|
||||
|
||||
pub use self::string::{take_lines, RangeArgument};
|
||||
pub use self::string::{take_anchored_lines, take_lines};
|
||||
|
||||
/// Replaces multiple consecutive whitespace characters with a single space character.
|
||||
pub fn collapse_whitespace(text: &str) -> Cow<'_, str> {
|
||||
@@ -65,20 +67,47 @@ pub fn id_from_content(content: &str) -> String {
|
||||
normalize_id(trimmed)
|
||||
}
|
||||
|
||||
fn adjust_links<'a>(event: Event<'a>, with_base: &str) -> Event<'a> {
|
||||
/// Fix links to the correct location.
|
||||
///
|
||||
/// This adjusts links, such as turning `.md` extensions to `.html`.
|
||||
///
|
||||
/// `path` is the path to the page being rendered relative to the root of the
|
||||
/// book. This is used for the `print.html` page so that links on the print
|
||||
/// page go to the original location. Normal page rendering sets `path` to
|
||||
/// None. Ideally, print page links would link to anchors on the print page,
|
||||
/// but that is very difficult.
|
||||
fn adjust_links<'a>(event: Event<'a>, path: Option<&Path>) -> Event<'a> {
|
||||
lazy_static! {
|
||||
static ref SCHEME_LINK: Regex = Regex::new(r"^[a-z][a-z0-9+.-]*:").unwrap();
|
||||
static ref MD_LINK: Regex = Regex::new(r"(?P<link>.*)\.md(?P<anchor>#.*)?").unwrap();
|
||||
}
|
||||
|
||||
fn fix<'a>(dest: CowStr<'a>, base: &str) -> CowStr<'a> {
|
||||
fn fix<'a>(dest: CowStr<'a>, path: Option<&Path>) -> CowStr<'a> {
|
||||
if dest.starts_with('#') {
|
||||
// Fragment-only link.
|
||||
if let Some(path) = path {
|
||||
let mut base = path.display().to_string();
|
||||
if base.ends_with(".md") {
|
||||
base.replace_range(base.len() - 3.., ".html");
|
||||
}
|
||||
return format!("{}{}", base, dest).into();
|
||||
} else {
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
// Don't modify links with schemes like `https`.
|
||||
if !SCHEME_LINK.is_match(&dest) {
|
||||
// This is a relative link, adjust it as necessary.
|
||||
let mut fixed_link = String::new();
|
||||
if !base.is_empty() {
|
||||
fixed_link.push_str(base);
|
||||
fixed_link.push_str("/");
|
||||
if let Some(path) = path {
|
||||
let base = path
|
||||
.parent()
|
||||
.expect("path can't be empty")
|
||||
.to_str()
|
||||
.expect("utf-8 paths only");
|
||||
if !base.is_empty() {
|
||||
write!(fixed_link, "{}/", base).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(caps) = MD_LINK.captures(&dest) {
|
||||
@@ -95,20 +124,45 @@ fn adjust_links<'a>(event: Event<'a>, with_base: &str) -> Event<'a> {
|
||||
dest
|
||||
}
|
||||
|
||||
fn fix_html<'a>(html: CowStr<'a>, path: Option<&Path>) -> CowStr<'a> {
|
||||
// This is a terrible hack, but should be reasonably reliable. Nobody
|
||||
// should ever parse a tag with a regex. However, there isn't anything
|
||||
// in Rust that I know of that is suitable for handling partial html
|
||||
// fragments like those generated by pulldown_cmark.
|
||||
//
|
||||
// There are dozens of HTML tags/attributes that contain paths, so
|
||||
// feel free to add more tags if desired; these are the only ones I
|
||||
// care about right now.
|
||||
lazy_static! {
|
||||
static ref HTML_LINK: Regex =
|
||||
Regex::new(r#"(<(?:a|img) [^>]*?(?:src|href)=")([^"]+?)""#).unwrap();
|
||||
}
|
||||
|
||||
HTML_LINK
|
||||
.replace_all(&html, |caps: ®ex::Captures<'_>| {
|
||||
let fixed = fix(caps[2].into(), path);
|
||||
format!("{}{}\"", &caps[1], fixed)
|
||||
})
|
||||
.into_owned()
|
||||
.into()
|
||||
}
|
||||
|
||||
match event {
|
||||
Event::Start(Tag::Link(link_type, dest, title)) => {
|
||||
Event::Start(Tag::Link(link_type, fix(dest, with_base), title))
|
||||
Event::Start(Tag::Link(link_type, fix(dest, path), title))
|
||||
}
|
||||
Event::Start(Tag::Image(link_type, dest, title)) => {
|
||||
Event::Start(Tag::Image(link_type, fix(dest, with_base), title))
|
||||
Event::Start(Tag::Image(link_type, fix(dest, path), title))
|
||||
}
|
||||
Event::Html(html) => Event::Html(fix_html(html, path)),
|
||||
Event::InlineHtml(html) => Event::InlineHtml(fix_html(html, path)),
|
||||
_ => event,
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper around the pulldown-cmark parser for rendering markdown to HTML.
|
||||
pub fn render_markdown(text: &str, curly_quotes: bool) -> String {
|
||||
render_markdown_with_base(text, curly_quotes, "")
|
||||
render_markdown_with_path(text, curly_quotes, None)
|
||||
}
|
||||
|
||||
pub fn new_cmark_parser(text: &str) -> Parser<'_> {
|
||||
@@ -120,13 +174,13 @@ pub fn new_cmark_parser(text: &str) -> Parser<'_> {
|
||||
Parser::new_ext(text, opts)
|
||||
}
|
||||
|
||||
pub fn render_markdown_with_base(text: &str, curly_quotes: bool, base: &str) -> String {
|
||||
pub fn render_markdown_with_path(text: &str, curly_quotes: bool, path: Option<&Path>) -> String {
|
||||
let mut s = String::with_capacity(text.len() * 3 / 2);
|
||||
let p = new_cmark_parser(text);
|
||||
let mut converter = EventQuoteConverter::new(curly_quotes);
|
||||
let events = p
|
||||
.map(clean_codeblock_headers)
|
||||
.map(|event| adjust_links(event, base))
|
||||
.map(|event| adjust_links(event, path))
|
||||
.map(|event| converter.convert(event));
|
||||
|
||||
html::push_html(&mut s, events);
|
||||
|
||||
@@ -1,63 +1,63 @@
|
||||
use itertools::Itertools;
|
||||
use std::ops::{Range, RangeFrom, RangeFull, RangeTo};
|
||||
|
||||
// This trait is already contained in the standard lib, however it is unstable.
|
||||
// TODO: Remove when the `collections_range` feature stabilises
|
||||
// (https://github.com/rust-lang/rust/issues/30877)
|
||||
pub trait RangeArgument<T: ?Sized> {
|
||||
fn start(&self) -> Option<&T>;
|
||||
fn end(&self) -> Option<&T>;
|
||||
}
|
||||
|
||||
impl<T: ?Sized> RangeArgument<T> for RangeFull {
|
||||
fn start(&self) -> Option<&T> {
|
||||
None
|
||||
}
|
||||
fn end(&self) -> Option<&T> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> RangeArgument<T> for RangeFrom<T> {
|
||||
fn start(&self) -> Option<&T> {
|
||||
Some(&self.start)
|
||||
}
|
||||
fn end(&self) -> Option<&T> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> RangeArgument<T> for RangeTo<T> {
|
||||
fn start(&self) -> Option<&T> {
|
||||
None
|
||||
}
|
||||
fn end(&self) -> Option<&T> {
|
||||
Some(&self.end)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> RangeArgument<T> for Range<T> {
|
||||
fn start(&self) -> Option<&T> {
|
||||
Some(&self.start)
|
||||
}
|
||||
fn end(&self) -> Option<&T> {
|
||||
Some(&self.end)
|
||||
}
|
||||
}
|
||||
use regex::Regex;
|
||||
use std::ops::Bound::{Excluded, Included, Unbounded};
|
||||
use std::ops::RangeBounds;
|
||||
|
||||
/// Take a range of lines from a string.
|
||||
pub fn take_lines<R: RangeArgument<usize>>(s: &str, range: R) -> String {
|
||||
let start = *range.start().unwrap_or(&0);
|
||||
pub fn take_lines<R: RangeBounds<usize>>(s: &str, range: R) -> String {
|
||||
let start = match range.start_bound() {
|
||||
Excluded(&n) => n + 1,
|
||||
Included(&n) => n,
|
||||
Unbounded => 0,
|
||||
};
|
||||
let mut lines = s.lines().skip(start);
|
||||
match range.end() {
|
||||
Some(&end) => lines.take(end.saturating_sub(start)).join("\n"),
|
||||
None => lines.join("\n"),
|
||||
match range.end_bound() {
|
||||
Excluded(end) => lines.take(end.saturating_sub(start)).join("\n"),
|
||||
Included(end) => lines.take((end + 1).saturating_sub(start)).join("\n"),
|
||||
Unbounded => lines.join("\n"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Take anchored lines from a string.
|
||||
/// Lines containing anchor are ignored.
|
||||
pub fn take_anchored_lines(s: &str, anchor: &str) -> String {
|
||||
lazy_static! {
|
||||
static ref RE_START: Regex = Regex::new(r"ANCHOR:\s*(?P<anchor_name>[\w_-]+)").unwrap();
|
||||
static ref RE_END: Regex = Regex::new(r"ANCHOR_END:\s*(?P<anchor_name>[\w_-]+)").unwrap();
|
||||
}
|
||||
|
||||
let mut retained = Vec::<&str>::new();
|
||||
let mut anchor_found = false;
|
||||
|
||||
for l in s.lines() {
|
||||
if anchor_found {
|
||||
match RE_END.captures(l) {
|
||||
Some(cap) => {
|
||||
if &cap["anchor_name"] == anchor {
|
||||
break;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if !RE_START.is_match(l) {
|
||||
retained.push(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let Some(cap) = RE_START.captures(l) {
|
||||
if &cap["anchor_name"] == anchor {
|
||||
anchor_found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
retained.join("\n")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::take_lines;
|
||||
use super::{take_anchored_lines, take_lines};
|
||||
|
||||
#[test]
|
||||
fn take_lines_test() {
|
||||
@@ -70,4 +70,33 @@ mod tests {
|
||||
assert_eq!(take_lines(s, 4..3), "");
|
||||
assert_eq!(take_lines(s, ..100), s);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn take_anchored_lines_test() {
|
||||
let s = "Lorem\nipsum\ndolor\nsit\namet";
|
||||
assert_eq!(take_anchored_lines(s, "test"), "");
|
||||
|
||||
let s = "Lorem\nipsum\ndolor\nANCHOR_END: test\nsit\namet";
|
||||
assert_eq!(take_anchored_lines(s, "test"), "");
|
||||
|
||||
let s = "Lorem\nipsum\nANCHOR: test\ndolor\nsit\namet";
|
||||
assert_eq!(take_anchored_lines(s, "test"), "dolor\nsit\namet");
|
||||
assert_eq!(take_anchored_lines(s, "something"), "");
|
||||
|
||||
let s = "Lorem\nipsum\nANCHOR: test\ndolor\nsit\namet\nANCHOR_END: test\nlorem\nipsum";
|
||||
assert_eq!(take_anchored_lines(s, "test"), "dolor\nsit\namet");
|
||||
assert_eq!(take_anchored_lines(s, "something"), "");
|
||||
|
||||
let s = "Lorem\nANCHOR: test\nipsum\nANCHOR: test\ndolor\nsit\namet\nANCHOR_END: test\nlorem\nipsum";
|
||||
assert_eq!(take_anchored_lines(s, "test"), "ipsum\ndolor\nsit\namet");
|
||||
assert_eq!(take_anchored_lines(s, "something"), "");
|
||||
|
||||
let s = "Lorem\nANCHOR: test2\nipsum\nANCHOR: test\ndolor\nsit\namet\nANCHOR_END: test\nlorem\nANCHOR_END:test2\nipsum";
|
||||
assert_eq!(
|
||||
take_anchored_lines(s, "test2"),
|
||||
"ipsum\ndolor\nsit\namet\nlorem"
|
||||
);
|
||||
assert_eq!(take_anchored_lines(s, "test"), "dolor\nsit\namet");
|
||||
assert_eq!(take_anchored_lines(s, "something"), "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#![allow(dead_code, unused_variables, unused_imports, unused_extern_crates)]
|
||||
|
||||
use mdbook::errors::*;
|
||||
use mdbook::utils::fs::file_to_string;
|
||||
use std::fs::{self, File};
|
||||
use std::io::{Read, Write};
|
||||
use std::path::Path;
|
||||
@@ -64,7 +63,7 @@ impl DummyBook {
|
||||
}
|
||||
|
||||
fn replace_pattern_in_file(filename: &Path, from: &str, to: &str) -> Result<()> {
|
||||
let contents = file_to_string(filename)?;
|
||||
let contents = fs::read_to_string(filename)?;
|
||||
File::create(filename)?.write_all(contents.replace(from, to).as_bytes())?;
|
||||
|
||||
Ok(())
|
||||
@@ -74,7 +73,7 @@ fn replace_pattern_in_file(filename: &Path, from: &str, to: &str) -> Result<()>
|
||||
/// the list of strings asserting that the file contains all of them.
|
||||
pub fn assert_contains_strings<P: AsRef<Path>>(filename: P, strings: &[&str]) {
|
||||
let filename = filename.as_ref();
|
||||
let content = file_to_string(filename).expect("Couldn't read the file's contents");
|
||||
let content = fs::read_to_string(filename).expect("Couldn't read the file's contents");
|
||||
|
||||
for s in strings {
|
||||
assert!(
|
||||
@@ -89,7 +88,7 @@ pub fn assert_contains_strings<P: AsRef<Path>>(filename: P, strings: &[&str]) {
|
||||
|
||||
pub fn assert_doesnt_contain_strings<P: AsRef<Path>>(filename: P, strings: &[&str]) {
|
||||
let filename = filename.as_ref();
|
||||
let content = file_to_string(filename).expect("Couldn't read the file's contents");
|
||||
let content = fs::read_to_string(filename).expect("Couldn't read the file's contents");
|
||||
|
||||
for s in strings {
|
||||
assert!(
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
- [Includes](first/includes.md)
|
||||
- [Recursive](first/recursive.md)
|
||||
- [Markdown](first/markdown.md)
|
||||
- [Unicode](first/unicode.md)
|
||||
- [Second Chapter](second.md)
|
||||
- [Nested Chapter](second/nested.md)
|
||||
|
||||
|
||||
21
tests/dummy_book/src/first/unicode.md
Normal file
21
tests/dummy_book/src/first/unicode.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Unicode stress tests
|
||||
|
||||
Please be careful editing, this contains carefully crafted characters.
|
||||
|
||||
Two byte character: spatiëring
|
||||
|
||||
Combining character: spatiëring
|
||||
|
||||
Three byte character: 书こんにちは
|
||||
|
||||
Four byte character: 𐌀𐌁𐌂𐌃𐌄𐌅𐌆𐌇𐌈
|
||||
|
||||
Right-to-left: مرحبا
|
||||
|
||||
Emoticons: 🔊 😍 💜 1️⃣
|
||||
|
||||
right-to-left mark: hello באמת!
|
||||
|
||||
|
||||
Zalgo: ǫ̛̖̱̗̝͈̋͒͋̏ͥͫ̒̆ͩ̏͌̾͊͐ͪ̾̚
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
When we link to [the first section](../first/nested.md), it should work on
|
||||
both the print page and the non-print page.
|
||||
|
||||
A [fragment link](#some-section) should work.
|
||||
|
||||
Link [outside](../../std/foo/bar.html).
|
||||
|
||||

|
||||
|
||||
<a href="../first/markdown.md">HTML Link</a>
|
||||
|
||||
<img src="../images/picture.png" alt="raw html">
|
||||
|
||||
## Some section
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::dummy_book::{assert_contains_strings, assert_doesnt_contain_strings,
|
||||
|
||||
use mdbook::config::Config;
|
||||
use mdbook::errors::*;
|
||||
use mdbook::utils::fs::{file_to_string, write_file};
|
||||
use mdbook::utils::fs::write_file;
|
||||
use mdbook::MDBook;
|
||||
use select::document::Document;
|
||||
use select::predicate::{Class, Name, Predicate};
|
||||
@@ -31,6 +31,7 @@ const TOC_SECOND_LEVEL: &[&str] = &[
|
||||
"1.2. Includes",
|
||||
"1.3. Recursive",
|
||||
"1.4. Markdown",
|
||||
"1.5. Unicode",
|
||||
"2.1. Nested Chapter",
|
||||
];
|
||||
|
||||
@@ -124,6 +125,9 @@ fn check_correct_relative_links_in_print_page() {
|
||||
r##"<a href="second/../first/nested.html">the first section</a>,"##,
|
||||
r##"<a href="second/../../std/foo/bar.html">outside</a>"##,
|
||||
r##"<img src="second/../images/picture.png" alt="Some image" />"##,
|
||||
r##"<a href="second/nested.html#some-section">fragment link</a>"##,
|
||||
r##"<a href="second/../first/markdown.html">HTML Link</a>"##,
|
||||
r##"<img src="second/../images/picture.png" alt="raw html">"##,
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -220,7 +224,7 @@ fn root_index_html() -> Result<Document> {
|
||||
.chain_err(|| "Book building failed")?;
|
||||
|
||||
let index_page = temp.path().join("book").join("index.html");
|
||||
let html = file_to_string(&index_page).chain_err(|| "Unable to read index.html")?;
|
||||
let html = fs::read_to_string(&index_page).chain_err(|| "Unable to read index.html")?;
|
||||
|
||||
Ok(Document::from(html.as_str()))
|
||||
}
|
||||
@@ -468,14 +472,13 @@ fn markdown_options() {
|
||||
#[cfg(feature = "search")]
|
||||
mod search {
|
||||
use crate::dummy_book::DummyBook;
|
||||
use mdbook::utils::fs::file_to_string;
|
||||
use mdbook::MDBook;
|
||||
use std::fs::File;
|
||||
use std::fs::{self, File};
|
||||
use std::path::Path;
|
||||
|
||||
fn read_book_index(root: &Path) -> serde_json::Value {
|
||||
let index = root.join("book/searchindex.js");
|
||||
let index = file_to_string(index).unwrap();
|
||||
let index = fs::read_to_string(index).unwrap();
|
||||
let index = index.trim_start_matches("Object.assign(window.search, ");
|
||||
let index = index.trim_end_matches(");");
|
||||
serde_json::from_str(&index).unwrap()
|
||||
@@ -511,7 +514,7 @@ mod search {
|
||||
assert_eq!(docs[&some_section]["body"], "");
|
||||
assert_eq!(
|
||||
docs[&summary]["body"],
|
||||
"Dummy Book Introduction First Chapter Nested Chapter Includes Recursive Markdown Second Chapter Nested Chapter Conclusion"
|
||||
"Dummy Book Introduction First Chapter Nested Chapter Includes Recursive Markdown Unicode Second Chapter Nested Chapter Conclusion"
|
||||
);
|
||||
assert_eq!(docs[&summary]["breadcrumbs"], "First Chapter » Summary");
|
||||
assert_eq!(docs[&conclusion]["body"], "I put <HTML> in here!");
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user