Compare commits

..

32 Commits

Author SHA1 Message Date
Eric Huss
6425c29893 Merge pull request #1562 from ehuss/bump-version
Update to 0.4.9
2021-06-02 09:54:43 -07:00
Eric Huss
d0bb830491 Update to 0.4.9 2021-06-01 18:50:29 -07:00
Eric Huss
d325c601bb Merge pull request #1554 from joshrotenberg/edit_url_custom_src
Use the configured book src directory for the edit url template path
2021-06-01 18:36:32 -07:00
Eric Huss
e9e889f523 Merge pull request #1560 from joshrotenberg/clippy_path_fixes
clippy: PathBuf to Path fixes.
2021-06-01 10:12:08 -07:00
josh rotenberg
05edc4421b clippy: PathBuf to Path 2021-05-31 20:27:52 -07:00
Eric Huss
22ea5fe335 Merge pull request #1557 from xrmx/cargo-clippy-fixes
Some clippy fixes
2021-05-31 07:10:30 -07:00
Riccardo Magliocchetti
714c5fb81e renderer: remove redundant clone in CmdRenderer
As suggested by clippy:
https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone
2021-05-30 19:33:46 +02:00
Riccardo Magliocchetti
56ceb627b8 book: simplify is_draft_chapter
As suggested by clippy:
https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern_matching
2021-05-30 19:33:46 +02:00
Riccardo Magliocchetti
c1b2bec7d7 book: use non_exhaustive attribute for struct Book
As suggested by clippy:
https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
2021-05-30 19:33:46 +02:00
Eric Huss
8201b411ab Merge pull request #1555 from joshrotenberg/exit_serve_if_panic
Use std::panic::set_hook to exit serve thread if serving fails
2021-05-29 15:12:04 -07:00
Eric Huss
836546cf0d Merge pull request #1544 from joshrotenberg/guide_configuration_restructure
Restructure guide configuration section
2021-05-29 14:46:58 -07:00
josh rotenberg
fcf8f938d2 use panic::set_hook to exit 2021-05-28 07:40:56 -07:00
josh rotenberg
60aaa7ae31 use book_config.src for edit path
use book_config.src for edit path

use book_config.src for edit path

fmt

concat the path, this is a url
2021-05-27 21:54:58 -07:00
josh rotenberg
aa4cb9465f restructure guide configuration section
restructure guide configuration section

restructure guide configuration section

redirect to new config top level

fix broken links

use a relative path for redirect

Co-authored-by: Eric Huss <eric@huss.org>

