From 13035baeae417e41ce98f49c072220de0e6e4075 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Fri, 22 Jul 2022 15:10:05 +1000 Subject: [PATCH 01/10] Workaround rust nightly borrowcheck error (#1860) Surprisingly, this fixes the error filed at #1860! This seems suspicious, perhaps indicative of a bug in Rust's non-lexical lifetime handling? The lifetimes in the `handlebars::Renderable::render` method signature are quite complicated, and its unclear to me whether or not Rust is catching some new safety edge-case that wasn't previously handled correctly... Possibly related to `drop` order, which I *think* is related to the order of binding statements? --- src/renderer/html_handlebars/helpers/navigation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/html_handlebars/helpers/navigation.rs b/src/renderer/html_handlebars/helpers/navigation.rs index d3f6ca90..65929bbf 100644 --- a/src/renderer/html_handlebars/helpers/navigation.rs +++ b/src/renderer/html_handlebars/helpers/navigation.rs @@ -149,8 +149,8 @@ fn render( _h.template() .ok_or_else(|| RenderError::new("Error with the handlebars template")) .and_then(|t| { - let mut local_rc = rc.clone(); let local_ctx = Context::wraps(&context)?; + let mut local_rc = rc.clone(); t.render(r, &local_ctx, &mut local_rc, out) })?; From bb09caa9a32a22da8ceb2ebb901a280986c99f9f Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 22 Jul 2022 10:54:53 -0700 Subject: [PATCH 02/10] Update to 0.4.21 --- CHANGELOG.md | 7 +++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- guide/src/continuous-integration.md | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34bc27cd..686004c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## mdBook 0.4.21 +[92afe9b...8f01d02](https://github.com/rust-lang/mdBook/compare/92afe9b...8f01d02) + +### Fixed +- Fixed an issue where mdBook would fail to compile with Rust nightly-2022-07-22. + [#1861](https://github.com/rust-lang/mdBook/pull/1861) + ## mdBook 0.4.20 [53055e0...da166e0](https://github.com/rust-lang/mdBook/compare/53055e0...da166e0) diff --git a/Cargo.lock b/Cargo.lock index dd7feff1..10fae527 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -796,7 +796,7 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "mdbook" -version = "0.4.20" +version = "0.4.21" dependencies = [ "ammonia", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index de7ff8c9..60472fb7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mdbook" -version = "0.4.20" +version = "0.4.21" authors = [ "Mathieu David ", "Michael-F-Bryan ", diff --git a/guide/src/continuous-integration.md b/guide/src/continuous-integration.md index 64764d9a..c39cb010 100644 --- a/guide/src/continuous-integration.md +++ b/guide/src/continuous-integration.md @@ -21,7 +21,7 @@ A simple approach would be to use the popular `curl` CLI tool to download the ex ```sh mkdir bin -curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.20/mdbook-v0.4.20-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=bin +curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.21/mdbook-v0.4.21-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=bin bin/mdbook build ``` From 217546c2a056be7a95d029b3265bce66bd79cee4 Mon Sep 17 00:00:00 2001 From: Martin Geisler Date: Wed, 29 Jun 2022 10:31:44 +0200 Subject: [PATCH 03/10] Trim trailing whitespace in Rust code blocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before, a code block would always end with a final newline. The newline was added unconditionally by `hide_lines`. When the code block is syntax highlighted by highlight.js, this is not a problem, no empty line is added for a final trailing `\n` character. However, when the code block is editable and thus handled by the ACE editor, a trailing newline _is_ significant. I believe this issue is most closely described by https://github.com/ajaxorg/ace/issues/2083 in the upstream repository. The effect of the way ACE handles newlines is that a code block like
      Some code
    
will create an editor with _two_ lines, not just one. By trimming trailing whitespace, we ensure that we don’t accidentally create more lines in the ACE editor than necessary. --- src/renderer/html_handlebars/hbs_renderer.rs | 49 +++++++++++--------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index 26f1432c..6debd669 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -903,13 +903,16 @@ fn hide_lines(content: &str) -> String { } let mut result = String::with_capacity(content.len()); - for line in content.lines() { + let mut lines = content.lines().peekable(); + while let Some(line) = lines.next() { + // Don't include newline on the last line. + let newline = if lines.peek().is_none() { "" } else { "\n" }; if let Some(caps) = BORING_LINES_REGEX.captures(line) { if &caps[2] == "#" { result += &caps[1]; result += &caps[2]; result += &caps[3]; - result += "\n"; + result += newline; continue; } else if &caps[2] != "!" && &caps[2] != "[" { result += ""; @@ -918,13 +921,13 @@ fn hide_lines(content: &str) -> String { result += &caps[2]; } result += &caps[3]; - result += "\n"; + result += newline; result += ""; continue; } } result += line; - result += "\n"; + result += newline; } result } @@ -1004,19 +1007,19 @@ mod tests { fn add_playground() { let inputs = [ ("x()", - "
#![allow(unused)]\nfn main() {\nx()\n}\n
"), + "
#![allow(unused)]\nfn main() {\nx()\n}
"), ("fn main() {}", - "
fn main() {}\n
"), + "
fn main() {}
"), ("let s = \"foo\n # bar\n\";", - "
let s = \"foo\n bar\n\";\n
"), + "
let s = \"foo\n bar\n\";
"), ("let s = \"foo\n ## bar\n\";", - "
let s = \"foo\n # bar\n\";\n
"), + "
let s = \"foo\n # bar\n\";
"), ("let s = \"foo\n # bar\n#\n\";", - "
let s = \"foo\n bar\n\n\";\n
"), + "
let s = \"foo\n bar\n\n\";
"), ("let s = \"foo\n # bar\n\";", - "let s = \"foo\n bar\n\";\n"), + "let s = \"foo\n bar\n\";"), ("#![no_std]\nlet s = \"foo\";\n #[some_attr]", - "
#![no_std]\nlet s = \"foo\";\n #[some_attr]\n
"), + "
#![no_std]\nlet s = \"foo\";\n #[some_attr]
"), ]; for (src, should_be) in &inputs { let got = add_playground_pre( @@ -1034,13 +1037,13 @@ mod tests { fn add_playground_edition2015() { let inputs = [ ("x()", - "
#![allow(unused)]\nfn main() {\nx()\n}\n
"), + "
#![allow(unused)]\nfn main() {\nx()\n}
"), ("fn main() {}", - "
fn main() {}\n
"), + "
fn main() {}
"), ("fn main() {}", - "
fn main() {}\n
"), + "
fn main() {}
"), ("fn main() {}", - "
fn main() {}\n
"), + "
fn main() {}
"), ]; for (src, should_be) in &inputs { let got = add_playground_pre( @@ -1058,13 +1061,13 @@ mod tests { fn add_playground_edition2018() { let inputs = [ ("x()", - "
#![allow(unused)]\nfn main() {\nx()\n}\n
"), + "
#![allow(unused)]\nfn main() {\nx()\n}
"), ("fn main() {}", - "
fn main() {}\n
"), + "
fn main() {}
"), ("fn main() {}", - "
fn main() {}\n
"), + "
fn main() {}
"), ("fn main() {}", - "
fn main() {}\n
"), + "
fn main() {}
"), ]; for (src, should_be) in &inputs { let got = add_playground_pre( @@ -1082,13 +1085,13 @@ mod tests { fn add_playground_edition2021() { let inputs = [ ("x()", - "
#![allow(unused)]\nfn main() {\nx()\n}\n
"), + "
#![allow(unused)]\nfn main() {\nx()\n}
"), ("fn main() {}", - "
fn main() {}\n
"), + "
fn main() {}
"), ("fn main() {}", - "
fn main() {}\n
"), + "
fn main() {}
"), ("fn main() {}", - "
fn main() {}\n
"), + "
fn main() {}
"), ]; for (src, should_be) in &inputs { let got = add_playground_pre( From b3941526cb738d476ec05e29b9aadfd33f4d572b Mon Sep 17 00:00:00 2001 From: Joep Meindertsma Date: Tue, 23 Aug 2022 10:33:25 +0200 Subject: [PATCH 04/10] Explain how to use `site-url` Make sure people use the right kind of asset-urls. This issue only shows up when deploying, not using `mdbook serve`. --- guide/src/format/configuration/renderers.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/guide/src/format/configuration/renderers.md b/guide/src/format/configuration/renderers.md index f1d5ee15..b9c30861 100644 --- a/guide/src/format/configuration/renderers.md +++ b/guide/src/format/configuration/renderers.md @@ -157,7 +157,8 @@ The following configuration options are available: Defaults to `404.md`. - **site-url:** The url where the book will be hosted. This is required to ensure navigation links and script/css imports in the 404 file work correctly, even when accessing - urls in subdirectories. Defaults to `/`. + urls in subdirectories. Defaults to `/`. If `site-url` is set, + make sure to use document relative links for your assets, meaning they should not start with `/`. - **cname:** The DNS subdomain or apex domain at which your book will be hosted. This string will be written to a file named CNAME in the root of your site, as required by GitHub Pages (see [*Managing a custom domain for your GitHub Pages From 74eb4059d6bea35380566411033f9a469a42f65c Mon Sep 17 00:00:00 2001 From: Chris Lovett Date: Thu, 25 Aug 2022 19:13:51 -0700 Subject: [PATCH 05/10] add a --chapter option to mdbook test. (#1741) Sometimes when working on large books it is handy to be able to run mdbook on a single chapter of a book. --- guide/src/cli/test.md | 7 ++++++- src/book/mod.rs | 26 ++++++++++++++++++++++++-- src/cmd/test.rs | 18 ++++++++++++++++-- tests/cli/test.rs | 20 ++++++++++---------- tests/testing.rs | 21 +++++++++++++++++++++ 5 files changed, 77 insertions(+), 15 deletions(-) diff --git a/guide/src/cli/test.md b/guide/src/cli/test.md index e134dc9b..a542f3ce 100644 --- a/guide/src/cli/test.md +++ b/guide/src/cli/test.md @@ -43,7 +43,7 @@ mdbook test path/to/book The `--library-path` (`-L`) option allows you to add directories to the library search path used by `rustdoc` when it builds and tests the examples. Multiple directories can be specified with multiple options (`-L foo -L bar`) or with a -comma-delimited list (`-L foo,bar`). The path should point to the Cargo +comma-delimited list (`-L foo,bar`). The path should point to the Cargo [build cache](https://doc.rust-lang.org/cargo/guide/build-cache.html) `deps` directory that contains the build output of your project. For example, if your Rust project's book is in a directory named `my-book`, the following command would include the crate's dependencies when running `test`: @@ -61,3 +61,8 @@ The `--dest-dir` (`-d`) option allows you to change the output directory for the book. Relative paths are interpreted relative to the book's root directory. If not specified it will default to the value of the `build.build-dir` key in `book.toml`, or to `./book`. + +#### --chapter + +The `--chapter` (`-c`) option allows you to test a specific chapter of the +book using the chapter name or the relative path to the chapter. \ No newline at end of file diff --git a/src/book/mod.rs b/src/book/mod.rs index 9745d2b7..e407ccc3 100644 --- a/src/book/mod.rs +++ b/src/book/mod.rs @@ -246,6 +246,13 @@ impl MDBook { /// Run `rustdoc` tests on the book, linking against the provided libraries. pub fn test(&mut self, library_paths: Vec<&str>) -> Result<()> { + // test_chapter with chapter:None will run all tests. + self.test_chapter(library_paths, None) + } + + /// Run `rustdoc` tests on a specific chapter of the book, linking against the provided libraries. + /// If `chapter` is `None`, all tests will be run. + pub fn test_chapter(&mut self, library_paths: Vec<&str>, chapter: Option<&str>) -> Result<()> { let library_args: Vec<&str> = (0..library_paths.len()) .map(|_| "-L") .zip(library_paths.into_iter()) @@ -254,6 +261,8 @@ impl MDBook { let temp_dir = TempFileBuilder::new().prefix("mdbook-").tempdir()?; + let mut chapter_found = false; + // FIXME: Is "test" the proper renderer name to use here? let preprocess_context = PreprocessorContext::new(self.root.clone(), self.config.clone(), "test".to_string()); @@ -270,8 +279,16 @@ impl MDBook { _ => continue, }; - let path = self.source_dir().join(&chapter_path); - info!("Testing file: {:?}", path); + if let Some(chapter) = chapter { + if ch.name != chapter && chapter_path.to_str() != Some(chapter) { + if chapter == "?" { + info!("Skipping chapter '{}'...", ch.name); + } + continue; + } + } + chapter_found = true; + info!("Testing chapter '{}': {:?}", ch.name, chapter_path); // write preprocessed file to tempdir let path = temp_dir.path().join(&chapter_path); @@ -311,6 +328,11 @@ impl MDBook { if failed { bail!("One or more tests failed"); } + if let Some(chapter) = chapter { + if !chapter_found { + bail!("Chapter not found: {}", chapter); + } + } Ok(()) } diff --git a/src/cmd/test.rs b/src/cmd/test.rs index 02f982a4..f5ca3ee4 100644 --- a/src/cmd/test.rs +++ b/src/cmd/test.rs @@ -17,6 +17,16 @@ pub fn make_subcommand<'help>() -> App<'help> { Relative paths are interpreted relative to the book's root directory.{n}\ If omitted, mdBook uses build.build-dir from book.toml or defaults to `./book`.", ), + ).arg( + Arg::new("chapter") + .short('c') + .long("chapter") + .value_name("chapter") + .help( + "Only test the specified chapter{n}\ + Where the name of the chapter is defined in the SUMMARY.md file.{n}\ + Use the special name \"?\" to the list of chapter names." + ) ) .arg(arg!([dir] "Root directory for the book{n}\ @@ -41,14 +51,18 @@ pub fn execute(args: &ArgMatches) -> Result<()> { .values_of("library-path") .map(std::iter::Iterator::collect) .unwrap_or_default(); + let chapter: Option<&str> = args.value_of("chapter"); + let book_dir = get_book_dir(args); let mut book = MDBook::load(&book_dir)?; if let Some(dest_dir) = args.value_of("dest-dir") { book.config.build.build_dir = dest_dir.into(); } - - book.test(library_paths)?; + match chapter { + Some(_) => book.test_chapter(library_paths, chapter), + None => book.test(library_paths), + }?; Ok(()) } diff --git a/tests/cli/test.rs b/tests/cli/test.rs index bc525d9a..63114d3a 100644 --- a/tests/cli/test.rs +++ b/tests/cli/test.rs @@ -10,11 +10,11 @@ fn mdbook_cli_can_correctly_test_a_passing_book() { let mut cmd = mdbook_cmd(); cmd.arg("test").current_dir(temp.path()); cmd.assert().success() - .stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]README.md""##).unwrap()) - .stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]intro.md""##).unwrap()) - .stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]first[\\/]index.md""##).unwrap()) - .stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]first[\\/]nested.md""##).unwrap()) - .stderr(predicates::str::is_match(r##"rustdoc returned an error:\n\n"##).unwrap().not()) + .stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "README.md""##).unwrap()) + .stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "intro.md""##).unwrap()) + .stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "first[\\/]index.md""##).unwrap()) + .stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "first[\\/]nested.md""##).unwrap()) + .stderr(predicates::str::is_match(r##"returned an error:\n\n"##).unwrap().not()) .stderr(predicates::str::is_match(r##"Nested_Chapter::Rustdoc_include_works_with_anchors_too \(line \d+\) ... FAILED"##).unwrap().not()); } @@ -25,10 +25,10 @@ fn mdbook_cli_detects_book_with_failing_tests() { let mut cmd = mdbook_cmd(); cmd.arg("test").current_dir(temp.path()); cmd.assert().failure() - .stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]README.md""##).unwrap()) - .stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]intro.md""##).unwrap()) - .stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]first[\\/]index.md""##).unwrap()) - .stderr(predicates::str::is_match(r##"Testing file: "([^"]+)[\\/]first[\\/]nested.md""##).unwrap()) - .stderr(predicates::str::is_match(r##"rustdoc returned an error:\n\n"##).unwrap()) + .stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "README.md""##).unwrap()) + .stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "intro.md""##).unwrap()) + .stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "first[\\/]index.md""##).unwrap()) + .stderr(predicates::str::is_match(r##"Testing chapter [^:]*: "first[\\/]nested.md""##).unwrap()) + .stderr(predicates::str::is_match(r##"returned an error:\n\n"##).unwrap()) .stderr(predicates::str::is_match(r##"Nested_Chapter::Rustdoc_include_works_with_anchors_too \(line \d+\) ... FAILED"##).unwrap()); } diff --git a/tests/testing.rs b/tests/testing.rs index 2b2c0fd0..3030c5cb 100644 --- a/tests/testing.rs +++ b/tests/testing.rs @@ -24,3 +24,24 @@ fn mdbook_detects_book_with_failing_tests() { assert!(md.test(vec![]).is_err()); } + +#[test] +fn mdbook_test_chapter() { + let temp = DummyBook::new().with_passing_test(true).build().unwrap(); + let mut md = MDBook::load(temp.path()).unwrap(); + + let result = md.test_chapter(vec![], Some("Introduction")); + assert!( + result.is_ok(), + "test_chapter failed with {}", + result.err().unwrap() + ); +} + +#[test] +fn mdbook_test_chapter_not_found() { + let temp = DummyBook::new().with_passing_test(true).build().unwrap(); + let mut md = MDBook::load(temp.path()).unwrap(); + + assert!(md.test_chapter(vec![], Some("Bogus Chapter Name")).is_err()); +} From 76b0493fb0d2ea90fb182c7931014f6bb1ad6b04 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 29 Aug 2022 21:07:50 +0200 Subject: [PATCH 06/10] Remove unneeded type attribute for + {{/if}} - - - - {{/if}} {{#if playground_copyable}} - {{/if}} {{#if playground_js}} - - - - - + + + + + {{/if}} {{#if search_js}} - - - + + + {{/if}} - - - + + + {{#each additional_js}} - + {{/each}} {{#if is_print}} {{#if mathjax_support}} - {{else}} -