mirror of
https://github.com/rust-lang/mdBook.git
synced 2025-12-28 12:41:16 -05:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f66df09324 | ||
|
|
648c9ae772 |
58
CHANGELOG.md
58
CHANGELOG.md
@@ -1,63 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## mdBook 0.4.7
|
||||
[9a9eb01...c83bbd6](https://github.com/rust-lang/mdBook/compare/9a9eb01...c83bbd6)
|
||||
|
||||
### Changed
|
||||
- Updated shlex parser to fix a minor parsing issue (used by the
|
||||
preprocessor/backend custom command config).
|
||||
[#1471](https://github.com/rust-lang/mdBook/pull/1471)
|
||||
- Enhanced text contrast of `light` theme to improve accessibility.
|
||||
[#1470](https://github.com/rust-lang/mdBook/pull/1470)
|
||||
|
||||
### Fixed
|
||||
- Fixed some issues with fragment scrolling and linking.
|
||||
[#1463](https://github.com/rust-lang/mdBook/pull/1463)
|
||||
|
||||
## mdBook 0.4.6
|
||||
[eaa6914...1a0c296](https://github.com/rust-lang/mdBook/compare/eaa6914...1a0c296)
|
||||
|
||||
### Changed
|
||||
- The chapter name is now included in the search breadcrumbs.
|
||||
[#1389](https://github.com/rust-lang/mdBook/pull/1389)
|
||||
- Pressing Escape will remove the `?highlight` argument from the URL.
|
||||
[#1427](https://github.com/rust-lang/mdBook/pull/1427)
|
||||
- `mdbook init --theme` will now place the theme in the root of the book
|
||||
directory instead of in the `src` directory.
|
||||
[#1432](https://github.com/rust-lang/mdBook/pull/1432)
|
||||
- A custom renderer that sets the `command` to a relative path now interprets
|
||||
the relative path relative to the book root. Previously it was inconsistent
|
||||
based on the platform (either relative to the current directory, or relative
|
||||
to the renderer output directory). Paths relative to the output directory
|
||||
are still supported with a deprecation warning.
|
||||
[#1418](https://github.com/rust-lang/mdBook/pull/1418)
|
||||
- The `theme` directory in the config is now interpreted as relative to the
|
||||
book root, instead of the current directory.
|
||||
[#1405](https://github.com/rust-lang/mdBook/pull/1405)
|
||||
- Handle UTF-8 BOM for chapter sources.
|
||||
[#1285](https://github.com/rust-lang/mdBook/pull/1285)
|
||||
- Removed extra whitespace added to `{{#playground}}` snippets.
|
||||
[#1375](https://github.com/rust-lang/mdBook/pull/1375)
|
||||
|
||||
### Fixed
|
||||
- Clicking on a search result with multiple search words will now correctly
|
||||
highlight all of the words.
|
||||
[#1426](https://github.com/rust-lang/mdBook/pull/1426)
|
||||
- Properly handle `<` and `>` characters in the table of contents.
|
||||
[#1376](https://github.com/rust-lang/mdBook/pull/1376)
|
||||
- Fixed to properly serialize the `build` table in the config, which prevented
|
||||
setting it in the API.
|
||||
[#1378](https://github.com/rust-lang/mdBook/pull/1378)
|
||||
|
||||
## mdBook 0.4.5
|
||||
[eaa6914...f66df09](https://github.com/rust-lang/mdBook/compare/eaa6914...f66df09)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed XSS in the search page.
|
||||
[CVE-2020-26297](https://groups.google.com/g/rustlang-security-announcements/c/3-sO6of29O0)
|
||||
[648c9ae](https://github.com/rust-lang/mdBook/commit/648c9ae772bec83f0a5954d17b4287d5bb1d6606)
|
||||
|
||||
## mdBook 0.4.4
|
||||
[4df9ec9...01836ba](https://github.com/rust-lang/mdBook/compare/4df9ec9...01836ba)
|
||||
|
||||
|
||||
6
Cargo.lock
generated
6
Cargo.lock
generated
@@ -723,7 +723,7 @@ checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
||||
|
||||
[[package]]
|
||||
name = "mdbook"
|
||||
version = "0.4.7"
|
||||
version = "0.4.5"
|
||||
dependencies = [
|
||||
"ammonia",
|
||||
"anyhow",
|
||||
@@ -1258,9 +1258,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.0.0"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42a568c8f2cd051a4d283bd6eb0343ac214c1b0f1ac19f93e1175b2dee38c73d"
|
||||
checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mdbook"
|
||||
version = "0.4.7"
|
||||
version = "0.4.5"
|
||||
authors = [
|
||||
"Mathieu David <mathieudavid@mathieudavid.org>",
|
||||
"Michael-F-Bryan <michaelfbryan@gmail.com>",
|
||||
@@ -30,7 +30,7 @@ regex = "1.0.0"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0"
|
||||
shlex = "1"
|
||||
shlex = "0.1"
|
||||
tempfile = "3.0"
|
||||
toml = "0.5.1"
|
||||
|
||||
|
||||
@@ -91,11 +91,10 @@ all its functionality as a Rust crate for integration in other projects.
|
||||
Here are the main commands you will want to run. For a more exhaustive
|
||||
explanation, check out the [User Guide].
|
||||
|
||||
- `mdbook init <directory>`
|
||||
- `mdbook init`
|
||||
|
||||
The init command will create a directory with the minimal boilerplate to
|
||||
start with. If the `<directory>` parameter is omitted, the current
|
||||
directory will be used.
|
||||
start with.
|
||||
|
||||
```
|
||||
book-test/
|
||||
@@ -150,7 +149,6 @@ preprocessors are:
|
||||
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
|
||||
|
||||
@@ -10,7 +10,6 @@ edition = "2018"
|
||||
[output.html]
|
||||
mathjax-support = true
|
||||
site-url = "/mdBook/"
|
||||
git-repository-url = "https://github.com/rust-lang/mdBook/tree/master/guide"
|
||||
|
||||
[output.html.playground]
|
||||
editable = true
|
||||
|
||||
@@ -12,7 +12,7 @@ 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.
|
||||
mdBook can also be installed from source
|
||||
|
||||
### Pre-requisite
|
||||
|
||||
|
||||
@@ -39,9 +39,6 @@ permissions (or "repo" for private repositories). Go to your repository's Travis
|
||||
CI settings page and add an environment variable named `GITHUB_TOKEN` that is
|
||||
marked secure and *not* shown in the logs.
|
||||
|
||||
Whilst still in your repository's settings page, navigate to Options and change the
|
||||
Source on GitHub pages to `gh-pages`.
|
||||
|
||||
Then, append this snippet to your `.travis.yml` and update the path to the
|
||||
`book` directory:
|
||||
|
||||
@@ -58,40 +55,6 @@ deploy:
|
||||
|
||||
That's it!
|
||||
|
||||
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:
|
||||
|
||||
```yaml
|
||||
language: rust
|
||||
os: linux
|
||||
dist: xenial
|
||||
|
||||
cache:
|
||||
- cargo
|
||||
|
||||
rust:
|
||||
- stable
|
||||
|
||||
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
|
||||
|
||||
script:
|
||||
- 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: path/to/mybook/book
|
||||
keep-history: false
|
||||
on:
|
||||
branch: master
|
||||
target_branch: gh-pages
|
||||
```
|
||||
|
||||
### Deploying to GitHub Pages manually
|
||||
|
||||
If your CI doesn't support GitHub pages, or you're deploying somewhere else
|
||||
@@ -124,31 +87,3 @@ deploy: book
|
||||
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:alpine
|
||||
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
|
||||
only:
|
||||
- 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!
|
||||
|
||||
@@ -14,11 +14,9 @@ Here are the files you can override:
|
||||
- **_index.hbs_** is the handlebars template.
|
||||
- **_head.hbs_** is appended to the HTML `<head>` section.
|
||||
- **_header.hbs_** content is appended on top of every book page.
|
||||
- **_css/_** contains the CSS files for styling the book.
|
||||
- **_css/chrome.css_** is for UI elements.
|
||||
- **_css/general.css_** is the base styles.
|
||||
- **_css/print.css_** is the style for printer output.
|
||||
- **_css/variables.css_** contains variables used in other CSS files.
|
||||
- **_book.css_** is the style used in the output. If you want to change the
|
||||
design of your book, this is probably the file you want to modify. Sometimes
|
||||
in conjunction with `index.hbs` when you want to radically change the layout.
|
||||
- **_book.js_** is mostly used to add client side functionality, like hiding /
|
||||
un-hiding the sidebar, changing the theme, ...
|
||||
- **_highlight.js_** is the JavaScript that is used to highlight code snippets,
|
||||
|
||||
@@ -19,7 +19,7 @@ Here is a list of the properties that are exposed:
|
||||
|
||||
- ***language*** Language of the book in the form `en`, as specified in `book.toml` (if not specified, defaults to `en`). To use in <code
|
||||
class="language-html">\<html lang="{{ language }}"></code> for example.
|
||||
- ***title*** Title used for the current page. This is identical to `{{ chapter_title }} - {{ book_title }}` unless `book_title` is not set in which case it just defaults to the `chapter_title`.
|
||||
- ***title*** Title used for the current page. This is identical to `{{ book_title }} - {{ chapter_title }}` unless `book_title` is not set in which case it just defaults to the `chapter_title`.
|
||||
- ***book_title*** Title of the book, as specified in `book.toml`
|
||||
- ***chapter_title*** Title of the current chapter, as listed in `SUMMARY.md`
|
||||
|
||||
|
||||
@@ -112,10 +112,10 @@ everyone can benefit from it.**
|
||||
## Improve default theme
|
||||
|
||||
If you think the default theme doesn't look quite right for a specific language,
|
||||
or could be improved, feel free to [submit a new
|
||||
or could be improved. Feel free to [submit a new
|
||||
issue](https://github.com/rust-lang/mdBook/issues) explaining what you
|
||||
have in mind and I will take a look at it.
|
||||
|
||||
You could also create a pull-request with the proposed improvements.
|
||||
|
||||
Overall the theme should be light and sober, without too many flashy colors.
|
||||
Overall the theme should be light and sober, without to many flashy colors.
|
||||
|
||||
@@ -16,6 +16,5 @@ shout-out to them!
|
||||
- [Phaiax](https://github.com/Phaiax)
|
||||
- Matt Ickstadt ([mattico](https://github.com/mattico))
|
||||
- Weihang Lo ([@weihanglo](https://github.com/weihanglo))
|
||||
- Avision Ho ([@avisionh](https://github.com/avisionh))
|
||||
|
||||
If you feel you're missing from this list, feel free to add yourself in a PR.
|
||||
If you feel you're missing from this list, feel free to add yourself in a PR.
|
||||
@@ -14,12 +14,11 @@ pub fn load_book<P: AsRef<Path>>(src_dir: P, cfg: &BuildConfig) -> Result<Book>
|
||||
let summary_md = src_dir.join("SUMMARY.md");
|
||||
|
||||
let mut summary_content = String::new();
|
||||
File::open(&summary_md)
|
||||
.with_context(|| format!("Couldn't open SUMMARY.md in {:?} directory", src_dir))?
|
||||
File::open(summary_md)
|
||||
.with_context(|| "Couldn't open SUMMARY.md")?
|
||||
.read_to_string(&mut summary_content)?;
|
||||
|
||||
let summary = parse_summary(&summary_content)
|
||||
.with_context(|| format!("Summary parsing failed for file={:?}", summary_md))?;
|
||||
let summary = parse_summary(&summary_content).with_context(|| "Summary parsing failed")?;
|
||||
|
||||
if cfg.create_missing {
|
||||
create_missing(&src_dir, &summary).with_context(|| "Unable to create missing chapters")?;
|
||||
@@ -50,9 +49,7 @@ fn create_missing(src_dir: &Path, summary: &Summary) -> Result<()> {
|
||||
}
|
||||
debug!("Creating missing file {}", filename.display());
|
||||
|
||||
let mut f = File::create(&filename).with_context(|| {
|
||||
format!("Unable to create missing file: {}", filename.display())
|
||||
})?;
|
||||
let mut f = File::create(&filename)?;
|
||||
writeln!(f, "# {}", link.name)?;
|
||||
}
|
||||
}
|
||||
@@ -66,7 +63,7 @@ fn create_missing(src_dir: &Path, summary: &Summary) -> Result<()> {
|
||||
|
||||
/// A dumb tree structure representing a book.
|
||||
///
|
||||
/// For the moment a book is just a collection of [`BookItems`] which are
|
||||
/// For the moment a book is just a collection of `BookItems` which are
|
||||
/// accessible by either iterating (immutably) over the book with [`iter()`], or
|
||||
/// recursively applying a closure to each section to mutate the chapters, using
|
||||
/// [`for_each_mut()`].
|
||||
@@ -160,7 +157,7 @@ pub struct Chapter {
|
||||
pub sub_items: Vec<BookItem>,
|
||||
/// The chapter's location, relative to the `SUMMARY.md` file.
|
||||
pub path: Option<PathBuf>,
|
||||
/// An ordered list of the names of each chapter above this one in the hierarchy.
|
||||
/// An ordered list of the names of each chapter above this one, in the hierarchy.
|
||||
pub parent_names: Vec<String>,
|
||||
}
|
||||
|
||||
@@ -181,8 +178,8 @@ impl Chapter {
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new draft chapter that is not attached to a source markdown file (and thus
|
||||
/// has no content).
|
||||
/// Create a new draft chapter that is not attached to a source markdown file and has
|
||||
/// thus no content.
|
||||
pub fn new_draft(name: &str, parent_names: Vec<String>) -> Self {
|
||||
Chapter {
|
||||
name: name.to_string(),
|
||||
@@ -193,7 +190,7 @@ impl Chapter {
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if the chapter is a draft chapter, meaning it has no path to a source markdown file.
|
||||
/// 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,
|
||||
@@ -267,10 +264,6 @@ fn load_chapter<P: AsRef<Path>>(
|
||||
format!("Unable to read \"{}\" ({})", link.name, location.display())
|
||||
})?;
|
||||
|
||||
if content.as_bytes().starts_with(b"\xef\xbb\xbf") {
|
||||
content.replace_range(..3, "");
|
||||
}
|
||||
|
||||
let stripped = location
|
||||
.strip_prefix(&src_dir)
|
||||
.expect("Chapters are always inside a book");
|
||||
@@ -280,7 +273,7 @@ fn load_chapter<P: AsRef<Path>>(
|
||||
Chapter::new_draft(&link.name, parent_names.clone())
|
||||
};
|
||||
|
||||
let mut sub_item_parents = parent_names;
|
||||
let mut sub_item_parents = parent_names.clone();
|
||||
|
||||
ch.number = link.number.clone();
|
||||
|
||||
@@ -302,6 +295,8 @@ fn load_chapter<P: AsRef<Path>>(
|
||||
///
|
||||
/// This struct shouldn't be created directly, instead prefer the
|
||||
/// [`Book::iter()`] method.
|
||||
///
|
||||
/// [`Book::iter()`]: struct.Book.html#method.iter
|
||||
pub struct BookItems<'a> {
|
||||
items: VecDeque<&'a BookItem>,
|
||||
}
|
||||
@@ -398,29 +393,6 @@ And here is some \
|
||||
assert_eq!(got, should_be);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_a_single_chapter_with_utf8_bom_from_disk() {
|
||||
let temp_dir = TempFileBuilder::new().prefix("book").tempdir().unwrap();
|
||||
|
||||
let chapter_path = temp_dir.path().join("chapter_1.md");
|
||||
File::create(&chapter_path)
|
||||
.unwrap()
|
||||
.write_all(("\u{feff}".to_owned() + DUMMY_SRC).as_bytes())
|
||||
.unwrap();
|
||||
|
||||
let link = Link::new("Chapter 1", chapter_path);
|
||||
|
||||
let should_be = Chapter::new(
|
||||
"Chapter 1",
|
||||
DUMMY_SRC.to_string(),
|
||||
"chapter_1.md",
|
||||
Vec::new(),
|
||||
);
|
||||
|
||||
let got = load_chapter(&link, temp_dir.path(), Vec::new()).unwrap();
|
||||
assert_eq!(got, should_be);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cant_load_a_nonexistent_chapter() {
|
||||
let link = Link::new("Chapter 1", "/foo/bar/baz.md");
|
||||
|
||||
@@ -28,7 +28,7 @@ impl BookBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the [`Config`] to be used.
|
||||
/// Set the `Config` to be used.
|
||||
pub fn with_config(&mut self, cfg: Config) -> &mut BookBuilder {
|
||||
self.config = cfg;
|
||||
self
|
||||
@@ -110,7 +110,10 @@ impl BookBuilder {
|
||||
debug!("Copying theme");
|
||||
|
||||
let html_config = self.config.html_config().unwrap_or_default();
|
||||
let themedir = html_config.theme_dir(&self.root);
|
||||
let themedir = html_config
|
||||
.theme
|
||||
.unwrap_or_else(|| self.config.book.src.join("theme"));
|
||||
let themedir = self.root.join(themedir);
|
||||
|
||||
if !themedir.exists() {
|
||||
debug!(
|
||||
@@ -124,9 +127,7 @@ impl BookBuilder {
|
||||
index.write_all(theme::INDEX)?;
|
||||
|
||||
let cssdir = themedir.join("css");
|
||||
if !cssdir.exists() {
|
||||
fs::create_dir(&cssdir)?;
|
||||
}
|
||||
fs::create_dir(&cssdir)?;
|
||||
|
||||
let mut general_css = File::create(cssdir.join("general.css"))?;
|
||||
general_css.write_all(theme::GENERAL_CSS)?;
|
||||
|
||||
@@ -40,7 +40,7 @@ pub struct MDBook {
|
||||
pub book: Book,
|
||||
renderers: Vec<Box<dyn Renderer>>,
|
||||
|
||||
/// List of pre-processors to be run on the book.
|
||||
/// List of pre-processors to be run on the book
|
||||
preprocessors: Vec<Box<dyn Preprocessor>>,
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ impl MDBook {
|
||||
MDBook::load_with_config(book_root, config)
|
||||
}
|
||||
|
||||
/// Load a book from its root directory using a custom `Config`.
|
||||
/// Load a book from its root directory using a custom config.
|
||||
pub fn load_with_config<P: Into<PathBuf>>(book_root: P, config: Config) -> Result<MDBook> {
|
||||
let root = book_root.into();
|
||||
|
||||
@@ -97,7 +97,7 @@ impl MDBook {
|
||||
})
|
||||
}
|
||||
|
||||
/// Load a book from its root directory using a custom `Config` and a custom summary.
|
||||
/// Load a book from its root directory using a custom config and a custom summary.
|
||||
pub fn load_with_config_and_summary<P: Into<PathBuf>>(
|
||||
book_root: P,
|
||||
config: Config,
|
||||
@@ -121,7 +121,7 @@ impl MDBook {
|
||||
}
|
||||
|
||||
/// Returns a flat depth-first iterator over the elements of the book,
|
||||
/// it returns a [`BookItem`] enum:
|
||||
/// it returns an [BookItem enum](bookitem.html):
|
||||
/// `(section: String, bookitem: &BookItem)`
|
||||
///
|
||||
/// ```no_run
|
||||
@@ -180,7 +180,7 @@ impl MDBook {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Run the entire build process for a particular [`Renderer`].
|
||||
/// Run the entire build process for a particular `Renderer`.
|
||||
pub fn execute_build_process(&self, renderer: &dyn Renderer) -> Result<()> {
|
||||
let mut preprocessed_book = self.book.clone();
|
||||
let preprocess_ctx = PreprocessorContext::new(
|
||||
@@ -219,14 +219,14 @@ impl MDBook {
|
||||
}
|
||||
|
||||
/// You can change the default renderer to another one by using this method.
|
||||
/// The only requirement is that your renderer implement the [`Renderer`]
|
||||
/// trait.
|
||||
/// The only requirement is for your renderer to implement the [`Renderer`
|
||||
/// trait](../renderer/trait.Renderer.html)
|
||||
pub fn with_renderer<R: Renderer + 'static>(&mut self, renderer: R) -> &mut Self {
|
||||
self.renderers.push(Box::new(renderer));
|
||||
self
|
||||
}
|
||||
|
||||
/// Register a [`Preprocessor`] to be used when rendering the book.
|
||||
/// Register a [`Preprocessor`](../preprocess/trait.Preprocessor.html) to be used when rendering the book.
|
||||
pub fn with_preprocessor<P: Preprocessor + 'static>(&mut self, preprocessor: P) -> &mut Self {
|
||||
self.preprocessors.push(Box::new(preprocessor));
|
||||
self
|
||||
@@ -303,7 +303,7 @@ impl MDBook {
|
||||
/// artefacts.
|
||||
///
|
||||
/// If there is only 1 renderer, put it in the directory pointed to by the
|
||||
/// `build.build_dir` key in [`Config`]. If there is more than one then the
|
||||
/// `build.build_dir` key in `Config`. If there is more than one then the
|
||||
/// renderer gets its own directory within the main build dir.
|
||||
///
|
||||
/// i.e. If there were only one renderer (in this case, the HTML renderer):
|
||||
|
||||
@@ -28,11 +28,15 @@ pub fn execute(args: &ArgMatches) -> Result<()> {
|
||||
|
||||
// If flag `--theme` is present, copy theme to src
|
||||
if args.is_present("theme") {
|
||||
let theme_dir = book_dir.join("theme");
|
||||
println!();
|
||||
println!("Copying the default theme to {}", theme_dir.display());
|
||||
config.set("output.html.theme", "src/theme")?;
|
||||
// Skip this if `--force` is present
|
||||
if !args.is_present("force") && theme_dir.exists() {
|
||||
if !args.is_present("force") {
|
||||
// Print warning
|
||||
println!();
|
||||
println!(
|
||||
"Copying the default theme to {}",
|
||||
builder.config().book.src.display()
|
||||
);
|
||||
println!("This could potentially overwrite files already present in that directory.");
|
||||
print!("\nAre you sure you want to continue? (y/n) ");
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//!
|
||||
//! The main entrypoint of the `config` module is the `Config` struct. This acts
|
||||
//! essentially as a bag of configuration information, with a couple
|
||||
//! pre-determined tables ([`BookConfig`] and [`BuildConfig`]) as well as support
|
||||
//! pre-determined tables (`BookConfig` and `BuildConfig`) as well as support
|
||||
//! for arbitrary data which is exposed to plugins and alternative backends.
|
||||
//!
|
||||
//!
|
||||
@@ -352,11 +352,6 @@ impl Serialize for Config {
|
||||
let book_config = Value::try_from(&self.book).expect("should always be serializable");
|
||||
table.insert("book", book_config);
|
||||
|
||||
if self.build != BuildConfig::default() {
|
||||
let build_config = Value::try_from(&self.build).expect("should always be serializable");
|
||||
table.insert("build", build_config);
|
||||
}
|
||||
|
||||
if self.rust != RustConfig::default() {
|
||||
let rust_config = Value::try_from(&self.rust).expect("should always be serializable");
|
||||
table.insert("rust", rust_config);
|
||||
|
||||
@@ -76,9 +76,9 @@
|
||||
//! access to the various methods for working with the [`Config`].
|
||||
//!
|
||||
//! [user guide]: https://rust-lang.github.io/mdBook/
|
||||
//! [`RenderContext`]: renderer::RenderContext
|
||||
//! [`RenderContext`]: renderer/struct.RenderContext.html
|
||||
//! [relevant chapter]: https://rust-lang.github.io/mdBook/for_developers/backends.html
|
||||
//! [`Config`]: config::Config
|
||||
//! [`Config`]: config/struct.Config.html
|
||||
|
||||
#![deny(missing_docs)]
|
||||
#![deny(rust_2018_idioms)]
|
||||
|
||||
@@ -335,7 +335,7 @@ impl<'a> Link<'a> {
|
||||
LinkType::Playground(ref pat, ref attrs) => {
|
||||
let target = base.join(pat);
|
||||
|
||||
let mut contents = fs::read_to_string(&target).with_context(|| {
|
||||
let contents = fs::read_to_string(&target).with_context(|| {
|
||||
format!(
|
||||
"Could not read file for link {} ({})",
|
||||
self.link_text,
|
||||
@@ -343,11 +343,8 @@ impl<'a> Link<'a> {
|
||||
)
|
||||
})?;
|
||||
let ftype = if !attrs.is_empty() { "rust," } else { "rust" };
|
||||
if !contents.ends_with('\n') {
|
||||
contents.push('\n');
|
||||
}
|
||||
Ok(format!(
|
||||
"```{}{}\n{}```\n",
|
||||
"```{}{}\n{}\n```\n",
|
||||
ftype,
|
||||
attrs.join(","),
|
||||
contents
|
||||
|
||||
@@ -366,7 +366,7 @@ impl HtmlHandlebars {
|
||||
// Note: all paths are relative to the build directory, so the
|
||||
// leading slash in an absolute path means nothing (and would mess
|
||||
// up `root.join(original)`).
|
||||
let original = original.trim_start_matches('/');
|
||||
let original = original.trim_start_matches("/");
|
||||
let filename = root.join(original);
|
||||
self.emit_redirect(handlebars, &filename, new)?;
|
||||
}
|
||||
@@ -452,7 +452,7 @@ impl Renderer for HtmlHandlebars {
|
||||
let mut handlebars = Handlebars::new();
|
||||
|
||||
let theme_dir = match html_config.theme {
|
||||
Some(ref theme) => ctx.root.join(theme),
|
||||
Some(ref theme) => theme.to_path_buf(),
|
||||
None => ctx.root.join("theme"),
|
||||
};
|
||||
|
||||
@@ -756,7 +756,7 @@ fn insert_link_into_header(
|
||||
*id_count += 1;
|
||||
|
||||
format!(
|
||||
r##"<h{level} id="{id}"><a class="header" href="#{id}">{text}</a></h{level}>"##,
|
||||
r##"<h{level}><a class="header" href="#{id}" id="{id}">{text}</a></h{level}>"##,
|
||||
level = level,
|
||||
id = id,
|
||||
text = content
|
||||
@@ -899,10 +899,10 @@ fn partition_source(s: &str) -> (String, String) {
|
||||
if !header || after_header {
|
||||
after_header = true;
|
||||
after.push_str(line);
|
||||
after.push('\n');
|
||||
after.push_str("\n");
|
||||
} else {
|
||||
before.push_str(line);
|
||||
before.push('\n');
|
||||
before.push_str("\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -927,27 +927,27 @@ mod tests {
|
||||
let inputs = vec![
|
||||
(
|
||||
"blah blah <h1>Foo</h1>",
|
||||
r##"blah blah <h1 id="foo"><a class="header" href="#foo">Foo</a></h1>"##,
|
||||
r##"blah blah <h1><a class="header" href="#foo" id="foo">Foo</a></h1>"##,
|
||||
),
|
||||
(
|
||||
"<h1>Foo</h1>",
|
||||
r##"<h1 id="foo"><a class="header" href="#foo">Foo</a></h1>"##,
|
||||
r##"<h1><a class="header" href="#foo" id="foo">Foo</a></h1>"##,
|
||||
),
|
||||
(
|
||||
"<h3>Foo^bar</h3>",
|
||||
r##"<h3 id="foobar"><a class="header" href="#foobar">Foo^bar</a></h3>"##,
|
||||
r##"<h3><a class="header" href="#foobar" id="foobar">Foo^bar</a></h3>"##,
|
||||
),
|
||||
(
|
||||
"<h4></h4>",
|
||||
r##"<h4 id=""><a class="header" href="#"></a></h4>"##,
|
||||
r##"<h4><a class="header" href="#" id=""></a></h4>"##,
|
||||
),
|
||||
(
|
||||
"<h4><em>Hï</em></h4>",
|
||||
r##"<h4 id="hï"><a class="header" href="#hï"><em>Hï</em></a></h4>"##,
|
||||
r##"<h4><a class="header" href="#hï" id="hï"><em>Hï</em></a></h4>"##,
|
||||
),
|
||||
(
|
||||
"<h1>Foo</h1><h3>Foo</h3>",
|
||||
r##"<h1 id="foo"><a class="header" href="#foo">Foo</a></h1><h3 id="foo-1"><a class="header" href="#foo-1">Foo</a></h3>"##,
|
||||
r##"<h1><a class="header" href="#foo" id="foo">Foo</a></h1><h3><a class="header" href="#foo-1" id="foo-1">Foo</a></h3>"##,
|
||||
),
|
||||
];
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::utils;
|
||||
@@ -103,7 +102,7 @@ impl HelperDef for RenderToc {
|
||||
// Part title
|
||||
if let Some(title) = item.get("part") {
|
||||
out.write("<li class=\"part-title\">")?;
|
||||
write_escaped(out, title)?;
|
||||
out.write(title)?;
|
||||
out.write("</li>")?;
|
||||
continue;
|
||||
}
|
||||
@@ -161,7 +160,7 @@ impl HelperDef for RenderToc {
|
||||
html::push_html(&mut markdown_parsed_name, parser);
|
||||
|
||||
// write to the handlebars template
|
||||
write_escaped(out, &markdown_parsed_name)?;
|
||||
out.write(&markdown_parsed_name)?;
|
||||
}
|
||||
|
||||
if path_exists {
|
||||
@@ -205,18 +204,3 @@ fn write_li_open_tag(
|
||||
li.push_str("\">");
|
||||
out.write(&li)
|
||||
}
|
||||
|
||||
fn write_escaped(out: &mut dyn Output, mut title: &str) -> io::Result<()> {
|
||||
let needs_escape: &[char] = &['<', '>'];
|
||||
while let Some(next) = title.find(needs_escape) {
|
||||
out.write(&title[..next])?;
|
||||
match title.as_bytes()[next] {
|
||||
b'<' => out.write("<")?,
|
||||
b'>' => out.write(">")?,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
title = &title[next + 1..];
|
||||
}
|
||||
out.write(title)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -95,8 +95,6 @@ fn render_item(
|
||||
let mut breadcrumbs = chapter.parent_names.clone();
|
||||
let mut footnote_numbers = HashMap::new();
|
||||
|
||||
breadcrumbs.push(chapter.name.clone());
|
||||
|
||||
while let Some(event) = p.next() {
|
||||
match event {
|
||||
Event::Start(Tag::Heading(i)) if i <= max_section_depth => {
|
||||
|
||||
@@ -20,7 +20,7 @@ mod markdown_renderer;
|
||||
use shlex::Shlex;
|
||||
use std::fs;
|
||||
use std::io::{self, ErrorKind, Read};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::PathBuf;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
use crate::book::Book;
|
||||
@@ -34,9 +34,12 @@ use toml::Value;
|
||||
/// provide your own renderer, there are two main renderer implementations that
|
||||
/// 99% of users will ever use:
|
||||
///
|
||||
/// - [`HtmlHandlebars`] - the built-in HTML renderer
|
||||
/// - [`CmdRenderer`] - a generic renderer which shells out to a program to do the
|
||||
/// - [HtmlHandlebars] - the built-in HTML renderer
|
||||
/// - [CmdRenderer] - a generic renderer which shells out to a program to do the
|
||||
/// actual rendering
|
||||
///
|
||||
/// [HtmlHandlebars]: struct.HtmlHandlebars.html
|
||||
/// [CmdRenderer]: struct.CmdRenderer.html
|
||||
pub trait Renderer {
|
||||
/// The `Renderer`'s name.
|
||||
fn name(&self) -> &str;
|
||||
@@ -130,44 +133,14 @@ impl CmdRenderer {
|
||||
CmdRenderer { name, cmd }
|
||||
}
|
||||
|
||||
fn compose_command(&self, root: &Path, destination: &Path) -> Result<Command> {
|
||||
fn compose_command(&self) -> Result<Command> {
|
||||
let mut words = Shlex::new(&self.cmd);
|
||||
let exe = match words.next() {
|
||||
Some(e) => PathBuf::from(e),
|
||||
let executable = match words.next() {
|
||||
Some(e) => e,
|
||||
None => bail!("Command string was empty"),
|
||||
};
|
||||
|
||||
let exe = if exe.components().count() == 1 {
|
||||
// Search PATH for the executable.
|
||||
exe
|
||||
} else {
|
||||
// Relative paths are preferred to be relative to the book root.
|
||||
let abs_exe = root.join(&exe);
|
||||
if abs_exe.exists() {
|
||||
abs_exe
|
||||
} else {
|
||||
// Historically paths were relative to the destination, but
|
||||
// this is not the preferred way.
|
||||
let legacy_path = destination.join(&exe);
|
||||
if legacy_path.exists() {
|
||||
warn!(
|
||||
"Renderer command `{}` uses a path relative to the \
|
||||
renderer output directory `{}`. This was previously \
|
||||
accepted, but has been deprecated. Relative executable \
|
||||
paths should be relative to the book root.",
|
||||
exe.display(),
|
||||
destination.display()
|
||||
);
|
||||
legacy_path
|
||||
} else {
|
||||
// Let this bubble through to later be handled by
|
||||
// handle_render_command_error.
|
||||
abs_exe.to_path_buf()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let mut cmd = Command::new(exe);
|
||||
let mut cmd = Command::new(executable);
|
||||
|
||||
for arg in words {
|
||||
cmd.arg(arg);
|
||||
@@ -222,7 +195,7 @@ impl Renderer for CmdRenderer {
|
||||
let _ = fs::create_dir_all(&ctx.destination);
|
||||
|
||||
let mut child = match self
|
||||
.compose_command(&ctx.root, &ctx.destination)?
|
||||
.compose_command()?
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::inherit())
|
||||
.stderr(Stdio::inherit())
|
||||
|
||||
@@ -93,7 +93,7 @@ a > .hljs {
|
||||
.menu-title {
|
||||
display: inline-block;
|
||||
font-weight: 200;
|
||||
font-size: 2.4rem;
|
||||
font-size: 2rem;
|
||||
line-height: var(--menu-bar-height);
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
|
||||
@@ -45,23 +45,20 @@ h4, h5 { margin-top: 2em; }
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
h1:target::before,
|
||||
h2:target::before,
|
||||
h3:target::before,
|
||||
h4:target::before,
|
||||
h5:target::before,
|
||||
h6:target::before {
|
||||
h1 a.header:target::before,
|
||||
h2 a.header:target::before,
|
||||
h3 a.header:target::before,
|
||||
h4 a.header:target::before {
|
||||
display: inline-block;
|
||||
content: "»";
|
||||
margin-left: -30px;
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
/* This is broken on Safari as of version 14, but is fixed
|
||||
in Safari Technology Preview 117 which I think will be Safari 14.2.
|
||||
https://bugs.webkit.org/show_bug.cgi?id=218076
|
||||
*/
|
||||
:target {
|
||||
h1 a.header:target,
|
||||
h2 a.header:target,
|
||||
h3 a.header:target,
|
||||
h4 a.header:target {
|
||||
scroll-margin-top: calc(var(--menu-bar-height) + 0.5em);
|
||||
}
|
||||
|
||||
|
||||
@@ -92,22 +92,22 @@
|
||||
|
||||
.light {
|
||||
--bg: hsl(0, 0%, 100%);
|
||||
--fg: hsl(0, 0%, 0%);
|
||||
--fg: #333333;
|
||||
|
||||
--sidebar-bg: #fafafa;
|
||||
--sidebar-fg: hsl(0, 0%, 0%);
|
||||
--sidebar-fg: #364149;
|
||||
--sidebar-non-existant: #aaaaaa;
|
||||
--sidebar-active: #1f1fff;
|
||||
--sidebar-active: #008cff;
|
||||
--sidebar-spacer: #f4f4f4;
|
||||
|
||||
--scrollbar: #8F8F8F;
|
||||
--scrollbar: #cccccc;
|
||||
|
||||
--icons: #747474;
|
||||
--icons-hover: #000000;
|
||||
--icons: #cccccc;
|
||||
--icons-hover: #333333;
|
||||
|
||||
--links: #20609f;
|
||||
--links: #4183c4;
|
||||
|
||||
--inline-code-color: #301900;
|
||||
--inline-code-color: #6e6b5e;
|
||||
|
||||
--theme-popup-bg: #fafafa;
|
||||
--theme-popup-border: #cccccc;
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
/*
|
||||
* An increased contrast highlighting scheme loosely based on the
|
||||
* "Base16 Atelier Dune Light" theme by Bram de Haan
|
||||
* (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune)
|
||||
* Original Base16 color scheme by Chris Kempson
|
||||
* (https://github.com/chriskempson/base16)
|
||||
*/
|
||||
/* Base16 Atelier Dune Light - Theme */
|
||||
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune) */
|
||||
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
|
||||
|
||||
/* Comment */
|
||||
/* Atelier-Dune Comment */
|
||||
.hljs-comment,
|
||||
.hljs-quote {
|
||||
color: #575757;
|
||||
color: #AAA;
|
||||
}
|
||||
|
||||
/* Red */
|
||||
/* Atelier-Dune Red */
|
||||
.hljs-variable,
|
||||
.hljs-template-variable,
|
||||
.hljs-attribute,
|
||||
@@ -23,10 +19,10 @@
|
||||
.hljs-name,
|
||||
.hljs-selector-id,
|
||||
.hljs-selector-class {
|
||||
color: #d70025;
|
||||
color: #d73737;
|
||||
}
|
||||
|
||||
/* Orange */
|
||||
/* Atelier-Dune Orange */
|
||||
.hljs-number,
|
||||
.hljs-meta,
|
||||
.hljs-built_in,
|
||||
@@ -34,33 +30,33 @@
|
||||
.hljs-literal,
|
||||
.hljs-type,
|
||||
.hljs-params {
|
||||
color: #b21e00;
|
||||
color: #b65611;
|
||||
}
|
||||
|
||||
/* Green */
|
||||
/* Atelier-Dune Green */
|
||||
.hljs-string,
|
||||
.hljs-symbol,
|
||||
.hljs-bullet {
|
||||
color: #008200;
|
||||
color: #60ac39;
|
||||
}
|
||||
|
||||
/* Blue */
|
||||
/* Atelier-Dune Blue */
|
||||
.hljs-title,
|
||||
.hljs-section {
|
||||
color: #0030f2;
|
||||
color: #6684e1;
|
||||
}
|
||||
|
||||
/* Purple */
|
||||
/* Atelier-Dune Purple */
|
||||
.hljs-keyword,
|
||||
.hljs-selector-tag {
|
||||
color: #9d00ec;
|
||||
color: #b854d4;
|
||||
}
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
background: #f6f7f6;
|
||||
color: #000;
|
||||
background: #f1f1f1;
|
||||
color: #6e6b5e;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
|
||||
@@ -296,7 +296,7 @@ window.search = window.search || {};
|
||||
}
|
||||
|
||||
if (url.params.hasOwnProperty(URL_MARK_PARAM)) {
|
||||
var words = decodeURIComponent(url.params[URL_MARK_PARAM]).split(' ');
|
||||
var words = url.params[URL_MARK_PARAM].split(' ');
|
||||
marker.mark(words, {
|
||||
exclude: mark_exclude
|
||||
});
|
||||
@@ -427,7 +427,6 @@ window.search = window.search || {};
|
||||
delete url.params[URL_MARK_PARAM];
|
||||
url.hash = "";
|
||||
} else {
|
||||
delete url.params[URL_MARK_PARAM];
|
||||
delete url.params[URL_SEARCH_PARAM];
|
||||
}
|
||||
// A new search will also add a new history item, so the user can go back
|
||||
|
||||
@@ -110,10 +110,7 @@ pub fn copy_files_except_ext(
|
||||
|
||||
for entry in fs::read_dir(from)? {
|
||||
let entry = entry?;
|
||||
let metadata = entry
|
||||
.path()
|
||||
.metadata()
|
||||
.with_context(|| format!("Failed to read {:?}", entry.path()))?;
|
||||
let metadata = entry.path().metadata()?;
|
||||
|
||||
// If the entry is a dir and the recursive option is enabled, call itself
|
||||
if metadata.is_dir() && recursive {
|
||||
|
||||
@@ -70,7 +70,7 @@ pub fn take_rustdoc_include_lines<R: RangeBounds<usize>>(s: &str, range: R) -> S
|
||||
output.push_str("# ");
|
||||
}
|
||||
output.push_str(line);
|
||||
output.push('\n');
|
||||
output.push_str("\n");
|
||||
}
|
||||
output.pop();
|
||||
output
|
||||
@@ -95,7 +95,7 @@ pub fn take_rustdoc_include_anchored_lines(s: &str, anchor: &str) -> String {
|
||||
None => {
|
||||
if !ANCHOR_START.is_match(l) {
|
||||
output.push_str(l);
|
||||
output.push('\n');
|
||||
output.push_str("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,7 +106,7 @@ pub fn take_rustdoc_include_anchored_lines(s: &str, anchor: &str) -> String {
|
||||
} else if !ANCHOR_END.is_match(l) {
|
||||
output.push_str("# ");
|
||||
output.push_str(l);
|
||||
output.push('\n');
|
||||
output.push_str("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ impl TomlExt for Value {
|
||||
}
|
||||
|
||||
fn split(key: &str) -> Option<(&str, &str)> {
|
||||
let ix = key.find('.')?;
|
||||
let ix = key.find(".")?;
|
||||
|
||||
let (head, tail) = key.split_at(ix);
|
||||
// splitting will leave the "."
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use mdbook::config::Config;
|
||||
use mdbook::MDBook;
|
||||
use std::fs;
|
||||
#[cfg(not(windows))]
|
||||
use std::path::Path;
|
||||
use tempfile::{Builder as TempFileBuilder, TempDir};
|
||||
|
||||
@@ -71,45 +71,6 @@ fn backends_receive_render_context_via_stdin() {
|
||||
assert!(got.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn relative_command_path() {
|
||||
// Checks behavior of relative paths for the `command` setting.
|
||||
let temp = TempFileBuilder::new().prefix("mdbook").tempdir().unwrap();
|
||||
let renderers = temp.path().join("renderers");
|
||||
fs::create_dir(&renderers).unwrap();
|
||||
rust_exe(
|
||||
&renderers,
|
||||
"myrenderer",
|
||||
r#"fn main() {
|
||||
std::fs::write("output", "test").unwrap();
|
||||
}"#,
|
||||
);
|
||||
let do_test = |cmd_path| {
|
||||
let mut config = Config::default();
|
||||
config
|
||||
.set("output.html", toml::value::Table::new())
|
||||
.unwrap();
|
||||
config.set("output.myrenderer.command", cmd_path).unwrap();
|
||||
let md = MDBook::init(&temp.path())
|
||||
.with_config(config)
|
||||
.build()
|
||||
.unwrap();
|
||||
let output = temp.path().join("book/myrenderer/output");
|
||||
assert!(!output.exists());
|
||||
md.build().unwrap();
|
||||
assert!(output.exists());
|
||||
fs::remove_file(output).unwrap();
|
||||
};
|
||||
// Legacy paths work, relative to the output directory.
|
||||
if cfg!(windows) {
|
||||
do_test("../../renderers/myrenderer.exe");
|
||||
} else {
|
||||
do_test("../../renderers/myrenderer");
|
||||
}
|
||||
// Modern path, relative to the book directory.
|
||||
do_test("renderers/myrenderer");
|
||||
}
|
||||
|
||||
fn dummy_book_with_backend(
|
||||
name: &str,
|
||||
command: &str,
|
||||
@@ -151,14 +112,3 @@ fn success_cmd() -> &'static str {
|
||||
"true"
|
||||
}
|
||||
}
|
||||
|
||||
fn rust_exe(temp: &Path, name: &str, src: &str) {
|
||||
let rs = temp.join(name).with_extension("rs");
|
||||
fs::write(&rs, src).unwrap();
|
||||
let status = std::process::Command::new("rustc")
|
||||
.arg(rs)
|
||||
.current_dir(temp)
|
||||
.status()
|
||||
.expect("rustc should run");
|
||||
assert!(status.success());
|
||||
}
|
||||
|
||||
@@ -91,12 +91,6 @@ fn run_mdbook_init_with_custom_book_and_src_locations() {
|
||||
file
|
||||
);
|
||||
}
|
||||
|
||||
let contents = fs::read_to_string(temp.path().join("book.toml")).unwrap();
|
||||
assert_eq!(
|
||||
contents,
|
||||
"[book]\nauthors = []\nlanguage = \"en\"\nmultilingual = false\nsrc = \"in\"\n\n[build]\nbuild-dir = \"out\"\ncreate-missing = true\nuse-default-preprocessors = true\n"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -108,37 +102,3 @@ fn book_toml_isnt_required() {
|
||||
|
||||
md.build().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copy_theme() {
|
||||
let temp = TempFileBuilder::new().prefix("mdbook").tempdir().unwrap();
|
||||
MDBook::init(temp.path()).copy_theme(true).build().unwrap();
|
||||
let expected = vec![
|
||||
"book.js",
|
||||
"css/chrome.css",
|
||||
"css/general.css",
|
||||
"css/print.css",
|
||||
"css/variables.css",
|
||||
"favicon.png",
|
||||
"favicon.svg",
|
||||
"highlight.css",
|
||||
"highlight.js",
|
||||
"index.hbs",
|
||||
];
|
||||
let theme_dir = temp.path().join("theme");
|
||||
let mut actual: Vec<_> = walkdir::WalkDir::new(&theme_dir)
|
||||
.into_iter()
|
||||
.filter_map(|e| e.ok())
|
||||
.filter(|e| !e.file_type().is_dir())
|
||||
.map(|e| {
|
||||
e.path()
|
||||
.strip_prefix(&theme_dir)
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.replace('\\', "/")
|
||||
})
|
||||
.collect();
|
||||
actual.sort();
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
@@ -104,12 +104,12 @@ fn check_correct_cross_links_in_nested_dir() {
|
||||
|
||||
assert_contains_strings(
|
||||
first.join("index.html"),
|
||||
&[r##"<h2 id="some-section"><a class="header" href="#some-section">"##],
|
||||
&[r##"href="#some-section" id="some-section""##],
|
||||
);
|
||||
|
||||
assert_contains_strings(
|
||||
first.join("nested.html"),
|
||||
&[r##"<h2 id="some-section"><a class="header" href="#some-section">"##],
|
||||
&[r##"href="#some-section" id="some-section""##],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -373,7 +373,7 @@ fn able_to_include_files_in_chapters() {
|
||||
let includes = temp.path().join("book/first/includes.html");
|
||||
|
||||
let summary_strings = &[
|
||||
r##"<h1 id="summary"><a class="header" href="#summary">Summary</a></h1>"##,
|
||||
r##"<h1><a class="header" href="#summary" id="summary">Summary</a></h1>"##,
|
||||
">First Chapter</a>",
|
||||
];
|
||||
assert_contains_strings(&includes, summary_strings);
|
||||
@@ -595,10 +595,7 @@ mod search {
|
||||
docs[&summary]["body"],
|
||||
"Dummy Book Introduction First Chapter Nested Chapter Includes Recursive Markdown Unicode Second Chapter Nested Chapter Conclusion"
|
||||
);
|
||||
assert_eq!(
|
||||
docs[&summary]["breadcrumbs"],
|
||||
"First Chapter » Includes » Summary"
|
||||
);
|
||||
assert_eq!(docs[&summary]["breadcrumbs"], "First Chapter » Summary");
|
||||
assert_eq!(docs[&conclusion]["body"], "I put <HTML> in here!");
|
||||
}
|
||||
|
||||
|
||||
@@ -27,234 +27,234 @@
|
||||
"docInfo": {
|
||||
"0": {
|
||||
"body": 9,
|
||||
"breadcrumbs": 4,
|
||||
"breadcrumbs": 2,
|
||||
"title": 2
|
||||
},
|
||||
"1": {
|
||||
"body": 3,
|
||||
"breadcrumbs": 2,
|
||||
"breadcrumbs": 1,
|
||||
"title": 1
|
||||
},
|
||||
"10": {
|
||||
"body": 16,
|
||||
"breadcrumbs": 4,
|
||||
"breadcrumbs": 3,
|
||||
"title": 1
|
||||
},
|
||||
"11": {
|
||||
"body": 3,
|
||||
"breadcrumbs": 5,
|
||||
"breadcrumbs": 4,
|
||||
"title": 2
|
||||
},
|
||||
"12": {
|
||||
"body": 4,
|
||||
"breadcrumbs": 4,
|
||||
"breadcrumbs": 3,
|
||||
"title": 1
|
||||
},
|
||||
"13": {
|
||||
"body": 12,
|
||||
"breadcrumbs": 4,
|
||||
"breadcrumbs": 3,
|
||||
"title": 1
|
||||
},
|
||||
"14": {
|
||||
"body": 2,
|
||||
"breadcrumbs": 4,
|
||||
"breadcrumbs": 3,
|
||||
"title": 1
|
||||
},
|
||||
"15": {
|
||||
"body": 3,
|
||||
"breadcrumbs": 4,
|
||||
"breadcrumbs": 3,
|
||||
"title": 1
|
||||
},
|
||||
"16": {
|
||||
"body": 29,
|
||||
"breadcrumbs": 6,
|
||||
"breadcrumbs": 5,
|
||||
"title": 3
|
||||
},
|
||||
"17": {
|
||||
"body": 20,
|
||||
"breadcrumbs": 4,
|
||||
"breadcrumbs": 2,
|
||||
"title": 2
|
||||
},
|
||||
"18": {
|
||||
"body": 18,
|
||||
"breadcrumbs": 9,
|
||||
"breadcrumbs": 7,
|
||||
"title": 5
|
||||
},
|
||||
"19": {
|
||||
"body": 0,
|
||||
"breadcrumbs": 5,
|
||||
"breadcrumbs": 3,
|
||||
"title": 1
|
||||
},
|
||||
"2": {
|
||||
"body": 2,
|
||||
"breadcrumbs": 4,
|
||||
"breadcrumbs": 2,
|
||||
"title": 2
|
||||
},
|
||||
"20": {
|
||||
"body": 3,
|
||||
"breadcrumbs": 2,
|
||||
"breadcrumbs": 1,
|
||||
"title": 1
|
||||
},
|
||||
"3": {
|
||||
"body": 0,
|
||||
"breadcrumbs": 3,
|
||||
"breadcrumbs": 1,
|
||||
"title": 1
|
||||
},
|
||||
"4": {
|
||||
"body": 4,
|
||||
"breadcrumbs": 6,
|
||||
"breadcrumbs": 4,
|
||||
"title": 2
|
||||
},
|
||||
"5": {
|
||||
"body": 1,
|
||||
"breadcrumbs": 5,
|
||||
"breadcrumbs": 3,
|
||||
"title": 1
|
||||
},
|
||||
"6": {
|
||||
"body": 21,
|
||||
"breadcrumbs": 11,
|
||||
"breadcrumbs": 9,
|
||||
"title": 7
|
||||
},
|
||||
"7": {
|
||||
"body": 6,
|
||||
"breadcrumbs": 10,
|
||||
"breadcrumbs": 8,
|
||||
"title": 6
|
||||
},
|
||||
"8": {
|
||||
"body": 6,
|
||||
"breadcrumbs": 8,
|
||||
"breadcrumbs": 6,
|
||||
"title": 4
|
||||
},
|
||||
"9": {
|
||||
"body": 0,
|
||||
"breadcrumbs": 4,
|
||||
"breadcrumbs": 3,
|
||||
"title": 1
|
||||
}
|
||||
},
|
||||
"docs": {
|
||||
"0": {
|
||||
"body": "This file is just here to cause the index preprocessor to run. Does a pretty good job, too.",
|
||||
"breadcrumbs": "Dummy Book » Dummy Book",
|
||||
"breadcrumbs": "Dummy Book",
|
||||
"id": "0",
|
||||
"title": "Dummy Book"
|
||||
},
|
||||
"1": {
|
||||
"body": "Here's some interesting text...",
|
||||
"breadcrumbs": "Introduction » Introduction",
|
||||
"breadcrumbs": "Introduction",
|
||||
"id": "1",
|
||||
"title": "Introduction"
|
||||
},
|
||||
"10": {
|
||||
"body": "Dummy Book Introduction First Chapter Nested Chapter Includes Recursive Markdown Unicode Second Chapter Nested Chapter Conclusion",
|
||||
"breadcrumbs": "First Chapter » Includes » Summary",
|
||||
"breadcrumbs": "First Chapter » Summary",
|
||||
"id": "10",
|
||||
"title": "Summary"
|
||||
},
|
||||
"11": {
|
||||
"body": "Tests for some markdown output.",
|
||||
"breadcrumbs": "First Chapter » Markdown » Markdown tests",
|
||||
"breadcrumbs": "First Chapter » Markdown tests",
|
||||
"id": "11",
|
||||
"title": "Markdown tests"
|
||||
},
|
||||
"12": {
|
||||
"body": "foo bar baz bim",
|
||||
"breadcrumbs": "First Chapter » Markdown » Tables",
|
||||
"breadcrumbs": "First Chapter » Tables",
|
||||
"id": "12",
|
||||
"title": "Tables"
|
||||
},
|
||||
"13": {
|
||||
"body": "Footnote example [1] , or with a word [2] . This is a footnote. A longer footnote. With multiple lines. Third line.",
|
||||
"breadcrumbs": "First Chapter » Markdown » Footnotes",
|
||||
"breadcrumbs": "First Chapter » Footnotes",
|
||||
"id": "13",
|
||||
"title": "Footnotes"
|
||||
},
|
||||
"14": {
|
||||
"body": "strikethrough example",
|
||||
"breadcrumbs": "First Chapter » Markdown » Strikethrough",
|
||||
"breadcrumbs": "First Chapter » Strikethrough",
|
||||
"id": "14",
|
||||
"title": "Strikethrough"
|
||||
},
|
||||
"15": {
|
||||
"body": "Apples Broccoli Carrots",
|
||||
"breadcrumbs": "First Chapter » Markdown » Tasklisks",
|
||||
"breadcrumbs": "First Chapter » Tasklisks",
|
||||
"id": "15",
|
||||
"title": "Tasklisks"
|
||||
},
|
||||
"16": {
|
||||
"body": "Please be careful editing, this contains carefully crafted characters. Two byte character: spatiëring Combining character: spatiëring Three byte character: 书こんにちは Four byte character: 𐌀𐌁𐌂𐌃𐌄𐌅𐌆𐌇𐌈 Right-to-left: مرحبا Emoticons: 🔊 😍 💜 1️⃣ right-to-left mark: hello באמת! Zalgo: ǫ̛̖̱̗̝͈̋͒͋̏ͥͫ̒̆ͩ̏͌̾͊͐ͪ̾̚",
|
||||
"breadcrumbs": "First Chapter » Unicode » Unicode stress tests",
|
||||
"breadcrumbs": "First Chapter » Unicode stress tests",
|
||||
"id": "16",
|
||||
"title": "Unicode stress tests"
|
||||
},
|
||||
"17": {
|
||||
"body": "This makes sure you can insert runnable Rust files. fn main() { println!(\"Hello World!\");\n#\n# // You can even hide lines! :D\n# println!(\"I am hidden! Expand the code snippet to see me\");\n}",
|
||||
"breadcrumbs": "Second Chapter » Second Chapter",
|
||||
"breadcrumbs": "Second Chapter",
|
||||
"id": "17",
|
||||
"title": "Second Chapter"
|
||||
},
|
||||
"18": {
|
||||
"body": "When we link to the first section , it should work on both the print page and the non-print page. A fragment link should work. Link outside . Some image HTML Link",
|
||||
"breadcrumbs": "Second Chapter » Nested Chapter » Testing relative links for the print page",
|
||||
"breadcrumbs": "Second Chapter » Testing relative links for the print page",
|
||||
"id": "18",
|
||||
"title": "Testing relative links for the print page"
|
||||
},
|
||||
"19": {
|
||||
"body": "",
|
||||
"breadcrumbs": "Second Chapter » Nested Chapter » Some section",
|
||||
"breadcrumbs": "Second Chapter » Some section",
|
||||
"id": "19",
|
||||
"title": "Some section"
|
||||
},
|
||||
"2": {
|
||||
"body": "more text.",
|
||||
"breadcrumbs": "First Chapter » First Chapter",
|
||||
"breadcrumbs": "First Chapter",
|
||||
"id": "2",
|
||||
"title": "First Chapter"
|
||||
},
|
||||
"20": {
|
||||
"body": "I put <HTML> in here!",
|
||||
"breadcrumbs": "Conclusion » Conclusion",
|
||||
"breadcrumbs": "Conclusion",
|
||||
"id": "20",
|
||||
"title": "Conclusion"
|
||||
},
|
||||
"3": {
|
||||
"body": "",
|
||||
"breadcrumbs": "First Chapter » Some Section",
|
||||
"breadcrumbs": "Some Section",
|
||||
"id": "3",
|
||||
"title": "Some Section"
|
||||
},
|
||||
"4": {
|
||||
"body": "This file has some testable code. assert!(true);",
|
||||
"breadcrumbs": "First Chapter » Nested Chapter » Nested Chapter",
|
||||
"breadcrumbs": "First Chapter » Nested Chapter",
|
||||
"id": "4",
|
||||
"title": "Nested Chapter"
|
||||
},
|
||||
"5": {
|
||||
"body": "assert!(true);",
|
||||
"breadcrumbs": "First Chapter » Nested Chapter » Some Section",
|
||||
"breadcrumbs": "First Chapter » Some Section",
|
||||
"id": "5",
|
||||
"title": "Some Section"
|
||||
},
|
||||
"6": {
|
||||
"body": "// The next line will cause a `rendered_output` test to fail if the anchor feature is broken in\n// such a way that the content between anchors isn't included.\n// unique-string-for-anchor-test\nassert!(true);",
|
||||
"breadcrumbs": "First Chapter » Nested Chapter » Anchors include the part of a file between special comments",
|
||||
"breadcrumbs": "First Chapter » Anchors include the part of a file between special comments",
|
||||
"id": "6",
|
||||
"title": "Anchors include the part of a file between special comments"
|
||||
},
|
||||
"7": {
|
||||
"body": "# fn some_function() {\n# assert!(true);\n# }\n# fn main() { some_function();\n}",
|
||||
"breadcrumbs": "First Chapter » Nested Chapter » Rustdoc include adds the rest of the file as hidden",
|
||||
"breadcrumbs": "First Chapter » Rustdoc include adds the rest of the file as hidden",
|
||||
"id": "7",
|
||||
"title": "Rustdoc include adds the rest of the file as hidden"
|
||||
},
|
||||
"8": {
|
||||
"body": "# fn some_other_function() {\n# assert!(true);\n# }\n# fn main() { some_other_function();\n}",
|
||||
"breadcrumbs": "First Chapter » Nested Chapter » Rustdoc include works with anchors too",
|
||||
"breadcrumbs": "First Chapter » Rustdoc include works with anchors too",
|
||||
"id": "8",
|
||||
"title": "Rustdoc include works with anchors too"
|
||||
},
|
||||
"9": {
|
||||
"body": "",
|
||||
"breadcrumbs": "First Chapter » Includes » Includes",
|
||||
"breadcrumbs": "First Chapter » Includes",
|
||||
"id": "9",
|
||||
"title": "Includes"
|
||||
}
|
||||
@@ -3048,7 +3048,7 @@
|
||||
"df": 2,
|
||||
"docs": {
|
||||
"0": {
|
||||
"tf": 1.7320508075688772
|
||||
"tf": 1.4142135623730951
|
||||
},
|
||||
"10": {
|
||||
"tf": 1.0
|
||||
@@ -3222,7 +3222,7 @@
|
||||
"df": 0,
|
||||
"docs": {},
|
||||
"r": {
|
||||
"df": 18,
|
||||
"df": 17,
|
||||
"docs": {
|
||||
"10": {
|
||||
"tf": 2.23606797749979
|
||||
@@ -3246,34 +3246,31 @@
|
||||
"tf": 1.0
|
||||
},
|
||||
"17": {
|
||||
"tf": 1.7320508075688772
|
||||
"tf": 1.4142135623730951
|
||||
},
|
||||
"18": {
|
||||
"tf": 1.4142135623730951
|
||||
},
|
||||
"19": {
|
||||
"tf": 1.4142135623730951
|
||||
},
|
||||
"2": {
|
||||
"tf": 1.7320508075688772
|
||||
},
|
||||
"3": {
|
||||
"tf": 1.0
|
||||
},
|
||||
"19": {
|
||||
"tf": 1.0
|
||||
},
|
||||
"2": {
|
||||
"tf": 1.4142135623730951
|
||||
},
|
||||
"4": {
|
||||
"tf": 2.0
|
||||
"tf": 1.7320508075688772
|
||||
},
|
||||
"5": {
|
||||
"tf": 1.4142135623730951
|
||||
"tf": 1.0
|
||||
},
|
||||
"6": {
|
||||
"tf": 1.4142135623730951
|
||||
"tf": 1.0
|
||||
},
|
||||
"7": {
|
||||
"tf": 1.4142135623730951
|
||||
"tf": 1.0
|
||||
},
|
||||
"8": {
|
||||
"tf": 1.4142135623730951
|
||||
"tf": 1.0
|
||||
},
|
||||
"9": {
|
||||
"tf": 1.0
|
||||
@@ -3382,7 +3379,7 @@
|
||||
"tf": 1.0
|
||||
},
|
||||
"20": {
|
||||
"tf": 1.7320508075688772
|
||||
"tf": 1.4142135623730951
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3470,7 +3467,7 @@
|
||||
"df": 2,
|
||||
"docs": {
|
||||
"0": {
|
||||
"tf": 1.7320508075688772
|
||||
"tf": 1.4142135623730951
|
||||
},
|
||||
"10": {
|
||||
"tf": 1.0
|
||||
@@ -3675,7 +3672,7 @@
|
||||
"df": 0,
|
||||
"docs": {},
|
||||
"t": {
|
||||
"df": 16,
|
||||
"df": 15,
|
||||
"docs": {
|
||||
"10": {
|
||||
"tf": 1.4142135623730951
|
||||
@@ -3702,10 +3699,7 @@
|
||||
"tf": 1.0
|
||||
},
|
||||
"2": {
|
||||
"tf": 1.7320508075688772
|
||||
},
|
||||
"3": {
|
||||
"tf": 1.0
|
||||
"tf": 1.4142135623730951
|
||||
},
|
||||
"4": {
|
||||
"tf": 1.0
|
||||
@@ -3970,7 +3964,7 @@
|
||||
"df": 5,
|
||||
"docs": {
|
||||
"10": {
|
||||
"tf": 1.4142135623730951
|
||||
"tf": 1.0
|
||||
},
|
||||
"6": {
|
||||
"tf": 1.7320508075688772
|
||||
@@ -3982,7 +3976,7 @@
|
||||
"tf": 1.4142135623730951
|
||||
},
|
||||
"9": {
|
||||
"tf": 1.7320508075688772
|
||||
"tf": 1.4142135623730951
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -4071,7 +4065,7 @@
|
||||
"df": 2,
|
||||
"docs": {
|
||||
"1": {
|
||||
"tf": 1.7320508075688772
|
||||
"tf": 1.4142135623730951
|
||||
},
|
||||
"10": {
|
||||
"tf": 1.0
|
||||
@@ -4288,25 +4282,13 @@
|
||||
"df": 0,
|
||||
"docs": {},
|
||||
"n": {
|
||||
"df": 6,
|
||||
"df": 2,
|
||||
"docs": {
|
||||
"10": {
|
||||
"tf": 1.0
|
||||
},
|
||||
"11": {
|
||||
"tf": 2.0
|
||||
},
|
||||
"12": {
|
||||
"tf": 1.0
|
||||
},
|
||||
"13": {
|
||||
"tf": 1.0
|
||||
},
|
||||
"14": {
|
||||
"tf": 1.0
|
||||
},
|
||||
"15": {
|
||||
"tf": 1.0
|
||||
"tf": 1.7320508075688772
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4379,31 +4361,13 @@
|
||||
"df": 0,
|
||||
"docs": {},
|
||||
"t": {
|
||||
"df": 8,
|
||||
"df": 2,
|
||||
"docs": {
|
||||
"10": {
|
||||
"tf": 1.4142135623730951
|
||||
},
|
||||
"18": {
|
||||
"tf": 1.0
|
||||
},
|
||||
"19": {
|
||||
"tf": 1.0
|
||||
},
|
||||
"4": {
|
||||
"tf": 1.7320508075688772
|
||||
},
|
||||
"5": {
|
||||
"tf": 1.0
|
||||
},
|
||||
"6": {
|
||||
"tf": 1.0
|
||||
},
|
||||
"7": {
|
||||
"tf": 1.0
|
||||
},
|
||||
"8": {
|
||||
"tf": 1.0
|
||||
"tf": 1.4142135623730951
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4879,7 +4843,7 @@
|
||||
"tf": 1.0
|
||||
},
|
||||
"17": {
|
||||
"tf": 1.7320508075688772
|
||||
"tf": 1.4142135623730951
|
||||
},
|
||||
"18": {
|
||||
"tf": 1.0
|
||||
@@ -5421,7 +5385,7 @@
|
||||
"tf": 1.0
|
||||
},
|
||||
"16": {
|
||||
"tf": 1.7320508075688772
|
||||
"tf": 1.4142135623730951
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user