remove extra heading
2021-05-25 07:43:36 -07:00
Eldred Habert
89a2e39b80 Mention missing file creation in build/watch/serve's docs (#1548)
Fixes #1246
2021-05-25 13:45:30 +02:00
Eric Huss
3c2b8cd10f Merge pull request #1539 from joshrotenberg/report_config_errors
Report book.toml parse error when invalid fields are found
2021-05-24 13:25:07 -07:00
josh rotenberg
6b0b42ebcc update build and rust config change 2021-05-24 12:01:56 -07:00
josh rotenberg
7a3513200f Update src/config.rs
Co-authored-by: Eric Huss <eric@huss.org>
2021-05-24 11:59:32 -07:00
Eric Huss
3db0c0b9a1 Merge pull request #1511 from joshrotenberg/example-semver
Use semver crate to validate version compatibility in nop-preprocessor example
2021-05-24 11:10:21 -07:00
Eric Huss
2c7aac6d7a Merge pull request #1542 from ISSOtm/patch-1
Apply max width to video as well as images
2021-05-24 10:33:23 -07:00
Eldred Habert
3ee22fb430 Apply max width to video as well as images
Since videos are essentially animated images, this same max width makes sense for both.
2021-05-23 16:10:26 +02:00
Eric Huss
7e7e779ef7 Merge pull request #1526 from apatniv/add_log_messages
Add useful messages when command line preprocessor fails
2021-05-21 10:06:36 -07:00
Andrea Gelmini
b364e8ea2c Fix typos (#1540)
Signed-off-by: Andrea Gelmini <andrea.gelmini@gelma.net>
2021-05-21 12:56:32 +02:00
josh rotenberg
78325aaccb report book.toml parse errors
check config for book parse errors

add invalid_title_type

handle build and rust config errors
2021-05-19 09:32:24 -07:00
Eric Huss
1411ea967a Merge pull request #1534 from joshrotenberg/docs/guide-summary-updates
Guide updates: summary.md
2021-05-17 14:38:18 -07:00
josh rotenberg
d147a85006 summary.md updates 2021-05-14 22:05:24 -07:00
Eric Huss
0f0dce8d6c Merge pull request #1530 from anoadragon453/patch-1
Fix a small typo
2021-05-13 16:14:10 -07:00
Andrew Morgan
379574dc61 Fix a small typo
misssing -> missing
2021-05-13 23:55:51 +01:00
Eric Huss
6a7de13c6f Update Cargo.lock, Bump msrv to 1.42 (#1528)
* Update Cargo.lock

* Bump MSRV to 1.42.

There are a few dependencies that require this version.
2021-05-10 20:08:18 +02:00
apatniv
b21446898a Add useful messages when command line preprocessor fails 2021-05-08 12:48:57 -04:00
josh rotenberg
5b7abf4714 add semver v0.11.0 for example 2021-04-26 08:08:53 -07:00
josh rotenberg
d0ef70e574 use semver to validate version 2021-04-26 08:08:24 -07:00
31 changed files with 1041 additions and 594 deletions

View File

@@ -31,7 +31,7 @@ jobs:
rust: stable
- build: msrv
os: ubuntu-latest
rust: 1.39.0
rust: 1.42.0
steps:
- uses: actions/checkout@master
- name: Install Rust

View File

@@ -1,5 +1,25 @@
# Changelog
## mdBook 0.4.9
[7e01cf9...d325c60](https://github.com/rust-lang/mdBook/compare/7e01cf9...d325c60)
### Changed
- Updated all dependencies and raised the minimum Rust version to 1.42.
[#1528](https://github.com/rust-lang/mdBook/pull/1528)
- Added more detail to error message when a preprocessor fails.
[#1526](https://github.com/rust-lang/mdBook/pull/1526)
- Set max-width of HTML video tags to 100% to match img tags.
[#1542](https://github.com/rust-lang/mdBook/pull/1542)
### Fixed
- Type errors when parsing `book.toml` are no longer ignored.
[#1539](https://github.com/rust-lang/mdBook/pull/1539)
- Better handling if `mdbook serve` fails to start the http server.
[#1555](https://github.com/rust-lang/mdBook/pull/1555)
- Fixed the path for `edit-url-template` if the book used a source directory
other than `src`.
[#1554](https://github.com/rust-lang/mdBook/pull/1554)
## mdBook 0.4.8
[fcceee4...b592b10](https://github.com/rust-lang/mdBook/compare/fcceee4...b592b10)

View File

@@ -79,7 +79,7 @@ For more information, such as running it from your favourite editor, please see
#### Finding Issues with Clippy
Clippy is a code analyser/linter detecting mistakes, and therfore helps to improve your code.
Clippy is a code analyser/linter detecting mistakes, and therefore helps to improve your code.
Like formatting your code with `rustfmt`, running clippy regularly and before your Pull Request will
help us maintain awesome code.

865
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package]
name = "mdbook"
version = "0.4.8"
version = "0.4.9"
authors = [
"Mathieu David <mathieudavid@mathieudavid.org>",
"Michael-F-Bryan <michaelfbryan@gmail.com>",
@@ -49,6 +49,7 @@ ammonia = { version = "3", optional = true }
[dev-dependencies]
select = "0.5"
semver = "0.11.0"
pretty_assertions = "0.6"
walkdir = "2.0"

View File

@@ -3,6 +3,7 @@ use clap::{App, Arg, ArgMatches, SubCommand};
use mdbook::book::Book;
use mdbook::errors::Error;
use mdbook::preprocess::{CmdPreprocessor, Preprocessor, PreprocessorContext};
use semver::{Version, VersionReq};
use std::io;
use std::process;
@@ -33,9 +34,10 @@ fn main() {
fn handle_preprocessing(pre: &dyn Preprocessor) -> Result<(), Error> {
let (ctx, book) = CmdPreprocessor::parse_input(io::stdin())?;
if ctx.mdbook_version != mdbook::MDBOOK_VERSION {
// We should probably use the `semver` crate to check compatibility
// here...
let book_version = Version::parse(&ctx.mdbook_version)?;
let version_req = VersionReq::parse(mdbook::MDBOOK_VERSION)?;
if version_req.matches(&book_version) != true {
eprintln!(
"Warning: The {} plugin was built against version {} of mdbook, \
but we're being called from version {}",

View File

@@ -25,3 +25,6 @@ boost-hierarchy = 2
boost-paragraph = 1
expand = true
heading-split-level = 2
[output.html.redirect]
"/format/config.html" = "configuration/index.html"

View File

@@ -11,7 +11,11 @@
- [Format](format/README.md)
- [SUMMARY.md](format/summary.md)
- [Draft chapter]()
- [Configuration](format/config.md)
- [Configuration](format/configuration/README.md)
- [General](format/configuration/general.md)
- [Preprocessors](format/configuration/preprocessors.md)
- [Renderers](format/configuration/renderers.md)
- [Environment Variables](format/configuration/environment-variables.md)
- [Theme](format/theme/README.md)
- [index.hbs](format/theme/index-hbs.md)
- [Syntax highlighting](format/theme/syntax-highlighting.md)

View File

@@ -7,7 +7,8 @@ mdbook build
```
It will try to parse your `SUMMARY.md` file to understand the structure of your
book and fetch the corresponding files.
book and fetch the corresponding files. Note that files mentioned in `SUMMARY.md`
but not present will be created.
The rendered output will maintain the same directory structure as the source for
convenience. Large books will therefore remain structured when rendered.

View File

@@ -8,7 +8,8 @@ mdbook serve
```
The `serve` command watches the book's `src` directory for
changes, rebuilding the book and refreshing clients for each change. A websocket
changes, rebuilding the book and refreshing clients for each change; this includes
re-creating deleted files still mentioned in `SUMMARY.md`! A websocket
connection is used to trigger the client-side refresh.
***Note:*** *The `serve` command is for testing a book's HTML output, and is not

View File

@@ -3,7 +3,8 @@
The `watch` command is useful when you want your book to be rendered on every
file change. You could repeatedly issue `mdbook build` every time a file is
changed. But using `mdbook watch` once will watch your files and will trigger a
build automatically whenever you modify a file.
build automatically whenever you modify a file; this includes re-creating
deleted files still mentioned in `SUMMARY.md`!
#### Specify a directory

View File

@@ -0,0 +1,12 @@
# Configuration
This section details the configuration options available in the ***book.toml***:
- **[General]** configuration including the `book`, `rust`, `build` sections
- **[Preprocessor]** configuration for default and custom book preprocessors
- **[Renderer]** configuration for the HTML, Markdown and custom renderers
- **[Environment Variable]** configuration for overriding configuration options in your environment
[General]: general.md
[Preprocessor]: preprocessors.md
[Renderer]: renderers.md
[Environment Variable]: environment-variables.md

View File

@@ -0,0 +1,38 @@
# Environment Variables
All configuration values can be overridden from the command line by setting the
corresponding environment variable. Because many operating systems restrict
environment variables to be alphanumeric characters or `_`, the configuration
key needs to be formatted slightly differently to the normal `foo.bar.baz` form.
Variables starting with `MDBOOK_` are used for configuration. The key is created
by removing the `MDBOOK_` prefix and turning the resulting string into
`kebab-case`. Double underscores (`__`) separate nested keys, while a single
underscore (`_`) is replaced with a dash (`-`).
For example:
- `MDBOOK_foo` -> `foo`
- `MDBOOK_FOO` -> `foo`
- `MDBOOK_FOO__BAR` -> `foo.bar`
- `MDBOOK_FOO_BAR` -> `foo-bar`
- `MDBOOK_FOO_bar__baz` -> `foo-bar.baz`
So by setting the `MDBOOK_BOOK__TITLE` environment variable you can override the
book's title without needing to touch your `book.toml`.
> **Note:** To facilitate setting more complex config items, the value of an
> environment variable is first parsed as JSON, falling back to a string if the
> parse fails.
>
> This means, if you so desired, you could override all book metadata when
> building the book with something like
>
> ```shell
> $ export MDBOOK_BOOK="{'title': 'My Awesome Book', authors: ['Michael-F-Bryan']}"
> $ mdbook build
> ```
The latter case may be useful in situations where `mdbook` is invoked from a
script or CI, where it sometimes isn't possible to update the `book.toml` before
building.

View File

@@ -0,0 +1,97 @@
# General Configuration
You can configure the parameters for your book in the ***book.toml*** file.
Here is an example of what a ***book.toml*** file might look like:
```toml
[book]
title = "Example book"
author = "John Doe"
description = "The example book covers examples."
[rust]
edition = "2018"
[build]
build-dir = "my-example-book"
create-missing = false
[preprocessor.index]
[preprocessor.links]
[output.html]
additional-css = ["custom.css"]
[output.html.search]
limit-results = 15
```
## Supported configuration options
It is important to note that **any** relative path specified in the
configuration will always be taken relative from the root of the book where the
configuration file is located.
### General metadata
This is general information about your book.
- **title:** The title of the book
- **authors:** The author(s) of the book
- **description:** A description for the book, which is added as meta
information in the html `<head>` of each page
- **src:** By default, the source directory is found in the directory named
`src` directly under the root folder. But this is configurable with the `src`
key in the configuration file.
- **language:** The main language of the book, which is used as a language attribute `<html lang="en">` for example.
**book.toml**
```toml
[book]
title = "Example book"
authors = ["John Doe", "Jane Doe"]
description = "The example book covers examples."
src = "my-src" # the source files will be found in `root/my-src` instead of `root/src`
language = "en"
```
### Rust options
Options for the Rust language, relevant to running tests and playground
integration.
- **edition**: Rust edition to use by default for the code snippets. Default
is "2015". Individual code blocks can be controlled with the `edition2015`
or `edition2018` annotations, such as:
~~~text
```rust,edition2015
// This only works in 2015.
let try = true;
```
~~~
### Build options
This controls the build process of your book.
- **build-dir:** The directory to put the rendered book in. By default this is
`book/` in the book's root directory.
- **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
do not exist.
- **use-default-preprocessors:** Disable the default preprocessors of (`links` &
`index`) by setting this option to `false`.
If you have the same, and/or other preprocessors declared via their table
of configuration, they will run instead.
- For clarity, with no preprocessor configuration, the default `links` and
`index` will run.
- Setting `use-default-preprocessors = false` will disable these
default preprocessors from running.
- Adding `[preprocessor.links]`, for example, will ensure, regardless of
`use-default-preprocessors` that `links` it will run.

View File

@@ -0,0 +1,58 @@
# Configuring Preprocessors
The following preprocessors are available and included by default:
- `links`: Expand the `{{ #playground }}`, `{{ #include }}`, and `{{ #rustdoc_include }}` handlebars
helpers in a chapter to include the contents of a file.
- `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.
**book.toml**
```toml
[build]
build-dir = "build"
create-missing = false
[preprocessor.links]
[preprocessor.index]
```
### 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
```toml
[preprocessor.links]
# set the renderers this preprocessor will run for
renderers = ["html"]
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
```
### 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
different program name or pass in command-line arguments, this behaviour can
be overridden by adding a `command` field.
```toml
[preprocessor.random]
command = "python random.py"
```

View File

@@ -1,161 +1,4 @@
# Configuration
You can configure the parameters for your book in the ***book.toml*** file.
Here is an example of what a ***book.toml*** file might look like:
```toml
[book]
title = "Example book"
author = "John Doe"
description = "The example book covers examples."
[rust]
edition = "2018"
[build]
build-dir = "my-example-book"
create-missing = false
[preprocessor.index]
[preprocessor.links]
[output.html]
additional-css = ["custom.css"]
[output.html.search]
limit-results = 15
```
## Supported configuration options
It is important to note that **any** relative path specified in the
configuration will always be taken relative from the root of the book where the
configuration file is located.
### General metadata
This is general information about your book.
- **title:** The title of the book
- **authors:** The author(s) of the book
- **description:** A description for the book, which is added as meta
information in the html `<head>` of each page
- **src:** By default, the source directory is found in the directory named
`src` directly under the root folder. But this is configurable with the `src`
key in the configuration file.
- **language:** The main language of the book, which is used as a language attribute `<html lang="en">` for example.
**book.toml**
```toml
[book]
title = "Example book"
authors = ["John Doe", "Jane Doe"]
description = "The example book covers examples."
src = "my-src" # the source files will be found in `root/my-src` instead of `root/src`
language = "en"
```
### Rust options
Options for the Rust language, relevant to running tests and playground
integration.
- **edition**: Rust edition to use by default for the code snippets. Default
is "2015". Individual code blocks can be controlled with the `edition2015`
or `edition2018` annotations, such as:
~~~text
```rust,edition2015
// This only works in 2015.
let try = true;
```
~~~
### Build options
This controls the build process of your book.
- **build-dir:** The directory to put the rendered book in. By default this is
`book/` in the book's root directory.
- **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
do not exist.
- **use-default-preprocessors:** Disable the default preprocessors of (`links` &
`index`) by setting this option to `false`.
If you have the same, and/or other preprocessors declared via their table
of configuration, they will run instead.
- For clarity, with no preprocessor configuration, the default `links` and
`index` will run.
- Setting `use-default-preprocessors = false` will disable these
default preprocessors from running.
- Adding `[preprocessor.links]`, for example, will ensure, regardless of
`use-default-preprocessors` that `links` it will run.
## Configuring Preprocessors
The following preprocessors are available and included by default:
- `links`: Expand the `{{ #playground }}`, `{{ #include }}`, and `{{ #rustdoc_include }}` handlebars
helpers in a chapter to include the contents of a file.
- `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.
**book.toml**
```toml
[build]
build-dir = "build"
create-missing = false
[preprocessor.links]
[preprocessor.index]
```
### 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
```toml
[preprocessor.links]
# set the renderers this preprocessor will run for
renderers = ["html"]
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
```
### 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
different program name or pass in command-line arguments, this behaviour can
be overridden by adding a `command` field.
```toml
[preprocessor.random]
command = "python random.py"
```
## Configuring Renderers
# Configuring Renderers
### HTML renderer options
@@ -175,7 +18,7 @@ The following configuration options are available:
CSS media query. Defaults to `navy`.
- **curly-quotes:** Convert straight quotes to curly quotes, except for those
that occur in code blocks and code spans. Defaults to `false`.
- **mathjax-support:** Adds support for [MathJax](mathjax.md). Defaults to
- **mathjax-support:** Adds support for [MathJax](../mathjax.md). Defaults to
`false`.
- **copy-fonts:** Copies fonts.css and respective font files to the output directory and use them in the default theme. Defaults to `true`.
- **google-analytics:** If you use Google Analytics, this option lets you enable
@@ -215,7 +58,7 @@ The following configuration options are available:
`/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 misssing files.
- **input-404:** The name of the markdown file used for missing files.
The corresponding output file will be the same, with the extension replaced with `html`.
Defaults to `404.md`.
- **site-url:** The url where the book will be hosted. This is required to ensure
@@ -363,43 +206,4 @@ anything under `[output.foo]`). mdBook checks for two common fields:
- **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
## Environment Variables
All configuration values can be overridden from the command line by setting the
corresponding environment variable. Because many operating systems restrict
environment variables to be alphanumeric characters or `_`, the configuration
key needs to be formatted slightly differently to the normal `foo.bar.baz` form.
Variables starting with `MDBOOK_` are used for configuration. The key is created
by removing the `MDBOOK_` prefix and turning the resulting string into
`kebab-case`. Double underscores (`__`) separate nested keys, while a single
underscore (`_`) is replaced with a dash (`-`).
For example:
- `MDBOOK_foo` -> `foo`
- `MDBOOK_FOO` -> `foo`
- `MDBOOK_FOO__BAR` -> `foo.bar`
- `MDBOOK_FOO_BAR` -> `foo-bar`
- `MDBOOK_FOO_bar__baz` -> `foo-bar.baz`
So by setting the `MDBOOK_BOOK__TITLE` environment variable you can override the
book's title without needing to touch your `book.toml`.
> **Note:** To facilitate setting more complex config items, the value of an
> environment variable is first parsed as JSON, falling back to a string if the
> parse fails.
>
> This means, if you so desired, you could override all book metadata when
> building the book with something like
>
> ```shell
> $ export MDBOOK_BOOK="{'title': 'My Awesome Book', authors: ['Michael-F-Bryan']}"
> $ mdbook build
> ```
The latter case may be useful in situations where `mdbook` is invoked from a
script or CI, where it sometimes isn't possible to update the `book.toml` before
building.
[alternative backends]: ../../for_developers/backends.md

View File

@@ -4,66 +4,96 @@ The summary file is used by mdBook to know what chapters to include, in what
order they should appear, what their hierarchy is and where the source files
are. Without this file, there is no book.
Even though `SUMMARY.md` is a markdown file, the formatting is very strict to
allow for easy parsing. Let's see how you should format your `SUMMARY.md` file.
This markdown file must be named `SUMMARY.md`. Its formatting
is very strict and must follow the structure outlined below to allow for easy
parsing. Any element not specified below, be it formatting or textual, is likely
to be ignored at best, or may cause an error when attempting to build the book.
#### Structure
### Structure
1. ***Title*** It's common practice to begin with a title, generally <code
class="language-markdown"># Summary</code>. But it is not mandatory, the
parser just ignores it. So you can too if you feel like it.
2. ***Prefix Chapter*** Before the main numbered chapters you can add a couple
of elements that will not be numbered. This is useful for forewords,
introductions, etc. There are however some constraints. You can not nest
prefix chapters, they should all be on the root level. And you can not add
prefix chapters once you have added numbered chapters.
1. ***Title*** - While optional, it's common practice to begin with a title, generally <code
class="language-markdown"># Summary</code>. This is ignored by the parser however, and
can be ommitted.
```markdown
[Title of prefix element](relative/path/to/markdown.md)
# Summary
```
3. ***Part Title:*** Headers can be used as a title for the following numbered
1. ***Prefix Chapter*** - Before the main numbered chapters, prefix chapters can be added
that will not be numbered. This is useful for forewords,
introductions, etc. There are, however, some constraints. Prefix chapters cannot be
nested; they should all be on the root level. And you can not add
prefix chapters once you have added numbered chapters.
```markdown
[A Prefix Chapter](relative/path/to/markdown.md)
- [First Chapter](relative/path/to/markdown2.md)
```
1. ***Part Title*** - Headers can be used as a title for the following numbered
chapters. This can be used to logically separate different sections
of book. The title is rendered as unclickable text.
of the book. The title is rendered as unclickable text.
Titles are optional, and the numbered chapters can be broken into as many
parts as desired.
```markdown
# My Part Tile
4. ***Numbered Chapter*** Numbered chapters are the main content of the book,
they will be numbered and can be nested, resulting in a nice hierarchy
(chapters, sub-chapters, etc.)
- [First Chapter](relative/path/to/markdown.md)
```
1. ***Numbered Chapter*** - Numbered chapters outline the main content of the book
and can be nested, resulting in a nice hierarchy
(chapters, sub-chapters, etc.).
```markdown
# Title of Part
- [Title of the first Chapter](relative/path/to/markdown.md)
- [Title of the second Chapter](relative/path/to/markdown2.md)
- [Title of a sub Chapter](relative/path/to/markdown3.md)
- [First Chapter](relative/path/to/markdown.md)
- [Second Chapter](relative/path/to/markdown2.md)
- [Sub Chapter](relative/path/to/markdown3.md)
# Title of Another Part
- [More Chapters](relative/path/to/markdown4.md)
- [Another Chapter](relative/path/to/markdown4.md)
```
You can either use `-` or `*` to indicate a numbered chapter.
Numbered chapters can be denoted with either `-` or `*`.
5. ***Suffix Chapter*** After the numbered chapters you can add a couple of
non-numbered chapters. They are the same as prefix chapters but come after
the numbered chapters instead of before.
1. ***Suffix Chapter*** - Like prefix chapters, suffix chapters are unnumbered, but they come after
numbered chapters.
```markdown
- [Last Chapter](relative/path/to/markdown.md)
All other elements are unsupported and will be ignored at best or result in an
error.
[Title of Suffix Chapter](relative/path/to/markdown2.md)
```
#### Other elements
1. ***Draft chapters*** - Draft chapters are chapters without a file and thus content.
The purpose of a draft chapter is to signal future chapters still to be written.
Or when still laying out the structure of the book to avoid creating the files
while you are still changing the structure of the book a lot.
Draft chapters will be rendered in the HTML renderer as disabled links in the table
of contents, as you can see for the next chapter in the table of contents on the left.
Draft chapters are written like normal chapters but without writing the path to the file.
```markdown
- [Draft Chapter]()
```
- ***Separators*** In between chapters you can add a separator. In the HTML renderer
this will result in a line being rendered in the table of contents. A separator is
a line containing exclusively dashes and at least three of them: `---`.
- ***Draft chapters*** Draft chapters are chapters without a file and thus content.
The purpose of a draft chapter is to signal future chapters still to be written.
Or when still laying out the structure of the book to avoid creating the files
while you are still changing the structure of the book a lot.
Draft chapters will be rendered in the HTML renderer as disabled links in the table
of contents, as you can see for the next chapter in the table of contents on the left.
Draft chapters are written like normal chapters but without writing the path to the file
```markdown
- [Draft chapter]()
```
1. ***Separators*** - Separators can be added before, in between, and after any other element. They result
in an HTML rendered line in the built table of contents. A separator is
a line containing exclusively dashes and at least three of them: `---`.
```markdown
# My Part Title
[A Prefix Chapter](relative/path/to/markdown.md)
---
- [First Chapter](relative/path/to/markdown2.md)
```
### Example
Below is the markdown source for the `SUMMARY.md` for this guide, with the resulting table
of contents as rendered to the left.
```markdown
{{#include ../SUMMARY.md}}
```

View File

@@ -42,5 +42,5 @@ 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.
[`output.html.preferred-dark-theme`]: ../config.md#html-renderer-options
[`output.html.preferred-dark-theme`]: ../configuration/renderers.md#html-renderer-options
[newer browsers]: https://caniuse.com/#feat=link-icon-svg

View File

@@ -33,7 +33,7 @@ Note the new `Undo Changes` button in the editable playgrounds.
## Customizing the Editor
By default, the editor is the [Ace](https://ace.c9.io/) editor, but, if desired,
the functionality may be overriden by providing a different folder:
the functionality may be overridden by providing a different folder:
```toml
[output.html.playground]
@@ -42,5 +42,5 @@ editor = "/path/to/editor"
```
Note that for the editor changes to function correctly, the `book.js` inside of
the `theme` folder will need to be overriden as it has some couplings with the
the `theme` folder will need to be overridden as it has some couplings with the
default Ace editor.

View File

@@ -74,10 +74,10 @@ fn create_missing(src_dir: &Path, summary: &Summary) -> Result<()> {
/// [`iter()`]: #method.iter
/// [`for_each_mut()`]: #method.for_each_mut
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Book {
/// The sections in this book.
pub sections: Vec<BookItem>,
__non_exhaustive: (),
}
impl Book {
@@ -200,10 +200,7 @@ impl Chapter {
/// Check if the chapter is a draft chapter, meaning it has no path to a source markdown file.
pub fn is_draft_chapter(&self) -> bool {
match self.path {
Some(_) => false,
None => true,
}
self.path.is_none()
}
}
@@ -228,10 +225,7 @@ pub(crate) fn load_book_from_disk<P: AsRef<Path>>(summary: &Summary, src_dir: P)
chapters.push(chapter);
}
Ok(Book {
sections: chapters,
__non_exhaustive: (),
})
Ok(Book { sections: chapters })
}
fn load_summary_item<P: AsRef<Path> + Clone>(

View File

@@ -173,7 +173,7 @@ struct SummaryParser<'a> {
/// `Event::End` is encountered which matches the `$delimiter` pattern.
///
/// This is the equivalent of doing
/// `$stream.take_while(|e| e != $delimeter).collect()` but it allows you to
/// `$stream.take_while(|e| e != $delimiter).collect()` but it allows you to
/// use pattern matching and you won't get errors because `take_while()`
/// moves `$stream` out of self.
macro_rules! collect_events {

View File

@@ -161,5 +161,12 @@ async fn serve(
let fallback_route = warp::fs::file(build_dir.join(file_404))
.map(|reply| warp::reply::with_status(reply, warp::http::StatusCode::NOT_FOUND));
let routes = livereload.or(book_route).or(fallback_route);
std::panic::set_hook(Box::new(move |panic_info| {
// exit if serve panics
error!("Unable to serve: {}", panic_info);
std::process::exit(1);
}));
warp::serve(routes).run(address).await;
}

View File

@@ -58,7 +58,7 @@ pub fn execute(args: &ArgMatches) -> Result<()> {
Ok(())
}
fn remove_ignored_files(book_root: &PathBuf, paths: &[PathBuf]) -> Vec<PathBuf> {
fn remove_ignored_files(book_root: &Path, paths: &[PathBuf]) -> Vec<PathBuf> {
if paths.is_empty() {
return vec![];
}
@@ -81,7 +81,7 @@ fn remove_ignored_files(book_root: &PathBuf, paths: &[PathBuf]) -> Vec<PathBuf>
}
}
fn find_gitignore(book_root: &PathBuf) -> Option<PathBuf> {
fn find_gitignore(book_root: &Path) -> Option<PathBuf> {
book_root
.ancestors()
.map(|p| p.join(".gitignore"))

View File

@@ -294,6 +294,7 @@ impl Default for Config {
}
}
}
impl<'de> Deserialize<'de> for Config {
fn deserialize<D: Deserializer<'de>>(de: D) -> std::result::Result<Self, D::Error> {
let raw = Value::deserialize(de)?;
@@ -310,10 +311,10 @@ impl<'de> Deserialize<'de> for Config {
return Ok(Config::from_legacy(raw));
}
use serde::de::Error;
let mut table = match raw {
Value::Table(t) => t,
_ => {
use serde::de::Error;
return Err(D::Error::custom(
"A config file should always be a toml table",
));
@@ -322,17 +323,20 @@ impl<'de> Deserialize<'de> for Config {
let book: BookConfig = table
.remove("book")
.and_then(|value| value.try_into().ok())
.map(|book| book.try_into().map_err(D::Error::custom))
.transpose()?
.unwrap_or_default();
let build: BuildConfig = table
.remove("build")
.and_then(|value| value.try_into().ok())
.map(|build| build.try_into().map_err(D::Error::custom))
.transpose()?
.unwrap_or_default();
let rust: RustConfig = table
.remove("rust")
.and_then(|value| value.try_into().ok())
.map(|rust| rust.try_into().map_err(D::Error::custom))
.transpose()?
.unwrap_or_default();
Ok(Config {
@@ -571,7 +575,7 @@ impl Default for HtmlConfig {
impl HtmlConfig {
/// Returns the directory of theme from the provided root directory. If the
/// directory is not present it will append the default directory of "theme"
pub fn theme_dir(&self, root: &PathBuf) -> PathBuf {
pub fn theme_dir(&self, root: &Path) -> PathBuf {
match self.theme {
Some(ref d) => root.join(d),
None => root.join("theme"),
@@ -656,7 +660,7 @@ pub struct Search {
pub boost_paragraph: u8,
/// True if the searchword `micro` should match `microwave`. Default: `true`.
pub expand: bool,
/// Documents are split into smaller parts, seperated by headings. This defines, until which
/// Documents are split into smaller parts, separated by headings. This defines, until which
/// level of heading documents should be split. Default: `3`. (`### This is a level 3 heading`)
pub heading_split_level: u8,
/// Copy JavaScript files for the search functionality to the output directory?
@@ -1070,4 +1074,57 @@ mod tests {
assert_eq!(html_config.input_404, Some("missing.md".to_string()));
assert_eq!(&get_404_output_file(&html_config.input_404), "missing.html");
}
#[test]
#[should_panic(expected = "Invalid configuration file")]
fn invalid_language_type_error() {
let src = r#"
[book]
title = "mdBook Documentation"
language = ["en", "pt-br"]
description = "Create book from markdown files. Like Gitbook but implemented in Rust"
authors = ["Mathieu David"]
src = "./source"
"#;
Config::from_str(src).unwrap();
}
#[test]
#[should_panic(expected = "Invalid configuration file")]
fn invalid_title_type() {
let src = r#"
[book]
title = 20
language = "en"
description = "Create book from markdown files. Like Gitbook but implemented in Rust"
authors = ["Mathieu David"]
src = "./source"
"#;
Config::from_str(src).unwrap();
}
#[test]
#[should_panic(expected = "Invalid configuration file")]
fn invalid_build_dir_type() {
let src = r#"
[build]
build-dir = 99
create-missing = false
"#;
Config::from_str(src).unwrap();
}
#[test]
#[should_panic(expected = "Invalid configuration file")]
fn invalid_rust_edition() {
let src = r#"
[rust]
edition = "1999"
"#;
Config::from_str(src).unwrap();
}
}

View File

@@ -109,18 +109,28 @@ impl Preprocessor for CmdPreprocessor {
self.write_input_to_child(&mut child, &book, ctx);
let output = child
.wait_with_output()
.with_context(|| "Error waiting for the preprocessor to complete")?;
let output = child.wait_with_output().with_context(|| {
format!(
"Error waiting for the \"{}\" preprocessor to complete",
self.name
)
})?;
trace!("{} exited with output: {:?}", self.cmd, output);
ensure!(
output.status.success(),
"The preprocessor exited unsuccessfully"
format!(
"The \"{}\" preprocessor exited unsuccessfully with {} status",
self.name, output.status
)
);
serde_json::from_slice(&output.stdout)
.with_context(|| "Unable to parse the preprocessed book")
serde_json::from_slice(&output.stdout).with_context(|| {
format!(
"Unable to parse the preprocessed book from \"{}\" processor",
self.name
)
})
}
fn supports_renderer(&self, renderer: &str) -> bool {

View File

@@ -1,5 +1,5 @@
use crate::book::{Book, BookItem};
use crate::config::{Config, HtmlConfig, Playground, RustEdition};
use crate::config::{BookConfig, Config, HtmlConfig, Playground, RustEdition};
use crate::errors::*;
use crate::renderer::html_handlebars::helpers;
use crate::renderer::{RenderContext, Renderer};
@@ -38,12 +38,14 @@ impl HtmlHandlebars {
};
if let Some(ref edit_url_template) = ctx.html_config.edit_url_template {
let full_path = "src/".to_owned()
let full_path = ctx.book_config.src.to_str().unwrap_or_default().to_owned()
+ "/"
+ ch.source_path
.clone()
.unwrap_or_default()
.to_str()
.unwrap_or_default();
let edit_url = edit_url_template.replace("{path}", &full_path);
ctx.data
.insert("git_repository_edit_url".to_owned(), json!(edit_url));
@@ -131,7 +133,7 @@ impl HtmlHandlebars {
&self,
ctx: &RenderContext,
html_config: &HtmlConfig,
src_dir: &PathBuf,
src_dir: &Path,
handlebars: &mut Handlebars<'_>,
data: &mut serde_json::Map<String, serde_json::Value>,
) -> Result<()> {
@@ -458,6 +460,7 @@ impl Renderer for HtmlHandlebars {
}
fn render(&self, ctx: &RenderContext) -> Result<()> {
let book_config = &ctx.config.book;
let html_config = ctx.config.html_config().unwrap_or_default();
let src_dir = ctx.root.join(&ctx.config.book.src);
let destination = &ctx.destination;
@@ -520,6 +523,7 @@ impl Renderer for HtmlHandlebars {
destination: destination.to_path_buf(),
data: data.clone(),
is_index,
book_config: book_config.clone(),
html_config: html_config.clone(),
edition: ctx.config.rust.edition,
chapter_titles: &ctx.chapter_titles,
@@ -936,6 +940,7 @@ struct RenderItemContext<'a> {
destination: PathBuf,
data: serde_json::Map<String, serde_json::Value>,
is_index: bool,
book_config: BookConfig,
html_config: HtmlConfig,
edition: Option<RustEdition>,
chapter_titles: &'a HashMap<PathBuf, String>,

View File

@@ -141,7 +141,7 @@ fn render_item(
body.push_str(&clean_html(&html_block));
}
Event::Start(_) | Event::End(_) | Event::Rule | Event::SoftBreak | Event::HardBreak => {
// Insert spaces where HTML output would usually seperate text
// Insert spaces where HTML output would usually separate text
// to ensure words don't get merged together
if in_heading {
heading.push(' ');

View File

@@ -166,7 +166,7 @@ impl CmdRenderer {
} else {
// Let this bubble through to later be handled by
// handle_render_command_error.
abs_exe.to_path_buf()
abs_exe
}
}
};

View File

@@ -92,7 +92,7 @@ h6:target::before {
.content ul { line-height: 1.45em; }
.content a { text-decoration: none; }
.content a:hover { text-decoration: underline; }
.content img { max-width: 100%; }
.content img, .content video { max-width: 100%; }
.content .header:link,
.content .header:visited {
color: var(--fg);

View File

@@ -4,7 +4,7 @@ use std::fs::{self, File};
use std::io::Write;
use std::path::{Component, Path, PathBuf};
/// Naively replaces any path seperator with a forward-slash '/'
/// Naively replaces any path separator with a forward-slash '/'
pub fn normalize_path(path: &str) -> String {
use std::path::is_separator;
path.chars()

View File

@@ -541,6 +541,57 @@ fn redirects_are_emitted_correctly() {
}
}
#[test]
fn edit_url_has_default_src_dir_edit_url() {
let temp = DummyBook::new().build().unwrap();
let book_toml = r#"
[book]
title = "implicit"
[output.html]
edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}"
"#;
write_file(&temp.path(), "book.toml", book_toml.as_bytes()).unwrap();
let md = MDBook::load(temp.path()).unwrap();
md.build().unwrap();
let index_html = temp.path().join("book").join("index.html");
assert_contains_strings(
index_html,
&vec![
r#"href="https://github.com/rust-lang/mdBook/edit/master/guide/src/README.md" title="Suggest an edit""#,
],
);
}
#[test]
fn edit_url_has_configured_src_dir_edit_url() {
let temp = DummyBook::new().build().unwrap();
let book_toml = r#"
[book]
title = "implicit"
src = "src2"
[output.html]
edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}"
"#;
write_file(&temp.path(), "book.toml", book_toml.as_bytes()).unwrap();
let md = MDBook::load(temp.path()).unwrap();
md.build().unwrap();
let index_html = temp.path().join("book").join("index.html");
assert_contains_strings(
index_html,
&vec![
r#"href="https://github.com/rust-lang/mdBook/edit/master/guide/src2/README.md" title="Suggest an edit""#,
],
);
}
fn remove_absolute_components(path: &Path) -> impl Iterator<Item = Component> + '_ {
path.components().skip_while(|c| match c {
Component::Prefix(_) | Component::RootDir => true,