Showing preview only (1,728K chars total). Download the full file or copy to clipboard to get everything.
Repository: rust-lang/mdBook
Branch: master
Commit: 30e0e1d1021d
Files: 601
Total size: 1.5 MB
Directory structure:
gitextract_yv8ug7wf/
├── .cargo/
│ └── config.toml
├── .git-blame-ignore-revs
├── .gitattributes
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.yml
│ │ ├── feature_request.yml
│ │ └── question.yml
│ ├── renovate.json5
│ └── workflows/
│ ├── deploy.yml
│ ├── main.yml
│ └── update-dependencies.yml
├── .gitignore
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Cargo.toml
├── LICENSE
├── README.md
├── ci/
│ ├── install-rust.sh
│ ├── make-release-asset.sh
│ ├── publish-guide.sh
│ └── update-dependencies.sh
├── crates/
│ ├── mdbook-compare/
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ └── src/
│ │ └── main.rs
│ ├── mdbook-core/
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ └── src/
│ │ ├── book/
│ │ │ └── tests.rs
│ │ ├── book.rs
│ │ ├── config.rs
│ │ ├── lib.rs
│ │ └── utils/
│ │ ├── fs.rs
│ │ ├── html.rs
│ │ ├── mod.rs
│ │ └── toml_ext.rs
│ ├── mdbook-driver/
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ └── src/
│ │ ├── builtin_preprocessors/
│ │ │ ├── cmd.rs
│ │ │ ├── index.rs
│ │ │ ├── links/
│ │ │ │ └── take_lines.rs
│ │ │ ├── links.rs
│ │ │ └── mod.rs
│ │ ├── builtin_renderers/
│ │ │ ├── markdown_renderer.rs
│ │ │ └── mod.rs
│ │ ├── init.rs
│ │ ├── lib.rs
│ │ ├── load.rs
│ │ ├── mdbook/
│ │ │ └── tests.rs
│ │ └── mdbook.rs
│ ├── mdbook-html/
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ ├── front-end/
│ │ │ ├── css/
│ │ │ │ ├── ayu-highlight.css
│ │ │ │ ├── chrome.css
│ │ │ │ ├── general.css
│ │ │ │ ├── highlight.css
│ │ │ │ ├── print.css
│ │ │ │ ├── tomorrow-night.css
│ │ │ │ └── variables.css
│ │ │ ├── fonts/
│ │ │ │ ├── OPEN-SANS-LICENSE.txt
│ │ │ │ ├── SOURCE-CODE-PRO-LICENSE.txt
│ │ │ │ └── fonts.css
│ │ │ ├── js/
│ │ │ │ ├── book.js
│ │ │ │ └── highlight.js
│ │ │ ├── playground_editor/
│ │ │ │ ├── ace.js
│ │ │ │ ├── editor.js
│ │ │ │ ├── mode-rust.js
│ │ │ │ ├── theme-dawn.js
│ │ │ │ └── theme-tomorrow_night.js
│ │ │ ├── searcher/
│ │ │ │ └── searcher.js
│ │ │ └── templates/
│ │ │ ├── head.hbs
│ │ │ ├── header.hbs
│ │ │ ├── index.hbs
│ │ │ ├── redirect.hbs
│ │ │ ├── toc.html.hbs
│ │ │ └── toc.js.hbs
│ │ └── src/
│ │ ├── html/
│ │ │ ├── admonitions.rs
│ │ │ ├── hide_lines.rs
│ │ │ ├── mod.rs
│ │ │ ├── print.rs
│ │ │ ├── serialize.rs
│ │ │ ├── tests.rs
│ │ │ ├── tokenizer.rs
│ │ │ └── tree.rs
│ │ ├── html_handlebars/
│ │ │ ├── hbs_renderer.rs
│ │ │ ├── helpers/
│ │ │ │ ├── fontawesome.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── resources.rs
│ │ │ │ └── toc.rs
│ │ │ ├── mod.rs
│ │ │ ├── search.rs
│ │ │ └── static_files.rs
│ │ ├── lib.rs
│ │ ├── theme/
│ │ │ ├── fonts.rs
│ │ │ ├── mod.rs
│ │ │ ├── playground_editor.rs
│ │ │ └── searcher.rs
│ │ └── utils.rs
│ ├── mdbook-markdown/
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ └── src/
│ │ └── lib.rs
│ ├── mdbook-preprocessor/
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ └── src/
│ │ └── lib.rs
│ ├── mdbook-renderer/
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ └── src/
│ │ └── lib.rs
│ ├── mdbook-summary/
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ └── src/
│ │ └── lib.rs
│ └── xtask/
│ ├── Cargo.toml
│ ├── README.md
│ └── src/
│ ├── changelog.rs
│ └── main.rs
├── eslint.config.mjs
├── examples/
│ ├── nop-preprocessor.rs
│ └── remove-emphasis/
│ ├── .gitignore
│ ├── book.toml
│ ├── mdbook-remove-emphasis/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── main.rs
│ ├── src/
│ │ ├── SUMMARY.md
│ │ └── chapter_1.md
│ └── test.rs
├── guide/
│ ├── book.toml
│ ├── guide-helper/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── lib.rs
│ │ └── main.rs
│ └── src/
│ ├── 404.md
│ ├── README.md
│ ├── SUMMARY.md
│ ├── cli/
│ │ ├── README.md
│ │ ├── arg-watcher.md
│ │ ├── build.md
│ │ ├── clean.md
│ │ ├── completions.md
│ │ ├── init.md
│ │ ├── serve.md
│ │ ├── test.md
│ │ └── watch.md
│ ├── continuous-integration.md
│ ├── for_developers/
│ │ ├── README.md
│ │ ├── backends.md
│ │ ├── mdbook-wordcount/
│ │ │ ├── Cargo.toml
│ │ │ └── src/
│ │ │ └── main.rs
│ │ └── preprocessors.md
│ ├── format/
│ │ ├── README.md
│ │ ├── configuration/
│ │ │ ├── README.md
│ │ │ ├── environment-variables.md
│ │ │ ├── general.md
│ │ │ ├── preprocessors.md
│ │ │ └── renderers.md
│ │ ├── example.rs
│ │ ├── markdown.md
│ │ ├── mathjax.md
│ │ ├── mdbook.md
│ │ ├── summary.md
│ │ └── theme/
│ │ ├── README.md
│ │ ├── editor.md
│ │ ├── index-hbs.md
│ │ └── syntax-highlighting.md
│ ├── guide/
│ │ ├── README.md
│ │ ├── creating.md
│ │ ├── installation.md
│ │ └── reading.md
│ └── misc/
│ └── contributors.md
├── rustfmt.toml
├── src/
│ ├── cmd/
│ │ ├── build.rs
│ │ ├── clean.rs
│ │ ├── command_prelude.rs
│ │ ├── init.rs
│ │ ├── mod.rs
│ │ ├── serve.rs
│ │ ├── test.rs
│ │ ├── watch/
│ │ │ ├── native.rs
│ │ │ └── poller.rs
│ │ └── watch.rs
│ └── main.rs
├── tests/
│ ├── gui/
│ │ ├── books/
│ │ │ ├── all-summary/
│ │ │ │ ├── README.md
│ │ │ │ ├── book.toml
│ │ │ │ └── src/
│ │ │ │ ├── SUMMARY.md
│ │ │ │ ├── intro.md
│ │ │ │ ├── part-1/
│ │ │ │ │ └── chapter-1.md
│ │ │ │ ├── part-2/
│ │ │ │ │ └── chapter-1.md
│ │ │ │ ├── prefix-1.md
│ │ │ │ ├── prefix-2.md
│ │ │ │ ├── suffix-1.md
│ │ │ │ └── suffix-2.md
│ │ │ ├── basic/
│ │ │ │ ├── book.toml
│ │ │ │ └── src/
│ │ │ │ ├── SUMMARY.md
│ │ │ │ └── chapter_1.md
│ │ │ ├── heading-nav/
│ │ │ │ ├── README.md
│ │ │ │ ├── book.toml
│ │ │ │ └── src/
│ │ │ │ ├── SUMMARY.md
│ │ │ │ ├── collapsed.md
│ │ │ │ ├── current-to-bottom.md
│ │ │ │ ├── empty.md
│ │ │ │ ├── filtered-headings.md
│ │ │ │ ├── large-intro.md
│ │ │ │ ├── markup.md
│ │ │ │ ├── normal-intro.md
│ │ │ │ └── unusual-heading-levels.md
│ │ │ ├── heading-nav-folded/
│ │ │ │ ├── book.toml
│ │ │ │ └── src/
│ │ │ │ ├── SUMMARY.md
│ │ │ │ ├── intro.md
│ │ │ │ ├── next-main.md
│ │ │ │ └── sub/
│ │ │ │ ├── index.md
│ │ │ │ ├── inner/
│ │ │ │ │ └── index.md
│ │ │ │ └── second.md
│ │ │ ├── highlighting/
│ │ │ │ ├── README.md
│ │ │ │ ├── book.toml
│ │ │ │ └── src/
│ │ │ │ ├── SUMMARY.md
│ │ │ │ └── languages.md
│ │ │ ├── redirect/
│ │ │ │ ├── README.md
│ │ │ │ ├── book.toml
│ │ │ │ └── src/
│ │ │ │ ├── SUMMARY.md
│ │ │ │ ├── chapter_1.md
│ │ │ │ ├── new-chapter.md
│ │ │ │ └── other-chapter.md
│ │ │ ├── search/
│ │ │ │ ├── README.md
│ │ │ │ ├── book.toml
│ │ │ │ └── src/
│ │ │ │ ├── SUMMARY.md
│ │ │ │ ├── chapter_1.md
│ │ │ │ └── inner/
│ │ │ │ └── chapter_2.md
│ │ │ └── sidebar-scroll/
│ │ │ ├── book.toml
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ ├── chapter_1.md
│ │ │ ├── chapter_10.md
│ │ │ ├── chapter_100.md
│ │ │ ├── chapter_11.md
│ │ │ ├── chapter_12.md
│ │ │ ├── chapter_13.md
│ │ │ ├── chapter_14.md
│ │ │ ├── chapter_15.md
│ │ │ ├── chapter_16.md
│ │ │ ├── chapter_17.md
│ │ │ ├── chapter_18.md
│ │ │ ├── chapter_19.md
│ │ │ ├── chapter_2.md
│ │ │ ├── chapter_20.md
│ │ │ ├── chapter_21.md
│ │ │ ├── chapter_22.md
│ │ │ ├── chapter_23.md
│ │ │ ├── chapter_24.md
│ │ │ ├── chapter_25.md
│ │ │ ├── chapter_26.md
│ │ │ ├── chapter_27.md
│ │ │ ├── chapter_28.md
│ │ │ ├── chapter_29.md
│ │ │ ├── chapter_3.md
│ │ │ ├── chapter_30.md
│ │ │ ├── chapter_31.md
│ │ │ ├── chapter_32.md
│ │ │ ├── chapter_33.md
│ │ │ ├── chapter_34.md
│ │ │ ├── chapter_35.md
│ │ │ ├── chapter_36.md
│ │ │ ├── chapter_37.md
│ │ │ ├── chapter_38.md
│ │ │ ├── chapter_39.md
│ │ │ ├── chapter_4.md
│ │ │ ├── chapter_40.md
│ │ │ ├── chapter_41.md
│ │ │ ├── chapter_42.md
│ │ │ ├── chapter_43.md
│ │ │ ├── chapter_44.md
│ │ │ ├── chapter_45.md
│ │ │ ├── chapter_46.md
│ │ │ ├── chapter_47.md
│ │ │ ├── chapter_48.md
│ │ │ ├── chapter_49.md
│ │ │ ├── chapter_5.md
│ │ │ ├── chapter_50.md
│ │ │ ├── chapter_51.md
│ │ │ ├── chapter_52.md
│ │ │ ├── chapter_53.md
│ │ │ ├── chapter_54.md
│ │ │ ├── chapter_55.md
│ │ │ ├── chapter_56.md
│ │ │ ├── chapter_57.md
│ │ │ ├── chapter_58.md
│ │ │ ├── chapter_59.md
│ │ │ ├── chapter_6.md
│ │ │ ├── chapter_60.md
│ │ │ ├── chapter_61.md
│ │ │ ├── chapter_62.md
│ │ │ ├── chapter_63.md
│ │ │ ├── chapter_64.md
│ │ │ ├── chapter_65.md
│ │ │ ├── chapter_66.md
│ │ │ ├── chapter_67.md
│ │ │ ├── chapter_68.md
│ │ │ ├── chapter_69.md
│ │ │ ├── chapter_7.md
│ │ │ ├── chapter_70.md
│ │ │ ├── chapter_71.md
│ │ │ ├── chapter_72.md
│ │ │ ├── chapter_73.md
│ │ │ ├── chapter_74.md
│ │ │ ├── chapter_75.md
│ │ │ ├── chapter_76.md
│ │ │ ├── chapter_77.md
│ │ │ ├── chapter_78.md
│ │ │ ├── chapter_79.md
│ │ │ ├── chapter_8.md
│ │ │ ├── chapter_80.md
│ │ │ ├── chapter_81.md
│ │ │ ├── chapter_82.md
│ │ │ ├── chapter_83.md
│ │ │ ├── chapter_84.md
│ │ │ ├── chapter_85.md
│ │ │ ├── chapter_86.md
│ │ │ ├── chapter_87.md
│ │ │ ├── chapter_88.md
│ │ │ ├── chapter_89.md
│ │ │ ├── chapter_9.md
│ │ │ ├── chapter_90.md
│ │ │ ├── chapter_91.md
│ │ │ ├── chapter_92.md
│ │ │ ├── chapter_93.md
│ │ │ ├── chapter_94.md
│ │ │ ├── chapter_95.md
│ │ │ ├── chapter_96.md
│ │ │ ├── chapter_97.md
│ │ │ ├── chapter_98.md
│ │ │ └── chapter_99.md
│ │ ├── heading-nav-collapsed.goml
│ │ ├── heading-nav-current-to-bottom.goml
│ │ ├── heading-nav-empty.goml
│ │ ├── heading-nav-filter.goml
│ │ ├── heading-nav-folded.goml
│ │ ├── heading-nav-large-intro.goml
│ │ ├── heading-nav-markup.goml
│ │ ├── heading-nav-normal-intro.goml
│ │ ├── heading-nav-unusual-levels.goml
│ │ ├── help.goml
│ │ ├── highlighting.goml
│ │ ├── move-between-pages.goml
│ │ ├── redirect.goml
│ │ ├── runner.rs
│ │ ├── search.goml
│ │ ├── sidebar-active.goml
│ │ ├── sidebar-nojs.goml
│ │ ├── sidebar-scroll.goml
│ │ ├── sidebar.goml
│ │ └── theme.goml
│ └── testsuite/
│ ├── README.md
│ ├── book_test.rs
│ ├── build/
│ │ ├── basic_build/
│ │ │ ├── README.md
│ │ │ ├── book.toml
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ └── chapter_1.md
│ │ ├── create_missing/
│ │ │ ├── book.toml
│ │ │ └── src/
│ │ │ └── SUMMARY.md
│ │ ├── missing_file/
│ │ │ ├── book.toml
│ │ │ └── src/
│ │ │ └── SUMMARY.md
│ │ └── no_reserved_filename/
│ │ ├── book.toml
│ │ └── src/
│ │ ├── SUMMARY.md
│ │ └── print.md
│ ├── build.rs
│ ├── cli.rs
│ ├── config/
│ │ └── empty/
│ │ ├── book.toml
│ │ └── src/
│ │ ├── SUMMARY.md
│ │ └── chapter_1.md
│ ├── config.rs
│ ├── includes/
│ │ └── all_includes/
│ │ ├── book.toml
│ │ └── src/
│ │ ├── SUMMARY.md
│ │ ├── anchors.md
│ │ ├── example.rs
│ │ ├── includes.md
│ │ ├── nested-test-with-anchors.rs
│ │ ├── partially-included-test-with-anchors.rs
│ │ ├── partially-included-test.rs
│ │ ├── playground.md
│ │ ├── recursive.md
│ │ ├── relative/
│ │ │ └── includes.md
│ │ ├── rustdoc.md
│ │ └── sample.md
│ ├── includes.rs
│ ├── index/
│ │ └── basic_readme/
│ │ ├── book.toml
│ │ └── src/
│ │ ├── README.md
│ │ ├── SUMMARY.md
│ │ ├── first/
│ │ │ └── README
│ │ └── second/
│ │ └── Readme.md
│ ├── index.rs
│ ├── init/
│ │ └── init_from_summary/
│ │ └── src/
│ │ └── SUMMARY.md
│ ├── init.rs
│ ├── main.rs
│ ├── markdown/
│ │ ├── admonitions/
│ │ │ ├── book.toml
│ │ │ ├── expected/
│ │ │ │ └── admonitions.html
│ │ │ ├── expected_disabled/
│ │ │ │ └── admonitions.html
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ └── admonitions.md
│ │ ├── basic_markdown/
│ │ │ ├── book.toml
│ │ │ ├── expected/
│ │ │ │ ├── blank.html
│ │ │ │ ├── blockquotes.html
│ │ │ │ ├── code-blocks.html
│ │ │ │ ├── html.html
│ │ │ │ ├── images.html
│ │ │ │ ├── inlines.html
│ │ │ │ ├── links.html
│ │ │ │ ├── lists.html
│ │ │ │ └── svg.html
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ ├── blank.md
│ │ │ ├── blockquotes.md
│ │ │ ├── code-blocks.md
│ │ │ ├── html.md
│ │ │ ├── images.md
│ │ │ ├── inlines.md
│ │ │ ├── links.md
│ │ │ ├── lists.md
│ │ │ └── svg.md
│ │ ├── custom_header_attributes/
│ │ │ ├── book.toml
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ └── custom_header_attributes.md
│ │ ├── definition_lists/
│ │ │ ├── book.toml
│ │ │ ├── expected/
│ │ │ │ ├── definition_lists.html
│ │ │ │ └── html_definition_lists.html
│ │ │ ├── expected_disabled/
│ │ │ │ ├── definition_lists.html
│ │ │ │ └── html_definition_lists.html
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ ├── definition_lists.md
│ │ │ └── html_definition_lists.md
│ │ ├── footnotes/
│ │ │ ├── expected/
│ │ │ │ └── footnotes.html
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ └── footnotes.md
│ │ ├── smart_punctuation/
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ └── smart_punctuation.md
│ │ ├── strikethrough/
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ └── strikethrough.md
│ │ ├── tables/
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ └── tables.md
│ │ └── tasklists/
│ │ └── src/
│ │ ├── SUMMARY.md
│ │ └── tasklists.md
│ ├── markdown.rs
│ ├── playground/
│ │ ├── disabled_playground/
│ │ │ ├── book.toml
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ └── disabled-rust-playground.md
│ │ └── playground_on_rust_code/
│ │ ├── book.toml
│ │ └── src/
│ │ ├── SUMMARY.md
│ │ └── rust-playground.md
│ ├── playground.rs
│ ├── preprocessor/
│ │ ├── extension_compatibility/
│ │ │ ├── book.toml
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ ├── chapter_1.md
│ │ │ ├── part/
│ │ │ │ ├── chapter.md
│ │ │ │ └── sub-chapter.md
│ │ │ ├── prefix.md
│ │ │ └── suffix.md
│ │ ├── failing_preprocessor/
│ │ │ ├── book.toml
│ │ │ └── src/
│ │ │ └── SUMMARY.md
│ │ ├── missing_optional_not_fatal/
│ │ │ ├── book.toml
│ │ │ └── src/
│ │ │ └── SUMMARY.md
│ │ ├── missing_preprocessor/
│ │ │ ├── book.toml
│ │ │ └── src/
│ │ │ └── SUMMARY.md
│ │ └── nop_preprocessor/
│ │ ├── book.toml
│ │ └── src/
│ │ └── SUMMARY.md
│ ├── preprocessor.rs
│ ├── print/
│ │ ├── chapter_no_h1/
│ │ │ ├── book.toml
│ │ │ ├── expected/
│ │ │ │ └── print.html
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ ├── chapter_1.md
│ │ │ ├── chapter_2.md
│ │ │ └── h2-instead.md
│ │ ├── duplicate_ids/
│ │ │ ├── book.toml
│ │ │ ├── expected/
│ │ │ │ └── print.html
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ ├── chapter_1.md
│ │ │ └── chapter_2.md
│ │ ├── noindex/
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ └── index.md
│ │ └── relative_links/
│ │ ├── book.toml
│ │ ├── expected/
│ │ │ └── print.html
│ │ └── src/
│ │ ├── SUMMARY.md
│ │ ├── first/
│ │ │ ├── index.md
│ │ │ └── nested.md
│ │ └── second/
│ │ └── nested.md
│ ├── print.rs
│ ├── redirects/
│ │ ├── redirect_existing_page/
│ │ │ ├── book.toml
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ └── chapter_1.md
│ │ ├── redirect_removed_with_fragments_only/
│ │ │ ├── book.toml
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ └── chapter_1.md
│ │ └── redirects_are_emitted_correctly/
│ │ ├── book.toml
│ │ ├── expected/
│ │ │ ├── nested/
│ │ │ │ └── page.html
│ │ │ └── overview.html
│ │ └── src/
│ │ ├── SUMMARY.md
│ │ ├── chapter_1.md
│ │ └── chapter_2.md
│ ├── redirects.rs
│ ├── renderer/
│ │ ├── backends_receive_render_context_via_stdin/
│ │ │ ├── book.toml
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ └── chapter_1.md
│ │ ├── missing_optional_not_fatal/
│ │ │ ├── book.toml
│ │ │ └── src/
│ │ │ └── SUMMARY.md
│ │ ├── missing_renderer/
│ │ │ ├── book.toml
│ │ │ └── src/
│ │ │ └── SUMMARY.md
│ │ └── renderer_with_arguments/
│ │ ├── book.toml
│ │ └── src/
│ │ └── SUMMARY.md
│ ├── renderer.rs
│ ├── rendering/
│ │ ├── code_blocks_fenced_with_indent/
│ │ │ ├── book.toml
│ │ │ ├── expected/
│ │ │ │ └── code-blocks-fenced-with-indent.html
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ └── code-blocks-fenced-with-indent.md
│ │ ├── default_rust_edition/
│ │ │ ├── book.toml
│ │ │ ├── expected/
│ │ │ │ └── default-rust-edition.html
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ └── default-rust-edition.md
│ │ ├── edit_url_template/
│ │ │ ├── book.toml
│ │ │ └── src/
│ │ │ └── SUMMARY.md
│ │ ├── edit_url_template_explicit_src/
│ │ │ ├── book.toml
│ │ │ └── src2/
│ │ │ └── SUMMARY.md
│ │ ├── editable_rust_block/
│ │ │ ├── book.toml
│ │ │ ├── expected/
│ │ │ │ └── editable-rust.html
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ └── editable-rust.md
│ │ ├── first_chapter_is_copied_as_index_even_if_not_first_elem/
│ │ │ └── src/
│ │ │ └── SUMMARY.md
│ │ ├── fontawesome/
│ │ │ ├── book.toml
│ │ │ ├── expected/
│ │ │ │ └── fa.html
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ └── fa.md
│ │ ├── fontawesome_error/
│ │ │ ├── book.toml
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ └── chapter_1.md
│ │ ├── header_links/
│ │ │ ├── book.toml
│ │ │ ├── expected/
│ │ │ │ └── header_links.html
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ └── header_links.md
│ │ ├── hidelines/
│ │ │ ├── book.toml
│ │ │ ├── expected/
│ │ │ │ └── hide-lines.html
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ └── hide-lines.md
│ │ └── html_blocks/
│ │ ├── book.toml
│ │ ├── expected/
│ │ │ ├── comment-in-list.html
│ │ │ └── script-in-block.html
│ │ └── src/
│ │ ├── SUMMARY.md
│ │ ├── comment-in-list.md
│ │ └── script-in-block.md
│ ├── rendering.rs
│ ├── search/
│ │ ├── chapter_settings_validation_error/
│ │ │ ├── book.toml
│ │ │ └── src/
│ │ │ └── SUMMARY.md
│ │ ├── disable_search_chapter/
│ │ │ ├── book.toml
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ ├── first/
│ │ │ │ ├── disable_me.md
│ │ │ │ └── keep_me.md
│ │ │ ├── second/
│ │ │ │ └── nested.md
│ │ │ └── second.md
│ │ └── reasonable_search_index/
│ │ ├── expected_index.js
│ │ └── src/
│ │ ├── SUMMARY.md
│ │ ├── first/
│ │ │ ├── duplicate-headers.md
│ │ │ ├── heading-attributes.md
│ │ │ ├── includes.md
│ │ │ ├── index.md
│ │ │ ├── no-headers.md
│ │ │ └── unicode.md
│ │ └── intro.md
│ ├── search.rs
│ ├── test/
│ │ ├── failing_tests/
│ │ │ ├── book.toml
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ ├── failing.md
│ │ │ ├── failing_include.md
│ │ │ └── test1.rs
│ │ └── passing_tests/
│ │ ├── book.toml
│ │ └── src/
│ │ ├── SUMMARY.md
│ │ ├── passing1.md
│ │ ├── passing2.md
│ │ ├── test1.rs
│ │ ├── test2.rs
│ │ └── test3.rs
│ ├── test.rs
│ ├── theme/
│ │ ├── custom_fonts_css/
│ │ │ ├── book.toml
│ │ │ ├── src/
│ │ │ │ └── SUMMARY.md
│ │ │ └── theme/
│ │ │ └── fonts/
│ │ │ └── fonts.css
│ │ ├── empty_fonts_css/
│ │ │ ├── book.toml
│ │ │ ├── src/
│ │ │ │ └── SUMMARY.md
│ │ │ └── theme/
│ │ │ └── fonts/
│ │ │ └── fonts.css
│ │ ├── empty_theme/
│ │ │ ├── book.toml
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ └── chapter_1.md
│ │ ├── fonts_css/
│ │ │ ├── src/
│ │ │ │ └── SUMMARY.md
│ │ │ └── theme/
│ │ │ └── fonts/
│ │ │ └── fonts.css
│ │ ├── missing_theme/
│ │ │ ├── book.toml
│ │ │ └── src/
│ │ │ ├── SUMMARY.md
│ │ │ └── chapter_1.md
│ │ └── override_index/
│ │ ├── src/
│ │ │ └── SUMMARY.md
│ │ └── theme/
│ │ └── index.hbs
│ ├── theme.rs
│ ├── toc/
│ │ ├── basic_toc/
│ │ │ ├── book.toml
│ │ │ └── src/
│ │ │ ├── README.md
│ │ │ ├── SUMMARY.md
│ │ │ ├── deep/
│ │ │ │ ├── a/
│ │ │ │ │ ├── b/
│ │ │ │ │ │ └── index.md
│ │ │ │ │ └── index.md
│ │ │ │ └── index.md
│ │ │ ├── nested/
│ │ │ │ ├── index.md
│ │ │ │ └── two.md
│ │ │ ├── prefix1.md
│ │ │ ├── prefix2.md
│ │ │ ├── suffix1.md
│ │ │ └── suffix2.md
│ │ └── summary_with_markdown_formatting/
│ │ └── src/
│ │ └── SUMMARY.md
│ └── toc.rs
└── triagebot.toml
================================================
FILE CONTENTS
================================================
================================================
FILE: .cargo/config.toml
================================================
[alias]
xtask = "run --manifest-path=crates/xtask/Cargo.toml --"
================================================
FILE: .git-blame-ignore-revs
================================================
# Use `git config blame.ignorerevsfile .git-blame-ignore-revs` to make `git blame` ignore the following commits.
# rustfmt
ad0794a0bd692e4f2ff23b85e361889620e93f51
# rustfmt and use_try_shorthand
75bbd55128083897d40c3f5265cc5b1f10314ddb
# rustfmt
382fc4139b96bde3c4b8875b499c720eabc89c6a
# rustfmt
154e0fb3080c6ffc225b0d47b5d835e589789892
# rustfmt
5835da243244bfc5c95c6c6db96f453da4bb5740
# rustfmt
fd9d27e082f5e9eea50e4fa9fa3a22060d02c66b
# rustfmt
1d69ccae4854f13552d452d0bffef95cbff70364
# rustfmt
3688f73052454bf510a5acc85cf55aae450c6e46
# rustfmt
742dbbc91700dce1b7d910bca6b3e10a5ae46b86
# rustfmt 1.38
b88839cc25a6fd1c782101e94318959e8079bb20
# rustfmt 1.40
2f59943c04f0aa204a9238d6a699ba9cc06c88d9
# Rustfmt for 2024
c7b67e363bb9ce3383636ee615e8e761bf185b33
================================================
FILE: .gitattributes
================================================
[attr]rust text eol=lf whitespace=tab-in-indent,trailing-space,tabwidth=4
* text=auto eol=lf
*.rs rust
*.woff binary
*.ttf binary
*.otf binary
*.png binary
*.eot binary
*.woff2 binary
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yml
================================================
name: Bug Report
description: Create a report to help us improve
labels: ["C-bug"]
body:
- type: markdown
attributes:
value: Thanks for filing a 🐛 bug report 😄!
- type: textarea
id: problem
attributes:
label: Problem
description: >
Please provide a clear and concise description of what the bug is,
including what currently happens and what you expected to happen.
validations:
required: true
- type: textarea
id: steps
attributes:
label: Steps
description: Please list the steps to reproduce the bug.
placeholder: |
1.
2.
3.
- type: textarea
id: possible-solutions
attributes:
label: Possible Solution(s)
description: >
Not obligatory, but suggest a fix/reason for the bug,
or ideas how to implement the addition or change.
- type: textarea
id: notes
attributes:
label: Notes
description: Provide any additional notes that might be helpful.
- type: textarea
id: version
attributes:
label: Version
description: >
Please paste the output of running `mdbook --version` or which version
of the library you are using.
render: text
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.yml
================================================
name: Enhancement
description: Suggest an idea for enhancing mdBook
labels: ["C-enhancement"]
body:
- type: markdown
attributes:
value: |
Thanks for filing a 🙋 feature request 😄!
- type: textarea
id: problem
attributes:
label: Problem
description: >
Please provide a clear description of your use case and the problem
this feature request is trying to solve.
validations:
required: true
- type: textarea
id: solution
attributes:
label: Proposed Solution
description: >
Please provide a clear and concise description of what you want to happen.
- type: textarea
id: notes
attributes:
label: Notes
description: Provide any additional context or information that might be helpful.
================================================
FILE: .github/ISSUE_TEMPLATE/question.yml
================================================
name: Question
description: Have a question on how to use mdBook?
labels: ["C-question"]
body:
- type: markdown
attributes:
value: |
Got a question on how to do something with mdBook?
- type: textarea
id: question
attributes:
label: Question
description: >
Enter your question here. Please try to provide as much detail as possible.
validations:
required: true
- type: textarea
id: version
attributes:
label: Version
description: >
Please paste the output of running `mdbook --version` or which version
of the library you are using.
render: text
================================================
FILE: .github/renovate.json5
================================================
{
schedule: ['before 5am on the first day of the month'],
// Raise from default of 2 to reduce trickle.
prHourlyLimit: 6,
dependencyDashboard: true,
// Creates PRs if this renovate config file needs updating.
configMigration: true,
ignorePaths: [
'guide/src/for_developers/mdbook-wordcount/',
],
customManagers: [
// Custom manager to extract the version of cargo-semver-checks from the workflow.
{
customType: 'regex',
managerFilePatterns: [
'/^.github.workflows.main.yml$/',
],
matchStrings: [
'cargo-semver-checks.releases.download.v(?<currentValue>\\d+\\.\\d+(\\.\\d+)?)',
],
depNameTemplate: 'cargo-semver-checks',
packageNameTemplate: 'obi1kenobi/cargo-semver-checks',
datasourceTemplate: 'github-releases',
},
],
packageRules: [
// The next two rules disable compatible dependency updates. I wasn't
// able to get Renovate to be able to update Cargo.toml for compatible
// updates only, update all transitive dependencies, and do that all
// in a single PR. Instead, the `update-dependencies.sh` will handle
// that.
{
matchManagers: ['cargo'],
matchUpdateTypes: ['patch'],
enabled: false,
},
{
matchManagers: ['cargo'],
matchCurrentVersion: '>=1.0.0',
matchUpdateTypes: ['minor'],
enabled: false,
},
// Allow minor updates for pre-1.0 dependencies (semver-breaking)
{
matchManagers: ['cargo'],
matchCurrentVersion: '<1.0.0',
matchUpdateTypes: ['minor'],
},
// Allow major updates for stable dependencies (semver-breaking)
{
matchManagers: ['cargo'],
matchCurrentVersion: '>=1.0.0',
matchUpdateTypes: ['major'],
},
// Update cargo-semver-checks when a new version is available.
{
commitMessageTopic: 'cargo-semver-checks',
matchManagers: [
'custom.regex',
],
matchDepNames: [
'cargo-semver-checks',
],
extractVersion: '^v(?<version>\\d+\\.\\d+\\.\\d+)',
schedule: [
'* * * * *',
],
internalChecksFilter: 'strict',
},
]
}
================================================
FILE: .github/workflows/deploy.yml
================================================
name: Deploy
on:
release:
types: [created]
defaults:
run:
shell: bash
permissions:
contents: write
jobs:
release:
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- target: aarch64-unknown-linux-musl
os: ubuntu-22.04
- target: x86_64-unknown-linux-gnu
os: ubuntu-22.04
- target: x86_64-unknown-linux-musl
os: ubuntu-22.04
- target: x86_64-apple-darwin
os: macos-latest
- target: aarch64-apple-darwin
os: macos-latest
- target: x86_64-pc-windows-msvc
os: windows-latest
name: Deploy ${{ matrix.target }}
steps:
- uses: actions/checkout@v5
- name: Install Rust
run: ci/install-rust.sh stable ${{ matrix.target }}
- name: Build asset
run: ci/make-release-asset.sh ${{ matrix.os }} ${{ matrix.target }}
- name: Update release with new asset
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh release upload $MDBOOK_TAG $MDBOOK_ASSET
pages:
name: GitHub Pages
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install Rust (rustup)
run: rustup update stable --no-self-update && rustup default stable
- name: Deploy the User Guide to GitHub Pages using the gh-pages branch
run: ci/publish-guide.sh
publish:
name: Publish to crates.io
runs-on: ubuntu-latest
permissions:
# Required for OIDC token exchange
id-token: write
environment: publish
steps:
- uses: actions/checkout@v5
- name: Install Rust (rustup)
run: rustup update stable --no-self-update && rustup default stable
- name: Authenticate with crates.io
id: auth
uses: rust-lang/crates-io-auth-action@v1
- name: Publish
env:
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
run: cargo publish --workspace --no-verify
================================================
FILE: .github/workflows/main.yml
================================================
name: CI
on:
pull_request:
merge_group:
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- name: stable linux
os: ubuntu-latest
rust: stable
target: x86_64-unknown-linux-gnu
- name: beta linux
os: ubuntu-latest
rust: beta
target: x86_64-unknown-linux-gnu
- name: nightly linux
os: ubuntu-latest
rust: nightly
target: x86_64-unknown-linux-gnu
- name: stable x86_64-unknown-linux-musl
os: ubuntu-22.04
rust: stable
target: x86_64-unknown-linux-musl
- name: stable x86_64 macos
os: macos-latest
rust: stable
target: x86_64-apple-darwin
- name: stable aarch64 macos
os: macos-latest
rust: stable
target: aarch64-apple-darwin
- name: stable windows-msvc
os: windows-latest
rust: stable
target: x86_64-pc-windows-msvc
- name: msrv
os: ubuntu-22.04
# sync MSRV with docs: guide/src/guide/installation.md and Cargo.toml
rust: 1.88.0
target: x86_64-unknown-linux-gnu
name: ${{ matrix.name }}
steps:
- uses: actions/checkout@v5
- name: Install Rust
run: bash ci/install-rust.sh ${{ matrix.rust }} ${{ matrix.target }}
- name: Build and run tests
run: cargo test --workspace --locked --target ${{ matrix.target }}
- name: Test no default
run: cargo test --workspace --no-default-features --target ${{ matrix.target }}
aarch64-cross-builds:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v5
- name: Install Rust
run: bash ci/install-rust.sh stable aarch64-unknown-linux-musl
- name: Build
run: cargo build --locked --target aarch64-unknown-linux-musl
rustfmt:
name: Rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install Rust
run: rustup update stable && rustup default stable && rustup component add rustfmt
- run: cargo fmt --check
gui:
name: GUI tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install Rust
run: bash ci/install-rust.sh stable x86_64-unknown-linux-gnu
- name: Install npm
uses: actions/setup-node@v6
with:
node-version: 24
- name: Install browser-ui-test
run: npm install
- name: Run eslint
run: npm run lint
- name: Build and run tests (+ GUI)
run: cargo test --locked --target x86_64-unknown-linux-gnu --test gui
# Ensure there are no clippy warnings
clippy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install Rust
run: bash ci/install-rust.sh stable x86_64-unknown-linux-gnu
- run: rustup component add clippy
- run: cargo clippy --workspace --all-targets --no-deps -- -D warnings
docs:
name: Check API docs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install Rust
run: bash ci/install-rust.sh stable x86_64-unknown-linux-gnu
- name: Ensure intradoc links are valid
run: cargo doc --workspace --document-private-items --no-deps
env:
RUSTDOCFLAGS: -D warnings
check-version-bump:
name: Check version bump
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- run: rustup update stable && rustup default stable
- name: Install cargo-semver-checks
run: |
mkdir installed-bins
curl -Lf https://github.com/obi1kenobi/cargo-semver-checks/releases/download/v0.47.0/cargo-semver-checks-x86_64-unknown-linux-gnu.tar.gz \
| tar -xz --directory=./installed-bins
echo `pwd`/installed-bins >> $GITHUB_PATH
- run: cargo semver-checks --workspace
# The success job is here to consolidate the total success/failure state of
# all other jobs. This job is then included in the GitHub branch protection
# rule which prevents merges unless all other jobs are passing. This makes
# it easier to manage the list of jobs via this yml file and to prevent
# accidentally adding new jobs without also updating the branch protections.
success:
name: Success gate
if: always()
needs:
- test
- rustfmt
- aarch64-cross-builds
- gui
- clippy
- docs
- check-version-bump
runs-on: ubuntu-latest
steps:
- run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
- name: Done
run: exit 0
================================================
FILE: .github/workflows/update-dependencies.yml
================================================
name: Update dependencies
on:
schedule:
- cron: '0 0 1 * *'
workflow_dispatch:
jobs:
update:
name: Update dependencies
runs-on: ubuntu-latest
if: github.repository == 'rust-lang/mdBook'
steps:
- uses: actions/checkout@v5
- name: Install Rust
run: bash ci/install-rust.sh stable x86_64-unknown-linux-gnu
- name: Install cargo-edit
run: cargo install cargo-edit --locked
- name: Update dependencies
run: ci/update-dependencies.sh
env:
GH_TOKEN: ${{ github.token }}
================================================
FILE: .gitignore
================================================
target
# MacOS temp file
.DS_Store
book-test
guide/book
.vscode
tests/dummy_book/book/
tests/gui/books/*/book/
tests/testsuite/*/*/book/
# Ignore Jetbrains specific files.
.idea/
# Ignore Vim temporary and swap files.
*.sw?
*~
# GUI tests
node_modules
package-lock.json
package.json
================================================
FILE: CHANGELOG.md
================================================
# Changelog
## mdBook 0.5.2
[v0.5.1...v0.5.2](https://github.com/rust-lang/mdBook/compare/v0.5.1...v0.5.2)
### Changed
- Updated Rust crate html5ever to 0.36.0.
[#2970](https://github.com/rust-lang/mdBook/pull/2970)
- Updated cargo dependencies.
[#2969](https://github.com/rust-lang/mdBook/pull/2969)
### Fixed
- Fixed repeated error message when HTML config is invalid in `mdbook serve`.
[#2983](https://github.com/rust-lang/mdBook/pull/2983)
- Fixed sidebar scroll position when heading nav is involved.
[#2982](https://github.com/rust-lang/mdBook/pull/2982)
- Fixed color for rustdoc error messages.
[#2981](https://github.com/rust-lang/mdBook/pull/2981)
- Fixed usage of custom preprocessors with `MDBook::test`.
[#2980](https://github.com/rust-lang/mdBook/pull/2980)
## mdBook 0.5.1
[v0.5.0...v0.5.1](https://github.com/rust-lang/mdBook/compare/v0.5.0...v0.5.1)
### Changed
- Changed the scrollbar background to be transparent.
[#2932](https://github.com/rust-lang/mdBook/pull/2932)
- Ignore invalid top-level environment variable config keys. This allows setting things like `MDBOOK_VERSION` to not cause an error.
[#2952](https://github.com/rust-lang/mdBook/pull/2952)
### Fixed
- Fixed the sidebar heading nav to have the correct nesting levels.
[#2953](https://github.com/rust-lang/mdBook/pull/2953)
- Various Font Awesome fixes and improvements.
[#2951](https://github.com/rust-lang/mdBook/pull/2951)
## mdBook 0.5.0
[v0.4.52...v0.5.0](https://github.com/rust-lang/mdBook/compare/v0.4.52...v0.5.0)
The 0.5.0 release is the next major release of mdBook, containing over 130 PRs since 0.4.52! The primary focus for this release has been an evolution of the Rust APIs to make it easier to maintain, to evolve in a backwards-compatible fashion, to clean up some things that have accumulated over time, and to significantly improve the performance and compile-times.
This release also includes many new features described below.
We have prepared a [0.5 Migration Guide](#05-migration-guide) to help existing authors switch from 0.4.
The final 0.5.0 release only contains the following changes since [0.5.0-beta.2](#mdbook-050-beta2):
- Added error handling to environment config handling. This checks that environment variables starting with `MDBOOK_` are correctly specified instead of silently ignoring. This also fixed being able to replace entire top-level tables like `MDBOOK_OUTPUT`.
[#2942](https://github.com/rust-lang/mdBook/pull/2942)
## 0.5 Migration Guide
The 0.5 release contains several breaking changes from the 0.4 release. Preprocessors and renderers will need to be migrated to continue to work with this release. After updating your configuration, it is recommended to carefully compare and review how your book renders to ensure everything is working correctly.
If you have overridden any of the theme files, you will likely need to update them to match the current version.
See the entries below for [mdBook 0.5.0-alpha.1](#mdbook-050-alpha1), [mdBook 0.5.0-beta.1](#mdbook-050-beta1), and [mdBook 0.5.0-beta.2](#mdbook-050-beta2) for a more complete list of changes and fixes.
The following is a summary of the changes that may require your attention when updating to 0.5:
### Major additions
- Added sidebar heading navigation. This includes the `output.html.sidebar-header-nav` option to disable it.
[#2822](https://github.com/rust-lang/mdBook/pull/2822)
- Added support for definition lists. These are enabled by default, with the option `output.html.definition-lists` to disable it. See [docs](https://rust-lang.github.io/mdBook/format/markdown.html#definition-lists) for more.
[#2847](https://github.com/rust-lang/mdBook/pull/2847)
- Added support for admonitions. These are enabled by default, with the option `output.html.admonitions` to disable it. See [docs](https://rust-lang.github.io/mdBook/format/markdown.html#admonitions) for more.
[#2851](https://github.com/rust-lang/mdBook/pull/2851)
- Links on the print page now link to elements on the print page instead of linking out to the individual chapters.
[#2844](https://github.com/rust-lang/mdBook/pull/2844)
### Config changes
- Unknown fields in config are now an error.
[#2787](https://github.com/rust-lang/mdBook/pull/2787)
[#2801](https://github.com/rust-lang/mdBook/pull/2801)
- Removed `curly-quotes`, use `output.html.smart-punctuation` instead.
[#2788](https://github.com/rust-lang/mdBook/pull/2788)
- Removed `output.html.copy-fonts`. The default fonts are now always copied unless you override the `theme/fonts/fonts.css` file.
[#2790](https://github.com/rust-lang/mdBook/pull/2790)
- If the `command` path for a renderer or preprocessor is relative, it is now always relative to the book root.
[#2792](https://github.com/rust-lang/mdBook/pull/2792)
[#2796](https://github.com/rust-lang/mdBook/pull/2796)
- Added the `optional` field for preprocessors. The default is `false`, so this also means it is an error by default if the preprocessor is missing.
[#2797](https://github.com/rust-lang/mdBook/pull/2797)
- `output.html.smart-punctuation` is now `true` by default.
[#2810](https://github.com/rust-lang/mdBook/pull/2810)
- `output.html.hash-files` is now `true` by default.
[#2820](https://github.com/rust-lang/mdBook/pull/2820)
- Removed support for google-analytics. Use a theme extension (like `head.hbs`) if you need to continue to support this.
[#2776](https://github.com/rust-lang/mdBook/pull/2776)
- Removed the `book.multilingual` field. This was never used.
[#2775](https://github.com/rust-lang/mdBook/pull/2775)
- Removed the very old legacy config support. Warnings have been displayed in previous versions on how to migrate.
[#2783](https://github.com/rust-lang/mdBook/pull/2783)
- Top-level config values set from the environment like `MDBOOK_BOOK` now *replace* the contents of the top-level table instead of merging into it.
[#2942](https://github.com/rust-lang/mdBook/pull/2942)
- Invalid environment variables are now rejected. Previously unknown keys like `MDBOOK_FOO` would be ignored, or keys or invalid values inside objects like the `[book]` table would be ignored.
[#2942](https://github.com/rust-lang/mdBook/pull/2942)
### Theme changes
- Replaced the `{{#previous}}` and `{{#next}}` handlebars helpers with simple objects that contain the previous and next values.
[#2794](https://github.com/rust-lang/mdBook/pull/2794)
- Removed the `{{theme_option}}` handlebars helper. It has not been used for a while.
[#2795](https://github.com/rust-lang/mdBook/pull/2795)
### Rendering changes
- Updated to a newer version of `pulldown-cmark`. This brings a large number of fixes to markdown processing.
[#2401](https://github.com/rust-lang/mdBook/pull/2401)
- The font-awesome font is no longer loaded as a font. Instead, the corresponding SVG is embedded in the output for the corresponding `<i>` tags. Additionally, a handlebars helper has been added for the `hbs` files. This also updates the version from 4.7.0 to 6.2.0, which means some of the icon names and styles have changed. Most of the free icons are in the "solid" set. See the [free icon set](https://fontawesome.com/v6/search) for the available icons.
[#1330](https://github.com/rust-lang/mdBook/pull/1330)
- Changed all internal HTML IDs to have an `mdbook-` prefix. This helps avoid namespace conflicts with header IDs.
[#2808](https://github.com/rust-lang/mdBook/pull/2808)
- There is a new internal HTML rendering pipeline. This is primarily intended to give mdBook more flexibility in generating its HTML output. This resulted in some small changes to the HTML structure. HTML parsing may now be more strict than before.
[#2844](https://github.com/rust-lang/mdBook/pull/2844)
- Links on the print page now link to elements on the print page instead of linking out to the individual chapters.
[#2844](https://github.com/rust-lang/mdBook/pull/2844)
- Added support for definition lists. These are enabled by default, with the option `output.html.definition-lists` to disable it.
[#2847](https://github.com/rust-lang/mdBook/pull/2847)
- Added support for admonitions. These are enabled by default, with the option `output.html.admonitions` to disable it.
[#2851](https://github.com/rust-lang/mdBook/pull/2851)
- Header ID generation has some minor changes to bring the ID generation closer to other tools and sites:
- IDs now use Unicode lowercase instead of ASCII lowercase.
[#2922](https://github.com/rust-lang/mdBook/pull/2922)
- Headers that start or end with HTML characters like `<`, `&`, or `>` now replace those characters in the link ID with `-` instead of being stripped.
[#2844](https://github.com/rust-lang/mdBook/pull/2844)
- Headers are no longer modified if the tag is manually written HTML.
[#2913](https://github.com/rust-lang/mdBook/pull/2913)
### CLI changes
- Removed the `--dest-dir` option to `mdbook test`. It was unused since `mdbook test` does not generate output.
[#2805](https://github.com/rust-lang/mdBook/pull/2805)
- Changed CLI `--dest-dir` to be relative to the current directory, not the book root.
[#2806](https://github.com/rust-lang/mdBook/pull/2806)
### Rust API
- The Rust API has been split into several crates ([#2766](https://github.com/rust-lang/mdBook/pull/2766)). In summary, the different crates are:
- `mdbook` — The CLI binary.
- [`mdbook-driver`](https://docs.rs/mdbook-driver/latest/mdbook_driver/) — The high-level library for running mdBook, primarily through the `MDBook` type. If you are driving mdBook programmatically, this is the crate you want.
- [`mdbook-preprocessor`](https://docs.rs/mdbook-preprocessor/latest/mdbook_preprocessor/) — Support for implementing preprocessors. If you have a preprocessor, then this is the crate you should depend on.
- [`mdbook-renderer`](https://docs.rs/mdbook-renderer/latest/mdbook_renderer/) — Support for implementing renderers. If you have a custom renderer, this is the crate you should depend on.
- [`mdbook-markdown`](https://docs.rs/mdbook-markdown/latest/mdbook_markdown/) — The Markdown renderer. If you are processing markdown, this is the crate you should depend on. This is essentially a thin wrapper around `pulldown-cmark`, and re-exports that crate so that you can ensure the version stays in sync with mdBook.
- [`mdbook-summary`](https://docs.rs/mdbook-summary/latest/mdbook_summary/) — The `SUMMARY.md` parser.
- [`mdbook-html`](https://docs.rs/mdbook-html/latest/mdbook_html/) — The HTML renderer.
- [`mdbook-core`](https://docs.rs/mdbook-core/latest/mdbook_core/) — An internal library that is used by the other crates for shared types. You should not depend on this crate directly since types from this crate are re-exported from the other crates as appropriate.
- Changes to `Config`:
- [`Config::get`](https://docs.rs/mdbook-core/latest/mdbook_core/config/struct.Config.html#method.get) is now generic over the return value, using `serde` to deserialize the value. It also returns a `Result` to handle deserialization errors. [#2773](https://github.com/rust-lang/mdBook/pull/2773)
- [`Config::set`](https://docs.rs/mdbook-core/latest/mdbook_core/config/struct.Config.html#method.set) now validates that the config keys and values are valid.
[#2942](https://github.com/rust-lang/mdBook/pull/2942)
- [`Config::update_from_env`](https://docs.rs/mdbook-core/latest/mdbook_core/config/struct.Config.html#method.update_from_env) now returns a `Result` to indicate any errors.
[#2942](https://github.com/rust-lang/mdBook/pull/2942)
- Removed `Config::get_deserialized`. Use `Config::get` instead.
- Removed `Config::get_deserialized_opt`. Use `Config::get` instead.
- Removed `Config::get_mut`. Use `Config::set` instead.
- Removed deprecated `Config::get_deserialized_opt`. Use `Config::get` instead.
- Removed `Config::get_renderer`. Use `Config::get` instead.
- Removed `Config::get_preprocessor`. Use `Config::get` instead.
- Public types have been switch to use the `#[non_exhaustive]` attribute to help allow them to change in a backwards-compatible way.
[#2779](https://github.com/rust-lang/mdBook/pull/2779)
[#2823](https://github.com/rust-lang/mdBook/pull/2823)
- Changed `MDBook` `with_renderer`/`with_preprocessor` to overwrite the entry if an extension of the same name is already loaded. This allows the caller to replace an entry.
[#2802](https://github.com/rust-lang/mdBook/pull/2802)
- Added `MarkdownOptions` struct to specify settings for markdown rendering for `mdbook_markdown::new_cmark_parser`.
[#2809](https://github.cocm/rust-lang/mdBook/pull/2809)
- Renamed `Book::sections` to `Book::items`.
[#2813](https://github.com/rust-lang/mdBook/pull/2813)
- `mdbook::book::load_book` is now private. Instead, use one of the `MDBook` load functions like `MDBook::load_with_config`.
- Removed `HtmlConfig::smart_punctuation` method, use the field of the same name.
- `CmdPreprocessor::parse_input` moved to `mdbook_preprocessor::parse_input`.
- `Preprocessor::supports_renderer` now returns a `Result<bool>` instead of `bool` to be able to handle errors.
- Most of the types from the `theme` module are now private. The `Theme` struct is still exposed for working with themes.
- Various functions in the `utils::fs` module have been removed, renamed, or reworked.
- Most of the functions in the `utils` module have been moved, removed, or made private.
## mdBook 0.5.0-beta.2
[v0.5.0-beta.1...v0.5.0-beta.2](https://github.com/rust-lang/mdBook/compare/v0.5.0-beta.1...v0.5.0-beta.2)
### Added
- Added a warning when a Font Awesome icon is missing.
[#2915](https://github.com/rust-lang/mdBook/pull/2915)
- Added some trace logging for event processing.
[#2911](https://github.com/rust-lang/mdBook/pull/2911)
- Added `Config::contains_key`.
[#2910](https://github.com/rust-lang/mdBook/pull/2910)
### Changed
- Heading IDs are now lowercase.
[#2922](https://github.com/rust-lang/mdBook/pull/2922)
- Updated cargo dependencies.
[#2916](https://github.com/rust-lang/mdBook/pull/2916)
- Removed italics for in quotes/comments in code blocks with the `ayu` theme.
[#2904](https://github.com/rust-lang/mdBook/pull/2904)
- Exposed "search" feature from mdbook-driver.
[#2907](https://github.com/rust-lang/mdBook/pull/2907)
### Fixed
- Fixed rust fenced code blocks with an indent.
[#2905](https://github.com/rust-lang/mdBook/pull/2905)
- Headers and `dt` tags are no longer modified if the tag is manually written HTML.
[#2913](https://github.com/rust-lang/mdBook/pull/2913)
- Fixed print page links for internal links to non-chapters.
[#2914](https://github.com/rust-lang/mdBook/pull/2914)
- Better handling for unbalanced HTML tags.
[#2924](https://github.com/rust-lang/mdBook/pull/2924)
- Handle unclosed HTML tags inside a markdown element.
[#2927](https://github.com/rust-lang/mdBook/pull/2927)
- Fixed missing font-awesome icons in the guide.
[#2926](https://github.com/rust-lang/mdBook/pull/2926)
- Hide the sidebar resize indicator when JS isn't available.
[#2923](https://github.com/rust-lang/mdBook/pull/2923)
## mdBook 0.5.0-beta.1
[v0.5.0-alpha.1...v0.5.0-beta.1](https://github.com/rust-lang/mdBook/compare/v0.5.0-alpha.1...v0.5.0-beta.1)
### Changed
- Reworked the look of the header navigation.
[#2898](https://github.com/rust-lang/mdBook/pull/2898)
- Update cargo dependencies.
[#2896](https://github.com/rust-lang/mdBook/pull/2896)
- Improved the heading nav debug.
[#2892](https://github.com/rust-lang/mdBook/pull/2892)
### Fixed
- Fixed error message for config.get deserialization error.
[#2902](https://github.com/rust-lang/mdBook/pull/2902)
- Filter `<mark>` tags from sidebar heading nav.
[#2899](https://github.com/rust-lang/mdBook/pull/2899)
- Avoid divide-by-zero in heading nav computation
[#2891](https://github.com/rust-lang/mdBook/pull/2891)
- Fixed heading nav with folded chapters.
[#2893](https://github.com/rust-lang/mdBook/pull/2893)
## mdBook 0.5.0-alpha.1
[v0.4.52...v0.5.0-alpha.1](https://github.com/rust-lang/mdBook/compare/v0.4.52...v0.5.0-alpha.1)
### Added
- The location of the generated HTML book is now displayed on the console.
[#2729](https://github.com/rust-lang/mdBook/pull/2729)
- ❗ Added the `optional` field for preprocessors. The default is `false`, so this also changes it so that it is an error if the preprocessor is missing.
[#2797](https://github.com/rust-lang/mdBook/pull/2797)
- ❗ Added `MarkdownOptions` struct to specify settings for markdown rendering.
[#2809](https://github.cocm/rust-lang/mdBook/pull/2809)
- Added sidebar heading navigation. This includes the `output.html.sidebar-header-nav` option to disable it.
[#2822](https://github.com/rust-lang/mdBook/pull/2822)
- Added the mdbook version to the guide.
[#2826](https://github.com/rust-lang/mdBook/pull/2826)
- Added `Book::chapters` and `Book::for_each_chapter_mut` to more conveniently iterate over chapters (instead of all items).
[#2838](https://github.com/rust-lang/mdBook/pull/2838)
- ❗ Added support for definition lists. These are enabled by default, with the option `output.html.definition-lists` to disable it.
[#2847](https://github.com/rust-lang/mdBook/pull/2847)
- ❗ Added support for admonitions. These are enabled by default, with the option `output.html.admonitions` to disable it.
[#2851](https://github.com/rust-lang/mdBook/pull/2851)
### Changed
- ❗ The `mdbook` crate has been split into multiple crates.
[#2766](https://github.com/rust-lang/mdBook/pull/2766)
- The minimum Rust version has been updated to 1.88.
[#2844](https://github.com/rust-lang/mdBook/pull/2844)
- ❗ `pulldown-cmark` has been upgraded to 0.13.0, bringing a large number of fixes to markdown processing.
[#2401](https://github.com/rust-lang/mdBook/pull/2401)
- ❗ Switched public types to `non_exhaustive` to help allow them to change in a backwards-compatible way.
[#2779](https://github.com/rust-lang/mdBook/pull/2779)
[#2823](https://github.com/rust-lang/mdBook/pull/2823)
- ❗ Unknown fields in config are now an error.
[#2787](https://github.com/rust-lang/mdBook/pull/2787)
[#2801](https://github.com/rust-lang/mdBook/pull/2801)
- ❗ Changed `id_from_content` to be private.
[#2791](https://github.com/rust-lang/mdBook/pull/2791)
- ❗ Changed preprocessor `command` to use paths relative to the book root.
[#2796](https://github.com/rust-lang/mdBook/pull/2796)
- ❗ Replaced the `{{#previous}}` and `{{#next}}` handelbars navigation helpers with objects.
[#2794](https://github.com/rust-lang/mdBook/pull/2794)
- ❗ Use embedded SVG instead of fonts for icons, font-awesome 6.2.
[#1330](https://github.com/rust-lang/mdBook/pull/1330)
- The `book.src` field is no longer serialized if it is the default of "src".
[#2800](https://github.com/rust-lang/mdBook/pull/2800)
- ❗ Changed `MDBook` `with_renderer`/`with_preprocessor` to overwrite the entry if an extension of the same name is already loaded.
[#2802](https://github.com/rust-lang/mdBook/pull/2802)
- ❗ Changed CLI `--dest-dir` to be relative to the current directory, not the book root.
[#2806](https://github.com/rust-lang/mdBook/pull/2806)
- ❗ Changed all internal HTML IDs to have an `mdbook-` prefix. This helps avoid namespace conflicts with header IDs.
[#2808](https://github.com/rust-lang/mdBook/pull/2808)
- ❗ `output.html.smart-punctuation` is now `true` by default.
[#2810](https://github.com/rust-lang/mdBook/pull/2810)
- ❗ Renamed `Book::sections` to `Book::items`.
[#2813](https://github.com/rust-lang/mdBook/pull/2813)
- ❗ `output.html.hash-files` is now `true` by default.
[#2820](https://github.com/rust-lang/mdBook/pull/2820)
- Switched from `log` to `tracing`.
[#2829](https://github.com/rust-lang/mdBook/pull/2829)
- ❗ Rewrote the HTML rendering pipeline.
[#2844](https://github.com/rust-lang/mdBook/pull/2844)
- ❗ Links on the print page now link to elements on the print page instead of linking out to the individual chapters.
[#2844](https://github.com/rust-lang/mdBook/pull/2844)
- ❗ Moved theme copy to the Theme type and reduced visibility.
[#2857](https://github.com/rust-lang/mdBook/pull/2857)
- ❗ Cleaned up some fs-related utilities.
[#2856](https://github.com/rust-lang/mdBook/pull/2856)
- ❗ Moved `get_404_output_file` to `HtmlConfig`.
[#2855](https://github.com/rust-lang/mdBook/pull/2855)
- ❗ Moved `take_lines` functions to `mdbook-driver` and made private.
[#2854](https://github.com/rust-lang/mdBook/pull/2854)
- Updated dependencies.
[#2793](https://github.com/rust-lang/mdBook/pull/2793)
[#2869](https://github.com/rust-lang/mdBook/pull/2869)
### Removed
- ❗ Removed `toml` as a public dependency.
[#2773](https://github.com/rust-lang/mdBook/pull/2773)
- ❗ Removed the `book.multilingual` field. This was never used.
[#2775](https://github.com/rust-lang/mdBook/pull/2775)
- ❗ Removed support for google-analytics.
[#2776](https://github.com/rust-lang/mdBook/pull/2776)
- ❗ Removed the very old legacy config support.
[#2783](https://github.com/rust-lang/mdBook/pull/2783)
- ❗ Removed `curly-quotes`, use `output.html.smart-punctuation` instead.
[#2788](https://github.com/rust-lang/mdBook/pull/2788)
- Removed old warning about `book.json`.
[#2789](https://github.com/rust-lang/mdBook/pull/2789)
- ❗ Removed `output.html.copy-fonts`. The default fonts are now always copied unless you override the `theme/fonts/fonts.css` file.
[#2790](https://github.com/rust-lang/mdBook/pull/2790)
- ❗ Removed legacy relative renderer command paths. Relative renderer command paths now must always be relative to the book root.
[#2792](https://github.com/rust-lang/mdBook/pull/2792)
- ❗ Removed the `{{theme_option}}` handlebars helper. It has not been used for a while.
[#2795](https://github.com/rust-lang/mdBook/pull/2795)
- ❗ Removed the `--dest-dir` option to `mdbook test`.
[#2805](https://github.com/rust-lang/mdBook/pull/2805)
### Fixed
- Fixed handling of multiple footnotes in a row.
[#2807](https://github.com/rust-lang/mdBook/pull/2807)
- Fixed ID collisions when the numeric suffix gets used.
[#2846](https://github.com/rust-lang/mdBook/pull/2846)
- Fixed missing css vars for no-js dark mode.
[#2850](https://github.com/rust-lang/mdBook/pull/2850)
## mdBook 0.4.52
[v0.4.51...v0.4.52](https://github.com/rust-lang/mdBook/compare/v0.4.51...v0.4.52)
**Note:** If you have a custom `index.hbs` theme file, it is recommended that you update it to the latest version to pick up the fixes in this release.
### Added
- Added the ability to redirect `#` HTML fragments using the existing `output.html.redirect` table.
[#2747](https://github.com/rust-lang/mdBook/pull/2747)
- Added the `rel="edit"` attribute to the edit page button.
[#2702](https://github.com/rust-lang/mdBook/pull/2702)
### Changed
- The search index is now only loaded when the search input is opened instead of always being loaded.
[#2553](https://github.com/rust-lang/mdBook/pull/2553)
[#2735](https://github.com/rust-lang/mdBook/pull/2735)
- The `mdbook serve` command has switched its underlying server library from warp to axum.
[#2748](https://github.com/rust-lang/mdBook/pull/2748)
- Updated dependencies.
[#2752](https://github.com/rust-lang/mdBook/pull/2752)
### Fixed
- The sidebar is now set to `display:none` when it is hidden in order to prevent the browser's search from thinking the sidebar's text is visible.
[#2725](https://github.com/rust-lang/mdBook/pull/2725)
- Fixed search index URL not updating correctly when `hash-files` is enabled.
[#2742](https://github.com/rust-lang/mdBook/pull/2742)
[#2746](https://github.com/rust-lang/mdBook/pull/2746)
- Fixed several sidebar animation bugs, particularly when manually resizing.
[#2750](https://github.com/rust-lang/mdBook/pull/2750)
## mdBook 0.4.51
[v0.4.50...v0.4.51](https://github.com/rust-lang/mdBook/compare/v0.4.50...v0.4.51)
### Fixed
- Fixed regression that broke the `S` search hotkey.
[#2713](https://github.com/rust-lang/mdBook/pull/2713)
## mdBook 0.4.50
[v0.4.49...v0.4.50](https://github.com/rust-lang/mdBook/compare/v0.4.49...v0.4.50)
### Added
- Added a keyboard shortcut help popup when pressing `?`.
[#2608](https://github.com/rust-lang/mdBook/pull/2608)
### Changed
- Changed the look of the sidebar resize handle to match the new rustdoc format.
[#2691](https://github.com/rust-lang/mdBook/pull/2691)
- `/` can now be used to open the search bar.
[#2698](https://github.com/rust-lang/mdBook/pull/2698)
- Pressing enter from the search bar will navigate to the first entry.
[#2698](https://github.com/rust-lang/mdBook/pull/2698)
- Updated `opener` to drop some dependencies.
[#2709](https://github.com/rust-lang/mdBook/pull/2709)
- Updated dependencies, MSRV raised to 1.82.
[#2711](https://github.com/rust-lang/mdBook/pull/2711)
### Fixed
- Fixed uncaught exception when pressing down when there are no search results.
[#2698](https://github.com/rust-lang/mdBook/pull/2698)
- Fixed syntax highlighting of Rust code in the ACE editor.
[#2710](https://github.com/rust-lang/mdBook/pull/2710)
## mdBook 0.4.49
[v0.4.48...v0.4.49](https://github.com/rust-lang/mdBook/compare/v0.4.48...v0.4.49)
### Added
- Added a warning on unused fields in the root of `book.toml`.
[#2622](https://github.com/rust-lang/mdBook/pull/2622)
### Changed
- Updated dependencies.
[#2650](https://github.com/rust-lang/mdBook/pull/2650)
[#2688](https://github.com/rust-lang/mdBook/pull/2688)
- Updated minimum Rust version to 1.81.
[#2688](https://github.com/rust-lang/mdBook/pull/2688)
- The unused `book.multilingual` field is no longer serialized, or shown in `mdbook init`.
[#2689](https://github.com/rust-lang/mdBook/pull/2689)
- Speed up search index loading by using `JSON.parse` instead of parsing JavaScript.
[#2633](https://github.com/rust-lang/mdBook/pull/2633)
### Fixed
- Search highlighting will not try to highlight in SVG `<text>` elements because it breaks the element.
[#2668](https://github.com/rust-lang/mdBook/pull/2668)
- Fixed scrolling of the sidebar when a search highlight term is in the URL.
[#2675](https://github.com/rust-lang/mdBook/pull/2675)
- Fixed issues when multiple footnote definitions use the same ID. Now, only one definition is used, and a warning is displayed.
[#2681](https://github.com/rust-lang/mdBook/pull/2681)
- The sidebar is now restricted to 80% of the viewport width to make it possible to collapse it when the viewport is very narrow.
[#2679](https://github.com/rust-lang/mdBook/pull/2679)
## mdBook 0.4.48
[v0.4.47...v0.4.48](https://github.com/rust-lang/mdBook/compare/v0.4.47...v0.4.48)
### Added
- Footnotes now have back-reference links. These links bring the reader back to the original location. As part of this change, footnotes are now only rendered at the bottom of the page. This also includes some styling updates and fixes for footnote rendering.
[#2626](https://github.com/rust-lang/mdBook/pull/2626)
- Added an "Auto" theme selection option which will default to the system-preferred mode. This will also automatically switch when the system changes the preferred mode.
[#2576](https://github.com/rust-lang/mdBook/pull/2576)
### Changed
- The `searchindex.json` file has been removed; only the `searchindex.js` file will be generated.
[#2552](https://github.com/rust-lang/mdBook/pull/2552)
- Updated Javascript code to use eslint.
[#2554](https://github.com/rust-lang/mdBook/pull/2554)
- An error is generated if there are duplicate files in `SUMMARY.md`.
[#2613](https://github.com/rust-lang/mdBook/pull/2613)
## mdBook 0.4.47
[v0.4.46...v0.4.47](https://github.com/rust-lang/mdBook/compare/v0.4.46...v0.4.47)
### Fixed
- Fixed search not showing up in sub-directories.
[#2586](https://github.com/rust-lang/mdBook/pull/2586)
## mdBook 0.4.46
[v0.4.45...v0.4.46](https://github.com/rust-lang/mdBook/compare/v0.4.45...v0.4.46)
### Changed
- The `output.html.hash-files` config option has been added to add hashes to static filenames to bust any caches when a book is updated. `{{resource}}` template tags have been added so that links can be properly generated to those files.
[#1368](https://github.com/rust-lang/mdBook/pull/1368)
### Fixed
- Playground links for Rust 2024 now set the edition correctly.
[#2557](https://github.com/rust-lang/mdBook/pull/2557)
## mdBook 0.4.45
[v0.4.44...v0.4.45](https://github.com/rust-lang/mdBook/compare/v0.4.44...v0.4.45)
### Changed
- Added context to error message when rustdoc is not found.
[#2545](https://github.com/rust-lang/mdBook/pull/2545)
- Slightly changed the styling rules around margins of footnotes.
[#2524](https://github.com/rust-lang/mdBook/pull/2524)
### Fixed
- Fixed an issue where it would panic if a source_path is not set.
[#2550](https://github.com/rust-lang/mdBook/pull/2550)
## mdBook 0.4.44
[v0.4.43...v0.4.44](https://github.com/rust-lang/mdBook/compare/v0.4.43...v0.4.44)
### Added
- Added pre-built aarch64-apple-darwin binaries to the releases.
[#2500](https://github.com/rust-lang/mdBook/pull/2500)
- `mdbook clean` now shows a summary of what it did.
[#2458](https://github.com/rust-lang/mdBook/pull/2458)
- Added the `output.html.search.chapter` config setting to disable search indexing of individual chapters.
[#2533](https://github.com/rust-lang/mdBook/pull/2533)
### Fixed
- Fixed auto-scrolling the side-bar when loading a page with a `#` fragment URL.
[#2517](https://github.com/rust-lang/mdBook/pull/2517)
- Fixed display of sidebar when javascript is disabled.
[#2529](https://github.com/rust-lang/mdBook/pull/2529)
- Fixed the sidebar visibility getting out of sync with the button.
[#2532](https://github.com/rust-lang/mdBook/pull/2532)
### Changed
- ❗ Rust code block hidden lines now follow the same logic as rustdoc. This requires a space after the `#` symbol.
[#2530](https://github.com/rust-lang/mdBook/pull/2530)
- ❗ Updated the Linux pre-built binaries which requires a newer version of glibc (2.34).
[#2523](https://github.com/rust-lang/mdBook/pull/2523)
- Updated dependencies
[#2538](https://github.com/rust-lang/mdBook/pull/2538)
[#2539](https://github.com/rust-lang/mdBook/pull/2539)
## mdBook 0.4.43
[v0.4.42...v0.4.43](https://github.com/rust-lang/mdBook/compare/v0.4.42...v0.4.43)
### Fixed
- Fixed setting the title in `mdbook init` when no git user is configured.
[#2486](https://github.com/rust-lang/mdBook/pull/2486)
### Changed
- The Rust 2024 edition no longer needs `-Zunstable-options`.
[#2495](https://github.com/rust-lang/mdBook/pull/2495)
## mdBook 0.4.42
[v0.4.41...v0.4.42](https://github.com/rust-lang/mdBook/compare/v0.4.41...v0.4.42)
### Fixed
- Fixed chapter list folding.
[#2473](https://github.com/rust-lang/mdBook/pull/2473)
## mdBook 0.4.41
[v0.4.40...v0.4.41](https://github.com/rust-lang/mdBook/compare/v0.4.40...v0.4.41)
**Note:** If you have a custom `index.hbs` theme file, you will need to update it to the latest version.
### Added
- Added preliminary support for Rust 2024 edition.
[#2398](https://github.com/rust-lang/mdBook/pull/2398)
- Added a full example of the remove-emphasis preprocessor.
[#2464](https://github.com/rust-lang/mdBook/pull/2464)
### Changed
- Adjusted styling of clipboard/play icons.
[#2421](https://github.com/rust-lang/mdBook/pull/2421)
- Updated to handlebars v6.
[#2416](https://github.com/rust-lang/mdBook/pull/2416)
- Attr and section rules now have specific code highlighting.
[#2448](https://github.com/rust-lang/mdBook/pull/2448)
- The sidebar is now loaded from a common file, significantly reducing the book size when there are many chapters.
[#2414](https://github.com/rust-lang/mdBook/pull/2414)
- Updated dependencies.
[#2470](https://github.com/rust-lang/mdBook/pull/2470)
### Fixed
- Improved theme support when JavaScript is disabled.
[#2454](https://github.com/rust-lang/mdBook/pull/2454)
- Fixed broken themes when localStorage has an invalid theme id.
[#2463](https://github.com/rust-lang/mdBook/pull/2463)
- Adjusted the line-height of superscripts (and footnotes) to avoid adding extra space between lines.
[#2465](https://github.com/rust-lang/mdBook/pull/2465)
## mdBook 0.4.40
[v0.4.39...v0.4.40](https://github.com/rust-lang/mdBook/compare/v0.4.39...v0.4.40)
### Fixed
- Reverted the update to pulldown-cmark which broke the semver API.
[#2388](https://github.com/rust-lang/mdBook/pull/2388)
## mdBook 0.4.39
[v0.4.38...v0.4.39](https://github.com/rust-lang/mdBook/compare/v0.4.38...v0.4.39)
### Fixed
- Fixed the automatic deploy broken in the previous release.
[#2383](https://github.com/rust-lang/mdBook/pull/2383)
## mdBook 0.4.38
[v0.4.37...v0.4.38](https://github.com/rust-lang/mdBook/compare/v0.4.37...v0.4.38)
### Added
- Added `nix` to the default set of languages supported for syntax highlighting.
[#2262](https://github.com/rust-lang/mdBook/pull/2262)
### Changed
- The `output.html.curly-quotes` option has been renamed to `output.html.smart-punctuation` to better reflect what it does. The old option `curly-quotes` is kept for compatibility, but may be removed in the future.
[#2327](https://github.com/rust-lang/mdBook/pull/2327)
- The file-watcher used in `mdbook serve` and `mdbook watch` now uses a poll-based watcher instead of the native operating system notifications. This should fix issues on various systems and environments, and more accurately detect when files change. The native watcher can still be used with the `--watcher native` CLI option.
[#2325](https://github.com/rust-lang/mdBook/pull/2325)
- `mdbook test` output now includes color, and shows relative paths to the source.
[#2259](https://github.com/rust-lang/mdBook/pull/2259)
- Updated dependencies, MSRV raised to 1.74
[#2350](https://github.com/rust-lang/mdBook/pull/2350)
[#2351](https://github.com/rust-lang/mdBook/pull/2351)
[#2378](https://github.com/rust-lang/mdBook/pull/2378)
[#2381](https://github.com/rust-lang/mdBook/pull/2381)
### Fixed
- Reduced memory allocation when copying files.
[#2355](https://github.com/rust-lang/mdBook/pull/2355)
- Fixed the horizontal divider in `SUMMARY.md` from being indented into the previous nested section.
[#2364](https://github.com/rust-lang/mdBook/pull/2364)
- Removed unnecessary `@import` in the CSS.
[#2260](https://github.com/rust-lang/mdBook/pull/2260)
## mdBook 0.4.37
[v0.4.36...v0.4.37](https://github.com/rust-lang/mdBook/compare/v0.4.36...v0.4.37)
### Changed
- ❗️ Updated the markdown parser. This brings in many changes to more closely follow the CommonMark spec. This may cause some small rendering changes. It is recommended to compare the output of the old and new version to check for changes. See <https://github.com/raphlinus/pulldown-cmark/releases/tag/v0.10.0> for more information.
[#2308](https://github.com/rust-lang/mdBook/pull/2308)
- The warning about the legacy `src/theme` directory has been removed.
[#2263](https://github.com/rust-lang/mdBook/pull/2263)
- Updated dependencies. MSRV raised to 1.71.0.
[#2283](https://github.com/rust-lang/mdBook/pull/2283)
[#2293](https://github.com/rust-lang/mdBook/pull/2293)
[#2297](https://github.com/rust-lang/mdBook/pull/2297)
[#2310](https://github.com/rust-lang/mdBook/pull/2310)
[#2309](https://github.com/rust-lang/mdBook/pull/2309)
- Some internal performance/memory improvements.
[#2273](https://github.com/rust-lang/mdBook/pull/2273)
[#2290](https://github.com/rust-lang/mdBook/pull/2290)
- Made the `pathdiff` dependency optional based on the `watch` feature.
[#2291](https://github.com/rust-lang/mdBook/pull/2291)
### Fixed
- The `s` shortcut key handler should not trigger when focus is in an HTML form.
[#2311](https://github.com/rust-lang/mdBook/pull/2311)
## mdBook 0.4.36
[v0.4.35...v0.4.36](https://github.com/rust-lang/mdBook/compare/v0.4.35...v0.4.36)
### Added
- Added Nim to the default highlighted languages.
[#2232](https://github.com/rust-lang/mdBook/pull/2232)
- Added a small indicator for the sidebar resize handle.
[#2209](https://github.com/rust-lang/mdBook/pull/2209)
### Changed
- Updated dependencies. MSRV raised to 1.70.0.
[#2173](https://github.com/rust-lang/mdBook/pull/2173)
[#2250](https://github.com/rust-lang/mdBook/pull/2250)
[#2252](https://github.com/rust-lang/mdBook/pull/2252)
### Fixed
- Fixed blank column in print page when the sidebar was visible.
[#2235](https://github.com/rust-lang/mdBook/pull/2235)
- Fixed indentation of code blocks when Javascript is disabled.
[#2162](https://github.com/rust-lang/mdBook/pull/2162)
- Fixed a panic when `mdbook serve` or `mdbook watch` were given certain kinds of paths.
[#2229](https://github.com/rust-lang/mdBook/pull/2229)
## mdBook 0.4.35
[v0.4.34...v0.4.35](https://github.com/rust-lang/mdBook/compare/v0.4.34...v0.4.35)
### Added
- Added the `book.text-direction` setting for explicit support for right-to-left languages.
[#1641](https://github.com/rust-lang/mdBook/pull/1641)
- Added `rel=prefetch` to the "next" links to potentially improve browser performance.
[#2168](https://github.com/rust-lang/mdBook/pull/2168)
- Added a `.warning` CSS class which is styled for displaying warning blocks.
[#2187](https://github.com/rust-lang/mdBook/pull/2187)
### Changed
- Better support of the sidebar when JavaScript is disabled.
[#2175](https://github.com/rust-lang/mdBook/pull/2175)
## mdBook 0.4.34
[v0.4.33...v0.4.34](https://github.com/rust-lang/mdBook/compare/v0.4.33...v0.4.34)
### Fixed
- Fixed file change watcher failing on macOS with a large number of files.
[#2157](https://github.com/rust-lang/mdBook/pull/2157)
## mdBook 0.4.33
[v0.4.32...v0.4.33](https://github.com/rust-lang/mdBook/compare/v0.4.32...v0.4.33)
### Added
- The `color-scheme` CSS property is now set based on the light/dark theme, which applies some slight color differences in browser elements like scroll bars on some browsers.
[#2134](https://github.com/rust-lang/mdBook/pull/2134)
### Fixed
- Fixed watching of extra-watch-dirs when not running in the book root directory.
[#2146](https://github.com/rust-lang/mdBook/pull/2146)
- Reverted the dependency update to the `toml` crate (again!). This was an unintentional breaking change in 0.4.32.
[#2021](https://github.com/rust-lang/mdBook/pull/2021)
- Changed macOS change notifications to use the kqueue implementation which should fix some issues with repeated rebuilds when a file changed.
[#2152](https://github.com/rust-lang/mdBook/pull/2152)
- Don't set a background color in the print page for code blocks in a header.
[#2150](https://github.com/rust-lang/mdBook/pull/2150)
## mdBook 0.4.32
[v0.4.31...v0.4.32](https://github.com/rust-lang/mdBook/compare/v0.4.31...v0.4.32)
### Fixed
- Fixed theme-color meta tag not syncing with the theme.
[#2118](https://github.com/rust-lang/mdBook/pull/2118)
### Changed
- Updated all dependencies.
[#2121](https://github.com/rust-lang/mdBook/pull/2121)
[#2122](https://github.com/rust-lang/mdBook/pull/2122)
[#2123](https://github.com/rust-lang/mdBook/pull/2123)
[#2124](https://github.com/rust-lang/mdBook/pull/2124)
[#2125](https://github.com/rust-lang/mdBook/pull/2125)
[#2126](https://github.com/rust-lang/mdBook/pull/2126)
## mdBook 0.4.31
[v0.4.30...v0.4.31](https://github.com/rust-lang/mdBook/compare/v0.4.30...v0.4.31)
### Fixed
- Fixed menu border render flash during page navigation.
[#2101](https://github.com/rust-lang/mdBook/pull/2101)
- Fixed flicker setting sidebar scroll position.
[#2104](https://github.com/rust-lang/mdBook/pull/2104)
- Fixed compile error with proc-macro2 on latest Rust nightly.
[#2109](https://github.com/rust-lang/mdBook/pull/2109)
## mdBook 0.4.30
[v0.4.29...v0.4.30](https://github.com/rust-lang/mdBook/compare/v0.4.29...v0.4.30)
### Added
- Added support for heading attributes.
Attributes are specified in curly braces just after the heading text.
An HTML ID can be specified with `#` and classes with `.`.
For example: `## My heading {#custom-id .class1 .class2}`
[#2013](https://github.com/rust-lang/mdBook/pull/2013)
- Added support for hidden code lines for languages other than Rust.
The `output.html.code.hidelines` table allows you to define the prefix character that will be used to hide code lines based on the language.
[#2093](https://github.com/rust-lang/mdBook/pull/2093)
### Fixed
- Fixed a few minor markdown rendering issues.
[#2092](https://github.com/rust-lang/mdBook/pull/2092)
## mdBook 0.4.29
[v0.4.28...v0.4.29](https://github.com/rust-lang/mdBook/compare/v0.4.28...v0.4.29)
### Changed
- Built-in fonts are no longer copied when `fonts/fonts.css` is overridden in the theme directory.
Additionally, the warning about `copy-fonts` has been removed if `fonts/fonts.css` is specified.
[#2080](https://github.com/rust-lang/mdBook/pull/2080)
- `mdbook init --force` now skips all interactive prompts as intended.
[#2057](https://github.com/rust-lang/mdBook/pull/2057)
- Updated dependencies
[#2063](https://github.com/rust-lang/mdBook/pull/2063)
[#2086](https://github.com/rust-lang/mdBook/pull/2086)
[#2082](https://github.com/rust-lang/mdBook/pull/2082)
[#2084](https://github.com/rust-lang/mdBook/pull/2084)
[#2085](https://github.com/rust-lang/mdBook/pull/2085)
### Fixed
- Switched from the `gitignore` library to `ignore`. This should bring some improvements with gitignore handling.
[#2076](https://github.com/rust-lang/mdBook/pull/2076)
## mdBook 0.4.28
[v0.4.27...v0.4.28](https://github.com/rust-lang/mdBook/compare/v0.4.27...v0.4.28)
### Changed
- The sidebar is now shown on wide screens when localstorage is disabled.
[#2017](https://github.com/rust-lang/mdBook/pull/2017)
- Preprocessors are now run with `mdbook test`.
[#1986](https://github.com/rust-lang/mdBook/pull/1986)
### Fixed
- Fixed regression in 0.4.26 that prevented the title bar from scrolling properly on smaller screens.
[#2039](https://github.com/rust-lang/mdBook/pull/2039)
## mdBook 0.4.27
[v0.4.26...v0.4.27](https://github.com/rust-lang/mdBook/compare/v0.4.26...v0.4.27)
### Changed
- Reverted the dependency update to the `toml` crate. This was an unintentional breaking change in 0.4.26.
[#2021](https://github.com/rust-lang/mdBook/pull/2021)
## mdBook 0.4.26
[v0.4.25...v0.4.26](https://github.com/rust-lang/mdBook/compare/v0.4.25...v0.4.26)
**The 0.4.26 release has been yanked due to an unintentional breaking change.**
### Changed
- Removed custom scrollbars for webkit browsers
[#1961](https://github.com/rust-lang/mdBook/pull/1961)
- Updated some dependencies
[#1998](https://github.com/rust-lang/mdBook/pull/1998)
[#2009](https://github.com/rust-lang/mdBook/pull/2009)
[#2011](https://github.com/rust-lang/mdBook/pull/2011)
- Fonts are now part of the theme.
The `output.html.copy-fonts` option has been deprecated.
To define custom fonts, be sure to define `theme/fonts.css`.
[#1987](https://github.com/rust-lang/mdBook/pull/1987)
### Fixed
- Fixed overflow viewport issue with mobile Safari
[#1994](https://github.com/rust-lang/mdBook/pull/1994)
## mdBook 0.4.25
[e14d381...1ba74a3](https://github.com/rust-lang/mdBook/compare/e14d381...1ba74a3)
### Fixed
- Fixed a regression where `mdbook test -L deps path-to-book` would not work.
[#1959](https://github.com/rust-lang/mdBook/pull/1959)
## mdBook 0.4.24
[eb77083...8767ebf](https://github.com/rust-lang/mdBook/compare/eb77083...8767ebf)
### Fixed
- The precompiled linux-gnu mdbook binary available on [GitHub Releases](https://github.com/rust-lang/mdBook/releases) inadvertently switched to a newer version of glibc. This release goes back to an older version that should be more compatible on older versions of Linux.
[#1955](https://github.com/rust-lang/mdBook/pull/1955)
## mdBook 0.4.23
[678b469...68a75da](https://github.com/rust-lang/mdBook/compare/678b469...68a75da)
### Changed
- Updated all dependencies
[#1951](https://github.com/rust-lang/mdBook/pull/1951)
[#1952](https://github.com/rust-lang/mdBook/pull/1952)
[#1844](https://github.com/rust-lang/mdBook/pull/1844)
- Updated minimum Rust version to 1.60.
[#1951](https://github.com/rust-lang/mdBook/pull/1951)
### Fixed
- Fixed a regression where playground code was missing hidden lines, preventing it from compiling correctly.
[#1950](https://github.com/rust-lang/mdBook/pull/1950)
## mdBook 0.4.22
[40c06f5...4844f72](https://github.com/rust-lang/mdBook/compare/40c06f5...4844f72)
### Added
- Added a `--chapter` option to `mdbook test` to specify a specific chapter to test.
[#1741](https://github.com/rust-lang/mdBook/pull/1741)
- Added CSS styling for `<kbd>` tags.
[#1906](https://github.com/rust-lang/mdBook/pull/1906)
- Added pre-compiled binaries for `x86_64-unknown-linux-musl` and `aarch64-unknown-linux-musl` (see [Releases](https://github.com/rust-lang/mdBook/releases)).
[#1862](https://github.com/rust-lang/mdBook/pull/1862)
- Added `build.extra-watch-dirs` which is an array of additional directories to watch for changes when running `mdbook serve`.
[#1884](https://github.com/rust-lang/mdBook/pull/1884)
### Changed
- Removed the `type="text/javascript"` attribute from `<script>` tags.
[#1881](https://github.com/rust-lang/mdBook/pull/1881)
- Switched to building with Rust Edition 2021.
This raises the minimum supported Rust version to 1.56.
[#1887](https://github.com/rust-lang/mdBook/pull/1887)
- When hidden code is hidden, the hidden parts are no longer copied to the clipboard via the copy button.
[#1911](https://github.com/rust-lang/mdBook/pull/1911)
- Various HTML changes and fixes to be more compliant with HTML5.
[#1924](https://github.com/rust-lang/mdBook/pull/1924)
- The theme picker now shows which theme is currently selected.
[#1935](https://github.com/rust-lang/mdBook/pull/1935)
### Fixed
- Avoid blank line at the end of an ACE code block
[#1836](https://github.com/rust-lang/mdBook/pull/1836)
## 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)
### Fixed
- Fixed a regression in 0.4.19 where inline code would have excessive padding
in some situations such as headings.
[#1855](https://github.com/rust-lang/mdBook/pull/1855)
## mdBook 0.4.19
[ae275ad...53055e0](https://github.com/rust-lang/mdBook/compare/ae275ad...53055e0)
### Added
- The `serve` command now supports HEAD requests.
[#1825](https://github.com/rust-lang/mdBook/pull/1825)
### Changed
- An error is now generated when a custom theme directory does not exist.
[#1791](https://github.com/rust-lang/mdBook/pull/1791)
- Very wide tables now have independent horizontal scrolling so that scrolling
to see the rest of the table will not scroll the entire page.
[#1617](https://github.com/rust-lang/mdBook/pull/1617)
- The buttons on code blocks are now only shown when the mouse cursor hovers
over them (or tapped on mobile). There is also some extra spacing to reduce
the overlap with the code.
[#1806](https://github.com/rust-lang/mdBook/pull/1806)
- The first chapter always generates an `index.html` file. Previously it would
only generate the index file for prefix chapters.
[#1829](https://github.com/rust-lang/mdBook/pull/1829)
### Fixed
- `mdbook serve --open` now properly handles the case if the first chapter is a draft.
[#1714](https://github.com/rust-lang/mdBook/pull/1714)
[#1830](https://github.com/rust-lang/mdBook/pull/1830)
- Very long words (over 80 characters) are no longer indexed to avoid a stack overflow.
[#1833](https://github.com/rust-lang/mdBook/pull/1833)
## mdBook 0.4.18
[981b79b...ae275ad](https://github.com/rust-lang/mdBook/compare/981b79b...ae275ad)
### Fixed
- Fixed rendering of SUMMARY links that contain markdown escapes or other
markdown elements.
[#1785](https://github.com/rust-lang/mdBook/pull/1785)
## mdBook 0.4.17
[a5fddfa...981b79b](https://github.com/rust-lang/mdBook/compare/a5fddfa...981b79b)
### Fixed
- Fixed parsing of `output.html.print` configuration table.
[#1775](https://github.com/rust-lang/mdBook/pull/1775)
## mdBook 0.4.16
[68a5c09...a5fddfa](https://github.com/rust-lang/mdBook/compare/68a5c09...a5fddfa)
### Added
- Added `output.html.print.page-break` config option to control whether or not
there is a page break between chapters in the print output.
[#1728](https://github.com/rust-lang/mdBook/pull/1728)
- Added `output.html.playground.runnable` config option to globally disable
the run button in code blocks.
[#1546](https://github.com/rust-lang/mdBook/pull/1546)
### Changed
- The `mdbook serve` live reload websocket now uses the protocol, host, and
port of the current page, allowing access through a proxy.
[#1771](https://github.com/rust-lang/mdBook/pull/1771)
- The 404 not-found page now includes the books title in the HTML title tag.
[#1693](https://github.com/rust-lang/mdBook/pull/1693)
- Migrated to clap 3.0 which handles CLI option parsing.
[#1731](https://github.com/rust-lang/mdBook/pull/1731)
### Fixed
- Minor fixes to the markdown parser.
[#1729](https://github.com/rust-lang/mdBook/pull/1729)
- Fixed incorrect parsing in `SUMMARY.md` when it didn't start with a title.
[#1744](https://github.com/rust-lang/mdBook/pull/1744)
- Fixed duplicate anchor IDs for links in search results.
[#1749](https://github.com/rust-lang/mdBook/pull/1749)
## mdBook 0.4.15
[5eb7d46...68a5c09](https://github.com/rust-lang/mdBook/compare/5eb7d46...68a5c09)
### Changed
- Major update to expand the documentation located at <https://rust-lang.github.io/mdBook/>.
[#1709](https://github.com/rust-lang/mdBook/pull/1709)
[#1710](https://github.com/rust-lang/mdBook/pull/1710)
- Updated the markdown parser with various fixes for common-mark compliance.
[#1712](https://github.com/rust-lang/mdBook/pull/1712)
## mdBook 0.4.14
[ffa8284...c9b6be8](https://github.com/rust-lang/mdBook/compare/ffa8284...c9b6be8)
### Added
- The 2021 Rust edition option has been stabilized.
[#1642](https://github.com/rust-lang/mdBook/pull/1642)
### Changed
- Header anchors no longer include any HTML tags. Previously only a small
subset were excluded.
[#1683](https://github.com/rust-lang/mdBook/pull/1683)
- Deprecated the google-analytics option. Books using this option should place
the appropriate code in the `theme/head.hbs` file instead.
[#1675](https://github.com/rust-lang/mdBook/pull/1675)
### Fixed
- Updated the markdown parser which brings in a few small fixes and removes
the custom smart quote handling.
[#1668](https://github.com/rust-lang/mdBook/pull/1668)
- Fixed iOS Safari enlarging text when going into landscape mode.
[#1685](https://github.com/rust-lang/mdBook/pull/1685)
## mdBook 0.4.13
[e6629cd...f55028b](https://github.com/rust-lang/mdBook/compare/e6629cd...f55028b)
### Added
- Added the ability to specify the preprocessor order.
[#1607](https://github.com/rust-lang/mdBook/pull/1607)
### Fixed
- Include chapters with no headers in the search index
[#1637](https://github.com/rust-lang/mdBook/pull/1637)
- Switched to the `opener` crate for opening a web browser, which should fix
some issues with blocking.
[#1656](https://github.com/rust-lang/mdBook/pull/1656)
- Fixed clicking the border of the theme switcher breaking the theme selection.
[#1651](https://github.com/rust-lang/mdBook/pull/1651)
## mdBook 0.4.12
[14add9c...8b4e488](https://github.com/rust-lang/mdBook/compare/14add9c...8b4e488)
### Changed
- Reverted the change to update to highlight.js 11, as it broke hidden code lines.
[#1597](https://github.com/rust-lang/mdBook/pull/1621)
## mdBook 0.4.11
[e440094...2cf00d0](https://github.com/rust-lang/mdBook/compare/e440094...2cf00d0)
### Added
- Added support for Rust 2021 edition.
[#1596](https://github.com/rust-lang/mdBook/pull/1596)
- Added `mdbook completions` subcommand which provides shell completions.
[#1425](https://github.com/rust-lang/mdBook/pull/1425)
- Added `--title` and `--ignore` flags to `mdbook init` to avoid the
interactive input.
[#1559](https://github.com/rust-lang/mdBook/pull/1559)
### Changed
- If running a Rust example does not have any output, it now displays the text
"No output" instead of not showing anything.
[#1599](https://github.com/rust-lang/mdBook/pull/1599)
- Code block language tags can now be separated by space or tab (along with
commas) to match the behavior of other sites like GitHub and rustdoc.
[#1469](https://github.com/rust-lang/mdBook/pull/1469)
- Updated `warp` (the web server) to the latest version.
This also updates the minimum supported Rust version to 1.46.
[#1612](https://github.com/rust-lang/mdBook/pull/1612)
- Updated to highlight.js 11. This has various highlighting improvements.
[#1597](https://github.com/rust-lang/mdBook/pull/1597)
### Fixed
- Inline code blocks inside a header are no longer highlighted when
`output.html.playground.editable` is `true`.
[#1613](https://github.com/rust-lang/mdBook/pull/1613)
## mdBook 0.4.10
[2f7293a...dc2062a](https://github.com/rust-lang/mdBook/compare/2f7293a...dc2062a)
### Changed
- Reverted breaking change in 0.4.9 that removed the `__non_exhaustive` marker
on the `Book` struct.
[#1572](https://github.com/rust-lang/mdBook/pull/1572)
- Updated handlebars to 4.0.
[#1550](https://github.com/rust-lang/mdBook/pull/1550)
- Removed the `chapter_begin` id on the print page's chapter separators.
[#1541](https://github.com/rust-lang/mdBook/pull/1541)
## 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)
### Added
- Added the option `output.html.edit-url-template` which can be a URL which is
linked on each page to direct the user to a site (such as GitHub) where the
user can directly suggest an edit for the page they are currently reading.
[#1506](https://github.com/rust-lang/mdBook/pull/1506)
### Changed
- Printed output now includes a page break between chapters.
[#1485](https://github.com/rust-lang/mdBook/pull/1485)
### Fixed
- HTML, such as HTML comments, is now ignored if it appears above the title line
in `SUMMARY.md`.
[#1437](https://github.com/rust-lang/mdBook/pull/1437)
## 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)
### Added
- Added the `output.html.print.enable` configuration value to disable the
"print" page.
[#1169](https://github.com/rust-lang/mdBook/pull/1169)
- Added a list of supported languages for syntax-highlighting to the
documentation.
[#1345](https://github.com/rust-lang/mdBook/pull/1345)
### Fixed
- Now supports symbolic links for files in the `src` directory.
[#1323](https://github.com/rust-lang/mdBook/pull/1323)
## mdBook 0.4.3
[9278b83...4df9ec9](https://github.com/rust-lang/mdBook/compare/9278b83...4df9ec9)
### Added
- Added `output.html.cname` option to emit a `CNAME` file which is used by
GitHub Pages to know which domain is being used.
[#1311](https://github.com/rust-lang/mdBook/pull/1311)
### Changed
- `mdbook test` no longer stops on the first test failure, but instead will
run all the tests.
[#1313](https://github.com/rust-lang/mdBook/pull/1313)
- Removed the `local` font source for Source Code Pro, as the locally
installed font may not render properly on FireFox on macOS.
[#1307](https://github.com/rust-lang/mdBook/pull/1307)
### Fixed
- Added newline to end of `.nojekyll` file.
[#1310](https://github.com/rust-lang/mdBook/pull/1310)
- Fixed missing space before draft chapter titles.
[#1309](https://github.com/rust-lang/mdBook/pull/1309)
## mdBook 0.4.2
[649f355...9278b83](https://github.com/rust-lang/mdBook/compare/649f355...9278b83)
### Changed
- The "show hidden lines" icon has changed from the "expand" icon to an "eye".
[#1281](https://github.com/rust-lang/mdBook/pull/1281)
- Updated highlight.js. This adds several languages: c, c-like (effectively
cpp), csharp (replaces cs), kotlin, less, lua, php-template, plaintext,
python-repl, r, scss, typescript.
[#1277](https://github.com/rust-lang/mdBook/pull/1277)
### Fixed
- Fixed SUMMARY links that contained newlines.
[#1291](https://github.com/rust-lang/mdBook/pull/1291)
- Fixed SUMMARY links that contain `%20` spaces.
[#1293](https://github.com/rust-lang/mdBook/pull/1293)
- Fixed favicon so that if only the png or svg is overridden, the other is not
automatically included in the `<link>` tag.
[#1272](https://github.com/rust-lang/mdBook/pull/1272)
## mdBook 0.4.1
[d4df7e7...649f355](https://github.com/rust-lang/mdBook/compare/d4df7e7...649f355)
### Changed
- Removed several outdated dev-dependencies.
[#1267](https://github.com/rust-lang/mdBook/pull/1267)
### Fixed
- Fixed sidebar scrolling if the book includes part titles.
[#1265](https://github.com/rust-lang/mdBook/pull/1265)
- Don't include the default favicon if only one of the PNG or SVG is overridden.
[#1266](https://github.com/rust-lang/mdBook/pull/1266)
## mdBook 0.4.0
[99ecd4f...d4df7e7](https://github.com/rust-lang/mdBook/compare/99ecd4f...d4df7e7)
### Breaking Changes
- Several of the changes in the release have altered the public API of the
mdbook library.
- Many dependencies have been updated or replaced.
This also removes the `--websocket-hostname` and `--websocket-port` from
the `serve` command.
[#1211](https://github.com/rust-lang/mdBook/pull/1211)
- A new "404" page is now automatically rendered. This requires knowledge of
the base URL of your site to work properly. If you decide to use this as
your 404 page, you should set the `site-url` setting in the book
configuration so mdbook can generate the links correctly. Alternatively you
can disable the 404 page generation, or set up your own 404 handling in your
web server.
[#1221](https://github.com/rust-lang/mdBook/pull/1221)
- The `debug` and `output` features have been removed as they were unused.
[#1211](https://github.com/rust-lang/mdBook/pull/1211)
- If you are using customized themes, you may want to consider setting the
`preferred-dark-theme` config setting, as it now defaults to "navy".
[#1199](https://github.com/rust-lang/mdBook/pull/1199)
- "Playpen" has been renamed to "playground". This is generally backwards
compatible for users, but `{{#playpen}}` will now display warnings. This may
impact books that have modified the "playpen" elements in the theme.
[#1241](https://github.com/rust-lang/mdBook/pull/1241)
- If a renderer is not installed, it is now treated as an error. If you want
the old behavior of ignoring missing renderers, set the `optional` setting
for that renderer.
[#1122](https://github.com/rust-lang/mdBook/pull/1122)
- If you have a custom favicon, you may need to look into adding an SVG
version, otherwise the default SVG icon will be displayed.
[#1230](https://github.com/rust-lang/mdBook/pull/1230)
### Added
- Added a new `[rust]` configuration section to `book.toml`, which allows
setting the default edition with `edition = "2018"`.
[#1163](https://github.com/rust-lang/mdBook/pull/1163)
- Renderers can now be marked as `optional`, so that they will be ignored if
the renderer is not installed.
[#1122](https://github.com/rust-lang/mdBook/pull/1122)
- Added `head.hbs` to allow adding content to the `<head>` section in HTML.
[#1206](https://github.com/rust-lang/mdBook/pull/1206)
- Added "draft chapters". These are chapters listed without a link to indicate
content yet to be written.
[#1153](https://github.com/rust-lang/mdBook/pull/1153)
- Added "parts" to split a book into different sections. Headers can be added
to `SUMMARY.md` to signify different sections.
[#1171](https://github.com/rust-lang/mdBook/pull/1171)
- Added generation of a "404" page for handling missing pages and broken links.
[#1221](https://github.com/rust-lang/mdBook/pull/1221)
- Added configuration section for specifying URL redirects.
[#1237](https://github.com/rust-lang/mdBook/pull/1237)
- Added an SVG favicon that works with light and dark colors schemes.
[#1230](https://github.com/rust-lang/mdBook/pull/1230)
### Changed
- Changed default Rust attribute of `allow(unused_variables)` to `allow(unused)`.
[#1195](https://github.com/rust-lang/mdBook/pull/1195)
- Fonts are now served locally instead of from the Google Fonts CDN. The
`copy-fonts` option was added to disable this if you want to supply your own
fonts.
[#1188](https://github.com/rust-lang/mdBook/pull/1188)
- Switched the built-in webserver for the `serve` command to a new
implementation. This results in some internal differences in how websockets
are handled, which removes the separate websocket options. This should also
make it easier to serve multiple books at once.
[#1211](https://github.com/rust-lang/mdBook/pull/1211)
- The default dark theme is now "navy".
[#1199](https://github.com/rust-lang/mdBook/pull/1199)
- "Playpen" has been renamed to "playground", matching the actual name of the
service which was renamed many years ago.
[#1241](https://github.com/rust-lang/mdBook/pull/1241)
### Fixed
- Links with the `+` symbol should now work.
[#1208](https://github.com/rust-lang/mdBook/pull/1208)
- The `MDBOOK_BOOK` environment variable now correctly allows overriding the
entire book configuration.
[#1207](https://github.com/rust-lang/mdBook/pull/1207)
- The sidebar can no longer be dragged outside of the window.
[#1229](https://github.com/rust-lang/mdBook/pull/1229)
- Hide the Rust Playground "play" button for `no_run` code samples.
[#1249](https://github.com/rust-lang/mdBook/pull/1249)
- Fixed the `--dest-dir` command-line option for the `serve` and `watch`
commands.
[#1228](https://github.com/rust-lang/mdBook/pull/1228)
- Hotkey handlers are now disabled in `text` input fields (for example, typing
`S` in a custom text input field).
[#1244](https://github.com/rust-lang/mdBook/pull/1244)
## mdBook 0.3.7
[88684d8...99ecd4f](https://github.com/rust-lang/mdBook/compare/88684d8...99ecd4f)
### Changed
- Code spans in headers are no longer highlighted as code.
[#1162](https://github.com/rust-lang/mdBook/pull/1162)
- The sidebar will now scroll the activate page to the middle instead of the top.
[#1161](https://github.com/rust-lang/mdBook/pull/1161)
- Reverted change to reject build output within the `src` directory, and
instead add a check that prevents infinite copies.
[#1181](https://github.com/rust-lang/mdBook/pull/1181)
[#1026](https://github.com/rust-lang/mdBook/pull/1026)
### Fixed
- Fixed sidebar line-height jumping for collapsed chapters.
[#1182](https://github.com/rust-lang/mdBook/pull/1182)
- Fixed theme selector focus.
[#1170](https://github.com/rust-lang/mdBook/pull/1170)
## mdBook 0.3.6
[efdb832...88684d8](https://github.com/rust-lang/mdBook/compare/efdb832...88684d8)
### Added
- `MDBook::execute_build_process` is now publicly accessible in the API so
that plugins can more easily initiate the build process.
[#1099](https://github.com/rust-lang/mdBook/pull/1099)
### Changed
- Use a different color for Ayu theme's highlighting for Rust attributes (uses
a bright color instead of the comment color).
[#1133](https://github.com/rust-lang/mdBook/pull/1133)
- Adjusted spacing of sidebar entries.
[#1137](https://github.com/rust-lang/mdBook/pull/1137)
- Slightly adjusted line-height of `<p>`, `<ul>`, and `<ol>`.
[#1136](https://github.com/rust-lang/mdBook/pull/1136)
- Handlebars updated to 3.0.
[#1130](https://github.com/rust-lang/mdBook/pull/1130)
### Fixed
- Fix an issue with sidebar scroll position on reload.
[#1108](https://github.com/rust-lang/mdBook/pull/1108)
- `mdbook serve` will retain the current scroll position when the page is reloaded.
[#1097](https://github.com/rust-lang/mdBook/pull/1097)
- Fixed the page name if the book didn't have a title to not be prefixed with ` - `.
[#1145](https://github.com/rust-lang/mdBook/pull/1145)
- HTML attributes `rel=next` and `rel=previous` are now supported in "wide"
mode (previously they were only set in narrow mode).
[#1150](https://github.com/rust-lang/mdBook/pull/1150)
- Prevent recursive copies when the destination directory is contained in the
source directory.
[#1135](https://github.com/rust-lang/mdBook/pull/1135)
- Adjusted the menu bar animation to not immediately obscure the top content.
[#989](https://github.com/rust-lang/mdBook/pull/989)
- Fix for comments in SUMMARY.md that appear between items.
[#1167](https://github.com/rust-lang/mdBook/pull/1167)
## mdBook 0.3.5
[6e0d0fa...efdb832](https://github.com/rust-lang/mdBook/compare/6e0d0fa...efdb832)
### Changed
- The `default-theme` config setting is now case-insensitive.
[#1079](https://github.com/rust-lang/mdBook/pull/1079)
### Fixed
- Fixed `#` hidden Rust code lines not rendering properly.
[#1088](https://github.com/rust-lang/mdBook/pull/1088)
- Updated pulldown-cmark to 0.6.1, fixing several issues.
[#1021](https://github.com/rust-lang/mdBook/pull/1021)
## mdBook 0.3.4
[e5f77aa...6e0d0fa](https://github.com/rust-lang/mdBook/compare/e5f77aa...6e0d0fa)
### Changed
- Switch to relative `rem` font sizes from `px`.
[#894](https://github.com/rust-lang/mdBook/pull/894)
- Migrated repository to https://github.com/rust-lang/mdBook/
[#1083](https://github.com/rust-lang/mdBook/pull/1083)
## mdBook 0.3.3
[2b649fe...e5f77aa](https://github.com/rust-lang/mdBook/compare/2b649fe...e5f77aa)
### Changed
- Improvements to the automatic dark theme selection.
[#1069](https://github.com/rust-lang/mdBook/pull/1069)
- Fragment links now prevent scrolling the header behind the menu bar.
[#1077](https://github.com/rust-lang/mdBook/pull/1077)
### Fixed
- Fixed error when building a book that has a spacer immediately after the
first chapter.
[#1075](https://github.com/rust-lang/mdBook/pull/1075)
## mdBook 0.3.2
[9cd47eb...2b649fe](https://github.com/rust-lang/mdBook/compare/9cd47eb...2b649fe)
### Added
- Added a markdown renderer, which is off by default. This may be useful for
debugging preprocessors.
[#1018](https://github.com/rust-lang/mdBook/pull/1018)
- Code samples may now include line numbers with the
`output.html.playpen.line-numbers` configuration value.
[#1035](https://github.com/rust-lang/mdBook/pull/1035)
- The `watch` and `serve` commands will now ignore files listed in
`.gitignore`.
[#1044](https://github.com/rust-lang/mdBook/pull/1044)
- Added automatic dark-theme detection based on the CSS `prefers-color-scheme`
feature. This may be enabled by setting `output.html.preferred-dark-theme`
to your preferred dark theme.
[#1037](https://github.com/rust-lang/mdBook/pull/1037)
- Added `rustdoc_include` preprocessor. This makes it easier to include
portions of an external Rust source file. The rest of the file is hidden,
but the user may expand it to see the entire file, and will continue to work
with `mdbook test`.
[#1003](https://github.com/rust-lang/mdBook/pull/1003)
- Added Ctrl-Enter shortcut to the playpen editor to automatically run the
sample.
[#1066](https://github.com/rust-lang/mdBook/pull/1066)
- Added `output.html.playpen.copyable` configuration option to disable
the copy button.
[#1050](https://github.com/rust-lang/mdBook/pull/1050)
- Added ability to dynamically expand and fold sections within the sidebar.
See the `output.html.fold` configuration to enable this feature.
[#1027](https://github.com/rust-lang/mdBook/pull/1027)
### Changed
- Use standard `scrollbar-color` CSS along with webkit extension
[#816](https://github.com/rust-lang/mdBook/pull/816)
- The renderer build directory is no longer deleted before the renderer is
run. This allows a backend to cache results between runs.
[#985](https://github.com/rust-lang/mdBook/pull/985)
- Next/prev links now highlight on hover to indicate it is clickable.
[#994](https://github.com/rust-lang/mdBook/pull/994)
- Increase padding of table headers.
[#824](https://github.com/rust-lang/mdBook/pull/824)
- Errors in `[output.html]` config are no longer ignored.
[#1033](https://github.com/rust-lang/mdBook/pull/1033)
- Updated highlight.js for syntax highlighting updates (primarily to add
async/await to Rust highlighting).
[#1041](https://github.com/rust-lang/mdBook/pull/1041)
- Raised minimum supported rust version to 1.35.
[#1003](https://github.com/rust-lang/mdBook/pull/1003)
- Hidden code lines are no longer dynamically removed via JavaScript, but
instead managed with CSS.
[#846](https://github.com/rust-lang/mdBook/pull/846)
[#1065](https://github.com/rust-lang/mdBook/pull/1065)
- Changed the default font set for the ACE editor, giving preference to
"Source Code Pro".
[#1062](https://github.com/rust-lang/mdBook/pull/1062)
- Windows 32-bit releases are no longer published.
[#1071](https://github.com/rust-lang/mdBook/pull/1071)
### Fixed
- Fixed sidebar auto-scrolling.
[#1052](https://github.com/rust-lang/mdBook/pull/1052)
- Fixed error message when running `clean` multiple times.
[#1055](https://github.com/rust-lang/mdBook/pull/1055)
- Actually fix the "next" link on index.html. The previous fix didn't work.
[#1005](https://github.com/rust-lang/mdBook/pull/1005)
- Stop using `inline-block` for `inline code`, fixing selection highlighting
and some rendering issues.
[#1058](https://github.com/rust-lang/mdBook/pull/1058)
- Fix header auto-hide on browsers with momentum scrolling that allows
negative `scrollTop`.
[#1070](https://github.com/rust-lang/mdBook/pull/1070)
## mdBook 0.3.1
[69a08ef...9cd47eb](https://github.com/rust-lang/mdBook/compare/69a08ef...9cd47eb)
### Added
- 🔥 Added ability to include files using anchor points instead of line numbers.
[#851](https://github.com/rust-lang/mdBook/pull/851)
- Added `language` configuration value to set the language of the book, which
will affect things like the `<html lang="en">` tag.
[#941](https://github.com/rust-lang/mdBook/pull/941)
### Changed
- Updated to handlebars 2.0.
[#977](https://github.com/rust-lang/mdBook/pull/977)
### Fixed
- Fixed memory leak warning.
[#967](https://github.com/rust-lang/mdBook/pull/967)
- Fix more print.html links.
[#963](https://github.com/rust-lang/mdBook/pull/963)
- Fixed crash on some unicode input.
[#978](https://github.com/rust-lang/mdBook/pull/978)
## mdBook 0.3.0
[6cbc41d...69a08ef](https://github.com/rust-lang/mdBook/compare/6cbc41d...69a08ef)
### Added
- Added ability to resize the sidebar.
[#849](https://github.com/rust-lang/mdBook/pull/849)
- Added `load_with_config_and_summary` function to `MDBook` to be able to
build a book with a custom `Summary`.
[#883](https://github.com/rust-lang/mdBook/pull/883)
- Set `noindex` on `print.html` page to prevent robots from indexing it.
[#844](https://github.com/rust-lang/mdBook/pull/844)
- Added support for ~~strikethrough~~ and GitHub-style tasklists.
[#952](https://github.com/rust-lang/mdBook/pull/952)
### Changed
- Command-line help output is now colored.
[#861](https://github.com/rust-lang/mdBook/pull/861)
- The build directory is now deleted before rendering starts, instead of after
if finishes.
[#878](https://github.com/rust-lang/mdBook/pull/878)
- Removed dependency on `same-file` crate.
[#903](https://github.com/rust-lang/mdBook/pull/903)
- 💥 Renamed `with_preprecessor` to `with_preprocessor`.
[#906](https://github.com/rust-lang/mdBook/pull/906)
- Updated ACE editor to 1.4.4, should remove a JavaScript console warning.
[#935](https://github.com/rust-lang/mdBook/pull/935)
- Dependencies have been updated.
[#934](https://github.com/rust-lang/mdBook/pull/934)
[#945](https://github.com/rust-lang/mdBook/pull/945)
- Highlight.js has been updated. This fixes some TOML highlighting, and adds
Julia support.
[#942](https://github.com/rust-lang/mdBook/pull/942)
- 🔥 Updated to pulldown-cmark 0.5. This may have significant changes to the
formatting of existing books, as the newer version has more accurate
interpretation of the CommonMark spec and a large number of bug fixes and
changes.
[#898](https://github.com/rust-lang/mdBook/pull/898)
- The `diff` language should now highlight correctly.
[#943](https://github.com/rust-lang/mdBook/pull/943)
- Make the blank region of a header not clickable.
[#948](https://github.com/rust-lang/mdBook/pull/948)
- Rustdoc tests now use the preprocessed content instead of the raw,
unpreprocessed content.
[#891](https://github.com/rust-lang/mdBook/pull/891)
### Fixed
- Fixed file change detection so that `mdbook serve` only reloads once when
multiple files are changed at once.
[#870](https://github.com/rust-lang/mdBook/pull/870)
- Fixed on-hover color highlighting for links in sidebar.
[#834](https://github.com/rust-lang/mdBook/pull/834)
- Fixed loss of focus when clicking the "Copy" button in code blocks.
[#867](https://github.com/rust-lang/mdBook/pull/867)
- Fixed incorrectly stripping the path for `additional-js` files.
[#796](https://github.com/rust-lang/mdBook/pull/796)
- Fixed color of `code spans` that are links.
[#905](https://github.com/rust-lang/mdBook/pull/905)
- Fixed "next" navigation on index.html.
[#916](https://github.com/rust-lang/mdBook/pull/916)
- Fixed keyboard chapter navigation for `file` urls.
[#915](https://github.com/rust-lang/mdBook/pull/915)
- Fixed bad wrapping for inline code on some browsers.
[#818](https://github.com/rust-lang/mdBook/pull/818)
- Properly load an existing `SUMMARY.md` in `mdbook init`.
[#841](https://github.com/rust-lang/mdBook/pull/841)
- Fixed some broken links in `print.html`.
[#871](https://github.com/rust-lang/mdBook/pull/871)
- The Rust Playground link now supports the 2018 edition.
[#946](https://github.com/rust-lang/mdBook/pull/946)
## mdBook 0.2.3 (2018-01-18)
[2c20c99...6cbc41d](https://github.com/rust-lang/mdBook/compare/2c20c99...6cbc41d)
### Added
- Added an optional button to the top of the page which will link to a git
repository. Use the `git-repository-url` and `git-repository-icon` options
in the `[output.html]` section to enable it and set its appearance.
[#802](https://github.com/rust-lang/mdBook/pull/802)
- Added a `default-theme` option to the `[output.html]` section.
[#804](https://github.com/rust-lang/mdBook/pull/804)
### Changed
- 💥 Header ID anchors no longer add an arbitrary `a` character for headers
that start with a non-ascii-alphabetic character.
[#788](https://github.com/rust-lang/mdBook/pull/788)
### Fixed
- Fix websocket hostname usage
[#865](https://github.com/rust-lang/mdBook/pull/865)
- Fixing links in print.html
[#866](https://github.com/rust-lang/mdBook/pull/866)
## mdBook 0.2.2 (2018-10-19)
[7e2e095...2c20c99](https://github.com/rust-lang/mdBook/compare/7e2e095...2c20c99)
### Added
- 🎉 Process-based custom preprocessors. See [the
docs](https://rust-lang.github.io/mdBook/for_developers/preprocessors.html)
for more.
[#792](https://github.com/rust-lang/mdBook/pull/792)
- 🎉 Configurable preprocessors.
Added `build.use-default-preprocessors` boolean TOML key to allow disabling
the built-in `links` and `index` preprocessors.
Added `[preprocessor]` TOML tables to configure each preprocessor.
Specifying `[preprocessor.links]` or `[preprocessor.index]` will enable the
respective built-in preprocessor if `build.use-default-preprocessors` is
`false`.
Added `fn supports_renderer(&self, renderer: &str) -> bool` to the
`Preprocessor` trait to specify if the preprocessor supports the given
renderer. The default implementation always returns `true`.
`Preprocessor::run` now takes a book by value instead of a mutable
reference. It should return a `Book` value with the intended modifications.
Added `PreprocessorContext::renderer` to indicate the renderer being used.
[#658](https://github.com/rust-lang/mdBook/pull/658)
[#787](https://github.com/rust-lang/mdBook/pull/787)
### Fixed
- Fix paths to additional CSS and JavaScript files
[#777](https://github.com/rust-lang/mdBook/pull/777)
- Ensure section numbers are correctly incremented after a horizontal
separator
[#790](https://github.com/rust-lang/mdBook/pull/790)
## mdBook 0.2.1 (2018-08-22)
[91ffca1...7e2e095](https://github.com/rust-lang/mdBook/compare/91ffca1...7e2e095)
### Changed
- Update to handlebars-rs 1.0
[#761](https://github.com/rust-lang/mdBook/pull/761)
### Fixed
- Fix table colors, broken by Stylus -> CSS transition
[#765](https://github.com/rust-lang/mdBook/pull/765)
## mdBook 0.2.0 (2018-08-02)
### Changed
- 💥 This release changes how links are handled in mdBook. Previously, relative
links were interpreted relative to the book's root. In `0.2.0`+ links are
relative to the page they are in, and use the `.md` extension. This has [several
advantages](https://github.com/rust-lang/mdBook/pull/603#issue-166701447),
such as making links work in other markdown viewers like GitHub. You will
likely have to change links in your book to accommodate this change. For
example, a book with this layout:
```
chapter_1/
section_1.md
section_2.md
SUMMARY.md
```
Previously a link in `section_1.md` to `section_2.md` would look like this:
```markdown
[section_2](chapter_1/section_2.html)
```
Now it must be changed to this:
```markdown
[section_2](section_2.md)
```
- 💥 `mdbook test --library-path` now accepts a comma-delimited list of
arguments rather than taking all following arguments. This makes it easier
to handle the trailing book directory argument without always needing to put
` -- ` before it. Multiple instances of the option continue to be accepted:
`mdbook test -L foo -L bar`.
- 💥 `mdbook serve` has some of its options renamed for clarity. See `mdbook
help serve` for details.
- Embedded rust playpens now use the "stable" playground API.
[#754](https://github.com/rust-lang/mdBook/pull/754)
### Fixed
- Escaped includes (`\{{#include file.rs}}`) will now render correctly.
[f30ce01](https://github.com/rust-lang/mdBook/commit/f30ce0184d71e342141145472bf816419d30a2c5)
- `index.html` will now render correctly when the book's first section is
inside a subdirectory.
[#756](https://github.com/rust-lang/mdBook/pull/756)
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# The Rust Code of Conduct
The Code of Conduct for this repository [can be found online](https://www.rust-lang.org/conduct.html).
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing
Welcome stranger!
If you have come here to learn how to contribute to mdBook, we have some tips for you!
First of all, don't hesitate to ask questions!
Use the [issue tracker](https://github.com/rust-lang/mdBook/issues), no question is too simple.
## Issue assignment
**:warning: Important :warning:**
Before working on pull request, please ping us on the corresponding issue.
The current PR backlog is beyond what we can process at this time.
Only issues that have an [`E-Help-wanted`](https://github.com/rust-lang/mdBook/labels/E-Help-wanted) or [`Feature accepted`](https://github.com/rust-lang/mdBook/labels/Feature%20accepted) label will likely receive reviews.
If there isn't already an open issue for what you want to work on, please open one first to see if it is something we would be available to review.
## Issues to work on
If you are starting out, you might be interested in the
[E-Easy issues](https://github.com/rust-lang/mdBook/issues?q=is%3Aopen+is%3Aissue+label%3AE-Easy).
Those are issues that are considered more straightforward for beginners to Rust or the codebase itself.
These issues can be a good launching pad for more involved issues.
Easy tasks for a first time contribution include documentation improvements, new tests, examples, updating dependencies, etc.
If you come from a web development background, you might be interested in issues related to web technologies tagged
[A-JavaScript](https://github.com/rust-lang/mdBook/issues?q=is%3Aopen+is%3Aissue+label%3AA-JavaScript),
[A-Style](https://github.com/rust-lang/mdBook/issues?q=is%3Aopen+is%3Aissue+label%3AA-Style),
[A-HTML](https://github.com/rust-lang/mdBook/issues?q=is%3Aopen+is%3Aissue+label%3AA-HTML) or
[A-Mobile](https://github.com/rust-lang/mdBook/issues?q=is%3Aopen+is%3Aissue+label%3AA-Mobile).
When you decide you want to work on a specific issue, and it isn't already assigned to someone else, assign the issue to yourself by leaving a comment with the text `@rustbot claim`.
Again, do not hesitate to ask questions. We will gladly mentor anyone that want to tackle an issue.
Issues on the issue tracker are categorized with the following labels:
- **A**-prefixed labels state which area of the project an issue relates to.
- **E**-prefixed labels show an estimate of the experience necessary to fix the issue.
- **M**-prefixed labels are meta-issues regarding the management of the mdBook project itself
- **S**-prefixed labels show the status of the issue
- **C**-prefixed labels show the category of issue
## Building mdBook
mdBook builds on stable Rust, if you want to build mdBook from source, here are the steps to follow:
1. Navigate to the directory of your choice
0. Clone this repository with git.
```
git clone https://github.com/rust-lang/mdBook.git
```
0. Navigate into the newly created `mdBook` directory
0. Run `cargo build`
The resulting binary can be found in `mdBook/target/debug/` under the name `mdbook` or `mdbook.exe`.
## Code quality
We love code quality and Rust has some excellent tools to assist you with contributions.
### Formatting code with rustfmt
Before you make your Pull Request to the project, please run it through the `rustfmt` utility.
This will ensure we have good quality source code that is better for us all to maintain.
[rustfmt](https://github.com/rust-lang/rustfmt) has a lot more information on the project.
The quick guide is
1. Install it (`rustfmt` is usually installed by default via [rustup](https://rustup.rs/)):
```
rustup component add rustfmt
```
1. You can now run `rustfmt` on a single file simply by...
```
rustfmt src/path/to/your/file.rs
```
... or you can format the entire project with
```
cargo fmt
```
When run through `cargo` it will format all bin and lib files in the current package.
For more information, such as running it from your favourite editor, please see the `rustfmt` project. [rustfmt](https://github.com/rust-lang/rustfmt)
### Finding issues with clippy
[Clippy](https://doc.rust-lang.org/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.
1. To install
```
rustup component add clippy
```
2. Running clippy
```
cargo clippy
```
## Change requirements
Please consider the following when making a change:
* Almost all changes that modify the Rust code must be accompanied with a test.
* Almost all features and changes must update the documentation.
mdBook has the [mdBook Guide](https://rust-lang.github.io/mdBook/) whose source is at <https://github.com/rust-lang/mdBook/tree/master/guide>.
* Almost all Rust items should be documented with doc comments.
See the [Rustdoc Book](https://doc.rust-lang.org/rustdoc/) for more information on writing doc comments.
* Breaking the API can only be done in major SemVer releases.
These are done very infrequently, so it is preferred to avoid these when possible.
See [SemVer Compatibility](https://doc.rust-lang.org/cargo/reference/semver.html) for more information on what a SemVer breaking change is.
(Note: At this time, some SemVer breaking changes are inevitable due to the current code structure.
An example is adding new fields to the config structures.
These are intended to be fixed in the next major release.)
* Similarly, the CLI interface is considered to be stable.
Care should be taken to avoid breaking existing workflows.
* Check out the [Rust API Guidelines](https://rust-lang.github.io/api-guidelines/) for guidelines on designing the API.
## Tests
The main test harness is described in the [testsuite documentation](tests/testsuite/README.md). There are several different commands to run different kinds of tests:
- `cargo test --workspace` — This runs all of the unit and integration tests, except for the GUI tests.
- `cargo test --test gui` — This runs the [GUI test harness](#browser-compatibility-and-testing). This does not get run automatically due to its extra requirements.
- `npm run lint` — [Checks the `.js` files](#checking-changes-in-js-files)
- `cargo test --workspace --no-default-features` — Testing without default features helps check that all feature checks are implemented correctly.
- `cargo clippy --workspace --all-targets --no-deps -- -D warnings` — This makes sure that there are no clippy warnings.
- `RUSTDOCFLAGS="-D warnings" cargo doc --workspace --document-private-items --no-deps` — This verifies that there aren't any rustdoc warnings.
- `cargo fmt --check` — Verifies that everything is formatted correctly.
- `cargo +stable semver-checks` — Verifies that no SemVer breaking changes have been made. You must install [`cargo-semver-checks`](https://crates.io/crates/cargo-semver-checks) first.
To help simplify running all these commands, you can run the following cargo command:
```sh
cargo xtask test-all
```
It is useful to run all tests before submitting a PR. While developing I recommend to run some subset of that command based on what you are working on. There are individual arguments for each one. For example:
```sh
cargo xtask test-workspace clippy doc eslint fmt gui semver-checks
```
While developing, remove any of those arguments that are not relevant to what you are changing, or are really slow.
## Making a pull-request
When you feel comfortable that your changes could be integrated into mdBook, you can create a pull-request on GitHub.
One of the core maintainers will then approve the changes or request some changes before it gets merged.
That's it, happy contributions! :tada: :tada: :tada:
## Browser compatibility and testing
Currently we don't have a strict browser compatibility matrix due to our limited resources.
We generally strive to keep mdBook compatible with a relatively recent browser on all of the most major platforms.
That is, supporting Chrome, Safari, Firefox, Edge on Windows, macOS, Linux, iOS, and Android.
If possible, do your best to avoid breaking older browser releases.
GUI tests are checked with the GUI testsuite. To run it, you need to install `npm` first. Then run:
```
cargo test --test gui
```
If you want to only run some tests, you can filter them by passing (part of) their name:
```
cargo test --test gui -- search
```
The first time, it'll fail and ask you to install the `browser-ui-test` package. Install it with the provided
command then re-run the tests.
If you want to disable the headless mode, use the `--disable-headless-test` option:
```
cargo test --test gui -- --disable-headless-test
```
The GUI tests are in the directory `tests/gui` in text files with the `.goml` extension. The books that the tests use are located in the `tests/gui/books` directory. These tests are run using a `node.js` framework called `browser-ui-test`. You can find documentation for this language on its [repository](https://github.com/GuillaumeGomez/browser-UI-test/blob/master/goml-script.md).
### Checking changes in `.js` files
The `.js` files source code is checked using [`eslint`](https://eslint.org/). This is a linter (just like `clippy` in Rust)
for the Javascript language. You can install it with `npm` by running the following command:
```
npm install
```
Then you can run it using:
```
npm run lint
```
## Updating highlight.js
The following are instructions for updating [highlight.js](https://highlightjs.org/).
1. Clone the repository at <https://github.com/highlightjs/highlight.js>
1. Check out a tagged release (like `10.1.1`).
1. Run `npm install`
1. Run `node tools/build.js :common apache armasm coffeescript d handlebars haskell http julia nginx nim nix properties r scala x86asm yaml`
1. Compare the language list that it spits out to the one in [`syntax-highlighting.md`](https://github.com/camelid/mdBook/blob/master/guide/src/format/theme/syntax-highlighting.md). If any are missing, add them to the list and rebuild (and update these docs). If any are added to the common set, add them to `syntax-highlighting.md`.
1. Copy `build/highlight.min.js` to mdbook's directory [`highlight.js`](https://github.com/rust-lang/mdBook/blob/master/src/theme/highlight.js).
1. Be sure to check the highlight.js [CHANGES](https://github.com/highlightjs/highlight.js/blob/main/CHANGES.md) for any breaking changes. Breaking changes that would affect users will need to wait until the next major release.
1. Build mdbook with the new file and build some books with the new version and compare the output with a variety of languages to see if anything changes. The [syntax GUI test](https://github.com/rust-lang/mdBook/tree/master/tests/gui/books/highlighting) contains a chapter with many languages to examine. Update the test (`highlighting.goml`) to add any new languages.
## Publishing new releases
Instructions for mdBook maintainers to publish a new release:
1. Create a PR that bumps the version and updates the changelog:
1. `git fetch upstream`
2. `git checkout -B bump-version upstream/master && git branch --set-upstream-to=origin/bump-version`
3. `cargo xtask bump <BUMP>`
- This will update the version of all the crates.
- `cargo set-version` must first be installed with `cargo install cargo-edit`.
- Replace `<BUMP>` with the kind of bump (patch, alpha, etc.)
4. `cargo xtask changelog`
- This will update `CHANGELOG.md` to add a list of all changes at the top. You will need to move those into the appropriate categories. Most changes that are generally not relevant to a user should be removed. Rewrite the descriptions so that a user can reasonably figure out what it means.
5. `git add --update .`
6. `git commit`
7. `git push`
2. After the PR has been merged, create a release in GitHub. This can either be done in the GitHub web UI, or on the command-line:
```bash
MDBOOK_VERS="`cargo read-manifest | jq -r .version`" ; \
gh release create -R rust-lang/mdbook v$MDBOOK_VERS \
--title v$MDBOOK_VERS \
--notes "See https://github.com/rust-lang/mdBook/blob/master/CHANGELOG.md#mdbook-${MDBOOK_VERS//.} for a complete list of changes."
```
================================================
FILE: Cargo.toml
================================================
[workspace]
members = [
".",
"crates/*",
"examples/remove-emphasis/mdbook-remove-emphasis", "guide/guide-helper",
]
[workspace.lints.clippy]
all = { level = "allow", priority = -2 }
correctness = { level = "warn", priority = -1 }
complexity = { level = "warn", priority = -1 }
exhaustive_enums = "warn"
exhaustive_structs = "warn"
manual_non_exhaustive = "warn"
[workspace.lints.rust]
missing_docs = "warn"
rust_2018_idioms = "warn"
unreachable_pub = "warn"
[workspace.package]
edition = "2024"
license = "MPL-2.0"
repository = "https://github.com/rust-lang/mdBook"
rust-version = "1.88.0" # Keep in sync with installation.md and .github/workflows/main.yml
[workspace.dependencies]
anyhow = "1.0.102"
axum = "0.8.8"
clap = { version = "4.5.60", features = ["cargo", "wrap_help"] }
clap_complete = "4.5.66"
ego-tree = "0.11.0"
elasticlunr-rs = "3.0.2"
font-awesome-as-a-crate = "0.3.0"
futures-util = "0.3.32"
glob = "0.3.3"
handlebars = "6.4.0"
hex = "0.4.3"
html5ever = "0.38.0"
indexmap = "2.13.0"
ignore = "0.4.25"
mdbook-core = { path = "crates/mdbook-core", version = "0.5.2" }
mdbook-driver = { path = "crates/mdbook-driver", version = "0.5.2" }
mdbook-html = { path = "crates/mdbook-html", version = "0.5.2" }
mdbook-markdown = { path = "crates/mdbook-markdown", version = "0.5.2" }
mdbook-preprocessor = { path = "crates/mdbook-preprocessor", version = "0.5.2" }
mdbook-renderer = { path = "crates/mdbook-renderer", version = "0.5.2" }
mdbook-summary = { path = "crates/mdbook-summary", version = "0.5.2" }
memchr = "2.8.0"
notify = "8.2.0"
notify-debouncer-mini = "0.7.0"
opener = "0.8.4"
pathdiff = "0.2.3"
pulldown-cmark = { version = "0.13.1", default-features = false, features = ["html"] } # Do not update, part of the public api.
regex = "1.12.3"
select = "0.6.1"
semver = "1.0.27"
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.149"
sha2 = "0.10.9"
shlex = "1.3.0"
snapbox = "1.0.0"
tempfile = "3.26.0"
tokio = "1.49.0"
toml = "1.0.3"
topological-sort = "0.2.2"
tower-http = "0.6.8"
tracing = "0.1.44"
tracing-subscriber = { version = "0.3.22", features = ["env-filter"] }
walkdir = "2.5.0"
[package]
name = "mdbook"
version = "0.5.2"
authors = [
"Mathieu David <mathieudavid@mathieudavid.org>",
"Michael-F-Bryan <michaelfbryan@gmail.com>",
"Matt Ickstadt <mattico8@gmail.com>"
]
documentation = "https://rust-lang.github.io/mdBook/index.html"
edition.workspace = true
exclude = ["/guide/*"]
keywords = ["book", "gitbook", "rustbook", "markdown"]
license.workspace = true
readme = "README.md"
repository.workspace = true
description = "Creates a book from markdown files"
rust-version.workspace = true
[dependencies]
anyhow.workspace = true
clap.workspace = true
clap_complete.workspace = true
mdbook-core.workspace = true
mdbook-driver.workspace = true
mdbook-html.workspace = true
opener.workspace = true
tracing.workspace = true
tracing-subscriber.workspace = true
# Watch feature
ignore = { workspace = true, optional = true }
notify = { workspace = true, optional = true }
notify-debouncer-mini = { workspace = true, optional = true }
pathdiff = { workspace = true, optional = true }
walkdir = { workspace = true, optional = true }
# Serve feature
axum = { workspace = true, features = ["ws"], optional = true }
futures-util = { workspace = true, optional = true }
tokio = { workspace = true, features = ["macros", "rt-multi-thread"], optional = true }
tower-http = { workspace = true, features = ["fs", "trace"], optional = true }
[dev-dependencies]
glob.workspace = true
mdbook-preprocessor.workspace = true
mdbook-renderer.workspace = true
regex.workspace = true
select.workspace = true
semver.workspace = true
serde_json.workspace = true
snapbox = { workspace = true, features = ["diff", "dir", "term-svg", "regex", "json"] }
tempfile.workspace = true
walkdir.workspace = true
[features]
default = ["watch", "serve", "search"]
watch = ["dep:notify", "dep:notify-debouncer-mini", "dep:ignore", "dep:pathdiff", "dep:walkdir"]
serve = ["dep:futures-util", "dep:tokio", "dep:axum", "dep:tower-http"]
search = ["mdbook-html/search"]
[[bin]]
doc = false
name = "mdbook"
[[example]]
name = "nop-preprocessor"
test = true
[[example]]
name = "remove-emphasis"
path = "examples/remove-emphasis/test.rs"
crate-type = ["lib"]
test = true
[[test]]
harness = false
test = false
name = "gui"
path = "tests/gui/runner.rs"
crate-type = ["bin"]
[lints]
workspace = true
================================================
FILE: LICENSE
================================================
Mozilla Public License, version 2.0
1. Definitions
1.1. "Contributor"
means each individual or legal entity that creates, contributes to the
creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used by a
Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached the
notice in Exhibit A, the Executable Form of such Source Code Form, and
Modifications of such Source Code Form, in each case including portions
thereof.
1.5. "Incompatible With Secondary Licenses"
means
a. that the initial Contributor has attached the notice described in
Exhibit B to the Covered Software; or
b. that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the terms of
a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in a
separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible, whether
at the time of the initial grant or subsequently, any and all of the
rights conveyed by this License.
1.10. "Modifications"
means any of the following:
a. any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered Software; or
b. any new file in Source Code Form that contains any Covered Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the License,
by the making, using, selling, offering for sale, having made, import,
or transfer of either its Contributions or its Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU Lesser
General Public License, Version 2.1, the GNU Affero General Public
License, Version 3.0, or any later versions of those licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that controls, is
controlled by, or is under common control with You. For purposes of this
definition, "control" means (a) the power, direct or indirect, to cause
the direction or management of such entity, whether by contract or
otherwise, or (b) ownership of more than fifty percent (50%) of the
outstanding shares or beneficial ownership of such entity.
2. License Grants and Conditions
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
a. under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
b. under Patent Claims of such Contributor to make, use, sell, offer for
sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
a. for any code that a Contributor has removed from Covered Software; or
b. for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
c. under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights to
grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
Section 2.1.
3. Responsibilities
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
a. such Covered Software must also be made available in Source Code Form,
as described in Section 3.1, and You must inform recipients of the
Executable Form how they can obtain a copy of such Source Code Form by
reasonable means in a timely manner, at a charge no more than the cost
of distribution to the recipient; and
b. You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter the
recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty, or
limitations of liability) contained within the Source Code Form of the
Covered Software, except that You may alter any license notices to the
extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
If it is impossible for You to comply with any of the terms of this License
with respect to some or all of the Covered Software due to statute,
judicial order, or regulation then You must: (a) comply with the terms of
this License to the maximum extent possible; and (b) describe the
limitations and the code they affect. Such description must be placed in a
text file included with all distributions of the Covered Software under
this License. Except to the extent prohibited by statute or regulation,
such description must be sufficiently detailed for a recipient of ordinary
skill to be able to understand it.
5. Termination
5.1. The rights granted under this License will terminate automatically if You
fail to comply with any of its terms. However, if You become compliant,
then the rights granted under this License from a particular Contributor
are reinstated (a) provisionally, unless and until such Contributor
explicitly and finally terminates Your grants, and (b) on an ongoing
basis, if such Contributor fails to notify You of the non-compliance by
some reasonable means prior to 60 days after You have come back into
compliance. Moreover, Your grants from a particular Contributor are
reinstated on an ongoing basis if such Contributor notifies You of the
non-compliance by some reasonable means, this is the first time You have
received notice of non-compliance with this License from such
Contributor, and You become compliant prior to 30 days after Your receipt
of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
license agreements (excluding distributors and resellers) which have been
validly granted by You or Your distributors under this License prior to
termination shall survive termination.
6. Disclaimer of Warranty
Covered Software is provided under this License on an "as is" basis,
without warranty of any kind, either expressed, implied, or statutory,
including, without limitation, warranties that the Covered Software is free
of defects, merchantable, fit for a particular purpose or non-infringing.
The entire risk as to the quality and performance of the Covered Software
is with You. Should any Covered Software prove defective in any respect,
You (not any Contributor) assume the cost of any necessary servicing,
repair, or correction. This disclaimer of warranty constitutes an essential
part of this License. No use of any Covered Software is authorized under
this License except under this disclaimer.
7. Limitation of Liability
Under no circumstances and under no legal theory, whether tort (including
negligence), contract, or otherwise, shall any Contributor, or anyone who
distributes Covered Software as permitted above, be liable to You for any
direct, indirect, special, incidental, or consequential damages of any
character including, without limitation, damages for lost profits, loss of
goodwill, work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses, even if such party shall have been
informed of the possibility of such damages. This limitation of liability
shall not apply to liability for death or personal injury resulting from
such party's negligence to the extent applicable law prohibits such
limitation. Some jurisdictions do not allow the exclusion or limitation of
incidental or consequential damages, so this exclusion and limitation may
not apply to You.
8. Litigation
Any litigation relating to this License may be brought only in the courts
of a jurisdiction where the defendant maintains its principal place of
business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions. Nothing
in this Section shall prevent a party's ability to bring cross-claims or
counter-claims.
9. Miscellaneous
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides that
the language of a contract shall be construed against the drafter shall not
be used to construe this License against a Contributor.
10. Versions of the License
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses If You choose to distribute Source Code Form that is
Incompatible With Secondary Licenses under the terms of this version of
the License, the notice described in Exhibit B of this License must be
attached.
Exhibit A - Source Code Form License Notice
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular file,
then You may include the notice in a location (such as a LICENSE file in a
relevant directory) where a recipient would be likely to look for such a
notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
This Source Code Form is "Incompatible
With Secondary Licenses", as defined by
the Mozilla Public License, v. 2.0.
================================================
FILE: README.md
================================================
# mdBook
[](https://github.com/rust-lang/mdBook/actions/workflows/main.yml)
[](https://crates.io/crates/mdbook)
[](LICENSE)
mdBook is a utility to create modern online books from Markdown files.
Check out the **[User Guide]** for a list of features and installation and usage information.
The User Guide also serves as a demonstration to showcase what a book looks like.
If you are interested in contributing to the development of mdBook, check out the [Contribution Guide].
## License
All the code in this repository is released under the ***Mozilla Public License v2.0***, for more information take a look at the [LICENSE] file.
[User Guide]: https://rust-lang.github.io/mdBook/
[contribution guide]: https://github.com/rust-lang/mdBook/blob/master/CONTRIBUTING.md
[LICENSE]: https://github.com/rust-lang/mdBook/blob/master/LICENSE
================================================
FILE: ci/install-rust.sh
================================================
#!/usr/bin/env bash
# Install/update rust.
# The first argument should be the toolchain to install.
set -ex
if [ -z "$1" ]
then
echo "First parameter must be toolchain to install."
exit 1
fi
TOOLCHAIN="$1"
rustup set profile minimal
rustup component remove --toolchain=$TOOLCHAIN rust-docs || echo "already removed"
rustup update --no-self-update $TOOLCHAIN
if [ -n "$2" ]
then
TARGET="$2"
HOST=$(rustc -Vv | grep ^host: | sed -e "s/host: //g")
if [ "$HOST" != "$TARGET" ]
then
rustup component add llvm-tools-preview --toolchain=$TOOLCHAIN
rustup component add rust-std-$TARGET --toolchain=$TOOLCHAIN
fi
if [[ $TARGET == *"musl" ]]
then
# This is needed by libdbus-sys.
sudo apt update -y && sudo apt install musl-dev musl-tools -y
fi
if [[ $TARGET == "aarch64-unknown-linux-musl" ]]
then
echo CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER=rust-lld >> $GITHUB_ENV
# This `CC` is some nonsense needed for libdbus-sys (via opener).
# I don't know if this is really the right thing to do, but it seems to work.
sudo apt install gcc-aarch64-linux-gnu -y
echo CC=aarch64-linux-gnu-gcc >> $GITHUB_ENV
fi
fi
rustup default $TOOLCHAIN
rustup -V
rustc -Vv
cargo -V
================================================
FILE: ci/make-release-asset.sh
================================================
#!/usr/bin/env bash
# Builds the release and creates an archive and optionally deploys to GitHub.
set -ex
if [[ -z "$GITHUB_REF" ]]
then
echo "GITHUB_REF must be set"
exit 1
fi
# Strip mdbook-refs/tags/ from the start of the ref.
TAG=${GITHUB_REF#*/tags/}
host=$(rustc -Vv | grep ^host: | sed -e "s/host: //g")
target=$2
export CARGO_PROFILE_RELEASE_LTO=true
cargo build --locked --bin mdbook --release --target $target
cd target/$target/release
case $1 in
ubuntu*)
asset="mdbook-$TAG-$target.tar.gz"
tar czf ../../$asset mdbook
;;
macos*)
asset="mdbook-$TAG-$target.tar.gz"
# There is a bug with BSD tar on macOS where the first 8MB of the file are
# sometimes all NUL bytes. See https://github.com/actions/cache/issues/403
# and https://github.com/rust-lang/cargo/issues/8603 for some more
# information. An alternative solution here is to install GNU tar, but
# flushing the disk cache seems to work, too.
sudo /usr/sbin/purge
tar czf ../../$asset mdbook
;;
windows*)
asset="mdbook-$TAG-$target.zip"
7z a ../../$asset mdbook.exe
;;
*)
echo "OS should be first parameter, was: $1"
;;
esac
cd ../..
if [[ -z "$GITHUB_ENV" ]]
then
echo "GITHUB_ENV not set, run: gh release upload $TAG target/$asset"
else
echo "MDBOOK_TAG=$TAG" >> $GITHUB_ENV
echo "MDBOOK_ASSET=target/$asset" >> $GITHUB_ENV
fi
================================================
FILE: ci/publish-guide.sh
================================================
#!/usr/bin/env bash
# This publishes the user guide to GitHub Pages.
#
# If this is a pre-release, then it goes in a separate directory called "pre-release".
# Commits are amended to avoid keeping history which can balloon the repo size.
set -ex
cargo run --no-default-features -F search -- build guide
VERSION=$(cargo metadata --format-version 1 --no-deps | jq '.packages[] | select(.name == "mdbook") | .version')
if [[ "$VERSION" == *-* ]]; then
PRERELEASE=true
else
PRERELEASE=false
fi
git fetch origin gh-pages
git worktree add gh-pages gh-pages
git config user.name "Deploy from CI"
git config user.email ""
cd gh-pages
if [[ "$PRERELEASE" == "true" ]]
then
rm -rf pre-release
mv ../guide/book pre-release
git add pre-release
git commit --amend -m "Deploy $GITHUB_SHA pre-release to gh-pages"
else
# Delete everything except pre-release and .git.
find . -mindepth 1 -maxdepth 1 -not -name "pre-release" -not -name ".git" -exec rm -rf {} +
# Copy the guide here.
find ../guide/book/ -mindepth 1 -maxdepth 1 -exec mv {} . \;
git add .
git commit --amend -m "Deploy $GITHUB_SHA to gh-pages"
fi
git push --force origin +gh-pages
================================================
FILE: ci/update-dependencies.sh
================================================
#!/usr/bin/env bash
# Updates all compatible Cargo dependencies.
#
# I wasn't able to get Renovate to update compatible dependencies in a way
# that I like, so this script takes care of it. This uses `cargo upgrade` to
# ensure that `Cargo.toml` also gets updated. This also makes sure that all
# transitive dependencies are updated.
set -ex
git fetch origin update-dependencies
if git checkout update-dependencies
then
git reset --hard origin/master
else
git checkout -b update-dependencies
fi
cat > commit-message << 'EOF'
Update cargo dependencies
```
EOF
cargo upgrade >> commit-message
echo '```' >> commit-message
if git diff --quiet
then
echo "No changes detected, exiting."
exit 0
fi
# Also update any transitive dependencies.
cargo update
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add Cargo.toml Cargo.lock
git commit -F commit-message
git push --force origin update-dependencies
gh pr create --fill \
--head update-dependencies \
--base master
================================================
FILE: crates/mdbook-compare/Cargo.toml
================================================
[package]
name = "mdbook-compare"
publish = false
edition.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true
[dependencies]
[lints]
workspace = true
================================================
FILE: crates/mdbook-compare/README.md
================================================
# mdbook-compare
This is a simple utility to compare the output of two different versions of mdbook.
To use this:
1. Install [`tidy`](https://www.html-tidy.org/).
2. Install or build the initial version of mdbook that you want to compare.
3. Install or build the new version of mdbook that you want to compare.
4. Run `mdbook-compare` with the arguments to the mdbook executables and the books to build.
```sh
cargo run --manifest-path /path/to/mdBook/Cargo.toml -p mdbook-compare -- \
/path/to/orig/mdbook /path/to/my-book /path/to/new/mdbook /path/to/my-book
```
It takes two separate paths for the book to use for "before" and "after" in case you need to customize the book to run on older versions. If you don't need that, then you can use the same directory for both the before and after.
`mdbook-compare` will do the following:
1. Clean up any book directories.
2. Build the book with the first mdbook.
3. Build the book with the second mdbook.
4. The output of those two commands are stored in directories called `compare1` and `compare2`.
5. The HTML in those directories is normalized using `tidy`.
6. Runs `git diff` to compare the output.
================================================
FILE: crates/mdbook-compare/src/main.rs
================================================
//! Utility to compare the output of two different versions of mdbook.
use std::path::Path;
use std::process::Command;
macro_rules! error {
($msg:literal $($arg:tt)*) => {
eprint!("error: ");
eprintln!($msg $($arg)*);
std::process::exit(1);
};
}
fn main() {
let mut args = std::env::args().skip(1);
let (Some(mdbook1), Some(book1), Some(mdbook2), Some(book2)) =
(args.next(), args.next(), args.next(), args.next())
else {
eprintln!("error: Expected four arguments: <exe1> <dir1> <exe2> <dir2>");
std::process::exit(1);
};
let mdbook1 = Path::new(&mdbook1);
let mdbook2 = Path::new(&mdbook2);
let book1 = Path::new(&book1);
let book2 = Path::new(&book2);
let compare1 = Path::new("compare1");
let compare2 = Path::new("compare2");
clean(compare1);
clean(compare2);
clean(&book1.join("book"));
clean(&book2.join("book"));
build(mdbook1, book1);
std::fs::rename(book1.join("book"), compare1).unwrap();
build(mdbook2, book2);
std::fs::rename(book2.join("book"), compare2).unwrap();
diff(compare1, compare2);
}
fn clean(path: &Path) {
if path.exists() {
println!("removing {path:?}");
std::fs::remove_dir_all(path).unwrap();
}
}
fn build(mdbook: &Path, book: &Path) {
println!("running `{mdbook:?} build` in `{book:?}`");
let status = Command::new(mdbook)
.arg("build")
.current_dir(book)
.status()
.unwrap_or_else(|e| {
error!("expected {mdbook:?} executable to exist: {e}");
});
if !status.success() {
error!("process {mdbook:?} failed");
}
process(&book.join("book"));
}
fn process(path: &Path) {
for entry in std::fs::read_dir(path).unwrap() {
let entry = entry.unwrap();
let path = entry.path();
if path.is_dir() {
process(&path);
} else {
if path.extension().is_some_and(|ext| ext == "html") {
tidy(&path);
process_html(&path);
} else {
std::fs::remove_file(path).unwrap();
}
}
}
}
fn process_html(path: &Path) {
let content = std::fs::read_to_string(path).unwrap();
let Some(start_index) = content.find("<main>") else {
return;
};
let end_index = content.rfind("</main>").unwrap();
let new_content = &content[start_index..end_index + 8];
std::fs::write(path, new_content).unwrap();
}
fn tidy(path: &Path) {
// quiet, no wrap, modify in place
let args = "-q -w 0 -m --custom-tags yes --drop-empty-elements no";
println!("running `tidy {args}` in `{path:?}`");
let status = Command::new("tidy")
.args(args.split(' '))
.arg(path)
.status()
.expect("tidy should be installed");
if !status.success() {
// Exit code 1 is a warning.
if status.code() != Some(1) {
error!("tidy failed: {status}");
}
}
}
fn diff(a: &Path, b: &Path) {
let args = "diff --no-index";
println!("running `git {args} {a:?} {b:?}`");
Command::new("git")
.args(args.split(' '))
.args([a, b])
.status()
.unwrap();
}
================================================
FILE: crates/mdbook-core/Cargo.toml
================================================
[package]
name = "mdbook-core"
version = "0.5.2"
description = "The base support library for mdbook, intended for internal use only"
edition.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true
[dependencies]
anyhow.workspace = true
regex.workspace = true
serde.workspace = true
serde_json.workspace = true
toml.workspace = true
tracing.workspace = true
[dev-dependencies]
tempfile.workspace = true
[lints]
workspace = true
================================================
FILE: crates/mdbook-core/README.md
================================================
# mdbook-core
[](https://docs.rs/mdbook-core)
[](https://crates.io/crates/mdbook-core)
[](https://github.com/rust-lang/mdBook/blob/master/CHANGELOG.md)
This is the base support library for [mdBook](https://rust-lang.github.io/mdBook/). It is intended for internal use only. Other mdBook crates depend on this for any types that are shared across the crates.
> This crate is maintained by the mdBook team, primarily for use by mdBook and not intended for external use (except as a transitive dependency). This crate may make major changes to its APIs or be deprecated without warning.
## License
[Mozilla Public License, version 2.0](https://github.com/rust-lang/mdBook/blob/master/LICENSE)
================================================
FILE: crates/mdbook-core/src/book/tests.rs
================================================
use super::*;
#[test]
fn section_number_has_correct_dotted_representation() {
let inputs = vec![
(vec![0], "0."),
(vec![1, 3], "1.3."),
(vec![1, 2, 3], "1.2.3."),
];
for (input, should_be) in inputs {
let section_number = SectionNumber(input).to_string();
assert_eq!(section_number, should_be);
}
}
#[test]
fn book_iter_iterates_over_sequential_items() {
let items = vec![
BookItem::Chapter(Chapter {
name: String::from("Chapter 1"),
content: String::from("# Chapter 1"),
..Default::default()
}),
BookItem::Separator,
];
let book = Book::new_with_items(items);
let should_be: Vec<_> = book.items.iter().collect();
let got: Vec<_> = book.iter().collect();
assert_eq!(got, should_be);
}
#[test]
fn for_each_mut_visits_all_items() {
let items = vec![
BookItem::Chapter(Chapter {
name: String::from("Chapter 1"),
content: String::from("# Chapter 1"),
number: None,
path: Some(PathBuf::from("Chapter_1/index.md")),
source_path: Some(PathBuf::from("Chapter_1/index.md")),
parent_names: Vec::new(),
sub_items: vec![
BookItem::Chapter(Chapter::new(
"Hello World",
String::new(),
"Chapter_1/hello.md",
Vec::new(),
)),
BookItem::Separator,
BookItem::Chapter(Chapter::new(
"Goodbye World",
String::new(),
"Chapter_1/goodbye.md",
Vec::new(),
)),
],
}),
BookItem::Separator,
];
let mut book = Book::new_with_items(items);
let num_items = book.iter().count();
let mut visited = 0;
book.for_each_mut(|_| visited += 1);
assert_eq!(visited, num_items);
}
#[test]
fn iterate_over_nested_book_items() {
let items = vec![
BookItem::Chapter(Chapter {
name: String::from("Chapter 1"),
content: String::from("# Chapter 1"),
number: None,
path: Some(PathBuf::from("Chapter_1/index.md")),
source_path: Some(PathBuf::from("Chapter_1/index.md")),
parent_names: Vec::new(),
sub_items: vec![
BookItem::Chapter(Chapter::new(
"Hello World",
String::new(),
"Chapter_1/hello.md",
Vec::new(),
)),
BookItem::Separator,
BookItem::Chapter(Chapter::new(
"Goodbye World",
String::new(),
"Chapter_1/goodbye.md",
Vec::new(),
)),
],
}),
BookItem::Separator,
];
let book = Book::new_with_items(items);
let got: Vec<_> = book.iter().collect();
assert_eq!(got.len(), 5);
// checking the chapter names are in the order should be sufficient here...
let chapter_names: Vec<String> = got
.into_iter()
.filter_map(|i| match *i {
BookItem::Chapter(ref ch) => Some(ch.name.clone()),
_ => None,
})
.collect();
let should_be: Vec<_> = vec![
String::from("Chapter 1"),
String::from("Hello World"),
String::from("Goodbye World"),
];
assert_eq!(chapter_names, should_be);
}
================================================
FILE: crates/mdbook-core/src/book.rs
================================================
//! A tree structure representing a book.
use serde::{Deserialize, Serialize};
use std::collections::VecDeque;
use std::fmt::{self, Display, Formatter};
use std::ops::{Deref, DerefMut};
use std::path::PathBuf;
#[cfg(test)]
mod tests;
/// A tree structure representing a book.
///
/// 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 item to mutate the chapters, using
/// [`for_each_mut()`].
///
/// [`iter()`]: #method.iter
/// [`for_each_mut()`]: #method.for_each_mut
#[allow(
clippy::exhaustive_structs,
reason = "This cannot be extended without breaking preprocessors."
)]
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct Book {
/// The items in this book.
pub items: Vec<BookItem>,
}
impl Book {
/// Create an empty book.
pub fn new() -> Self {
Default::default()
}
/// Creates a new book with the given items.
pub fn new_with_items(items: Vec<BookItem>) -> Book {
Book { items }
}
/// Get a depth-first iterator over the items in the book.
pub fn iter(&self) -> BookItems<'_> {
BookItems {
items: self.items.iter().collect(),
}
}
/// A depth-first iterator over each [`Chapter`], skipping draft chapters.
pub fn chapters(&self) -> impl Iterator<Item = &Chapter> {
self.iter().filter_map(|item| match item {
BookItem::Chapter(ch) if !ch.is_draft_chapter() => Some(ch),
_ => None,
})
}
/// Recursively apply a closure to each item in the book, allowing you to
/// mutate them.
///
/// # Note
///
/// Unlike the `iter()` method, this requires a closure instead of returning
/// an iterator. This is because using iterators can possibly allow you
/// to have iterator invalidation errors.
pub fn for_each_mut<F>(&mut self, mut func: F)
where
F: FnMut(&mut BookItem),
{
for_each_mut(&mut func, &mut self.items);
}
/// Recursively apply a closure to each non-draft chapter in the book,
/// allowing you to mutate them.
pub fn for_each_chapter_mut<F>(&mut self, mut func: F)
where
F: FnMut(&mut Chapter),
{
for_each_mut(
&mut |item| {
let BookItem::Chapter(ch) = item else {
return;
};
if ch.is_draft_chapter() {
return;
}
func(ch)
},
&mut self.items,
);
}
/// Append a `BookItem` to the `Book`.
pub fn push_item<I: Into<BookItem>>(&mut self, item: I) -> &mut Self {
self.items.push(item.into());
self
}
}
fn for_each_mut<'a, F, I>(func: &mut F, items: I)
where
F: FnMut(&mut BookItem),
I: IntoIterator<Item = &'a mut BookItem>,
{
for item in items {
if let BookItem::Chapter(ch) = item {
for_each_mut(func, &mut ch.sub_items);
}
func(item);
}
}
/// Enum representing any type of item which can be added to a book.
#[allow(
clippy::exhaustive_enums,
reason = "This cannot be extended without breaking preprocessors."
)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum BookItem {
/// A nested chapter.
Chapter(Chapter),
/// A section separator.
Separator,
/// A part title.
PartTitle(String),
}
impl From<Chapter> for BookItem {
fn from(other: Chapter) -> BookItem {
BookItem::Chapter(other)
}
}
/// The representation of a "chapter", usually mapping to a single file on
/// disk however it may contain multiple sub-chapters.
#[allow(
clippy::exhaustive_structs,
reason = "This cannot be extended without breaking preprocessors."
)]
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct Chapter {
/// The chapter's name.
pub name: String,
/// The chapter's contents.
pub content: String,
/// The chapter's section number, if it has one.
pub number: Option<SectionNumber>,
/// Nested items.
pub sub_items: Vec<BookItem>,
/// The chapter's location, relative to the `SUMMARY.md` file.
///
/// **Note**: After the index preprocessor runs, any README files will be
/// modified to be `index.md`. If you need access to the actual filename
/// on disk, use [`Chapter::source_path`] instead.
///
/// This is `None` for a draft chapter.
pub path: Option<PathBuf>,
/// The chapter's source file, relative to the `SUMMARY.md` file.
///
/// **Note**: Beware that README files will internally be treated as
/// `index.md` via the [`Chapter::path`] field. The `source_path` field
/// exists if you need access to the true file path.
///
/// This is `None` for a draft chapter, or a synthetically generated
/// chapter that has no file on disk.
pub source_path: Option<PathBuf>,
/// An ordered list of the names of each chapter above this one in the hierarchy.
pub parent_names: Vec<String>,
}
impl Chapter {
/// Create a new chapter with the provided content.
pub fn new<P: Into<PathBuf>>(
name: &str,
content: String,
p: P,
parent_names: Vec<String>,
) -> Chapter {
let path: PathBuf = p.into();
Chapter {
name: name.to_string(),
content,
path: Some(path.clone()),
source_path: Some(path),
parent_names,
..Default::default()
}
}
/// Create a new draft chapter that is not attached to a source markdown file (and thus
/// has no content).
pub fn new_draft(name: &str, parent_names: Vec<String>) -> Self {
Chapter {
name: name.to_string(),
content: String::new(),
path: None,
source_path: None,
parent_names,
..Default::default()
}
}
/// 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 {
self.path.is_none()
}
}
impl Display for Chapter {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if let Some(ref section_number) = self.number {
write!(f, "{section_number} ")?;
}
write!(f, "{}", self.name)
}
}
/// A section number like "1.2.3", basically just a newtype'd `Vec<u32>` with
/// a pretty `Display` impl.
#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
pub struct SectionNumber(Vec<u32>);
impl SectionNumber {
/// Creates a new [`SectionNumber`].
pub fn new(numbers: impl Into<Vec<u32>>) -> SectionNumber {
SectionNumber(numbers.into())
}
}
impl Display for SectionNumber {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if self.0.is_empty() {
write!(f, "0")
} else {
for item in &self.0 {
write!(f, "{item}.")?;
}
Ok(())
}
}
}
impl Deref for SectionNumber {
type Target = Vec<u32>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for SectionNumber {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl FromIterator<u32> for SectionNumber {
fn from_iter<I: IntoIterator<Item = u32>>(it: I) -> Self {
SectionNumber(it.into_iter().collect())
}
}
/// A depth-first iterator over the items in a book.
///
/// # Note
///
/// This struct shouldn't be created directly, instead prefer the
/// [`Book::iter()`] method.
pub struct BookItems<'a> {
items: VecDeque<&'a BookItem>,
}
impl<'a> Iterator for BookItems<'a> {
type Item = &'a BookItem;
fn next(&mut self) -> Option<Self::Item> {
let item = self.items.pop_front();
if let Some(BookItem::Chapter(ch)) = item {
// if we wanted a breadth-first iterator we'd `extend()` here
for sub_item in ch.sub_items.iter().rev() {
self.items.push_front(sub_item);
}
}
item
}
}
================================================
FILE: crates/mdbook-core/src/config.rs
================================================
//! Mdbook's configuration system.
//!
//! 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
//! for arbitrary data which is exposed to plugins and alternative backends.
//!
//!
//! # Examples
//!
//! ```rust
//! # use anyhow::Result;
//! use std::path::PathBuf;
//! use std::str::FromStr;
//! use mdbook_core::config::Config;
//!
//! # fn run() -> Result<()> {
//! let src = r#"
//! [book]
//! title = "My Book"
//! authors = ["Michael-F-Bryan"]
//!
//! [preprocessor.my-preprocessor]
//! bar = 123
//! "#;
//!
//! // load the `Config` from a toml string
//! let mut cfg = Config::from_str(src)?;
//!
//! // retrieve a nested value
//! let bar = cfg.get::<i32>("preprocessor.my-preprocessor.bar")?;
//! assert_eq!(bar, Some(123));
//!
//! // Set the `output.html.theme` directory
//! assert!(cfg.get::<toml::Value>("output.html")?.is_none());
//! cfg.set("output.html.theme", "./themes");
//!
//! // then load it again, automatically deserializing to a `PathBuf`.
//! let got = cfg.get("output.html.theme")?;
//! assert_eq!(got, Some(PathBuf::from("./themes")));
//! # Ok(())
//! # }
//! # run().unwrap()
//! ```
use crate::static_regex;
use crate::utils::{TomlExt, fs, log_backtrace};
use anyhow::{Context, Error, Result, bail};
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap};
use std::env;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use toml::Value;
use toml::value::Table;
use tracing::{debug, trace};
/// The overall configuration object for MDBook, essentially an in-memory
/// representation of `book.toml`.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(default, deny_unknown_fields)]
#[non_exhaustive]
pub struct Config {
/// Metadata about the book.
pub book: BookConfig,
/// Information about the build environment.
#[serde(skip_serializing_if = "is_default")]
pub build: BuildConfig,
/// Information about Rust language support.
#[serde(skip_serializing_if = "is_default")]
pub rust: RustConfig,
/// The renderer configurations.
#[serde(skip_serializing_if = "toml_is_empty")]
output: Value,
/// The preprocessor configurations.
#[serde(skip_serializing_if = "toml_is_empty")]
preprocessor: Value,
}
/// Helper for serde serialization.
fn is_default<T: Default + PartialEq>(t: &T) -> bool {
t == &T::default()
}
/// Helper for serde serialization.
fn toml_is_empty(table: &Value) -> bool {
table.as_table().unwrap().is_empty()
}
impl FromStr for Config {
type Err = Error;
/// Load a `Config` from some string.
fn from_str(src: &str) -> Result<Self> {
toml::from_str(src).with_context(|| "Invalid configuration file")
}
}
impl Default for Config {
fn default() -> Config {
Config {
book: BookConfig::default(),
build: BuildConfig::default(),
rust: RustConfig::default(),
output: Value::Table(Table::default()),
preprocessor: Value::Table(Table::default()),
}
}
}
impl Config {
/// Load the configuration file from disk.
pub fn from_disk<P: AsRef<Path>>(config_file: P) -> Result<Config> {
let cfg = fs::read_to_string(config_file)?;
Config::from_str(&cfg)
}
/// Updates the `Config` from the available environment variables.
///
/// 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_book` -> `book`
/// - `MDBOOK_BOOK` -> `book`
/// - `MDBOOK_BOOK__TITLE` -> `book.title`
/// - `MDBOOK_BOOK__TEXT_DIRECTION` -> `book.text-direction`
///
/// 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
/// >
/// > ```text
/// > $ 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.
pub fn update_from_env(&mut self) -> Result<()> {
debug!("Updating the config from environment variables");
static_regex!(
VALID_KEY,
r"^(:?book|build|rust|output|preprocessor)(:?$|\.)"
);
let overrides =
env::vars().filter_map(|(key, value)| parse_env(&key).map(|index| (index, value)));
for (key, value) in overrides {
trace!("{} => {}", key, value);
if !VALID_KEY.is_match(&key) {
// Ignore environment variables for other top-level things.
// This allows users to set things like `MDBOOK_VERSION` or
// `MDBOOK_DOWNLOAD_URL` for their own scripts and not
// interfere with how the config is loaded.
continue;
}
let parsed_value = serde_json::from_str(&value)
.unwrap_or_else(|_| serde_json::Value::String(value.to_string()));
self.set(key, parsed_value)?;
}
Ok(())
}
/// Get a value from the configuration.
///
/// This fetches a value from the book configuration. The key can have
/// dotted indices to access nested items (e.g. `output.html.playground`
/// will fetch the "playground" out of the html output table).
///
/// This can only access the `output` and `preprocessor` tables.
///
/// Returns `Ok(None)` if the field is not set.
///
/// Returns `Err` if it fails to deserialize.
pub fn get<'de, T: Deserialize<'de>>(&self, name: &str) -> Result<Option<T>> {
let (key, table) = if let Some(key) = name.strip_prefix("output.") {
(key, &self.output)
} else if let Some(key) = name.strip_prefix("preprocessor.") {
(key, &self.preprocessor)
} else {
bail!(
"unable to get `{name}`, only `output` and `preprocessor` table entries are allowed"
);
};
table
.read(key)
.map(|value| {
value
.clone()
.try_into()
.with_context(|| format!("Failed to deserialize `{name}`"))
})
.transpose()
}
/// Returns whether the config contains the given dotted key name.
///
/// The key can have dotted indices to access nested items (e.g.
/// `preprocessor.foo.bar` will check if that key is set in the config).
///
/// This can only access the `output` and `preprocessor` tables.
pub fn contains_key(&self, name: &str) -> bool {
if let Some(key) = name.strip_prefix("output.") {
self.output.read(key)
} else if let Some(key) = name.strip_prefix("preprocessor.") {
self.preprocessor.read(key)
} else {
panic!("invalid key `{name}`");
}
.is_some()
}
/// Returns the configuration for all preprocessors.
pub fn preprocessors<'de, T: Deserialize<'de>>(&self) -> Result<BTreeMap<String, T>> {
self.preprocessor
.clone()
.try_into()
.with_context(|| "Failed to read preprocessors")
}
/// Returns the configuration for all renderers.
pub fn outputs<'de, T: Deserialize<'de>>(&self) -> Result<BTreeMap<String, T>> {
self.output
.clone()
.try_into()
.with_context(|| "Failed to read renderers")
}
/// Convenience method for getting the html renderer's configuration.
///
/// # Note
///
/// This is for compatibility only. It will be removed completely once the
/// HTML renderer is refactored to be less coupled to `mdbook` internals.
#[doc(hidden)]
pub fn html_config(&self) -> Option<HtmlConfig> {
match self.get("output.html") {
Ok(Some(config)) => Some(config),
Ok(None) => None,
Err(e) => {
log_backtrace(&e);
None
}
}
}
/// Set a config key, clobbering any existing values along the way.
///
/// The key can have dotted indices for nested items (e.g.
/// `output.html.playground` will set the "playground" in the html output
/// table).
///
/// # Errors
///
/// This will fail if:
///
/// - The value cannot be represented as TOML.
/// - The value is not a correct type.
/// - The key is an unknown configuration option.
pub fn set<S: Serialize, I: AsRef<str>>(&mut self, index: I, value: S) -> Result<()> {
let index = index.as_ref();
let value = Value::try_from(value)
.with_context(|| "Unable to represent the item as a JSON Value")?;
if index == "book" {
self.book = value.try_into()?;
} else if index == "build" {
self.build = value.try_into()?;
} else if index == "rust" {
self.rust = value.try_into()?;
} else if index == "output" {
self.output = value;
} else if index == "preprocessor" {
self.preprocessor = value;
} else if let Some(key) = index.strip_prefix("book.") {
self.book.update_value(key, value)?;
} else if let Some(key) = index.strip_prefix("build.") {
self.build.update_value(key, value)?;
} else if let Some(key) = index.strip_prefix("rust.") {
self.rust.update_value(key, value)?;
} else if let Some(key) = index.strip_prefix("output.") {
self.output.update_value(key, value)?;
} else if let Some(key) = index.strip_prefix("preprocessor.") {
self.preprocessor.update_value(key, value)?;
} else {
bail!("invalid key `{index}`");
}
Ok(())
}
}
fn parse_env(key: &str) -> Option<String> {
key.strip_prefix("MDBOOK_")
.map(|key| key.to_lowercase().replace("__", ".").replace('_', "-"))
}
/// Configuration options which are specific to the book and required for
/// loading it from disk.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
#[non_exhaustive]
pub struct BookConfig {
/// The book's title.
pub title: Option<String>,
/// The book's authors.
pub authors: Vec<String>,
/// An optional description for the book.
pub description: Option<String>,
/// Location of the book source relative to the book's root directory.
#[serde(skip_serializing_if = "is_default_src")]
pub src: PathBuf,
/// The main language of the book.
pub language: Option<String>,
/// The direction of text in the book: Left-to-right (LTR) or Right-to-left (RTL).
/// When not specified, the text direction is derived from [`BookConfig::language`].
pub text_direction: Option<TextDirection>,
}
/// Helper for serde serialization.
fn is_default_src(src: &PathBuf) -> bool {
src == Path::new("src")
}
impl Default for BookConfig {
fn default() -> BookConfig {
BookConfig {
title: None,
authors: Vec::new(),
description: None,
src: PathBuf::from("src"),
language: Some(String::from("en")),
text_direction: None,
}
}
}
impl BookConfig {
/// Gets the realized text direction, either from [`BookConfig::text_direction`]
/// or derived from [`BookConfig::language`], to be used by templating engines.
pub fn realized_text_direction(&self) -> TextDirection {
if let Some(direction) = self.text_direction {
direction
} else {
TextDirection::from_lang_code(self.language.as_deref().unwrap_or_default())
}
}
}
/// Text direction to use for HTML output
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum TextDirection {
/// Left to right.
#[serde(rename = "ltr")]
LeftToRight,
/// Right to left
#[serde(rename = "rtl")]
RightToLeft,
}
impl TextDirection {
/// Gets the text direction from language code
pub fn from_lang_code(code: &str) -> Self {
match code {
// list sourced from here: https://github.com/abarrak/rtl/blob/master/lib/rtl/core.rb#L16
"ar" | "ara" | "arc" | "ae" | "ave" | "egy" | "he" | "heb" | "nqo" | "pal" | "phn"
| "sam" | "syc" | "syr" | "fa" | "per" | "fas" | "ku" | "kur" | "ur" | "urd"
| "pus" | "ps" | "yi" | "yid" => TextDirection::RightToLeft,
_ => TextDirection::LeftToRight,
}
}
}
/// Configuration for the build procedure.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
#[non_exhaustive]
pub struct BuildConfig {
/// Where to put built artifacts relative to the book's root directory.
pub build_dir: PathBuf,
/// Should non-existent markdown files specified in `SUMMARY.md` be created
/// if they don't exist?
pub create_missing: bool,
/// Should the default preprocessors always be used when they are
/// compatible with the renderer?
pub use_default_preprocessors: bool,
/// Extra directories to trigger rebuild when watching/serving
pub extra_watch_dirs: Vec<PathBuf>,
}
impl Default for BuildConfig {
fn default() -> BuildConfig {
BuildConfig {
build_dir: PathBuf::from("book"),
create_missing: true,
use_default_preprocessors: true,
extra_watch_dirs: Vec::new(),
}
}
}
/// Configuration for the Rust compiler(e.g., for playground)
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
#[non_exhaustive]
pub struct RustConfig {
/// Rust edition used in playground
pub edition: Option<RustEdition>,
}
/// Rust edition to use for the code.
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum RustEdition {
/// The 2024 edition of Rust
#[serde(rename = "2024")]
E2024,
/// The 2021 edition of Rust
#[serde(rename = "2021")]
E2021,
/// The 2018 edition of Rust
#[serde(rename = "2018")]
E2018,
/// The 2015 edition of Rust
#[serde(rename = "2015")]
E2015,
}
/// Configuration for the HTML renderer.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
#[non_exhaustive]
pub struct HtmlConfig {
/// The theme directory, if specified.
pub theme: Option<PathBuf>,
/// The default theme to use, defaults to 'light'
pub default_theme: Option<String>,
/// The theme to use if the browser requests the dark version of the site.
/// Defaults to 'navy'.
pub preferred_dark_theme: Option<String>,
/// Supports smart quotes, apostrophes, ellipsis, en-dash, and em-dash.
pub smart_punctuation: bool,
/// Support for definition lists.
pub definition_lists: bool,
/// Support for admonitions.
pub admonitions: bool,
/// Should mathjax be enabled?
pub mathjax_support: bool,
/// Additional CSS stylesheets to include in the rendered page's `<head>`.
pub additional_css: Vec<PathBuf>,
/// Additional JS scripts to include at the bottom of the rendered page's
/// `<body>`.
pub additional_js: Vec<PathBuf>,
/// Fold settings.
pub fold: Fold,
/// Playground settings.
#[serde(alias = "playpen")]
pub playground: Playground,
/// Code settings.
pub code: Code,
/// Print settings.
pub print: Print,
/// Don't render section labels.
pub no_section_label: bool,
/// Search settings. If `None`, the default will be used.
pub search: Option<Search>,
/// Git repository url. If `None`, the git button will not be shown.
pub git_repository_url: Option<String>,
/// FontAwesome icon class to use for the Git repository link.
/// Defaults to `fa-github` if `None`.
pub git_repository_icon: Option<String>,
/// Input path for the 404 file, defaults to 404.md, set to "" to disable 404 file output
pub input_404: Option<String>,
/// Absolute url to site, used to emit correct paths for the 404 page, which might be accessed in a deeply nested directory
pub site_url: Option<String>,
/// 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 site*][custom domain]).
///
/// [custom domain]: https://docs.github.com/en/github/working-with-github-pages/managing-a-custom-domain-for-your-github-pages-site
pub cname: Option<String>,
/// Edit url template, when set shows a "Suggest an edit" button for
/// directly jumping to editing the currently viewed page.
/// Contains {path} that is replaced with chapter source file path
pub edit_url_template: Option<String>,
/// Endpoint of websocket, for livereload usage. Value loaded from .toml
/// file is ignored, because our code overrides this field with an
/// internal value (`LIVE_RELOAD_ENDPOINT)
///
/// This config item *should not be edited* by the end user.
#[doc(hidden)]
pub live_reload_endpoint: Option<String>,
/// The mapping from old pages to new pages/URLs to use when generating
/// redirects.
pub redirect: HashMap<String, String>,
/// If this option is turned on, "cache bust" static files by adding
/// hashes to their file names.
///
/// The default is `true`.
pub hash_files: bool,
/// If enabled, the sidebar includes navigation for headers on the current
/// page. Default is `true`.
pub sidebar_header_nav: bool,
}
impl Default for HtmlConfig {
fn default() -> HtmlConfig {
HtmlConfig {
theme: None,
default_theme: None,
preferred_dark_theme: None,
smart_punctuation: true,
definition_lists: true,
admonitions: true,
mathjax_support: false,
additional_css: Vec::new(),
additional_js: Vec::new(),
fold: Fold::default(),
playground: Playground::default(),
code: Code::default(),
print: Print::default(),
no_section_label: false,
search: None,
git_repository_url: None,
git_repository_icon: None,
input_404: None,
site_url: None,
cname: None,
edit_url_template: None,
live_reload_endpoint: None,
redirect: HashMap::new(),
hash_files: true,
sidebar_header_nav: true,
}
}
}
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: &Path) -> PathBuf {
match self.theme {
Some(ref d) => root.join(d),
None => root.join("theme"),
}
}
/// Returns the name of the file used for HTTP 404 "not found" with the `.html` extension.
pub fn get_404_output_file(&self) -> String {
self.input_404
.as_ref()
.unwrap_or(&"404.md".to_string())
.replace(".md", ".html")
}
}
/// Configuration for how to render the print icon, print.html, and print.css.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
#[non_exhaustive]
pub struct Print {
/// Whether print support is enabled.
pub enable: bool,
/// Insert page breaks between chapters. Default: `true`.
pub page_break: bool,
}
impl Default for Print {
fn default() -> Self {
Self {
enable: true,
page_break: true,
}
}
}
/// Configuration for how to fold chapters of sidebar.
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
#[non_exhaustive]
pub struct Fold {
/// When off, all folds are open. Default: `false`.
pub enable: bool,
/// The higher the more folded regions are open. When level is 0, all folds
/// are closed.
/// Default: `0`.
pub level: u8,
}
/// Configuration for tweaking how the HTML renderer handles the playground.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
#[non_exhaustive]
pub struct Playground {
/// Should playground snippets be editable? Default: `false`.
pub editable: bool,
/// Display the copy button. Default: `true`.
pub copyable: bool,
/// Copy JavaScript files for the editor to the output directory?
/// Default: `true`.
pub copy_js: bool,
/// Display line numbers on playground snippets. Default: `false`.
pub line_numbers: bool,
/// Display the run button. Default: `true`
pub runnable: bool,
}
impl Default for Playground {
fn default() -> Playground {
Playground {
editable: false,
copyable: true,
copy_js: true,
line_numbers: false,
runnable: true,
}
}
}
/// Configuration for tweaking how the HTML renderer handles code blocks.
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
#[non_exhaustive]
pub struct Code {
/// A prefix string to hide lines per language (one or more chars).
pub hidelines: HashMap<String, String>,
}
/// Configuration of the search functionality of the HTML renderer.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
#[non_exhaustive]
pub struct Search {
/// Enable the search feature. Default: `true`.
pub enable: bool,
/// Maximum number of visible results. Default: `30`.
pub limit_results: u32,
/// The number of words used for a search result teaser. Default: `30`.
pub teaser_word_count: u32,
/// Define the logical link between multiple search words.
/// If true, all search words must appear in each result. Default: `false`.
pub use_boolean_and: bool,
/// Boost factor for the search result score if a search word appears in the header.
/// Default: `2`.
pub boost_title: u8,
/// Boost factor for the search result score if a search word appears in the hierarchy.
/// The hierarchy contains all titles of the parent documents and all parent headings.
/// Default: `1`.
pub boost_hierarchy: u8,
/// Boost factor for the search result score if a search word appears in the text.
/// Default: `1`.
pub boost_paragraph: u8,
/// True if the searchword `micro` should match `microwave`. Default: `true`.
pub expand: bool,
/// 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?
/// Default: `true`.
pub copy_js: bool,
/// Specifies search settings for the given path.
///
/// The path can be for a specific chapter, or a directory. This will
/// merge recursively, with more specific paths taking precedence.
pub chapter: HashMap<String, SearchChapterSettings>,
}
impl Default for Search {
fn default() -> Search {
// Please update the documentation of `Search` when changing values!
Search {
enable: true,
limit_results: 30,
teaser_word_count: 30,
use_boolean_and: false,
boost_title: 2,
boost_hierarchy: 1,
boost_paragraph: 1,
expand: true,
heading_split_level: 3,
copy_js: true,
chapter: HashMap::new(),
}
}
}
/// Search options for chapters (or paths).
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
#[non_exhaustive]
pub struct SearchChapterSettings {
/// Whether or not indexing is enabled, default `true`.
pub enable: Option<bool>,
}
/// Allows you to "update" any arbitrary field in a struct by round-tripping via
/// a `toml::Value`.
///
/// This is definitely not the most performant way to do things, which means you
/// should probably keep it away from tight loops...
trait Updateable<'de>: Serialize + Deserialize<'de> {
fn update_value<S: Serialize>(&mut self, key: &str, value: S) -> Result<()> {
let mut raw = Value::try_from(&self).expect("unreachable");
let value = Value::try_from(value)?;
raw.insert(key, value);
let updated = raw.try_into()?;
*self = updated;
Ok(())
}
}
impl<'de, T> Updateable<'de> for T where T: Serialize + Deserialize<'de> {}
#[cfg(test)]
mod tests {
use super::*;
const COMPLEX_CONFIG: &str = r#"
[book]
title = "Some Book"
authors = ["Michael-F-Bryan <michaelfbryan@gmail.com>"]
description = "A completely useless book"
src = "source"
language = "ja"
[build]
build-dir = "outputs"
create-missing = false
use-default-preprocessors = true
[output.html]
theme = "./themedir"
default-theme = "rust"
smart-punctuation = true
additional-css = ["./foo/bar/baz.css"]
git-repository-url = "https://foo.com/"
git-repository-icon = "fa-code-fork"
[output.html.playground]
editable = true
[output.html.redirect]
"index.html" = "overview.html"
"nexted/page.md" = "https://rust-lang.org/"
[preprocessor.first]
[preprocessor.second]
"#;
#[test]
fn load_a_complex_config_file() {
let src = COMPLEX_CONFIG;
let book_should_be = BookConfig {
title: Some(String::from("Some Book")),
authors: vec![String::from("Michael-F-Bryan <michaelfbryan@gmail.com>")],
description: Some(String::from("A completely useless book")),
src: PathBuf::from("source"),
language: Some(String::from("ja")),
text_direction: None,
};
let build_should_be = BuildConfig {
build_dir: PathBuf::from("outputs"),
create_missing: false,
use_default_preprocessors: true,
extra_watch_dirs: Vec::new(),
};
let rust_should_be = RustConfig { edition: None };
let playground_should_be = Playground {
editable: true,
copyable: true,
copy_js: true,
line_numbers: false,
runnable: true,
};
let html_should_be = HtmlConfig {
smart_punctuation: true,
additional_css: vec![PathBuf::from("./foo/bar/baz.css")],
theme: Some(PathBuf::from("./themedir")),
default_theme: Some(String::from("rust")),
playground: playground_should_be,
git_repository_url: Some(String::from("https://foo.com/")),
git_repository_icon: Some(String::from("fa-code-fork")),
redirect: vec![
(String::from("index.html"), String::from("overview.html")),
(
String::from("nexted/page.md"),
String::from("https://rust-lang.org/"),
),
]
.into_iter()
.collect(),
..Default::default()
};
let got = Config::from_str(src).unwrap();
assert_eq!(got.book, book_should_be);
assert_eq!(got.build, build_should_be);
assert_eq!(got.rust, rust_should_be);
assert_eq!(got.html_config().unwrap(), html_should_be);
}
#[test]
fn disable_runnable() {
let src = r#"
[book]
title = "Some Book"
description = "book book book"
authors = ["Shogo Takata"]
[output.html.playground]
runnable = false
"#;
let got = Config::from_str(src).unwrap();
assert!(!got.html_config().unwrap().playground.runnable);
}
#[test]
fn edition_2015() {
let src = r#"
[book]
title = "mdBook Documentation"
description = "Create book from markdown files. Like Gitbook but implemented in Rust"
authors = ["Mathieu David"]
src = "./source"
[rust]
edition = "2015"
"#;
let book_should_be = BookConfig {
title: Some(String::from("mdBook Documentation")),
description: Some(String::from(
"Create book from markdown files. Like Gitbook but implemented in Rust",
)),
authors: vec![String::from("Mathieu David")],
src: PathBuf::from("./source"),
..Default::default()
};
let got = Config::from_str(src).unwrap();
assert_eq!(got.book, book_should_be);
let rust_should_be = RustConfig {
edition: Some(RustEdition::E2015),
};
let got = Config::from_str(src).unwrap();
assert_eq!(got.rust, rust_should_be);
}
#[test]
fn edition_2018() {
let src = r#"
[book]
title = "mdBook Documentation"
description = "Create book from markdown files. Like Gitbook but implemented in Rust"
authors = ["Mathieu David"]
src = "./source"
[rust]
edition = "2018"
"#;
let rust_should_be = RustConfig {
edition: Some(RustEdition::E2018),
};
let got = Config::from_str(src).unwrap();
assert_eq!(got.rust, rust_should_be);
}
#[test]
fn edition_2021() {
let src = r#"
[book]
title = "mdBook Documentation"
description = "Create book from markdown files. Like Gitbook but implemented in Rust"
authors = ["Mathieu David"]
src = "./source"
[rust]
edition = "2021"
"#;
let rust_should_be = RustConfig {
edition: Some(RustEdition::E2021),
};
let got = Config::from_str(src).unwrap();
assert_eq!(got.rust, rust_should_be);
}
#[test]
fn load_arbitrary_output_type() {
#[derive(Debug, Deserialize, PartialEq)]
struct RandomOutput {
foo: u32,
bar: String,
baz: Vec<bool>,
}
let src = r#"
[output.random]
foo = 5
bar = "Hello World"
baz = [true, true, false]
"#;
let should_be = RandomOutput {
foo: 5,
bar: String::from("Hello World"),
baz: vec![true, true, false],
};
let cfg = Config::from_str(src).unwrap();
let got: RandomOutput = cfg.get("output.random").unwrap().unwrap();
assert_eq!(got, should_be);
let got_baz: Vec<bool> = cfg.get("output.random.baz").unwrap().unwrap();
let baz_should_be = vec![true, true, false];
assert_eq!(got_baz, baz_should_be);
}
#[test]
fn set_special_tables() {
let mut cfg = Config::default();
assert_eq!(cfg.book.title, None);
cfg.set("book.title", "my title").unwrap();
assert_eq!(cfg.book.title, Some("my title".to_string()));
assert_eq!(&cfg.build.build_dir, Path::new("book"));
cfg.set("build.build-dir", "some-directory").unwrap();
assert_eq!(&cfg.build.build_dir, Path::new("some-directory"));
assert_eq!(cfg.rust.edition, None);
cfg.set("rust.edition", "2024").unwrap();
assert_eq!(cfg.rust.edition, Some(RustEdition::E2024));
cfg.set("output.foo.value", "123").unwrap();
let got: String = cfg.get("output.foo.value").unwrap().unwrap();
assert_eq!(got, "123");
cfg.set("preprocessor.bar.value", "456").unwrap();
let got: String = cfg.get("preprocessor.bar.value").unwrap().unwrap();
assert_eq!(got, "456");
}
#[test]
fn set_invalid_keys() {
let mut cfg = Config::default();
let err = cfg.set("foo", "test").unwrap_err();
assert!(err.to_string().contains("invalid key `foo`"));
}
#[test]
fn parse_env_vars() {
let inputs = vec![
("FOO", None),
("MDBOOK_foo", Some("foo")),
("MDBOOK_FOO__bar__baz", Some("foo.bar.baz")),
("MDBOOK_FOO_bar__baz", Some("foo-bar.baz")),
];
for (src, should_be) in inputs {
let got = parse_env(src);
let should_be = should_be.map(ToString::to_string);
assert_eq!(got, should_be);
}
}
#[test]
fn file_404_default() {
let src = r#"
[output.html]
"#;
let got = Config::from_str(src).unwrap();
let html_config = got.html_config().unwrap();
assert_eq!(html_config.input_404, None);
assert_eq!(html_config.get_404_output_file(), "404.html");
}
#[test]
fn file_404_custom() {
let src = r#"
[output.html]
input-404= "missing.md"
"#;
let got = Config::from_str(src).unwrap();
let html_config = got.html_config().unwrap();
assert_eq!(html_config.input_404, Some("missing.md".to_string()));
assert_eq!(html_config.get_404_output_file(), "missing.html");
}
#[test]
fn text_direction_ltr() {
let src = r#"
[book]
text-direction = "ltr"
"#;
let got = Config::from_str(src).unwrap();
assert_eq!(got.book.text_direction, Some(TextDirection::LeftToRight));
}
#[test]
fn text_direction_rtl() {
let src = r#"
[book]
text-direction = "rtl"
"#;
let got = Config::from_str(src).unwrap();
assert_eq!(got.book.text_direction, Some(TextDirection::RightToLeft));
}
#[test]
fn text_direction_none() {
let src = r#"
[book]
"#;
let got = Config::from_str(src).unwrap();
assert_eq!(got.book.text_direction, None);
}
#[test]
fn test_text_direction() {
let mut cfg = BookConfig::default();
// test deriving the text direction from language codes
cfg.language = Some("ar".into());
assert_eq!(cfg.realized_text_direction(), TextDirection::RightToLeft);
cfg.language = Some("he".into());
assert_eq!(cfg.realized_text_direction(), TextDirection::RightToLeft);
cfg.language = Some("en".into());
assert_eq!(cfg.realized_text_direction(), TextDirection::LeftToRight);
cfg.language = Some("ja".into());
assert_eq!(cfg.realized_text_direction(), TextDirection::LeftToRight);
// test forced direction
cfg.language = Some("ar".into());
cfg.text_direction = Some(TextDirection::LeftToRight);
assert_eq!(cfg.realized_text_direction(), TextDirection::LeftToRight);
cfg.language = Some("ar".into());
cfg.text_direction = Some(TextDirection::RightToLeft);
assert_eq!(cfg.realized_text_direction(), TextDirection::RightToLeft);
cfg.language = Some("en".into());
cfg.text_direction = Some(TextDirection::LeftToRight);
assert_eq!(cfg.realized_text_direction(), TextDirection::LeftToRight);
cfg.language = Some("en".into());
cfg.text_direction = Some(TextDirection::RightToLeft);
assert_eq!(cfg.realized_text_direction(), TextDirection::RightToLeft);
}
#[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();
}
#[test]
#[should_panic(
expected = "unknown variant `1999`, expected one of `2024`, `2021`, `2018`, `2015`\n"
)]
fn invalid_rust_edition_expected() {
let src = r#"
[rust]
edition = "1999"
"#;
Config::from_str(src).unwrap();
}
#[test]
fn print_config() {
let src = r#"
[output.html.print]
enable = false
"#;
let got = Config::from_str(src).unwrap();
let html_config = got.html_config().unwrap();
assert!(!html_config.print.enable);
assert!(html_config.print.page_break);
let src = r#"
[output.html.print]
page-break = false
"#;
let got = Config::from_str(src).unwrap();
let html_config = got.html_config().unwrap();
assert!(html_config.print.enable);
assert!(!html_config.print.page_break);
}
#[test]
fn test_json_direction() {
use serde_json::json;
assert_eq!(json!(TextDirection::RightToLeft), json!("rtl"));
assert_eq!(json!(TextDirection::LeftToRight), json!("ltr"));
}
#[test]
fn get_deserialize_error() {
let src = r#"
[preprocessor.foo]
x = 123
"#;
let cfg = Config::from_str(src).unwrap();
let err = cfg.get::<String>("preprocessor.foo.x").unwrap_err();
assert_eq!(
err.to_string(),
"Failed to deserialize `preprocessor.foo.x`"
);
}
#[test]
fn contains_key() {
let src = r#"
[preprocessor.foo]
x = 123
[output.foo.sub]
y = 'x'
"#;
let cfg = Config::from_str(src).unwrap();
assert!(cfg.contains_key("preprocessor.foo"));
assert!(cfg.contains_key("preprocessor.foo.x"));
assert!(!cfg.contains_key("preprocessor.bar"));
assert!(!cfg.contains_key("preprocessor.foo.y"));
assert!(cfg.contains_key("output.foo"));
assert!(cfg.contains_key("output.foo.sub"));
assert!(cfg.contains_key("output.foo.sub.y"));
assert!(!cfg.contains_key("output.bar"));
assert!(!cfg.contains_key("output.foo.sub.z"));
}
}
================================================
FILE: crates/mdbook-core/src/lib.rs
================================================
//! The base support library for mdbook, intended for internal use only.
/// The current version of `mdbook`.
///
/// This is provided as a way for custom preprocessors and renderers to do
/// compatibility checks.
pub const MDBOOK_VERSION: &str = env!("CARGO_PKG_VERSION");
pub mod book;
pub mod config;
pub mod utils;
/// The error types used in mdbook.
pub mod errors {
pub use anyhow::{Error, Result};
}
================================================
FILE: crates/mdbook-core/src/utils/fs.rs
================================================
//! Filesystem utilities and helpers.
use anyhow::{Context, Result};
use std::fs;
use std::path::{Component, Path, PathBuf};
use tracing::debug;
/// Reads a file into a string.
///
/// Equivalent to [`std::fs::read_to_string`] with better error messages.
pub fn read_to_string<P: AsRef<Path>>(path: P) -> Result<String> {
let path = path.as_ref();
fs::read_to_string(path).with_context(|| format!("failed to read `{}`", path.display()))
}
/// Writes a file to disk.
///
/// Equivalent to [`std::fs::write`] with better error messages. This will
/// also create the parent directory if it doesn't exist.
pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> {
let path = path.as_ref();
debug!("Writing `{}`", path.display());
if let Some(parent) = path.parent() {
create_dir_all(parent)?;
}
fs::write(path, contents.as_ref())
.with_context(|| format!("failed to write `{}`", path.display()))
}
/// Equivalent to [`std::fs::create_dir_all`] with better error messages.
pub fn create_dir_all(p: impl AsRef<Path>) -> Result<()> {
let p = p.as_ref();
fs::create_dir_all(p)
.with_context(|| format!("failed to create directory `{}`", p.display()))?;
Ok(())
}
/// Takes a path and returns a path containing just enough `../` to point to
/// the root of the given path.
///
/// This is mostly interesting for a relative path to point back to the
/// directory from where the path starts.
///
/// ```rust
/// # use std::path::Path;
/// # use mdbook_core::utils::fs::path_to_root;
/// let path = Path::new("some/relative/path");
/// assert_eq!(path_to_root(path), "../../");
/// ```
///
/// **note:** it's not very fool-proof, if you find a situation where
/// it doesn't return the correct path.
/// Consider [submitting a new issue](https://github.com/rust-lang/mdBook/issues)
/// or a [pull-request](https://github.com/rust-lang/mdBook/pulls) to improve it.
pub fn path_to_root<P: Into<PathBuf>>(path: P) -> String {
// Remove filename and add "../" for every directory
path.into()
.parent()
.expect("")
.components()
.fold(String::new(), |mut s, c| {
match c {
Component::Normal(_) => s.push_str("../"),
_ => {
debug!("Other path component... {:?}", c);
}
}
s
})
}
/// Removes all the content of a directory but not the directory itself.
pub fn remove_dir_content(dir: &Path) -> Result<()> {
for item in fs::read_dir(dir)
.with_context(|| format!("failed to read directory `{}`", dir.display()))?
.flatten()
{
let item = item.path();
if item.is_dir() {
fs::remove_dir_all(&item)
.with_context(|| format!("failed to remove `{}`", item.display()))?;
gitextract_yv8ug7wf/ ├── .cargo/ │ └── config.toml ├── .git-blame-ignore-revs ├── .gitattributes ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.yml │ │ ├── feature_request.yml │ │ └── question.yml │ ├── renovate.json5 │ └── workflows/ │ ├── deploy.yml │ ├── main.yml │ └── update-dependencies.yml ├── .gitignore ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Cargo.toml ├── LICENSE ├── README.md ├── ci/ │ ├── install-rust.sh │ ├── make-release-asset.sh │ ├── publish-guide.sh │ └── update-dependencies.sh ├── crates/ │ ├── mdbook-compare/ │ │ ├── Cargo.toml │ │ ├── README.md │ │ └── src/ │ │ └── main.rs │ ├── mdbook-core/ │ │ ├── Cargo.toml │ │ ├── README.md │ │ └── src/ │ │ ├── book/ │ │ │ └── tests.rs │ │ ├── book.rs │ │ ├── config.rs │ │ ├── lib.rs │ │ └── utils/ │ │ ├── fs.rs │ │ ├── html.rs │ │ ├── mod.rs │ │ └── toml_ext.rs │ ├── mdbook-driver/ │ │ ├── Cargo.toml │ │ ├── README.md │ │ └── src/ │ │ ├── builtin_preprocessors/ │ │ │ ├── cmd.rs │ │ │ ├── index.rs │ │ │ ├── links/ │ │ │ │ └── take_lines.rs │ │ │ ├── links.rs │ │ │ └── mod.rs │ │ ├── builtin_renderers/ │ │ │ ├── markdown_renderer.rs │ │ │ └── mod.rs │ │ ├── init.rs │ │ ├── lib.rs │ │ ├── load.rs │ │ ├── mdbook/ │ │ │ └── tests.rs │ │ └── mdbook.rs │ ├── mdbook-html/ │ │ ├── Cargo.toml │ │ ├── README.md │ │ ├── front-end/ │ │ │ ├── css/ │ │ │ │ ├── ayu-highlight.css │ │ │ │ ├── chrome.css │ │ │ │ ├── general.css │ │ │ │ ├── highlight.css │ │ │ │ ├── print.css │ │ │ │ ├── tomorrow-night.css │ │ │ │ └── variables.css │ │ │ ├── fonts/ │ │ │ │ ├── OPEN-SANS-LICENSE.txt │ │ │ │ ├── SOURCE-CODE-PRO-LICENSE.txt │ │ │ │ └── fonts.css │ │ │ ├── js/ │ │ │ │ ├── book.js │ │ │ │ └── highlight.js │ │ │ ├── playground_editor/ │ │ │ │ ├── ace.js │ │ │ │ ├── editor.js │ │ │ │ ├── mode-rust.js │ │ │ │ ├── theme-dawn.js │ │ │ │ └── theme-tomorrow_night.js │ │ │ ├── searcher/ │ │ │ │ └── searcher.js │ │ │ └── templates/ │ │ │ ├── head.hbs │ │ │ ├── header.hbs │ │ │ ├── index.hbs │ │ │ ├── redirect.hbs │ │ │ ├── toc.html.hbs │ │ │ └── toc.js.hbs │ │ └── src/ │ │ ├── html/ │ │ │ ├── admonitions.rs │ │ │ ├── hide_lines.rs │ │ │ ├── mod.rs │ │ │ ├── print.rs │ │ │ ├── serialize.rs │ │ │ ├── tests.rs │ │ │ ├── tokenizer.rs │ │ │ └── tree.rs │ │ ├── html_handlebars/ │ │ │ ├── hbs_renderer.rs │ │ │ ├── helpers/ │ │ │ │ ├── fontawesome.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── resources.rs │ │ │ │ └── toc.rs │ │ │ ├── mod.rs │ │ │ ├── search.rs │ │ │ └── static_files.rs │ │ ├── lib.rs │ │ ├── theme/ │ │ │ ├── fonts.rs │ │ │ ├── mod.rs │ │ │ ├── playground_editor.rs │ │ │ └── searcher.rs │ │ └── utils.rs │ ├── mdbook-markdown/ │ │ ├── Cargo.toml │ │ ├── README.md │ │ └── src/ │ │ └── lib.rs │ ├── mdbook-preprocessor/ │ │ ├── Cargo.toml │ │ ├── README.md │ │ └── src/ │ │ └── lib.rs │ ├── mdbook-renderer/ │ │ ├── Cargo.toml │ │ ├── README.md │ │ └── src/ │ │ └── lib.rs │ ├── mdbook-summary/ │ │ ├── Cargo.toml │ │ ├── README.md │ │ └── src/ │ │ └── lib.rs │ └── xtask/ │ ├── Cargo.toml │ ├── README.md │ └── src/ │ ├── changelog.rs │ └── main.rs ├── eslint.config.mjs ├── examples/ │ ├── nop-preprocessor.rs │ └── remove-emphasis/ │ ├── .gitignore │ ├── book.toml │ ├── mdbook-remove-emphasis/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── main.rs │ ├── src/ │ │ ├── SUMMARY.md │ │ └── chapter_1.md │ └── test.rs ├── guide/ │ ├── book.toml │ ├── guide-helper/ │ │ ├── Cargo.toml │ │ └── src/ │ │ ├── lib.rs │ │ └── main.rs │ └── src/ │ ├── 404.md │ ├── README.md │ ├── SUMMARY.md │ ├── cli/ │ │ ├── README.md │ │ ├── arg-watcher.md │ │ ├── build.md │ │ ├── clean.md │ │ ├── completions.md │ │ ├── init.md │ │ ├── serve.md │ │ ├── test.md │ │ └── watch.md │ ├── continuous-integration.md │ ├── for_developers/ │ │ ├── README.md │ │ ├── backends.md │ │ ├── mdbook-wordcount/ │ │ │ ├── Cargo.toml │ │ │ └── src/ │ │ │ └── main.rs │ │ └── preprocessors.md │ ├── format/ │ │ ├── README.md │ │ ├── configuration/ │ │ │ ├── README.md │ │ │ ├── environment-variables.md │ │ │ ├── general.md │ │ │ ├── preprocessors.md │ │ │ └── renderers.md │ │ ├── example.rs │ │ ├── markdown.md │ │ ├── mathjax.md │ │ ├── mdbook.md │ │ ├── summary.md │ │ └── theme/ │ │ ├── README.md │ │ ├── editor.md │ │ ├── index-hbs.md │ │ └── syntax-highlighting.md │ ├── guide/ │ │ ├── README.md │ │ ├── creating.md │ │ ├── installation.md │ │ └── reading.md │ └── misc/ │ └── contributors.md ├── rustfmt.toml ├── src/ │ ├── cmd/ │ │ ├── build.rs │ │ ├── clean.rs │ │ ├── command_prelude.rs │ │ ├── init.rs │ │ ├── mod.rs │ │ ├── serve.rs │ │ ├── test.rs │ │ ├── watch/ │ │ │ ├── native.rs │ │ │ └── poller.rs │ │ └── watch.rs │ └── main.rs ├── tests/ │ ├── gui/ │ │ ├── books/ │ │ │ ├── all-summary/ │ │ │ │ ├── README.md │ │ │ │ ├── book.toml │ │ │ │ └── src/ │ │ │ │ ├── SUMMARY.md │ │ │ │ ├── intro.md │ │ │ │ ├── part-1/ │ │ │ │ │ └── chapter-1.md │ │ │ │ ├── part-2/ │ │ │ │ │ └── chapter-1.md │ │ │ │ ├── prefix-1.md │ │ │ │ ├── prefix-2.md │ │ │ │ ├── suffix-1.md │ │ │ │ └── suffix-2.md │ │ │ ├── basic/ │ │ │ │ ├── book.toml │ │ │ │ └── src/ │ │ │ │ ├── SUMMARY.md │ │ │ │ └── chapter_1.md │ │ │ ├── heading-nav/ │ │ │ │ ├── README.md │ │ │ │ ├── book.toml │ │ │ │ └── src/ │ │ │ │ ├── SUMMARY.md │ │ │ │ ├── collapsed.md │ │ │ │ ├── current-to-bottom.md │ │ │ │ ├── empty.md │ │ │ │ ├── filtered-headings.md │ │ │ │ ├── large-intro.md │ │ │ │ ├── markup.md │ │ │ │ ├── normal-intro.md │ │ │ │ └── unusual-heading-levels.md │ │ │ ├── heading-nav-folded/ │ │ │ │ ├── book.toml │ │ │ │ └── src/ │ │ │ │ ├── SUMMARY.md │ │ │ │ ├── intro.md │ │ │ │ ├── next-main.md │ │ │ │ └── sub/ │ │ │ │ ├── index.md │ │ │ │ ├── inner/ │ │ │ │ │ └── index.md │ │ │ │ └── second.md │ │ │ ├── highlighting/ │ │ │ │ ├── README.md │ │ │ │ ├── book.toml │ │ │ │ └── src/ │ │ │ │ ├── SUMMARY.md │ │ │ │ └── languages.md │ │ │ ├── redirect/ │ │ │ │ ├── README.md │ │ │ │ ├── book.toml │ │ │ │ └── src/ │ │ │ │ ├── SUMMARY.md │ │ │ │ ├── chapter_1.md │ │ │ │ ├── new-chapter.md │ │ │ │ └── other-chapter.md │ │ │ ├── search/ │ │ │ │ ├── README.md │ │ │ │ ├── book.toml │ │ │ │ └── src/ │ │ │ │ ├── SUMMARY.md │ │ │ │ ├── chapter_1.md │ │ │ │ └── inner/ │ │ │ │ └── chapter_2.md │ │ │ └── sidebar-scroll/ │ │ │ ├── book.toml │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ ├── chapter_1.md │ │ │ ├── chapter_10.md │ │ │ ├── chapter_100.md │ │ │ ├── chapter_11.md │ │ │ ├── chapter_12.md │ │ │ ├── chapter_13.md │ │ │ ├── chapter_14.md │ │ │ ├── chapter_15.md │ │ │ ├── chapter_16.md │ │ │ ├── chapter_17.md │ │ │ ├── chapter_18.md │ │ │ ├── chapter_19.md │ │ │ ├── chapter_2.md │ │ │ ├── chapter_20.md │ │ │ ├── chapter_21.md │ │ │ ├── chapter_22.md │ │ │ ├── chapter_23.md │ │ │ ├── chapter_24.md │ │ │ ├── chapter_25.md │ │ │ ├── chapter_26.md │ │ │ ├── chapter_27.md │ │ │ ├── chapter_28.md │ │ │ ├── chapter_29.md │ │ │ ├── chapter_3.md │ │ │ ├── chapter_30.md │ │ │ ├── chapter_31.md │ │ │ ├── chapter_32.md │ │ │ ├── chapter_33.md │ │ │ ├── chapter_34.md │ │ │ ├── chapter_35.md │ │ │ ├── chapter_36.md │ │ │ ├── chapter_37.md │ │ │ ├── chapter_38.md │ │ │ ├── chapter_39.md │ │ │ ├── chapter_4.md │ │ │ ├── chapter_40.md │ │ │ ├── chapter_41.md │ │ │ ├── chapter_42.md │ │ │ ├── chapter_43.md │ │ │ ├── chapter_44.md │ │ │ ├── chapter_45.md │ │ │ ├── chapter_46.md │ │ │ ├── chapter_47.md │ │ │ ├── chapter_48.md │ │ │ ├── chapter_49.md │ │ │ ├── chapter_5.md │ │ │ ├── chapter_50.md │ │ │ ├── chapter_51.md │ │ │ ├── chapter_52.md │ │ │ ├── chapter_53.md │ │ │ ├── chapter_54.md │ │ │ ├── chapter_55.md │ │ │ ├── chapter_56.md │ │ │ ├── chapter_57.md │ │ │ ├── chapter_58.md │ │ │ ├── chapter_59.md │ │ │ ├── chapter_6.md │ │ │ ├── chapter_60.md │ │ │ ├── chapter_61.md │ │ │ ├── chapter_62.md │ │ │ ├── chapter_63.md │ │ │ ├── chapter_64.md │ │ │ ├── chapter_65.md │ │ │ ├── chapter_66.md │ │ │ ├── chapter_67.md │ │ │ ├── chapter_68.md │ │ │ ├── chapter_69.md │ │ │ ├── chapter_7.md │ │ │ ├── chapter_70.md │ │ │ ├── chapter_71.md │ │ │ ├── chapter_72.md │ │ │ ├── chapter_73.md │ │ │ ├── chapter_74.md │ │ │ ├── chapter_75.md │ │ │ ├── chapter_76.md │ │ │ ├── chapter_77.md │ │ │ ├── chapter_78.md │ │ │ ├── chapter_79.md │ │ │ ├── chapter_8.md │ │ │ ├── chapter_80.md │ │ │ ├── chapter_81.md │ │ │ ├── chapter_82.md │ │ │ ├── chapter_83.md │ │ │ ├── chapter_84.md │ │ │ ├── chapter_85.md │ │ │ ├── chapter_86.md │ │ │ ├── chapter_87.md │ │ │ ├── chapter_88.md │ │ │ ├── chapter_89.md │ │ │ ├── chapter_9.md │ │ │ ├── chapter_90.md │ │ │ ├── chapter_91.md │ │ │ ├── chapter_92.md │ │ │ ├── chapter_93.md │ │ │ ├── chapter_94.md │ │ │ ├── chapter_95.md │ │ │ ├── chapter_96.md │ │ │ ├── chapter_97.md │ │ │ ├── chapter_98.md │ │ │ └── chapter_99.md │ │ ├── heading-nav-collapsed.goml │ │ ├── heading-nav-current-to-bottom.goml │ │ ├── heading-nav-empty.goml │ │ ├── heading-nav-filter.goml │ │ ├── heading-nav-folded.goml │ │ ├── heading-nav-large-intro.goml │ │ ├── heading-nav-markup.goml │ │ ├── heading-nav-normal-intro.goml │ │ ├── heading-nav-unusual-levels.goml │ │ ├── help.goml │ │ ├── highlighting.goml │ │ ├── move-between-pages.goml │ │ ├── redirect.goml │ │ ├── runner.rs │ │ ├── search.goml │ │ ├── sidebar-active.goml │ │ ├── sidebar-nojs.goml │ │ ├── sidebar-scroll.goml │ │ ├── sidebar.goml │ │ └── theme.goml │ └── testsuite/ │ ├── README.md │ ├── book_test.rs │ ├── build/ │ │ ├── basic_build/ │ │ │ ├── README.md │ │ │ ├── book.toml │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ └── chapter_1.md │ │ ├── create_missing/ │ │ │ ├── book.toml │ │ │ └── src/ │ │ │ └── SUMMARY.md │ │ ├── missing_file/ │ │ │ ├── book.toml │ │ │ └── src/ │ │ │ └── SUMMARY.md │ │ └── no_reserved_filename/ │ │ ├── book.toml │ │ └── src/ │ │ ├── SUMMARY.md │ │ └── print.md │ ├── build.rs │ ├── cli.rs │ ├── config/ │ │ └── empty/ │ │ ├── book.toml │ │ └── src/ │ │ ├── SUMMARY.md │ │ └── chapter_1.md │ ├── config.rs │ ├── includes/ │ │ └── all_includes/ │ │ ├── book.toml │ │ └── src/ │ │ ├── SUMMARY.md │ │ ├── anchors.md │ │ ├── example.rs │ │ ├── includes.md │ │ ├── nested-test-with-anchors.rs │ │ ├── partially-included-test-with-anchors.rs │ │ ├── partially-included-test.rs │ │ ├── playground.md │ │ ├── recursive.md │ │ ├── relative/ │ │ │ └── includes.md │ │ ├── rustdoc.md │ │ └── sample.md │ ├── includes.rs │ ├── index/ │ │ └── basic_readme/ │ │ ├── book.toml │ │ └── src/ │ │ ├── README.md │ │ ├── SUMMARY.md │ │ ├── first/ │ │ │ └── README │ │ └── second/ │ │ └── Readme.md │ ├── index.rs │ ├── init/ │ │ └── init_from_summary/ │ │ └── src/ │ │ └── SUMMARY.md │ ├── init.rs │ ├── main.rs │ ├── markdown/ │ │ ├── admonitions/ │ │ │ ├── book.toml │ │ │ ├── expected/ │ │ │ │ └── admonitions.html │ │ │ ├── expected_disabled/ │ │ │ │ └── admonitions.html │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ └── admonitions.md │ │ ├── basic_markdown/ │ │ │ ├── book.toml │ │ │ ├── expected/ │ │ │ │ ├── blank.html │ │ │ │ ├── blockquotes.html │ │ │ │ ├── code-blocks.html │ │ │ │ ├── html.html │ │ │ │ ├── images.html │ │ │ │ ├── inlines.html │ │ │ │ ├── links.html │ │ │ │ ├── lists.html │ │ │ │ └── svg.html │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ ├── blank.md │ │ │ ├── blockquotes.md │ │ │ ├── code-blocks.md │ │ │ ├── html.md │ │ │ ├── images.md │ │ │ ├── inlines.md │ │ │ ├── links.md │ │ │ ├── lists.md │ │ │ └── svg.md │ │ ├── custom_header_attributes/ │ │ │ ├── book.toml │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ └── custom_header_attributes.md │ │ ├── definition_lists/ │ │ │ ├── book.toml │ │ │ ├── expected/ │ │ │ │ ├── definition_lists.html │ │ │ │ └── html_definition_lists.html │ │ │ ├── expected_disabled/ │ │ │ │ ├── definition_lists.html │ │ │ │ └── html_definition_lists.html │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ ├── definition_lists.md │ │ │ └── html_definition_lists.md │ │ ├── footnotes/ │ │ │ ├── expected/ │ │ │ │ └── footnotes.html │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ └── footnotes.md │ │ ├── smart_punctuation/ │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ └── smart_punctuation.md │ │ ├── strikethrough/ │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ └── strikethrough.md │ │ ├── tables/ │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ └── tables.md │ │ └── tasklists/ │ │ └── src/ │ │ ├── SUMMARY.md │ │ └── tasklists.md │ ├── markdown.rs │ ├── playground/ │ │ ├── disabled_playground/ │ │ │ ├── book.toml │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ └── disabled-rust-playground.md │ │ └── playground_on_rust_code/ │ │ ├── book.toml │ │ └── src/ │ │ ├── SUMMARY.md │ │ └── rust-playground.md │ ├── playground.rs │ ├── preprocessor/ │ │ ├── extension_compatibility/ │ │ │ ├── book.toml │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ ├── chapter_1.md │ │ │ ├── part/ │ │ │ │ ├── chapter.md │ │ │ │ └── sub-chapter.md │ │ │ ├── prefix.md │ │ │ └── suffix.md │ │ ├── failing_preprocessor/ │ │ │ ├── book.toml │ │ │ └── src/ │ │ │ └── SUMMARY.md │ │ ├── missing_optional_not_fatal/ │ │ │ ├── book.toml │ │ │ └── src/ │ │ │ └── SUMMARY.md │ │ ├── missing_preprocessor/ │ │ │ ├── book.toml │ │ │ └── src/ │ │ │ └── SUMMARY.md │ │ └── nop_preprocessor/ │ │ ├── book.toml │ │ └── src/ │ │ └── SUMMARY.md │ ├── preprocessor.rs │ ├── print/ │ │ ├── chapter_no_h1/ │ │ │ ├── book.toml │ │ │ ├── expected/ │ │ │ │ └── print.html │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ ├── chapter_1.md │ │ │ ├── chapter_2.md │ │ │ └── h2-instead.md │ │ ├── duplicate_ids/ │ │ │ ├── book.toml │ │ │ ├── expected/ │ │ │ │ └── print.html │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ ├── chapter_1.md │ │ │ └── chapter_2.md │ │ ├── noindex/ │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ └── index.md │ │ └── relative_links/ │ │ ├── book.toml │ │ ├── expected/ │ │ │ └── print.html │ │ └── src/ │ │ ├── SUMMARY.md │ │ ├── first/ │ │ │ ├── index.md │ │ │ └── nested.md │ │ └── second/ │ │ └── nested.md │ ├── print.rs │ ├── redirects/ │ │ ├── redirect_existing_page/ │ │ │ ├── book.toml │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ └── chapter_1.md │ │ ├── redirect_removed_with_fragments_only/ │ │ │ ├── book.toml │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ └── chapter_1.md │ │ └── redirects_are_emitted_correctly/ │ │ ├── book.toml │ │ ├── expected/ │ │ │ ├── nested/ │ │ │ │ └── page.html │ │ │ └── overview.html │ │ └── src/ │ │ ├── SUMMARY.md │ │ ├── chapter_1.md │ │ └── chapter_2.md │ ├── redirects.rs │ ├── renderer/ │ │ ├── backends_receive_render_context_via_stdin/ │ │ │ ├── book.toml │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ └── chapter_1.md │ │ ├── missing_optional_not_fatal/ │ │ │ ├── book.toml │ │ │ └── src/ │ │ │ └── SUMMARY.md │ │ ├── missing_renderer/ │ │ │ ├── book.toml │ │ │ └── src/ │ │ │ └── SUMMARY.md │ │ └── renderer_with_arguments/ │ │ ├── book.toml │ │ └── src/ │ │ └── SUMMARY.md │ ├── renderer.rs │ ├── rendering/ │ │ ├── code_blocks_fenced_with_indent/ │ │ │ ├── book.toml │ │ │ ├── expected/ │ │ │ │ └── code-blocks-fenced-with-indent.html │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ └── code-blocks-fenced-with-indent.md │ │ ├── default_rust_edition/ │ │ │ ├── book.toml │ │ │ ├── expected/ │ │ │ │ └── default-rust-edition.html │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ └── default-rust-edition.md │ │ ├── edit_url_template/ │ │ │ ├── book.toml │ │ │ └── src/ │ │ │ └── SUMMARY.md │ │ ├── edit_url_template_explicit_src/ │ │ │ ├── book.toml │ │ │ └── src2/ │ │ │ └── SUMMARY.md │ │ ├── editable_rust_block/ │ │ │ ├── book.toml │ │ │ ├── expected/ │ │ │ │ └── editable-rust.html │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ └── editable-rust.md │ │ ├── first_chapter_is_copied_as_index_even_if_not_first_elem/ │ │ │ └── src/ │ │ │ └── SUMMARY.md │ │ ├── fontawesome/ │ │ │ ├── book.toml │ │ │ ├── expected/ │ │ │ │ └── fa.html │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ └── fa.md │ │ ├── fontawesome_error/ │ │ │ ├── book.toml │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ └── chapter_1.md │ │ ├── header_links/ │ │ │ ├── book.toml │ │ │ ├── expected/ │ │ │ │ └── header_links.html │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ └── header_links.md │ │ ├── hidelines/ │ │ │ ├── book.toml │ │ │ ├── expected/ │ │ │ │ └── hide-lines.html │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ └── hide-lines.md │ │ └── html_blocks/ │ │ ├── book.toml │ │ ├── expected/ │ │ │ ├── comment-in-list.html │ │ │ └── script-in-block.html │ │ └── src/ │ │ ├── SUMMARY.md │ │ ├── comment-in-list.md │ │ └── script-in-block.md │ ├── rendering.rs │ ├── search/ │ │ ├── chapter_settings_validation_error/ │ │ │ ├── book.toml │ │ │ └── src/ │ │ │ └── SUMMARY.md │ │ ├── disable_search_chapter/ │ │ │ ├── book.toml │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ ├── first/ │ │ │ │ ├── disable_me.md │ │ │ │ └── keep_me.md │ │ │ ├── second/ │ │ │ │ └── nested.md │ │ │ └── second.md │ │ └── reasonable_search_index/ │ │ ├── expected_index.js │ │ └── src/ │ │ ├── SUMMARY.md │ │ ├── first/ │ │ │ ├── duplicate-headers.md │ │ │ ├── heading-attributes.md │ │ │ ├── includes.md │ │ │ ├── index.md │ │ │ ├── no-headers.md │ │ │ └── unicode.md │ │ └── intro.md │ ├── search.rs │ ├── test/ │ │ ├── failing_tests/ │ │ │ ├── book.toml │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ ├── failing.md │ │ │ ├── failing_include.md │ │ │ └── test1.rs │ │ └── passing_tests/ │ │ ├── book.toml │ │ └── src/ │ │ ├── SUMMARY.md │ │ ├── passing1.md │ │ ├── passing2.md │ │ ├── test1.rs │ │ ├── test2.rs │ │ └── test3.rs │ ├── test.rs │ ├── theme/ │ │ ├── custom_fonts_css/ │ │ │ ├── book.toml │ │ │ ├── src/ │ │ │ │ └── SUMMARY.md │ │ │ └── theme/ │ │ │ └── fonts/ │ │ │ └── fonts.css │ │ ├── empty_fonts_css/ │ │ │ ├── book.toml │ │ │ ├── src/ │ │ │ │ └── SUMMARY.md │ │ │ └── theme/ │ │ │ └── fonts/ │ │ │ └── fonts.css │ │ ├── empty_theme/ │ │ │ ├── book.toml │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ └── chapter_1.md │ │ ├── fonts_css/ │ │ │ ├── src/ │ │ │ │ └── SUMMARY.md │ │ │ └── theme/ │ │ │ └── fonts/ │ │ │ └── fonts.css │ │ ├── missing_theme/ │ │ │ ├── book.toml │ │ │ └── src/ │ │ │ ├── SUMMARY.md │ │ │ └── chapter_1.md │ │ └── override_index/ │ │ ├── src/ │ │ │ └── SUMMARY.md │ │ └── theme/ │ │ └── index.hbs │ ├── theme.rs │ ├── toc/ │ │ ├── basic_toc/ │ │ │ ├── book.toml │ │ │ └── src/ │ │ │ ├── README.md │ │ │ ├── SUMMARY.md │ │ │ ├── deep/ │ │ │ │ ├── a/ │ │ │ │ │ ├── b/ │ │ │ │ │ │ └── index.md │ │ │ │ │ └── index.md │ │ │ │ └── index.md │ │ │ ├── nested/ │ │ │ │ ├── index.md │ │ │ │ └── two.md │ │ │ ├── prefix1.md │ │ │ ├── prefix2.md │ │ │ ├── suffix1.md │ │ │ └── suffix2.md │ │ └── summary_with_markdown_formatting/ │ │ └── src/ │ │ └── SUMMARY.md │ └── toc.rs └── triagebot.toml
SYMBOL INDEX (984 symbols across 88 files)
FILE: crates/mdbook-compare/src/main.rs
function main (line 14) | fn main() {
function clean (line 39) | fn clean(path: &Path) {
function build (line 46) | fn build(mdbook: &Path, book: &Path) {
function process (line 61) | fn process(path: &Path) {
function process_html (line 78) | fn process_html(path: &Path) {
function tidy (line 88) | fn tidy(path: &Path) {
function diff (line 105) | fn diff(a: &Path, b: &Path) {
FILE: crates/mdbook-core/src/book.rs
type Book (line 26) | pub struct Book {
method new (line 33) | pub fn new() -> Self {
method new_with_items (line 38) | pub fn new_with_items(items: Vec<BookItem>) -> Book {
method iter (line 43) | pub fn iter(&self) -> BookItems<'_> {
method chapters (line 50) | pub fn chapters(&self) -> impl Iterator<Item = &Chapter> {
method for_each_mut (line 65) | pub fn for_each_mut<F>(&mut self, mut func: F)
method for_each_chapter_mut (line 74) | pub fn for_each_chapter_mut<F>(&mut self, mut func: F)
method push_item (line 93) | pub fn push_item<I: Into<BookItem>>(&mut self, item: I) -> &mut Self {
function for_each_mut (line 99) | fn for_each_mut<'a, F, I>(func: &mut F, items: I)
type BookItem (line 119) | pub enum BookItem {
method from (line 129) | fn from(other: Chapter) -> BookItem {
type Chapter (line 141) | pub struct Chapter {
method new (line 173) | pub fn new<P: Into<PathBuf>>(
method new_draft (line 192) | pub fn new_draft(name: &str, parent_names: Vec<String>) -> Self {
method is_draft_chapter (line 204) | pub fn is_draft_chapter(&self) -> bool {
method fmt (line 210) | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
type SectionNumber (line 222) | pub struct SectionNumber(Vec<u32>);
method new (line 226) | pub fn new(numbers: impl Into<Vec<u32>>) -> SectionNumber {
method from_iter (line 258) | fn from_iter<I: IntoIterator<Item = u32>>(it: I) -> Self {
method fmt (line 232) | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
type Target (line 245) | type Target = Vec<u32>;
method deref (line 246) | fn deref(&self) -> &Self::Target {
method deref_mut (line 252) | fn deref_mut(&mut self) -> &mut Self::Target {
type BookItems (line 269) | pub struct BookItems<'a> {
type Item (line 274) | type Item = &'a BookItem;
method next (line 276) | fn next(&mut self) -> Option<Self::Item> {
FILE: crates/mdbook-core/src/book/tests.rs
function section_number_has_correct_dotted_representation (line 4) | fn section_number_has_correct_dotted_representation() {
function book_iter_iterates_over_sequential_items (line 18) | fn book_iter_iterates_over_sequential_items() {
function for_each_mut_visits_all_items (line 37) | fn for_each_mut_visits_all_items() {
function iterate_over_nested_book_items (line 75) | fn iterate_over_nested_book_items() {
FILE: crates/mdbook-core/src/config.rs
type Config (line 63) | pub struct Config {
method from_disk (line 113) | pub fn from_disk<P: AsRef<Path>>(config_file: P) -> Result<Config> {
method update_from_env (line 150) | pub fn update_from_env(&mut self) -> Result<()> {
method get (line 189) | pub fn get<'de, T: Deserialize<'de>>(&self, name: &str) -> Result<Opti...
method contains_key (line 216) | pub fn contains_key(&self, name: &str) -> bool {
method preprocessors (line 228) | pub fn preprocessors<'de, T: Deserialize<'de>>(&self) -> Result<BTreeM...
method outputs (line 236) | pub fn outputs<'de, T: Deserialize<'de>>(&self) -> Result<BTreeMap<Str...
method html_config (line 250) | pub fn html_config(&self) -> Option<HtmlConfig> {
method set (line 274) | pub fn set<S: Serialize, I: AsRef<str>>(&mut self, index: I, value: S)...
function is_default (line 81) | fn is_default<T: Default + PartialEq>(t: &T) -> bool {
function toml_is_empty (line 86) | fn toml_is_empty(table: &Value) -> bool {
type Err (line 91) | type Err = Error;
method from_str (line 94) | fn from_str(src: &str) -> Result<Self> {
method default (line 100) | fn default() -> Config {
function parse_env (line 308) | fn parse_env(key: &str) -> Option<String> {
type BookConfig (line 318) | pub struct BookConfig {
method realized_text_direction (line 356) | pub fn realized_text_direction(&self) -> TextDirection {
function is_default_src (line 336) | fn is_default_src(src: &PathBuf) -> bool {
method default (line 341) | fn default() -> BookConfig {
type TextDirection (line 368) | pub enum TextDirection {
method from_lang_code (line 379) | pub fn from_lang_code(code: &str) -> Self {
type BuildConfig (line 394) | pub struct BuildConfig {
method default (line 408) | fn default() -> BuildConfig {
type RustConfig (line 422) | pub struct RustConfig {
type RustEdition (line 430) | pub enum RustEdition {
type HtmlConfig (line 449) | pub struct HtmlConfig {
method theme_dir (line 558) | pub fn theme_dir(&self, root: &Path) -> PathBuf {
method get_404_output_file (line 566) | pub fn get_404_output_file(&self) -> String {
method default (line 524) | fn default() -> HtmlConfig {
type Print (line 578) | pub struct Print {
method default (line 586) | fn default() -> Self {
type Fold (line 598) | pub struct Fold {
type Playground (line 611) | pub struct Playground {
method default (line 626) | fn default() -> Playground {
type Code (line 641) | pub struct Code {
type Search (line 650) | pub struct Search {
method default (line 686) | fn default() -> Search {
type SearchChapterSettings (line 708) | pub struct SearchChapterSettings {
type Updateable (line 718) | trait Updateable<'de>: Serialize + Deserialize<'de> {
method update_value (line 719) | fn update_value<S: Serialize>(&mut self, key: &str, value: S) -> Resul...
constant COMPLEX_CONFIG (line 735) | const COMPLEX_CONFIG: &str = r#"
function load_a_complex_config_file (line 769) | fn load_a_complex_config_file() {
function disable_runnable (line 823) | fn disable_runnable() {
function edition_2015 (line 839) | fn edition_2015() {
function edition_2018 (line 871) | fn edition_2018() {
function edition_2021 (line 891) | fn edition_2021() {
function load_arbitrary_output_type (line 911) | fn load_arbitrary_output_type() {
function set_special_tables (line 944) | fn set_special_tables() {
function set_invalid_keys (line 968) | fn set_invalid_keys() {
function parse_env_vars (line 975) | fn parse_env_vars() {
function file_404_default (line 992) | fn file_404_default() {
function file_404_custom (line 1004) | fn file_404_custom() {
function text_direction_ltr (line 1017) | fn text_direction_ltr() {
function text_direction_rtl (line 1028) | fn text_direction_rtl() {
function text_direction_none (line 1039) | fn text_direction_none() {
function test_text_direction (line 1049) | fn test_text_direction() {
function invalid_language_type_error (line 1085) | fn invalid_language_type_error() {
function invalid_title_type (line 1100) | fn invalid_title_type() {
function invalid_build_dir_type (line 1115) | fn invalid_build_dir_type() {
function invalid_rust_edition (line 1127) | fn invalid_rust_edition() {
function invalid_rust_edition_expected (line 1140) | fn invalid_rust_edition_expected() {
function print_config (line 1150) | fn print_config() {
function test_json_direction (line 1170) | fn test_json_direction() {
function get_deserialize_error (line 1177) | fn get_deserialize_error() {
function contains_key (line 1191) | fn contains_key() {
FILE: crates/mdbook-core/src/lib.rs
constant MDBOOK_VERSION (line 7) | pub const MDBOOK_VERSION: &str = env!("CARGO_PKG_VERSION");
FILE: crates/mdbook-core/src/utils/fs.rs
function read_to_string (line 11) | pub fn read_to_string<P: AsRef<Path>>(path: P) -> Result<String> {
function write (line 20) | pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Re...
function create_dir_all (line 31) | pub fn create_dir_all(p: impl AsRef<Path>) -> Result<()> {
function path_to_root (line 55) | pub fn path_to_root<P: Into<PathBuf>>(path: P) -> String {
function remove_dir_content (line 74) | pub fn remove_dir_content(dir: &Path) -> Result<()> {
function copy_files_except_ext (line 93) | pub fn copy_files_except_ext(
function copy (line 155) | fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<()> {
function symlink (line 217) | fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> Result<()> {
function symlink (line 222) | fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> Result<()> {
function copy_files_except_ext_test (line 227) | fn copy_files_except_ext_test() {
FILE: crates/mdbook-core/src/utils/html.rs
function escape_html_attribute (line 6) | pub fn escape_html_attribute(text: &str) -> Cow<'_, str> {
function escape_html (line 32) | pub fn escape_html(text: &str) -> Cow<'_, str> {
function attributes_are_escaped (line 55) | fn attributes_are_escaped() {
function html_is_escaped (line 68) | fn html_is_escaped() {
FILE: crates/mdbook-core/src/utils/mod.rs
function log_backtrace (line 29) | pub fn log_backtrace(e: &Error) {
FILE: crates/mdbook-core/src/utils/toml_ext.rs
type TomlExt (line 6) | pub(crate) trait TomlExt {
method read (line 8) | fn read(&self, key: &str) -> Option<&Value>;
method insert (line 10) | fn insert(&mut self, key: &str, value: Value);
method read (line 14) | fn read(&self, key: &str) -> Option<&Value> {
method insert (line 22) | fn insert(&mut self, key: &str, value: Value) {
function split (line 40) | fn split(key: &str) -> Option<(&str, &str)> {
function read_simple_table (line 55) | fn read_simple_table() {
function read_nested_item (line 65) | fn read_nested_item() {
function insert_item_at_top_level (line 75) | fn insert_item_at_top_level() {
function insert_nested_item (line 85) | fn insert_nested_item() {
FILE: crates/mdbook-driver/src/builtin_preprocessors/cmd.rs
type CmdPreprocessor (line 14) | pub struct CmdPreprocessor {
method new (line 23) | pub fn new(name: String, cmd: String, root: PathBuf, optional: bool) -...
method write_input_to_child (line 32) | fn write_input_to_child(&self, child: &mut Child, book: &Book, ctx: &P...
method write_input (line 42) | fn write_input<W: Write>(
method cmd (line 52) | pub fn cmd(&self) -> &str {
method name (line 58) | fn name(&self) -> &str {
method run (line 62) | fn run(&self, ctx: &PreprocessorContext, book: Book) -> Result<Book> {
method supports_renderer (line 115) | fn supports_renderer(&self, renderer: &str) -> Result<bool> {
function guide (line 155) | fn guide() -> MDBook {
function round_trip_write_and_parse_input (line 161) | fn round_trip_write_and_parse_input() {
FILE: crates/mdbook-driver/src/builtin_preprocessors/index.rs
type IndexPreprocessor (line 12) | pub struct IndexPreprocessor;
constant NAME (line 16) | pub const NAME: &'static str = "index";
method new (line 19) | pub fn new() -> Self {
method name (line 25) | fn name(&self) -> &str {
method run (line 29) | fn run(&self, ctx: &PreprocessorContext, mut book: Book) -> Result<Book> {
function warn_readme_name_conflict (line 50) | fn warn_readme_name_conflict<P: AsRef<Path>>(readme_path: P, index_path:...
function is_readme_file (line 70) | fn is_readme_file<P: AsRef<Path>>(path: P) -> bool {
function file_stem_exactly_matches_readme_case_insensitively (line 86) | fn file_stem_exactly_matches_readme_case_insensitively() {
FILE: crates/mdbook-driver/src/builtin_preprocessors/links.rs
constant ESCAPE_CHAR (line 17) | const ESCAPE_CHAR: char = '\\';
constant MAX_LINK_NESTED_DEPTH (line 18) | const MAX_LINK_NESTED_DEPTH: usize = 10;
type LinkPreprocessor (line 32) | pub struct LinkPreprocessor;
constant NAME (line 36) | pub const NAME: &'static str = "links";
method new (line 39) | pub fn new() -> Self {
method name (line 45) | fn name(&self) -> &str {
method run (line 49) | fn run(&self, ctx: &PreprocessorContext, mut book: Book) -> Result<Book> {
function replace_all (line 77) | fn replace_all<P1, P2>(
type LinkType (line 139) | enum LinkType<'a> {
type RangeOrAnchor (line 148) | enum RangeOrAnchor {
type LineRange (line 155) | enum LineRange {
method start_bound (line 163) | fn start_bound(&self) -> Bound<&usize> {
method end_bound (line 172) | fn end_bound(&self) -> Bound<&usize> {
method from (line 183) | fn from(r: Range<usize>) -> LineRange {
method from (line 189) | fn from(r: RangeFrom<usize>) -> LineRange {
method from (line 195) | fn from(r: RangeTo<usize>) -> LineRange {
method from (line 201) | fn from(r: RangeFull) -> LineRange {
function relative_path (line 207) | fn relative_path<P: AsRef<Path>>(self, base: P) -> Option<PathBuf> {
function return_relative_path (line 218) | fn return_relative_path<P: AsRef<Path>>(base: P, relative: P) -> PathBuf {
function parse_range_or_anchor (line 226) | fn parse_range_or_anchor(parts: Option<&str>) -> RangeOrAnchor {
function parse_include_path (line 256) | fn parse_include_path(path: &str) -> LinkType<'static> {
function parse_rustdoc_include_path (line 265) | fn parse_rustdoc_include_path(path: &str) -> LinkType<'static> {
type Link (line 275) | struct Link<'a> {
function from_capture (line 283) | fn from_capture(cap: Captures<'a>) -> Option<Link<'a>> {
function render_with_path (line 324) | fn render_with_path<P: AsRef<Path>>(
type LinkIter (line 398) | struct LinkIter<'a>(CaptureMatches<'a, 'a>);
type Item (line 401) | type Item = Link<'a>;
method next (line 402) | fn next(&mut self) -> Option<Link<'a>> {
function find_links (line 412) | fn find_links(contents: &str) -> LinkIter<'_> {
function test_replace_all_escaped (line 433) | fn test_replace_all_escaped() {
function test_set_chapter_title (line 449) | fn test_set_chapter_title() {
function test_find_links_no_link (line 462) | fn test_find_links_no_link() {
function test_find_links_partial_link (line 468) | fn test_find_links_partial_link() {
function test_find_links_empty_link (line 478) | fn test_find_links_empty_link() {
function test_find_links_unknown_link_type (line 484) | fn test_find_links_unknown_link_type() {
function test_find_links_simple_link (line 490) | fn test_find_links_simple_link() {
function test_find_links_with_special_characters (line 516) | fn test_find_links_with_special_characters() {
function test_find_links_with_range (line 534) | fn test_find_links_with_range() {
function test_find_links_with_line_number (line 553) | fn test_find_links_with_line_number() {
function test_find_links_with_from_range (line 572) | fn test_find_links_with_from_range() {
function test_find_links_with_to_range (line 591) | fn test_find_links_with_to_range() {
function test_find_links_with_full_range (line 610) | fn test_find_links_with_full_range() {
function test_find_links_with_no_range_specified (line 629) | fn test_find_links_with_no_range_specified() {
function test_find_links_with_anchor (line 648) | fn test_find_links_with_anchor() {
function test_find_links_escaped_link (line 667) | fn test_find_links_escaped_link() {
function test_find_playgrounds_with_properties (line 685) | fn test_find_playgrounds_with_properties() {
function test_find_all_link_types (line 714) | fn test_find_all_link_types() {
function parse_without_colon_includes_all (line 758) | fn parse_without_colon_includes_all() {
function parse_with_nothing_after_colon_includes_all (line 770) | fn parse_with_nothing_after_colon_includes_all() {
function parse_with_two_colons_includes_all (line 782) | fn parse_with_two_colons_includes_all() {
function parse_with_garbage_after_two_colons_includes_all (line 794) | fn parse_with_garbage_after_two_colons_includes_all() {
function parse_with_one_number_after_colon_only_that_line (line 806) | fn parse_with_one_number_after_colon_only_that_line() {
function parse_with_one_based_start_becomes_zero_based (line 818) | fn parse_with_one_based_start_becomes_zero_based() {
function parse_with_zero_based_start_stays_zero_based_but_is_probably_an_error (line 830) | fn parse_with_zero_based_start_stays_zero_based_but_is_probably_an_error...
function parse_start_only_range (line 842) | fn parse_start_only_range() {
function parse_start_with_garbage_interpreted_as_start_only_range (line 854) | fn parse_start_with_garbage_interpreted_as_start_only_range() {
function parse_end_only_range (line 866) | fn parse_end_only_range() {
function parse_start_and_end_range (line 878) | fn parse_start_and_end_range() {
function parse_with_negative_interpreted_as_anchor (line 890) | fn parse_with_negative_interpreted_as_anchor() {
function parse_with_floating_point_interpreted_as_anchor (line 902) | fn parse_with_floating_point_interpreted_as_anchor() {
function parse_with_anchor_followed_by_colon (line 914) | fn parse_with_anchor_followed_by_colon() {
function parse_with_more_than_three_colons_ignores_everything_after_third_colon (line 926) | fn parse_with_more_than_three_colons_ignores_everything_after_third_colo...
FILE: crates/mdbook-driver/src/builtin_preprocessors/links/take_lines.rs
function take_lines (line 6) | pub(super) fn take_lines<R: RangeBounds<usize>>(s: &str, range: R) -> St...
function take_anchored_lines (line 31) | pub(super) fn take_anchored_lines(s: &str, anchor: &str) -> String {
function take_rustdoc_include_lines (line 63) | pub(super) fn take_rustdoc_include_lines<R: RangeBounds<usize>>(s: &str,...
function take_rustdoc_include_anchored_lines (line 81) | pub(super) fn take_rustdoc_include_anchored_lines(s: &str, anchor: &str)...
function take_lines_test (line 124) | fn take_lines_test() {
function take_anchored_lines_test (line 136) | fn take_anchored_lines_test() {
function take_rustdoc_include_lines_test (line 166) | fn take_rustdoc_include_lines_test() {
function take_rustdoc_include_anchored_lines_test (line 190) | fn take_rustdoc_include_anchored_lines_test() {
FILE: crates/mdbook-driver/src/builtin_renderers/markdown_renderer.rs
type MarkdownRenderer (line 10) | pub struct MarkdownRenderer;
method new (line 14) | pub fn new() -> Self {
method name (line 20) | fn name(&self) -> &str {
method render (line 24) | fn render(&self, ctx: &RenderContext) -> Result<()> {
FILE: crates/mdbook-driver/src/builtin_renderers/mod.rs
type CmdRenderer (line 20) | pub struct CmdRenderer {
method new (line 27) | pub fn new(name: String, cmd: String) -> CmdRenderer {
method name (line 33) | fn name(&self) -> &str {
method render (line 37) | fn render(&self, ctx: &RenderContext) -> Result<()> {
FILE: crates/mdbook-driver/src/init.rs
type BookBuilder (line 13) | pub struct BookBuilder {
method new (line 23) | pub fn new<P: Into<PathBuf>>(root: P) -> BookBuilder {
method with_config (line 33) | pub fn with_config(&mut self, cfg: Config) -> &mut BookBuilder {
method config (line 39) | pub fn config(&self) -> &Config {
method copy_theme (line 45) | pub fn copy_theme(&mut self, copy: bool) -> &mut BookBuilder {
method create_gitignore (line 51) | pub fn create_gitignore(&mut self, create: bool) -> &mut BookBuilder {
method build (line 64) | pub fn build(&self) -> Result<MDBook> {
method write_book_toml (line 98) | fn write_book_toml(&self) -> Result<()> {
method copy_across_theme (line 108) | fn copy_across_theme(&self) -> Result<()> {
method build_gitignore (line 116) | fn build_gitignore(&self) -> Result<()> {
method create_stub_files (line 124) | fn create_stub_files(&self) -> Result<()> {
method create_directory_structure (line 145) | fn create_directory_structure(&self) -> Result<()> {
FILE: crates/mdbook-driver/src/lib.rs
function compose_command (line 82) | fn compose_command(cmd: &str, root: &Path) -> Result<Command> {
function handle_command_error (line 107) | fn handle_command_error(
FILE: crates/mdbook-driver/src/load.rs
function load_book (line 10) | pub(crate) fn load_book<P: AsRef<Path>>(src_dir: P, cfg: &BuildConfig) -...
function create_missing (line 25) | fn create_missing(src_dir: &Path, summary: &Summary) -> Result<()> {
function load_book_from_disk (line 60) | pub(crate) fn load_book_from_disk<P: AsRef<Path>>(summary: &Summary, src...
function load_summary_item (line 80) | fn load_summary_item<P: AsRef<Path> + Clone>(
function load_chapter (line 93) | fn load_chapter<P: AsRef<Path>>(
constant DUMMY_SRC (line 148) | const DUMMY_SRC: &str = "
function dummy_link (line 158) | fn dummy_link() -> (Link, TempDir) {
function nested_links (line 170) | fn nested_links() -> (Link, TempDir) {
function load_a_single_chapter_from_disk (line 187) | fn load_a_single_chapter_from_disk() {
function load_a_single_chapter_with_utf8_bom_from_disk (line 201) | fn load_a_single_chapter_with_utf8_bom_from_disk() {
function cant_load_a_nonexistent_chapter (line 221) | fn cant_load_a_nonexistent_chapter() {
function load_recursive_link_with_separators (line 229) | fn load_recursive_link_with_separators() {
function load_a_book_with_a_single_chapter (line 253) | fn load_a_book_with_a_single_chapter() {
function cant_load_chapters_with_an_empty_path (line 272) | fn cant_load_chapters_with_an_empty_path() {
function cant_load_chapters_when_the_link_is_a_directory (line 282) | fn cant_load_chapters_when_the_link_is_a_directory() {
function cant_open_summary_md (line 296) | fn cant_open_summary_md() {
FILE: crates/mdbook-driver/src/mdbook.rs
type MDBook (line 29) | pub struct MDBook {
method load (line 48) | pub fn load<P: Into<PathBuf>>(book_root: P) -> Result<MDBook> {
method load_with_config (line 71) | pub fn load_with_config<P: Into<PathBuf>>(book_root: P, config: Config...
method load_with_config_and_summary (line 90) | pub fn load_with_config_and_summary<P: Into<PathBuf>>(
method iter (line 135) | pub fn iter(&self) -> BookItems<'_> {
method init (line 156) | pub fn init<P: Into<PathBuf>>(book_root: P) -> BookBuilder {
method build (line 161) | pub fn build(&self) -> Result<()> {
method preprocess_book (line 172) | pub fn preprocess_book(&self, renderer: &dyn Renderer) -> Result<(Book...
method execute_build_process (line 189) | pub fn execute_build_process(&self, renderer: &dyn Renderer) -> Result...
method with_renderer (line 214) | pub fn with_renderer<R: Renderer + 'static>(&mut self, renderer: R) ->...
method with_preprocessor (line 221) | pub fn with_preprocessor<P: Preprocessor + 'static>(&mut self, preproc...
method test (line 228) | pub fn test(&mut self, library_paths: Vec<&str>) -> Result<()> {
method test_chapter (line 235) | pub fn test_chapter(&mut self, library_paths: Vec<&str>, chapter: Opti...
method build_dir_for (line 371) | pub fn build_dir_for(&self, backend_name: &str) -> PathBuf {
method source_dir (line 382) | pub fn source_dir(&self) -> PathBuf {
method theme_dir (line 387) | pub fn theme_dir(&self) -> PathBuf {
type OutputConfig (line 397) | struct OutputConfig {
function determine_renderers (line 402) | fn determine_renderers(config: &Config) -> Result<IndexMap<String, Box<d...
constant DEFAULT_PREPROCESSORS (line 426) | const DEFAULT_PREPROCESSORS: &[&str] = &["links", "index"];
function is_default_preprocessor (line 428) | fn is_default_preprocessor(pre: &dyn Preprocessor) -> bool {
type PreprocessorConfig (line 435) | struct PreprocessorConfig {
function determine_preprocessors (line 446) | fn determine_preprocessors(
function preprocessor_should_run (line 549) | fn preprocessor_should_run(
FILE: crates/mdbook-driver/src/mdbook/tests.rs
function config_defaults_to_html_renderer_if_empty (line 6) | fn config_defaults_to_html_renderer_if_empty() {
function add_a_random_renderer_to_the_config (line 19) | fn add_a_random_renderer_to_the_config() {
function add_a_random_renderer_with_custom_command_to_the_config (line 30) | fn add_a_random_renderer_with_custom_command_to_the_config() {
function config_defaults_to_link_and_index_preprocessor_if_not_set (line 44) | fn config_defaults_to_link_and_index_preprocessor_if_not_set() {
function use_default_preprocessors_works (line 57) | fn use_default_preprocessors_works() {
function can_determine_third_party_preprocessors (line 67) | fn can_determine_third_party_preprocessors() {
function preprocessors_can_provide_their_own_commands (line 90) | fn preprocessors_can_provide_their_own_commands() {
function preprocessor_before_must_be_array (line 107) | fn preprocessor_before_must_be_array() {
function preprocessor_after_must_be_array (line 119) | fn preprocessor_after_must_be_array() {
function preprocessor_order_is_honored (line 131) | fn preprocessor_order_is_honored() {
function cyclic_dependencies_are_detected (line 162) | fn cyclic_dependencies_are_detected() {
function dependencies_dont_register_undefined_preprocessors (line 177) | fn dependencies_dont_register_undefined_preprocessors() {
function dependencies_dont_register_builtin_preprocessors_if_disabled (line 192) | fn dependencies_dont_register_builtin_preprocessors_if_disabled() {
function config_respects_preprocessor_selection (line 210) | fn config_respects_preprocessor_selection() {
type BoolPreprocessor (line 225) | struct BoolPreprocessor(bool);
method name (line 227) | fn name(&self) -> &str {
method run (line 231) | fn run(&self, _ctx: &PreprocessorContext, _book: Book) -> Result<Book> {
method supports_renderer (line 235) | fn supports_renderer(&self, _renderer: &str) -> Result<bool> {
function preprocessor_should_run_falls_back_to_supports_renderer_method (line 241) | fn preprocessor_should_run_falls_back_to_supports_renderer_method() {
function preprocessor_sorted_by_name (line 256) | fn preprocessor_sorted_by_name() {
function renderers_sorted_by_name (line 272) | fn renderers_sorted_by_name() {
FILE: crates/mdbook-html/front-end/js/book.js
function playground_text (line 9) | function playground_text(playground, hidden = true) {
function fetch_with_timeout (line 23) | function fetch_with_timeout(url, options, timeout = 6000) {
function handle_crate_list_update (line 47) | function handle_crate_list_update(playground_block, playground_crates) {
function update_play_button (line 74) | function update_play_button(pre_block, playground_crates) {
function run_rust_code (line 105) | function run_rust_code(code_block) {
function showThemes (line 324) | function showThemes() {
function updateThemeSelected (line 330) | function updateThemeSelected() {
function hideThemes (line 343) | function hideThemes() {
function get_saved_theme (line 349) | function get_saved_theme() {
function delete_saved_theme (line 359) | function delete_saved_theme() {
function get_theme (line 363) | function get_theme() {
function set_theme (line 380) | function set_theme(theme, store = true) {
function showSidebar (line 553) | function showSidebar() {
function hideSidebar (line 567) | function hideSidebar() {
function initResize (line 597) | function initResize() {
function resize (line 602) | function resize(e) {
function stopResize (line 615) | function stopResize() {
function next (line 659) | function next() {
function prev (line 665) | function prev() {
function showHelp (line 671) | function showHelp() {
function hideHelp (line 703) | function hideHelp() {
function hideTooltip (line 744) | function hideTooltip(elem) {
function showTooltip (line 749) | function showTooltip(elem, msg) {
function updateBorder (line 833) | function updateBorder() {
FILE: crates/mdbook-html/front-end/js/highlight.js
function e (line 6) | function e(n){Object.freeze(n);var t="function"==typeof n;return Object....
class n (line 6) | class n{constructor(e){void 0===e.data&&(e.data={}),this.data=e.data}ign...
method constructor (line 6) | constructor(e){void 0===e.data&&(e.data={}),this.data=e.data}
method ignoreMatch (line 6) | ignoreMatch(){this.ignore=!0}
function t (line 6) | function t(e){return e.replace(/&/g,"&").replace(/</g,"<").replac...
function r (line 6) | function r(e,...n){var t={};for(const n in e)t[n]=e[n];return n.forEach(...
function a (line 6) | function a(e){return e.nodeName.toLowerCase()}
function l (line 6) | function l(){return e.length&&n.length?e[0].offset!==n[0].offset?e[0].of...
method constructor (line 6) | constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e.walk(...
method addText (line 6) | addText(e){this.buffer+=t(e)}
method openNode (line 6) | openNode(e){if(!o(e))return;let n=e.kind;e.sublanguage||(n=`${this.cla...
method closeNode (line 6) | closeNode(e){o(e)&&(this.buffer+=s)}
method value (line 6) | value(){return this.buffer}
method span (line 6) | span(e){this.buffer+=`<span class="${e}">`}
function c (line 6) | function c(e){s+="<"+a(e)+[].map.call(e.attributes,(function(e){return" ...
method constructor (line 6) | constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}
method top (line 6) | get top(){return this.stack[this.stack.length-1]}
method root (line 6) | get root(){return this.rootNode}
method add (line 6) | add(e){this.top.children.push(e)}
method openNode (line 6) | openNode(e){const n={kind:e,children:[]};this.add(n),this.stack.push(n)}
method closeNode (line 6) | closeNode(){if(this.stack.length>1)return this.stack.pop()}
method closeAllNodes (line 6) | closeAllNodes(){for(;this.closeNode(););}
method toJSON (line 6) | toJSON(){return JSON.stringify(this.rootNode,null,4)}
method walk (line 6) | walk(e){return this.constructor._walk(e,this.rootNode)}
method _walk (line 6) | static _walk(e,n){return"string"==typeof n?e.addText(n):n.children&&(e...
method _collapse (line 6) | static _collapse(e){"string"!=typeof e&&e.children&&(e.children.every(...
function u (line 6) | function u(e){s+="</"+a(e)+">"}
method constructor (line 6) | constructor(e){super(),this.options=e}
method addKeyword (line 6) | addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNo...
method addText (line 6) | addText(e){""!==e&&this.add(e)}
method addSublanguage (line 6) | addSublanguage(e,n){const t=e.root;t.kind=n,t.sublanguage=!0,this.add(t)}
method toHTML (line 6) | toHTML(){return new l(this,this.options).value()}
method finalize (line 6) | finalize(){return!0}
function d (line 6) | function d(e){("start"===e.event?c:u)(e.node)}
class l (line 6) | class l{constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e...
method constructor (line 6) | constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e.walk(...
method addText (line 6) | addText(e){this.buffer+=t(e)}
method openNode (line 6) | openNode(e){if(!o(e))return;let n=e.kind;e.sublanguage||(n=`${this.cla...
method closeNode (line 6) | closeNode(e){o(e)&&(this.buffer+=s)}
method value (line 6) | value(){return this.buffer}
method span (line 6) | span(e){this.buffer+=`<span class="${e}">`}
class c (line 6) | class c{constructor(){this.rootNode={children:[]},this.stack=[this.rootN...
method constructor (line 6) | constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}
method top (line 6) | get top(){return this.stack[this.stack.length-1]}
method root (line 6) | get root(){return this.rootNode}
method add (line 6) | add(e){this.top.children.push(e)}
method openNode (line 6) | openNode(e){const n={kind:e,children:[]};this.add(n),this.stack.push(n)}
method closeNode (line 6) | closeNode(){if(this.stack.length>1)return this.stack.pop()}
method closeAllNodes (line 6) | closeAllNodes(){for(;this.closeNode(););}
method toJSON (line 6) | toJSON(){return JSON.stringify(this.rootNode,null,4)}
method walk (line 6) | walk(e){return this.constructor._walk(e,this.rootNode)}
method _walk (line 6) | static _walk(e,n){return"string"==typeof n?e.addText(n):n.children&&(e...
method _collapse (line 6) | static _collapse(e){"string"!=typeof e&&e.children&&(e.children.every(...
class u (line 6) | class u extends c{constructor(e){super(),this.options=e}addKeyword(e,n){...
method constructor (line 6) | constructor(e){super(),this.options=e}
method addKeyword (line 6) | addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNo...
method addText (line 6) | addText(e){""!==e&&this.add(e)}
method addSublanguage (line 6) | addSublanguage(e,n){const t=e.root;t.kind=n,t.sublanguage=!0,this.add(t)}
method toHTML (line 6) | toHTML(){return new l(this,this.options).value()}
method finalize (line 6) | finalize(){return!0}
function d (line 6) | function d(e){return e?"string"==typeof e?e:e.source:null}
function w (line 6) | function w(e,n){return n?+n:function(e){return N.includes(e.toLowerCase(...
function p (line 6) | function p(e){return f.noHighlightRe.test(e)}
function b (line 6) | function b(e,n,t,r){var a={code:n,language:e};S("before:highlight",a);va...
function m (line 6) | function m(e,t,a,s){var o=t;function c(e,n){var t=E.case_insensitive?n[0...
function v (line 6) | function v(e,n){n=n||f.languages||Object.keys(i);var t=function(e){const...
function x (line 6) | function x(e){return f.tabReplace||f.useBR?e.replace(c,e=>"\n"===e?f.use...
function E (line 6) | function E(e){let n=null;const t=function(e){var n=e.className+" ";n+=e....
function T (line 6) | function T(e){return e=(e||"").toLowerCase(),i[e]||i[s[e]]}
function A (line 6) | function A(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach(e=>...
function I (line 6) | function I(e){var n=T(e);return n&&!n.disableAutodetect}
function S (line 6) | function S(e,n){var t=e;o.forEach((function(e){e[t]&&e[t](n)}))}
function t (line 9) | function t(e){return"(?:"+e+")?"}
function e (line 18) | function e(e){return e?"string"==typeof e?e:e.source:null}
function n (line 18) | function n(...n){return n.map(n=>e(n)).join("")}
method constructor (line 6) | constructor(e){void 0===e.data&&(e.data={}),this.data=e.data}
method ignoreMatch (line 6) | ignoreMatch(){this.ignore=!0}
function e (line 19) | function e(e){return e?"string"==typeof e?e:e.source:null}
function n (line 19) | function n(e){return a("(",e,")?")}
method constructor (line 6) | constructor(e){void 0===e.data&&(e.data={}),this.data=e.data}
method ignoreMatch (line 6) | ignoreMatch(){this.ignore=!0}
function a (line 19) | function a(...n){return n.map(n=>e(n)).join("")}
function s (line 19) | function s(...n){return"("+n.map(n=>e(n)).join("|")+")"}
function s (line 20) | function s(e){return r("(?=",e,")")}
function r (line 20) | function r(...e){return e.map(e=>(function(e){return e?"string"==typeof ...
function e (line 47) | function e(...e){return e.map(e=>(function(e){return e?"string"==typeof ...
FILE: crates/mdbook-html/front-end/playground_editor/ace.js
function o (line 28) | function o(n){var i=e;n&&(e[n]||(e[n]={}),i=e[n]);if(!i.define||!i.defin...
function o (line 28) | function o(e){return(e.global?"g":"")+(e.ignoreCase?"i":"")+(e.multiline...
function u (line 28) | function u(e,t,n){if(Array.prototype.indexOf)return e.indexOf(t,n);for(v...
function r (line 28) | function r(){}
function w (line 28) | function w(e){try{return Object.defineProperty(e,"sentinel",{}),"sentine...
function H (line 28) | function H(e){return e=+e,e!==e?e=0:e!==0&&e!==1/0&&e!==-1/0&&(e=(e>0||-...
function B (line 28) | function B(e){var t=typeof e;return e===null||t==="undefined"||t==="bool...
function j (line 28) | function j(e){var t,n,r;if(B(e))return e;n=e.valueOf;if(typeof n=="funct...
function e (line 28) | function e(e){var t=new Array(e+2);return t[0]=t[1]=0,t}
function a (line 28) | function a(e,t,n){var a=u(t);if(!i.isMac&&s){t.getModifierState&&(t.getM...
function f (line 28) | function f(){s=Object.create(null)}
function i (line 28) | function i(e){n&&n(e),r&&r(e),t.removeListener(document,"mousemove",n,!0...
function c (line 28) | function c(e){t.getButton(e)!==0?o=0:e.detail>1?(o++,o>4&&(o=1)):o=1;if(...
function h (line 28) | function h(e){o=2,f&&clearTimeout(f),f=setTimeout(function(){f=null},n[o...
function W (line 28) | function W(){x=!0,n.blur(),n.focus(),x=!1}
function V (line 28) | function V(e){e.keyCode==27&&n.value.length<n.selectionStart&&(g||(T=n.v...
function J (line 28) | function J(){clearTimeout($),$=setTimeout(function(){b&&(n.style.cssText...
function Q (line 28) | function Q(e,t,n){var r=null,i=!1;n.addEventListener("keydown",function(...
function o (line 28) | function o(e){e.$clickSelection=null;var t=e.editor;t.setDefaultHandler(...
function u (line 28) | function u(e,t,n,r){return Math.sqrt(Math.pow(n-e,2)+Math.pow(r-t,2))}
function a (line 28) | function a(e,t){if(e.start.row==e.end.row)var n=2*t.column-e.start.colum...
function s (line 28) | function s(e){this.isOpen=!1,this.$element=null,this.$parentNode=e}
function u (line 28) | function u(e){function l(){var r=u.getDocumentPosition().row,s=n.$annota...
function a (line 28) | function a(e){o.call(this,e)}
function f (line 28) | function f(e){function T(e,n){var r=Date.now(),i=!n||e.row!=n.row,s=!n||...
function l (line 28) | function l(e,t,n,r){return Math.sqrt(Math.pow(n-e,2)+Math.pow(r-t,2))}
function o (line 28) | function o(e){typeof console!="undefined"&&console.warn&&console.warn.ap...
function u (line 28) | function u(e,t){var n=new Error(e);n.data=t,typeof console=="object"&&co...
function l (line 28) | function l(r){if(!u||!u.document)return;a.packaged=r||e.packaged||n.pack...
function c (line 28) | function c(e){return e.replace(/-(.)/g,function(e,t){return t.toUpperCas...
function i (line 28) | function i(e){e.on("click",function(t){var n=t.getDocumentPosition(),i=e...
function F (line 28) | function F(e,t,n,r){var i=s?d:p,c=null,h=null,v=null,m=0,g=null,y=null,b...
function I (line 28) | function I(e,t,n){if(o<e)return;if(e==1&&s==m&&!f){n.reverse();return}va...
function q (line 28) | function q(e,t,n,r){var i=t[r],o,c,h,p;switch(i){case g:case y:u=!1;case...
function R (line 28) | function R(e){var t=e.charCodeAt(0),n=t>>8;return n==0?t>191?g:B[t]:n==5...
function U (line 28) | function U(e){return e>="\u064b"&&e<="\u0655"}
function i (line 28) | function i(s){var o=r[s];o.processed=!0;for(var u=0;u<o.length;u++){var ...
function w (line 28) | function w(e){for(var t=n;t<=r;t++)e(i.getLine(t),t)}
function r (line 28) | function r(e,t){throw console.log("Invalid Delta:",e),"Invalid Delta: "+t}
function i (line 28) | function i(e,t){return t.row>=0&&t.row<e.length&&t.column>=0&&t.column<=...
function s (line 28) | function s(e,t){t.action!="insert"&&t.action!="remove"&&r(t,"delta.actio...
function e (line 28) | function e(e,t,n){var r=n?e.column<=t.column:e.column<t.column;return e....
function t (line 28) | function t(t,n,r){var i=t.action=="insert",s=(i?1:-1)*(t.end.row-t.start...
function i (line 28) | function i(e,t){this.foldData=e,Array.isArray(t)?this.folds=t:t=this.fol...
function u (line 28) | function u(e,t){e.row-=t.row,e.row==0&&(e.column-=t.column)}
function a (line 28) | function a(e,t){u(e.start,t),u(e.end,t)}
function f (line 28) | function f(e,t){e.row==0&&(e.column+=t.column),e.row+=t.row}
function l (line 28) | function l(e,t){f(e.start,t),f(e.end,t)}
function u (line 28) | function u(){this.getFoldAt=function(e,t,n){var r=this.getFoldLine(e);if...
function s (line 28) | function s(){this.findMatchingBracket=function(e,t){if(e.column==0)retur...
function m (line 28) | function m(e){return e<4352?!1:e>=4352&&e<=4447||e>=4515&&e<=4519||e>=46...
function n (line 28) | function n(e){return t?e.action!=="insert":e.action==="insert"}
function g (line 28) | function g(){var t=0;if(m===0)return t;if(p)for(var n=0;n<e.length;n++){...
function y (line 28) | function y(t){var n=t-f;for(var r=f;r<t;r++){var i=e[r];if(i===12||i===2...
function u (line 28) | function u(e,t){function n(e){return/\w/.test(e)||t.regExp?"\\b":""}retu...
function o (line 28) | function o(e,t){this.platform=t||(i.isMac?"mac":"win"),this.commands={},...
function u (line 28) | function u(e,t){o.call(this,e,t),this.$singleCommand=!1}
function e (line 28) | function e(e){return typeof e=="object"&&e.bindKey&&e.bindKey.position||...
function o (line 28) | function o(e,t){return{win:e,mac:t}}
function i (line 28) | function i(e,t){for(var n=t;n--;){var r=e[n];if(r&&!r[0].ignore){while(n...
function a (line 28) | function a(e){var t=e.action=="insert",n=e.start,r=e.end,i=(r.row-n.row)...
function f (line 28) | function f(e){return{row:e.row,column:e.column}}
function l (line 28) | function l(e){return{start:f(e.start),end:f(e.end),action:e.action,lines...
function c (line 28) | function c(e){e=e||this;if(Array.isArray(e))return e.map(c).join("\n");v...
function h (line 28) | function h(e){return e.start.row+":"+e.start.column+"=>"+e.end.row+":"+e...
function p (line 28) | function p(e,t){var n=e.action=="insert",r=t.action=="insert";if(n&&r)if...
function d (line 28) | function d(e,t){for(var n=e.length;n--;)for(var r=0;r<t.length;r++)if(!p...
function v (line 28) | function v(e,t){var n=e.action=="insert",r=t.action=="insert";if(n&&r)o(...
function m (line 28) | function m(e,t,n){g(e.start,t.start,t.end,n),g(e.end,t.start,t.end,n)}
function g (line 28) | function g(e,t,n,r){e.row==(r==1?t:n).row&&(e.column+=r*(n.column-t.colu...
function y (line 28) | function y(e,t){var n=e.lines,r=e.end;e.end=f(t);var i=e.end.row-e.start...
function b (line 28) | function b(e,t){t=l(t);for(var n=e.length;n--;){var r=e[n];for(var i=0;i...
function w (line 28) | function w(e,t){for(var n=0;n<t.length;n++){var r=t[n];for(var i=0;i<r.l...
function f (line 28) | function f(e){var t=document.createTextNode("");e.appendChild(t);var n=r...
function e (line 28) | function e(e,t,n,r){return(e?1:0)|(t?2:0)|(n?4:0)|(r?8:0)}
function i (line 28) | function i(e,t,n){var i=0,s=0;while(s+e[i].value.length<t){s+=e[i].value...
function r (line 28) | function r(e,t,n){var r=e[1]*t[0]-e[0]*t[1];return[(-t[1]*n[0]+t[0]*n[1]...
function i (line 28) | function i(e,t){return[e[0]-t[0],e[1]-t[1]]}
function s (line 28) | function s(e,t){return[e[0]+t[0],e[1]+t[1]]}
function o (line 28) | function o(e,t){return[e*t[0],e*t[1]]}
function u (line 28) | function u(e){var t=e.getBoundingClientRect();return[t.left,t.top]}
function o (line 28) | function o(r){if(n.$themeId!=e)return t&&t();if(!r||!r.cssClass)throw ne...
function u (line 28) | function u(e){var t="importScripts('"+i.qualifyURL(e)+"');";try{return n...
function a (line 28) | function a(e){if(typeof Worker=="undefined")return{postMessage:function(...
function s (line 28) | function s(e,t){return e.row==t.row&&e.column==t.column}
function o (line 28) | function o(e){var t=e.domEvent,n=t.altKey,o=t.shiftKey,u=t.ctrlKey,a=e.g...
function h (line 28) | function h(e,t,n){return c.$options.wrap=!0,c.$options.needle=t,c.$optio...
function v (line 28) | function v(e,t){return e.row==t.row&&e.column==t.column}
function m (line 28) | function m(e){if(e.$multiselectOnSessionChange)return;e.$onAddRange=e.$o...
function g (line 28) | function g(e){function r(t){n&&(e.renderer.setMouseCursor(""),n=!1)}var ...
function u (line 28) | function u(e){return a.stringRepeat(" ",e)}
function f (line 28) | function f(e){return e[2]?u(i)+e[2]+u(s-e[2].length+o)+e[4].replace(/^([...
function l (line 28) | function l(e){return e[2]?u(i+s-e[2].length)+e[2]+u(o)+e[4].replace(/^([...
function c (line 28) | function c(e){return e[2]?u(i)+e[2]+u(o)+e[4].replace(/^([=:])\s+/,"$1 "...
function o (line 28) | function o(e){this.session=e,this.session.widgetManager=this,this.sessio...
function o (line 28) | function o(e,t,n){var r=0,i=e.length-1;while(r<=i){var s=r+i>>1,o=n(t,e[...
function u (line 28) | function u(e,t,n){var r=e.getAnnotations().sort(s.comparePoints);if(!r.l...
FILE: crates/mdbook-html/front-end/searcher/searcher.js
function hasFocus (line 57) | function hasFocus() {
function removeChildren (line 61) | function removeChildren(elem) {
function parseURL (line 68) | function parseURL(url) {
function renderURL (line 95) | function renderURL(urlobject) {
function formatSearchMetric (line 131) | function formatSearchMetric(count, searchterm) {
function formatSearchResult (line 141) | function formatSearchResult(result, searchterms) {
function makeTeaser (line 163) | function makeTeaser(body, searchterms) {
function init (line 261) | function init(config) {
function initSearchInteractions (line 278) | function initSearchInteractions(config) {
function unfocusSearchbar (line 307) | function unfocusSearchbar() {
function doSearchOrMarkFromUrl (line 317) | function doSearchOrMarkFromUrl() {
function globalKeyHandler (line 353) | function globalKeyHandler(e) {
function loadSearchScript (line 420) | function loadSearchScript(url, id) {
function showSearch (line 436) | function showSearch(yes) {
function showResults (line 454) | function showResults(yes) {
function searchIconClickHandler (line 463) | function searchIconClickHandler() {
function searchbarKeyUpHandler (line 474) | function searchbarKeyUpHandler() {
function setSearchUrlParameters (line 495) | function setSearchUrlParameters(searchterm, action) {
function doSearch (line 520) | function doSearch(searchterm) {
FILE: crates/mdbook-html/src/html/admonitions.rs
constant ICON_NOTE (line 4) | const ICON_NOTE: &str = r#"<path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8...
constant ICON_TIP (line 7) | const ICON_TIP: &str = r#"<path d="M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984....
constant ICON_IMPORTANT (line 10) | const ICON_IMPORTANT: &str = r#"<path d="M0 1.75C0 .784.784 0 1.75 0h12....
constant ICON_WARNING (line 13) | const ICON_WARNING: &str = r#"<path d="M6.457 1.047c.659-1.234 2.427-1.2...
constant ICON_CAUTION (line 16) | const ICON_CAUTION: &str = r#"<path d="M4.47.22A.749.749 0 0 1 5 0h6c.19...
function select_tag (line 18) | pub(crate) fn select_tag(kind: BlockQuoteKind) -> (&'static str, &'stati...
FILE: crates/mdbook-html/src/html/hide_lines.rs
function hide_lines (line 10) | pub(crate) fn hide_lines(
function hide_lines_rust (line 59) | fn hide_lines_rust(text: &StrTendril) -> Tree<Node> {
function hide_lines_with_prefix (line 90) | fn hide_lines_with_prefix(content: &str, prefix: &str) -> Tree<Node> {
function wrap_rust_main (line 110) | pub(crate) fn wrap_rust_main(text: &str) -> Option<String> {
function partition_rust_source (line 129) | fn partition_rust_source(s: &str) -> (&str, &str) {
function it_partitions_rust_source (line 159) | fn it_partitions_rust_source() {
FILE: crates/mdbook-html/src/html/mod.rs
type HtmlRenderOptions (line 34) | pub(crate) struct HtmlRenderOptions<'a> {
function new (line 47) | pub(crate) fn new(
function render_markdown (line 66) | pub(crate) fn render_markdown(text: &str, options: &HtmlRenderOptions<'_...
function build_tree (line 74) | fn build_tree(text: &str, options: &HtmlRenderOptions<'_>) -> Tree<Node> {
type ChapterTree (line 80) | pub(crate) struct ChapterTree<'book> {
function build_trees (line 89) | pub(crate) fn build_trees<'book>(
FILE: crates/mdbook-html/src/html/print.rs
function render_print_page (line 17) | pub(crate) fn render_print_page(mut chapter_trees: Vec<ChapterTree<'_>>)...
function make_ids_unique (line 43) | fn make_ids_unique(
function make_root_id_map (line 74) | fn make_root_id_map(
function rewrite_links (line 124) | fn rewrite_links(
FILE: crates/mdbook-html/src/html/serialize.rs
function serialize (line 11) | pub(crate) fn serialize(tree: &Tree<Node>, output: &mut String) {
function wants_pretty_html_newline (line 40) | fn wants_pretty_html_newline(name: &str) -> bool {
function serialize_start (line 64) | fn serialize_start(el: &Element, output: &mut String) {
function serialize_end (line 100) | fn serialize_end(el: &Element, output: &mut String) {
FILE: crates/mdbook-html/src/html/tests.rs
function parse_html_script (line 6) | fn parse_html_script() {
function parse_html_script_unclosed (line 42) | fn parse_html_script_unclosed() {
FILE: crates/mdbook-html/src/html/tokenizer.rs
type TokenCollector (line 16) | struct TokenCollector {
type Handle (line 22) | type Handle = ();
method process_token (line 24) | fn process_token(&self, token: Token, _line_number: u64) -> TokenSinkRes...
function parse_html (line 67) | pub(crate) fn parse_html(html: &str) -> Vec<Token> {
FILE: crates/mdbook-html/src/html/tree.rs
type Node (line 33) | pub(crate) enum Node {
method as_element (line 53) | pub(crate) fn as_element(&self) -> Option<&Element> {
method as_element_mut (line 62) | fn as_element_mut(&mut self) -> Option<&mut Element> {
type Element (line 73) | pub(crate) struct Element {
method new (line 86) | pub(crate) fn new(tag_name: &str) -> Element {
method name (line 97) | pub(crate) fn name(&self) -> &str {
method heading_level (line 103) | pub(crate) fn heading_level(&self) -> Option<u8> {
method attr (line 113) | pub(crate) fn attr(&self, name: &str) -> Option<&str> {
method insert_attr (line 119) | pub(crate) fn insert_attr(&mut self, name: &str, value: StrTendril) {
type Attributes (line 126) | type Attributes = IndexMap<QualName, StrTendril>;
type ToTendril (line 129) | trait ToTendril {
method into_tendril (line 131) | fn into_tendril(self) -> StrTendril;
method into_tendril (line 135) | fn into_tendril(self) -> StrTendril {
type TableState (line 150) | enum TableState {
type MarkdownTreeBuilder (line 160) | pub(crate) struct MarkdownTreeBuilder<'opts, 'event, EventIter> {
function build (line 210) | pub(crate) fn build(options: &'opts HtmlRenderOptions<'opts>, events: Ev...
function append (line 236) | fn append(&mut self, node: Node) -> NodeId {
function append_text (line 248) | fn append_text(&mut self, text: StrTendril) {
function push (line 262) | fn push(&mut self, node: Node) {
function push_no_stack (line 272) | fn push_no_stack(&mut self, node: Node) {
function pop (line 278) | fn pop(&mut self) {
function node_ids_for_tag (line 290) | fn node_ids_for_tag(&self, filter: &dyn Fn(&str) -> bool) -> Vec<NodeId> {
function process_events (line 304) | fn process_events(&mut self) {
function start_tag (line 369) | fn start_tag(&mut self, tag: Tag<'event>) {
function end_tag (line 585) | fn end_tag(&mut self, tag: TagEnd) {
function append_html (line 627) | fn append_html(&mut self, html: &str) {
function start_html_tag (line 663) | fn start_html_tag(&mut self, tag: html5ever::tokenizer::Tag, is_raw: &mu...
function end_html_tag (line 687) | fn end_html_tag(&mut self, tag: html5ever::tokenizer::Tag, is_raw: &mut ...
function is_html_tag_matching (line 706) | fn is_html_tag_matching(&self, name: &str) -> bool {
function eat_till_end (line 719) | fn eat_till_end(&mut self) {
function text_for_img_alt (line 737) | fn text_for_img_alt(&mut self) -> String {
function finish_stack (line 772) | fn finish_stack(&mut self) {
function footnote_reference (line 806) | fn footnote_reference(&mut self, name: CowStr<'event>) {
function collect_footnote_defs (line 838) | fn collect_footnote_defs(&mut self) {
function add_header_links (line 907) | fn add_header_links(&mut self) {
function update_code_blocks (line 950) | fn update_code_blocks(&mut self) {
function convert_fontawesome (line 1016) | fn convert_fontawesome(&mut self) {
function text_in_node (line 1077) | fn text_in_node(node: NodeRef<'_, Node>, output: &mut String) {
function fix_link (line 1093) | fn fix_link<'a>(link: CowStr<'a>) -> CowStr<'a> {
function fix_html_link (line 1120) | fn fix_html_link(el: &mut Element) {
function is_void_element (line 1137) | pub(crate) fn is_void_element(name: &str) -> bool {
FILE: crates/mdbook-html/src/html_handlebars/hbs_renderer.rs
type HtmlHandlebars (line 22) | pub struct HtmlHandlebars;
method new (line 26) | pub fn new() -> Self {
method render_chapter (line 30) | fn render_chapter(
method render_404 (line 138) | fn render_404(
method render_print_page (line 198) | fn render_print_page(
method register_hbs_helpers (line 227) | fn register_hbs_helpers(&self, handlebars: &mut Handlebars<'_>, html_c...
method emit_redirects (line 237) | fn emit_redirects(
method emit_redirect (line 274) | fn emit_redirect(
method name (line 304) | fn name(&self) -> &str {
method render (line 308) | fn render(&self, ctx: &RenderContext) -> Result<()> {
function make_data (line 455) | fn make_data(
type RenderChapterContext (line 633) | struct RenderChapterContext<'a> {
type CombinedRedirects (line 649) | type CombinedRedirects = BTreeMap<String, (String, BTreeMap<String, Stri...
function combine_fragment_redirects (line 650) | fn combine_fragment_redirects(redirects: &HashMap<String, String>) -> Co...
function collect_redirects_for_path (line 674) | fn collect_redirects_for_path(
FILE: crates/mdbook-html/src/html_handlebars/helpers/fontawesome.rs
function fa_helper (line 8) | pub(crate) fn fa_helper(
FILE: crates/mdbook-html/src/html_handlebars/helpers/resources.rs
type ResourceHelper (line 11) | pub(crate) struct ResourceHelper {
method call (line 16) | fn call<'reg: 'rc, 'rc>(
FILE: crates/mdbook-html/src/html_handlebars/helpers/toc.rs
type RenderToc (line 11) | pub(crate) struct RenderToc {
method call (line 16) | fn call<'reg: 'rc, 'rc>(
function write_li_open_tag (line 177) | fn write_li_open_tag(out: &mut dyn Output, is_expanded: bool) -> Result<...
FILE: crates/mdbook-html/src/html_handlebars/search.rs
constant MAX_WORD_LENGTH_TO_INDEX (line 17) | const MAX_WORD_LENGTH_TO_INDEX: usize = 80;
function tokenize (line 20) | fn tokenize(text: &str) -> Vec<String> {
function create_files (line 29) | pub(super) fn create_files(
function add_doc (line 82) | fn add_doc(
function index_chapter (line 103) | fn index_chapter(
function write_to_json (line 211) | fn write_to_json(index: Index, search_config: &Search, doc_urls: Vec<Str...
function settings_path (line 273) | fn settings_path(ch: &Chapter) -> &Path {
function validate_chapter_config (line 279) | fn validate_chapter_config(
function sort_search_config (line 297) | fn sort_search_config(
function get_chapter_settings (line 310) | fn get_chapter_settings(
function collapse_whitespace (line 324) | fn collapse_whitespace(text: &str) -> Cow<'_, str> {
function chapter_settings_priority (line 330) | fn chapter_settings_priority() {
function test_tokenize_basic (line 363) | fn test_tokenize_basic() {
function test_tokenize_with_hyphens (line 368) | fn test_tokenize_with_hyphens() {
function test_tokenize_mixed_whitespace (line 376) | fn test_tokenize_mixed_whitespace() {
function test_tokenize_empty_string (line 384) | fn test_tokenize_empty_string() {
function test_tokenize_only_whitespace (line 389) | fn test_tokenize_only_whitespace() {
function test_tokenize_case_normalization (line 394) | fn test_tokenize_case_normalization() {
function test_tokenize_trim_whitespace (line 399) | fn test_tokenize_trim_whitespace() {
function test_tokenize_long_words_filtered (line 404) | fn test_tokenize_long_words_filtered() {
function test_tokenize_max_length_word (line 412) | fn test_tokenize_max_length_word() {
function test_tokenize_special_characters (line 418) | fn test_tokenize_special_characters() {
function test_tokenize_unicode (line 426) | fn test_tokenize_unicode() {
function test_tokenize_unicode_rtl_hebre (line 434) | fn test_tokenize_unicode_rtl_hebre() {
function test_tokenize_numbers (line 439) | fn test_tokenize_numbers() {
FILE: crates/mdbook-html/src/html_handlebars/static_files.rs
type StaticFiles (line 22) | pub(super) struct StaticFiles {
method new (line 39) | pub(super) fn new(theme: &Theme, html_config: &HtmlConfig, root: &Path...
method add_builtin (line 129) | pub(super) fn add_builtin(&mut self, filename: &str, data: &[u8]) {
method hash_files (line 138) | pub(super) fn hash_files(&mut self) -> Result<()> {
method write_files (line 193) | pub(super) fn write_files(self, destination: &Path) -> Result<Resource...
type StaticFile (line 27) | enum StaticFile {
function test_write_directive (line 273) | fn test_write_directive() {
FILE: crates/mdbook-html/src/theme/mod.rs
type Theme (line 40) | pub struct Theme {
method new (line 66) | pub fn new<P: AsRef<Path>>(theme_dir: P) -> Self {
method copy_theme (line 166) | pub fn copy_theme(html_config: &HtmlConfig, root: &Path) -> Result<()> {
method default (line 201) | fn default() -> Theme {
function load_file_contents (line 229) | fn load_file_contents<P: AsRef<Path>>(filename: P, dest: &mut Vec<u8>) -...
function theme_uses_defaults_with_nonexistent_src_dir (line 248) | fn theme_uses_defaults_with_nonexistent_src_dir() {
function theme_dir_overrides_defaults (line 259) | fn theme_dir_overrides_defaults() {
function favicon_override (line 320) | fn favicon_override() {
FILE: crates/mdbook-html/src/utils.rs
function normalize_path (line 7) | pub(crate) fn normalize_path(path: &Path) -> PathBuf {
type ToUrlPath (line 42) | pub(crate) trait ToUrlPath {
method to_url_path (line 43) | fn to_url_path(&self) -> String;
method to_url_path (line 47) | fn to_url_path(&self) -> String {
function unique_id (line 58) | pub(crate) fn unique_id(id: &str, used: &mut HashSet<String>) -> String {
function id_from_content (line 76) | pub(crate) fn id_from_content(content: &str) -> String {
function it_generates_unique_ids (line 107) | fn it_generates_unique_ids() {
function it_normalizes_ids (line 117) | fn it_normalizes_ids() {
FILE: crates/mdbook-markdown/src/lib.rs
type MarkdownOptions (line 15) | pub struct MarkdownOptions {
method default (line 34) | fn default() -> MarkdownOptions {
function new_cmark_parser (line 44) | pub fn new_cmark_parser<'text>(text: &'text str, options: &MarkdownOptio...
FILE: crates/mdbook-preprocessor/src/lib.rs
type Preprocessor (line 30) | pub trait Preprocessor {
method name (line 32) | fn name(&self) -> &str;
method run (line 36) | fn run(&self, ctx: &PreprocessorContext, book: Book) -> Result<Book>;
method supports_renderer (line 42) | fn supports_renderer(&self, _renderer: &str) -> Result<bool> {
type PreprocessorContext (line 51) | pub struct PreprocessorContext {
method new (line 70) | pub fn new(root: PathBuf, config: Config, renderer: String) -> Self {
function parse_input (line 82) | pub fn parse_input<R: Read>(reader: R) -> Result<(PreprocessorContext, B...
FILE: crates/mdbook-renderer/src/lib.rs
type Renderer (line 28) | pub trait Renderer {
method name (line 30) | fn name(&self) -> &str;
method render (line 34) | fn render(&self, ctx: &RenderContext) -> Result<()>;
type RenderContext (line 40) | pub struct RenderContext {
method new (line 65) | pub fn new<P, Q>(root: P, book: Book, config: Config, destination: Q) ...
method source_dir (line 81) | pub fn source_dir(&self) -> PathBuf {
method from_json (line 86) | pub fn from_json<R: Read>(reader: R) -> Result<RenderContext> {
FILE: crates/mdbook-summary/src/lib.rs
function parse_summary (line 59) | pub fn parse_summary(summary: &str) -> Result<Summary> {
type Summary (line 67) | pub struct Summary {
type Link (line 84) | pub struct Link {
method new (line 98) | pub fn new<S: Into<String>, P: AsRef<Path>>(name: S, location: P) -> L...
method default (line 109) | fn default() -> Self {
type SummaryItem (line 122) | pub enum SummaryItem {
method maybe_link_mut (line 132) | fn maybe_link_mut(&mut self) -> Option<&mut Link> {
method from (line 141) | fn from(other: Link) -> SummaryItem {
type SummaryParser (line 173) | struct SummaryParser<'a> {
function new (line 222) | fn new(text: &'a str) -> SummaryParser<'a> {
function current_location (line 235) | fn current_location(&self) -> (usize, usize) {
function parse (line 245) | fn parse(mut self) -> Result<Summary> {
function check_for_duplicates (line 272) | fn check_for_duplicates<'b>(
function parse_affix (line 294) | fn parse_affix(&mut self, is_prefix: bool) -> Result<Vec<SummaryItem>> {
function parse_parts (line 332) | fn parse_parts(&mut self) -> Result<Vec<SummaryItem>> {
function parse_link (line 381) | fn parse_link(&mut self, href: String) -> Link {
function parse_numbered (line 401) | fn parse_numbered(
function back (line 476) | fn back(&mut self, ev: Event<'a>) {
function next_event (line 482) | fn next_event(&mut self) -> Option<Event<'a>> {
function parse_nested_numbered (line 495) | fn parse_nested_numbered(&mut self, parent: &SectionNumber) -> Result<Ve...
function parse_nested_item (line 530) | fn parse_nested_item(
function parse_error (line 567) | fn parse_error<D: Display>(&self, msg: D) -> Error {
function parse_title (line 578) | fn parse_title(&mut self) -> Option<String> {
function update_section_numbers (line 604) | fn update_section_numbers(items: &mut [SummaryItem], level: usize, by: u...
function get_last_link (line 618) | fn get_last_link(links: &mut [SummaryItem]) -> Result<(usize, &mut Link)> {
function stringify_events (line 634) | fn stringify_events(events: Vec<Event<'_>>) -> String {
function parse_initial_title (line 650) | fn parse_initial_title() {
function no_initial_title (line 661) | fn no_initial_title() {
function parse_title_with_styling (line 673) | fn parse_title_with_styling() {
function convert_markdown_events_to_a_string (line 684) | fn convert_markdown_events_to_a_string() {
function parse_some_prefix_items (line 695) | fn parse_some_prefix_items() {
function parse_prefix_items_with_a_separator (line 718) | fn parse_prefix_items_with_a_separator() {
function suffix_items_cannot_be_followed_by_a_list (line 729) | fn suffix_items_cannot_be_followed_by_a_list() {
function expected_a_start_of_a_link (line 744) | fn expected_a_start_of_a_link() {
function parse_a_link (line 759) | fn parse_a_link() {
function parse_a_numbered_chapter (line 780) | fn parse_a_numbered_chapter() {
function parse_nested_numbered_chapters (line 799) | fn parse_nested_numbered_chapters() {
function parse_numbered_chapters_separated_by_comment (line 831) | fn parse_numbered_chapters_separated_by_comment() {
function parse_titled_parts (line 858) | fn parse_titled_parts() {
function can_have_a_subheader_between_nested_items (line 900) | fn can_have_a_subheader_between_nested_items() {
function an_empty_link_location_is_a_draft_chapter (line 926) | fn an_empty_link_location_is_a_draft_chapter() {
function keep_numbering_after_separator (line 945) | fn keep_numbering_after_separator() {
function add_space_for_multi_line_chapter_names (line 982) | fn add_space_for_multi_line_chapter_names() {
function allow_space_in_link_destination (line 1000) | fn allow_space_in_link_destination() {
function skip_html_comments (line 1025) | fn skip_html_comments() {
function duplicate_entries_1 (line 1124) | fn duplicate_entries_1() {
function duplicate_entries_2 (line 1138) | fn duplicate_entries_2() {
function duplicate_entries_3 (line 1151) | fn duplicate_entries_3() {
function duplicate_entries_4 (line 1166) | fn duplicate_entries_4() {
function duplicate_entries_5 (line 1181) | fn duplicate_entries_5() {
FILE: crates/xtask/src/changelog.rs
constant CHANGELOG_PATH (line 8) | const CHANGELOG_PATH: &str = "CHANGELOG.md";
function changelog (line 10) | pub(crate) fn changelog() -> Result<()> {
function get_previous (line 25) | fn get_previous() -> Result<String> {
function get_current (line 36) | fn get_current() -> Result<String> {
function get_prs (line 47) | fn get_prs(previous: &str) -> Result<Vec<(String, String)>> {
function update_changelog (line 91) | fn update_changelog(previous: &str, current: &str, prs: &[(String, Strin...
FILE: crates/xtask/src/main.rs
type Result (line 11) | type Result<T> = std::result::Result<T, Box<dyn Error>>;
function main (line 13) | fn main() -> Result<()> {
function test_all (line 59) | fn test_all() -> Result<()> {
function cargo (line 70) | fn cargo(args: &str, cb: &dyn Fn(&mut Command)) -> Result<()> {
function test_workspace (line 82) | fn test_workspace() -> Result<()> {
function clippy (line 88) | fn clippy() -> Result<()> {
function doc (line 96) | fn doc() -> Result<()> {
function fmt (line 106) | fn fmt() -> Result<()> {
function semver_checks (line 111) | fn semver_checks() -> Result<()> {
function gui (line 116) | fn gui() -> Result<()> {
function eslint (line 121) | fn eslint() -> Result<()> {
function bump (line 133) | fn bump(bump: &str) -> Result<()> {
FILE: eslint.config.mjs
method preprocess (line 7) | preprocess(text, filename) {
method postprocess (line 16) | postprocess(messages, filename) {
FILE: examples/nop-preprocessor.rs
function make_app (line 12) | fn make_app() -> Command {
function main (line 22) | fn main() {
function handle_preprocessing (line 36) | fn handle_preprocessing(pre: &dyn Preprocessor) -> Result<()> {
function handle_supports (line 58) | fn handle_supports(pre: &dyn Preprocessor, sub_args: &ArgMatches) -> ! {
type Nop (line 79) | pub struct Nop;
method new (line 82) | pub fn new() -> Nop {
method name (line 88) | fn name(&self) -> &str {
method run (line 92) | fn run(&self, ctx: &PreprocessorContext, book: Book) -> Result<Book> {
method supports_renderer (line 108) | fn supports_renderer(&self, renderer: &str) -> Result<bool> {
function nop_preprocessor_run (line 118) | fn nop_preprocessor_run() {
FILE: examples/remove-emphasis/mdbook-remove-emphasis/src/main.rs
function main (line 10) | fn main() {
type RemoveEmphasis (line 30) | struct RemoveEmphasis;
method name (line 33) | fn name(&self) -> &str {
method run (line 37) | fn run(&self, _ctx: &PreprocessorContext, mut book: Book) -> Result<Book> {
function remove_emphasis (line 49) | fn remove_emphasis(num_removed_items: &mut usize, chapter: &mut Chapter)...
function handle_preprocessing (line 65) | pub fn handle_preprocessing() -> Result<()> {
FILE: examples/remove-emphasis/test.rs
function remove_emphasis_works (line 4) | fn remove_emphasis_works() {
FILE: guide/guide-helper/src/lib.rs
function handle_preprocessing (line 10) | pub fn handle_preprocessing() -> Result<()> {
type GuideHelper (line 33) | struct GuideHelper;
method name (line 36) | fn name(&self) -> &str {
method run (line 40) | fn run(&self, _ctx: &PreprocessorContext, mut book: Book) -> Result<Book> {
function insert_version (line 46) | fn insert_version(book: &mut Book) {
FILE: guide/guide-helper/src/main.rs
function main (line 3) | fn main() {
FILE: guide/src/for_developers/mdbook-wordcount/src/main.rs
function main (line 12) | fn main() {
function count_words (line 40) | fn count_words(ch: &Chapter) -> usize {
type WordcountConfig (line 46) | pub struct WordcountConfig {
FILE: guide/src/format/example.rs
function main (line 1) | fn main() {
FILE: src/cmd/build.rs
function make_subcommand (line 8) | pub fn make_subcommand() -> Command {
function execute (line 17) | pub fn execute(args: &ArgMatches) -> Result<()> {
FILE: src/cmd/clean.rs
function make_subcommand (line 11) | pub fn make_subcommand() -> Command {
function execute (line 19) | pub fn execute(args: &ArgMatches) -> Result<()> {
function human_readable_bytes (line 38) | pub fn human_readable_bytes(bytes: u64) -> (f32, &'static str) {
type Clean (line 46) | pub struct Clean {
method new (line 53) | fn new(dir: &PathBuf) -> Result<Clean> {
method fmt (line 92) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
FILE: src/cmd/command_prelude.rs
type CommandExt (line 7) | pub trait CommandExt: Sized {
method _arg (line 8) | fn _arg(self, arg: Arg) -> Self;
method arg_dest_dir (line 10) | fn arg_dest_dir(self) -> Self {
method arg_root_dir (line 26) | fn arg_root_dir(self) -> Self {
method arg_open (line 37) | fn arg_open(self) -> Self {
method arg_watcher (line 42) | fn arg_watcher(self) -> Self {
method _arg (line 57) | fn _arg(self, arg: Arg) -> Self {
function set_dest_dir (line 62) | pub fn set_dest_dir(args: &ArgMatches, book: &mut MDBook) {
FILE: src/cmd/init.rs
function make_subcommand (line 12) | pub fn make_subcommand() -> ClapCommand {
function execute (line 32) | pub fn execute(args: &ArgMatches) -> Result<()> {
function get_author_name (line 88) | fn get_author_name() -> Option<String> {
function request_book_title (line 102) | fn request_book_title() -> Option<String> {
function confirm (line 116) | fn confirm() -> bool {
FILE: src/cmd/serve.rs
constant LIVE_RELOAD_ENDPOINT (line 20) | const LIVE_RELOAD_ENDPOINT: &str = "__livereload";
function make_subcommand (line 23) | pub fn make_subcommand() -> Command {
function execute (line 51) | pub fn execute(args: &ArgMatches) -> Result<()> {
function serve (line 109) | async fn serve(
function websocket_connection (line 142) | async fn websocket_connection(ws: WebSocket, reload_tx: broadcast::Sende...
FILE: src/cmd/test.rs
function make_subcommand (line 9) | pub fn make_subcommand() -> Command {
function execute (line 35) | pub fn execute(args: &ArgMatches) -> Result<()> {
FILE: src/cmd/watch.rs
function make_subcommand (line 12) | pub fn make_subcommand() -> Command {
type WatcherKind (line 21) | pub enum WatcherKind {
method from_str (line 27) | pub fn from_str(s: &str) -> WatcherKind {
function execute (line 37) | pub fn execute(args: &ArgMatches) -> Result<()> {
function rebuild_on_change (line 62) | pub fn rebuild_on_change(
function find_gitignore (line 74) | fn find_gitignore(book_root: &Path) -> Option<PathBuf> {
FILE: src/cmd/watch/native.rs
function rebuild_on_change (line 11) | pub fn rebuild_on_change(
function remove_ignored_files (line 107) | fn remove_ignored_files(book_root: &Path, paths: &[PathBuf]) -> Vec<Path...
function filter_ignored_files (line 132) | fn filter_ignored_files(ignore: Gitignore, paths: &[PathBuf]) -> Vec<Pat...
function test_filter_ignored_files (line 158) | fn test_filter_ignored_files() {
function filter_ignored_files_should_handle_parent_dir (line 174) | fn filter_ignored_files_should_handle_parent_dir() {
FILE: src/cmd/watch/poller.rs
function rebuild_on_change (line 18) | pub fn rebuild_on_change(
type PathData (line 78) | struct PathData {
type Watcher (line 86) | struct Watcher {
method new (line 96) | fn new(book_root: &Path) -> Watcher {
method set_roots (line 124) | fn set_roots(&mut self, book: &MDBook) {
method scan (line 153) | fn scan(&mut self) -> Vec<PathBuf> {
function check_watch_behavior (line 242) | fn check_watch_behavior(
function test_ignore (line 302) | fn test_ignore() {
function test_ignore_in_parent (line 315) | fn test_ignore_in_parent() {
function test_ignore_canonical (line 333) | fn test_ignore_canonical() {
function test_scan_extra_watch (line 350) | fn test_scan_extra_watch() {
FILE: src/main.rs
constant VERSION (line 16) | const VERSION: &str = concat!("v", clap::crate_version!());
function main (line 18) | fn main() {
function create_clap_command (line 58) | fn create_clap_command() -> Command {
function init_logger (line 93) | fn init_logger() {
function get_book_dir (line 126) | fn get_book_dir(args: &ArgMatches) -> PathBuf {
function open (line 139) | fn open<P: AsRef<OsStr>>(path: P) {
function verify_app (line 147) | fn verify_app() {
FILE: tests/gui/runner.rs
function get_available_browser_ui_test_version_inner (line 12) | fn get_available_browser_ui_test_version_inner(global: bool) -> Option<S...
function get_available_browser_ui_test_version (line 30) | fn get_available_browser_ui_test_version() -> Option<String> {
function expected_browser_ui_test_version (line 35) | fn expected_browser_ui_test_version() -> String {
function main (line 50) | fn main() {
function build_books (line 77) | fn build_books(out_dir: &Path) {
function check_status (line 99) | fn check_status(cmd: &Command, output: &Output) {
function run_browser_ui_test (line 109) | fn run_browser_ui_test(out_dir: &Path) {
FILE: tests/testsuite/book_test.rs
type StatusCode (line 16) | enum StatusCode {
type BookTest (line 23) | pub struct BookTest {
method from_dir (line 37) | pub fn from_dir(dir: &str) -> BookTest {
method empty (line 54) | pub fn empty() -> BookTest {
method init (line 61) | pub fn init(f: impl Fn(&mut BookBuilder)) -> BookTest {
method new_tmp (line 70) | fn new_tmp() -> PathBuf {
method new (line 83) | fn new(dir: PathBuf, original_source: Option<PathBuf>) -> BookTest {
method check_main_file (line 99) | pub fn check_main_file(&mut self, path: &str, expected: impl IntoData)...
method check_all_main_files (line 127) | pub fn check_all_main_files(&mut self) -> &mut Self {
method check_toc_js (line 167) | pub fn check_toc_js(&mut self, expected: impl IntoData) -> &mut Self {
method toc_js_html (line 180) | pub fn toc_js_html(&self) -> String {
method check_file (line 199) | pub fn check_file(&mut self, path_pattern: &str, expected: impl IntoDa...
method check_file_contains (line 213) | pub fn check_file_contains(&mut self, path_pattern: &str, expected: &s...
method check_file_doesnt_contain (line 232) | pub fn check_file_doesnt_contain(&mut self, path_pattern: &str, string...
method check_file_list (line 247) | pub fn check_file_list(&mut self, path: &str, expected: impl IntoData)...
method load_book (line 269) | pub fn load_book(&self) -> MDBook {
method build (line 274) | pub fn build(&mut self) -> &mut Self {
method run (line 288) | pub fn run(&mut self, args: &str, f: impl Fn(&mut BookCommand)) -> &mu...
method change_file (line 311) | pub fn change_file(&mut self, path: impl AsRef<Path>, body: &str) -> &...
method rm_r (line 318) | pub fn rm_r(&mut self, path: impl AsRef<Path>) -> &mut Self {
method rust_program (line 341) | pub fn rust_program(&mut self, path: &str, src: &str) -> &mut Self {
type BookCommand (line 361) | pub struct BookCommand {
method expect_failure (line 374) | pub fn expect_failure(&mut self) -> &mut Self {
method expect_code (line 380) | pub fn expect_code(&mut self, code: i32) -> &mut Self {
method expect_stderr (line 386) | pub fn expect_stderr(&mut self, expected: impl snapbox::IntoData) -> &...
method expect_stdout (line 392) | pub fn expect_stdout(&mut self, expected: impl snapbox::IntoData) -> &...
method args (line 398) | pub fn args(&mut self, args: &[&str]) -> &mut Self {
method env (line 404) | pub fn env<T: Into<String>>(&mut self, key: &str, value: T) -> &mut Se...
method current_dir (line 410) | pub fn current_dir<S: AsRef<std::path::Path>>(&mut self, path: S) -> &...
method debug (line 422) | pub fn debug(&mut self, value: &str) -> &mut Self {
method run (line 431) | fn run(&mut self) {
function split_args (line 504) | fn split_args(s: &str) -> Vec<String> {
function assert (line 536) | fn assert(root: &Path) -> snapbox::Assert {
function read_to_string (line 552) | pub fn read_to_string<P: AsRef<Path>>(path: P) -> String {
function glob_one (line 558) | pub fn glob_one<P: AsRef<Path>>(path: P, pattern: &str) -> PathBuf {
function list_all_files (line 578) | pub fn list_all_files(dir: &Path) -> Vec<PathBuf> {
FILE: tests/testsuite/build.rs
function basic_build (line 10) | fn basic_build() {
function failure_on_missing_file (line 24) | fn failure_on_missing_file() {
function create_missing (line 36) | fn create_missing() {
function no_reserved_filename (line 46) | fn no_reserved_filename() {
function book_toml_isnt_required (line 60) | fn book_toml_isnt_required() {
function dest_dir_relative_path (line 72) | fn dest_dir_relative_path() {
FILE: tests/testsuite/cli.rs
function no_args (line 12) | fn no_args() {
function help (line 26) | fn help() {
FILE: tests/testsuite/config.rs
function config_from_env (line 7) | fn config_from_env() {
function config_json_from_env (line 23) | fn config_json_from_env() {
function preprocessor_cfg_from_env (line 47) | fn preprocessor_cfg_from_env() {
function output_cfg_from_env (line 82) | fn output_cfg_from_env() {
function bad_config_top_level (line 116) | fn bad_config_top_level() {
function bad_config_top_level_table (line 137) | fn bad_config_top_level_table() {
function bad_config_in_book_table (line 162) | fn bad_config_in_book_table() {
function bad_config_in_rust_table (line 188) | fn bad_config_in_rust_table() {
function env_invalid_config_key (line 213) | fn env_invalid_config_key() {
function env_invalid_value (line 228) | fn env_invalid_value() {
function env_entire_book_table (line 267) | fn env_entire_book_table() {
function env_entire_output_preprocessor_table (line 288) | fn env_entire_output_preprocessor_table() {
FILE: tests/testsuite/includes.rs
function include (line 7) | fn include() {
function anchored_include (line 29) | fn anchored_include() {
function recursive_include (line 44) | fn recursive_include() {
function playground_include (line 75) | fn playground_include() {
function rustdoc_include (line 91) | fn rustdoc_include() {
FILE: tests/testsuite/includes/all_includes/src/example.rs
function main (line 1) | fn main() {
FILE: tests/testsuite/includes/all_includes/src/partially-included-test-with-anchors.rs
function some_other_function (line 1) | fn some_other_function() {
function main (line 8) | fn main() {
FILE: tests/testsuite/includes/all_includes/src/partially-included-test.rs
function some_function (line 1) | fn some_function() {
function main (line 5) | fn main() {
FILE: tests/testsuite/index.rs
function readme_to_index (line 7) | fn readme_to_index() {
FILE: tests/testsuite/init.rs
function basic_init (line 10) | fn basic_init() {
function init_api (line 61) | fn init_api() {
function init_force (line 78) | fn init_force() {
function no_git_config_with_title (line 107) | fn no_git_config_with_title() {
function init_from_summary (line 139) | fn init_from_summary() {
function init_with_custom_book_and_src_locations (line 168) | fn init_with_custom_book_and_src_locations() {
function copy_theme (line 211) | fn copy_theme() {
FILE: tests/testsuite/markdown.rs
function custom_header_attributes (line 8) | fn custom_header_attributes() {
function footnotes (line 20) | fn footnotes() {
function tables (line 40) | fn tables() {
function strikethrough (line 75) | fn strikethrough() {
function tasklists (line 87) | fn tasklists() {
function smart_punctuation (line 103) | fn smart_punctuation() {
function basic_markdown (line 146) | fn basic_markdown() {
function definition_lists (line 151) | fn definition_lists() {
function admonitions (line 168) | fn admonitions() {
FILE: tests/testsuite/playground.rs
function playground_on_rust_code (line 7) | fn playground_on_rust_code() {
function disabled_playground (line 22) | fn disabled_playground() {
FILE: tests/testsuite/preprocessor.rs
type Spy (line 12) | struct Spy(Arc<Mutex<Inner>>);
type Inner (line 15) | struct Inner {
method name (line 21) | fn name(&self) -> &str {
method run (line 25) | fn run(&self, ctx: &PreprocessorContext, book: Book) -> Result<Book> {
function runs_preprocessors (line 35) | fn runs_preprocessors() {
function test_with_custom_preprocessor (line 49) | fn test_with_custom_preprocessor() {
function nop_preprocessor (line 63) | fn nop_preprocessor() {
function failing_preprocessor (line 76) | fn failing_preprocessor() {
function example (line 89) | fn example() -> CmdPreprocessor {
function example_supports_whatever (line 99) | fn example_supports_whatever() {
function example_doesnt_support_not_supported (line 108) | fn example_doesnt_support_not_supported() {
function relative_command_path (line 118) | fn relative_command_path() {
function missing_preprocessor (line 171) | fn missing_preprocessor() {
function missing_optional_not_fatal (line 187) | fn missing_optional_not_fatal() {
function with_preprocessor_same_name (line 201) | fn with_preprocessor_same_name() {
function extension_compatibility (line 225) | fn extension_compatibility() {
FILE: tests/testsuite/print.rs
function relative_links (line 8) | fn relative_links() {
function duplicate_ids (line 17) | fn duplicate_ids() {
function chapter_no_h1 (line 26) | fn chapter_no_h1() {
function noindex (line 35) | fn noindex() {
FILE: tests/testsuite/redirects.rs
function redirects_are_emitted_correctly (line 8) | fn redirects_are_emitted_correctly() {
function redirect_removed_with_fragments_only (line 22) | fn redirect_removed_with_fragments_only() {
function redirect_existing_page (line 38) | fn redirect_existing_page() {
FILE: tests/testsuite/renderer.rs
type Spy (line 10) | struct Spy(Arc<Mutex<Inner>>);
type Inner (line 13) | struct Inner {
method name (line 18) | fn name(&self) -> &str {
method render (line 22) | fn render(&self, _ctx: &RenderContext) -> Result<()> {
function runs_renderers (line 31) | fn runs_renderers() {
function failing_command (line 44) | fn failing_command() {
function missing_renderer (line 80) | fn missing_renderer() {
function missing_optional_not_fatal (line 99) | fn missing_optional_not_fatal() {
function renderer_with_arguments (line 113) | fn renderer_with_arguments() {
function backends_receive_render_context_via_stdin (line 144) | fn backends_receive_render_context_via_stdin() {
function relative_command_path (line 216) | fn relative_command_path() {
function with_renderer_same_name (line 247) | fn with_renderer_same_name() {
FILE: tests/testsuite/rendering.rs
function edit_url_template (line 9) | fn edit_url_template() {
function edit_url_template_explicit_src (line 19) | fn edit_url_template_explicit_src() {
function first_chapter_is_copied_as_index_even_if_not_first_elem (line 30) | fn first_chapter_is_copied_as_index_even_if_not_first_elem() {
function fontawesome (line 49) | fn fontawesome() {
function fontawesome_error_message (line 66) | fn fontawesome_error_message() {
function default_rust_edition (line 83) | fn default_rust_edition() {
function editable_rust_block (line 89) | fn editable_rust_block() {
function hidelines (line 95) | fn hidelines() {
function language_rust_playground (line 101) | fn language_rust_playground() {
function code_block_in_list (line 193) | fn code_block_in_list() {
function header_links (line 226) | fn header_links() {
function busted_end_tag (line 232) | fn busted_end_tag() {
function html_blocks (line 251) | fn html_blocks() {
function code_block_fenced_with_indent (line 257) | fn code_block_fenced_with_indent() {
function unclosed_html_tags (line 266) | fn unclosed_html_tags() {
function unbalanced_html_tags (line 288) | fn unbalanced_html_tags() {
function heading_with_unbalanced_html (line 307) | fn heading_with_unbalanced_html() {
FILE: tests/testsuite/search.rs
function read_book_index (line 8) | fn read_book_index(root: &Path) -> serde_json::Value {
function reasonable_search_index (line 20) | fn reasonable_search_index() {
function search_index_hasnt_changed_accidentally (line 88) | fn search_index_hasnt_changed_accidentally() {
function can_disable_individual_chapters (line 97) | fn can_disable_individual_chapters() {
function with_no_source_path (line 116) | fn with_no_source_path() {
function chapter_settings_validation_error (line 126) | fn chapter_settings_validation_error() {
FILE: tests/testsuite/test.rs
function passing_tests (line 7) | fn passing_tests() {
function failing_tests (line 20) | fn failing_tests() {
function test_individual_chapter (line 59) | fn test_individual_chapter() {
function chapter_not_found (line 80) | fn chapter_not_found() {
FILE: tests/testsuite/test/failing_tests/src/test1.rs
function test2 (line 1) | fn test2() {
FILE: tests/testsuite/test/passing_tests/src/test2.rs
function test2 (line 1) | fn test2() {
FILE: tests/testsuite/theme.rs
function missing_theme (line 7) | fn missing_theme() {
function empty_theme (line 21) | fn empty_theme() {
function override_index (line 35) | fn override_index() {
function default_fonts (line 47) | fn default_fonts() {
function theme_fonts_copied (line 73) | fn theme_fonts_copied() {
function fonts_css (line 122) | fn fonts_css() {
function empty_fonts_css (line 144) | fn empty_fonts_css() {
function custom_fonts_css (line 160) | fn custom_fonts_css() {
FILE: tests/testsuite/toc.rs
constant TOC_TOP_LEVEL (line 8) | const TOC_TOP_LEVEL: &[&str] = &[
constant TOC_SECOND_LEVEL (line 16) | const TOC_SECOND_LEVEL: &[&str] = &[
function toc_js_html (line 37) | fn toc_js_html() -> Document {
function toc_fallback_html (line 46) | fn toc_fallback_html() -> Result<Document> {
function check_second_toc_level (line 56) | fn check_second_toc_level() {
function check_first_toc_level (line 78) | fn check_first_toc_level() {
function check_spacers (line 101) | fn check_spacers() {
function check_link_target_js (line 113) | fn check_link_target_js() {
function check_link_target_fallback (line 128) | fn check_link_target_fallback() {
function summary_with_markdown_formatting (line 146) | fn summary_with_markdown_formatting() {
Condensed preview — 601 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,718K chars).
[
{
"path": ".cargo/config.toml",
"chars": 65,
"preview": "[alias]\nxtask = \"run --manifest-path=crates/xtask/Cargo.toml --\"\n"
},
{
"path": ".git-blame-ignore-revs",
"chars": 767,
"preview": "# Use `git config blame.ignorerevsfile .git-blame-ignore-revs` to make `git blame` ignore the following commits.\n\n# rust"
},
{
"path": ".gitattributes",
"chars": 185,
"preview": "[attr]rust text eol=lf whitespace=tab-in-indent,trailing-space,tabwidth=4\n\n* text=auto eol=lf\n*.rs rust\n*.woff binary\n*."
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.yml",
"chars": 1243,
"preview": "name: Bug Report\ndescription: Create a report to help us improve\nlabels: [\"C-bug\"]\nbody:\n - type: markdown\n attribut"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.yml",
"chars": 798,
"preview": "name: Enhancement\ndescription: Suggest an idea for enhancing mdBook\nlabels: [\"C-enhancement\"]\nbody:\n - type: markdown\n "
},
{
"path": ".github/ISSUE_TEMPLATE/question.yml",
"chars": 650,
"preview": "name: Question\ndescription: Have a question on how to use mdBook?\nlabels: [\"C-question\"]\nbody:\n - type: markdown\n at"
},
{
"path": ".github/renovate.json5",
"chars": 2491,
"preview": "{\n schedule: ['before 5am on the first day of the month'],\n // Raise from default of 2 to reduce trickle.\n prHo"
},
{
"path": ".github/workflows/deploy.yml",
"chars": 1972,
"preview": "name: Deploy\non:\n release:\n types: [created]\n\ndefaults:\n run:\n shell: bash\n\npermissions:\n contents: write\n\njobs"
},
{
"path": ".github/workflows/main.yml",
"chars": 4732,
"preview": "name: CI\non:\n pull_request:\n merge_group:\n\njobs:\n test:\n runs-on: ${{ matrix.os }}\n strategy:\n matrix:\n "
},
{
"path": ".github/workflows/update-dependencies.yml",
"chars": 556,
"preview": "name: Update dependencies\non:\n schedule:\n - cron: '0 0 1 * *'\n workflow_dispatch:\n\njobs:\n update:\n name: Update"
},
{
"path": ".gitignore",
"chars": 289,
"preview": "target\n\n# MacOS temp file\n.DS_Store\n\nbook-test\nguide/book\n\n.vscode\ntests/dummy_book/book/\ntests/gui/books/*/book/\ntests/"
},
{
"path": "CHANGELOG.md",
"chars": 82166,
"preview": "# Changelog\n\n## mdBook 0.5.2\n[v0.5.1...v0.5.2](https://github.com/rust-lang/mdBook/compare/v0.5.1...v0.5.2)\n\n### Changed"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 131,
"preview": "# The Rust Code of Conduct\n\nThe Code of Conduct for this repository [can be found online](https://www.rust-lang.org/cond"
},
{
"path": "CONTRIBUTING.md",
"chars": 12230,
"preview": "# Contributing\n\nWelcome stranger!\n\nIf you have come here to learn how to contribute to mdBook, we have some tips for you"
},
{
"path": "Cargo.toml",
"chars": 4442,
"preview": "[workspace]\nmembers = [\n \".\",\n \"crates/*\",\n \"examples/remove-emphasis/mdbook-remove-emphasis\", \"guide/guide-hel"
},
{
"path": "LICENSE",
"chars": 15921,
"preview": "Mozilla Public License, version 2.0\n\n1. Definitions\n\n1.1. \"Contributor\"\n\n means each individual or legal entity that"
},
{
"path": "README.md",
"chars": 1053,
"preview": "# mdBook\n\n[](https://github.com/ru"
},
{
"path": "ci/install-rust.sh",
"chars": 1285,
"preview": "#!/usr/bin/env bash\n# Install/update rust.\n# The first argument should be the toolchain to install.\n\nset -ex\nif [ -z \"$1"
},
{
"path": "ci/make-release-asset.sh",
"chars": 1384,
"preview": "#!/usr/bin/env bash\n# Builds the release and creates an archive and optionally deploys to GitHub.\nset -ex\n\nif [[ -z \"$GI"
},
{
"path": "ci/publish-guide.sh",
"chars": 1184,
"preview": "#!/usr/bin/env bash\n# This publishes the user guide to GitHub Pages.\n#\n# If this is a pre-release, then it goes in a sep"
},
{
"path": "ci/update-dependencies.sh",
"chars": 1060,
"preview": "#!/usr/bin/env bash\n# Updates all compatible Cargo dependencies.\n#\n# I wasn't able to get Renovate to update compatible "
},
{
"path": "crates/mdbook-compare/Cargo.toml",
"chars": 200,
"preview": "[package]\nname = \"mdbook-compare\"\npublish = false\nedition.workspace = true\nlicense.workspace = true\nrepository.workspace"
},
{
"path": "crates/mdbook-compare/README.md",
"chars": 1161,
"preview": "# mdbook-compare\n\nThis is a simple utility to compare the output of two different versions of mdbook.\n\nTo use this:\n\n1. "
},
{
"path": "crates/mdbook-compare/src/main.rs",
"chars": 3240,
"preview": "//! Utility to compare the output of two different versions of mdbook.\n\nuse std::path::Path;\nuse std::process::Command;\n"
},
{
"path": "crates/mdbook-core/Cargo.toml",
"chars": 474,
"preview": "[package]\nname = \"mdbook-core\"\nversion = \"0.5.2\"\ndescription = \"The base support library for mdbook, intended for intern"
},
{
"path": "crates/mdbook-core/README.md",
"chars": 880,
"preview": "# mdbook-core\n\n[](https://docs.rs/mdbook-core)\n[ {\n let inputs = vec![\n (vec![0], "
},
{
"path": "crates/mdbook-core/src/book.rs",
"chars": 8216,
"preview": "//! A tree structure representing a book.\n\nuse serde::{Deserialize, Serialize};\nuse std::collections::VecDeque;\nuse std:"
},
{
"path": "crates/mdbook-core/src/config.rs",
"chars": 40321,
"preview": "//! Mdbook's configuration system.\n//!\n//! The main entrypoint of the `config` module is the `Config` struct. This acts\n"
},
{
"path": "crates/mdbook-core/src/lib.rs",
"chars": 415,
"preview": "//! The base support library for mdbook, intended for internal use only.\n\n/// The current version of `mdbook`.\n///\n/// T"
},
{
"path": "crates/mdbook-core/src/utils/fs.rs",
"chars": 9359,
"preview": "//! Filesystem utilities and helpers.\n\nuse anyhow::{Context, Result};\nuse std::fs;\nuse std::path::{Component, Path, Path"
},
{
"path": "crates/mdbook-core/src/utils/html.rs",
"chars": 2555,
"preview": "//! Utilities for dealing with HTML.\n\nuse std::borrow::Cow;\n\n/// Escape characters to make it safe for an HTML string.\np"
},
{
"path": "crates/mdbook-core/src/utils/mod.rs",
"chars": 958,
"preview": "//! Various helpers and utilities.\n\nuse anyhow::Error;\nuse std::fmt::Write;\nuse tracing::error;\n\npub mod fs;\nmod html;\nm"
},
{
"path": "crates/mdbook-core/src/utils/toml_ext.rs",
"chars": 2289,
"preview": "//! Helper for working with toml types.\n\nuse toml::value::{Table, Value};\n\n/// Helper for working with toml types.\npub(c"
},
{
"path": "crates/mdbook-driver/Cargo.toml",
"chars": 746,
"preview": "[package]\nname = \"mdbook-driver\"\nversion = \"0.5.2\"\ndescription = \"High-level library for running mdBook\"\nedition.workspa"
},
{
"path": "crates/mdbook-driver/README.md",
"chars": 1010,
"preview": "# mdbook-driver\n\n[](https://docs.rs/mdbook-driver)\n[![crate"
},
{
"path": "crates/mdbook-driver/src/builtin_preprocessors/cmd.rs",
"chars": 5307,
"preview": "use anyhow::{Context, Result, ensure};\nuse mdbook_core::book::Book;\nuse mdbook_preprocessor::{Preprocessor, Preprocessor"
},
{
"path": "crates/mdbook-driver/src/builtin_preprocessors/index.rs",
"chars": 3090,
"preview": "use anyhow::Result;\nuse mdbook_core::book::{Book, BookItem};\nuse mdbook_core::static_regex;\nuse mdbook_preprocessor::{Pr"
},
{
"path": "crates/mdbook-driver/src/builtin_preprocessors/links/take_lines.rs",
"chars": 9234,
"preview": "use mdbook_core::static_regex;\nuse std::ops::Bound::{Excluded, Included, Unbounded};\nuse std::ops::RangeBounds;\n\n/// Tak"
},
{
"path": "crates/mdbook-driver/src/builtin_preprocessors/links.rs",
"chars": 30288,
"preview": "use self::take_lines::{\n take_anchored_lines, take_lines, take_rustdoc_include_anchored_lines,\n take_rustdoc_inclu"
},
{
"path": "crates/mdbook-driver/src/builtin_preprocessors/mod.rs",
"chars": 176,
"preview": "//! Built-in preprocessors.\n\npub use self::cmd::CmdPreprocessor;\npub use self::index::IndexPreprocessor;\npub use self::l"
},
{
"path": "crates/mdbook-driver/src/builtin_renderers/markdown_renderer.rs",
"chars": 1254,
"preview": "use anyhow::{Context, Result};\nuse mdbook_core::utils::fs;\nuse mdbook_renderer::{RenderContext, Renderer};\nuse tracing::"
},
{
"path": "crates/mdbook-driver/src/builtin_renderers/mod.rs",
"chars": 2741,
"preview": "//! Built-in renderers.\n//!\n//! The HTML renderer can be found in the [`mdbook_html`] crate.\n\nuse anyhow::{Context, Resu"
},
{
"path": "crates/mdbook-driver/src/init.rs",
"chars": 4656,
"preview": "//! Support for initializing a new book.\n\nuse super::MDBook;\nuse anyhow::{Context, Result};\nuse mdbook_core::config::Con"
},
{
"path": "crates/mdbook-driver/src/lib.rs",
"chars": 3963,
"preview": "//! High-level library for running mdBook.\n//!\n//! This is the high-level library for running\n//! [mdBook](https://rust-"
},
{
"path": "crates/mdbook-driver/src/load.rs",
"chars": 9815,
"preview": "use anyhow::{Context, Result};\nuse mdbook_core::book::{Book, BookItem, Chapter};\nuse mdbook_core::config::BuildConfig;\nu"
},
{
"path": "crates/mdbook-driver/src/mdbook/tests.rs",
"chars": 7327,
"preview": "use super::*;\nuse std::str::FromStr;\nuse toml::value::{Table, Value};\n\n#[test]\nfn config_defaults_to_html_renderer_if_em"
},
{
"path": "crates/mdbook-driver/src/mdbook.rs",
"chars": 20047,
"preview": "//! The high-level interface for loading and rendering books.\n\nuse crate::builtin_preprocessors::{CmdPreprocessor, Index"
},
{
"path": "crates/mdbook-html/Cargo.toml",
"chars": 844,
"preview": "[package]\nname = \"mdbook-html\"\nversion = \"0.5.2\"\ndescription = \"mdBook HTML renderer\"\nedition.workspace = true\nlicense.w"
},
{
"path": "crates/mdbook-html/README.md",
"chars": 906,
"preview": "# mdbook-html\n\n[](https://docs.rs/mdbook-html)\n[\n*/\n\n.hljs {\n display: block;\n overflo"
},
{
"path": "crates/mdbook-html/front-end/css/chrome.css",
"chars": 17518,
"preview": "/* CSS for UI elements (a.k.a. chrome) */\n\nhtml {\n scrollbar-color: var(--scrollbar) transparent;\n}\n#mdbook-searchres"
},
{
"path": "crates/mdbook-html/front-end/css/general.css",
"chars": 9920,
"preview": "/* Base styles and content styles */\n\n:root {\n /* Browser default font-size is 16px, this way 1 rem = 10px */\n fon"
},
{
"path": "crates/mdbook-html/front-end/css/highlight.css",
"chars": 1209,
"preview": "/*\n * An increased contrast highlighting scheme loosely based on the\n * \"Base16 Atelier Dune Light\" theme by Bram de Haa"
},
{
"path": "crates/mdbook-html/front-end/css/print.css",
"chars": 689,
"preview": "\n#mdbook-sidebar,\n#mdbook-menu-bar,\n.nav-chapters,\n.mobile-nav-chapters {\n display: none;\n}\n\n#mdbook-page-wrapper.pag"
},
{
"path": "crates/mdbook-html/front-end/css/tomorrow-night.css",
"chars": 1694,
"preview": "/* Tomorrow Night Theme */\n/* https://github.com/jmblog/color-themes-for-highlightjs */\n/* Original theme - https://gith"
},
{
"path": "crates/mdbook-html/front-end/css/variables.css",
"chars": 10422,
"preview": "\n/* Globals */\n\n:root {\n --sidebar-target-width: 300px;\n --sidebar-width: min(var(--sidebar-target-width), 80vw);\n"
},
{
"path": "crates/mdbook-html/front-end/fonts/OPEN-SANS-LICENSE.txt",
"chars": 11358,
"preview": "\n Apache License\n Version 2.0, January 2004\n "
},
{
"path": "crates/mdbook-html/front-end/fonts/SOURCE-CODE-PRO-LICENSE.txt",
"chars": 4528,
"preview": "Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Re"
},
{
"path": "crates/mdbook-html/front-end/fonts/fonts.css",
"chars": 3873,
"preview": "/* Open Sans is licensed under the Apache License, Version 2.0. See http://www.apache.org/licenses/LICENSE-2.0 */\n/* Sou"
},
{
"path": "crates/mdbook-html/front-end/js/book.js",
"chars": 30019,
"preview": "'use strict';\n\n/* global default_theme, default_dark_theme, default_light_theme, hljs, ClipboardJS */\n\n// Fix back butto"
},
{
"path": "crates/mdbook-html/front-end/js/highlight.js",
"chars": 137512,
"preview": "/*\n Highlight.js 10.1.1 (93fd0d73)\n License: BSD-3-Clause\n Copyright (c) 2006-2020, Ivan Sagalaev\n*/\nvar hljs=functio"
},
{
"path": "crates/mdbook-html/front-end/playground_editor/ace.js",
"chars": 371590,
"preview": "/*\nCopyright (c) 2010, Ajax.org B.V.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or wi"
},
{
"path": "crates/mdbook-html/front-end/playground_editor/editor.js",
"chars": 875,
"preview": "\"use strict\";\nwindow.editors = [];\n(function(editors) {\n if (typeof(ace) === 'undefined' || !ace) {\n return;\n "
},
{
"path": "crates/mdbook-html/front-end/playground_editor/mode-rust.js",
"chars": 6935,
"preview": "ace.define(\"ace/mode/rust_highlight_rules\",[\"require\",\"exports\",\"module\",\"ace/lib/oop\",\"ace/mode/text_highlight_rules\"],"
},
{
"path": "crates/mdbook-html/front-end/playground_editor/theme-dawn.js",
"chars": 2554,
"preview": "ace.define(\"ace/theme/dawn\",[\"require\",\"exports\",\"module\",\"ace/lib/dom\"],function(e,t,n){t.isDark=!1,t.cssClass=\"ace-daw"
},
{
"path": "crates/mdbook-html/front-end/playground_editor/theme-tomorrow_night.js",
"chars": 3144,
"preview": "ace.define(\"ace/theme/tomorrow_night\",[\"require\",\"exports\",\"module\",\"ace/lib/dom\"],function(e,t,n){t.isDark=!0,t.cssClas"
},
{
"path": "crates/mdbook-html/front-end/searcher/searcher.js",
"chars": 20102,
"preview": "'use strict';\n\n/* global Mark, elasticlunr, path_to_root */\n\nwindow.search = window.search || {};\n(function search() {\n "
},
{
"path": "crates/mdbook-html/front-end/templates/head.hbs",
"chars": 40,
"preview": "{{!-- Put your head HTML text here --}}\n"
},
{
"path": "crates/mdbook-html/front-end/templates/header.hbs",
"chars": 41,
"preview": "{{!-- Put your header HTML text here --}}"
},
{
"path": "crates/mdbook-html/front-end/templates/index.hbs",
"chars": 16604,
"preview": "<!DOCTYPE HTML>\n<html lang=\"{{ language }}\" class=\"{{ default_theme }} sidebar-visible\" dir=\"{{ text_direction }}\">\n "
},
{
"path": "crates/mdbook-html/front-end/templates/redirect.hbs",
"chars": 1109,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <title>Redirecting...</title>\n <meta http-eq"
},
{
"path": "crates/mdbook-html/front-end/templates/toc.html.hbs",
"chars": 1828,
"preview": "<!DOCTYPE HTML>\n<html lang=\"{{ language }}\" class=\"{{ default_theme }}\" dir=\"{{ text_direction }}\">\n <head>\n <"
},
{
"path": "crates/mdbook-html/front-end/templates/toc.js.hbs",
"chars": 19168,
"preview": "// Populate the sidebar\n//\n// This is a script, and not included directly in the page, to control the total size of the "
},
{
"path": "crates/mdbook-html/src/html/admonitions.rs",
"chars": 3212,
"preview": "use pulldown_cmark::BlockQuoteKind;\n\n// This icon is from GitHub, MIT License, see https://github.com/primer/octicons\nco"
},
{
"path": "crates/mdbook-html/src/html/hide_lines.rs",
"chars": 6464,
"preview": "//! Support for hiding code lines.\n\nuse crate::html::{Element, Node};\nuse ego_tree::{NodeId, Tree};\nuse html5ever::tendr"
},
{
"path": "crates/mdbook-html/src/html/mod.rs",
"chars": 3663,
"preview": "//! HTML rendering support.\n//!\n//! This module's primary entry point is [`render_markdown`] which will take\n//! markdow"
},
{
"path": "crates/mdbook-html/src/html/print.rs",
"chars": 8544,
"preview": "//! Support for generating the print page.\n//!\n//! The print page takes all the individual chapters (as `Tree<Node>`\n//!"
},
{
"path": "crates/mdbook-html/src/html/serialize.rs",
"chars": 3191,
"preview": "//! Serializes the [`Node`] tree to an HTML string.\n\nuse super::tree::is_void_element;\nuse super::tree::{Element, Node};"
},
{
"path": "crates/mdbook-html/src/html/tests.rs",
"chars": 1263,
"preview": "use crate::html::tokenizer::parse_html;\nuse html5ever::tokenizer::{Tag, TagKind, Token};\n\n// Basic tokenizer behavior of"
},
{
"path": "crates/mdbook-html/src/html/tokenizer.rs",
"chars": 2794,
"preview": "//! Support for parsing HTML.\n//!\n//! The primary entry point is [`parse_html`] which uses [`html5ever`] to\n//! tokenize"
},
{
"path": "crates/mdbook-html/src/html/tree.rs",
"chars": 43596,
"preview": "//! Tree data structure for representing a markdown document.\n//!\n//! [`MarkdownTreeBuilder::build`] is the primary entr"
},
{
"path": "crates/mdbook-html/src/html_handlebars/hbs_renderer.rs",
"chars": 25022,
"preview": "use super::helpers;\nuse super::static_files::StaticFiles;\nuse crate::html::ChapterTree;\nuse crate::html::{build_trees, r"
},
{
"path": "crates/mdbook-html/src/html_handlebars/helpers/fontawesome.rs",
"chars": 1780,
"preview": "use font_awesome_as_a_crate as fa;\nuse handlebars::{\n Context, Handlebars, Helper, Output, RenderContext, RenderError"
},
{
"path": "crates/mdbook-html/src/html_handlebars/helpers/mod.rs",
"chars": 74,
"preview": "pub(crate) mod fontawesome;\npub(crate) mod resources;\npub(crate) mod toc;\n"
},
{
"path": "crates/mdbook-html/src/html_handlebars/helpers/resources.rs",
"chars": 1332,
"preview": "use std::collections::HashMap;\n\nuse mdbook_core::utils;\n\nuse handlebars::{\n Context, Handlebars, Helper, HelperDef, O"
},
{
"path": "crates/mdbook-html/src/html_handlebars/helpers/toc.rs",
"chars": 6326,
"preview": "use crate::utils::ToUrlPath;\nuse handlebars::{\n Context, Handlebars, Helper, HelperDef, Output, RenderContext, Render"
},
{
"path": "crates/mdbook-html/src/html_handlebars/mod.rs",
"chars": 133,
"preview": "mod hbs_renderer;\nmod helpers;\n#[cfg(feature = \"search\")]\nmod search;\nmod static_files;\n\npub use self::hbs_renderer::Htm"
},
{
"path": "crates/mdbook-html/src/html_handlebars/search.rs",
"chars": 14168,
"preview": "use super::static_files::StaticFiles;\nuse crate::html::{ChapterTree, Node};\nuse crate::theme::searcher;\nuse crate::utils"
},
{
"path": "crates/mdbook-html/src/html_handlebars/static_files.rs",
"chars": 13070,
"preview": "//! Support for writing static files.\n\nuse super::helpers::resources::ResourceHelper;\nuse crate::theme::{self, Theme, pl"
},
{
"path": "crates/mdbook-html/src/lib.rs",
"chars": 137,
"preview": "//! mdBook HTML renderer.\n\nmod html;\nmod html_handlebars;\npub mod theme;\npub(crate) mod utils;\n\npub use html_handlebars:"
},
{
"path": "crates/mdbook-html/src/theme/fonts.rs",
"chars": 2376,
"preview": "pub(crate) static CSS: &[u8] = include_bytes!(\"../../front-end/fonts/fonts.css\");\n// An array of (file_name, file_conten"
},
{
"path": "crates/mdbook-html/src/theme/mod.rs",
"chars": 12950,
"preview": "//! Support for theme files.\n\nuse anyhow::Result;\nuse mdbook_core::config::HtmlConfig;\nuse mdbook_core::utils::fs;\nuse s"
},
{
"path": "crates/mdbook-html/src/theme/playground_editor.rs",
"chars": 592,
"preview": "//! Theme dependencies for the playground editor.\n\npub(crate) static JS: &[u8] = include_bytes!(\"../../front-end/playgro"
},
{
"path": "crates/mdbook-html/src/theme/searcher.rs",
"chars": 405,
"preview": "//! Theme dependencies for in-browser search. Not included in mdbook when\n//! the \"search\" cargo feature is disabled.\n\np"
},
{
"path": "crates/mdbook-html/src/utils.rs",
"chars": 4580,
"preview": "//! Utilities for processing HTML.\n\nuse std::collections::HashSet;\nuse std::path::{Component, Path, PathBuf};\n\n/// Utili"
},
{
"path": "crates/mdbook-markdown/Cargo.toml",
"chars": 334,
"preview": "[package]\nname = \"mdbook-markdown\"\nversion = \"0.5.2\"\ndescription = \"Markdown processing used in mdBook\"\nedition.workspac"
},
{
"path": "crates/mdbook-markdown/README.md",
"chars": 849,
"preview": "# mdbook-markdown\n\n[](https://docs.rs/mdbook-markdown)\n[!"
},
{
"path": "crates/mdbook-markdown/src/lib.rs",
"chars": 1857,
"preview": "//! Markdown processing used in mdBook.\n//!\n//! This crate provides functions for processing Markdown in the same way as"
},
{
"path": "crates/mdbook-preprocessor/Cargo.toml",
"chars": 381,
"preview": "[package]\nname = \"mdbook-preprocessor\"\nversion = \"0.5.2\"\ndescription = \"Library to assist implementing an mdBook preproc"
},
{
"path": "crates/mdbook-preprocessor/README.md",
"chars": 853,
"preview": "# mdbook-preprocessor\n\n[](https://docs.rs/mdbook-prep"
},
{
"path": "crates/mdbook-preprocessor/src/lib.rs",
"chars": 2979,
"preview": "//! Library to assist implementing an mdbook preprocessor.\n//!\n//! This library is used to implement a\n//! [preprocessor"
},
{
"path": "crates/mdbook-renderer/Cargo.toml",
"chars": 373,
"preview": "[package]\nname = \"mdbook-renderer\"\nversion = \"0.5.2\"\ndescription = \"Library to assist implementing an mdBook renderer\"\ne"
},
{
"path": "crates/mdbook-renderer/README.md",
"chars": 824,
"preview": "# mdbook-renderer\n\n[](https://docs.rs/mdbook-renderer)\n[!"
},
{
"path": "crates/mdbook-renderer/src/lib.rs",
"chars": 3106,
"preview": "//! Library to assist implementing an mdbook renderer.\n//!\n//! This library is used to implement a\n//! [renderer](https:"
},
{
"path": "crates/mdbook-summary/Cargo.toml",
"chars": 401,
"preview": "[package]\nname = \"mdbook-summary\"\nversion = \"0.5.2\"\ndescription = \"Summary parser for mdBook\"\nedition.workspace = true\nl"
},
{
"path": "crates/mdbook-summary/README.md",
"chars": 832,
"preview": "# mdbook-summary\n\n[](https://docs.rs/mdbook-summary)\n["
},
{
"path": "crates/xtask/src/changelog.rs",
"chars": 3760,
"preview": "//! Helper to generate a changelog for a new release.\n\nuse super::Result;\nuse std::fs;\nuse std::process::Command;\nuse st"
},
{
"path": "crates/xtask/src/main.rs",
"chars": 4339,
"preview": "//! Helper for local development.\n\nuse std::collections::BTreeMap;\nuse std::error::Error;\nuse std::io::Write;\nuse std::p"
},
{
"path": "eslint.config.mjs",
"chars": 2923,
"preview": "import { defineConfig, globalIgnores } from \"eslint/config\";\n\n// Custom preprocessor to strip Handlebars templates.\ncons"
},
{
"path": "examples/nop-preprocessor.rs",
"chars": 5194,
"preview": "//! A basic example of a preprocessor that does nothing.\n\nuse crate::nop_lib::Nop;\nuse clap::{Arg, ArgMatches, Command};"
},
{
"path": "examples/remove-emphasis/.gitignore",
"chars": 5,
"preview": "book\n"
},
{
"path": "examples/remove-emphasis/book.toml",
"chars": 146,
"preview": "[book]\ntitle = \"remove-emphasis\"\n\n[preprocessor.remove-emphasis]\ncommand = \"cargo run --manifest-path=mdbook-remove-emph"
},
{
"path": "examples/remove-emphasis/mdbook-remove-emphasis/Cargo.toml",
"chars": 399,
"preview": "[package]\nname = \"mdbook-remove-emphasis\"\nversion = \"0.1.0\"\nedition.workspace = true\npublish = false\n\n[dependencies]\nmdb"
},
{
"path": "examples/remove-emphasis/mdbook-remove-emphasis/src/main.rs",
"chars": 2146,
"preview": "//! This is a demonstration of an mdBook preprocessor which parses markdown\n//! and removes any instances of emphasis.\n\n"
},
{
"path": "examples/remove-emphasis/src/SUMMARY.md",
"chars": 41,
"preview": "# Summary\n\n- [Chapter 1](./chapter_1.md)\n"
},
{
"path": "examples/remove-emphasis/src/chapter_1.md",
"chars": 62,
"preview": "# Chapter 1\n\nThis has *light emphasis* and **bold emphasis**.\n"
},
{
"path": "examples/remove-emphasis/test.rs",
"chars": 534,
"preview": "//! A test to ensure that the remove-emphasis example works.\n\n#[test]\nfn remove_emphasis_works() {\n // Tests that the"
},
{
"path": "guide/book.toml",
"chars": 961,
"preview": "[book]\ntitle = \"mdBook Documentation\"\ndescription = \"Create book from markdown files. Like Gitbook but implemented in Ru"
},
{
"path": "guide/guide-helper/Cargo.toml",
"chars": 309,
"preview": "[package]\nname = \"guide-helper\"\npublish = false\nedition.workspace = true\nlicense.workspace = true\nrepository.workspace ="
},
{
"path": "guide/guide-helper/src/lib.rs",
"chars": 1823,
"preview": "//! Preprocessor for the mdBook guide.\n\nuse mdbook_preprocessor::book::Book;\nuse mdbook_preprocessor::errors::Result;\nus"
},
{
"path": "guide/guide-helper/src/main.rs",
"chars": 501,
"preview": "//! Preprocessor for the mdBook guide.\n\nfn main() {\n let mut args = std::env::args().skip(1);\n match args.next().a"
},
{
"path": "guide/src/404.md",
"chars": 79,
"preview": "# Document not found (404)\n\nThis URL is invalid, sorry. Try the search instead!"
},
{
"path": "guide/src/README.md",
"chars": 2316,
"preview": "# Introduction\n\n<style>\n .mdbook-version {\n position: absolute;\n right: 20px;\n top: 60px;\n "
},
{
"path": "guide/src/SUMMARY.md",
"chars": 1425,
"preview": "# Summary\n\n[Introduction](README.md)\n\n# User guide\n\n- [Installation](guide/installation.md)\n- [Reading books](guide/read"
},
{
"path": "guide/src/cli/README.md",
"chars": 857,
"preview": "# Command-line tool\n\nThe `mdbook` command-line tool is used to create and build books.\nAfter you have [installed](../gui"
},
{
"path": "guide/src/cli/arg-watcher.md",
"chars": 706,
"preview": "#### `--watcher`\n\nThere are different backends used to determine when a file has changed.\n\n* `poll` (default) --- Checks"
},
{
"path": "guide/src/cli/build.md",
"chars": 1230,
"preview": "# The build command\n\nThe build command is used to render your book:\n\n```bash\nmdbook build\n```\n\nIt will try to parse your"
},
{
"path": "guide/src/cli/clean.md",
"chars": 735,
"preview": "# The clean command\n\nThe clean command is used to delete the generated book and any other build\nartifacts.\n\n```bash\nmdbo"
},
{
"path": "guide/src/cli/completions.md",
"chars": 871,
"preview": "# The completions command\n\nThe completions command is used to generate auto-completions for some common shells.\nThis mea"
},
{
"path": "guide/src/cli/init.md",
"chars": 2158,
"preview": "# The init command\n\nThere is some minimal boilerplate that is the same for every new book. It's for\nthis purpose that md"
},
{
"path": "guide/src/cli/serve.md",
"chars": 1922,
"preview": "# The serve command\n\nThe serve command is used to preview a book by serving it via HTTP at\n`localhost:3000` by default: "
},
{
"path": "guide/src/cli/test.md",
"chars": 2046,
"preview": "# The test command\n\nWhen writing a book, you sometimes need to automate some tests. For example,\n[The Rust Programming B"
},
{
"path": "guide/src/cli/watch.md",
"chars": 1503,
"preview": "# The watch command\n\nThe `watch` command is useful when you want your book to be rendered on every\nfile change. You coul"
},
{
"path": "guide/src/continuous-integration.md",
"chars": 6077,
"preview": "# Running `mdbook` in continuous integration\n\nThere are a variety of services such as [GitHub Actions] or [GitLab CI/CD]"
},
{
"path": "guide/src/for_developers/README.md",
"chars": 1866,
"preview": "# For developers\n\nWhile `mdbook` is mainly used as a command line tool, you can also import the\nunderlying libraries dir"
},
{
"path": "guide/src/for_developers/backends.md",
"chars": 10985,
"preview": "# Alternative backends\n\nA \"backend\" is simply a program which `mdbook` will invoke during the book\nrendering process. Th"
},
{
"path": "guide/src/for_developers/mdbook-wordcount/Cargo.toml",
"chars": 208,
"preview": "[package]\nname = \"mdbook-wordcount\"\nversion = \"0.1.0\"\nauthors = [\"Michael Bryan <michaelfbryan@gmail.com>\"]\n\n[dependenci"
},
{
"path": "guide/src/for_developers/mdbook-wordcount/src/main.rs",
"chars": 1379,
"preview": "extern crate mdbook;\nextern crate serde;\n#[macro_use]\nextern crate serde_derive;\n\nuse std::process;\nuse std::fs::{self, "
},
{
"path": "guide/src/for_developers/preprocessors.md",
"chars": 5504,
"preview": "# Preprocessors\n\nA *preprocessor* is simply a bit of code which gets run immediately after the\nbook is loaded and before"
},
{
"path": "guide/src/format/README.md",
"chars": 177,
"preview": "# Format\n\nIn this section you will learn how to:\n\n- Structure your book correctly\n- Format your `SUMMARY.md` file\n- Conf"
},
{
"path": "guide/src/format/configuration/README.md",
"chars": 556,
"preview": "# Configuration\n\nThis section details the configuration options available in the ***book.toml***:\n- **[General]** config"
},
{
"path": "guide/src/format/configuration/environment-variables.md",
"chars": 1500,
"preview": "# Environment variables\n\nAll configuration values can be overridden from the command line by setting the\ncorresponding e"
},
{
"path": "guide/src/format/configuration/general.md",
"chars": 4012,
"preview": "# General configuration\n\nYou can configure the parameters for your book in the ***book.toml*** file.\n\nHere is an example"
},
{
"path": "guide/src/format/configuration/preprocessors.md",
"chars": 3432,
"preview": "# Configuring Preprocessors\n\nPreprocessors are extensions that can modify the raw Markdown source before it gets sent to"
},
{
"path": "guide/src/format/configuration/renderers.md",
"chars": 16229,
"preview": "# Configuring Renderers\n\nRenderers (also called \"backends\") are responsible for creating the output of the book.\n\nThe fo"
},
{
"path": "guide/src/format/example.rs",
"chars": 149,
"preview": "fn main() {\n println!(\"Hello World!\");\n#\n# // You can even hide lines! :D\n# println!(\"I am hidden! Expand the"
},
{
"path": "guide/src/format/markdown.md",
"chars": 8876,
"preview": "# Markdown\n\nmdBook's [parser](https://github.com/raphlinus/pulldown-cmark) adheres to the [CommonMark](https://commonmar"
},
{
"path": "guide/src/format/mathjax.md",
"chars": 1225,
"preview": "# MathJax support\n\nmdBook has optional support for math equations through\n[MathJax](https://www.mathjax.org/).\n\nTo enabl"
},
{
"path": "guide/src/format/mdbook.md",
"chars": 9909,
"preview": "# mdBook-specific features\n\n## Hiding code lines\n\nThere is a feature in mdBook that lets you hide code lines by prependi"
},
{
"path": "guide/src/format/summary.md",
"chars": 3783,
"preview": "# SUMMARY.md\n\nThe summary file is used by mdBook to know what chapters to include, in what\norder they should appear, wha"
},
{
"path": "guide/src/format/theme/README.md",
"chars": 2663,
"preview": "# Theme\n\nThe default renderer uses a [handlebars](https://handlebarsjs.com) template to\nrender your markdown files and c"
},
{
"path": "guide/src/format/theme/editor.md",
"chars": 1110,
"preview": "# Editor\n\nIn addition to providing runnable code playgrounds, mdBook optionally allows them\nto be editable. In order to "
},
{
"path": "guide/src/format/theme/index-hbs.md",
"chars": 4157,
"preview": "# index.hbs\n\n`index.hbs` is the handlebars template that is used to render the book. The\nmarkdown files are processed to"
},
{
"path": "guide/src/format/theme/syntax-highlighting.md",
"chars": 1783,
"preview": "# Syntax highlighting\n\nmdBook uses [Highlight.js](https://highlightjs.org) with a custom theme\nfor syntax highlighting.\n"
},
{
"path": "guide/src/guide/README.md",
"chars": 188,
"preview": "# User guide\n\nThis user guide provides an introduction to basic concepts of using mdBook.\n\n- [Installation](installation"
},
{
"path": "guide/src/guide/creating.md",
"chars": 3985,
"preview": "# Creating a book\n\nOnce you have the `mdbook` CLI tool installed, you can use it to create and render a book.\n\n## Initia"
},
{
"path": "guide/src/guide/installation.md",
"chars": 2248,
"preview": "# Installation\n\nThere are multiple ways to install the mdBook CLI tool.\nChoose any one of the methods below that best su"
},
{
"path": "guide/src/guide/reading.md",
"chars": 3762,
"preview": "# Reading books\n\nThis chapter gives an introduction on how to interact with a book produced by mdBook.\nThis assumes you "
},
{
"path": "guide/src/misc/contributors.md",
"chars": 1101,
"preview": "# Contributors\n\nHere is a list of the contributors who have helped improving mdBook. Big\nshout-out to them!\n\n- [mdinger]"
},
{
"path": "rustfmt.toml",
"chars": 23,
"preview": "style_edition = \"2024\"\n"
},
{
"path": "src/cmd/build.rs",
"chars": 922,
"preview": "use super::command_prelude::*;\nuse crate::{get_book_dir, open};\nuse anyhow::Result;\nuse mdbook_driver::MDBook;\nuse traci"
},
{
"path": "src/cmd/clean.rs",
"chars": 3747,
"preview": "use super::command_prelude::*;\nuse crate::get_book_dir;\nuse anyhow::Context;\nuse anyhow::Result;\nuse mdbook_driver::MDBo"
},
{
"path": "src/cmd/command_prelude.rs",
"chars": 2105,
"preview": "//! Helpers for building the command-line arguments for commands.\n\npub use clap::{Arg, ArgMatches, Command, arg};\nuse md"
},
{
"path": "src/cmd/init.rs",
"chars": 3845,
"preview": "use crate::get_book_dir;\nuse anyhow::Result;\nuse clap::{ArgMatches, Command as ClapCommand, arg};\nuse mdbook_core::confi"
},
{
"path": "src/cmd/mod.rs",
"chars": 214,
"preview": "//! Subcommand modules for the `mdbook` binary.\n\npub mod build;\npub mod clean;\npub mod command_prelude;\npub mod init;\n#["
},
{
"path": "src/cmd/serve.rs",
"chars": 4911,
"preview": "use super::command_prelude::*;\n#[cfg(feature = \"watch\")]\nuse super::watch;\nuse crate::{get_book_dir, open};\nuse anyhow::"
},
{
"path": "src/cmd/test.rs",
"chars": 1558,
"preview": "use super::command_prelude::*;\nuse crate::get_book_dir;\nuse anyhow::Result;\nuse clap::ArgAction;\nuse clap::builder::NonE"
},
{
"path": "src/cmd/watch/native.rs",
"chars": 6323,
"preview": "//! A filesystem watcher using native operating system facilities.\n\nuse ignore::gitignore::Gitignore;\nuse mdbook_driver:"
},
{
"path": "src/cmd/watch/poller.rs",
"chars": 13095,
"preview": "//! A simple poll-based filesystem watcher.\n//!\n//! This exists because the native change notifications have historicall"
},
{
"path": "src/cmd/watch.rs",
"chars": 1993,
"preview": "use super::command_prelude::*;\nuse crate::{get_book_dir, open};\nuse anyhow::Result;\nuse mdbook_driver::MDBook;\nuse std::"
},
{
"path": "src/main.rs",
"chars": 4974,
"preview": "//! The mdbook CLI.\n\n#![allow(unreachable_pub, reason = \"not needed in a bin crate\")]\n\nuse anyhow::anyhow;\nuse clap::{Ar"
},
{
"path": "tests/gui/books/all-summary/README.md",
"chars": 94,
"preview": "# All summary\n\nThis GUI test book tests all the different kinds of book items in the summary.\n"
},
{
"path": "tests/gui/books/all-summary/book.toml",
"chars": 29,
"preview": "[book]\ntitle = \"all-summary\"\n"
},
{
"path": "tests/gui/books/all-summary/src/SUMMARY.md",
"chars": 237,
"preview": "# Summary\n\n[Prefix 1](prefix-1.md)\n[Prefix 2](prefix-2.md)\n\n- [Introduction](intro.md)\n- [Draft]()\n\n# Part 1\n\n- [P1 C1]("
},
{
"path": "tests/gui/books/all-summary/src/intro.md",
"chars": 15,
"preview": "# Introduction\n"
},
{
"path": "tests/gui/books/all-summary/src/part-1/chapter-1.md",
"chars": 8,
"preview": "# P1 C1\n"
},
{
"path": "tests/gui/books/all-summary/src/part-2/chapter-1.md",
"chars": 8,
"preview": "# P2 C1\n"
},
{
"path": "tests/gui/books/all-summary/src/prefix-1.md",
"chars": 11,
"preview": "# Prefix 1\n"
},
{
"path": "tests/gui/books/all-summary/src/prefix-2.md",
"chars": 11,
"preview": "# Prefix 2\n"
},
{
"path": "tests/gui/books/all-summary/src/suffix-1.md",
"chars": 11,
"preview": "# Suffix 1\n"
},
{
"path": "tests/gui/books/all-summary/src/suffix-2.md",
"chars": 11,
"preview": "# Suffix 2\n"
},
{
"path": "tests/gui/books/basic/book.toml",
"chars": 23,
"preview": "[book]\ntitle = \"basic\"\n"
},
{
"path": "tests/gui/books/basic/src/SUMMARY.md",
"chars": 41,
"preview": "# Summary\n\n- [Chapter 1](./chapter_1.md)\n"
},
{
"path": "tests/gui/books/basic/src/chapter_1.md",
"chars": 12,
"preview": "# Chapter 1\n"
},
{
"path": "tests/gui/books/heading-nav/README.md",
"chars": 82,
"preview": "# Heading nav\n\nThis GUI test book is used for testing sidebar heading navigation.\n"
},
{
"path": "tests/gui/books/heading-nav/book.toml",
"chars": 29,
"preview": "[book]\ntitle = \"heading-nav\"\n"
},
{
"path": "tests/gui/books/heading-nav/src/SUMMARY.md",
"chars": 365,
"preview": "# Summary\n\n- [Empty page](empty.md)\n- [Large text before first heading](large-intro.md)\n- [Normal text before first head"
},
{
"path": "tests/gui/books/heading-nav/src/collapsed.md",
"chars": 418,
"preview": "# Collapsed headings\n\nTests collapsed headings.\n\n## Heading 1\n\n1\\\n2\\\n3\\\n4\\\n5\n\n### Heading 1.1\n\n1\\\n2\\\n3\\\n4\\\n5\n\n### Headin"
},
{
"path": "tests/gui/books/heading-nav/src/current-to-bottom.md",
"chars": 1080,
"preview": "# Current scrolls to bottom\n\nChecks that the \"current\" header works even when there are headers near the bottom.\n\n## Fir"
},
{
"path": "tests/gui/books/heading-nav/src/empty.md",
"chars": 13,
"preview": "# Empty page\n"
},
{
"path": "tests/gui/books/heading-nav/src/filtered-headings.md",
"chars": 65,
"preview": "# Filtered headings\n\n## Skateboard\n\nChecking for search marking.\n"
},
{
"path": "tests/gui/books/heading-nav/src/large-intro.md",
"chars": 261,
"preview": "# Large text before first heading\n\nThis tests what happens if there is a lot of text before the first header, which is o"
},
{
"path": "tests/gui/books/heading-nav/src/markup.md",
"chars": 480,
"preview": "# Headings with markup\n\nTests that heading markup gets copied to the sidebar.\n\n## Heading with `code` or *italic* or **b"
},
{
"path": "tests/gui/books/heading-nav/src/normal-intro.md",
"chars": 190,
"preview": "# Normal text before first heading\n\nThis test is to ensure the first heading shows up as \"current\" on page load.\n\n## The"
},
{
"path": "tests/gui/books/heading-nav/src/unusual-heading-levels.md",
"chars": 88,
"preview": "# Unusual heading levels\n\n### Heading 3\n\n## Heading 2\n\n#### Heading 5\n\n#### Heading 5.1\n"
},
{
"path": "tests/gui/books/heading-nav-folded/book.toml",
"chars": 80,
"preview": "[book]\ntitle = \"heading-nav-folded\"\n\n[output.html.fold]\nenable = true\nlevel = 0\n"
}
]
// ... and 401 more files (download for full content)
About this extraction
This page contains the full source code of the rust-lang/mdBook GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 601 files (1.5 MB), approximately 457.0k tokens, and a symbol index with 984 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.