Merge branch 'rust-lang:master' into draft-no-index
This commit is contained in:
commit
860a17d85a
|
@ -31,7 +31,8 @@ jobs:
|
||||||
rust: stable
|
rust: stable
|
||||||
- build: msrv
|
- build: msrv
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
rust: 1.46.0
|
# sync MSRV with docs: guide/src/guide/installation.md
|
||||||
|
rust: 1.54.0
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@master
|
||||||
- name: Install Rust
|
- name: Install Rust
|
||||||
|
@ -48,4 +49,4 @@ jobs:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@master
|
||||||
- name: Install Rust
|
- name: Install Rust
|
||||||
run: rustup update stable && rustup default stable && rustup component add rustfmt
|
run: rustup update stable && rustup default stable && rustup component add rustfmt
|
||||||
- run: cargo fmt -- --check
|
- run: cargo fmt --check
|
||||||
|
|
45
CHANGELOG.md
45
CHANGELOG.md
|
@ -1,5 +1,50 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## mdBook 0.4.17
|
||||||
|
[a5fddfa...981b79b](https://github.com/rust-lang/mdBook/compare/a5fddfa...981b79b)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed parsing of `output.html.print` configuration table.
|
||||||
|
[#1775](https://github.com/rust-lang/mdBook/pull/1775)
|
||||||
|
|
||||||
|
## mdBook 0.4.16
|
||||||
|
[68a5c09...a5fddfa](https://github.com/rust-lang/mdBook/compare/68a5c09...a5fddfa)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Added `output.html.print.page-break` config option to control whether or not
|
||||||
|
there is a page break between chapters in the print output.
|
||||||
|
[#1728](https://github.com/rust-lang/mdBook/pull/1728)
|
||||||
|
- Added `output.html.playground.runnable` config option to globally disable
|
||||||
|
the run button in code blocks.
|
||||||
|
[#1546](https://github.com/rust-lang/mdBook/pull/1546)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- The `cargo serve` live reload websocket now uses the protocol, host, and
|
||||||
|
port of the current page, allowing access through a proxy.
|
||||||
|
[#1771](https://github.com/rust-lang/mdBook/pull/1771)
|
||||||
|
- The 404 not-found page now includes the books title in the HTML title tag.
|
||||||
|
[#1693](https://github.com/rust-lang/mdBook/pull/1693)
|
||||||
|
- Migrated to clap 3.0 which which handles CLI option parsing.
|
||||||
|
[#1731](https://github.com/rust-lang/mdBook/pull/1731)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Minor fixes to the markdown parser.
|
||||||
|
[#1729](https://github.com/rust-lang/mdBook/pull/1729)
|
||||||
|
- Fixed incorrect parsing in `SUMMARY.md` when it didn't start with a title.
|
||||||
|
[#1744](https://github.com/rust-lang/mdBook/pull/1744)
|
||||||
|
- Fixed duplicate anchor IDs for links in search results.
|
||||||
|
[#1749](https://github.com/rust-lang/mdBook/pull/1749)
|
||||||
|
|
||||||
|
## mdBook 0.4.15
|
||||||
|
[5eb7d46...68a5c09](https://github.com/rust-lang/mdBook/compare/5eb7d46...68a5c09)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Major update to expand the documentation located at <https://rust-lang.github.io/mdBook/>.
|
||||||
|
[#1709](https://github.com/rust-lang/mdBook/pull/1709)
|
||||||
|
[#1710](https://github.com/rust-lang/mdBook/pull/1710)
|
||||||
|
- Updated the markdown parser with various fixes for common-mark compliance.
|
||||||
|
[#1712](https://github.com/rust-lang/mdBook/pull/1712)
|
||||||
|
|
||||||
## mdBook 0.4.14
|
## mdBook 0.4.14
|
||||||
[ffa8284...c9b6be8](https://github.com/rust-lang/mdBook/compare/ffa8284...c9b6be8)
|
[ffa8284...c9b6be8](https://github.com/rust-lang/mdBook/compare/ffa8284...c9b6be8)
|
||||||
|
|
||||||
|
|
|
@ -127,4 +127,4 @@ The following are instructions for updating [highlight.js](https://highlightjs.o
|
||||||
1. Compare the language list that it spits out to the one in [`syntax-highlighting.md`](https://github.com/camelid/mdBook/blob/master/guide/src/format/theme/syntax-highlighting.md). If any are missing, add them to the list and rebuild (and update these docs). If any are added to the common set, add them to `syntax-highlighting.md`.
|
1. Compare the language list that it spits out to the one in [`syntax-highlighting.md`](https://github.com/camelid/mdBook/blob/master/guide/src/format/theme/syntax-highlighting.md). If any are missing, add them to the list and rebuild (and update these docs). If any are added to the common set, add them to `syntax-highlighting.md`.
|
||||||
1. Copy `build/highlight.min.js` to mdbook's directory [`highlight.js`](https://github.com/rust-lang/mdBook/blob/master/src/theme/highlight.js).
|
1. Copy `build/highlight.min.js` to mdbook's directory [`highlight.js`](https://github.com/rust-lang/mdBook/blob/master/src/theme/highlight.js).
|
||||||
1. Be sure to check the highlight.js [CHANGES](https://github.com/highlightjs/highlight.js/blob/main/CHANGES.md) for any breaking changes. Breaking changes that would affect users will need to wait until the next major release.
|
1. Be sure to check the highlight.js [CHANGES](https://github.com/highlightjs/highlight.js/blob/main/CHANGES.md) for any breaking changes. Breaking changes that would affect users will need to wait until the next major release.
|
||||||
1. Build mdbook with the new file and build some books with the new version and compare the output with a variety of languages to see if anything changes. (TODO: It would be nice to have a demo file in the repo to help with this.)
|
1. Build mdbook with the new file and build some books with the new version and compare the output with a variety of languages to see if anything changes. The [test_book](https://github.com/rust-lang/mdBook/tree/master/test_book) contains a chapter with many languages to examine.
|
||||||
|
|
|
@ -185,17 +185,27 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "2.33.3"
|
version = "3.0.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
checksum = "7a30c3bf9ff12dfe5dae53f0a96e0febcd18420d1c0e7fad77796d9d5c4b5375"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term",
|
|
||||||
"atty",
|
"atty",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
|
"indexmap",
|
||||||
|
"lazy_static",
|
||||||
|
"os_str_bytes",
|
||||||
"strsim",
|
"strsim",
|
||||||
|
"termcolor",
|
||||||
"textwrap",
|
"textwrap",
|
||||||
"unicode-width",
|
]
|
||||||
"vec_map",
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_complete"
|
||||||
|
version = "3.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d044e9db8cd0f68191becdeb5246b7462e4cf0c069b19ae00d1bf3fa9889498d"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -473,15 +483,6 @@ dependencies = [
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "getopts"
|
|
||||||
version = "0.2.21"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-width",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.1.16"
|
version = "0.1.16"
|
||||||
|
@ -839,13 +840,14 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mdbook"
|
name = "mdbook"
|
||||||
version = "0.4.14"
|
version = "0.4.17"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ammonia",
|
"ammonia",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"assert_cmd",
|
"assert_cmd",
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
|
"clap_complete",
|
||||||
"elasticlunr-rs",
|
"elasticlunr-rs",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
|
@ -1062,6 +1064,15 @@ dependencies = [
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "os_str_bytes"
|
||||||
|
version = "6.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "output_vt100"
|
name = "output_vt100"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
|
@ -1267,12 +1278,11 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pulldown-cmark"
|
name = "pulldown-cmark"
|
||||||
version = "0.8.0"
|
version = "0.9.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8"
|
checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"getopts",
|
|
||||||
"memchr",
|
"memchr",
|
||||||
"unicase",
|
"unicase",
|
||||||
]
|
]
|
||||||
|
@ -1400,9 +1410,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.5.4"
|
version = "1.5.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
@ -1464,21 +1474,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "0.11.0"
|
version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
|
checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012"
|
||||||
dependencies = [
|
|
||||||
"semver-parser",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "semver-parser"
|
|
||||||
version = "0.10.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
|
|
||||||
dependencies = [
|
|
||||||
"pest",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
|
@ -1600,9 +1598,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.8.0"
|
version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strum"
|
name = "strum"
|
||||||
|
@ -1669,12 +1667,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.11.0"
|
version = "0.14.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
|
||||||
dependencies = [
|
|
||||||
"unicode-width",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
|
@ -1882,12 +1877,6 @@ version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
|
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-width"
|
|
||||||
version = "0.1.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
@ -1912,12 +1901,6 @@ version = "0.7.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vec_map"
|
|
||||||
version = "0.8.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.3"
|
version = "0.9.3"
|
||||||
|
|
11
Cargo.toml
11
Cargo.toml
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "mdbook"
|
name = "mdbook"
|
||||||
version = "0.4.14"
|
version = "0.4.17"
|
||||||
authors = [
|
authors = [
|
||||||
"Mathieu David <mathieudavid@mathieudavid.org>",
|
"Mathieu David <mathieudavid@mathieudavid.org>",
|
||||||
"Michael-F-Bryan <michaelfbryan@gmail.com>",
|
"Michael-F-Bryan <michaelfbryan@gmail.com>",
|
||||||
|
@ -18,15 +18,16 @@ description = "Creates a book from markdown files"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.28"
|
anyhow = "1.0.28"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
clap = "2.24"
|
clap = { version = "3.0", features = ["cargo"] }
|
||||||
|
clap_complete = "3.0"
|
||||||
env_logger = "0.7.1"
|
env_logger = "0.7.1"
|
||||||
handlebars = "4.0"
|
handlebars = "4.0"
|
||||||
lazy_static = "1.0"
|
lazy_static = "1.0"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
memchr = "2.0"
|
memchr = "2.0"
|
||||||
opener = "0.5"
|
opener = "0.5"
|
||||||
pulldown-cmark = "0.8.0"
|
pulldown-cmark = { version = "0.9.1", default-features = false }
|
||||||
regex = "1.0.0"
|
regex = "1.5.5"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
@ -52,7 +53,7 @@ ammonia = { version = "3", optional = true }
|
||||||
assert_cmd = "1"
|
assert_cmd = "1"
|
||||||
predicates = "2"
|
predicates = "2"
|
||||||
select = "0.5"
|
select = "0.5"
|
||||||
semver = "0.11.0"
|
semver = "1.0"
|
||||||
pretty_assertions = "0.6"
|
pretty_assertions = "0.6"
|
||||||
walkdir = "2.0"
|
walkdir = "2.0"
|
||||||
|
|
||||||
|
|
224
README.md
224
README.md
|
@ -6,233 +6,15 @@
|
||||||
|
|
||||||
mdBook is a utility to create modern online books from Markdown files.
|
mdBook is a utility to create modern online books from Markdown files.
|
||||||
|
|
||||||
|
Check out the **[User Guide]** for a list of features and installation and usage information.
|
||||||
|
The User Guide also serves as a demonstration to showcase what a book looks like.
|
||||||
|
|
||||||
## What does it look like?
|
If you are interested in contributing to the development of mdBook, check out the [Contribution Guide].
|
||||||
|
|
||||||
The [User Guide] for mdBook has been written in Markdown and is using mdBook to
|
|
||||||
generate the online book-like website you can read. The documentation uses the
|
|
||||||
latest version on GitHub and showcases the available features.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
There are multiple ways to install mdBook.
|
|
||||||
|
|
||||||
1. **Binaries**
|
|
||||||
|
|
||||||
Binaries are available for download [here][releases]. Make sure to put the
|
|
||||||
path to the binary into your `PATH`.
|
|
||||||
|
|
||||||
2. **From Crates.io**
|
|
||||||
|
|
||||||
This requires at least [Rust] 1.46 and Cargo to be installed. Once you have installed
|
|
||||||
Rust, type the following in the terminal:
|
|
||||||
|
|
||||||
```
|
|
||||||
cargo install mdbook
|
|
||||||
```
|
|
||||||
|
|
||||||
This will download and compile mdBook for you, the only thing left to do is
|
|
||||||
to add the Cargo bin directory to your `PATH`.
|
|
||||||
|
|
||||||
**Note for automatic deployment**
|
|
||||||
|
|
||||||
If you are using a script to do automatic deployments, we recommend that
|
|
||||||
you specify a semver version range for mdBook when you install it through
|
|
||||||
your script!
|
|
||||||
|
|
||||||
This will constrain the server to install the latest **non-breaking**
|
|
||||||
version of mdBook and will prevent your books from failing to build because
|
|
||||||
we released a new version.
|
|
||||||
|
|
||||||
You can also disable default features to speed up compile time.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```
|
|
||||||
cargo install mdbook --no-default-features --vers "^0.4.0"
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **From Git**
|
|
||||||
|
|
||||||
The version published to crates.io will ever so slightly be behind the
|
|
||||||
version hosted here on GitHub. If you need the latest version you can build
|
|
||||||
the git version of mdBook yourself. Cargo makes this ***super easy***!
|
|
||||||
|
|
||||||
```
|
|
||||||
cargo install --git https://github.com/rust-lang/mdBook.git mdbook
|
|
||||||
```
|
|
||||||
|
|
||||||
Again, make sure to add the Cargo bin directory to your `PATH`.
|
|
||||||
|
|
||||||
4. **For Contributions**
|
|
||||||
|
|
||||||
If you want to contribute to mdBook you will have to clone the repository on
|
|
||||||
your local machine:
|
|
||||||
|
|
||||||
```
|
|
||||||
git clone https://github.com/rust-lang/mdBook.git
|
|
||||||
```
|
|
||||||
|
|
||||||
`cd` into `mdBook/` and run
|
|
||||||
|
|
||||||
```
|
|
||||||
cargo build
|
|
||||||
```
|
|
||||||
|
|
||||||
The resulting binary can be found in `mdBook/target/debug/` under the name
|
|
||||||
`mdBook` or `mdBook.exe`.
|
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
mdBook is primarily used as a command line tool, even though it exposes
|
|
||||||
all its functionality as a Rust crate for integration in other projects.
|
|
||||||
|
|
||||||
Here are the main commands you will want to run. For a more exhaustive
|
|
||||||
explanation, check out the [User Guide].
|
|
||||||
|
|
||||||
- `mdbook init <directory>`
|
|
||||||
|
|
||||||
The init command will create a directory with the minimal boilerplate to
|
|
||||||
start with. If the `<directory>` parameter is omitted, the current
|
|
||||||
directory will be used.
|
|
||||||
|
|
||||||
```
|
|
||||||
book-test/
|
|
||||||
├── book
|
|
||||||
└── src
|
|
||||||
├── chapter_1.md
|
|
||||||
└── SUMMARY.md
|
|
||||||
```
|
|
||||||
|
|
||||||
`book` and `src` are both directories. `src` contains the markdown files
|
|
||||||
that will be used to render the output to the `book` directory.
|
|
||||||
|
|
||||||
Please, take a look at the [CLI docs] for more information and some neat tricks.
|
|
||||||
|
|
||||||
- `mdbook build`
|
|
||||||
|
|
||||||
This is the command you will run to render your book, it reads the
|
|
||||||
`SUMMARY.md` file to understand the structure of your book, takes the
|
|
||||||
markdown files in the source directory as input and outputs static html
|
|
||||||
pages that you can upload to a server.
|
|
||||||
|
|
||||||
- `mdbook watch`
|
|
||||||
|
|
||||||
When you run this command, mdbook will watch your markdown files to rebuild
|
|
||||||
the book on every change. This avoids having to come back to the terminal
|
|
||||||
to type `mdbook build` over and over again.
|
|
||||||
|
|
||||||
- `mdbook serve`
|
|
||||||
|
|
||||||
Does the same thing as `mdbook watch` but additionally serves the book at
|
|
||||||
`http://localhost:3000` (port is changeable) and reloads the browser when a
|
|
||||||
change occurs.
|
|
||||||
|
|
||||||
- `mdbook clean`
|
|
||||||
|
|
||||||
Delete directory in which generated book is located.
|
|
||||||
|
|
||||||
### 3rd Party Plugins
|
|
||||||
|
|
||||||
The way a book is loaded and rendered can be configured by the user via third
|
|
||||||
party plugins. These plugins are just programs which will be invoked during the
|
|
||||||
build process and are split into roughly two categories, *preprocessors* and
|
|
||||||
*renderers*.
|
|
||||||
|
|
||||||
Preprocessors are used to transform a book before it is sent to a renderer.
|
|
||||||
One example would be to replace all occurrences of
|
|
||||||
`{{#include some_file.ext}}` with the contents of that file. Some existing
|
|
||||||
preprocessors are:
|
|
||||||
|
|
||||||
- `index` - a built-in preprocessor (enabled by default) which will transform
|
|
||||||
all `README.md` chapters to `index.md` so `foo/README.md` can be accessed via
|
|
||||||
the url `foo/` when published to a browser
|
|
||||||
- `links` - a built-in preprocessor (enabled by default) for expanding the
|
|
||||||
`{{# playground}}` and `{{# include}}` helpers in a chapter.
|
|
||||||
- [`katex`](https://github.com/lzanini/mdbook-katex) - a preprocessor rendering LaTex equations to HTML.
|
|
||||||
|
|
||||||
Renderers are given the final book so they can do something with it. This is
|
|
||||||
typically used for, as the name suggests, rendering the document in a particular
|
|
||||||
format, however there's nothing stopping a renderer from doing static analysis
|
|
||||||
of a book in order to validate links or run tests. Some existing renderers are:
|
|
||||||
|
|
||||||
- `html` - the built-in renderer which will generate a HTML version of the book
|
|
||||||
- `markdown` - the built-in renderer (disabled by default) which will run
|
|
||||||
preprocessors then output the resulting Markdown. Useful for debugging
|
|
||||||
preprocessors.
|
|
||||||
- [`linkcheck`] - a backend which will check that all links are valid
|
|
||||||
- [`epub`] - an experimental EPUB generator
|
|
||||||
- [`man`] - a backend that generates manual pages from the book
|
|
||||||
|
|
||||||
> **Note for Developers:** Feel free to send us a PR if you've developed your
|
|
||||||
> own plugin and want it mentioned here.
|
|
||||||
|
|
||||||
A preprocessor or renderer is enabled by installing the appropriate program and
|
|
||||||
then mentioning it in the book's `book.toml` file.
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ cargo install mdbook-linkcheck
|
|
||||||
$ edit book.toml && cat book.toml
|
|
||||||
[book]
|
|
||||||
title = "My Awesome Book"
|
|
||||||
authors = ["Michael-F-Bryan"]
|
|
||||||
|
|
||||||
[output.html]
|
|
||||||
|
|
||||||
[output.linkcheck] # enable the "mdbook-linkcheck" renderer
|
|
||||||
|
|
||||||
$ mdbook build
|
|
||||||
2018-10-20 13:57:51 [INFO] (mdbook::book): Book building has started
|
|
||||||
2018-10-20 13:57:51 [INFO] (mdbook::book): Running the html backend
|
|
||||||
2018-10-20 13:57:53 [INFO] (mdbook::book): Running the linkcheck backend
|
|
||||||
```
|
|
||||||
|
|
||||||
For more information on the plugin system, consult the [User Guide].
|
|
||||||
|
|
||||||
### As a library
|
|
||||||
|
|
||||||
Aside from the command line interface, this crate can also be used as a
|
|
||||||
library. This means that you could integrate it in an existing project, like a
|
|
||||||
web-app for example. Since the command line interface is just a wrapper around
|
|
||||||
the library functionality, when you use this crate as a library you have full
|
|
||||||
access to all the functionality of the command line interface with an easy to
|
|
||||||
use API and more!
|
|
||||||
|
|
||||||
See the [User Guide] and the [API docs] for more information.
|
|
||||||
|
|
||||||
## Contributions
|
|
||||||
|
|
||||||
Contributions are highly appreciated and encouraged! Don't hesitate to
|
|
||||||
participate to discussions in the issues, propose new features and ask for
|
|
||||||
help.
|
|
||||||
|
|
||||||
If you are just starting out with Rust, there are a series of issues that are
|
|
||||||
tagged [E-Easy] and **we will gladly mentor you** so that you can successfully
|
|
||||||
go through the process of fixing a bug or adding a new feature! Let us know if
|
|
||||||
you need any help.
|
|
||||||
|
|
||||||
For more info about contributing, check out our [contribution guide] which helps
|
|
||||||
you go through the build and contribution process!
|
|
||||||
|
|
||||||
There is also a [rendered version][master-docs] of the latest API docs
|
|
||||||
available, for those hacking on `master`.
|
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
All the code in this repository is released under the ***Mozilla Public License v2.0***, for more information take a look at the [LICENSE] file.
|
All the code in this repository is released under the ***Mozilla Public License v2.0***, for more information take a look at the [LICENSE] file.
|
||||||
|
|
||||||
|
|
||||||
[User Guide]: https://rust-lang.github.io/mdBook/
|
[User Guide]: https://rust-lang.github.io/mdBook/
|
||||||
[API docs]: https://docs.rs/mdbook/*/mdbook/
|
|
||||||
[E-Easy]: https://github.com/rust-lang/mdBook/issues?q=is%3Aopen+is%3Aissue+label%3AE-Easy
|
|
||||||
[contribution guide]: https://github.com/rust-lang/mdBook/blob/master/CONTRIBUTING.md
|
[contribution guide]: https://github.com/rust-lang/mdBook/blob/master/CONTRIBUTING.md
|
||||||
[LICENSE]: https://github.com/rust-lang/mdBook/blob/master/LICENSE
|
[LICENSE]: https://github.com/rust-lang/mdBook/blob/master/LICENSE
|
||||||
[releases]: https://github.com/rust-lang/mdBook/releases
|
|
||||||
[Rust]: https://www.rust-lang.org/
|
|
||||||
[CLI docs]: http://rust-lang.github.io/mdBook/cli/init.html
|
|
||||||
[master-docs]: http://rust-lang.github.io/mdBook/
|
|
||||||
[`linkcheck`]: https://crates.io/crates/mdbook-linkcheck
|
|
||||||
[`epub`]: https://crates.io/crates/mdbook-epub
|
|
||||||
[`man`]: https://crates.io/crates/mdbook-man
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::nop_lib::Nop;
|
use crate::nop_lib::Nop;
|
||||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
use clap::{App, Arg, ArgMatches};
|
||||||
use mdbook::book::Book;
|
use mdbook::book::Book;
|
||||||
use mdbook::errors::Error;
|
use mdbook::errors::Error;
|
||||||
use mdbook::preprocess::{CmdPreprocessor, Preprocessor, PreprocessorContext};
|
use mdbook::preprocess::{CmdPreprocessor, Preprocessor, PreprocessorContext};
|
||||||
|
@ -7,12 +7,12 @@ use semver::{Version, VersionReq};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
pub fn make_app() -> App<'static, 'static> {
|
pub fn make_app() -> App<'static> {
|
||||||
App::new("nop-preprocessor")
|
App::new("nop-preprocessor")
|
||||||
.about("A mdbook preprocessor which does precisely nothing")
|
.about("A mdbook preprocessor which does precisely nothing")
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("supports")
|
App::new("supports")
|
||||||
.arg(Arg::with_name("renderer").required(true))
|
.arg(Arg::new("renderer").required(true))
|
||||||
.about("Check whether a renderer is supported by this preprocessor"),
|
.about("Check whether a renderer is supported by this preprocessor"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,30 @@
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
**mdBook** is a command line tool and Rust crate to create books with Markdown. The output resembles tools like Gitbook,
|
**mdBook** is a command line tool to create books with Markdown.
|
||||||
and is ideal for creating product or API documentation, tutorials, course materials or anything that requires a clean,
|
It is ideal for creating product or API documentation, tutorials, course materials or anything that requires a clean,
|
||||||
easily navigable and customizable presentation. mdBook is written in [Rust](https://www.rust-lang.org); its performance
|
easily navigable and customizable presentation.
|
||||||
and simplicity made it ideal for use as a tool to publish directly to hosted websites such
|
|
||||||
as [GitHub Pages](https://pages.github.com) via automation. This guide, in fact, serves as both the mdBook documentation
|
|
||||||
and a fine example of what mdBook produces.
|
|
||||||
|
|
||||||
mdBook includes built in support for both preprocessing your Markdown and alternative renderers for producing formats
|
* Lightweight [Markdown] syntax helps you focus more on your content
|
||||||
other than HTML. These facilities also enable other functionality such as
|
* Integrated [search] support
|
||||||
validation. [Searching](https://crates.io/search?q=mdbook&sort=relevance) Rust's [crates.io](https://crates.io) is a
|
* Color [syntax highlighting] for code blocks for many different languages
|
||||||
great way to discover more extensions.
|
* [Theme] files allow customizing the formatting of the output
|
||||||
|
* [Preprocessors] can provide extensions for custom syntax and modifying content
|
||||||
|
* [Backends] can render the output to multiple formats
|
||||||
|
* Written in [Rust] for speed, safety, and simplicity
|
||||||
|
* Automated testing of [Rust code samples]
|
||||||
|
|
||||||
## API Documentation
|
This guide is an example of what mdBook produces.
|
||||||
|
mdBook is used by the Rust programming language project, and [The Rust Programming Language][trpl] book is another fine example of mdBook in action.
|
||||||
|
|
||||||
In addition to the above features, mdBook also has a Rust [API](https://docs.rs/mdbook/*/mdbook/). This allows you to
|
[Markdown]: format/markdown.md
|
||||||
write your own preprocessor or renderer, as well as incorporate mdBook features into other applications.
|
[search]: guide/reading.md#search
|
||||||
The [For Developers](for_developers) section of this guide contains more information and some examples.
|
[syntax highlighting]: format/theme/syntax-highlighting.md
|
||||||
|
[theme]: format/theme/index.html
|
||||||
|
[preprocessors]: format/configuration/preprocessors.md
|
||||||
|
[backends]: format/configuration/renderers.md
|
||||||
|
[Rust]: https://www.rust-lang.org/
|
||||||
|
[trpl]: https://doc.rust-lang.org/book/
|
||||||
|
[Rust code samples]: cli/test.md
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,15 @@
|
||||||
# Summary
|
# Summary
|
||||||
|
|
||||||
- [Introduction](README.md)
|
[Introduction](README.md)
|
||||||
|
|
||||||
|
# User Guide
|
||||||
|
|
||||||
|
- [Installation](guide/installation.md)
|
||||||
|
- [Reading Books](guide/reading.md)
|
||||||
|
- [Creating a Book](guide/creating.md)
|
||||||
|
|
||||||
|
# Reference Guide
|
||||||
|
|
||||||
- [Command Line Tool](cli/README.md)
|
- [Command Line Tool](cli/README.md)
|
||||||
- [init](cli/init.md)
|
- [init](cli/init.md)
|
||||||
- [build](cli/build.md)
|
- [build](cli/build.md)
|
||||||
|
@ -8,6 +17,7 @@
|
||||||
- [serve](cli/serve.md)
|
- [serve](cli/serve.md)
|
||||||
- [test](cli/test.md)
|
- [test](cli/test.md)
|
||||||
- [clean](cli/clean.md)
|
- [clean](cli/clean.md)
|
||||||
|
- [completions](cli/completions.md)
|
||||||
- [Format](format/README.md)
|
- [Format](format/README.md)
|
||||||
- [SUMMARY.md](format/summary.md)
|
- [SUMMARY.md](format/summary.md)
|
||||||
- [Draft chapter]()
|
- [Draft chapter]()
|
||||||
|
|
|
@ -1,55 +1,14 @@
|
||||||
# Command Line Tool
|
# Command Line Tool
|
||||||
|
|
||||||
mdBook can be used either as a command line tool or a [Rust
|
The `mdbook` command-line tool is used to create and build books.
|
||||||
crate](https://crates.io/crates/mdbook). Let's focus on the command line tool
|
After you have [installed](../guide/installation.md) `mdbook`, you can run the `mdbook help` command in your terminal to view the available commands.
|
||||||
capabilities first.
|
|
||||||
|
|
||||||
## Install From Binaries
|
This following sections provide in-depth information on the different commands available.
|
||||||
|
|
||||||
Precompiled binaries are provided for major platforms on a best-effort basis.
|
* [`mdbook init <directory>`](init.md) — Creates a new book with minimal boilerplate to start with.
|
||||||
Visit [the releases page](https://github.com/rust-lang/mdBook/releases)
|
* [`mdbook build`](build.md) — Renders the book.
|
||||||
to download the appropriate version for your platform.
|
* [`mdbook watch`](watch.md) — Rebuilds the book any time a source file changes.
|
||||||
|
* [`mdbook serve`](serve.md) — Runs a web server to view the book, and rebuilds on changes.
|
||||||
## Install From Source
|
* [`mdbook test`](test.md) — Tests Rust code samples.
|
||||||
|
* [`mdbook clean`](clean.md) — Deletes the rendered output.
|
||||||
mdBook can also be installed by compiling the source code on your local machine.
|
* [`mdbook completions`](completions.md) — Support for shell auto-completion.
|
||||||
|
|
||||||
### Pre-requisite
|
|
||||||
|
|
||||||
mdBook is written in **[Rust](https://www.rust-lang.org/)** and therefore needs
|
|
||||||
to be compiled with **Cargo**. If you haven't already installed Rust, please go
|
|
||||||
ahead and [install it](https://www.rust-lang.org/tools/install) now.
|
|
||||||
|
|
||||||
### Install Crates.io version
|
|
||||||
|
|
||||||
Installing mdBook is relatively easy if you already have Rust and Cargo
|
|
||||||
installed. You just have to type this snippet in your terminal:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cargo install mdbook
|
|
||||||
```
|
|
||||||
|
|
||||||
This will fetch the source code for the latest release from
|
|
||||||
[Crates.io](https://crates.io/) and compile it. You will have to add Cargo's
|
|
||||||
`bin` directory to your `PATH`.
|
|
||||||
|
|
||||||
Run `mdbook help` in your terminal to verify if it works. Congratulations, you
|
|
||||||
have installed mdBook!
|
|
||||||
|
|
||||||
|
|
||||||
### Install Git version
|
|
||||||
|
|
||||||
The **[git version](https://github.com/rust-lang/mdBook)** contains all
|
|
||||||
the latest bug-fixes and features, that will be released in the next version on
|
|
||||||
**Crates.io**, if you can't wait until the next release. You can build the git
|
|
||||||
version yourself. Open your terminal and navigate to the directory of you
|
|
||||||
choice. We need to clone the git repository and then build it with Cargo.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone --depth=1 https://github.com/rust-lang/mdBook.git
|
|
||||||
cd mdBook
|
|
||||||
cargo build --release
|
|
||||||
```
|
|
||||||
|
|
||||||
The executable `mdbook` will be in the `./target/release` folder, this should be
|
|
||||||
added to the path.
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
# The completions command
|
||||||
|
|
||||||
|
The completions command is used to generate auto-completions for some common shells.
|
||||||
|
This means when you type `mdbook` in your shell, you can then press your shell's auto-complete key (usually the Tab key) and it may display what the valid options are, or finish partial input.
|
||||||
|
|
||||||
|
The completions first need to be installed for your shell:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mdbook completions bash > ~/.local/share/bash-completion/completions/mdbook
|
||||||
|
```
|
||||||
|
|
||||||
|
The command prints a completion script for the given shell.
|
||||||
|
Run `mdbook completions --help` for a list of supported shells.
|
||||||
|
|
||||||
|
Where to place the completions depend on which shell you are using and your operating system.
|
||||||
|
Consult your shell's documentation for more information one where to place the script.
|
|
@ -1,154 +1,121 @@
|
||||||
# Running `mdbook` in Continuous Integration
|
# Running `mdbook` in Continuous Integration
|
||||||
|
|
||||||
While the following examples use Travis CI, their principles should
|
There are a variety of services such as [GitHub Actions] or [GitLab CI/CD] which can be used to test and deploy your book automatically.
|
||||||
straightforwardly transfer to other continuous integration providers as well.
|
|
||||||
|
|
||||||
## Ensuring Your Book Builds and Tests Pass
|
The following provides some general guidelines on how to configure your service to run mdBook.
|
||||||
|
Specific recipes can be found at the [Automated Deployment] wiki page.
|
||||||
|
|
||||||
Here is a sample Travis CI `.travis.yml` configuration that ensures `mdbook
|
[GitHub Actions]: https://docs.github.com/en/actions
|
||||||
build` and `mdbook test` run successfully. The key to fast CI turnaround times
|
[GitLab CI/CD]: https://docs.gitlab.com/ee/ci/
|
||||||
is caching `mdbook` installs, so that you aren't compiling `mdbook` on every CI
|
[Automated Deployment]: https://github.com/rust-lang/mdBook/wiki/Automated-Deployment
|
||||||
run.
|
|
||||||
|
|
||||||
```yaml
|
## Installing mdBook
|
||||||
language: rust
|
|
||||||
sudo: false
|
|
||||||
|
|
||||||
cache:
|
There are several different strategies for installing mdBook.
|
||||||
- cargo
|
The particular method depends on your needs and preferences.
|
||||||
|
|
||||||
rust:
|
### Pre-compiled binaries
|
||||||
- stable
|
|
||||||
|
|
||||||
before_script:
|
Perhaps the easiest method is to use the pre-compiled binaries found on the [GitHub Releases page][releases].
|
||||||
- (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update)
|
A simple approach would be to use the popular `curl` CLI tool to download the executable:
|
||||||
- (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.3" mdbook)
|
|
||||||
- cargo install-update -a
|
|
||||||
|
|
||||||
script:
|
```sh
|
||||||
- mdbook build && mdbook test # In case of custom book path: mdbook build path/to/mybook && mdbook test path/to/mybook
|
mkdir bin
|
||||||
|
curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.17/mdbook-v0.4.17-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=bin
|
||||||
|
bin/mdbook build
|
||||||
```
|
```
|
||||||
|
|
||||||
## Deploying Your Book to GitHub Pages
|
Some considerations for this approach:
|
||||||
|
|
||||||
Following these instructions will result in your book being published to GitHub
|
* This is relatively fast, and does not necessarily require dealing with caching.
|
||||||
pages after a successful CI run on your repository's `master` branch.
|
* This does not require installing Rust.
|
||||||
|
* Specifying a specific URL means you have to manually update your script to get a new version.
|
||||||
|
This may be a benefit if you want to lock to a specific version.
|
||||||
|
However, some users prefer to automatically get a newer version when they are published.
|
||||||
|
* You are reliant on the GitHub CDN being available.
|
||||||
|
|
||||||
First, create a new GitHub "Personal Access Token" with the "public_repo"
|
[releases]: https://github.com/rust-lang/mdBook/releases
|
||||||
permissions (or "repo" for private repositories). Go to your repository's Travis
|
|
||||||
CI settings page and add an environment variable named `GITHUB_TOKEN` that is
|
|
||||||
marked secure and *not* shown in the logs.
|
|
||||||
|
|
||||||
Whilst still in your repository's settings page, navigate to Options and change the
|
### Building from source
|
||||||
Source on GitHub pages to `gh-pages`.
|
|
||||||
|
|
||||||
Then, append this snippet to your `.travis.yml` and update the path to the
|
Building from source will require having Rust installed.
|
||||||
`book` directory:
|
Some services have Rust pre-installed, but if your service does not, you will need to add a step to install it.
|
||||||
|
|
||||||
```yaml
|
After Rust is installed, `cargo install` can be used to build and install mdBook.
|
||||||
deploy:
|
We recommend using a SemVer version specifier so that you get the latest **non-breaking** version of mdBook.
|
||||||
provider: pages
|
For example:
|
||||||
skip-cleanup: true
|
|
||||||
github-token: $GITHUB_TOKEN
|
```sh
|
||||||
local-dir: book # In case of custom book path: path/to/mybook/book
|
cargo install mdbook --no-default-features --features search --vers "^0.4" --locked
|
||||||
keep-history: false
|
|
||||||
on:
|
|
||||||
branch: main
|
|
||||||
```
|
```
|
||||||
|
|
||||||
That's it!
|
This includes several recommended options:
|
||||||
|
|
||||||
Note: Travis has a new [dplv2](https://blog.travis-ci.com/2019-08-27-deployment-tooling-dpl-v2-preview-release) configuration that is currently in beta. To use this new format, update your `.travis.yml` file to:
|
* `--no-default-features` — Disables features like the HTTP server used by `mdbook serve` that is likely not needed on CI.
|
||||||
|
This will speed up the build time significantly.
|
||||||
|
* `--features search` — Disabling default features means you should then manually enable features that you want, such as the built-in [search] capability.
|
||||||
|
* `--vers "^0.4"` — This will install the most recent version of the `0.4` series.
|
||||||
|
However, versions after like `0.5.0` won't be installed, as they may break your build.
|
||||||
|
Cargo will automatically upgrade mdBook if you have an older version already installed.
|
||||||
|
* `--locked` — This will use the dependencies that were used when mdBook was released.
|
||||||
|
Without `--locked`, it will use the latest version of all dependencies, which may include some fixes since the last release, but may also (rarely) cause build problems.
|
||||||
|
|
||||||
```yaml
|
You will likely want to investigate caching options, as building mdBook can be somewhat slow.
|
||||||
language: rust
|
|
||||||
os: linux
|
|
||||||
dist: xenial
|
|
||||||
|
|
||||||
cache:
|
[search]: guide/reading.md#search
|
||||||
- cargo
|
|
||||||
|
|
||||||
rust:
|
## Running tests
|
||||||
- stable
|
|
||||||
|
|
||||||
before_script:
|
You may want to run tests using [`mdbook test`] every time you push a change or create a pull request.
|
||||||
- (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update)
|
This can be used to validate Rust code examples in the book.
|
||||||
- (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.3" mdbook)
|
|
||||||
- cargo install-update -a
|
|
||||||
|
|
||||||
script:
|
This will require having Rust installed.
|
||||||
- mdbook build && mdbook test # In case of custom book path: mdbook build path/to/mybook && mdbook test path/to/mybook
|
Some services have Rust pre-installed, but if your service does not, you will need to add a step to install it.
|
||||||
|
|
||||||
deploy:
|
Other than making sure the appropriate version of Rust is installed, there's not much more than just running `mdbook test` from the book directory.
|
||||||
provider: pages
|
|
||||||
strategy: git
|
You may also want to consider running other kinds of tests, like [mdbook-linkcheck] which will check for broken links.
|
||||||
edge: true
|
Or if you have your own style checks, spell checker, or any other tests it might be good to run them in CI.
|
||||||
cleanup: false
|
|
||||||
github-token: $GITHUB_TOKEN
|
[`mdbook test`]: cli/test.md
|
||||||
local-dir: book # In case of custom book path: path/to/mybook/book
|
[mdbook-linkcheck]: https://github.com/Michael-F-Bryan/mdbook-linkcheck#continuous-integration
|
||||||
keep-history: false
|
|
||||||
on:
|
## Deploying
|
||||||
branch: main
|
|
||||||
target_branch: gh-pages
|
You may want to automatically deploy your book.
|
||||||
|
Some may want to do this with every time a change is pushed, and others may want to only deploy when a specific release is tagged.
|
||||||
|
|
||||||
|
You'll also need to understand the specifics on how to push a change to your web service.
|
||||||
|
For example, [GitHub Pages] just requires committing the output onto a specific git branch.
|
||||||
|
Other services may require using something like SSH to connect to a remote server.
|
||||||
|
|
||||||
|
The basic outline is that you need to run `mdbook build` to generate the output, and then transfer the files (which are in the `book` directory) to the correct location.
|
||||||
|
|
||||||
|
You may then want to consider if you need to invalidate any caches on your web service.
|
||||||
|
|
||||||
|
See the [Automated Deployment] wiki page for examples of various different services.
|
||||||
|
|
||||||
|
[GitHub Pages]: https://docs.github.com/en/pages
|
||||||
|
|
||||||
|
### 404 handling
|
||||||
|
|
||||||
|
mdBook automatically generates a 404 page to be used for broken links.
|
||||||
|
The default output is a file named `404.html` at the root of the book.
|
||||||
|
Some services like [GitHub Pages] will automatically use this page for broken links.
|
||||||
|
For other services, you may want to consider configuring the web server to use this page as it will provide the reader navigation to get back to the book.
|
||||||
|
|
||||||
|
If your book is not deployed at the root of the domain, then you should set the [`output.html.site-url`] setting so that the 404 page works correctly.
|
||||||
|
It needs to know where the book is deployed in order to load the static files (like CSS) correctly.
|
||||||
|
For example, this guide is deployed at <https://rust-lang.github.io/mdBook/>, and the `site-url` setting is configured like this:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# book.toml
|
||||||
|
[output.html]
|
||||||
|
site-url = "/mdBook/"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Deploying to GitHub Pages manually
|
You can customize the look of the 404 page by creating a file named `src/404.md` in your book.
|
||||||
|
If you want to use a different filename, you can set [`output.html.input-404`] to a different filename.
|
||||||
|
|
||||||
If your CI doesn't support GitHub pages, or you're deploying somewhere else
|
[`output.html.site-url`]: format/configuration/renderers.md#html-renderer-options
|
||||||
with integrations such as Github Pages:
|
[`output.html.input-404`]: format/configuration/renderers.md#html-renderer-options
|
||||||
*note: you may want to use different tmp dirs*:
|
|
||||||
|
|
||||||
```console
|
|
||||||
$> git worktree add /tmp/book gh-pages
|
|
||||||
$> mdbook build
|
|
||||||
$> rm -rf /tmp/book/* # this won't delete the .git directory
|
|
||||||
$> cp -rp book/* /tmp/book/
|
|
||||||
$> cd /tmp/book
|
|
||||||
$> git add -A
|
|
||||||
$> git commit 'new book message'
|
|
||||||
$> git push origin gh-pages
|
|
||||||
$> cd -
|
|
||||||
```
|
|
||||||
|
|
||||||
Or put this into a Makefile rule:
|
|
||||||
|
|
||||||
```makefile
|
|
||||||
.PHONY: deploy
|
|
||||||
deploy: book
|
|
||||||
@echo "====> deploying to github"
|
|
||||||
git worktree add /tmp/book gh-pages
|
|
||||||
rm -rf /tmp/book/*
|
|
||||||
cp -rp book/* /tmp/book/
|
|
||||||
cd /tmp/book && \
|
|
||||||
git add -A && \
|
|
||||||
git commit -m "deployed on $(shell date) by ${USER}" && \
|
|
||||||
git push origin gh-pages
|
|
||||||
```
|
|
||||||
|
|
||||||
## Deploying Your Book to GitLab Pages
|
|
||||||
Inside your repository's project root, create a file named `.gitlab-ci.yml` with the following contents:
|
|
||||||
```yml
|
|
||||||
stages:
|
|
||||||
- deploy
|
|
||||||
|
|
||||||
pages:
|
|
||||||
stage: deploy
|
|
||||||
image: rust
|
|
||||||
variables:
|
|
||||||
CARGO_HOME: $CI_PROJECT_DIR/cargo
|
|
||||||
before_script:
|
|
||||||
- export PATH="$PATH:$CARGO_HOME/bin"
|
|
||||||
- mdbook --version || cargo install mdbook
|
|
||||||
script:
|
|
||||||
- mdbook build -d public
|
|
||||||
rules:
|
|
||||||
- if: '$CI_COMMIT_REF_NAME == "master"'
|
|
||||||
artifacts:
|
|
||||||
paths:
|
|
||||||
- public
|
|
||||||
cache:
|
|
||||||
paths:
|
|
||||||
- $CARGO_HOME/bin
|
|
||||||
```
|
|
||||||
|
|
||||||
After you commit and push this new file, GitLab CI will run and your book will be available!
|
|
||||||
|
|
|
@ -24,8 +24,9 @@ The process of rendering a book project goes through several steps.
|
||||||
exist
|
exist
|
||||||
- Load the book chapters into memory
|
- Load the book chapters into memory
|
||||||
- Discover which preprocessors/backends should be used
|
- Discover which preprocessors/backends should be used
|
||||||
2. Run the preprocessors
|
2. For each backend:
|
||||||
3. Call each backend in turn
|
1. Run all the preprocessors.
|
||||||
|
2. Call the backend to render the processed result.
|
||||||
|
|
||||||
|
|
||||||
## Using `mdbook` as a Library
|
## Using `mdbook` as a Library
|
||||||
|
|
|
@ -5,23 +5,17 @@ rendering process. This program is passed a JSON representation of the book and
|
||||||
configuration information via `stdin`. Once the backend receives this
|
configuration information via `stdin`. Once the backend receives this
|
||||||
information it is free to do whatever it wants.
|
information it is free to do whatever it wants.
|
||||||
|
|
||||||
There are already several alternative backends on GitHub which can be used as a
|
See [Configuring Renderers](../format/configuration/renderers.md) for more information about using backends.
|
||||||
rough example of how this is accomplished in practice.
|
|
||||||
|
|
||||||
- [mdbook-linkcheck] - a simple program for verifying the book doesn't contain
|
The community has developed several backends.
|
||||||
any broken links
|
See the [Third Party Plugins] wiki page for a list of available backends.
|
||||||
- [mdbook-epub] - an EPUB renderer
|
|
||||||
- [mdbook-test] - a program to run the book's contents through [rust-skeptic] to
|
## Setting Up
|
||||||
verify everything compiles and runs correctly (similar to `rustdoc --test`)
|
|
||||||
- [mdbook-man] - generate manual pages from the book
|
|
||||||
|
|
||||||
This page will step you through creating your own alternative backend in the form
|
This page will step you through creating your own alternative backend in the form
|
||||||
of a simple word counting program. Although it will be written in Rust, there's
|
of a simple word counting program. Although it will be written in Rust, there's
|
||||||
no reason why it couldn't be accomplished using something like Python or Ruby.
|
no reason why it couldn't be accomplished using something like Python or Ruby.
|
||||||
|
|
||||||
|
|
||||||
## Setting Up
|
|
||||||
|
|
||||||
First you'll want to create a new binary program and add `mdbook` as a
|
First you'll want to create a new binary program and add `mdbook` as a
|
||||||
dependency.
|
dependency.
|
||||||
|
|
||||||
|
@ -330,39 +324,6 @@ generation or a warning).
|
||||||
All environment variables are passed through to the backend, allowing you to use
|
All environment variables are passed through to the backend, allowing you to use
|
||||||
the usual `RUST_LOG` to control logging verbosity.
|
the usual `RUST_LOG` to control logging verbosity.
|
||||||
|
|
||||||
## Handling missing backends
|
|
||||||
|
|
||||||
If you enable a backend that isn't installed, the default behavior is to throw an error:
|
|
||||||
|
|
||||||
```text
|
|
||||||
The command `mdbook-wordcount` wasn't found, is the "wordcount" backend installed?
|
|
||||||
If you want to ignore this error when the "wordcount" backend is not installed,
|
|
||||||
set `optional = true` in the `[output.wordcount]` section of the book.toml configuration file.
|
|
||||||
```
|
|
||||||
|
|
||||||
This behavior can be changed by marking the backend as optional.
|
|
||||||
|
|
||||||
```diff
|
|
||||||
[book]
|
|
||||||
title = "mdBook Documentation"
|
|
||||||
description = "Create book from markdown files. Like Gitbook but implemented in Rust"
|
|
||||||
authors = ["Mathieu David", "Michael-F-Bryan"]
|
|
||||||
|
|
||||||
[output.html]
|
|
||||||
|
|
||||||
[output.wordcount]
|
|
||||||
command = "python /path/to/wordcount.py"
|
|
||||||
+ optional = true
|
|
||||||
```
|
|
||||||
|
|
||||||
This demotes the error to a warning, and it will instead look like this:
|
|
||||||
|
|
||||||
```text
|
|
||||||
The command was not found, but was marked as optional.
|
|
||||||
Command: wordcount
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Wrapping Up
|
## Wrapping Up
|
||||||
|
|
||||||
Although contrived, hopefully this example was enough to show how you'd create
|
Although contrived, hopefully this example was enough to show how you'd create
|
||||||
|
@ -375,11 +336,7 @@ as a good example of how it's done in real life, so feel free to skim through
|
||||||
the source code or ask questions.
|
the source code or ask questions.
|
||||||
|
|
||||||
|
|
||||||
[mdbook-linkcheck]: https://github.com/Michael-F-Bryan/mdbook-linkcheck
|
[Third Party Plugins]: https://github.com/rust-lang/mdBook/wiki/Third-party-plugins
|
||||||
[mdbook-epub]: https://github.com/Michael-F-Bryan/mdbook-epub
|
|
||||||
[mdbook-test]: https://github.com/Michael-F-Bryan/mdbook-test
|
|
||||||
[mdbook-man]: https://github.com/vv9k/mdbook-man
|
|
||||||
[rust-skeptic]: https://github.com/budziq/rust-skeptic
|
|
||||||
[`RenderContext`]: https://docs.rs/mdbook/*/mdbook/renderer/struct.RenderContext.html
|
[`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
|
[`RenderContext::from_json()`]: https://docs.rs/mdbook/*/mdbook/renderer/struct.RenderContext.html#method.from_json
|
||||||
[`semver`]: https://crates.io/crates/semver
|
[`semver`]: https://crates.io/crates/semver
|
||||||
|
|
|
@ -5,35 +5,18 @@ book is loaded and before it gets rendered, allowing you to update and mutate
|
||||||
the book. Possible use cases are:
|
the book. Possible use cases are:
|
||||||
|
|
||||||
- Creating custom helpers like `\{{#include /path/to/file.md}}`
|
- Creating custom helpers like `\{{#include /path/to/file.md}}`
|
||||||
- Updating links so `[some chapter](some_chapter.md)` is automatically changed
|
|
||||||
to `[some chapter](some_chapter.html)` for the HTML renderer
|
|
||||||
- Substituting in latex-style expressions (`$$ \frac{1}{3} $$`) with their
|
- Substituting in latex-style expressions (`$$ \frac{1}{3} $$`) with their
|
||||||
mathjax equivalents
|
mathjax equivalents
|
||||||
|
|
||||||
|
See [Configuring Preprocessors](../format/configuration/preprocessors.md) for more information about using preprocessors.
|
||||||
|
|
||||||
## Hooking Into MDBook
|
## Hooking Into MDBook
|
||||||
|
|
||||||
MDBook uses a fairly simple mechanism for discovering third party plugins.
|
MDBook uses a fairly simple mechanism for discovering third party plugins.
|
||||||
A new table is added to `book.toml` (e.g. `preprocessor.foo` for the `foo`
|
A new table is added to `book.toml` (e.g. `[preprocessor.foo]` for the `foo`
|
||||||
preprocessor) and then `mdbook` will try to invoke the `mdbook-foo` program as
|
preprocessor) and then `mdbook` will try to invoke the `mdbook-foo` program as
|
||||||
part of the build process.
|
part of the build process.
|
||||||
|
|
||||||
A preprocessor can be hard-coded to specify which backend(s) it should be run
|
|
||||||
for with the `preprocessor.foo.renderer` key. For example, it doesn't make sense for
|
|
||||||
[MathJax](../format/mathjax.md) to be used for non-HTML renderers.
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[book]
|
|
||||||
title = "My Book"
|
|
||||||
authors = ["Michael-F-Bryan"]
|
|
||||||
|
|
||||||
[preprocessor.foo]
|
|
||||||
# The command can also be specified manually
|
|
||||||
command = "python3 /path/to/foo.py"
|
|
||||||
# Only run the `foo` preprocessor for the HTML and EPUB renderer
|
|
||||||
renderer = ["html", "epub"]
|
|
||||||
```
|
|
||||||
|
|
||||||
Once the preprocessor has been defined and the build process starts, mdBook executes the command defined in the `preprocessor.foo.command` key twice.
|
Once the preprocessor has been defined and the build process starts, mdBook executes the command defined in the `preprocessor.foo.command` key twice.
|
||||||
The first time it runs the preprocessor to determine if it supports the given renderer.
|
The first time it runs the preprocessor to determine if it supports the given renderer.
|
||||||
mdBook passes two arguments to the process: the first argument is the string `supports` and the second argument is the renderer name.
|
mdBook passes two arguments to the process: the first argument is the string `supports` and the second argument is the renderer name.
|
||||||
|
@ -78,7 +61,7 @@ The `chapter.content` is just a string which happens to be markdown. While it's
|
||||||
entirely possible to use regular expressions or do a manual find & replace,
|
entirely possible to use regular expressions or do a manual find & replace,
|
||||||
you'll probably want to process the input into something more computer-friendly.
|
you'll probably want to process the input into something more computer-friendly.
|
||||||
The [`pulldown-cmark`][pc] crate implements a production-quality event-based
|
The [`pulldown-cmark`][pc] crate implements a production-quality event-based
|
||||||
Markdown parser, with the [`pulldown-cmark-to-cmark`][pctc] allowing you to
|
Markdown parser, with the [`pulldown-cmark-to-cmark`][pctc] crate allowing you to
|
||||||
translate events back into markdown text.
|
translate events back into markdown text.
|
||||||
|
|
||||||
The following code block shows how to remove all emphasis from markdown,
|
The following code block shows how to remove all emphasis from markdown,
|
||||||
|
|
|
@ -62,6 +62,11 @@ language = "en"
|
||||||
Options for the Rust language, relevant to running tests and playground
|
Options for the Rust language, relevant to running tests and playground
|
||||||
integration.
|
integration.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[rust]
|
||||||
|
edition = "2015" # the default edition for code blocks
|
||||||
|
```
|
||||||
|
|
||||||
- **edition**: Rust edition to use by default for the code snippets. Default
|
- **edition**: Rust edition to use by default for the code snippets. Default
|
||||||
is "2015". Individual code blocks can be controlled with the `edition2015`,
|
is "2015". Individual code blocks can be controlled with the `edition2015`,
|
||||||
`edition2018` or `edition2021` annotations, such as:
|
`edition2018` or `edition2021` annotations, such as:
|
||||||
|
@ -77,8 +82,16 @@ integration.
|
||||||
|
|
||||||
This controls the build process of your book.
|
This controls the build process of your book.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[build]
|
||||||
|
build-dir = "book" # the directory where the output is placed
|
||||||
|
create-missing = true # whether or not to create missing pages
|
||||||
|
use-default-preprocessors = true # use the default preprocessors
|
||||||
|
```
|
||||||
|
|
||||||
- **build-dir:** The directory to put the rendered book in. By default this is
|
- **build-dir:** The directory to put the rendered book in. By default this is
|
||||||
`book/` in the book's root directory.
|
`book/` in the book's root directory.
|
||||||
|
This can overridden with the `--dest-dir` CLI option.
|
||||||
- **create-missing:** By default, any missing files specified in `SUMMARY.md`
|
- **create-missing:** By default, any missing files specified in `SUMMARY.md`
|
||||||
will be created when the book is built (i.e. `create-missing = true`). If this
|
will be created when the book is built (i.e. `create-missing = true`). If this
|
||||||
is `false` then the build process will instead exit with an error if any files
|
is `false` then the build process will instead exit with an error if any files
|
||||||
|
|
|
@ -1,51 +1,58 @@
|
||||||
# Configuring Preprocessors
|
# Configuring Preprocessors
|
||||||
|
|
||||||
The following preprocessors are available and included by default:
|
Preprocessors are extensions that can modify the raw Markdown source before it gets sent to the renderer.
|
||||||
|
|
||||||
- `links`: Expand the `{{ #playground }}`, `{{ #include }}`, and `{{ #rustdoc_include }}` handlebars
|
The following preprocessors are built-in and included by default:
|
||||||
|
|
||||||
|
- `links`: Expands the `{{ #playground }}`, `{{ #include }}`, and `{{ #rustdoc_include }}` handlebars
|
||||||
helpers in a chapter to include the contents of a file.
|
helpers in a chapter to include the contents of a file.
|
||||||
|
See [Including files] for more.
|
||||||
- `index`: Convert all chapter files named `README.md` into `index.md`. That is
|
- `index`: Convert all chapter files named `README.md` into `index.md`. That is
|
||||||
to say, all `README.md` would be rendered to an index file `index.html` in the
|
to say, all `README.md` would be rendered to an index file `index.html` in the
|
||||||
rendered book.
|
rendered book.
|
||||||
|
|
||||||
|
The built-in preprocessors can be disabled with the [`build.use-default-preprocessors`] config option.
|
||||||
|
|
||||||
**book.toml**
|
The community has developed several preprocessors.
|
||||||
```toml
|
See the [Third Party Plugins] wiki page for a list of available preprocessors.
|
||||||
[build]
|
|
||||||
build-dir = "build"
|
|
||||||
create-missing = false
|
|
||||||
|
|
||||||
[preprocessor.links]
|
For information on how to create a new preprocessor, see the [Preprocessors for Developers] chapter.
|
||||||
|
|
||||||
[preprocessor.index]
|
[Including files]: ../mdbook.md#including-files
|
||||||
```
|
[`build.use-default-preprocessors`]: general.md#build-options
|
||||||
|
[Third Party Plugins]: https://github.com/rust-lang/mdBook/wiki/Third-party-plugins
|
||||||
|
[Preprocessors for Developers]: ../../for_developers/preprocessors.md
|
||||||
|
|
||||||
### Custom Preprocessor Configuration
|
## Custom Preprocessor Configuration
|
||||||
|
|
||||||
Like renderers, preprocessor will need to be given its own table (e.g.
|
Preprocessors can be added by including a `preprocessor` table in `book.toml` with the name of the preprocessor.
|
||||||
`[preprocessor.mathjax]`). In the section, you may then pass extra
|
For example, if you have a preprocessor called `mdbook-example`, then you can include it with:
|
||||||
configuration to the preprocessor by adding key-value pairs to the table.
|
|
||||||
|
|
||||||
For example
|
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[preprocessor.links]
|
[preprocessor.example]
|
||||||
# set the renderers this preprocessor will run for
|
|
||||||
renderers = ["html"]
|
|
||||||
some_extra_feature = true
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Locking a Preprocessor dependency to a renderer
|
With this table, mdBook will execute the `mdbook-example` preprocessor.
|
||||||
|
|
||||||
|
This table can include additional key-value pairs that are specific to the preprocessor.
|
||||||
|
For example, if our example prepocessor needed some extra configuration options:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[preprocessor.example]
|
||||||
|
some-extra-feature = true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Locking a Preprocessor dependency to a renderer
|
||||||
|
|
||||||
You can explicitly specify that a preprocessor should run for a renderer by
|
You can explicitly specify that a preprocessor should run for a renderer by
|
||||||
binding the two together.
|
binding the two together.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[preprocessor.mathjax]
|
[preprocessor.example]
|
||||||
renderers = ["html"] # mathjax only makes sense with the HTML renderer
|
renderers = ["html"] # example preprocessor only runs with the HTML renderer
|
||||||
```
|
```
|
||||||
|
|
||||||
### Provide Your Own Command
|
## Provide Your Own Command
|
||||||
|
|
||||||
By default when you add a `[preprocessor.foo]` table to your `book.toml` file,
|
By default when you add a `[preprocessor.foo]` table to your `book.toml` file,
|
||||||
`mdbook` will try to invoke the `mdbook-foo` executable. If you want to use a
|
`mdbook` will try to invoke the `mdbook-foo` executable. If you want to use a
|
||||||
|
@ -57,7 +64,7 @@ be overridden by adding a `command` field.
|
||||||
command = "python random.py"
|
command = "python random.py"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Require A Certain Order
|
## Require A Certain Order
|
||||||
|
|
||||||
The order in which preprocessors are run can be controlled with the `before` and `after` fields.
|
The order in which preprocessors are run can be controlled with the `before` and `after` fields.
|
||||||
For example, suppose you want your `linenos` preprocessor to process lines that may have been `{{#include}}`d; then you want it to run after the built-in `links` preprocessor, which you can require using either the `before` or `after` field:
|
For example, suppose you want your `linenos` preprocessor to process lines that may have been `{{#include}}`d; then you want it to run after the built-in `links` preprocessor, which you can require using either the `before` or `after` field:
|
||||||
|
|
|
@ -1,9 +1,115 @@
|
||||||
# Configuring Renderers
|
# Configuring Renderers
|
||||||
|
|
||||||
### HTML renderer options
|
Renderers (also called "backends") are responsible for creating the output of the book.
|
||||||
|
|
||||||
The HTML renderer has a couple of options as well. All the options for the
|
The following backends are built-in:
|
||||||
renderer need to be specified under the TOML table `[output.html]`.
|
|
||||||
|
* [`html`](#html-renderer-options) — This renders the book to HTML.
|
||||||
|
This is enabled by default if no other `[output]` tables are defined in `book.toml`.
|
||||||
|
* [`markdown`](#markdown-renderer) — This outputs the book as markdown after running the preprocessors.
|
||||||
|
This is useful for debugging preprocessors.
|
||||||
|
|
||||||
|
The community has developed several backends.
|
||||||
|
See the [Third Party Plugins] wiki page for a list of available backends.
|
||||||
|
|
||||||
|
For information on how to create a new backend, see the [Backends for Developers] chapter.
|
||||||
|
|
||||||
|
[Third Party Plugins]: https://github.com/rust-lang/mdBook/wiki/Third-party-plugins
|
||||||
|
[Backends for Developers]: ../../for_developers/backends.md
|
||||||
|
|
||||||
|
## Output tables
|
||||||
|
|
||||||
|
Backends can be added by including a `output` table in `book.toml` with the name of the backend.
|
||||||
|
For example, if you have a backend called `mdbook-wordcount`, then you can include it with:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[output.wordcount]
|
||||||
|
```
|
||||||
|
|
||||||
|
With this table, mdBook will execute the `mdbook-wordcount` backend.
|
||||||
|
|
||||||
|
This table can include additional key-value pairs that are specific to the backend.
|
||||||
|
For example, if our example backend needed some extra configuration options:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[output.wordcount]
|
||||||
|
ignores = ["Example Chapter"]
|
||||||
|
```
|
||||||
|
|
||||||
|
If you define any `[output]` tables, then the `html` backend is not enabled by default.
|
||||||
|
If you want to keep the `html` backend running, then just include it in the `book.toml` file.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[book]
|
||||||
|
title = "My Awesome Book"
|
||||||
|
|
||||||
|
[output.wordcount]
|
||||||
|
|
||||||
|
[output.html]
|
||||||
|
```
|
||||||
|
|
||||||
|
If more than one `output` table is included, this changes the behavior for the layout of the output directory.
|
||||||
|
If there is only one backend, then it places its output directly in the `book` directory (see [`build.build-dir`] to override this location).
|
||||||
|
If there is more than one backend, then each backend is placed in a separate directory underneath `book`.
|
||||||
|
For example, the above would have directories `book/html` and `book/wordcount`.
|
||||||
|
|
||||||
|
[`build.build-dir`]: general.md#build-options
|
||||||
|
|
||||||
|
### Custom backend commands
|
||||||
|
|
||||||
|
By default when you add an `[output.foo]` table to your `book.toml` file,
|
||||||
|
`mdbook` will try to invoke the `mdbook-foo` executable.
|
||||||
|
If you want to use a different program name or pass in command-line arguments,
|
||||||
|
this behaviour can be overridden by adding a `command` field.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[output.random]
|
||||||
|
command = "python random.py"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Optional backends
|
||||||
|
|
||||||
|
If you enable a backend that isn't installed, the default behavior is to throw an error.
|
||||||
|
This behavior can be changed by marking the backend as optional:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[output.wordcount]
|
||||||
|
optional = true
|
||||||
|
```
|
||||||
|
|
||||||
|
This demotes the error to a warning.
|
||||||
|
|
||||||
|
|
||||||
|
## HTML renderer options
|
||||||
|
|
||||||
|
The HTML renderer has a variety of options detailed below.
|
||||||
|
They should be specified in the `[output.html]` table of the `book.toml` file.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# Example book.toml file with all output options.
|
||||||
|
[book]
|
||||||
|
title = "Example book"
|
||||||
|
authors = ["John Doe", "Jane Doe"]
|
||||||
|
description = "The example book covers examples."
|
||||||
|
|
||||||
|
[output.html]
|
||||||
|
theme = "my-theme"
|
||||||
|
default-theme = "light"
|
||||||
|
preferred-dark-theme = "navy"
|
||||||
|
curly-quotes = true
|
||||||
|
mathjax-support = false
|
||||||
|
copy-fonts = true
|
||||||
|
additional-css = ["custom.css", "custom2.css"]
|
||||||
|
additional-js = ["custom.js"]
|
||||||
|
no-section-label = false
|
||||||
|
git-repository-url = "https://github.com/rust-lang/mdBook"
|
||||||
|
git-repository-icon = "fa-github"
|
||||||
|
edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}"
|
||||||
|
site-url = "/example-book/"
|
||||||
|
cname = "myproject.rs"
|
||||||
|
input-404 = "not-found.md"
|
||||||
|
```
|
||||||
|
|
||||||
The following configuration options are available:
|
The following configuration options are available:
|
||||||
|
|
||||||
|
@ -30,34 +136,22 @@ The following configuration options are available:
|
||||||
- **additional-js:** If you need to add some behaviour to your book without
|
- **additional-js:** If you need to add some behaviour to your book without
|
||||||
removing the current behaviour, you can specify a set of JavaScript files that
|
removing the current behaviour, you can specify a set of JavaScript files that
|
||||||
will be loaded alongside the default one.
|
will be loaded alongside the default one.
|
||||||
- **print:** A subtable for configuration print settings. mdBook by default adds
|
- **no-section-label:** mdBook by defaults adds numeric section labels in the table of
|
||||||
support for printing out the book as a single page. This is accessed using the
|
|
||||||
print icon on the top right of the book.
|
|
||||||
- **no-section-label:** mdBook by defaults adds section label in table of
|
|
||||||
contents column. For example, "1.", "2.1". Set this option to true to disable
|
contents column. For example, "1.", "2.1". Set this option to true to disable
|
||||||
those labels. Defaults to `false`.
|
those labels. Defaults to `false`.
|
||||||
- **fold:** A subtable for configuring sidebar section-folding behavior.
|
|
||||||
- **playground:** A subtable for configuring various playground settings.
|
|
||||||
- **search:** A subtable for configuring the in-browser search functionality.
|
|
||||||
mdBook must be compiled with the `search` feature enabled (on by default).
|
|
||||||
- **git-repository-url:** A url to the git repository for the book. If provided
|
- **git-repository-url:** A url to the git repository for the book. If provided
|
||||||
an icon link will be output in the menu bar of the book.
|
an icon link will be output in the menu bar of the book.
|
||||||
- **git-repository-icon:** The FontAwesome icon class to use for the git
|
- **git-repository-icon:** The FontAwesome icon class to use for the git
|
||||||
repository link. Defaults to `fa-github`.
|
repository link. Defaults to `fa-github` which looks like <i class="fa fa-github"></i>.
|
||||||
|
If you are not using GitHub, another option to consider is `fa-code-fork` which looks like <i class="fa fa-code-fork"></i>.
|
||||||
- **edit-url-template:** Edit url template, when provided shows a
|
- **edit-url-template:** Edit url template, when provided shows a
|
||||||
"Suggest an edit" button for directly jumping to editing the currently
|
"Suggest an edit" button (which looks like <i class="fa fa-edit"></i>) for directly jumping to editing the currently
|
||||||
viewed page. For e.g. GitHub projects set this to
|
viewed page. For e.g. GitHub projects set this to
|
||||||
`https://github.com/<owner>/<repo>/edit/master/{path}` or for
|
`https://github.com/<owner>/<repo>/edit/master/{path}` or for
|
||||||
Bitbucket projects set it to
|
Bitbucket projects set it to
|
||||||
`https://bitbucket.org/<owner>/<repo>/src/master/{path}?mode=edit`
|
`https://bitbucket.org/<owner>/<repo>/src/master/{path}?mode=edit`
|
||||||
where {path} will be replaced with the full path of the file in the
|
where {path} will be replaced with the full path of the file in the
|
||||||
repository.
|
repository.
|
||||||
- **redirect:** A subtable used for generating redirects when a page is moved.
|
|
||||||
The table contains key-value pairs where the key is where the redirect file
|
|
||||||
needs to be created, as an absolute path from the build directory, (e.g.
|
|
||||||
`/appendices/bibliography.html`). The value can be any valid URI the
|
|
||||||
browser should navigate to (e.g. `https://rust-lang.org/`,
|
|
||||||
`/overview.html`, or `../bibliography.html`).
|
|
||||||
- **input-404:** The name of the markdown file used for missing files.
|
- **input-404:** The name of the markdown file used for missing files.
|
||||||
The corresponding output file will be the same, with the extension replaced with `html`.
|
The corresponding output file will be the same, with the extension replaced with `html`.
|
||||||
Defaults to `404.md`.
|
Defaults to `404.md`.
|
||||||
|
@ -71,29 +165,80 @@ The following configuration options are available:
|
||||||
|
|
||||||
[custom domain]: https://docs.github.com/en/github/working-with-github-pages/managing-a-custom-domain-for-your-github-pages-site
|
[custom domain]: https://docs.github.com/en/github/working-with-github-pages/managing-a-custom-domain-for-your-github-pages-site
|
||||||
|
|
||||||
Available configuration options for the `[output.html.print]` table:
|
### `[output.html.print]`
|
||||||
|
|
||||||
|
The `[output.html.print]` table provides options for controlling the printable output.
|
||||||
|
By default, mdBook will include an icon on the top right of the book (which looks like <i class="fa fa-print"></i>) that will print the book as a single page.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[output.html.print]
|
||||||
|
enable = true # include support for printable output
|
||||||
|
page-break = true # insert page-break after each chapter
|
||||||
|
```
|
||||||
|
|
||||||
- **enable:** Enable print support. When `false`, all print support will not be
|
- **enable:** Enable print support. When `false`, all print support will not be
|
||||||
rendered. Defaults to `true`.
|
rendered. Defaults to `true`.
|
||||||
|
- **page-break** Insert page breaks between chapters. Defaults to `true`.
|
||||||
|
|
||||||
Available configuration options for the `[output.html.fold]` table:
|
### `[output.html.fold]`
|
||||||
|
|
||||||
|
The `[output.html.fold]` table provides options for controlling folding of the chapter listing in the navigation sidebar.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[output.html.fold]
|
||||||
|
enable = false # whether or not to enable section folding
|
||||||
|
level = 0 # the depth to start folding
|
||||||
|
```
|
||||||
|
|
||||||
- **enable:** Enable section-folding. When off, all folds are open.
|
- **enable:** Enable section-folding. When off, all folds are open.
|
||||||
Defaults to `false`.
|
Defaults to `false`.
|
||||||
- **level:** The higher the more folded regions are open. When level is 0, all
|
- **level:** The higher the more folded regions are open. When level is 0, all
|
||||||
folds are closed. Defaults to `0`.
|
folds are closed. Defaults to `0`.
|
||||||
|
|
||||||
Available configuration options for the `[output.html.playground]` table:
|
### `[output.html.playground]`
|
||||||
|
|
||||||
|
The `[output.html.playground]` table provides options for controlling Rust sample code blocks, and their integration with the [Rust Playground].
|
||||||
|
|
||||||
|
[Rust Playground]: https://play.rust-lang.org/
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[output.html.playground]
|
||||||
|
editable = false # allows editing the source code
|
||||||
|
copyable = true # include the copy button for copying code snippets
|
||||||
|
copy-js = true # includes the JavaScript for the code editor
|
||||||
|
line-numbers = false # displays line numbers for editable code
|
||||||
|
runnable = true # displays a run button for rust code
|
||||||
|
```
|
||||||
|
|
||||||
- **editable:** Allow editing the source code. Defaults to `false`.
|
- **editable:** Allow editing the source code. Defaults to `false`.
|
||||||
- **copyable:** Display the copy button on code snippets. Defaults to `true`.
|
- **copyable:** Display the copy button on code snippets. Defaults to `true`.
|
||||||
- **copy-js:** Copy JavaScript files for the editor to the output directory.
|
- **copy-js:** Copy JavaScript files for the editor to the output directory.
|
||||||
Defaults to `true`.
|
Defaults to `true`.
|
||||||
- **line-numbers** Display line numbers on editable sections of code. Requires both `editable` and `copy-js` to be `true`. Defaults to `false`.
|
- **line-numbers** Display line numbers on editable sections of code. Requires both `editable` and `copy-js` to be `true`. Defaults to `false`.
|
||||||
|
- **runnable** Displays a run button for rust code snippets. Changing this to `false` will disable the run in playground feature globally. Defaults to `true`.
|
||||||
|
|
||||||
[Ace]: https://ace.c9.io/
|
[Ace]: https://ace.c9.io/
|
||||||
|
|
||||||
Available configuration options for the `[output.html.search]` table:
|
### `[output.html.search]`
|
||||||
|
|
||||||
|
The `[output.html.search]` table provides options for controlling the built-in text [search].
|
||||||
|
mdBook must be compiled with the `search` feature enabled (on by default).
|
||||||
|
|
||||||
|
[search]: ../../guide/reading.md#search
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[output.html.search]
|
||||||
|
enable = true # enables the search feature
|
||||||
|
limit-results = 30 # maximum number of search results
|
||||||
|
teaser-word-count = 30 # number of words used for a search result teaser
|
||||||
|
use-boolean-and = true # multiple search terms must all match
|
||||||
|
boost-title = 2 # ranking boost factor for matches in headers
|
||||||
|
boost-hierarchy = 1 # ranking boost factor for matches in page names
|
||||||
|
boost-paragraph = 1 # ranking boost factor for matches in text
|
||||||
|
expand = true # partial words will match longer terms
|
||||||
|
heading-split-level = 3 # link results to heading levels
|
||||||
|
copy-js = true # include Javascript code for search
|
||||||
|
```
|
||||||
|
|
||||||
- **enable:** Enables the search feature. Defaults to `true`.
|
- **enable:** Enables the search feature. Defaults to `true`.
|
||||||
- **limit-results:** The maximum number of search results. Defaults to `30`.
|
- **limit-results:** The maximum number of search results. Defaults to `30`.
|
||||||
|
@ -116,61 +261,24 @@ Available configuration options for the `[output.html.search]` table:
|
||||||
- **copy-js:** Copy JavaScript files for the search implementation to the output
|
- **copy-js:** Copy JavaScript files for the search implementation to the output
|
||||||
directory. Defaults to `true`.
|
directory. Defaults to `true`.
|
||||||
|
|
||||||
This shows all available HTML output options in the **book.toml**:
|
### `[output.html.redirect]`
|
||||||
|
|
||||||
|
The `[output.html.redirect]` table provides a way to add redirects.
|
||||||
|
This is useful when you move, rename, or remove a page to ensure that links to the old URL will go to the new location.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[book]
|
|
||||||
title = "Example book"
|
|
||||||
authors = ["John Doe", "Jane Doe"]
|
|
||||||
description = "The example book covers examples."
|
|
||||||
|
|
||||||
[output.html]
|
|
||||||
theme = "my-theme"
|
|
||||||
default-theme = "light"
|
|
||||||
preferred-dark-theme = "navy"
|
|
||||||
curly-quotes = true
|
|
||||||
mathjax-support = false
|
|
||||||
copy-fonts = true
|
|
||||||
additional-css = ["custom.css", "custom2.css"]
|
|
||||||
additional-js = ["custom.js"]
|
|
||||||
no-section-label = false
|
|
||||||
git-repository-url = "https://github.com/rust-lang/mdBook"
|
|
||||||
git-repository-icon = "fa-github"
|
|
||||||
edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}"
|
|
||||||
site-url = "/example-book/"
|
|
||||||
cname = "myproject.rs"
|
|
||||||
input-404 = "not-found.md"
|
|
||||||
|
|
||||||
[output.html.print]
|
|
||||||
enable = true
|
|
||||||
|
|
||||||
[output.html.fold]
|
|
||||||
enable = false
|
|
||||||
level = 0
|
|
||||||
|
|
||||||
[output.html.playground]
|
|
||||||
editable = false
|
|
||||||
copy-js = true
|
|
||||||
line-numbers = false
|
|
||||||
|
|
||||||
[output.html.search]
|
|
||||||
enable = true
|
|
||||||
limit-results = 30
|
|
||||||
teaser-word-count = 30
|
|
||||||
use-boolean-and = true
|
|
||||||
boost-title = 2
|
|
||||||
boost-hierarchy = 1
|
|
||||||
boost-paragraph = 1
|
|
||||||
expand = true
|
|
||||||
heading-split-level = 3
|
|
||||||
copy-js = true
|
|
||||||
|
|
||||||
[output.html.redirect]
|
[output.html.redirect]
|
||||||
"/appendices/bibliography.html" = "https://rustc-dev-guide.rust-lang.org/appendix/bibliography.html"
|
"/appendices/bibliography.html" = "https://rustc-dev-guide.rust-lang.org/appendix/bibliography.html"
|
||||||
"/other-installation-methods.html" = "../infra/other-installation-methods.html"
|
"/other-installation-methods.html" = "../infra/other-installation-methods.html"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Markdown Renderer
|
The table contains key-value pairs where the key is where the redirect file needs to be created, as an absolute path from the build directory, (e.g. `/appendices/bibliography.html`).
|
||||||
|
The value can be any valid URI the browser should navigate to (e.g. `https://rust-lang.org/`, `/overview.html`, or `../bibliography.html`).
|
||||||
|
|
||||||
|
This will generate an HTML page which will automatically redirect to the given location.
|
||||||
|
Note that the source location does not support `#` anchor redirects.
|
||||||
|
|
||||||
|
## Markdown Renderer
|
||||||
|
|
||||||
The Markdown renderer will run preprocessors and then output the resulting
|
The Markdown renderer will run preprocessors and then output the resulting
|
||||||
Markdown. This is mostly useful for debugging preprocessors, especially in
|
Markdown. This is mostly useful for debugging preprocessors, especially in
|
||||||
|
@ -189,20 +297,3 @@ only whether it is enabled or disabled.
|
||||||
|
|
||||||
See [the preprocessors documentation](preprocessors.md) for how to
|
See [the preprocessors documentation](preprocessors.md) for how to
|
||||||
specify which preprocessors should run before the Markdown renderer.
|
specify which preprocessors should run before the Markdown renderer.
|
||||||
|
|
||||||
### Custom Renderers
|
|
||||||
|
|
||||||
A custom renderer can be enabled by adding a `[output.foo]` table to your
|
|
||||||
`book.toml`. Similar to [preprocessors](preprocessors.md) this will
|
|
||||||
instruct `mdbook` to pass a representation of the book to `mdbook-foo` for
|
|
||||||
rendering. See the [alternative backends] chapter for more detail.
|
|
||||||
|
|
||||||
The custom renderer has access to all the fields within its table (i.e.
|
|
||||||
anything under `[output.foo]`). mdBook checks for two common fields:
|
|
||||||
|
|
||||||
- **command:** The command to execute for this custom renderer. Defaults to
|
|
||||||
the name of the renderer with the `mdbook-` prefix (such as `mdbook-foo`).
|
|
||||||
- **optional:** If `true`, then the command will be ignored if it is not
|
|
||||||
installed, otherwise mdBook will fail with an error. Defaults to `false`.
|
|
||||||
|
|
||||||
[alternative backends]: ../../for_developers/backends.md
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Markdown
|
# Markdown
|
||||||
|
|
||||||
mdBook's [parser](https://github.com/raphlinus/pulldown-cmark) adheres to the [CommonMark](https://commonmark.org/)
|
mdBook's [parser](https://github.com/raphlinus/pulldown-cmark) adheres to the [CommonMark](https://commonmark.org/) specification with some extensions described below.
|
||||||
specification. You can take a quick [tutorial](https://commonmark.org/help/tutorial/),
|
You can take a quick [tutorial](https://commonmark.org/help/tutorial/),
|
||||||
or [try out](https://spec.commonmark.org/dingus/) CommonMark in real time. A complete Markdown overview is out of scope for
|
or [try out](https://spec.commonmark.org/dingus/) CommonMark in real time. A complete Markdown overview is out of scope for
|
||||||
this documentation, but below is a high level overview of some of the basics. For a more in-depth experience, check out the
|
this documentation, but below is a high level overview of some of the basics. For a more in-depth experience, check out the
|
||||||
[Markdown Guide](https://www.markdownguide.org).
|
[Markdown Guide](https://www.markdownguide.org).
|
||||||
|
@ -84,6 +84,20 @@ Read about [mdBook](mdBook.md).
|
||||||
|
|
||||||
A bare url: <https://www.rust-lang.org>.
|
A bare url: <https://www.rust-lang.org>.
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Relative links that end with `.md` will be converted to the `.html` extension.
|
||||||
|
It is recommended to use `.md` links when possible.
|
||||||
|
This is useful when viewing the Markdown file outside of mdBook, for example on GitHub or GitLab which render Markdown automatically.
|
||||||
|
|
||||||
|
Links to `README.md` will be converted to `index.html`.
|
||||||
|
This is done since some services like GitHub render README files automatically, but web servers typically expect the root file to be called `index.html`.
|
||||||
|
|
||||||
|
You can link to individual headings with `#` fragments.
|
||||||
|
For example, `mdbook.md#text-and-paragraphs` would link to the [Text and Paragraphs](#text-and-paragraphs) section above.
|
||||||
|
The ID is created by transforming the heading such as converting to lowercase and replacing spaces with dashes.
|
||||||
|
You can click on any heading and look at the URL in your browser to see what the fragment looks like.
|
||||||
|
|
||||||
## Images
|
## Images
|
||||||
|
|
||||||
Including images is simply a matter of including a link to them, much like in the _Links_ section above. The following markdown
|
Including images is simply a matter of including a link to them, much like in the _Links_ section above. The following markdown
|
||||||
|
@ -103,5 +117,106 @@ Which, of course displays the image like so:
|
||||||
|
|
||||||
![The Rust Logo](images/rust-logo-blk.svg)
|
![The Rust Logo](images/rust-logo-blk.svg)
|
||||||
|
|
||||||
|
## Extensions
|
||||||
|
|
||||||
See the [Markdown Guide Basic Syntax](https://www.markdownguide.org/basic-syntax/) document for more.
|
mdBook has several extensions beyond the standard CommonMark specification.
|
||||||
|
|
||||||
|
### Strikethrough
|
||||||
|
|
||||||
|
Text may be rendered with a horizontal line through the center by wrapping the
|
||||||
|
text with two tilde characters on each side:
|
||||||
|
|
||||||
|
```text
|
||||||
|
An example of ~~strikethrough text~~.
|
||||||
|
```
|
||||||
|
|
||||||
|
This example will render as:
|
||||||
|
|
||||||
|
> An example of ~~strikethrough text~~.
|
||||||
|
|
||||||
|
This follows the [GitHub Strikethrough extension][strikethrough].
|
||||||
|
|
||||||
|
### Footnotes
|
||||||
|
|
||||||
|
A footnote generates a small numbered link in the text which when clicked
|
||||||
|
takes the reader to the footnote text at the bottom of the item. The footnote
|
||||||
|
label is written similarly to a link reference with a caret at the front. The
|
||||||
|
footnote text is written like a link reference definition, with the text
|
||||||
|
following the label. Example:
|
||||||
|
|
||||||
|
```text
|
||||||
|
This is an example of a footnote[^note].
|
||||||
|
|
||||||
|
[^note]: This text is the contents of the footnote, which will be rendered
|
||||||
|
towards the bottom.
|
||||||
|
```
|
||||||
|
|
||||||
|
This example will render as:
|
||||||
|
|
||||||
|
> This is an example of a footnote[^note].
|
||||||
|
>
|
||||||
|
> [^note]: This text is the contents of the footnote, which will be rendered
|
||||||
|
> towards the bottom.
|
||||||
|
|
||||||
|
The footnotes are automatically numbered based on the order the footnotes are
|
||||||
|
written.
|
||||||
|
|
||||||
|
### Tables
|
||||||
|
|
||||||
|
Tables can be written using pipes and dashes to draw the rows and columns of
|
||||||
|
the table. These will be translated to HTML table matching the shape. Example:
|
||||||
|
|
||||||
|
```text
|
||||||
|
| Header1 | Header2 |
|
||||||
|
|---------|---------|
|
||||||
|
| abc | def |
|
||||||
|
```
|
||||||
|
|
||||||
|
This example will render similarly to this:
|
||||||
|
|
||||||
|
| Header1 | Header2 |
|
||||||
|
|---------|---------|
|
||||||
|
| abc | def |
|
||||||
|
|
||||||
|
See the specification for the [GitHub Tables extension][tables] for more
|
||||||
|
details on the exact syntax supported.
|
||||||
|
|
||||||
|
### Task lists
|
||||||
|
|
||||||
|
Task lists can be used as a checklist of items that have been completed.
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```md
|
||||||
|
- [x] Complete task
|
||||||
|
- [ ] Incomplete task
|
||||||
|
```
|
||||||
|
|
||||||
|
This will render as:
|
||||||
|
|
||||||
|
> - [x] Complete task
|
||||||
|
> - [ ] Incomplete task
|
||||||
|
|
||||||
|
See the specification for the [task list extension] for more details.
|
||||||
|
|
||||||
|
### Smart punctuation
|
||||||
|
|
||||||
|
Some ASCII punctuation sequences will be automatically turned into fancy Unicode
|
||||||
|
characters:
|
||||||
|
|
||||||
|
| ASCII sequence | Unicode |
|
||||||
|
|----------------|---------|
|
||||||
|
| `--` | – |
|
||||||
|
| `---` | — |
|
||||||
|
| `...` | … |
|
||||||
|
| `"` | “ or ”, depending on context |
|
||||||
|
| `'` | ‘ or ’, depending on context |
|
||||||
|
|
||||||
|
So, no need to manually enter those Unicode characters!
|
||||||
|
|
||||||
|
This feature is disabled by default.
|
||||||
|
To enable it, see the [`output.html.curly-quotes`] config option.
|
||||||
|
|
||||||
|
[strikethrough]: https://github.github.com/gfm/#strikethrough-extension-
|
||||||
|
[tables]: https://github.github.com/gfm/#tables-extension-
|
||||||
|
[task list extension]: https://github.github.com/gfm/#task-list-items-extension-
|
||||||
|
[`output.html.curly-quotes`]: configuration/renderers.md#html-renderer-options
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
There is a feature in mdBook that lets you hide code lines by prepending them
|
There is a feature in mdBook that lets you hide code lines by prepending them
|
||||||
with a `#` [like you would with Rustdoc][rustdoc-hide].
|
with a `#` [like you would with Rustdoc][rustdoc-hide].
|
||||||
|
This currently only works with Rust language code blocks.
|
||||||
|
|
||||||
[rustdoc-hide]: https://doc.rust-lang.org/stable/rustdoc/documentation-tests.html#hiding-portions-of-the-example
|
[rustdoc-hide]: https://doc.rust-lang.org/stable/rustdoc/documentation-tests.html#hiding-portions-of-the-example
|
||||||
|
|
||||||
|
@ -27,6 +28,67 @@ Will render as
|
||||||
# }
|
# }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The code block has an eyeball icon (<i class="fa fa-eye"></i>) which will toggle the visibility of the hidden lines.
|
||||||
|
|
||||||
|
## Rust Playground
|
||||||
|
|
||||||
|
Rust language code blocks will automatically get a play button (<i class="fa fa-play"></i>) which will execute the code and display the output just below the code block.
|
||||||
|
This works by sending the code to the [Rust Playground].
|
||||||
|
|
||||||
|
```rust
|
||||||
|
println!("Hello, World!");
|
||||||
|
```
|
||||||
|
|
||||||
|
If there is no `main` function, then the code is automatically wrapped inside one.
|
||||||
|
|
||||||
|
If you wish to disable the play button for a code block, you can include the `noplayground` option on the code block like this:
|
||||||
|
|
||||||
|
~~~markdown
|
||||||
|
```rust,noplayground
|
||||||
|
let mut name = String::new();
|
||||||
|
std::io::stdin().read_line(&mut name).expect("failed to read line");
|
||||||
|
println!("Hello {}!", name);
|
||||||
|
```
|
||||||
|
~~~
|
||||||
|
|
||||||
|
Or, if you wish to disable the play button for all code blocks in your book, you can write the config to the `book.toml` like this.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[output.html.playground]
|
||||||
|
runnable = false
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rust code block attributes
|
||||||
|
|
||||||
|
Additional attributes can be included in Rust code blocks with comma, space, or tab-separated terms just after the language term. For example:
|
||||||
|
|
||||||
|
~~~markdown
|
||||||
|
```rust,ignore
|
||||||
|
# This example won't be tested.
|
||||||
|
panic!("oops!");
|
||||||
|
```
|
||||||
|
~~~
|
||||||
|
|
||||||
|
These are particularly important when using [`mdbook test`] to test Rust examples.
|
||||||
|
These use the same attributes as [rustdoc attributes], with a few additions:
|
||||||
|
|
||||||
|
* `editable` — Enables the [editor].
|
||||||
|
* `noplayground` — Removes the play button, but will still be tested.
|
||||||
|
* `mdbook-runnable` — Forces the play button to be displayed.
|
||||||
|
This is intended to be combined with the `ignore` attribute for examples that should not be tested, but you want to allow the reader to run.
|
||||||
|
* `ignore` — Will not be tested and no play button is shown, but it is still highlighted as Rust syntax.
|
||||||
|
* `should_panic` — When executed, it should produce a panic.
|
||||||
|
* `no_run` — The code is compiled when tested, but it is not run.
|
||||||
|
The play button is also not shown.
|
||||||
|
* `compile_fail` — The code should fail to compile.
|
||||||
|
* `edition2015`, `edition2018`, `edition2021` — Forces the use of a specific Rust edition.
|
||||||
|
See [`rust.edition`] to set this globally.
|
||||||
|
|
||||||
|
[`mdbook test`]: ../cli/test.md
|
||||||
|
[rustdoc attributes]: https://doc.rust-lang.org/rustdoc/documentation-tests.html#attributes
|
||||||
|
[editor]: theme/editor.md
|
||||||
|
[`rust.edition`]: configuration/general.md#rust-options
|
||||||
|
|
||||||
## Including files
|
## Including files
|
||||||
|
|
||||||
With the following syntax, you can include files into your book:
|
With the following syntax, you can include files into your book:
|
||||||
|
@ -191,6 +253,17 @@ Here is what a rendered code snippet looks like:
|
||||||
|
|
||||||
{{#playground example.rs}}
|
{{#playground example.rs}}
|
||||||
|
|
||||||
|
Any additional values passed after the filename will be included as attributes of the code block.
|
||||||
|
For example `\{{#playground example.rs editable}}` will create the code block like the following:
|
||||||
|
|
||||||
|
~~~markdown
|
||||||
|
```rust,editable
|
||||||
|
# Contents of example.rs here.
|
||||||
|
```
|
||||||
|
~~~
|
||||||
|
|
||||||
|
And the `editable` attribute will enable the [editor] as described at [Rust code block attributes](#rust-code-block-attributes).
|
||||||
|
|
||||||
[Rust Playground]: https://play.rust-lang.org/
|
[Rust Playground]: https://play.rust-lang.org/
|
||||||
|
|
||||||
## Controlling page \<title\>
|
## Controlling page \<title\>
|
||||||
|
|
|
@ -38,6 +38,10 @@ template and only add / modify what you need. You can copy the default theme
|
||||||
into your source directory automatically by using `mdbook init --theme` and just
|
into your source directory automatically by using `mdbook init --theme` and just
|
||||||
remove the files you don't want to override.
|
remove the files you don't want to override.
|
||||||
|
|
||||||
|
`mdbook init --theme` will not create every file listed above.
|
||||||
|
Some files, such as `head.hbs`, do not have built-in equivalents.
|
||||||
|
Just create the file if you need it.
|
||||||
|
|
||||||
If you completely replace all built-in themes, be sure to also set
|
If you completely replace all built-in themes, be sure to also set
|
||||||
[`output.html.preferred-dark-theme`] in the config, which defaults to the
|
[`output.html.preferred-dark-theme`] in the config, which defaults to the
|
||||||
built-in `navy` theme.
|
built-in `navy` theme.
|
||||||
|
|
|
@ -12,12 +12,14 @@ editable = true
|
||||||
To make a specific block available for editing, the attribute `editable` needs
|
To make a specific block available for editing, the attribute `editable` needs
|
||||||
to be added to it:
|
to be added to it:
|
||||||
|
|
||||||
<pre><code class="language-markdown">```rust,editable
|
~~~markdown
|
||||||
|
```rust,editable
|
||||||
fn main() {
|
fn main() {
|
||||||
let number = 5;
|
let number = 5;
|
||||||
print!("{}", number);
|
print!("{}", number);
|
||||||
}
|
}
|
||||||
```</code></pre>
|
```
|
||||||
|
~~~
|
||||||
|
|
||||||
The above will result in this editable playground:
|
The above will result in this editable playground:
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
# User Guide
|
||||||
|
|
||||||
|
This user guide provides an introduction to basic concepts of using mdBook.
|
||||||
|
|
||||||
|
- [Installation](installation.md)
|
||||||
|
- [Reading Books](reading.md)
|
||||||
|
- [Creating a Book](creating.md)
|
|
@ -0,0 +1,109 @@
|
||||||
|
# Creating a Book
|
||||||
|
|
||||||
|
Once you have the `mdbook` CLI tool installed, you can use it to create and render a book.
|
||||||
|
|
||||||
|
## Initializing a book
|
||||||
|
|
||||||
|
The `mdbook init` command will create a new directory containing an empty book for you to get started.
|
||||||
|
Give it the name of the directory that you want to create:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mdbook init my-first-book
|
||||||
|
```
|
||||||
|
|
||||||
|
It will ask a few questions before generating the book.
|
||||||
|
After answering the questions, you can change the current directory into the new book:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd my-first-book
|
||||||
|
```
|
||||||
|
|
||||||
|
There are several ways to render a book, but one of the easiest methods is to use the `serve` command, which will build your book and start a local webserver:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mdbook serve --open
|
||||||
|
```
|
||||||
|
|
||||||
|
The `--open` option will open your default web browser to view your new book.
|
||||||
|
You can leave the server running even while you edit the content of the book, and `mdbook` will automatically rebuild the output *and* automatically refresh your web browser.
|
||||||
|
|
||||||
|
Check out the [CLI Guide](../cli/index.html) for more information about other `mdbook` commands and CLI options.
|
||||||
|
|
||||||
|
## Anatomy of a book
|
||||||
|
|
||||||
|
A book is built from several files which define the settings and layout of the book.
|
||||||
|
|
||||||
|
### `book.toml`
|
||||||
|
|
||||||
|
In the root of your book, there is a `book.toml` file which contains settings for describing how to build your book.
|
||||||
|
This is written in the [TOML markup language](https://toml.io/).
|
||||||
|
The default settings are usually good enough to get you started.
|
||||||
|
When you are interested in exploring more features and options that mdBook provides, check out the [Configuration chapter](../format/configuration/index.html) for more details.
|
||||||
|
|
||||||
|
A very basic `book.toml` can be as simple as this:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[book]
|
||||||
|
title = "My First Book"
|
||||||
|
```
|
||||||
|
|
||||||
|
### `SUMMARY.md`
|
||||||
|
|
||||||
|
The next major part of a book is the summary file located at `src/SUMMARY.md`.
|
||||||
|
This file contains a list of all the chapters in the book.
|
||||||
|
Before a chapter can be viewed, it must be added to this list.
|
||||||
|
|
||||||
|
Here's a basic summary file with a few chapters:
|
||||||
|
|
||||||
|
```md
|
||||||
|
# Summary
|
||||||
|
|
||||||
|
[Introduction](README.md)
|
||||||
|
|
||||||
|
- [My First Chapter](my-first-chapter.md)
|
||||||
|
- [Nested example](nested/README.md)
|
||||||
|
- [Sub-chapter](nested/sub-chapter.md)
|
||||||
|
```
|
||||||
|
|
||||||
|
Try opening up `src/SUMMARY.md` in your editor and adding a few chapters.
|
||||||
|
If any of the chapter files do not exist, `mdbook` will automatically create them for you.
|
||||||
|
|
||||||
|
For more details on other formatting options for the summary file, check out the [Summary chapter](../format/summary.md).
|
||||||
|
|
||||||
|
### Source files
|
||||||
|
|
||||||
|
The content of your book is all contained in the `src` directory.
|
||||||
|
Each chapter is a separate Markdown file.
|
||||||
|
Typically, each chapter starts with a level 1 heading with the title of the chapter.
|
||||||
|
|
||||||
|
```md
|
||||||
|
# My First Chapter
|
||||||
|
|
||||||
|
Fill out your content here.
|
||||||
|
```
|
||||||
|
|
||||||
|
The precise layout of the files is up to you.
|
||||||
|
The organization of the files will correspond to the HTML files generated, so keep in mind that the file layout is part of the URL of each chapter.
|
||||||
|
|
||||||
|
While the `mdbook serve` command is running, you can open any of the chapter files and start editing them.
|
||||||
|
Each time you save the file, `mdbook` will rebuild the book and refresh your web browser.
|
||||||
|
|
||||||
|
Check out the [Markdown chapter](../format/markdown.md) for more information on formatting the content of your chapters.
|
||||||
|
|
||||||
|
All other files in the `src` directory will be included in the output.
|
||||||
|
So if you have images or other static files, just include them somewhere in the `src` directory.
|
||||||
|
|
||||||
|
## Publishing a book
|
||||||
|
|
||||||
|
Once you've written your book, you may want to host it somewhere for others to view.
|
||||||
|
The first step is to build the output of the book.
|
||||||
|
This can be done with the `mdbook build` command in the same directory where the `book.toml` file is located:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mdbook build
|
||||||
|
```
|
||||||
|
|
||||||
|
This will generate a directory named `book` which contains the HTML content of your book.
|
||||||
|
You can then place this directory on any web server to host it.
|
||||||
|
|
||||||
|
For more information about publishing and deploying, check out the [Continuous Integration chapter](../continuous-integration.md) for more.
|
|
@ -0,0 +1,50 @@
|
||||||
|
# Installation
|
||||||
|
|
||||||
|
There are multiple ways to install the mdBook CLI tool.
|
||||||
|
Choose any one of the methods below that best suit your needs.
|
||||||
|
If you are installing mdBook for automatic deployment, check out the [continuous integration] chapter for more examples on how to install.
|
||||||
|
|
||||||
|
[continuous integration]: ../continuous-integration.md
|
||||||
|
|
||||||
|
## Pre-compiled binaries
|
||||||
|
|
||||||
|
Executable binaries are available for download on the [GitHub Releases page][releases].
|
||||||
|
Download the binary for your platform (Windows, macOS, or Linux) and extract the archive.
|
||||||
|
The archive contains an `mdbook` executable which you can run to build your books.
|
||||||
|
|
||||||
|
To make it easier to run, put the path to the binary into your `PATH`.
|
||||||
|
|
||||||
|
[releases]: https://github.com/rust-lang/mdBook/releases
|
||||||
|
|
||||||
|
## Build from source using Rust
|
||||||
|
|
||||||
|
To build the `mdbook` executable from source, you will first need to install Rust and Cargo.
|
||||||
|
Follow the instructions on the [Rust installation page].
|
||||||
|
mdBook currently requires at least Rust version 1.54.
|
||||||
|
|
||||||
|
Once you have installed Rust, the following command can be used to build and install mdBook:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo install mdbook
|
||||||
|
```
|
||||||
|
|
||||||
|
This will automatically download mdBook from [crates.io], build it, and install it in Cargo's global binary directory (`~/.cargo/bin/` by default).
|
||||||
|
|
||||||
|
[Rust installation page]: https://www.rust-lang.org/tools/install
|
||||||
|
[crates.io]: https://crates.io/
|
||||||
|
|
||||||
|
### Installing the latest master version
|
||||||
|
|
||||||
|
The version published to crates.io will ever so slightly be behind the version hosted on GitHub.
|
||||||
|
If you need the latest version you can build the git version of mdBook yourself.
|
||||||
|
Cargo makes this ***super easy***!
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo install --git https://github.com/rust-lang/mdBook.git mdbook
|
||||||
|
```
|
||||||
|
|
||||||
|
Again, make sure to add the Cargo bin directory to your `PATH`.
|
||||||
|
|
||||||
|
If you are interested in making modifications to mdBook itself, check out the [Contributing Guide] for more information.
|
||||||
|
|
||||||
|
[Contributing Guide]: https://github.com/rust-lang/mdBook/blob/master/CONTRIBUTING.md
|
|
@ -0,0 +1,74 @@
|
||||||
|
# Reading Books
|
||||||
|
|
||||||
|
This chapter gives an introduction on how to interact with a book produced by mdBook.
|
||||||
|
This assumes you are reading an HTML book.
|
||||||
|
The options and formatting will be different for other output formats such as PDF.
|
||||||
|
|
||||||
|
A book is organized into *chapters*.
|
||||||
|
Each chapter is a separate page.
|
||||||
|
Chapters can be nested into a hierarchy of sub-chapters.
|
||||||
|
Typically, each chapter will be organized into a series of *headings* to subdivide a chapter.
|
||||||
|
|
||||||
|
## Navigation
|
||||||
|
|
||||||
|
There are several methods for navigating through the chapters of a book.
|
||||||
|
|
||||||
|
The **sidebar** on the left provides a list of all chapters.
|
||||||
|
Clicking on any of the chapter titles will load that page.
|
||||||
|
|
||||||
|
The sidebar may not automatically appear if the window is too narrow, particularly on mobile displays.
|
||||||
|
In that situation, the menu icon (three horizontal bars) at the top-left of the page can be pressed to open and close the sidebar.
|
||||||
|
|
||||||
|
The **arrow buttons** at the bottom of the page can be used to navigate to the previous or the next chapter.
|
||||||
|
|
||||||
|
The **left and right arrow keys** on the keyboard can be used to navigate to the previous or the next chapter.
|
||||||
|
|
||||||
|
## Top menu bar
|
||||||
|
|
||||||
|
The menu bar at the top of the page provides some icons for interacting with the book.
|
||||||
|
The icons displayed will depend on the settings of how the book was generated.
|
||||||
|
|
||||||
|
| Icon | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| <i class="fa fa-bars"></i> | Opens and closes the chapter listing sidebar. |
|
||||||
|
| <i class="fa fa-paint-brush"></i> | Opens a picker to choose a different color theme. |
|
||||||
|
| <i class="fa fa-search"></i> | Opens a search bar for searching within the book. |
|
||||||
|
| <i class="fa fa-print"></i> | Instructs the web browser to print the entire book. |
|
||||||
|
| <i class="fa fa-github"></i> | Opens a link to the website that hosts the source code of the book. |
|
||||||
|
| <i class="fa fa-edit"></i> | Opens a page to directly edit the source of the page you are currently reading. |
|
||||||
|
|
||||||
|
Tapping the menu bar will scroll the page to the top.
|
||||||
|
|
||||||
|
## Search
|
||||||
|
|
||||||
|
Each book has a built-in search system.
|
||||||
|
Pressing the search icon (<i class="fa fa-search"></i>) in the menu bar, or pressing the `S` key on the keyboard will open an input box for entering search terms.
|
||||||
|
Typing some terms will show matching chapters and sections in real time.
|
||||||
|
|
||||||
|
Clicking any of the results will jump to that section.
|
||||||
|
The up and down arrow keys can be used to navigate the results, and enter will open the highlighted section.
|
||||||
|
|
||||||
|
After loading a search result, the matching search terms will be highlighted in the text.
|
||||||
|
Clicking a highlighted word or pressing the `Esc` key will remove the highlighting.
|
||||||
|
|
||||||
|
## Code blocks
|
||||||
|
|
||||||
|
mdBook books are often used for programming projects, and thus support highlighting code blocks and samples.
|
||||||
|
Code blocks may contain several different icons for interacting with them:
|
||||||
|
|
||||||
|
| Icon | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| <i class="fa fa-copy"></i> | Copies the code block into your local clipboard, to allow pasting into another application. |
|
||||||
|
| <i class="fa fa-play"></i> | For Rust code examples, this will execute the sample code and display the compiler output just below the example (see [playground]). |
|
||||||
|
| <i class="fa fa-eye"></i> | For Rust code examples, this will toggle visibility of "hidden" lines. Sometimes, larger examples will hide lines which are not particularly relevant to what is being illustrated (see [hiding code lines]). |
|
||||||
|
| <i class="fa fa-history"></i> | For [editable code examples][editor], this will undo any changes you have made. |
|
||||||
|
|
||||||
|
Here's an example:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
println!("Hello, World!");
|
||||||
|
```
|
||||||
|
|
||||||
|
[editor]: ../format/theme/editor.md
|
||||||
|
[playground]: ../format/mdbook.md#rust-playground
|
||||||
|
[hiding code lines]: ../format/mdbook.md#hiding-code-lines
|
|
@ -1,3 +0,0 @@
|
||||||
# Introduction
|
|
||||||
|
|
||||||
A frontmatter chapter.
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
use memchr::{self, Memchr};
|
use memchr::{self, Memchr};
|
||||||
use pulldown_cmark::{self, Event, Tag};
|
use pulldown_cmark::{self, Event, HeadingLevel, Tag};
|
||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
@ -161,7 +161,7 @@ impl From<Link> for SummaryItem {
|
||||||
/// > match the following regex: "[^<>\n[]]+".
|
/// > match the following regex: "[^<>\n[]]+".
|
||||||
struct SummaryParser<'a> {
|
struct SummaryParser<'a> {
|
||||||
src: &'a str,
|
src: &'a str,
|
||||||
stream: pulldown_cmark::OffsetIter<'a>,
|
stream: pulldown_cmark::OffsetIter<'a, 'a>,
|
||||||
offset: usize,
|
offset: usize,
|
||||||
|
|
||||||
/// We can't actually put an event back into the `OffsetIter` stream, so instead we store it
|
/// We can't actually put an event back into the `OffsetIter` stream, so instead we store it
|
||||||
|
@ -263,7 +263,7 @@ impl<'a> SummaryParser<'a> {
|
||||||
loop {
|
loop {
|
||||||
match self.next_event() {
|
match self.next_event() {
|
||||||
Some(ev @ Event::Start(Tag::List(..)))
|
Some(ev @ Event::Start(Tag::List(..)))
|
||||||
| Some(ev @ Event::Start(Tag::Heading(1))) => {
|
| Some(ev @ Event::Start(Tag::Heading(HeadingLevel::H1, ..))) => {
|
||||||
if is_prefix {
|
if is_prefix {
|
||||||
// we've finished prefix chapters and are at the start
|
// we've finished prefix chapters and are at the start
|
||||||
// of the numbered section.
|
// of the numbered section.
|
||||||
|
@ -302,10 +302,10 @@ impl<'a> SummaryParser<'a> {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(Event::Start(Tag::Heading(1))) => {
|
Some(Event::Start(Tag::Heading(HeadingLevel::H1, ..))) => {
|
||||||
debug!("Found a h1 in the SUMMARY");
|
debug!("Found a h1 in the SUMMARY");
|
||||||
|
|
||||||
let tags = collect_events!(self.stream, end Tag::Heading(1));
|
let tags = collect_events!(self.stream, end Tag::Heading(HeadingLevel::H1, ..));
|
||||||
Some(stringify_events(tags))
|
Some(stringify_events(tags))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,7 +375,7 @@ impl<'a> SummaryParser<'a> {
|
||||||
}
|
}
|
||||||
// The expectation is that pulldown cmark will terminate a paragraph before a new
|
// The expectation is that pulldown cmark will terminate a paragraph before a new
|
||||||
// heading, so we can always count on this to return without skipping headings.
|
// heading, so we can always count on this to return without skipping headings.
|
||||||
Some(ev @ Event::Start(Tag::Heading(1))) => {
|
Some(ev @ Event::Start(Tag::Heading(HeadingLevel::H1, ..))) => {
|
||||||
// we're starting a new part
|
// we're starting a new part
|
||||||
self.back(ev);
|
self.back(ev);
|
||||||
break;
|
break;
|
||||||
|
@ -527,15 +527,19 @@ impl<'a> SummaryParser<'a> {
|
||||||
fn parse_title(&mut self) -> Option<String> {
|
fn parse_title(&mut self) -> Option<String> {
|
||||||
loop {
|
loop {
|
||||||
match self.next_event() {
|
match self.next_event() {
|
||||||
Some(Event::Start(Tag::Heading(1))) => {
|
Some(Event::Start(Tag::Heading(HeadingLevel::H1, ..))) => {
|
||||||
debug!("Found a h1 in the SUMMARY");
|
debug!("Found a h1 in the SUMMARY");
|
||||||
|
|
||||||
let tags = collect_events!(self.stream, end Tag::Heading(1));
|
let tags = collect_events!(self.stream, end Tag::Heading(HeadingLevel::H1, ..));
|
||||||
return Some(stringify_events(tags));
|
return Some(stringify_events(tags));
|
||||||
}
|
}
|
||||||
// Skip a HTML element such as a comment line.
|
// Skip a HTML element such as a comment line.
|
||||||
Some(Event::Html(_)) => {}
|
Some(Event::Html(_)) => {}
|
||||||
// Otherwise, no title.
|
// Otherwise, no title.
|
||||||
|
Some(ev) => {
|
||||||
|
self.back(ev);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
_ => return None,
|
_ => return None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -647,6 +651,18 @@ mod tests {
|
||||||
assert_eq!(got, should_be);
|
assert_eq!(got, should_be);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_initial_title() {
|
||||||
|
let src = "[Link]()";
|
||||||
|
let mut parser = SummaryParser::new(src);
|
||||||
|
|
||||||
|
assert!(parser.parse_title().is_none());
|
||||||
|
assert!(matches!(
|
||||||
|
parser.next_event(),
|
||||||
|
Some(Event::Start(Tag::Paragraph))
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_title_with_styling() {
|
fn parse_title_with_styling() {
|
||||||
let src = "# My **Awesome** Summary";
|
let src = "# My **Awesome** Summary";
|
||||||
|
|
|
@ -1,23 +1,29 @@
|
||||||
use crate::{get_book_dir, open};
|
use crate::{get_book_dir, open};
|
||||||
use clap::{App, ArgMatches, SubCommand};
|
use clap::{arg, App, Arg, ArgMatches};
|
||||||
use mdbook::errors::Result;
|
use mdbook::errors::Result;
|
||||||
use mdbook::MDBook;
|
use mdbook::MDBook;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
// Create clap subcommand arguments
|
// Create clap subcommand arguments
|
||||||
pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
|
pub fn make_subcommand<'help>() -> App<'help> {
|
||||||
SubCommand::with_name("build")
|
App::new("build")
|
||||||
.about("Builds a book from its markdown files")
|
.about("Builds a book from its markdown files")
|
||||||
.arg_from_usage(
|
.arg(
|
||||||
"-d, --dest-dir=[dest-dir] 'Output directory for the book{n}\
|
Arg::new("dest-dir")
|
||||||
|
.short('d')
|
||||||
|
.long("dest-dir")
|
||||||
|
.value_name("dest-dir")
|
||||||
|
.help(
|
||||||
|
"Output directory for the book{n}\
|
||||||
Relative paths are interpreted relative to the book's root directory.{n}\
|
Relative paths are interpreted relative to the book's root directory.{n}\
|
||||||
If omitted, mdBook uses build.build-dir from book.toml or defaults to `./book`.'",
|
If omitted, mdBook uses build.build-dir from book.toml or defaults to `./book`.",
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.arg_from_usage(
|
.arg(arg!([dir]
|
||||||
"[dir] 'Root directory for the book{n}\
|
"Root directory for the book{n}\
|
||||||
(Defaults to the Current Directory when omitted)'",
|
(Defaults to the Current Directory when omitted)"
|
||||||
)
|
))
|
||||||
.arg_from_usage("-o, --open 'Opens the compiled book in a web browser'")
|
.arg(arg!(-o --open "Opens the compiled book in a web browser"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build command implementation
|
// Build command implementation
|
||||||
|
|
|
@ -1,23 +1,28 @@
|
||||||
use crate::get_book_dir;
|
use crate::get_book_dir;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use clap::{App, ArgMatches, SubCommand};
|
use clap::{arg, App, Arg, ArgMatches};
|
||||||
use mdbook::MDBook;
|
use mdbook::MDBook;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
// Create clap subcommand arguments
|
// Create clap subcommand arguments
|
||||||
pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
|
pub fn make_subcommand<'help>() -> App<'help> {
|
||||||
SubCommand::with_name("clean")
|
App::new("clean")
|
||||||
.about("Deletes a built book")
|
.about("Deletes a built book")
|
||||||
.arg_from_usage(
|
.arg(
|
||||||
"-d, --dest-dir=[dest-dir] 'Output directory for the book{n}\
|
Arg::new("dest-dir")
|
||||||
|
.short('d')
|
||||||
|
.long("dest-dir")
|
||||||
|
.value_name("dest-dir")
|
||||||
|
.help(
|
||||||
|
"Output directory for the book{n}\
|
||||||
Relative paths are interpreted relative to the book's root directory.{n}\
|
Relative paths are interpreted relative to the book's root directory.{n}\
|
||||||
Running this command deletes this directory.{n}\
|
If omitted, mdBook uses build.build-dir from book.toml or defaults to `./book`.",
|
||||||
If omitted, mdBook uses build.build-dir from book.toml or defaults to `./book`.'",
|
),
|
||||||
)
|
|
||||||
.arg_from_usage(
|
|
||||||
"[dir] 'Root directory for the book{n}\
|
|
||||||
(Defaults to the Current Directory when omitted)'",
|
|
||||||
)
|
)
|
||||||
|
.arg(arg!([dir]
|
||||||
|
"Root directory for the book{n}\
|
||||||
|
(Defaults to the Current Directory when omitted)"
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean command implementation
|
// Clean command implementation
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::get_book_dir;
|
use crate::get_book_dir;
|
||||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
use clap::{arg, App, Arg, ArgMatches};
|
||||||
use mdbook::config;
|
use mdbook::config;
|
||||||
use mdbook::errors::Result;
|
use mdbook::errors::Result;
|
||||||
use mdbook::MDBook;
|
use mdbook::MDBook;
|
||||||
|
@ -8,25 +8,25 @@ use std::io::Write;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
// Create clap subcommand arguments
|
// Create clap subcommand arguments
|
||||||
pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
|
pub fn make_subcommand<'help>() -> App<'help> {
|
||||||
SubCommand::with_name("init")
|
App::new("init")
|
||||||
.about("Creates the boilerplate structure and files for a new book")
|
.about("Creates the boilerplate structure and files for a new book")
|
||||||
// the {n} denotes a newline which will properly aligned in all help messages
|
// the {n} denotes a newline which will properly aligned in all help messages
|
||||||
.arg_from_usage(
|
.arg(arg!([dir]
|
||||||
"[dir] 'Directory to create the book in{n}\
|
"Directory to create the book in{n}\
|
||||||
(Defaults to the Current Directory when omitted)'",
|
(Defaults to the Current Directory when omitted)"
|
||||||
)
|
))
|
||||||
.arg_from_usage("--theme 'Copies the default theme into your source folder'")
|
.arg(arg!(--theme "Copies the default theme into your source folder"))
|
||||||
.arg_from_usage("--force 'Skips confirmation prompts'")
|
.arg(arg!(--force "Skips confirmation prompts"))
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("title")
|
Arg::new("title")
|
||||||
.long("title")
|
.long("title")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.help("Sets the book title")
|
.help("Sets the book title")
|
||||||
.required(false),
|
.required(false),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("ignore")
|
Arg::new("ignore")
|
||||||
.long("ignore")
|
.long("ignore")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.possible_values(&["none", "git"])
|
.possible_values(&["none", "git"])
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#[cfg(feature = "watch")]
|
#[cfg(feature = "watch")]
|
||||||
use super::watch;
|
use super::watch;
|
||||||
use crate::{get_book_dir, open};
|
use crate::{get_book_dir, open};
|
||||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
use clap::{arg, App, Arg, ArgMatches};
|
||||||
use futures_util::sink::SinkExt;
|
use futures_util::sink::SinkExt;
|
||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
use mdbook::errors::*;
|
use mdbook::errors::*;
|
||||||
|
@ -18,37 +18,43 @@ use warp::Filter;
|
||||||
const LIVE_RELOAD_ENDPOINT: &str = "__livereload";
|
const LIVE_RELOAD_ENDPOINT: &str = "__livereload";
|
||||||
|
|
||||||
// Create clap subcommand arguments
|
// Create clap subcommand arguments
|
||||||
pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
|
pub fn make_subcommand<'help>() -> App<'help> {
|
||||||
SubCommand::with_name("serve")
|
App::new("serve")
|
||||||
.about("Serves a book at http://localhost:3000, and rebuilds it on changes")
|
.about("Serves a book at http://localhost:3000, and rebuilds it on changes")
|
||||||
.arg_from_usage(
|
|
||||||
"-d, --dest-dir=[dest-dir] 'Output directory for the book{n}\
|
|
||||||
Relative paths are interpreted relative to the book's root directory.{n}\
|
|
||||||
If omitted, mdBook uses build.build-dir from book.toml or defaults to `./book`.'",
|
|
||||||
)
|
|
||||||
.arg_from_usage(
|
|
||||||
"[dir] 'Root directory for the book{n}\
|
|
||||||
(Defaults to the Current Directory when omitted)'",
|
|
||||||
)
|
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("hostname")
|
Arg::new("dest-dir")
|
||||||
.short("n")
|
.short('d')
|
||||||
|
.long("dest-dir")
|
||||||
|
.value_name("dest-dir")
|
||||||
|
.help(
|
||||||
|
"Output directory for the book{n}\
|
||||||
|
Relative paths are interpreted relative to the book's root directory.{n}\
|
||||||
|
If omitted, mdBook uses build.build-dir from book.toml or defaults to `./book`.",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.arg(arg!([dir]
|
||||||
|
"Root directory for the book{n}\
|
||||||
|
(Defaults to the Current Directory when omitted)"
|
||||||
|
))
|
||||||
|
.arg(
|
||||||
|
Arg::new("hostname")
|
||||||
|
.short('n')
|
||||||
.long("hostname")
|
.long("hostname")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.default_value("localhost")
|
.default_value("localhost")
|
||||||
.empty_values(false)
|
.forbid_empty_values(true)
|
||||||
.help("Hostname to listen on for HTTP connections"),
|
.help("Hostname to listen on for HTTP connections"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("port")
|
Arg::new("port")
|
||||||
.short("p")
|
.short('p')
|
||||||
.long("port")
|
.long("port")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.default_value("3000")
|
.default_value("3000")
|
||||||
.empty_values(false)
|
.forbid_empty_values(true)
|
||||||
.help("Port to use for HTTP connections"),
|
.help("Port to use for HTTP connections"),
|
||||||
)
|
)
|
||||||
.arg_from_usage("-o, --open 'Opens the book server in a web browser'")
|
.arg(arg!(-o --open "Opens the compiled book in a web browser"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serve command implementation
|
// Serve command implementation
|
||||||
|
@ -62,11 +68,10 @@ pub fn execute(args: &ArgMatches) -> Result<()> {
|
||||||
|
|
||||||
let address = format!("{}:{}", hostname, port);
|
let address = format!("{}:{}", hostname, port);
|
||||||
|
|
||||||
let livereload_url = format!("ws://{}/{}", address, LIVE_RELOAD_ENDPOINT);
|
|
||||||
let update_config = |book: &mut MDBook| {
|
let update_config = |book: &mut MDBook| {
|
||||||
book.config
|
book.config
|
||||||
.set("output.html.livereload-url", &livereload_url)
|
.set("output.html.live-reload-endpoint", &LIVE_RELOAD_ENDPOINT)
|
||||||
.expect("livereload-url update failed");
|
.expect("live-reload-endpoint update failed");
|
||||||
if let Some(dest_dir) = args.value_of("dest-dir") {
|
if let Some(dest_dir) = args.value_of("dest-dir") {
|
||||||
book.config.build.build_dir = dest_dir.into();
|
book.config.build.build_dir = dest_dir.into();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,37 @@
|
||||||
use crate::get_book_dir;
|
use crate::get_book_dir;
|
||||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
use clap::{arg, App, Arg, ArgMatches};
|
||||||
use mdbook::errors::Result;
|
use mdbook::errors::Result;
|
||||||
use mdbook::MDBook;
|
use mdbook::MDBook;
|
||||||
|
|
||||||
// Create clap subcommand arguments
|
// Create clap subcommand arguments
|
||||||
pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
|
pub fn make_subcommand<'help>() -> App<'help> {
|
||||||
SubCommand::with_name("test")
|
App::new("test")
|
||||||
.about("Tests that a book's Rust code samples compile")
|
.about("Tests that a book's Rust code samples compile")
|
||||||
.arg_from_usage(
|
.arg(
|
||||||
"-d, --dest-dir=[dest-dir] 'Output directory for the book{n}\
|
Arg::new("dest-dir")
|
||||||
|
.short('d')
|
||||||
|
.long("dest-dir")
|
||||||
|
.value_name("dest-dir")
|
||||||
|
.help(
|
||||||
|
"Output directory for the book{n}\
|
||||||
Relative paths are interpreted relative to the book's root directory.{n}\
|
Relative paths are interpreted relative to the book's root directory.{n}\
|
||||||
If omitted, mdBook uses build.build-dir from book.toml or defaults to `./book`.'",
|
If omitted, mdBook uses build.build-dir from book.toml or defaults to `./book`.",
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.arg_from_usage(
|
.arg(arg!([dir]
|
||||||
"[dir] 'Root directory for the book{n}\
|
"Root directory for the book{n}\
|
||||||
(Defaults to the Current Directory when omitted)'",
|
(Defaults to the Current Directory when omitted)"
|
||||||
)
|
))
|
||||||
.arg(Arg::with_name("library-path")
|
.arg(Arg::new("library-path")
|
||||||
.short("L")
|
.short('L')
|
||||||
.long("library-path")
|
.long("library-path")
|
||||||
.value_name("dir")
|
.value_name("dir")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
|
.use_delimiter(true)
|
||||||
.require_delimiter(true)
|
.require_delimiter(true)
|
||||||
.multiple(true)
|
.multiple_values(true)
|
||||||
.empty_values(false)
|
.multiple_occurrences(true)
|
||||||
|
.forbid_empty_values(true)
|
||||||
.help("A comma-separated list of directories to add to {n}the crate search path when building tests"))
|
.help("A comma-separated list of directories to add to {n}the crate search path when building tests"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{get_book_dir, open};
|
use crate::{get_book_dir, open};
|
||||||
use clap::{App, ArgMatches, SubCommand};
|
use clap::{arg, App, Arg, ArgMatches};
|
||||||
use mdbook::errors::Result;
|
use mdbook::errors::Result;
|
||||||
use mdbook::utils;
|
use mdbook::utils;
|
||||||
use mdbook::MDBook;
|
use mdbook::MDBook;
|
||||||
|
@ -10,19 +10,25 @@ use std::thread::sleep;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
// Create clap subcommand arguments
|
// Create clap subcommand arguments
|
||||||
pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
|
pub fn make_subcommand<'help>() -> App<'help> {
|
||||||
SubCommand::with_name("watch")
|
App::new("watch")
|
||||||
.about("Watches a book's files and rebuilds it on changes")
|
.about("Watches a book's files and rebuilds it on changes")
|
||||||
.arg_from_usage(
|
.arg(
|
||||||
"-d, --dest-dir=[dest-dir] 'Output directory for the book{n}\
|
Arg::new("dest-dir")
|
||||||
|
.short('d')
|
||||||
|
.long("dest-dir")
|
||||||
|
.value_name("dest-dir")
|
||||||
|
.help(
|
||||||
|
"Output directory for the book{n}\
|
||||||
Relative paths are interpreted relative to the book's root directory.{n}\
|
Relative paths are interpreted relative to the book's root directory.{n}\
|
||||||
If omitted, mdBook uses build.build-dir from book.toml or defaults to `./book`.'",
|
If omitted, mdBook uses build.build-dir from book.toml or defaults to `./book`.",
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.arg_from_usage(
|
.arg(arg!([dir]
|
||||||
"[dir] 'Root directory for the book{n}\
|
"Root directory for the book{n}\
|
||||||
(Defaults to the Current Directory when omitted)'",
|
(Defaults to the Current Directory when omitted)"
|
||||||
)
|
))
|
||||||
.arg_from_usage("-o, --open 'Open the compiled book in a web browser'")
|
.arg(arg!(-o --open "Opens the compiled book in a web browser"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Watch command implementation
|
// Watch command implementation
|
||||||
|
|
|
@ -533,14 +533,14 @@ pub struct HtmlConfig {
|
||||||
/// directly jumping to editing the currently viewed page.
|
/// directly jumping to editing the currently viewed page.
|
||||||
/// Contains {path} that is replaced with chapter source file path
|
/// Contains {path} that is replaced with chapter source file path
|
||||||
pub edit_url_template: Option<String>,
|
pub edit_url_template: Option<String>,
|
||||||
/// This is used as a bit of a workaround for the `mdbook serve` command.
|
/// Endpoint of websocket, for livereload usage. Value loaded from .toml file
|
||||||
/// Basically, because you set the websocket port from the command line, the
|
/// is ignored, because our code overrides this field with the value [`LIVE_RELOAD_ENDPOINT`]
|
||||||
/// `mdbook serve` command needs a way to let the HTML renderer know where
|
///
|
||||||
/// to point livereloading at, if it has been enabled.
|
/// [`LIVE_RELOAD_ENDPOINT`]: cmd::serve::LIVE_RELOAD_ENDPOINT
|
||||||
///
|
///
|
||||||
/// This config item *should not be edited* by the end user.
|
/// This config item *should not be edited* by the end user.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub livereload_url: Option<String>,
|
pub live_reload_endpoint: Option<String>,
|
||||||
/// The mapping from old pages to new pages/URLs to use when generating
|
/// The mapping from old pages to new pages/URLs to use when generating
|
||||||
/// redirects.
|
/// redirects.
|
||||||
pub redirect: HashMap<String, String>,
|
pub redirect: HashMap<String, String>,
|
||||||
|
@ -569,7 +569,7 @@ impl Default for HtmlConfig {
|
||||||
input_404: None,
|
input_404: None,
|
||||||
site_url: None,
|
site_url: None,
|
||||||
cname: None,
|
cname: None,
|
||||||
livereload_url: None,
|
live_reload_endpoint: None,
|
||||||
redirect: HashMap::new(),
|
redirect: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -588,15 +588,20 @@ impl HtmlConfig {
|
||||||
|
|
||||||
/// Configuration for how to render the print icon, print.html, and print.css.
|
/// Configuration for how to render the print icon, print.html, and print.css.
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(default, rename_all = "kebab-case")]
|
||||||
pub struct Print {
|
pub struct Print {
|
||||||
/// Whether print support is enabled.
|
/// Whether print support is enabled.
|
||||||
pub enable: bool,
|
pub enable: bool,
|
||||||
|
/// Insert page breaks between chapters. Default: `true`.
|
||||||
|
pub page_break: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Print {
|
impl Default for Print {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self { enable: true }
|
Self {
|
||||||
|
enable: true,
|
||||||
|
page_break: true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -625,6 +630,8 @@ pub struct Playground {
|
||||||
pub copy_js: bool,
|
pub copy_js: bool,
|
||||||
/// Display line numbers on playground snippets. Default: `false`.
|
/// Display line numbers on playground snippets. Default: `false`.
|
||||||
pub line_numbers: bool,
|
pub line_numbers: bool,
|
||||||
|
/// Display the run button. Default: `true`
|
||||||
|
pub runnable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Playground {
|
impl Default for Playground {
|
||||||
|
@ -634,6 +641,7 @@ impl Default for Playground {
|
||||||
copyable: true,
|
copyable: true,
|
||||||
copy_js: true,
|
copy_js: true,
|
||||||
line_numbers: false,
|
line_numbers: false,
|
||||||
|
runnable: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -776,6 +784,7 @@ mod tests {
|
||||||
copyable: true,
|
copyable: true,
|
||||||
copy_js: true,
|
copy_js: true,
|
||||||
line_numbers: false,
|
line_numbers: false,
|
||||||
|
runnable: true,
|
||||||
};
|
};
|
||||||
let html_should_be = HtmlConfig {
|
let html_should_be = HtmlConfig {
|
||||||
curly_quotes: true,
|
curly_quotes: true,
|
||||||
|
@ -806,6 +815,22 @@ mod tests {
|
||||||
assert_eq!(got.html_config().unwrap(), html_should_be);
|
assert_eq!(got.html_config().unwrap(), html_should_be);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn disable_runnable() {
|
||||||
|
let src = r#"
|
||||||
|
[book]
|
||||||
|
title = "Some Book"
|
||||||
|
description = "book book book"
|
||||||
|
authors = ["Shogo Takata"]
|
||||||
|
|
||||||
|
[output.html.playground]
|
||||||
|
runnable = false
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let got = Config::from_str(src).unwrap();
|
||||||
|
assert_eq!(got.html_config().unwrap().playground.runnable, false);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn edition_2015() {
|
fn edition_2015() {
|
||||||
let src = r#"
|
let src = r#"
|
||||||
|
@ -1150,4 +1175,24 @@ mod tests {
|
||||||
|
|
||||||
Config::from_str(src).unwrap();
|
Config::from_str(src).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn print_config() {
|
||||||
|
let src = r#"
|
||||||
|
[output.html.print]
|
||||||
|
enable = false
|
||||||
|
"#;
|
||||||
|
let got = Config::from_str(src).unwrap();
|
||||||
|
let html_config = got.html_config().unwrap();
|
||||||
|
assert_eq!(html_config.print.enable, false);
|
||||||
|
assert_eq!(html_config.print.page_break, true);
|
||||||
|
let src = r#"
|
||||||
|
[output.html.print]
|
||||||
|
page-break = false
|
||||||
|
"#;
|
||||||
|
let got = Config::from_str(src).unwrap();
|
||||||
|
let html_config = got.html_config().unwrap();
|
||||||
|
assert_eq!(html_config.print.enable, true);
|
||||||
|
assert_eq!(html_config.print.page_break, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
43
src/main.rs
43
src/main.rs
|
@ -5,7 +5,8 @@ extern crate log;
|
||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
use clap::{App, AppSettings, Arg, ArgMatches, Shell, SubCommand};
|
use clap::{App, AppSettings, Arg, ArgMatches};
|
||||||
|
use clap_complete::Shell;
|
||||||
use env_logger::Builder;
|
use env_logger::Builder;
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
use mdbook::utils;
|
use mdbook::utils;
|
||||||
|
@ -25,25 +26,31 @@ fn main() {
|
||||||
|
|
||||||
// Check which subcomamnd the user ran...
|
// Check which subcomamnd the user ran...
|
||||||
let res = match app.get_matches().subcommand() {
|
let res = match app.get_matches().subcommand() {
|
||||||
("init", Some(sub_matches)) => cmd::init::execute(sub_matches),
|
Some(("init", sub_matches)) => cmd::init::execute(sub_matches),
|
||||||
("build", Some(sub_matches)) => cmd::build::execute(sub_matches),
|
Some(("build", sub_matches)) => cmd::build::execute(sub_matches),
|
||||||
("clean", Some(sub_matches)) => cmd::clean::execute(sub_matches),
|
Some(("clean", sub_matches)) => cmd::clean::execute(sub_matches),
|
||||||
#[cfg(feature = "watch")]
|
#[cfg(feature = "watch")]
|
||||||
("watch", Some(sub_matches)) => cmd::watch::execute(sub_matches),
|
Some(("watch", sub_matches)) => cmd::watch::execute(sub_matches),
|
||||||
#[cfg(feature = "serve")]
|
#[cfg(feature = "serve")]
|
||||||
("serve", Some(sub_matches)) => cmd::serve::execute(sub_matches),
|
Some(("serve", sub_matches)) => cmd::serve::execute(sub_matches),
|
||||||
("test", Some(sub_matches)) => cmd::test::execute(sub_matches),
|
Some(("test", sub_matches)) => cmd::test::execute(sub_matches),
|
||||||
("completions", Some(sub_matches)) => (|| {
|
Some(("completions", sub_matches)) => (|| {
|
||||||
let shell: Shell = sub_matches
|
let shell: Shell = sub_matches
|
||||||
.value_of("shell")
|
.value_of("shell")
|
||||||
.ok_or_else(|| anyhow!("Shell name missing."))?
|
.ok_or_else(|| anyhow!("Shell name missing."))?
|
||||||
.parse()
|
.parse()
|
||||||
.map_err(|s| anyhow!("Invalid shell: {}", s))?;
|
.map_err(|s| anyhow!("Invalid shell: {}", s))?;
|
||||||
|
|
||||||
create_clap_app().gen_completions_to("mdbook", shell, &mut std::io::stdout().lock());
|
let mut complete_app = create_clap_app();
|
||||||
|
clap_complete::generate(
|
||||||
|
shell,
|
||||||
|
&mut complete_app,
|
||||||
|
"mdbook",
|
||||||
|
&mut std::io::stdout().lock(),
|
||||||
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
})(),
|
})(),
|
||||||
(_, _) => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(e) = res {
|
if let Err(e) = res {
|
||||||
|
@ -54,14 +61,13 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a list of valid arguments and sub-commands
|
/// Create a list of valid arguments and sub-commands
|
||||||
fn create_clap_app<'a, 'b>() -> App<'a, 'b> {
|
fn create_clap_app() -> App<'static> {
|
||||||
let app = App::new(crate_name!())
|
let app = App::new(crate_name!())
|
||||||
.about(crate_description!())
|
.about(crate_description!())
|
||||||
.author("Mathieu David <mathieudavid@mathieudavid.org>")
|
.author("Mathieu David <mathieudavid@mathieudavid.org>")
|
||||||
.version(VERSION)
|
.version(VERSION)
|
||||||
.setting(AppSettings::GlobalVersion)
|
.setting(AppSettings::PropagateVersion)
|
||||||
.setting(AppSettings::ArgRequiredElseHelp)
|
.setting(AppSettings::ArgRequiredElseHelp)
|
||||||
.setting(AppSettings::ColoredHelp)
|
|
||||||
.after_help(
|
.after_help(
|
||||||
"For more information about a specific command, try `mdbook <command> --help`\n\
|
"For more information about a specific command, try `mdbook <command> --help`\n\
|
||||||
The source code for mdBook is available at: https://github.com/rust-lang/mdBook",
|
The source code for mdBook is available at: https://github.com/rust-lang/mdBook",
|
||||||
|
@ -71,12 +77,12 @@ fn create_clap_app<'a, 'b>() -> App<'a, 'b> {
|
||||||
.subcommand(cmd::test::make_subcommand())
|
.subcommand(cmd::test::make_subcommand())
|
||||||
.subcommand(cmd::clean::make_subcommand())
|
.subcommand(cmd::clean::make_subcommand())
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("completions")
|
App::new("completions")
|
||||||
.about("Generate shell completions for your shell to stdout")
|
.about("Generate shell completions for your shell to stdout")
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("shell")
|
Arg::new("shell")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.possible_values(&Shell::variants())
|
.possible_values(Shell::possible_values())
|
||||||
.help("the shell to generate completions for")
|
.help("the shell to generate completions for")
|
||||||
.value_name("SHELL")
|
.value_name("SHELL")
|
||||||
.required(true),
|
.required(true),
|
||||||
|
@ -137,3 +143,8 @@ fn open<P: AsRef<OsStr>>(path: P) {
|
||||||
error!("Error opening web browser: {}", e);
|
error!("Error opening web browser: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn verify_app() {
|
||||||
|
create_clap_app().debug_assert();
|
||||||
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ impl HtmlHandlebars {
|
||||||
|
|
||||||
let fixed_content =
|
let fixed_content =
|
||||||
utils::render_markdown_with_path(&ch.content, ctx.html_config.curly_quotes, Some(path));
|
utils::render_markdown_with_path(&ch.content, ctx.html_config.curly_quotes, Some(path));
|
||||||
if !ctx.is_index {
|
if !ctx.is_index && ctx.html_config.print.page_break {
|
||||||
// Add page break between chapters
|
// Add page break between chapters
|
||||||
// See https://developer.mozilla.org/en-US/docs/Web/CSS/break-before and https://developer.mozilla.org/en-US/docs/Web/CSS/page-break-before
|
// See https://developer.mozilla.org/en-US/docs/Web/CSS/break-before and https://developer.mozilla.org/en-US/docs/Web/CSS/page-break-before
|
||||||
// Add both two CSS properties because of the compatibility issue
|
// Add both two CSS properties because of the compatibility issue
|
||||||
|
@ -170,6 +170,13 @@ impl HtmlHandlebars {
|
||||||
// Set a dummy path to ensure other paths (e.g. in the TOC) are generated correctly
|
// Set a dummy path to ensure other paths (e.g. in the TOC) are generated correctly
|
||||||
data_404.insert("path".to_owned(), json!("404.md"));
|
data_404.insert("path".to_owned(), json!("404.md"));
|
||||||
data_404.insert("content".to_owned(), json!(html_content_404));
|
data_404.insert("content".to_owned(), json!(html_content_404));
|
||||||
|
|
||||||
|
let mut title = String::from("Page not found");
|
||||||
|
if let Some(book_title) = &ctx.config.book.title {
|
||||||
|
title.push_str(" - ");
|
||||||
|
title.push_str(book_title);
|
||||||
|
}
|
||||||
|
data_404.insert("title".to_owned(), json!(title));
|
||||||
let rendered = handlebars.render("index", &data_404)?;
|
let rendered = handlebars.render("index", &data_404)?;
|
||||||
|
|
||||||
let rendered =
|
let rendered =
|
||||||
|
@ -606,8 +613,11 @@ fn make_data(
|
||||||
if theme.favicon_svg.is_some() {
|
if theme.favicon_svg.is_some() {
|
||||||
data.insert("favicon_svg".to_owned(), json!("favicon.svg"));
|
data.insert("favicon_svg".to_owned(), json!("favicon.svg"));
|
||||||
}
|
}
|
||||||
if let Some(ref livereload) = html_config.livereload_url {
|
if let Some(ref live_reload_endpoint) = html_config.live_reload_endpoint {
|
||||||
data.insert("livereload".to_owned(), json!(livereload));
|
data.insert(
|
||||||
|
"live_reload_endpoint".to_owned(),
|
||||||
|
json!(live_reload_endpoint),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let default_theme = match html_config.default_theme {
|
let default_theme = match html_config.default_theme {
|
||||||
|
@ -768,16 +778,7 @@ fn insert_link_into_header(
|
||||||
content: &str,
|
content: &str,
|
||||||
id_counter: &mut HashMap<String, usize>,
|
id_counter: &mut HashMap<String, usize>,
|
||||||
) -> String {
|
) -> String {
|
||||||
let raw_id = utils::id_from_content(content);
|
let id = utils::unique_id_from_content(content, id_counter);
|
||||||
|
|
||||||
let id_count = id_counter.entry(raw_id.clone()).or_insert(0);
|
|
||||||
|
|
||||||
let id = match *id_count {
|
|
||||||
0 => raw_id,
|
|
||||||
other => format!("{}-{}", raw_id, other),
|
|
||||||
};
|
|
||||||
|
|
||||||
*id_count += 1;
|
|
||||||
|
|
||||||
format!(
|
format!(
|
||||||
r##"<h{level} id="{id}"><a class="header" href="#{id}">{text}</a></h{level}>"##,
|
r##"<h{level} id="{id}"><a class="header" href="#{id}">{text}</a></h{level}>"##,
|
||||||
|
@ -828,7 +829,8 @@ fn add_playground_pre(
|
||||||
if classes.contains("language-rust") {
|
if classes.contains("language-rust") {
|
||||||
if (!classes.contains("ignore")
|
if (!classes.contains("ignore")
|
||||||
&& !classes.contains("noplayground")
|
&& !classes.contains("noplayground")
|
||||||
&& !classes.contains("noplaypen"))
|
&& !classes.contains("noplaypen")
|
||||||
|
&& playground_config.runnable)
|
||||||
|| classes.contains("mdbook-runnable")
|
|| classes.contains("mdbook-runnable")
|
||||||
{
|
{
|
||||||
let contains_e2015 = classes.contains("edition2015");
|
let contains_e2015 = classes.contains("edition2015");
|
||||||
|
|
|
@ -97,9 +97,10 @@ fn render_item(
|
||||||
|
|
||||||
breadcrumbs.push(chapter.name.clone());
|
breadcrumbs.push(chapter.name.clone());
|
||||||
|
|
||||||
|
let mut id_counter = HashMap::new();
|
||||||
while let Some(event) = p.next() {
|
while let Some(event) = p.next() {
|
||||||
match event {
|
match event {
|
||||||
Event::Start(Tag::Heading(i)) if i <= max_section_depth => {
|
Event::Start(Tag::Heading(i, ..)) if i as u32 <= max_section_depth => {
|
||||||
if !heading.is_empty() {
|
if !heading.is_empty() {
|
||||||
// Section finished, the next heading is following now
|
// Section finished, the next heading is following now
|
||||||
// Write the data to the index, and clear it for the next section
|
// Write the data to the index, and clear it for the next section
|
||||||
|
@ -118,9 +119,9 @@ fn render_item(
|
||||||
|
|
||||||
in_heading = true;
|
in_heading = true;
|
||||||
}
|
}
|
||||||
Event::End(Tag::Heading(i)) if i <= max_section_depth => {
|
Event::End(Tag::Heading(i, ..)) if i as u32 <= max_section_depth => {
|
||||||
in_heading = false;
|
in_heading = false;
|
||||||
section_id = Some(utils::id_from_content(&heading));
|
section_id = Some(utils::unique_id_from_content(&heading, &mut id_counter));
|
||||||
breadcrumbs.push(heading.clone());
|
breadcrumbs.push(heading.clone());
|
||||||
}
|
}
|
||||||
Event::Start(Tag::FootnoteDefinition(name)) => {
|
Event::Start(Tag::FootnoteDefinition(name)) => {
|
||||||
|
|
|
@ -219,10 +219,12 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#if livereload}}
|
{{#if live_reload_endpoint}}
|
||||||
<!-- Livereload script (if served using the cli tool) -->
|
<!-- Livereload script (if served using the cli tool) -->
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var socket = new WebSocket("{{{livereload}}}");
|
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||||
|
const wsAddress = wsProtocol + "//" + location.host + "/" + "{{{live_reload_endpoint}}}";
|
||||||
|
const socket = new WebSocket(wsAddress);
|
||||||
socket.onmessage = function (event) {
|
socket.onmessage = function (event) {
|
||||||
if (event.data === "reload") {
|
if (event.data === "reload") {
|
||||||
socket.close();
|
socket.close();
|
||||||
|
|
|
@ -9,6 +9,7 @@ use regex::Regex;
|
||||||
use pulldown_cmark::{html, CodeBlockKind, CowStr, Event, Options, Parser, Tag};
|
use pulldown_cmark::{html, CodeBlockKind, CowStr, Event, Options, Parser, Tag};
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
|
@ -44,6 +45,8 @@ pub fn normalize_id(content: &str) -> String {
|
||||||
|
|
||||||
/// Generate an ID for use with anchors which is derived from a "normalised"
|
/// Generate an ID for use with anchors which is derived from a "normalised"
|
||||||
/// string.
|
/// string.
|
||||||
|
// This function should be made private when the deprecation expires.
|
||||||
|
#[deprecated(since = "0.4.16", note = "use unique_id_from_content instead")]
|
||||||
pub fn id_from_content(content: &str) -> String {
|
pub fn id_from_content(content: &str) -> String {
|
||||||
let mut content = content.to_string();
|
let mut content = content.to_string();
|
||||||
|
|
||||||
|
@ -59,10 +62,30 @@ pub fn id_from_content(content: &str) -> String {
|
||||||
|
|
||||||
// Remove spaces and hashes indicating a header
|
// Remove spaces and hashes indicating a header
|
||||||
let trimmed = content.trim().trim_start_matches('#').trim();
|
let trimmed = content.trim().trim_start_matches('#').trim();
|
||||||
|
|
||||||
normalize_id(trimmed)
|
normalize_id(trimmed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate an ID for use with anchors which is derived from a "normalised"
|
||||||
|
/// string.
|
||||||
|
///
|
||||||
|
/// Each ID returned will be unique, if the same `id_counter` is provided on
|
||||||
|
/// each call.
|
||||||
|
pub fn unique_id_from_content(content: &str, id_counter: &mut HashMap<String, usize>) -> String {
|
||||||
|
let id = {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
id_from_content(content)
|
||||||
|
};
|
||||||
|
|
||||||
|
// If we have headers with the same normalized id, append an incrementing counter
|
||||||
|
let id_count = id_counter.entry(id.clone()).or_insert(0);
|
||||||
|
let unique_id = match *id_count {
|
||||||
|
0 => id,
|
||||||
|
id_count => format!("{}-{}", id, id_count),
|
||||||
|
};
|
||||||
|
*id_count += 1;
|
||||||
|
unique_id
|
||||||
|
}
|
||||||
|
|
||||||
/// Fix links to the correct location.
|
/// Fix links to the correct location.
|
||||||
///
|
///
|
||||||
/// This adjusts links, such as turning `.md` extensions to `.html`.
|
/// This adjusts links, such as turning `.md` extensions to `.html`.
|
||||||
|
@ -160,7 +183,7 @@ pub fn render_markdown(text: &str, curly_quotes: bool) -> String {
|
||||||
render_markdown_with_path(text, curly_quotes, None)
|
render_markdown_with_path(text, curly_quotes, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_cmark_parser(text: &str, curly_quotes: bool) -> Parser<'_> {
|
pub fn new_cmark_parser(text: &str, curly_quotes: bool) -> Parser<'_, '_> {
|
||||||
let mut opts = Options::empty();
|
let mut opts = Options::empty();
|
||||||
opts.insert(Options::ENABLE_TABLES);
|
opts.insert(Options::ENABLE_TABLES);
|
||||||
opts.insert(Options::ENABLE_FOOTNOTES);
|
opts.insert(Options::ENABLE_FOOTNOTES);
|
||||||
|
@ -332,8 +355,9 @@ more text with spaces
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod html_munging {
|
#[allow(deprecated)]
|
||||||
use super::super::{id_from_content, normalize_id};
|
mod id_from_content {
|
||||||
|
use super::super::id_from_content;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn it_generates_anchors() {
|
fn it_generates_anchors() {
|
||||||
|
@ -361,6 +385,10 @@ more text with spaces
|
||||||
);
|
);
|
||||||
assert_eq!(id_from_content("## Über"), "Über");
|
assert_eq!(id_from_content("## Über"), "Über");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod html_munging {
|
||||||
|
use super::super::{normalize_id, unique_id_from_content};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn it_normalizes_ids() {
|
fn it_normalizes_ids() {
|
||||||
|
@ -379,5 +407,28 @@ more text with spaces
|
||||||
assert_eq!(normalize_id("한국어"), "한국어");
|
assert_eq!(normalize_id("한국어"), "한국어");
|
||||||
assert_eq!(normalize_id(""), "");
|
assert_eq!(normalize_id(""), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn it_generates_unique_ids_from_content() {
|
||||||
|
// Same id if not given shared state
|
||||||
|
assert_eq!(
|
||||||
|
unique_id_from_content("## 中文標題 CJK title", &mut Default::default()),
|
||||||
|
"中文標題-cjk-title"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
unique_id_from_content("## 中文標題 CJK title", &mut Default::default()),
|
||||||
|
"中文標題-cjk-title"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Different id if given shared state
|
||||||
|
let mut id_counter = Default::default();
|
||||||
|
assert_eq!(unique_id_from_content("## Über", &mut id_counter), "Über");
|
||||||
|
assert_eq!(
|
||||||
|
unique_id_from_content("## 中文標題 CJK title", &mut id_counter),
|
||||||
|
"中文標題-cjk-title"
|
||||||
|
);
|
||||||
|
assert_eq!(unique_id_from_content("## Über", &mut id_counter), "Über-1");
|
||||||
|
assert_eq!(unique_id_from_content("## Über", &mut id_counter), "Über-2");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
use crate::cli::cmd::mdbook_cmd;
|
||||||
use crate::dummy_book::DummyBook;
|
use crate::dummy_book::DummyBook;
|
||||||
|
|
||||||
use assert_cmd::Command;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn mdbook_cli_dummy_book_generates_index_html() {
|
fn mdbook_cli_dummy_book_generates_index_html() {
|
||||||
let temp = DummyBook::new().build().unwrap();
|
let temp = DummyBook::new().build().unwrap();
|
||||||
|
@ -9,7 +8,7 @@ fn mdbook_cli_dummy_book_generates_index_html() {
|
||||||
// doesn't exist before
|
// doesn't exist before
|
||||||
assert!(!temp.path().join("book").exists());
|
assert!(!temp.path().join("book").exists());
|
||||||
|
|
||||||
let mut cmd = Command::cargo_bin("mdbook").unwrap();
|
let mut cmd = mdbook_cmd();
|
||||||
cmd.arg("build").current_dir(temp.path());
|
cmd.arg("build").current_dir(temp.path());
|
||||||
cmd.assert()
|
cmd.assert()
|
||||||
.success()
|
.success()
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
use assert_cmd::Command;
|
||||||
|
|
||||||
|
pub(crate) fn mdbook_cmd() -> Command {
|
||||||
|
let mut cmd = Command::cargo_bin("mdbook").unwrap();
|
||||||
|
cmd.env_remove("RUST_LOG");
|
||||||
|
cmd
|
||||||
|
}
|
|
@ -1,2 +1,3 @@
|
||||||
mod build;
|
mod build;
|
||||||
|
mod cmd;
|
||||||
mod test;
|
mod test;
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
|
use crate::cli::cmd::mdbook_cmd;
|
||||||
use crate::dummy_book::DummyBook;
|
use crate::dummy_book::DummyBook;
|
||||||
|
|
||||||
use assert_cmd::Command;
|
|
||||||
use predicates::boolean::PredicateBooleanExt;
|
use predicates::boolean::PredicateBooleanExt;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn mdbook_cli_can_correctly_test_a_passing_book() {
|
fn mdbook_cli_can_correctly_test_a_passing_book() {
|
||||||
let temp = DummyBook::new().with_passing_test(true).build().unwrap();
|
let temp = DummyBook::new().with_passing_test(true).build().unwrap();
|
||||||
|
|
||||||
let mut cmd = Command::cargo_bin("mdbook").unwrap();
|
let mut cmd = mdbook_cmd();
|
||||||
cmd.arg("test").current_dir(temp.path());
|
cmd.arg("test").current_dir(temp.path());
|
||||||
cmd.assert().success()
|
cmd.assert().success()
|
||||||
.stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]README.md""##).unwrap())
|
.stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]README.md""##).unwrap())
|
||||||
|
@ -22,7 +22,7 @@ fn mdbook_cli_can_correctly_test_a_passing_book() {
|
||||||
fn mdbook_cli_detects_book_with_failing_tests() {
|
fn mdbook_cli_detects_book_with_failing_tests() {
|
||||||
let temp = DummyBook::new().with_passing_test(false).build().unwrap();
|
let temp = DummyBook::new().with_passing_test(false).build().unwrap();
|
||||||
|
|
||||||
let mut cmd = Command::cargo_bin("mdbook").unwrap();
|
let mut cmd = mdbook_cmd();
|
||||||
cmd.arg("test").current_dir(temp.path());
|
cmd.arg("test").current_dir(temp.path());
|
||||||
cmd.assert().failure()
|
cmd.assert().failure()
|
||||||
.stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]README.md""##).unwrap())
|
.stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]README.md""##).unwrap())
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
- [Markdown](first/markdown.md)
|
- [Markdown](first/markdown.md)
|
||||||
- [Unicode](first/unicode.md)
|
- [Unicode](first/unicode.md)
|
||||||
- [No Headers](first/no-headers.md)
|
- [No Headers](first/no-headers.md)
|
||||||
|
- [Duplicate Headers](first/duplicate-headers.md)
|
||||||
- [Second Chapter](second.md)
|
- [Second Chapter](second.md)
|
||||||
- [Nested Chapter](second/nested.md)
|
- [Nested Chapter](second/nested.md)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Duplicate headers
|
||||||
|
|
||||||
|
This page validates behaviour of duplicate headers.
|
||||||
|
|
||||||
|
# Header Text
|
||||||
|
|
||||||
|
# Header Text
|
||||||
|
|
||||||
|
# header-text
|
|
@ -17,6 +17,7 @@ use std::ffi::OsStr;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::{Component, Path, PathBuf};
|
use std::path::{Component, Path, PathBuf};
|
||||||
|
use std::str::FromStr;
|
||||||
use tempfile::Builder as TempFileBuilder;
|
use tempfile::Builder as TempFileBuilder;
|
||||||
use walkdir::{DirEntry, WalkDir};
|
use walkdir::{DirEntry, WalkDir};
|
||||||
|
|
||||||
|
@ -35,6 +36,7 @@ const TOC_SECOND_LEVEL: &[&str] = &[
|
||||||
"1.4. Markdown",
|
"1.4. Markdown",
|
||||||
"1.5. Unicode",
|
"1.5. Unicode",
|
||||||
"1.6. No Headers",
|
"1.6. No Headers",
|
||||||
|
"1.7. Duplicate Headers",
|
||||||
"2.1. Nested Chapter",
|
"2.1. Nested Chapter",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -150,6 +152,25 @@ fn rendered_code_has_playground_stuff() {
|
||||||
assert_contains_strings(book_js, &[".playground"]);
|
assert_contains_strings(book_js, &[".playground"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rendered_code_does_not_have_playground_stuff_in_html_when_disabled_in_config() {
|
||||||
|
let temp = DummyBook::new().build().unwrap();
|
||||||
|
let config = Config::from_str(
|
||||||
|
"
|
||||||
|
[output.html.playground]
|
||||||
|
runnable = false
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let md = MDBook::load_with_config(temp.path(), config).unwrap();
|
||||||
|
md.build().unwrap();
|
||||||
|
|
||||||
|
let nested = temp.path().join("book/first/nested.html");
|
||||||
|
let playground_class = vec![r#"class="playground""#];
|
||||||
|
|
||||||
|
assert_doesnt_contain_strings(nested, &playground_class);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn anchors_include_text_between_but_not_anchor_comments() {
|
fn anchors_include_text_between_but_not_anchor_comments() {
|
||||||
let temp = DummyBook::new().build().unwrap();
|
let temp = DummyBook::new().build().unwrap();
|
||||||
|
@ -633,11 +654,12 @@ mod search {
|
||||||
let some_section = get_doc_ref("first/index.html#some-section");
|
let some_section = get_doc_ref("first/index.html#some-section");
|
||||||
let summary = get_doc_ref("first/includes.html#summary");
|
let summary = get_doc_ref("first/includes.html#summary");
|
||||||
let no_headers = get_doc_ref("first/no-headers.html");
|
let no_headers = get_doc_ref("first/no-headers.html");
|
||||||
|
let duplicate_headers_1 = get_doc_ref("first/duplicate-headers.html#header-text-1");
|
||||||
let conclusion = get_doc_ref("conclusion.html#conclusion");
|
let conclusion = get_doc_ref("conclusion.html#conclusion");
|
||||||
|
|
||||||
let bodyidx = &index["index"]["index"]["body"]["root"];
|
let bodyidx = &index["index"]["index"]["body"]["root"];
|
||||||
let textidx = &bodyidx["t"]["e"]["x"]["t"];
|
let textidx = &bodyidx["t"]["e"]["x"]["t"];
|
||||||
assert_eq!(textidx["df"], 2);
|
assert_eq!(textidx["df"], 5);
|
||||||
assert_eq!(textidx["docs"][&first_chapter]["tf"], 1.0);
|
assert_eq!(textidx["docs"][&first_chapter]["tf"], 1.0);
|
||||||
assert_eq!(textidx["docs"][&introduction]["tf"], 1.0);
|
assert_eq!(textidx["docs"][&introduction]["tf"], 1.0);
|
||||||
|
|
||||||
|
@ -646,7 +668,7 @@ mod search {
|
||||||
assert_eq!(docs[&some_section]["body"], "");
|
assert_eq!(docs[&some_section]["body"], "");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
docs[&summary]["body"],
|
docs[&summary]["body"],
|
||||||
"Dummy Book Introduction First Chapter Nested Chapter Includes Recursive Markdown Unicode No Headers Second Chapter Nested Chapter Conclusion"
|
"Dummy Book Introduction First Chapter Nested Chapter Includes Recursive Markdown Unicode No Headers Duplicate Headers Second Chapter Nested Chapter Conclusion"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
docs[&summary]["breadcrumbs"],
|
docs[&summary]["breadcrumbs"],
|
||||||
|
@ -657,6 +679,10 @@ mod search {
|
||||||
docs[&no_headers]["breadcrumbs"],
|
docs[&no_headers]["breadcrumbs"],
|
||||||
"First Chapter » No Headers"
|
"First Chapter » No Headers"
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
docs[&duplicate_headers_1]["breadcrumbs"],
|
||||||
|
"First Chapter » Duplicate Headers » Header Text"
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
docs[&no_headers]["body"],
|
docs[&no_headers]["body"],
|
||||||
"Capybara capybara capybara. Capybara capybara capybara."
|
"Capybara capybara capybara. Capybara capybara capybara."
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue