Update to mdbook 0.5

This updates to mdbook 0.5.2 from mdbook 0.4.52. A primary aspect of
this change is that it splits the `mdbook` crate into multiple crates,
and various API changes and cleanup.

There's full release notes and a migration guide at
https://github.com/rust-lang/mdBook/blob/master/CHANGELOG.md#mdbook-050.

This also includes submodule updates:

## book

2 commits in 8c0eacd5c4acbb650497454f3a58c9e8083202a4..39aeceaa3aeab845bc4517e7a44e48727d3b9dbe
2025-11-18 10:36:41 -0500 to 2025-12-12 11:02:27 -0500
- Synchronize TrplNote name
- Update to mdbook 0.5

## edition-guide

1 commits in 9cf5443d632673c4d41edad5e8ed8be86eeb3b8f..c3c0f0b3da26610138b7ba7663f60cd2c68cf184
2025-11-15 21:51:11 +0000 to 2025-11-28 18:54:18 +0000
- Update to mdbook 0.5 (rust-lang/edition-guide#381)

## nomicon

2 commits in 0fe83ab28985b99aba36a1f0dbde3e08286fefda..9fe8fa599ad228dda74f240cc32b54bc5c1aa3e6
2025-11-15 00:03:14 +0000 to 2025-12-03 11:54:04 +0000
- Remove references to outdated unsafe code guidelines (rust-lang/nomicon#512)
- Update to mdbook 0.5 (rust-lang/nomicon#511)

## reference

5 commits in b14b4e40f53ca468beaf2f5d0dfb4f4c4ba6bc7b..50c5de90487b68d429a30cc9466dc8f5b410128f
2025-12-02 21:17:44 +0000 to 2025-12-09 22:19:05 +0000
- UB: update the extra clause for provenance UB during const evaluation (rust-lang/reference#2091)
- Remove `[no-mentions]` handler in our triagebot config (rust-lang/reference#2102)
- Clarify that omitting `nostack` is a promise from the compiler to the programmer (rust-lang/reference#1999)
- Specify that range patterns must be nonempty. (rust-lang/reference#2093)
- Update to mdbook 0.5 (rust-lang/reference#2096)

## rust-by-example

1 commits in 111cfae2f9c3a43f7b0ff8fa68c51cc8f930637c..7d21279e40e8f0e91c2a22c5148dd2d745aef8b6
2025-11-27 17:16:42 -0300 to 2025-12-01 15:02:09 -0300
- Update to mdbook 0.5 (rust-lang/rust-by-example#1977)
This commit is contained in:
Eric Huss 2025-12-11 15:49:36 -08:00
parent 198328ad79
commit 29f688a05f
17 changed files with 412 additions and 862 deletions

@ -1 +1 @@
Subproject commit 8c0eacd5c4acbb650497454f3a58c9e8083202a4
Subproject commit 39aeceaa3aeab845bc4517e7a44e48727d3b9dbe

@ -1 +1 @@
Subproject commit 9cf5443d632673c4d41edad5e8ed8be86eeb3b8f
Subproject commit c3c0f0b3da26610138b7ba7663f60cd2c68cf184

@ -1 +1 @@
Subproject commit 0fe83ab28985b99aba36a1f0dbde3e08286fefda
Subproject commit 9fe8fa599ad228dda74f240cc32b54bc5c1aa3e6

@ -1 +1 @@
Subproject commit b14b4e40f53ca468beaf2f5d0dfb4f4c4ba6bc7b
Subproject commit 50c5de90487b68d429a30cc9466dc8f5b410128f

@ -1 +1 @@
Subproject commit 111cfae2f9c3a43f7b0ff8fa68c51cc8f930637c
Subproject commit 7d21279e40e8f0e91c2a22c5148dd2d745aef8b6

View file

@ -1,13 +1,9 @@
[book]
multilingual = false
src = "src"
title = "The rustc book"
[output.html]
git-repository-url = "https://github.com/rust-lang/rust/tree/HEAD/src/doc/rustc"
edit-url-template = "https://github.com/rust-lang/rust/edit/HEAD/src/doc/rustc/{path}"
additional-css = ["theme/pagetoc.css"]
additional-js = ["theme/pagetoc.js"]
[output.html.search]
use-boolean-and = true

View file

@ -1,84 +0,0 @@
/* Inspired by https://github.com/JorelAli/mdBook-pagetoc/tree/98ee241 (under WTFPL) */
:root {
--toc-width: 270px;
--center-content-toc-shift: calc(-1 * var(--toc-width) / 2);
}
.nav-chapters {
/* adjust width of buttons that bring to the previous or the next page */
min-width: 50px;
}
@media only screen {
@media (max-width: 1179px) {
.sidebar-hidden #sidetoc {
display: none;
}
}
@media (max-width: 1439px) {
.sidebar-visible #sidetoc {
display: none;
}
}
@media (1180px <= width <= 1439px) {
.sidebar-hidden main {
position: relative;
left: var(--center-content-toc-shift);
}
}
@media (1440px <= width <= 1700px) {
.sidebar-visible main {
position: relative;
left: var(--center-content-toc-shift);
}
}
#sidetoc {
margin-left: calc(100% + 20px);
}
#pagetoc {
position: fixed;
/* adjust TOC width */
width: var(--toc-width);
height: calc(100vh - var(--menu-bar-height) - 0.67em * 4);
overflow: auto;
}
#pagetoc a {
border-left: 1px solid var(--sidebar-bg);
color: var(--fg);
display: block;
padding-bottom: 5px;
padding-top: 5px;
padding-left: 10px;
text-align: left;
text-decoration: none;
}
#pagetoc a:hover,
#pagetoc a.active {
background: var(--sidebar-bg);
color: var(--sidebar-active) !important;
}
#pagetoc .active {
background: var(--sidebar-bg);
color: var(--sidebar-active);
}
#pagetoc .pagetoc-H2 {
padding-left: 20px;
}
#pagetoc .pagetoc-H3 {
padding-left: 40px;
}
#pagetoc .pagetoc-H4 {
padding-left: 60px;
}
}
@media print {
#sidetoc {
display: none;
}
}

