diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bd3c7558..bfd114ca 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -31,7 +31,8 @@ jobs: rust: stable - build: msrv os: ubuntu-latest - rust: 1.46.0 + # sync MSRV with docs: guide/src/guide/installation.md + rust: 1.54.0 steps: - uses: actions/checkout@master - name: Install Rust @@ -48,4 +49,4 @@ jobs: - uses: actions/checkout@master - name: Install Rust run: rustup update stable && rustup default stable && rustup component add rustfmt - - run: cargo fmt -- --check + - run: cargo fmt --check diff --git a/CHANGELOG.md b/CHANGELOG.md index 83e7818f..87d281c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,50 @@ # 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 . + [#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 [ffa8284...c9b6be8](https://github.com/rust-lang/mdBook/compare/ffa8284...c9b6be8) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 924cfdba..72010ad2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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. 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. 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. diff --git a/Cargo.lock b/Cargo.lock index ea59887b..2428b308 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -185,17 +185,27 @@ dependencies = [ [[package]] name = "clap" -version = "2.33.3" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +checksum = "7a30c3bf9ff12dfe5dae53f0a96e0febcd18420d1c0e7fad77796d9d5c4b5375" dependencies = [ - "ansi_term", "atty", "bitflags", + "indexmap", + "lazy_static", + "os_str_bytes", "strsim", + "termcolor", "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]] @@ -473,15 +483,6 @@ dependencies = [ "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]] name = "getrandom" version = "0.1.16" @@ -839,13 +840,14 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "mdbook" -version = "0.4.14" +version = "0.4.17" dependencies = [ "ammonia", "anyhow", "assert_cmd", "chrono", "clap", + "clap_complete", "elasticlunr-rs", "env_logger", "futures-util", @@ -1062,6 +1064,15 @@ dependencies = [ "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]] name = "output_vt100" version = "0.1.2" @@ -1267,12 +1278,11 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8" +checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6" dependencies = [ "bitflags", - "getopts", "memchr", "unicase", ] @@ -1400,9 +1410,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ "aho-corasick", "memchr", @@ -1464,21 +1474,9 @@ dependencies = [ [[package]] name = "semver" -version = "0.11.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -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", -] +checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" [[package]] name = "serde" @@ -1600,9 +1598,9 @@ dependencies = [ [[package]] name = "strsim" -version = "0.8.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strum" @@ -1669,12 +1667,9 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.11.0" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] +checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" [[package]] name = "time" @@ -1882,12 +1877,6 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" -[[package]] -name = "unicode-width" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" - [[package]] name = "unicode-xid" version = "0.2.2" @@ -1912,12 +1901,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - [[package]] name = "version_check" version = "0.9.3" diff --git a/Cargo.toml b/Cargo.toml index fc5e1b16..15f0e5ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mdbook" -version = "0.4.14" +version = "0.4.17" authors = [ "Mathieu David ", "Michael-F-Bryan ", @@ -18,15 +18,16 @@ description = "Creates a book from markdown files" [dependencies] anyhow = "1.0.28" chrono = "0.4" -clap = "2.24" +clap = { version = "3.0", features = ["cargo"] } +clap_complete = "3.0" env_logger = "0.7.1" handlebars = "4.0" lazy_static = "1.0" log = "0.4" memchr = "2.0" opener = "0.5" -pulldown-cmark = "0.8.0" -regex = "1.0.0" +pulldown-cmark = { version = "0.9.1", default-features = false } +regex = "1.5.5" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" @@ -52,7 +53,7 @@ ammonia = { version = "3", optional = true } assert_cmd = "1" predicates = "2" select = "0.5" -semver = "0.11.0" +semver = "1.0" pretty_assertions = "0.6" walkdir = "2.0" diff --git a/README.md b/README.md index c70cf225..b2177cf3 100644 --- a/README.md +++ b/README.md @@ -6,233 +6,15 @@ 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? - -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 ` - - The init command will create a directory with the minimal boilerplate to - start with. If the `` 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`. - +If you are interested in contributing to the development of mdBook, check out the [Contribution Guide]. ## 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. - [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 [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 diff --git a/examples/nop-preprocessor.rs b/examples/nop-preprocessor.rs index 486fd86d..ace40093 100644 --- a/examples/nop-preprocessor.rs +++ b/examples/nop-preprocessor.rs @@ -1,5 +1,5 @@ use crate::nop_lib::Nop; -use clap::{App, Arg, ArgMatches, SubCommand}; +use clap::{App, Arg, ArgMatches}; use mdbook::book::Book; use mdbook::errors::Error; use mdbook::preprocess::{CmdPreprocessor, Preprocessor, PreprocessorContext}; @@ -7,12 +7,12 @@ use semver::{Version, VersionReq}; use std::io; use std::process; -pub fn make_app() -> App<'static, 'static> { +pub fn make_app() -> App<'static> { App::new("nop-preprocessor") .about("A mdbook preprocessor which does precisely nothing") .subcommand( - SubCommand::with_name("supports") - .arg(Arg::with_name("renderer").required(true)) + App::new("supports") + .arg(Arg::new("renderer").required(true)) .about("Check whether a renderer is supported by this preprocessor"), ) } diff --git a/guide/src/README.md b/guide/src/README.md index 7bbfd995..a3aeb68d 100644 --- a/guide/src/README.md +++ b/guide/src/README.md @@ -1,22 +1,30 @@ # Introduction -**mdBook** is a command line tool and Rust crate to create books with Markdown. The output resembles tools like Gitbook, -and 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 -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** is a command line tool to create books with Markdown. +It is ideal for creating product or API documentation, tutorials, course materials or anything that requires a clean, +easily navigable and customizable presentation. -mdBook includes built in support for both preprocessing your Markdown and alternative renderers for producing formats -other than HTML. These facilities also enable other functionality such as -validation. [Searching](https://crates.io/search?q=mdbook&sort=relevance) Rust's [crates.io](https://crates.io) is a -great way to discover more extensions. +* Lightweight [Markdown] syntax helps you focus more on your content +* Integrated [search] support +* Color [syntax highlighting] for code blocks for many different languages +* [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 -write your own preprocessor or renderer, as well as incorporate mdBook features into other applications. -The [For Developers](for_developers) section of this guide contains more information and some examples. +[Markdown]: format/markdown.md +[search]: guide/reading.md#search +[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 diff --git a/guide/src/SUMMARY.md b/guide/src/SUMMARY.md index 181d7972..974d65fa 100644 --- a/guide/src/SUMMARY.md +++ b/guide/src/SUMMARY.md @@ -1,6 +1,15 @@ # 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) - [init](cli/init.md) - [build](cli/build.md) @@ -8,6 +17,7 @@ - [serve](cli/serve.md) - [test](cli/test.md) - [clean](cli/clean.md) + - [completions](cli/completions.md) - [Format](format/README.md) - [SUMMARY.md](format/summary.md) - [Draft chapter]() diff --git a/guide/src/cli/README.md b/guide/src/cli/README.md index 9fc7c2a9..2fbe3781 100644 --- a/guide/src/cli/README.md +++ b/guide/src/cli/README.md @@ -1,55 +1,14 @@ # Command Line Tool -mdBook can be used either as a command line tool or a [Rust -crate](https://crates.io/crates/mdbook). Let's focus on the command line tool -capabilities first. +The `mdbook` command-line tool is used to create and build books. +After you have [installed](../guide/installation.md) `mdbook`, you can run the `mdbook help` command in your terminal to view the available commands. -## 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. -Visit [the releases page](https://github.com/rust-lang/mdBook/releases) -to download the appropriate version for your platform. - -## Install From Source - -mdBook can also be installed by compiling the source code on your local machine. - -### 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. +* [`mdbook init `](init.md) — Creates a new book with minimal boilerplate to start with. +* [`mdbook build`](build.md) — Renders the book. +* [`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. +* [`mdbook test`](test.md) — Tests Rust code samples. +* [`mdbook clean`](clean.md) — Deletes the rendered output. +* [`mdbook completions`](completions.md) — Support for shell auto-completion. diff --git a/guide/src/cli/completions.md b/guide/src/cli/completions.md new file mode 100644 index 00000000..1246b1ee --- /dev/null +++ b/guide/src/cli/completions.md @@ -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. diff --git a/guide/src/continuous-integration.md b/guide/src/continuous-integration.md index ce075040..0196200c 100644 --- a/guide/src/continuous-integration.md +++ b/guide/src/continuous-integration.md @@ -1,154 +1,121 @@ # Running `mdbook` in Continuous Integration -While the following examples use Travis CI, their principles should -straightforwardly transfer to other continuous integration providers as well. +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. -## 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 -build` and `mdbook test` run successfully. The key to fast CI turnaround times -is caching `mdbook` installs, so that you aren't compiling `mdbook` on every CI -run. +[GitHub Actions]: https://docs.github.com/en/actions +[GitLab CI/CD]: https://docs.gitlab.com/ee/ci/ +[Automated Deployment]: https://github.com/rust-lang/mdBook/wiki/Automated-Deployment -```yaml -language: rust -sudo: false +## Installing mdBook -cache: - - cargo +There are several different strategies for installing mdBook. +The particular method depends on your needs and preferences. -rust: - - stable +### Pre-compiled binaries -before_script: - - (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update) - - (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.3" mdbook) - - cargo install-update -a +Perhaps the easiest method is to use the pre-compiled binaries found on the [GitHub Releases page][releases]. +A simple approach would be to use the popular `curl` CLI tool to download the executable: -script: - - mdbook build && mdbook test # In case of custom book path: mdbook build path/to/mybook && mdbook test path/to/mybook +```sh +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 -pages after a successful CI run on your repository's `master` branch. +* This is relatively fast, and does not necessarily require dealing with caching. +* 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" -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. +[releases]: https://github.com/rust-lang/mdBook/releases -Whilst still in your repository's settings page, navigate to Options and change the -Source on GitHub pages to `gh-pages`. +### Building from source -Then, append this snippet to your `.travis.yml` and update the path to the -`book` directory: +Building from source will require having Rust installed. +Some services have Rust pre-installed, but if your service does not, you will need to add a step to install it. -```yaml -deploy: - provider: pages - skip-cleanup: true - github-token: $GITHUB_TOKEN - local-dir: book # In case of custom book path: path/to/mybook/book - keep-history: false - on: - branch: main +After Rust is installed, `cargo install` can be used to build and install mdBook. +We recommend using a SemVer version specifier so that you get the latest **non-breaking** version of mdBook. +For example: + +```sh +cargo install mdbook --no-default-features --features search --vers "^0.4" --locked ``` -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 -language: rust -os: linux -dist: xenial +You will likely want to investigate caching options, as building mdBook can be somewhat slow. -cache: - - cargo +[search]: guide/reading.md#search -rust: - - stable +## Running tests -before_script: - - (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update) - - (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.3" mdbook) - - cargo install-update -a +You may want to run tests using [`mdbook test`] every time you push a change or create a pull request. +This can be used to validate Rust code examples in the book. -script: - - mdbook build && mdbook test # In case of custom book path: mdbook build path/to/mybook && mdbook test path/to/mybook - -deploy: - provider: pages - strategy: git - edge: true - cleanup: false - github-token: $GITHUB_TOKEN - local-dir: book # In case of custom book path: path/to/mybook/book - keep-history: false - on: - branch: main - target_branch: gh-pages +This will require having Rust installed. +Some services have Rust pre-installed, but if your service does not, you will need to add a step to install it. + +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. + +You may also want to consider running other kinds of tests, like [mdbook-linkcheck] which will check for broken links. +Or if you have your own style checks, spell checker, or any other tests it might be good to run them in CI. + +[`mdbook test`]: cli/test.md +[mdbook-linkcheck]: https://github.com/Michael-F-Bryan/mdbook-linkcheck#continuous-integration + +## Deploying + +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 , 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 -with integrations such as Github Pages: - *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! +[`output.html.site-url`]: format/configuration/renderers.md#html-renderer-options +[`output.html.input-404`]: format/configuration/renderers.md#html-renderer-options diff --git a/guide/src/for_developers/README.md b/guide/src/for_developers/README.md index 14a56d55..d8b97709 100644 --- a/guide/src/for_developers/README.md +++ b/guide/src/for_developers/README.md @@ -24,8 +24,9 @@ The process of rendering a book project goes through several steps. exist - Load the book chapters into memory - Discover which preprocessors/backends should be used -2. Run the preprocessors -3. Call each backend in turn +2. For each backend: + 1. Run all the preprocessors. + 2. Call the backend to render the processed result. ## Using `mdbook` as a Library diff --git a/guide/src/for_developers/backends.md b/guide/src/for_developers/backends.md index fcc44a47..78326a36 100644 --- a/guide/src/for_developers/backends.md +++ b/guide/src/for_developers/backends.md @@ -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 information it is free to do whatever it wants. -There are already several alternative backends on GitHub which can be used as a -rough example of how this is accomplished in practice. +See [Configuring Renderers](../format/configuration/renderers.md) for more information about using backends. -- [mdbook-linkcheck] - a simple program for verifying the book doesn't contain - any broken links -- [mdbook-epub] - an EPUB renderer -- [mdbook-test] - a program to run the book's contents through [rust-skeptic] to - verify everything compiles and runs correctly (similar to `rustdoc --test`) -- [mdbook-man] - generate manual pages from the book +The community has developed several backends. +See the [Third Party Plugins] wiki page for a list of available backends. + +## Setting Up 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 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 dependency. @@ -330,39 +324,6 @@ generation or a warning). All environment variables are passed through to the backend, allowing you to use 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 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. -[mdbook-linkcheck]: https://github.com/Michael-F-Bryan/mdbook-linkcheck -[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 +[Third Party Plugins]: https://github.com/rust-lang/mdBook/wiki/Third-party-plugins [`RenderContext`]: https://docs.rs/mdbook/*/mdbook/renderer/struct.RenderContext.html [`RenderContext::from_json()`]: https://docs.rs/mdbook/*/mdbook/renderer/struct.RenderContext.html#method.from_json [`semver`]: https://crates.io/crates/semver diff --git a/guide/src/for_developers/preprocessors.md b/guide/src/for_developers/preprocessors.md index 074d1c3c..1ac46256 100644 --- a/guide/src/for_developers/preprocessors.md +++ b/guide/src/for_developers/preprocessors.md @@ -5,35 +5,18 @@ book is loaded and before it gets rendered, allowing you to update and mutate the book. Possible use cases are: - 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 mathjax equivalents +See [Configuring Preprocessors](../format/configuration/preprocessors.md) for more information about using preprocessors. ## Hooking Into MDBook 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 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. 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. @@ -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, you'll probably want to process the input into something more computer-friendly. 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. The following code block shows how to remove all emphasis from markdown, diff --git a/guide/src/format/configuration/general.md b/guide/src/format/configuration/general.md index 1c3884fb..b1fe49e4 100644 --- a/guide/src/format/configuration/general.md +++ b/guide/src/format/configuration/general.md @@ -62,6 +62,11 @@ language = "en" Options for the Rust language, relevant to running tests and playground integration. +```toml +[rust] +edition = "2015" # the default edition for code blocks +``` + - **edition**: Rust edition to use by default for the code snippets. Default is "2015". Individual code blocks can be controlled with the `edition2015`, `edition2018` or `edition2021` annotations, such as: @@ -77,8 +82,16 @@ integration. 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 `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` 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 diff --git a/guide/src/format/configuration/preprocessors.md b/guide/src/format/configuration/preprocessors.md index 8d3e1dc6..f44bdd4f 100644 --- a/guide/src/format/configuration/preprocessors.md +++ b/guide/src/format/configuration/preprocessors.md @@ -1,51 +1,58 @@ # 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. + See [Including files] for more. - `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 rendered book. +The built-in preprocessors can be disabled with the [`build.use-default-preprocessors`] config option. -**book.toml** -```toml -[build] -build-dir = "build" -create-missing = false +The community has developed several preprocessors. +See the [Third Party Plugins] wiki page for a list of available preprocessors. -[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. -`[preprocessor.mathjax]`). In the section, you may then pass extra -configuration to the preprocessor by adding key-value pairs to the table. - -For example +Preprocessors can be added by including a `preprocessor` table in `book.toml` with the name of the preprocessor. +For example, if you have a preprocessor called `mdbook-example`, then you can include it with: ```toml -[preprocessor.links] -# set the renderers this preprocessor will run for -renderers = ["html"] -some_extra_feature = true +[preprocessor.example] ``` -#### 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 binding the two together. ```toml -[preprocessor.mathjax] -renderers = ["html"] # mathjax only makes sense with the HTML renderer +[preprocessor.example] +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, `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" ``` -### Require A Certain Order +## Require A Certain Order 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: diff --git a/guide/src/format/configuration/renderers.md b/guide/src/format/configuration/renderers.md index df105c8d..f1d5ee15 100644 --- a/guide/src/format/configuration/renderers.md +++ b/guide/src/format/configuration/renderers.md @@ -1,9 +1,115 @@ # 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 -renderer need to be specified under the TOML table `[output.html]`. +The following backends are built-in: + +* [`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: @@ -30,34 +136,22 @@ The following configuration options are available: - **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 will be loaded alongside the default one. -- **print:** A subtable for configuration print settings. mdBook by default adds - 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 +- **no-section-label:** mdBook by defaults adds numeric section labels in the table of contents column. For example, "1.", "2.1". Set this option to true to disable 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 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 - repository link. Defaults to `fa-github`. + repository link. Defaults to `fa-github` which looks like . + If you are not using GitHub, another option to consider is `fa-code-fork` which looks like . - **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 ) for directly jumping to editing the currently viewed page. For e.g. GitHub projects set this to `https://github.com///edit/master/{path}` or for Bitbucket projects set it to `https://bitbucket.org///src/master/{path}?mode=edit` where {path} will be replaced with the full path of the file in the 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. The corresponding output file will be the same, with the extension replaced with `html`. 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 -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 ) 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 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. Defaults to `false`. - **level:** The higher the more folded regions are open. When level is 0, all 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`. - **copyable:** Display the copy button on code snippets. Defaults to `true`. - **copy-js:** Copy JavaScript files for the editor to the output directory. 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`. +- **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/ -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`. - **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 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 -[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] "/appendices/bibliography.html" = "https://rustc-dev-guide.rust-lang.org/appendix/bibliography.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 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 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 diff --git a/guide/src/format/markdown.md b/guide/src/format/markdown.md index 74ecaf56..963a1538 100644 --- a/guide/src/format/markdown.md +++ b/guide/src/format/markdown.md @@ -1,7 +1,7 @@ # Markdown -mdBook's [parser](https://github.com/raphlinus/pulldown-cmark) adheres to the [CommonMark](https://commonmark.org/) -specification. You can take a quick [tutorial](https://commonmark.org/help/tutorial/), +mdBook's [parser](https://github.com/raphlinus/pulldown-cmark) adheres to the [CommonMark](https://commonmark.org/) specification with some extensions described below. +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 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). @@ -84,6 +84,20 @@ Read about [mdBook](mdBook.md). A bare url: . +---- + +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 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) +## 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 diff --git a/guide/src/format/mdbook.md b/guide/src/format/mdbook.md index 6c691473..62e89843 100644 --- a/guide/src/format/mdbook.md +++ b/guide/src/format/mdbook.md @@ -4,6 +4,7 @@ There is a feature in mdBook that lets you hide code lines by prepending them 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 @@ -27,6 +28,67 @@ Will render as # } ``` +The code block has an eyeball icon () which will toggle the visibility of the hidden lines. + +## Rust Playground + +Rust language code blocks will automatically get a play button () 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 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}} +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/ ## Controlling page \ diff --git a/guide/src/format/theme/README.md b/guide/src/format/theme/README.md index c298272a..4a776e60 100644 --- a/guide/src/format/theme/README.md +++ b/guide/src/format/theme/README.md @@ -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 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 [`output.html.preferred-dark-theme`] in the config, which defaults to the built-in `navy` theme. diff --git a/guide/src/format/theme/editor.md b/guide/src/format/theme/editor.md index 04f6cc91..9294dd44 100644 --- a/guide/src/format/theme/editor.md +++ b/guide/src/format/theme/editor.md @@ -12,12 +12,14 @@ editable = true To make a specific block available for editing, the attribute `editable` needs to be added to it: -
```rust,editable
+~~~markdown
+```rust,editable
 fn main() {
     let number = 5;
     print!("{}", number);
 }