View file

@ -1,104 +0,0 @@
// Inspired by https://github.com/JorelAli/mdBook-pagetoc/tree/98ee241 (under WTFPL)
let activeHref = location.href;
function updatePageToc(elem = undefined) {
let selectedPageTocElem = elem;
const pagetoc = document.getElementById("pagetoc");
function getRect(element) {
return element.getBoundingClientRect();
}
function overflowTop(container, element) {
return getRect(container).top - getRect(element).top;
}
function overflowBottom(container, element) {
return getRect(container).bottom - getRect(element).bottom;
}
// We've not selected a heading to highlight, and the URL needs updating
// so we need to find a heading based on the URL
if (selectedPageTocElem === undefined && location.href !== activeHref) {
activeHref = location.href;
for (const pageTocElement of pagetoc.children) {
if (pageTocElement.href === activeHref) {
selectedPageTocElem = pageTocElement;
}
}
}
// We still don't have a selected heading, let's try and find the most
// suitable heading based on the scroll position
if (selectedPageTocElem === undefined) {
const margin = window.innerHeight / 3;
const headers = document.getElementsByClassName("header");
for (let i = 0; i < headers.length; i++) {
const header = headers[i];
if (selectedPageTocElem === undefined && getRect(header).top >= 0) {
if (getRect(header).top < margin) {
selectedPageTocElem = header;
} else {
selectedPageTocElem = headers[Math.max(0, i - 1)];
}
}
// a very long last section's heading is over the screen
if (selectedPageTocElem === undefined && i === headers.length - 1) {
selectedPageTocElem = header;
}
}
}
// Remove the active flag from all pagetoc elements
for (const pageTocElement of pagetoc.children) {
pageTocElement.classList.remove("active");
}
// If we have a selected heading, set it to active and scroll to it
if (selectedPageTocElem !== undefined) {
for (const pageTocElement of pagetoc.children) {
if (selectedPageTocElem.href.localeCompare(pageTocElement.href) === 0) {
pageTocElement.classList.add("active");
if (overflowTop(pagetoc, pageTocElement) > 0) {
pagetoc.scrollTop = pageTocElement.offsetTop;
}
if (overflowBottom(pagetoc, pageTocElement) < 0) {
pagetoc.scrollTop -= overflowBottom(pagetoc, pageTocElement);
}
}
}
}
}
if (document.getElementById("sidetoc") === null &&
document.getElementsByClassName("header").length > 0) {
// The sidetoc element doesn't exist yet, let's create it
// Create the empty sidetoc and pagetoc elements
const sidetoc = document.createElement("div");
const pagetoc = document.createElement("div");
sidetoc.id = "sidetoc";
pagetoc.id = "pagetoc";
sidetoc.appendChild(pagetoc);
// And append them to the current DOM
const main = document.querySelector('main');
main.insertBefore(sidetoc, main.firstChild);
// Populate sidebar on load
window.addEventListener("load", () => {
for (const header of document.getElementsByClassName("header")) {
const link = document.createElement("a");
link.innerHTML = header.innerHTML;
link.href = header.hash;
link.classList.add("pagetoc-" + header.parentElement.tagName);
document.getElementById("pagetoc").appendChild(link);
link.onclick = () => updatePageToc(link);
}
updatePageToc();
});
// Update page table of contents selected heading on scroll
window.addEventListener("scroll", () => updatePageToc());
}