-```
+``` +~~~ The above will result in this editable playground: diff --git a/guide/src/guide/README.md b/guide/src/guide/README.md new file mode 100644 index 00000000..90deb10e --- /dev/null +++ b/guide/src/guide/README.md @@ -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) diff --git a/guide/src/guide/creating.md b/guide/src/guide/creating.md new file mode 100644 index 00000000..f68a8c60 --- /dev/null +++ b/guide/src/guide/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. \ No newline at end of file diff --git a/guide/src/guide/installation.md b/guide/src/guide/installation.md new file mode 100644 index 00000000..d7946587 --- /dev/null +++ b/guide/src/guide/installation.md @@ -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 diff --git a/guide/src/guide/reading.md b/guide/src/guide/reading.md new file mode 100644 index 00000000..cab3a865 --- /dev/null +++ b/guide/src/guide/reading.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 | +|------|-------------| +| | Opens and closes the chapter listing sidebar. | +| | Opens a picker to choose a different color theme. | +| | Opens a search bar for searching within the book. | +| | Instructs the web browser to print the entire book. | +| | Opens a link to the website that hosts the source code of the book. | +| | 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 () 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 | +|------|-------------| +| | Copies the code block into your local clipboard, to allow pasting into another application. | +| | For Rust code examples, this will execute the sample code and display the compiler output just below the example (see [playground]). | +| | 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]). | +| | 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 diff --git a/guide/src/misc/introduction.md b/guide/src/misc/introduction.md deleted file mode 100644 index 36495382..00000000 --- a/guide/src/misc/introduction.md +++ /dev/null @@ -1,3 +0,0 @@ -# Introduction - -A frontmatter chapter. diff --git a/src/book/summary.rs b/src/book/summary.rs index 981e1079..4bb8e969 100644 --- a/src/book/summary.rs +++ b/src/book/summary.rs @@ -1,6 +1,6 @@ use crate::errors::*; 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::iter::FromIterator; use std::ops::{Deref, DerefMut}; @@ -161,7 +161,7 @@ impl From for SummaryItem { /// > match the following regex: "[^<>\n[]]+". struct SummaryParser<'a> { src: &'a str, - stream: pulldown_cmark::OffsetIter<'a>, + stream: pulldown_cmark::OffsetIter<'a, 'a>, offset: usize, /// 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 { match self.next_event() { Some(ev @ Event::Start(Tag::List(..))) - | Some(ev @ Event::Start(Tag::Heading(1))) => { + | Some(ev @ Event::Start(Tag::Heading(HeadingLevel::H1, ..))) => { if is_prefix { // we've finished prefix chapters and are at the start // of the numbered section. @@ -302,10 +302,10 @@ impl<'a> SummaryParser<'a> { break; } - Some(Event::Start(Tag::Heading(1))) => { + Some(Event::Start(Tag::Heading(HeadingLevel::H1, ..))) => { 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)) } @@ -375,7 +375,7 @@ impl<'a> SummaryParser<'a> { } // 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. - Some(ev @ Event::Start(Tag::Heading(1))) => { + Some(ev @ Event::Start(Tag::Heading(HeadingLevel::H1, ..))) => { // we're starting a new part self.back(ev); break; @@ -527,15 +527,19 @@ impl<'a> SummaryParser<'a> { fn parse_title(&mut self) -> Option { loop { match self.next_event() { - Some(Event::Start(Tag::Heading(1))) => { + Some(Event::Start(Tag::Heading(HeadingLevel::H1, ..))) => { 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)); } // Skip a HTML element such as a comment line. Some(Event::Html(_)) => {} // Otherwise, no title. + Some(ev) => { + self.back(ev); + return None; + } _ => return None, } } @@ -647,6 +651,18 @@ mod tests { 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] fn parse_title_with_styling() { let src = "# My **Awesome** Summary"; diff --git a/src/cmd/build.rs b/src/cmd/build.rs index e9112f9b..dacf45cf 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -1,23 +1,29 @@ use crate::{get_book_dir, open}; -use clap::{App, ArgMatches, SubCommand}; +use clap::{arg, App, Arg, ArgMatches}; use mdbook::errors::Result; use mdbook::MDBook; use std::path::Path; // Create clap subcommand arguments -pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> { - SubCommand::with_name("build") +pub fn make_subcommand<'help>() -> App<'help> { + App::new("build") .about("Builds a book from its markdown files") - .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( + 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}\ + 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_from_usage("-o, --open 'Opens the compiled book in a web browser'") + .arg(arg!([dir] + "Root directory for the book{n}\ + (Defaults to the Current Directory when omitted)" + )) + .arg(arg!(-o --open "Opens the compiled book in a web browser")) } // Build command implementation diff --git a/src/cmd/clean.rs b/src/cmd/clean.rs index b58f937e..0569726e 100644 --- a/src/cmd/clean.rs +++ b/src/cmd/clean.rs @@ -1,23 +1,28 @@ use crate::get_book_dir; use anyhow::Context; -use clap::{App, ArgMatches, SubCommand}; +use clap::{arg, App, Arg, ArgMatches}; use mdbook::MDBook; use std::fs; // Create clap subcommand arguments -pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> { - SubCommand::with_name("clean") +pub fn make_subcommand<'help>() -> App<'help> { + App::new("clean") .about("Deletes a built book") - .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}\ - Running this command deletes this 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::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}\ + 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)" + )) } // Clean command implementation diff --git a/src/cmd/init.rs b/src/cmd/init.rs index ed0aa17d..1ee5ff21 100644 --- a/src/cmd/init.rs +++ b/src/cmd/init.rs @@ -1,5 +1,5 @@ use crate::get_book_dir; -use clap::{App, Arg, ArgMatches, SubCommand}; +use clap::{arg, App, Arg, ArgMatches}; use mdbook::config; use mdbook::errors::Result; use mdbook::MDBook; @@ -8,25 +8,25 @@ use std::io::Write; use std::process::Command; // Create clap subcommand arguments -pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> { - SubCommand::with_name("init") +pub fn make_subcommand<'help>() -> App<'help> { + App::new("init") .about("Creates the boilerplate structure and files for a new book") // the {n} denotes a newline which will properly aligned in all help messages - .arg_from_usage( - "[dir] 'Directory to create the book in{n}\ - (Defaults to the Current Directory when omitted)'", - ) - .arg_from_usage("--theme 'Copies the default theme into your source folder'") - .arg_from_usage("--force 'Skips confirmation prompts'") + .arg(arg!([dir] + "Directory to create the book in{n}\ + (Defaults to the Current Directory when omitted)" + )) + .arg(arg!(--theme "Copies the default theme into your source folder")) + .arg(arg!(--force "Skips confirmation prompts")) .arg( - Arg::with_name("title") + Arg::new("title") .long("title") .takes_value(true) .help("Sets the book title") .required(false), ) .arg( - Arg::with_name("ignore") + Arg::new("ignore") .long("ignore") .takes_value(true) .possible_values(&["none", "git"]) diff --git a/src/cmd/serve.rs b/src/cmd/serve.rs index c5394f8a..bafbfd52 100644 --- a/src/cmd/serve.rs +++ b/src/cmd/serve.rs @@ -1,7 +1,7 @@ #[cfg(feature = "watch")] use super::watch; 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::StreamExt; use mdbook::errors::*; @@ -18,37 +18,43 @@ use warp::Filter; const LIVE_RELOAD_ENDPOINT: &str = "__livereload"; // Create clap subcommand arguments -pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> { - SubCommand::with_name("serve") +pub fn make_subcommand<'help>() -> App<'help> { + App::new("serve") .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::with_name("hostname") - .short("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}\ + 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") .takes_value(true) .default_value("localhost") - .empty_values(false) + .forbid_empty_values(true) .help("Hostname to listen on for HTTP connections"), ) .arg( - Arg::with_name("port") - .short("p") + Arg::new("port") + .short('p') .long("port") .takes_value(true) .default_value("3000") - .empty_values(false) + .forbid_empty_values(true) .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 @@ -62,11 +68,10 @@ pub fn execute(args: &ArgMatches) -> Result<()> { let address = format!("{}:{}", hostname, port); - let livereload_url = format!("ws://{}/{}", address, LIVE_RELOAD_ENDPOINT); let update_config = |book: &mut MDBook| { book.config - .set("output.html.livereload-url", &livereload_url) - .expect("livereload-url update failed"); + .set("output.html.live-reload-endpoint", &LIVE_RELOAD_ENDPOINT) + .expect("live-reload-endpoint update failed"); if let Some(dest_dir) = args.value_of("dest-dir") { book.config.build.build_dir = dest_dir.into(); } diff --git a/src/cmd/test.rs b/src/cmd/test.rs index f6d97aa6..02f982a4 100644 --- a/src/cmd/test.rs +++ b/src/cmd/test.rs @@ -1,29 +1,37 @@ use crate::get_book_dir; -use clap::{App, Arg, ArgMatches, SubCommand}; +use clap::{arg, App, Arg, ArgMatches}; use mdbook::errors::Result; use mdbook::MDBook; // Create clap subcommand arguments -pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> { - SubCommand::with_name("test") +pub fn make_subcommand<'help>() -> App<'help> { + App::new("test") .about("Tests that a book's Rust code samples compile") - .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( + 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}\ + 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::with_name("library-path") - .short("L") + .arg(arg!([dir] + "Root directory for the book{n}\ + (Defaults to the Current Directory when omitted)" + )) + .arg(Arg::new("library-path") + .short('L') .long("library-path") .value_name("dir") .takes_value(true) + .use_delimiter(true) .require_delimiter(true) - .multiple(true) - .empty_values(false) + .multiple_values(true) + .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")) } diff --git a/src/cmd/watch.rs b/src/cmd/watch.rs index b27516b0..78ae1968 100644 --- a/src/cmd/watch.rs +++ b/src/cmd/watch.rs @@ -1,5 +1,5 @@ use crate::{get_book_dir, open}; -use clap::{App, ArgMatches, SubCommand}; +use clap::{arg, App, Arg, ArgMatches}; use mdbook::errors::Result; use mdbook::utils; use mdbook::MDBook; @@ -10,19 +10,25 @@ use std::thread::sleep; use std::time::Duration; // Create clap subcommand arguments -pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> { - SubCommand::with_name("watch") +pub fn make_subcommand<'help>() -> App<'help> { + App::new("watch") .about("Watches a book's files 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( + 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}\ + 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_from_usage("-o, --open 'Open the compiled book in a web browser'") + .arg(arg!([dir] + "Root directory for the book{n}\ + (Defaults to the Current Directory when omitted)" + )) + .arg(arg!(-o --open "Opens the compiled book in a web browser")) } // Watch command implementation diff --git a/src/config.rs b/src/config.rs index bf4aabbb..951957bd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -533,14 +533,14 @@ pub struct HtmlConfig { /// directly jumping to editing the currently viewed page. /// Contains {path} that is replaced with chapter source file path pub edit_url_template: Option, - /// This is used as a bit of a workaround for the `mdbook serve` command. - /// Basically, because you set the websocket port from the command line, the - /// `mdbook serve` command needs a way to let the HTML renderer know where - /// to point livereloading at, if it has been enabled. + /// Endpoint of websocket, for livereload usage. Value loaded from .toml file + /// is ignored, because our code overrides this field with the value [`LIVE_RELOAD_ENDPOINT`] + /// + /// [`LIVE_RELOAD_ENDPOINT`]: cmd::serve::LIVE_RELOAD_ENDPOINT /// /// This config item *should not be edited* by the end user. #[doc(hidden)] - pub livereload_url: Option, + pub live_reload_endpoint: Option, /// The mapping from old pages to new pages/URLs to use when generating /// redirects. pub redirect: HashMap, @@ -569,7 +569,7 @@ impl Default for HtmlConfig { input_404: None, site_url: None, cname: None, - livereload_url: None, + live_reload_endpoint: None, redirect: HashMap::new(), } } @@ -588,15 +588,20 @@ impl HtmlConfig { /// Configuration for how to render the print icon, print.html, and print.css. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] +#[serde(default, rename_all = "kebab-case")] pub struct Print { /// Whether print support is enabled. pub enable: bool, + /// Insert page breaks between chapters. Default: `true`. + pub page_break: bool, } impl Default for Print { fn default() -> Self { - Self { enable: true } + Self { + enable: true, + page_break: true, + } } } @@ -625,6 +630,8 @@ pub struct Playground { pub copy_js: bool, /// Display line numbers on playground snippets. Default: `false`. pub line_numbers: bool, + /// Display the run button. Default: `true` + pub runnable: bool, } impl Default for Playground { @@ -634,6 +641,7 @@ impl Default for Playground { copyable: true, copy_js: true, line_numbers: false, + runnable: true, } } } @@ -776,6 +784,7 @@ mod tests { copyable: true, copy_js: true, line_numbers: false, + runnable: true, }; let html_should_be = HtmlConfig { curly_quotes: true, @@ -806,6 +815,22 @@ mod tests { 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] fn edition_2015() { let src = r#" @@ -1150,4 +1175,24 @@ mod tests { 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); + } } diff --git a/src/main.rs b/src/main.rs index 1f286d2d..35562e64 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,8 @@ extern crate log; use anyhow::anyhow; 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 log::LevelFilter; use mdbook::utils; @@ -25,25 +26,31 @@ fn main() { // Check which subcomamnd the user ran... let res = match app.get_matches().subcommand() { - ("init", Some(sub_matches)) => cmd::init::execute(sub_matches), - ("build", Some(sub_matches)) => cmd::build::execute(sub_matches), - ("clean", Some(sub_matches)) => cmd::clean::execute(sub_matches), + Some(("init", sub_matches)) => cmd::init::execute(sub_matches), + Some(("build", sub_matches)) => cmd::build::execute(sub_matches), + Some(("clean", sub_matches)) => cmd::clean::execute(sub_matches), #[cfg(feature = "watch")] - ("watch", Some(sub_matches)) => cmd::watch::execute(sub_matches), + Some(("watch", sub_matches)) => cmd::watch::execute(sub_matches), #[cfg(feature = "serve")] - ("serve", Some(sub_matches)) => cmd::serve::execute(sub_matches), - ("test", Some(sub_matches)) => cmd::test::execute(sub_matches), - ("completions", Some(sub_matches)) => (|| { + Some(("serve", sub_matches)) => cmd::serve::execute(sub_matches), + Some(("test", sub_matches)) => cmd::test::execute(sub_matches), + Some(("completions", sub_matches)) => (|| { let shell: Shell = sub_matches .value_of("shell") .ok_or_else(|| anyhow!("Shell name missing."))? .parse() .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(()) })(), - (_, _) => unreachable!(), + _ => unreachable!(), }; if let Err(e) = res { @@ -54,14 +61,13 @@ fn main() { } /// 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!()) .about(crate_description!()) .author("Mathieu David ") .version(VERSION) - .setting(AppSettings::GlobalVersion) + .setting(AppSettings::PropagateVersion) .setting(AppSettings::ArgRequiredElseHelp) - .setting(AppSettings::ColoredHelp) .after_help( "For more information about a specific command, try `mdbook --help`\n\ 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::clean::make_subcommand()) .subcommand( - SubCommand::with_name("completions") + App::new("completions") .about("Generate shell completions for your shell to stdout") .arg( - Arg::with_name("shell") + Arg::new("shell") .takes_value(true) - .possible_values(&Shell::variants()) + .possible_values(Shell::possible_values()) .help("the shell to generate completions for") .value_name("SHELL") .required(true), @@ -137,3 +143,8 @@ fn open>(path: P) { error!("Error opening web browser: {}", e); } } + +#[test] +fn verify_app() { + create_clap_app().debug_assert(); +} diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index e8da5b4a..3d2d1afe 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -56,7 +56,7 @@ impl HtmlHandlebars { let fixed_content = 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 // 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 @@ -170,6 +170,13 @@ impl HtmlHandlebars { // 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("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 = @@ -606,8 +613,11 @@ fn make_data( if theme.favicon_svg.is_some() { data.insert("favicon_svg".to_owned(), json!("favicon.svg")); } - if let Some(ref livereload) = html_config.livereload_url { - data.insert("livereload".to_owned(), json!(livereload)); + if let Some(ref live_reload_endpoint) = html_config.live_reload_endpoint { + data.insert( + "live_reload_endpoint".to_owned(), + json!(live_reload_endpoint), + ); } let default_theme = match html_config.default_theme { @@ -768,16 +778,7 @@ fn insert_link_into_header( content: &str, id_counter: &mut HashMap, ) -> String { - let raw_id = utils::id_from_content(content); - - 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; + let id = utils::unique_id_from_content(content, id_counter); format!( r##"{text}"##, @@ -828,7 +829,8 @@ fn add_playground_pre( if classes.contains("language-rust") { if (!classes.contains("ignore") && !classes.contains("noplayground") - && !classes.contains("noplaypen")) + && !classes.contains("noplaypen") + && playground_config.runnable) || classes.contains("mdbook-runnable") { let contains_e2015 = classes.contains("edition2015"); diff --git a/src/renderer/html_handlebars/search.rs b/src/renderer/html_handlebars/search.rs index 2dc717fb..5dd063da 100644 --- a/src/renderer/html_handlebars/search.rs +++ b/src/renderer/html_handlebars/search.rs @@ -97,9 +97,10 @@ fn render_item( breadcrumbs.push(chapter.name.clone()); + let mut id_counter = HashMap::new(); while let Some(event) = p.next() { 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() { // Section finished, the next heading is following now // Write the data to the index, and clear it for the next section @@ -118,9 +119,9 @@ fn render_item( 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; - section_id = Some(utils::id_from_content(&heading)); + section_id = Some(utils::unique_id_from_content(&heading, &mut id_counter)); breadcrumbs.push(heading.clone()); } Event::Start(Tag::FootnoteDefinition(name)) => { diff --git a/src/theme/index.hbs b/src/theme/index.hbs index 966eedbc..18d984a2 100644 --- a/src/theme/index.hbs +++ b/src/theme/index.hbs @@ -219,10 +219,12 @@ - {{#if livereload}} + {{#if live_reload_endpoint}}