View file

@ -4,7 +4,7 @@ Rustdoc's HTML output includes a settings menu, and this chapter describes what
each setting in this menu does.
It can be accessed by clicking on the gear button
(<i class="fa fa-cog" aria-hidden="true"></i>) in the upper right.
(<i class="fas fa-gear" aria-hidden="true"></i>) in the upper right.
## Changing displayed theme

View file

@ -1,8 +1,6 @@
[book]
title = "The Rust Style Guide"
author = "The Rust Style Team"
multilingual = false
src = "src"
authors = ["The Rust Style Team"]
[output.html]
git-repository-url = "https://github.com/rust-lang/rust/tree/HEAD/src/doc/style-guide/"

View file

@ -1,6 +1,5 @@
[book]
title = "The Rust Unstable Book"
author = "The Rust Community"
[output.html]
git-repository-url = "https://github.com/rust-lang/rust/tree/HEAD/src/doc/unstable-book"

View file

@ -5,7 +5,8 @@ edition = "2021"
workspace = "../rustbook"
[dependencies]
mdbook = { version = "0.4", default-features = false, features = ["search"] }
mdbook-driver = { version = "0.5.1", features = ["search"] }
mdbook-summary = "0.5.1"
[[bin]]
name = "error_index_generator"

View file

@ -12,8 +12,10 @@ use std::io::Write;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use mdbook::book::{BookItem, Chapter, parse_summary};
use mdbook::{Config, MDBook};
use mdbook_driver::MDBook;
use mdbook_driver::book::{BookItem, Chapter};
use mdbook_driver::config::Config;
use mdbook_summary::parse_summary;
use rustc_errors::codes::DIAGNOSTICS;
enum OutputFormat {
@ -121,7 +123,7 @@ This page lists all the error codes emitted by the Rust compiler.
source_path: None,
parent_names: Vec::new(),
};
book.book.sections.push(BookItem::Chapter(chapter));
book.book.items.push(BookItem::Chapter(chapter));
book.build()?;
// The error-index used to be generated manually (without mdbook), and the

File diff suppressed because it is too large Load diff

View file

@ -8,14 +8,9 @@ license = "MIT OR Apache-2.0"
edition = "2021"
[dependencies]
clap = "4.0.32"
env_logger = "0.11"
libc = "0.2"
mdbook-trpl = { path = "../../doc/book/packages/mdbook-trpl" }
mdbook-i18n-helpers = "0.3.3"
clap = { version = "4.0.32", features = ["cargo"] }
mdbook-driver = { version = "0.5.2", features = ["search"] }
mdbook-i18n-helpers = "0.4.0"
mdbook-spec = { path = "../../doc/reference/mdbook-spec" }
[dependencies.mdbook]
version = "0.4.52"
default-features = false
features = ["search"]
mdbook-trpl = { path = "../../doc/book/packages/mdbook-trpl" }
tracing-subscriber = { version = "0.3.20", features = ["env-filter"] }

View file

@ -2,15 +2,27 @@ use std::env;
use std::path::{Path, PathBuf};
use clap::{ArgMatches, Command, arg, crate_version};
use mdbook::MDBook;
use mdbook::errors::Result as Result3;
use mdbook_driver::MDBook;
use mdbook_driver::errors::Result as Result3;
use mdbook_i18n_helpers::preprocessors::Gettext;
use mdbook_spec::Spec;
use mdbook_trpl::{Figure, Listing, Note};
fn main() {
let crate_version = concat!("v", crate_version!());
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("warn")).init();
let filter = tracing_subscriber::EnvFilter::builder()
.with_env_var("MDBOOK_LOG")
.with_default_directive(tracing_subscriber::filter::LevelFilter::INFO.into())
.from_env_lossy();
tracing_subscriber::fmt()
.without_time()
.with_ansi(std::io::IsTerminal::is_terminal(&std::io::stderr()))
.with_writer(std::io::stderr)
.with_env_filter(filter)
.with_target(std::env::var_os("MDBOOK_LOG").is_some())
.init();
// env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
let d_arg = arg!(-d --"dest-dir" <DEST_DIR>
"The output directory for your book\n(Defaults to ./book when omitted)")
.required(false)
@ -82,60 +94,22 @@ fn main() {
};
}
// Build command implementation
pub fn build(args: &ArgMatches) -> Result3<()> {
fn build(args: &ArgMatches) -> Result3<()> {
let book_dir = get_book_dir(args);
let mut book = load_book(&book_dir)?;
if let Some(lang) = args.get_one::<String>("lang") {
let gettext = Gettext;
book.with_preprocessor(gettext);
book.config.set("book.language", lang).unwrap();
}
// Set this to allow us to catch bugs in advance.
book.config.build.create_missing = false;
if let Some(dest_dir) = args.get_one::<PathBuf>("dest-dir") {
book.config.build.build_dir = dest_dir.into();
}
// NOTE: Replacing preprocessors using this technique causes error
// messages to be displayed when the original preprocessor doesn't work
// (but it otherwise succeeds).
//
// This should probably be fixed in mdbook to remove the existing
// preprocessor, or this should modify the config and use
// MDBook::load_with_config.
if book.config.get_preprocessor("trpl-note").is_some() {
book.with_preprocessor(Note);
}
if book.config.get_preprocessor("trpl-listing").is_some() {
book.with_preprocessor(Listing);
}
if book.config.get_preprocessor("trpl-figure").is_some() {
book.with_preprocessor(Figure);
}
if book.config.get_preprocessor("spec").is_some() {
let rust_root = args.get_one::<PathBuf>("rust-root").cloned();
book.with_preprocessor(Spec::new(rust_root)?);
}
book.build()?;
Ok(())
let dest_dir = args.get_one::<PathBuf>("dest-dir");
let lang = args.get_one::<String>("lang");
let rust_root = args.get_one::<PathBuf>("rust-root");
let book = load_book(&book_dir, dest_dir, lang, rust_root.cloned())?;
book.build()
}
fn test(args: &ArgMatches) -> Result3<()> {
let book_dir = get_book_dir(args);
let mut book = load_book(&book_dir, None, None, None)?;
let library_paths = args
.try_get_one::<Vec<String>>("library-path")?
.map(|v| v.iter().map(|s| s.as_str()).collect::<Vec<&str>>())
.unwrap_or_default();
let mut book = load_book(&book_dir)?;
book.test(library_paths)
}
@ -148,10 +122,52 @@ fn get_book_dir(args: &ArgMatches) -> PathBuf {
}
}
fn load_book(book_dir: &Path) -> Result3<MDBook> {
fn load_book(
book_dir: &Path,
dest_dir: Option<&PathBuf>,
lang: Option<&String>,
rust_root: Option<PathBuf>,
) -> Result3<MDBook> {
let mut book = MDBook::load(book_dir)?;
book.config.set("output.html.input-404", "").unwrap();
book.config.set("output.html.hash-files", true).unwrap();
if let Some(lang) = lang {
let gettext = Gettext;
book.with_preprocessor(gettext);
book.config.set("book.language", lang).unwrap();
}
// Set this to allow us to catch bugs in advance.
book.config.build.create_missing = false;
if let Some(dest_dir) = dest_dir {
book.config.build.build_dir = dest_dir.into();
}
// NOTE: Replacing preprocessors using this technique causes error
// messages to be displayed when the original preprocessor doesn't work
// (but it otherwise succeeds).
//
// This should probably be fixed in mdbook to remove the existing
// preprocessor, or this should modify the config and use
// MDBook::load_with_config.
if book.config.contains_key("preprocessor.trpl-note") {
book.with_preprocessor(Note);
}
if book.config.contains_key("preprocessor.trpl-listing") {
book.with_preprocessor(Listing);
}
if book.config.contains_key("preprocessor.trpl-figure") {
book.with_preprocessor(Figure);
}
if book.config.contains_key("preprocessor.spec") {
book.with_preprocessor(Spec::new(rust_root)?);
}
Ok(book)
}
@ -159,7 +175,7 @@ fn parse_library_paths(input: &str) -> Result<Vec<String>, String> {
Ok(input.split(",").map(String::from).collect())
}
fn handle_error(error: mdbook::errors::Error) -> ! {
fn handle_error(error: mdbook_driver::errors::Error) -> ! {
eprintln!("Error: {}", error);
for cause in error.chain().skip(1) {

View file

@ -222,10 +222,14 @@ const EXCEPTIONS_RUSTC_PERF: ExceptionList = &[
const EXCEPTIONS_RUSTBOOK: ExceptionList = &[
// tidy-alphabetical-start
("cssparser", "MPL-2.0"),
("cssparser-macros", "MPL-2.0"),
("dtoa-short", "MPL-2.0"),
("mdbook", "MPL-2.0"),
("font-awesome-as-a-crate", "CC-BY-4.0 AND MIT"),
("mdbook-core", "MPL-2.0"),
("mdbook-driver", "MPL-2.0"),
("mdbook-html", "MPL-2.0"),
("mdbook-markdown", "MPL-2.0"),
("mdbook-preprocessor", "MPL-2.0"),
("mdbook-renderer", "MPL-2.0"),
("mdbook-summary", "MPL-2.0"),
// tidy-alphabetical-end
];