mirror of
https://github.com/rust-lang/mdBook.git
synced 2025-12-28 12:41:16 -05:00
Compare commits
134 Commits
v0.5.0-alp
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b29f8a717 | ||
|
|
94569a42da | ||
|
|
97747621aa | ||
|
|
723d9df6c7 | ||
|
|
45e2158e84 | ||
|
|
59017ea918 | ||
|
|
f857ab294c | ||
|
|
938a9126b0 | ||
|
|
23724b0a6b | ||
|
|
7bdea7c085 | ||
|
|
2bcae6b0a9 | ||
|
|
6457b381d8 | ||
|
|
9eb6fe0483 | ||
|
|
674733864f | ||
|
|
3d39bf4adb | ||
|
|
55830b9fca | ||
|
|
8bd3c52abf | ||
|
|
de8202a67f | ||
|
|
8f277a0d39 | ||
|
|
d63aeb6526 | ||
|
|
eb83d080f6 | ||
|
|
710ec2755d | ||
|
|
5d64d0e5f2 | ||
|
|
718ceecfa2 | ||
|
|
09616e31af | ||
|
|
7e7a3b495e | ||
|
|
d39deca76a | ||
|
|
8385e750ec | ||
|
|
8571d70b52 | ||
|
|
4b5ea14ee1 | ||
|
|
c53379e3ac | ||
|
|
6bf7fadc29 | ||
|
|
d193775a3b | ||
|
|
8e4bc4aecd | ||
|
|
2afad43bdd | ||
|
|
5445458d1a | ||
|
|
ef476a7329 | ||
|
|
262afdc2f8 | ||
|
|
ef10e720a5 | ||
|
|
fff6087f36 | ||
|
|
922f0d8ad4 | ||
|
|
ab1325b213 | ||
|
|
63b159741b | ||
|
|
4a9a517f27 | ||
|
|
700839f77f | ||
|
|
152132458e | ||
|
|
054da77b6a | ||
|
|
9a5e8dbb0a | ||
|
|
63c45cd879 | ||
|
|
bc7ca458b6 | ||
|
|
07fb33f5da | ||
|
|
7d1566860c | ||
|
|
f0117ec3df | ||
|
|
22065ebc79 | ||
|
|
5905bf1d85 | ||
|
|
1646e4923a | ||
|
|
1e190137c3 | ||
|
|
4417f8cb0a | ||
|
|
cc7f8be496 | ||
|
|
051fc9f01d | ||
|
|
d0bde467e0 | ||
|
|
475951c9ee | ||
|
|
5b2cc1735b | ||
|
|
1c00395230 | ||
|
|
9799326590 | ||
|
|
2546c8cc60 | ||
|
|
33c9b4063e | ||
|
|
f66fd92f32 | ||
|
|
541e16335b | ||
|
|
6cc40cb5f7 | ||
|
|
37f8a79d4d | ||
|
|
385246a9ef | ||
|
|
7619f9a91c | ||
|
|
f27c3aea4c | ||
|
|
b3bd103742 | ||
|
|
7e5fa3565b | ||
|
|
6d9f49cbc5 | ||
|
|
8670bcc540 | ||
|
|
005f4d648a | ||
|
|
59343b525d | ||
|
|
e8d7dd6f57 | ||
|
|
54175698d5 | ||
|
|
07ed00e8f7 | ||
|
|
ab8a4dfa5a | ||
|
|
e2c954f693 | ||
|
|
b2111a3f91 | ||
|
|
8ba833feb2 | ||
|
|
7124f4c7de | ||
|
|
1cc4cbb202 | ||
|
|
405f407260 | ||
|
|
eaa778bebd | ||
|
|
a17c1d1b95 | ||
|
|
8a27d1b7ac | ||
|
|
d6cd50b601 | ||
|
|
68d9bcfec4 | ||
|
|
3fa49214ad | ||
|
|
ddf02e0c0c | ||
|
|
3992bc18f5 | ||
|
|
49f9c9741e | ||
|
|
f84b1a15b6 | ||
|
|
ac11e00aa2 | ||
|
|
860e8d109e | ||
|
|
adcbd117da | ||
|
|
08d9fddfc9 | ||
|
|
118c1096ea | ||
|
|
18813516e1 | ||
|
|
a6944683e6 | ||
|
|
f27ae21825 | ||
|
|
58af25384d | ||
|
|
51a80febb3 | ||
|
|
7945ac8e8c | ||
|
|
a097fe6232 | ||
|
|
4b5004b621 | ||
|
|
7b7dee4a4e | ||
|
|
5282083dec | ||
|
|
816913bd72 | ||
|
|
1620858032 | ||
|
|
4a07076896 | ||
|
|
3a2705d742 | ||
|
|
b0229e76a5 | ||
|
|
a43ef4ca4b | ||
|
|
780fd83cac | ||
|
|
d5406c8dff | ||
|
|
5e7b6d7d9d | ||
|
|
07d2989486 | ||
|
|
5fe7e9531d | ||
|
|
f958a0e8cf | ||
|
|
dbad189b26 | ||
|
|
4a06e067c5 | ||
|
|
98a093a0ff | ||
|
|
9b5c57bf48 | ||
|
|
87e9cc0ac3 | ||
|
|
e37e5314f8 | ||
|
|
4913bf82f1 |
@@ -1,4 +1,26 @@
|
||||
# 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
|
||||
|
||||
1
.github/workflows/deploy.yml
vendored
1
.github/workflows/deploy.yml
vendored
@@ -54,6 +54,7 @@ jobs:
|
||||
permissions:
|
||||
# Required for OIDC token exchange
|
||||
id-token: write
|
||||
environment: publish
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Install Rust (rustup)
|
||||
|
||||
6
.github/workflows/main.yml
vendored
6
.github/workflows/main.yml
vendored
@@ -78,9 +78,9 @@ jobs:
|
||||
- name: Install Rust
|
||||
run: bash ci/install-rust.sh stable x86_64-unknown-linux-gnu
|
||||
- name: Install npm
|
||||
uses: actions/setup-node@v5
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 22
|
||||
node-version: 24
|
||||
- name: Install browser-ui-test
|
||||
run: npm install
|
||||
- name: Run eslint
|
||||
@@ -119,7 +119,7 @@ jobs:
|
||||
- name: Install cargo-semver-checks
|
||||
run: |
|
||||
mkdir installed-bins
|
||||
curl -Lf https://github.com/obi1kenobi/cargo-semver-checks/releases/download/v0.44.0/cargo-semver-checks-x86_64-unknown-linux-gnu.tar.gz \
|
||||
curl -Lf https://github.com/obi1kenobi/cargo-semver-checks/releases/download/v0.45.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
|
||||
|
||||
1
.github/workflows/update-dependencies.yml
vendored
1
.github/workflows/update-dependencies.yml
vendored
@@ -8,6 +8,7 @@ jobs:
|
||||
update:
|
||||
name: Update dependencies
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'rust-lang/mdBook'
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Install Rust
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -8,7 +8,7 @@ guide/book
|
||||
|
||||
.vscode
|
||||
tests/dummy_book/book/
|
||||
test_book/book/
|
||||
tests/gui/books/*/book/
|
||||
tests/testsuite/*/*/book/
|
||||
|
||||
# Ignore Jetbrains specific files.
|
||||
|
||||
157
CHANGELOG.md
157
CHANGELOG.md
@@ -1,16 +1,77 @@
|
||||
# Changelog
|
||||
|
||||
### 0.5 Migration Guide
|
||||
## mdBook 0.5.2
|
||||
[v0.5.1...v0.5.2](https://github.com/rust-lang/mdBook/compare/v0.5.1...v0.5.2)
|
||||
|
||||
During the pre-release phase of the 0.5 release, the documentation may be found at <https://rust-lang.github.io/mdBook/pre-release/>.
|
||||
### 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:
|
||||
|
||||
#### Config changes
|
||||
### 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)
|
||||
@@ -34,19 +95,23 @@ The following is a summary of the changes that may require your attention when u
|
||||
[#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
|
||||
### 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
|
||||
### 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.
|
||||
- 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)
|
||||
@@ -58,15 +123,22 @@ The following is a summary of the changes that may require your attention when u
|
||||
[#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
|
||||
### 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
|
||||
### 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.
|
||||
@@ -76,9 +148,13 @@ The following is a summary of the changes that may require your attention when u
|
||||
- [`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 rexported from the other crates as appropriate.
|
||||
- [`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.
|
||||
@@ -102,6 +178,69 @@ The following is a summary of the changes that may require your attention when u
|
||||
- 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)
|
||||
|
||||
|
||||
@@ -185,9 +185,7 @@ If you want to disable the headless mode, use the `--disable-headless-test` opti
|
||||
cargo test --test gui -- --disable-headless-test
|
||||
```
|
||||
|
||||
The GUI tests are in the directory `tests/gui` in text files with the `.goml` extension. 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).
|
||||
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
|
||||
|
||||
@@ -215,7 +213,7 @@ The following are instructions for updating [highlight.js](https://highlightjs.o
|
||||
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 [test_book](https://github.com/rust-lang/mdBook/tree/master/test_book) contains a chapter with many languages to examine.
|
||||
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
|
||||
|
||||
@@ -223,7 +221,7 @@ 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`
|
||||
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`.
|
||||
|
||||
843
Cargo.lock
generated
843
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
58
Cargo.toml
58
Cargo.toml
@@ -25,10 +25,10 @@ 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.98"
|
||||
axum = "0.8.4"
|
||||
clap = { version = "4.5.41", features = ["cargo", "wrap_help"] }
|
||||
clap_complete = "4.5.55"
|
||||
anyhow = "1.0.100"
|
||||
axum = "0.8.7"
|
||||
clap = { version = "4.5.53", features = ["cargo", "wrap_help"] }
|
||||
clap_complete = "4.5.61"
|
||||
ego-tree = "0.10.0"
|
||||
elasticlunr-rs = "3.0.2"
|
||||
font-awesome-as-a-crate = "0.3.0"
|
||||
@@ -36,42 +36,42 @@ futures-util = "0.3.31"
|
||||
glob = "0.3.3"
|
||||
handlebars = "6.3.2"
|
||||
hex = "0.4.3"
|
||||
html5ever = "0.35.0"
|
||||
indexmap = "2.10.0"
|
||||
ignore = "0.4.23"
|
||||
mdbook-core = { path = "crates/mdbook-core", version = "0.5.0-alpha.1" }
|
||||
mdbook-driver = { path = "crates/mdbook-driver", version = "0.5.0-alpha.1" }
|
||||
mdbook-html = { path = "crates/mdbook-html", version = "0.5.0-alpha.1" }
|
||||
mdbook-markdown = { path = "crates/mdbook-markdown", version = "0.5.0-alpha.1" }
|
||||
mdbook-preprocessor = { path = "crates/mdbook-preprocessor", version = "0.5.0-alpha.1" }
|
||||
mdbook-renderer = { path = "crates/mdbook-renderer", version = "0.5.0-alpha.1" }
|
||||
mdbook-summary = { path = "crates/mdbook-summary", version = "0.5.0-alpha.1" }
|
||||
memchr = "2.7.5"
|
||||
notify = "8.1.0"
|
||||
html5ever = "0.36.0"
|
||||
indexmap = "2.12.1"
|
||||
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.7.6"
|
||||
notify = "8.2.0"
|
||||
notify-debouncer-mini = "0.7.0"
|
||||
opener = "0.8.2"
|
||||
opener = "0.8.3"
|
||||
pathdiff = "0.2.3"
|
||||
pulldown-cmark = { version = "0.13.0", default-features = false, features = ["html"] } # Do not update, part of the public api.
|
||||
regex = "1.11.1"
|
||||
regex = "1.12.2"
|
||||
select = "0.6.1"
|
||||
semver = "1.0.26"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
serde_json = "1.0.140"
|
||||
semver = "1.0.27"
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
serde_json = "1.0.145"
|
||||
sha2 = "0.10.9"
|
||||
shlex = "1.3.0"
|
||||
snapbox = "0.6.21"
|
||||
tempfile = "3.20.0"
|
||||
tokio = "1.46.1"
|
||||
toml = "0.9.2"
|
||||
snapbox = "0.6.23"
|
||||
tempfile = "3.23.0"
|
||||
tokio = "1.48.0"
|
||||
toml = "0.9.8"
|
||||
topological-sort = "0.2.2"
|
||||
tower-http = "0.6.6"
|
||||
tracing = "0.1.41"
|
||||
tracing-subscriber = { version = "0.3.20", features = ["env-filter"] }
|
||||
tower-http = "0.6.7"
|
||||
tracing = "0.1.43"
|
||||
tracing-subscriber = { version = "0.3.22", features = ["env-filter"] }
|
||||
walkdir = "2.5.0"
|
||||
|
||||
[package]
|
||||
name = "mdbook"
|
||||
version = "0.5.0-alpha.1"
|
||||
version = "0.5.2"
|
||||
authors = [
|
||||
"Mathieu David <mathieudavid@mathieudavid.org>",
|
||||
"Michael-F-Bryan <michaelfbryan@gmail.com>",
|
||||
|
||||
@@ -104,7 +104,7 @@ fn tidy(path: &Path) {
|
||||
|
||||
fn diff(a: &Path, b: &Path) {
|
||||
let args = "diff --no-index";
|
||||
println!("running `git diff {args} {a:?} {b:?}`");
|
||||
println!("running `git {args} {a:?} {b:?}`");
|
||||
Command::new("git")
|
||||
.args(args.split(' '))
|
||||
.args([a, b])
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mdbook-core"
|
||||
version = "0.5.0-alpha.1"
|
||||
version = "0.5.2"
|
||||
description = "The base support library for mdbook, intended for internal use only"
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
//! # run().unwrap()
|
||||
//! ```
|
||||
|
||||
use crate::static_regex;
|
||||
use crate::utils::{TomlExt, fs, log_backtrace};
|
||||
use anyhow::{Context, Error, Result, bail};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -123,11 +124,10 @@ impl Config {
|
||||
///
|
||||
/// For example:
|
||||
///
|
||||
/// - `MDBOOK_foo` -> `foo`
|
||||
/// - `MDBOOK_FOO` -> `foo`
|
||||
/// - `MDBOOK_FOO__BAR` -> `foo.bar`
|
||||
/// - `MDBOOK_FOO_BAR` -> `foo-bar`
|
||||
/// - `MDBOOK_FOO_bar__baz` -> `foo-bar.baz`
|
||||
/// - `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`.
|
||||
@@ -147,34 +147,32 @@ impl Config {
|
||||
/// 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) {
|
||||
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 {
|
||||
if key == "log" {
|
||||
// MDBOOK_LOG is used to control logging.
|
||||
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;
|
||||
}
|
||||
trace!("{} => {}", key, value);
|
||||
let parsed_value = serde_json::from_str(&value)
|
||||
.unwrap_or_else(|_| serde_json::Value::String(value.to_string()));
|
||||
|
||||
if key == "book" || key == "build" {
|
||||
if let serde_json::Value::Object(ref map) = parsed_value {
|
||||
// To `set` each `key`, we wrap them as `prefix.key`
|
||||
for (k, v) in map {
|
||||
let full_key = format!("{key}.{k}");
|
||||
self.set(&full_key, v).expect("unreachable");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self.set(key, parsed_value).expect("unreachable");
|
||||
self.set(key, parsed_value)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get a value from the configuration.
|
||||
@@ -204,11 +202,28 @@ impl Config {
|
||||
value
|
||||
.clone()
|
||||
.try_into()
|
||||
.with_context(|| "Failed to deserialize `{name}`")
|
||||
.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
|
||||
@@ -249,24 +264,39 @@ impl Config {
|
||||
/// `output.html.playground` will set the "playground" in the html output
|
||||
/// table).
|
||||
///
|
||||
/// The only way this can fail is if we can't serialize `value` into a
|
||||
/// `toml::Value`.
|
||||
/// # 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 let Some(key) = index.strip_prefix("book.") {
|
||||
self.book.update_value(key, 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);
|
||||
self.build.update_value(key, value)?;
|
||||
} else if let Some(key) = index.strip_prefix("rust.") {
|
||||
self.rust.update_value(key, value);
|
||||
self.rust.update_value(key, value)?;
|
||||
} else if let Some(key) = index.strip_prefix("output.") {
|
||||
self.output.update_value(key, value);
|
||||
self.output.update_value(key, value)?;
|
||||
} else if let Some(key) = index.strip_prefix("preprocessor.") {
|
||||
self.preprocessor.update_value(key, value);
|
||||
self.preprocessor.update_value(key, value)?;
|
||||
} else {
|
||||
bail!("invalid key `{index}`");
|
||||
}
|
||||
@@ -686,18 +716,13 @@ pub struct SearchChapterSettings {
|
||||
/// 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) {
|
||||
fn update_value<S: Serialize>(&mut self, key: &str, value: S) -> Result<()> {
|
||||
let mut raw = Value::try_from(&self).expect("unreachable");
|
||||
|
||||
if let Ok(value) = Value::try_from(value) {
|
||||
raw.insert(key, value);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Ok(updated) = raw.try_into() {
|
||||
*self = updated;
|
||||
}
|
||||
let value = Value::try_from(value)?;
|
||||
raw.insert(key, value);
|
||||
let updated = raw.try_into()?;
|
||||
*self = updated;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1147,4 +1172,38 @@ mod tests {
|
||||
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"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mdbook-driver"
|
||||
version = "0.5.0-alpha.1"
|
||||
version = "0.5.2"
|
||||
description = "High-level library for running mdBook"
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
@@ -27,3 +27,6 @@ tracing.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[features]
|
||||
search = ["mdbook-html/search"]
|
||||
|
||||
@@ -23,6 +23,12 @@
|
||||
//! for shared types. Types from this crate are rexported from the other
|
||||
//! crates as appropriate.
|
||||
//!
|
||||
//! ## Cargo features
|
||||
//!
|
||||
//! The following cargo features are available:
|
||||
//!
|
||||
//! - `search`: Enables the search index in the HTML renderer.
|
||||
//!
|
||||
//! ## Examples
|
||||
//!
|
||||
//! If creating a new book from scratch, you'll want to get a [`init::BookBuilder`] via
|
||||
|
||||
@@ -20,7 +20,7 @@ use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use tempfile::Builder as TempFileBuilder;
|
||||
use topological_sort::TopologicalSort;
|
||||
use tracing::{debug, error, info, trace, warn};
|
||||
use tracing::{debug, info, trace, warn};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
@@ -56,7 +56,7 @@ impl MDBook {
|
||||
Config::default()
|
||||
};
|
||||
|
||||
config.update_from_env();
|
||||
config.update_from_env()?;
|
||||
|
||||
if tracing::enabled!(tracing::Level::TRACE) {
|
||||
for line in format!("Config: {config:#?}").lines() {
|
||||
@@ -263,11 +263,6 @@ impl MDBook {
|
||||
}
|
||||
}
|
||||
|
||||
// Index Preprocessor is disabled so that chapter paths
|
||||
// continue to point to the actual markdown files.
|
||||
self.preprocessors = determine_preprocessors(&self.config, &self.root)?;
|
||||
self.preprocessors
|
||||
.shift_remove_entry(IndexPreprocessor::NAME);
|
||||
let (book, _) = self.preprocess_book(&TestRenderer)?;
|
||||
|
||||
let color_output = std::io::stderr().is_terminal();
|
||||
@@ -329,8 +324,8 @@ impl MDBook {
|
||||
|
||||
if !output.status.success() {
|
||||
failed = true;
|
||||
error!(
|
||||
"rustdoc returned an error:\n\
|
||||
eprintln!(
|
||||
"ERROR rustdoc returned an error:\n\
|
||||
\n--- stdout\n{}\n--- stderr\n{}",
|
||||
String::from_utf8_lossy(&output.stdout),
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mdbook-html"
|
||||
version = "0.5.0-alpha.1"
|
||||
version = "0.5.2"
|
||||
description = "mdBook HTML renderer"
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
@@ -13,7 +13,6 @@ Original by Dempfi (https://github.com/dempfi/ayu)
|
||||
.hljs-comment,
|
||||
.hljs-quote {
|
||||
color: #5c6773;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.hljs-variable,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* CSS for UI elements (a.k.a. chrome) */
|
||||
|
||||
html {
|
||||
scrollbar-color: var(--scrollbar) var(--bg);
|
||||
scrollbar-color: var(--scrollbar) transparent;
|
||||
}
|
||||
#mdbook-searchresults a,
|
||||
.content a:link,
|
||||
@@ -509,9 +509,9 @@ html:not(.sidebar-resizing) .sidebar {
|
||||
height: 16px;
|
||||
color: var(--icons);
|
||||
margin-inline-start: var(--sidebar-resize-indicator-space);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.sidebar-resize-handle .sidebar-resize-indicator::before {
|
||||
content: "";
|
||||
@@ -534,6 +534,11 @@ html:not(.sidebar-resizing) .sidebar {
|
||||
cursor: col-resize;
|
||||
width: calc(var(--sidebar-resize-indicator-width) - var(--sidebar-resize-indicator-space));
|
||||
}
|
||||
|
||||
html:not(.js) .sidebar-resize-handle {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* sidebar-hidden */
|
||||
#mdbook-sidebar-toggle-anchor:not(:checked) ~ .sidebar {
|
||||
transform: translateX(calc(0px - var(--sidebar-width) - var(--sidebar-resize-indicator-width)));
|
||||
@@ -571,17 +576,18 @@ html:not(.sidebar-resizing) .sidebar {
|
||||
line-height: 2.2em;
|
||||
}
|
||||
|
||||
.chapter ol {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.chapter li {
|
||||
display: flex;
|
||||
color: var(--sidebar-non-existant);
|
||||
}
|
||||
|
||||
/* This is a span wrapping the chapter link and the fold chevron. */
|
||||
.chapter-link-wrapper {
|
||||
/* Used to position the chevron to the right, allowing the text to wrap before it. */
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.chapter li a {
|
||||
display: block;
|
||||
padding: 0;
|
||||
/* Remove underlines. */
|
||||
text-decoration: none;
|
||||
color: var(--sidebar-fg);
|
||||
}
|
||||
@@ -594,21 +600,22 @@ html:not(.sidebar-resizing) .sidebar {
|
||||
color: var(--sidebar-active);
|
||||
}
|
||||
|
||||
.chapter li > a.toggle {
|
||||
/* This is the toggle chevron. */
|
||||
.chapter-fold-toggle {
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
/* Positions the chevron to the side. */
|
||||
margin-inline-start: auto;
|
||||
padding: 0 10px;
|
||||
user-select: none;
|
||||
opacity: 0.68;
|
||||
}
|
||||
|
||||
.chapter li > a.toggle div {
|
||||
.chapter-fold-toggle div {
|
||||
transition: transform 0.5s;
|
||||
}
|
||||
|
||||
/* collapse the section */
|
||||
.chapter li:not(.expanded) + li > ol {
|
||||
.chapter li:not(.expanded) > ol {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -617,10 +624,26 @@ html:not(.sidebar-resizing) .sidebar {
|
||||
margin-block-start: 0.6em;
|
||||
}
|
||||
|
||||
.chapter li.expanded > a.toggle div {
|
||||
/* When expanded, rotate the chevron to point down. */
|
||||
.chapter li.expanded > span > .chapter-fold-toggle div {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.chapter a.current-header {
|
||||
color: var(--sidebar-active);
|
||||
}
|
||||
|
||||
.on-this-page {
|
||||
margin-left: 22px;
|
||||
border-inline-start: 4px solid var(--sidebar-header-border-color);
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.on-this-page > ol {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
/* Horizontal line in chapter list. */
|
||||
.spacer {
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
@@ -630,6 +653,7 @@ html:not(.sidebar-resizing) .sidebar {
|
||||
background-color: var(--sidebar-spacer);
|
||||
}
|
||||
|
||||
/* On touch devices, add more vertical spacing to make it easier to tap links. */
|
||||
@media (-moz-touch-enabled: 1), (pointer: coarse) {
|
||||
.chapter li a { padding: 5px 0; }
|
||||
.spacer { margin: 10px 0; }
|
||||
@@ -730,21 +754,3 @@ html:not(.sidebar-resizing) .sidebar {
|
||||
/* mdbook's margin for h2 is way too large. */
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.current-header {
|
||||
/* Allows the circle positioning. */
|
||||
position: relative
|
||||
}
|
||||
|
||||
/* Places a circle just before the current header in the sidebar. */
|
||||
.current-header::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: -16px;
|
||||
top: 0;
|
||||
margin-top: 10px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-color: var(--sidebar-active);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
@@ -73,6 +73,8 @@
|
||||
--blockquote-important-color: #d3abff;
|
||||
--blockquote-warning-color: #f0b72f;
|
||||
--blockquote-caution-color: #f21424;
|
||||
|
||||
--sidebar-header-border-color: #c18639;
|
||||
}
|
||||
|
||||
.coal {
|
||||
@@ -132,6 +134,8 @@
|
||||
--blockquote-important-color: #ab7df8;
|
||||
--blockquote-warning-color: #d29922;
|
||||
--blockquote-caution-color: #d91b29;
|
||||
|
||||
--sidebar-header-border-color: #3473ad;
|
||||
}
|
||||
|
||||
.light, html:not(.js) {
|
||||
@@ -191,6 +195,8 @@
|
||||
--blockquote-important-color: #8250df;
|
||||
--blockquote-warning-color: #9a6700;
|
||||
--blockquote-caution-color: #b52731;
|
||||
|
||||
--sidebar-header-border-color: #6e6edb;
|
||||
}
|
||||
|
||||
.navy {
|
||||
@@ -250,6 +256,8 @@
|
||||
--blockquote-important-color: #ab7df8;
|
||||
--blockquote-warning-color: #d29922;
|
||||
--blockquote-caution-color: #f21424;
|
||||
|
||||
--sidebar-header-border-color: #2f6ab5;
|
||||
}
|
||||
|
||||
.rust {
|
||||
@@ -307,6 +315,8 @@
|
||||
--blockquote-important-color: #8250df;
|
||||
--blockquote-warning-color: #603700;
|
||||
--blockquote-caution-color: #aa1721;
|
||||
|
||||
--sidebar-header-border-color: #8c391f;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
@@ -367,5 +377,7 @@
|
||||
--blockquote-important-color: #ab7df8;
|
||||
--blockquote-warning-color: #d29922;
|
||||
--blockquote-caution-color: #d91b29;
|
||||
|
||||
--sidebar-header-border-color: #3473ad;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,14 +29,9 @@ class MDBookSidebarScrollbox extends HTMLElement {
|
||||
&& current_page.endsWith('/index.html')) {
|
||||
link.classList.add('active');
|
||||
let parent = link.parentElement;
|
||||
if (parent && parent.classList.contains('chapter-item')) {
|
||||
parent.classList.add('expanded');
|
||||
}
|
||||
while (parent) {
|
||||
if (parent.tagName === 'LI' && parent.previousElementSibling) {
|
||||
if (parent.previousElementSibling.classList.contains('chapter-item')) {
|
||||
parent.previousElementSibling.classList.add('expanded');
|
||||
}
|
||||
if (parent.tagName === 'LI' && parent.classList.contains('chapter-item')) {
|
||||
parent.classList.add('expanded');
|
||||
}
|
||||
parent = parent.parentElement;
|
||||
}
|
||||
@@ -45,14 +40,22 @@ class MDBookSidebarScrollbox extends HTMLElement {
|
||||
// Track and set sidebar scroll position
|
||||
this.addEventListener('click', e => {
|
||||
if (e.target.tagName === 'A') {
|
||||
sessionStorage.setItem('sidebar-scroll', this.scrollTop);
|
||||
const clientRect = e.target.getBoundingClientRect();
|
||||
const sidebarRect = this.getBoundingClientRect();
|
||||
sessionStorage.setItem('sidebar-scroll-offset', clientRect.top - sidebarRect.top);
|
||||
}
|
||||
}, { passive: true });
|
||||
const sidebarScrollTop = sessionStorage.getItem('sidebar-scroll');
|
||||
sessionStorage.removeItem('sidebar-scroll');
|
||||
if (sidebarScrollTop) {
|
||||
const sidebarScrollOffset = sessionStorage.getItem('sidebar-scroll-offset');
|
||||
sessionStorage.removeItem('sidebar-scroll-offset');
|
||||
if (sidebarScrollOffset !== null) {
|
||||
// preserve sidebar scroll position when navigating via links within sidebar
|
||||
this.scrollTop = sidebarScrollTop;
|
||||
const activeSection = this.querySelector('.active');
|
||||
if (activeSection) {
|
||||
const clientRect = activeSection.getBoundingClientRect();
|
||||
const sidebarRect = this.getBoundingClientRect();
|
||||
const currentOffset = clientRect.top - sidebarRect.top;
|
||||
this.scrollTop += currentOffset - parseFloat(sidebarScrollOffset);
|
||||
}
|
||||
} else {
|
||||
// scroll sidebar to current active section when navigating via
|
||||
// 'next/previous chapter' buttons
|
||||
@@ -62,9 +65,9 @@ class MDBookSidebarScrollbox extends HTMLElement {
|
||||
}
|
||||
}
|
||||
// Toggle buttons
|
||||
const sidebarAnchorToggles = document.querySelectorAll('#mdbook-sidebar a.toggle');
|
||||
const sidebarAnchorToggles = document.querySelectorAll('.chapter-fold-toggle');
|
||||
function toggleSection(ev) {
|
||||
ev.currentTarget.parentElement.classList.toggle('expanded');
|
||||
ev.currentTarget.parentElement.parentElement.classList.toggle('expanded');
|
||||
}
|
||||
Array.from(sidebarAnchorToggles).forEach(el => {
|
||||
el.addEventListener('click', toggleSection);
|
||||
@@ -78,10 +81,6 @@ window.customElements.define('mdbook-sidebar-scrollbox', MDBookSidebarScrollbox)
|
||||
// ---------------------------------------------------------------------------
|
||||
// Support for dynamically adding headers to the sidebar.
|
||||
|
||||
// This is a debugging tool for the threshold which you can enable in the console.
|
||||
// eslint-disable-next-line prefer-const
|
||||
let mdbookThresholdDebug = false;
|
||||
|
||||
(function() {
|
||||
// This is used to detect which direction the page has scrolled since the
|
||||
// last scroll event.
|
||||
@@ -108,6 +107,101 @@ let mdbookThresholdDebug = false;
|
||||
// I'm not sure why eslint seems to have a false positive here.
|
||||
// eslint-disable-next-line prefer-const
|
||||
let headerToggles = [];
|
||||
// This is a debugging tool for the threshold which you can enable in the console.
|
||||
let thresholdDebug = false;
|
||||
|
||||
// Updates the threshold based on the scroll position.
|
||||
function updateThreshold() {
|
||||
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
||||
const windowHeight = window.innerHeight;
|
||||
const documentHeight = document.documentElement.scrollHeight;
|
||||
|
||||
// The number of pixels below the viewport, at most documentHeight.
|
||||
// This is used to push the threshold down to the bottom of the page
|
||||
// as the user scrolls towards the bottom.
|
||||
const pixelsBelow = Math.max(0, documentHeight - (scrollTop + windowHeight));
|
||||
// The number of pixels above the viewport, at least defaultDownThreshold.
|
||||
// Similar to pixelsBelow, this is used to push the threshold back towards
|
||||
// the top when reaching the top of the page.
|
||||
const pixelsAbove = Math.max(0, defaultDownThreshold - scrollTop);
|
||||
// How much the threshold should be offset once it gets close to the
|
||||
// bottom of the page.
|
||||
const bottomAdd = Math.max(0, windowHeight - pixelsBelow - defaultDownThreshold);
|
||||
let adjustedBottomAdd = bottomAdd;
|
||||
|
||||
// Adjusts bottomAdd for a small document. The calculation above
|
||||
// assumes the document is at least twice the windowheight in size. If
|
||||
// it is less than that, then bottomAdd needs to be shrunk
|
||||
// proportional to the difference in size.
|
||||
if (documentHeight < windowHeight * 2) {
|
||||
const maxPixelsBelow = documentHeight - windowHeight;
|
||||
const t = 1 - pixelsBelow / Math.max(1, maxPixelsBelow);
|
||||
const clamp = Math.max(0, Math.min(1, t));
|
||||
adjustedBottomAdd *= clamp;
|
||||
}
|
||||
|
||||
let scrollingDown = true;
|
||||
if (scrollTop < lastKnownScrollPosition) {
|
||||
scrollingDown = false;
|
||||
}
|
||||
|
||||
if (scrollingDown) {
|
||||
// When scrolling down, move the threshold up towards the default
|
||||
// downwards threshold position. If near the bottom of the page,
|
||||
// adjustedBottomAdd will offset the threshold towards the bottom
|
||||
// of the page.
|
||||
const amountScrolledDown = scrollTop - lastKnownScrollPosition;
|
||||
const adjustedDefault = defaultDownThreshold + adjustedBottomAdd;
|
||||
threshold = Math.max(adjustedDefault, threshold - amountScrolledDown);
|
||||
} else {
|
||||
// When scrolling up, move the threshold down towards the default
|
||||
// upwards threshold position. If near the bottom of the page,
|
||||
// quickly transition the threshold back up where it normally
|
||||
// belongs.
|
||||
const amountScrolledUp = lastKnownScrollPosition - scrollTop;
|
||||
const adjustedDefault = defaultUpThreshold - pixelsAbove
|
||||
+ Math.max(0, adjustedBottomAdd - defaultDownThreshold);
|
||||
threshold = Math.min(adjustedDefault, threshold + amountScrolledUp);
|
||||
}
|
||||
|
||||
if (documentHeight <= windowHeight) {
|
||||
threshold = 0;
|
||||
}
|
||||
|
||||
if (thresholdDebug) {
|
||||
const id = 'mdbook-threshold-debug-data';
|
||||
let data = document.getElementById(id);
|
||||
if (data === null) {
|
||||
data = document.createElement('div');
|
||||
data.id = id;
|
||||
data.style.cssText = `
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
right: 10px;
|
||||
background-color: 0xeeeeee;
|
||||
z-index: 9999;
|
||||
pointer-events: none;
|
||||
`;
|
||||
document.body.appendChild(data);
|
||||
}
|
||||
data.innerHTML = `
|
||||
<table>
|
||||
<tr><td>documentHeight</td><td>${documentHeight.toFixed(1)}</td></tr>
|
||||
<tr><td>windowHeight</td><td>${windowHeight.toFixed(1)}</td></tr>
|
||||
<tr><td>scrollTop</td><td>${scrollTop.toFixed(1)}</td></tr>
|
||||
<tr><td>pixelsAbove</td><td>${pixelsAbove.toFixed(1)}</td></tr>
|
||||
<tr><td>pixelsBelow</td><td>${pixelsBelow.toFixed(1)}</td></tr>
|
||||
<tr><td>bottomAdd</td><td>${bottomAdd.toFixed(1)}</td></tr>
|
||||
<tr><td>adjustedBottomAdd</td><td>${adjustedBottomAdd.toFixed(1)}</td></tr>
|
||||
<tr><td>scrollingDown</td><td>${scrollingDown}</td></tr>
|
||||
<tr><td>threshold</td><td>${threshold.toFixed(1)}</td></tr>
|
||||
</table>
|
||||
`;
|
||||
drawDebugLine();
|
||||
}
|
||||
|
||||
lastKnownScrollPosition = scrollTop;
|
||||
}
|
||||
|
||||
function drawDebugLine() {
|
||||
if (!document.body) {
|
||||
@@ -133,76 +227,25 @@ let mdbookThresholdDebug = false;
|
||||
document.body.appendChild(line);
|
||||
}
|
||||
|
||||
// Updates the threshold based on the scroll position.
|
||||
function updateThreshold() {
|
||||
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
||||
const windowHeight = window.innerHeight;
|
||||
const documentHeight = document.documentElement.scrollHeight;
|
||||
// The number of pixels below the viewport, at most documentHeight.
|
||||
// This is used to push the threshold down to the bottom of the page
|
||||
// as the user scrolls towards the bottom.
|
||||
const pixelsBelow = Math.max(0, documentHeight - (scrollTop + windowHeight));
|
||||
// The number of pixels above the viewport, at most defaultDownThreshold.
|
||||
// Similar to pixelsBelow, this is used to push the threshold back towards
|
||||
// the top when reaching the top of the page.
|
||||
const pixelsAbove = Math.max(0, defaultDownThreshold - scrollTop);
|
||||
// How much the threshold should be offset once it gets close to the
|
||||
// bottom of the page.
|
||||
let bottomAdd = Math.max(0, windowHeight - pixelsBelow - defaultDownThreshold);
|
||||
|
||||
// Adjusts bottomAdd for a small document. The calculation above
|
||||
// assumes the document is at least twice the windowheight in size. If
|
||||
// it is less than that, then bottomAdd needs to be shrunk
|
||||
// proportional to the difference in size.
|
||||
if (documentHeight < windowHeight * 2) {
|
||||
const maxPixelsBelow = documentHeight - windowHeight;
|
||||
const t = 1 - pixelsBelow / maxPixelsBelow;
|
||||
const clamp = Math.max(0, Math.min(1, t));
|
||||
bottomAdd *= clamp;
|
||||
}
|
||||
|
||||
let scrollingDown = true;
|
||||
if (scrollTop < lastKnownScrollPosition) {
|
||||
scrollingDown = false;
|
||||
}
|
||||
|
||||
if (scrollingDown) {
|
||||
// When scrolling down, move the threshold up towards the default
|
||||
// downwards threshold position. If near the bottom of the page,
|
||||
// bottomAdd will offset the threshold towards the bottom of the
|
||||
// page.
|
||||
const amountScrolledDown = scrollTop - lastKnownScrollPosition;
|
||||
const adjustedDefault = defaultDownThreshold + bottomAdd;
|
||||
threshold = Math.max(adjustedDefault, threshold - amountScrolledDown);
|
||||
} else {
|
||||
// When scrolling up, move the threshold down towards the default
|
||||
// upwards threshold position. If near the bottom of the page,
|
||||
// quickly transition the threshold back up where it normally
|
||||
// belongs.
|
||||
const amountScrolledUp = lastKnownScrollPosition - scrollTop;
|
||||
const adjustedDefault = defaultUpThreshold - pixelsAbove
|
||||
+ Math.max(0, bottomAdd - defaultDownThreshold);
|
||||
threshold = Math.min(adjustedDefault, threshold + amountScrolledUp);
|
||||
}
|
||||
lastKnownScrollPosition = scrollTop;
|
||||
function mdbookEnableThresholdDebug() {
|
||||
thresholdDebug = true;
|
||||
updateThreshold();
|
||||
drawDebugLine();
|
||||
}
|
||||
|
||||
window.mdbookEnableThresholdDebug = mdbookEnableThresholdDebug;
|
||||
|
||||
// Updates which headers in the sidebar should be expanded. If the current
|
||||
// header is inside a collapsed group, then it, and all its parents should
|
||||
// be expanded.
|
||||
function updateHeaderExpanded(currentA) {
|
||||
// Add expanded to all header-item li ancestors.
|
||||
let current = currentA.parentElement.parentElement.parentElement;
|
||||
while (current.tagName === 'LI') {
|
||||
const prevSibling = current.previousElementSibling;
|
||||
if (prevSibling !== null
|
||||
&& prevSibling.tagName === 'LI'
|
||||
&& prevSibling.classList.contains('header-item')) {
|
||||
prevSibling.classList.add('expanded');
|
||||
current = prevSibling.parentElement.parentElement;
|
||||
} else {
|
||||
break;
|
||||
let current = currentA.parentElement;
|
||||
while (current) {
|
||||
if (current.tagName === 'LI' && current.classList.contains('header-item')) {
|
||||
current.classList.add('expanded');
|
||||
}
|
||||
current = current.parentElement;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,9 +253,6 @@ let mdbookThresholdDebug = false;
|
||||
// This is done with a virtual Y threshold, where headers at or below
|
||||
// that line will be considered the current one.
|
||||
function updateCurrentHeader() {
|
||||
if (mdbookThresholdDebug) {
|
||||
drawDebugLine();
|
||||
}
|
||||
if (!headers || !headers.length) {
|
||||
return;
|
||||
}
|
||||
@@ -295,25 +335,22 @@ let mdbookThresholdDebug = false;
|
||||
});
|
||||
}
|
||||
|
||||
// Takes the nodes from the given head and copies them over to the
|
||||
// destination, along with some filtering.
|
||||
function filterHeader(source, dest) {
|
||||
const clone = source.cloneNode(true);
|
||||
clone.querySelectorAll('mark').forEach(mark => {
|
||||
mark.replaceWith(...mark.childNodes);
|
||||
});
|
||||
dest.append(...clone.childNodes);
|
||||
}
|
||||
|
||||
// Scans page for headers and adds them to the sidebar.
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const activeSection = document.querySelector('#mdbook-sidebar .active');
|
||||
if (activeSection === null) {
|
||||
return;
|
||||
}
|
||||
const activeItem = activeSection.parentElement;
|
||||
const activeList = activeItem.parentElement;
|
||||
|
||||
// Build a tree of headers in the sidebar.
|
||||
const rootLi = document.createElement('li');
|
||||
rootLi.classList.add('header-item');
|
||||
rootLi.classList.add('expanded');
|
||||
const rootOl = document.createElement('ol');
|
||||
rootOl.classList.add('section');
|
||||
rootLi.appendChild(rootOl);
|
||||
const stack = [{ level: 0, ol: rootOl }];
|
||||
// The level where it will start folding deeply nested headers.
|
||||
const foldLevel = 3;
|
||||
|
||||
const main = document.getElementsByTagName('main')[0];
|
||||
headers = Array.from(main.querySelectorAll('h2, h3, h4, h5, h6'))
|
||||
@@ -323,57 +360,93 @@ let mdbookThresholdDebug = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Build a tree of headers in the sidebar.
|
||||
|
||||
const stack = [];
|
||||
|
||||
const firstLevel = parseInt(headers[0].tagName.charAt(1));
|
||||
for (let i = 1; i < firstLevel; i++) {
|
||||
const ol = document.createElement('ol');
|
||||
ol.classList.add('section');
|
||||
if (stack.length > 0) {
|
||||
stack[stack.length - 1].ol.appendChild(ol);
|
||||
}
|
||||
stack.push({level: i + 1, ol: ol});
|
||||
}
|
||||
|
||||
// The level where it will start folding deeply nested headers.
|
||||
const foldLevel = 3;
|
||||
|
||||
for (let i = 0; i < headers.length; i++) {
|
||||
const header = headers[i];
|
||||
const level = parseInt(header.tagName.charAt(1));
|
||||
|
||||
const currentLevel = stack[stack.length - 1].level;
|
||||
if (level > currentLevel) {
|
||||
// Begin nesting to this level.
|
||||
for (let nextLevel = currentLevel + 1; nextLevel <= level; nextLevel++) {
|
||||
const ol = document.createElement('ol');
|
||||
ol.classList.add('section');
|
||||
const last = stack[stack.length - 1];
|
||||
const lastChild = last.ol.lastChild;
|
||||
// Handle the case where jumping more than one nesting
|
||||
// level, which doesn't have a list item to place this new
|
||||
// list inside of.
|
||||
if (lastChild) {
|
||||
lastChild.appendChild(ol);
|
||||
} else {
|
||||
last.ol.appendChild(ol);
|
||||
}
|
||||
stack.push({level: nextLevel, ol: ol});
|
||||
}
|
||||
} else if (level < currentLevel) {
|
||||
while (stack.length > 1 && stack[stack.length - 1].level > level) {
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
const li = document.createElement('li');
|
||||
li.classList.add('header-item');
|
||||
li.classList.add('expanded');
|
||||
if (level < foldLevel) {
|
||||
li.classList.add('expanded');
|
||||
}
|
||||
const span = document.createElement('span');
|
||||
span.classList.add('chapter-link-wrapper');
|
||||
const a = document.createElement('a');
|
||||
span.appendChild(a);
|
||||
a.href = '#' + header.id;
|
||||
a.classList.add('header-in-summary');
|
||||
a.innerHTML = header.children[0].innerHTML;
|
||||
filterHeader(header.children[0], a);
|
||||
a.addEventListener('click', headerThresholdClick);
|
||||
li.appendChild(a);
|
||||
const nextHeader = headers[i + 1];
|
||||
if (nextHeader !== undefined) {
|
||||
const nextLevel = parseInt(nextHeader.tagName.charAt(1));
|
||||
if (nextLevel > level && level >= foldLevel) {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = '❱';
|
||||
const toggle = document.createElement('a');
|
||||
toggle.classList.add('toggle');
|
||||
toggle.classList.add('chapter-fold-toggle');
|
||||
toggle.classList.add('header-toggle');
|
||||
toggle.appendChild(div);
|
||||
toggle.addEventListener('click', () => {
|
||||
li.classList.toggle('expanded');
|
||||
});
|
||||
li.appendChild(toggle);
|
||||
const toggleDiv = document.createElement('div');
|
||||
toggleDiv.textContent = '❱';
|
||||
toggle.appendChild(toggleDiv);
|
||||
span.appendChild(toggle);
|
||||
headerToggles.push(li);
|
||||
}
|
||||
}
|
||||
|
||||
// Find the appropriate parent level.
|
||||
while (stack.length > 1 && stack[stack.length - 1].level >= level) {
|
||||
stack.pop();
|
||||
}
|
||||
li.appendChild(span);
|
||||
|
||||
const currentParent = stack[stack.length - 1];
|
||||
currentParent.ol.appendChild(li);
|
||||
|
||||
// Create new nested ol for potential children.
|
||||
const nestedOl = document.createElement('ol');
|
||||
nestedOl.classList.add('section');
|
||||
const nestedLi = document.createElement('li');
|
||||
nestedLi.appendChild(nestedOl);
|
||||
currentParent.ol.appendChild(nestedLi);
|
||||
stack.push({ level: level, ol: nestedOl });
|
||||
}
|
||||
|
||||
activeList.insertBefore(rootLi, activeItem.nextSibling);
|
||||
const onThisPage = document.createElement('div');
|
||||
onThisPage.classList.add('on-this-page');
|
||||
onThisPage.append(stack[0].ol);
|
||||
const activeItemSpan = activeSection.parentElement;
|
||||
activeItemSpan.after(onThisPage);
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', reloadCurrentHeader);
|
||||
|
||||
@@ -141,7 +141,14 @@ fn partition_rust_source(s: &str) -> (&str, &str) {
|
||||
let split_idx = match HEADER_RE.captures(s) {
|
||||
Some(caps) => {
|
||||
let attributes = &caps[1];
|
||||
attributes.len()
|
||||
if attributes.trim().is_empty() {
|
||||
// Don't include pure whitespace as an attribute. The
|
||||
// whitespace in the regex is intended to handle multiple
|
||||
// attributes *separated* by potential whitespace.
|
||||
0
|
||||
} else {
|
||||
attributes.len()
|
||||
}
|
||||
}
|
||||
None => 0,
|
||||
};
|
||||
@@ -179,4 +186,8 @@ fn it_partitions_rust_source() {
|
||||
),
|
||||
("\n#![allow(foo)]\n\n#![allow(bar)]\n\n", "let x = 1;")
|
||||
);
|
||||
assert_eq!(
|
||||
partition_rust_source(" // Example"),
|
||||
("", " // Example")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::html::{ChapterTree, Element, serialize};
|
||||
use crate::utils::{ToUrlPath, id_from_content, normalize_path, unique_id};
|
||||
use mdbook_core::static_regex;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::path::{Component, PathBuf};
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Takes all the chapter trees, modifies them to be suitable to render for
|
||||
/// the print page, and returns an string of all the chapters rendered to a
|
||||
@@ -166,13 +166,9 @@ fn rewrite_links(
|
||||
{
|
||||
lookup_key.pop();
|
||||
lookup_key.push(href_path);
|
||||
let normalized = normalize_path(&lookup_key);
|
||||
// If this points outside of the book, don't modify it.
|
||||
let is_outside = matches!(
|
||||
normalized.components().next(),
|
||||
Some(Component::ParentDir | Component::RootDir)
|
||||
);
|
||||
if is_outside || !href_path.ends_with(".html") {
|
||||
lookup_key = normalize_path(&lookup_key);
|
||||
let is_a_chapter = path_to_root_id.contains_key(&lookup_key);
|
||||
if !is_a_chapter {
|
||||
// Make the link relative to the print page location.
|
||||
let mut rel_path = normalize_path(&base.join(href_path)).to_url_path();
|
||||
if let Some(anchor) = caps.name("anchor") {
|
||||
@@ -184,10 +180,7 @@ fn rewrite_links(
|
||||
}
|
||||
}
|
||||
|
||||
let lookup_key = normalize_path(&lookup_key);
|
||||
|
||||
let anchor = caps.name("anchor");
|
||||
let id = match anchor {
|
||||
let id = match caps.name("anchor") {
|
||||
Some(anchor_id) => {
|
||||
let anchor_id = anchor_id.as_str().to_string();
|
||||
match id_remap.get(&lookup_key) {
|
||||
@@ -204,7 +197,15 @@ fn rewrite_links(
|
||||
}
|
||||
None => match path_to_root_id.get(&lookup_key) {
|
||||
Some(id) => id.to_string(),
|
||||
None => continue,
|
||||
None => {
|
||||
// This should be guaranteed that either the
|
||||
// chapter itself is in the map (for anchor-only
|
||||
// links), or the is_a_chapter check above.
|
||||
panic!(
|
||||
"internal error: expected `{lookup_key:?}` to be in \
|
||||
root map (chapter path is `{html_path:?}`)"
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
el.insert_attr(attr, format!("#{id}").into());
|
||||
|
||||
@@ -19,7 +19,7 @@ use pulldown_cmark::{Alignment, CodeBlockKind, CowStr, Event, LinkType, Tag, Tag
|
||||
use std::borrow::Cow;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::ops::Deref;
|
||||
use tracing::{error, warn};
|
||||
use tracing::{trace, warn};
|
||||
|
||||
/// Helper to create a [`QualName`].
|
||||
macro_rules! attr_qual_name {
|
||||
@@ -77,6 +77,8 @@ pub(crate) struct Element {
|
||||
pub(crate) attrs: Attributes,
|
||||
/// True if this tag ends with `/>`.
|
||||
pub(crate) self_closing: bool,
|
||||
/// True if this was raw HTML written in the markdown.
|
||||
pub(crate) was_raw: bool,
|
||||
}
|
||||
|
||||
impl Element {
|
||||
@@ -87,6 +89,7 @@ impl Element {
|
||||
name,
|
||||
attrs: Attributes::new(),
|
||||
self_closing: false,
|
||||
was_raw: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,25 +303,10 @@ where
|
||||
/// The main processing loop. Processes all events until the end.
|
||||
fn process_events(&mut self) {
|
||||
while let Some(event) = self.events.next() {
|
||||
trace!("event={event:?}");
|
||||
match event {
|
||||
Event::Start(tag) => self.start_tag(tag),
|
||||
Event::End(tag) => {
|
||||
self.pop();
|
||||
match tag {
|
||||
TagEnd::TableHead => {
|
||||
self.table_state = TableState::Body;
|
||||
self.push(Node::Element(Element::new("tbody")));
|
||||
}
|
||||
TagEnd::TableCell => {
|
||||
self.table_cell_index += 1;
|
||||
}
|
||||
TagEnd::Table => {
|
||||
// Pop tbody or thead
|
||||
self.pop();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Event::End(tag) => self.end_tag(tag),
|
||||
Event::Text(text) => {
|
||||
self.append_text(text.into_tendril());
|
||||
}
|
||||
@@ -374,6 +362,7 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
self.finish_stack();
|
||||
self.collect_footnote_defs();
|
||||
}
|
||||
|
||||
@@ -593,47 +582,59 @@ where
|
||||
self.push(Node::Element(element));
|
||||
}
|
||||
|
||||
fn end_tag(&mut self, tag: TagEnd) {
|
||||
// TODO: This should validate that the event stack is properly
|
||||
// synchronized with the tag stack. That, would likely require keeping
|
||||
// a parallel "expected end tag" with the tag stack, since mapping a
|
||||
// pulldown-cmark event tag to an HTML tag isn't always clear.
|
||||
//
|
||||
// Check for unclosed HTML tags when exiting a markdown event.
|
||||
while let Some(node_id) = self.tag_stack.last() {
|
||||
let node = self.tree.get(*node_id).unwrap().value();
|
||||
let Node::Element(el) = node else {
|
||||
break;
|
||||
};
|
||||
if !el.was_raw {
|
||||
break;
|
||||
}
|
||||
warn!(
|
||||
"unclosed HTML tag `<{}>` found in `{}` while exiting {tag:?}\n\
|
||||
HTML tags must be closed before exiting a markdown element.",
|
||||
el.name.local,
|
||||
self.options.path.display(),
|
||||
);
|
||||
self.pop();
|
||||
}
|
||||
self.pop();
|
||||
match tag {
|
||||
TagEnd::TableHead => {
|
||||
self.table_state = TableState::Body;
|
||||
self.push(Node::Element(Element::new("tbody")));
|
||||
}
|
||||
TagEnd::TableCell => {
|
||||
self.table_cell_index += 1;
|
||||
}
|
||||
TagEnd::Table => {
|
||||
// Pop tbody or thead
|
||||
self.pop();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// Given some HTML, parse it into [`Node`] elements and append them to
|
||||
/// the current node.
|
||||
fn append_html(&mut self, html: &str) {
|
||||
let tokens = parse_html(&html);
|
||||
let mut is_raw = false;
|
||||
for token in tokens {
|
||||
trace!("html token={token:?}");
|
||||
match token {
|
||||
Token::DoctypeToken(_) => {}
|
||||
Token::TagToken(tag) => {
|
||||
match tag.kind {
|
||||
TagKind::StartTag => {
|
||||
let is_closed = is_void_element(&tag.name) || tag.self_closing;
|
||||
is_raw = matches!(&*tag.name, "script" | "style");
|
||||
let name = QualName::new(None, html5ever::ns!(html), tag.name);
|
||||
let attrs = tag
|
||||
.attrs
|
||||
.into_iter()
|
||||
.map(|attr| (attr.name, attr.value))
|
||||
.collect();
|
||||
let mut el = Element {
|
||||
name,
|
||||
attrs,
|
||||
self_closing: tag.self_closing,
|
||||
};
|
||||
fix_html_link(&mut el);
|
||||
self.push(Node::Element(el));
|
||||
if is_closed {
|
||||
// No end element.
|
||||
self.pop();
|
||||
}
|
||||
}
|
||||
TagKind::EndTag => {
|
||||
is_raw = false;
|
||||
if self.is_html_tag_matching(&tag.name) {
|
||||
self.pop();
|
||||
}
|
||||
// else the stack is corrupt. I'm not really sure
|
||||
// what to do here...
|
||||
}
|
||||
}
|
||||
}
|
||||
Token::TagToken(tag) => match tag.kind {
|
||||
TagKind::StartTag => self.start_html_tag(tag, &mut is_raw),
|
||||
TagKind::EndTag => self.end_html_tag(tag, &mut is_raw),
|
||||
},
|
||||
Token::CommentToken(comment) => {
|
||||
self.append(Node::Comment(comment));
|
||||
}
|
||||
@@ -658,22 +659,59 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds an open HTML tag.
|
||||
fn start_html_tag(&mut self, tag: html5ever::tokenizer::Tag, is_raw: &mut bool) {
|
||||
let is_closed = is_void_element(&tag.name) || tag.self_closing;
|
||||
*is_raw = matches!(&*tag.name, "script" | "style");
|
||||
let name = QualName::new(None, html5ever::ns!(html), tag.name);
|
||||
let attrs = tag
|
||||
.attrs
|
||||
.into_iter()
|
||||
.map(|attr| (attr.name, attr.value))
|
||||
.collect();
|
||||
let mut el = Element {
|
||||
name,
|
||||
attrs,
|
||||
self_closing: tag.self_closing,
|
||||
was_raw: true,
|
||||
};
|
||||
fix_html_link(&mut el);
|
||||
self.push(Node::Element(el));
|
||||
if is_closed {
|
||||
// No end element.
|
||||
self.pop();
|
||||
}
|
||||
}
|
||||
|
||||
/// Closes the given HTML tag.
|
||||
fn end_html_tag(&mut self, tag: html5ever::tokenizer::Tag, is_raw: &mut bool) {
|
||||
*is_raw = false;
|
||||
if self.is_html_tag_matching(&tag.name) {
|
||||
self.pop();
|
||||
} else {
|
||||
// The proper thing to do here is to recover. However, the HTML
|
||||
// parsing algorithm for that is quite complex. See
|
||||
// https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inbody
|
||||
// and the adoption agency algorithm.
|
||||
warn!(
|
||||
"unexpected HTML end tag `</{}>` found in `{}`\n\
|
||||
Check that the HTML tags are properly balanced.",
|
||||
tag.name,
|
||||
self.options.path.display()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// This is used to verify HTML parsing keeps the stack of tags in sync.
|
||||
fn is_html_tag_matching(&self, name: &str) -> bool {
|
||||
let current = self.tree.get(self.current_node).unwrap().value();
|
||||
if let Node::Element(el) = current
|
||||
&& el.name() == name
|
||||
{
|
||||
return true;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
error!(
|
||||
"internal error: HTML tag stack out of sync.\n
|
||||
path: `{}`\n\
|
||||
current={current:?}\n\
|
||||
pop name: {name}",
|
||||
self.options.path.display()
|
||||
);
|
||||
false
|
||||
}
|
||||
|
||||
/// Eats all pulldown-cmark events until the next `End` matching the
|
||||
@@ -730,6 +768,40 @@ where
|
||||
output
|
||||
}
|
||||
|
||||
/// Deals with any unclosed elements on the stack.
|
||||
fn finish_stack(&mut self) {
|
||||
while let Some(node_id) = self.tag_stack.pop() {
|
||||
let node = self.tree.get(node_id).unwrap().value();
|
||||
match node {
|
||||
Node::Fragment => {}
|
||||
Node::Element(el) => {
|
||||
if el.was_raw {
|
||||
warn!(
|
||||
"unclosed HTML tag `<{}>` found in `{}`",
|
||||
el.name.local,
|
||||
self.options.path.display()
|
||||
);
|
||||
} else {
|
||||
panic!(
|
||||
"internal error: expected empty tag stack.\n
|
||||
path: `{}`\n\
|
||||
element={el:?}",
|
||||
self.options.path.display()
|
||||
);
|
||||
}
|
||||
}
|
||||
node => {
|
||||
panic!(
|
||||
"internal error: expected empty tag stack.\n
|
||||
path: `{}`\n\
|
||||
node={node:?}",
|
||||
self.options.path.display()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Appends a new footnote reference.
|
||||
fn footnote_reference(&mut self, name: CowStr<'event>) {
|
||||
let len = self.footnote_numbers.len() + 1;
|
||||
@@ -840,6 +912,11 @@ where
|
||||
for heading in headings {
|
||||
let node = self.tree.get(heading).unwrap();
|
||||
let el = node.value().as_element().unwrap();
|
||||
// Don't modify tags if they were manually written HTML. The
|
||||
// user probably had some intent, and we don't want to mess it up.
|
||||
if el.was_raw {
|
||||
continue;
|
||||
}
|
||||
let href = if let Some(id) = el.attr("id") {
|
||||
format!("#{id}")
|
||||
} else {
|
||||
@@ -953,32 +1030,42 @@ where
|
||||
let i_el = node.value().as_element().unwrap();
|
||||
let classes = i_el.attr("class").unwrap_or_default();
|
||||
for class in classes.split(" ") {
|
||||
if let Some(class) = class.strip_prefix("fa-") {
|
||||
icon = class.to_owned();
|
||||
} else if class == "fa" {
|
||||
if matches!(class, "fa" | "fa-regular") {
|
||||
type_ = fa::Type::Regular;
|
||||
} else if class == "fas" {
|
||||
} else if matches!(class, "fas" | "fa-solid") {
|
||||
type_ = fa::Type::Solid;
|
||||
} else if class == "fab" {
|
||||
} else if matches!(class, "fab" | "fa-brands") {
|
||||
type_ = fa::Type::Brands;
|
||||
} else if let Some(class) = class.strip_prefix("fa-") {
|
||||
icon = class.to_owned();
|
||||
} else {
|
||||
new_classes += " ";
|
||||
new_classes += class;
|
||||
}
|
||||
}
|
||||
if icon.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !icon.is_empty()
|
||||
&& let Ok(svg) = fa::svg(type_, &icon)
|
||||
{
|
||||
let mut span = Element::new("span");
|
||||
span.insert_attr("class", new_classes.into());
|
||||
for (name, value) in &i_el.attrs {
|
||||
if *name != attr_qual_name!("class") {
|
||||
span.attrs.insert(name.clone(), value.clone());
|
||||
match fa::svg(type_, &icon) {
|
||||
Ok(svg) => {
|
||||
let mut span = Element::new("span");
|
||||
span.insert_attr("class", new_classes.into());
|
||||
for (name, value) in &i_el.attrs {
|
||||
if *name != attr_qual_name!("class") {
|
||||
span.attrs.insert(name.clone(), value.clone());
|
||||
}
|
||||
}
|
||||
*node.value() = Node::Element(span);
|
||||
node.append(Node::RawData(svg.into()));
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(
|
||||
"failed to find Font Awesome icon for icon `{icon}` \
|
||||
with type `{type_}` in `{}`: {e}",
|
||||
self.options.path.display()
|
||||
);
|
||||
}
|
||||
*node.value() = Node::Element(span);
|
||||
node.append(Node::RawData(svg.into()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,13 +57,13 @@ impl HelperDef for RenderToc {
|
||||
out.write("<ol class=\"chapter\">")?;
|
||||
|
||||
let mut current_level = 1;
|
||||
let mut first = true;
|
||||
|
||||
for item in chapters {
|
||||
let (_section, level) = if let Some(s) = item.get("section") {
|
||||
(s.as_str(), s.matches('.').count())
|
||||
} else {
|
||||
("", 1)
|
||||
};
|
||||
let level = item
|
||||
.get("section")
|
||||
.map(|s| s.matches('.').count())
|
||||
.unwrap_or(1);
|
||||
|
||||
// Expand if folding is disabled, or if levels that are larger than this would not
|
||||
// be folded.
|
||||
@@ -71,25 +71,31 @@ impl HelperDef for RenderToc {
|
||||
|
||||
match level.cmp(¤t_level) {
|
||||
Ordering::Greater => {
|
||||
while level > current_level {
|
||||
out.write("<li>")?;
|
||||
out.write("<ol class=\"section\">")?;
|
||||
current_level += 1;
|
||||
}
|
||||
write_li_open_tag(out, is_expanded, false)?;
|
||||
// There is an assumption that when descending, it can
|
||||
// only go one level down at a time. This should be
|
||||
// enforced by the nature of markdown lists and the
|
||||
// summary parser.
|
||||
assert_eq!(level, current_level + 1);
|
||||
current_level += 1;
|
||||
out.write("<ol class=\"section\">")?;
|
||||
write_li_open_tag(out, is_expanded)?;
|
||||
}
|
||||
Ordering::Less => {
|
||||
while level < current_level {
|
||||
out.write("</ol>")?;
|
||||
out.write("</li>")?;
|
||||
out.write("</ol>")?;
|
||||
current_level -= 1;
|
||||
}
|
||||
write_li_open_tag(out, is_expanded, false)?;
|
||||
write_li_open_tag(out, is_expanded)?;
|
||||
}
|
||||
Ordering::Equal => {
|
||||
write_li_open_tag(out, is_expanded, !item.contains_key("section"))?;
|
||||
if !first {
|
||||
out.write("</li>")?;
|
||||
}
|
||||
write_li_open_tag(out, is_expanded)?;
|
||||
}
|
||||
}
|
||||
first = false;
|
||||
|
||||
// Spacer
|
||||
if item.contains_key("spacer") {
|
||||
@@ -105,6 +111,8 @@ impl HelperDef for RenderToc {
|
||||
continue;
|
||||
}
|
||||
|
||||
out.write("<span class=\"chapter-link-wrapper\">")?;
|
||||
|
||||
// Link
|
||||
let path_exists = match item.get("path") {
|
||||
Some(path) if !path.is_empty() => {
|
||||
@@ -121,7 +129,7 @@ impl HelperDef for RenderToc {
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
out.write("<div>")?;
|
||||
out.write("<span>")?;
|
||||
false
|
||||
}
|
||||
};
|
||||
@@ -142,41 +150,35 @@ impl HelperDef for RenderToc {
|
||||
if path_exists {
|
||||
out.write("</a>")?;
|
||||
} else {
|
||||
out.write("</div>")?;
|
||||
out.write("</span>")?;
|
||||
}
|
||||
|
||||
// Render expand/collapse toggle
|
||||
if let Some(flag) = item.get("has_sub_items") {
|
||||
let has_sub_items = flag.parse::<bool>().unwrap_or_default();
|
||||
if fold_enable && has_sub_items {
|
||||
out.write("<a class=\"toggle\"><div>❱</div></a>")?;
|
||||
// The <div> here is to manage rotating the element when
|
||||
// the chapter title is long and word-wraps.
|
||||
out.write("<a class=\"chapter-fold-toggle\"><div>❱</div></a>")?;
|
||||
}
|
||||
}
|
||||
out.write("</li>")?;
|
||||
out.write("</span>")?;
|
||||
}
|
||||
while current_level > 1 {
|
||||
out.write("</ol>")?;
|
||||
while current_level > 0 {
|
||||
out.write("</li>")?;
|
||||
out.write("</ol>")?;
|
||||
current_level -= 1;
|
||||
}
|
||||
|
||||
out.write("</ol>")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn write_li_open_tag(
|
||||
out: &mut dyn Output,
|
||||
is_expanded: bool,
|
||||
is_affix: bool,
|
||||
) -> Result<(), std::io::Error> {
|
||||
fn write_li_open_tag(out: &mut dyn Output, is_expanded: bool) -> Result<(), std::io::Error> {
|
||||
let mut li = String::from("<li class=\"chapter-item ");
|
||||
if is_expanded {
|
||||
li.push_str("expanded ");
|
||||
}
|
||||
if is_affix {
|
||||
li.push_str("affix ");
|
||||
}
|
||||
li.push_str("\">");
|
||||
out.write(&li)
|
||||
}
|
||||
|
||||
@@ -74,12 +74,22 @@ pub(crate) fn unique_id(id: &str, used: &mut HashSet<String>) -> String {
|
||||
|
||||
/// Generates an HTML id from the given text.
|
||||
pub(crate) fn id_from_content(content: &str) -> String {
|
||||
// This is intended to be close to how header ID generation is done in
|
||||
// other sites and tools, but is not 100% the same. Not all sites and
|
||||
// tools use the same algorithm. See these for more information:
|
||||
//
|
||||
// - https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#section-links
|
||||
// - https://docs.gitlab.com/user/markdown/#heading-ids-and-links
|
||||
// - https://pandoc.org/MANUAL.html#extension-auto_identifiers
|
||||
// - https://kramdown.gettalong.org/converter/html#auto-ids
|
||||
// - https://docs.rs/comrak/latest/comrak/options/struct.Extension.html#structfield.header_ids
|
||||
content
|
||||
.trim()
|
||||
.to_lowercase()
|
||||
.chars()
|
||||
.filter_map(|ch| {
|
||||
if ch.is_alphanumeric() || ch == '_' || ch == '-' {
|
||||
Some(ch.to_ascii_lowercase())
|
||||
Some(ch)
|
||||
} else if ch.is_whitespace() {
|
||||
Some('-')
|
||||
} else {
|
||||
@@ -120,6 +130,6 @@ mod tests {
|
||||
assert_eq!(id_from_content("한국어"), "한국어");
|
||||
assert_eq!(id_from_content(""), "");
|
||||
assert_eq!(id_from_content("中文標題 CJK title"), "中文標題-cjk-title");
|
||||
assert_eq!(id_from_content("Über"), "Über");
|
||||
assert_eq!(id_from_content("Über"), "über");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mdbook-markdown"
|
||||
version = "0.5.0-alpha.1"
|
||||
version = "0.5.2"
|
||||
description = "Markdown processing used in mdBook"
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mdbook-preprocessor"
|
||||
version = "0.5.0-alpha.1"
|
||||
version = "0.5.2"
|
||||
description = "Library to assist implementing an mdBook preprocessor"
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mdbook-renderer"
|
||||
version = "0.5.0-alpha.1"
|
||||
version = "0.5.2"
|
||||
description = "Library to assist implementing an mdBook renderer"
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mdbook-summary"
|
||||
version = "0.5.0-alpha.1"
|
||||
version = "0.5.2"
|
||||
description = "Summary parser for mdBook"
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
@@ -74,7 +74,7 @@ fn cargo(args: &str, cb: &dyn Fn(&mut Command)) -> Result<()> {
|
||||
cb(&mut cmd);
|
||||
let status = cmd.status().expect("cargo should be installed");
|
||||
if !status.success() {
|
||||
return Err("command `cargo {args}` failed".into());
|
||||
return Err(format!("command `cargo {args}` failed").into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ By pulling in `mdbook-preprocessor` as a library, preprocessors can have access
|
||||
existing infrastructure for dealing with books.
|
||||
|
||||
For example, a custom preprocessor could use the
|
||||
[`CmdPreprocessor::parse_input()`] function to deserialize the JSON written to
|
||||
[`parse_input()`] function to deserialize the JSON written to
|
||||
`stdin`. Then each chapter of the `Book` can be mutated in-place via
|
||||
[`Book::for_each_mut()`], and then written to `stdout` with the `serde_json`
|
||||
crate.
|
||||
@@ -101,7 +101,7 @@ if __name__ == '__main__':
|
||||
[pc]: https://crates.io/crates/pulldown-cmark
|
||||
[pctc]: https://crates.io/crates/pulldown-cmark-to-cmark
|
||||
[an example no-op preprocessor]: https://github.com/rust-lang/mdBook/blob/master/examples/nop-preprocessor.rs
|
||||
[`CmdPreprocessor::parse_input()`]: https://docs.rs/mdbook-preprocessor/latest/mdbook_preprocessor/trait.Preprocessor.html#method.parse_input
|
||||
[`parse_input()`]: https://docs.rs/mdbook-preprocessor/latest/mdbook_preprocessor/fn.parse_input.html
|
||||
[`Book::for_each_mut()`]: https://docs.rs/mdbook-preprocessor/latest/mdbook_preprocessor/book/struct.Book.html#method.for_each_mut
|
||||
[`PreprocessorContext`]: https://docs.rs/mdbook-preprocessor/latest/mdbook_preprocessor/struct.PreprocessorContext.html
|
||||
[`Book`]: https://docs.rs/mdbook-preprocessor/latest/mdbook_preprocessor/book/struct.Book.html
|
||||
|
||||
@@ -12,11 +12,10 @@ underscore (`_`) is replaced with a dash (`-`).
|
||||
|
||||
For example:
|
||||
|
||||
- `MDBOOK_foo` -> `foo`
|
||||
- `MDBOOK_FOO` -> `foo`
|
||||
- `MDBOOK_FOO__BAR` -> `foo.bar`
|
||||
- `MDBOOK_FOO_BAR` -> `foo-bar`
|
||||
- `MDBOOK_FOO_bar__baz` -> `foo-bar.baz`
|
||||
- `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`.
|
||||
|
||||
@@ -143,11 +143,9 @@ The following configuration options are available:
|
||||
those labels. Defaults to `false`.
|
||||
- **git-repository-url:** A url to the git repository for the book. If provided
|
||||
an icon link will be output in the menu bar of the book.
|
||||
- **git-repository-icon:** The FontAwesome icon class to use for the git
|
||||
repository link. Defaults to `fab-github` which looks like <i class="fa fab-github"></i>.
|
||||
If you are not using GitHub, another option to consider is `fa-code-fork` which looks like <i class="fa fa-code-fork"></i>.
|
||||
- **git-repository-icon:** The Font Awesome icon class to use for the git repository link. Defaults to `fab-github` which looks like <i class="fab fa-github"></i>. If you are not using GitHub, another option to consider is `fas-code-fork` which looks like <i class="fas fa-code-fork"></i>. The start of the string should be `fa-` for regular icons, `fas-` for solid icons, or `fab-` for brand icons. See the [free icon set](https://fontawesome.com/v6/search) for the available icons.
|
||||
- **edit-url-template:** Edit url template, when provided shows a
|
||||
"Suggest an edit" button (which looks like <i class="fa fa-edit"></i>) for directly jumping to editing the currently
|
||||
"Suggest an edit" button (which looks like <i class="fas fa-pencil"></i>) for directly jumping to editing the currently
|
||||
viewed page. For e.g. GitHub projects set this to
|
||||
`https://github.com/<owner>/<repo>/edit/<branch>/{path}` or for
|
||||
Bitbucket projects set it to
|
||||
@@ -178,7 +176,7 @@ The following configuration options are available:
|
||||
### `[output.html.print]`
|
||||
|
||||
The `[output.html.print]` table provides options for controlling the printable output.
|
||||
By default, mdBook will include an icon on the top right of the book (which looks like <i class="fa fa-print"></i>) that will print the book as a single page.
|
||||
By default, mdBook will include an icon on the top right of the book (which looks like <i class="fas fa-print"></i>) that will print the book as a single page.
|
||||
|
||||
```toml
|
||||
[output.html.print]
|
||||
|
||||
@@ -73,7 +73,7 @@ nothidden():
|
||||
|
||||
## Rust playground
|
||||
|
||||
Rust language code blocks will automatically get a play button (<i class="fa fa-play"></i>) which will execute the code and display the output just below the code block.
|
||||
Rust language code blocks will automatically get a play button (<i class="fas fa-play"></i>) which will execute the code and display the output just below the code block.
|
||||
This works by sending the code to the [Rust Playground].
|
||||
|
||||
```rust
|
||||
@@ -340,7 +340,7 @@ HTML tags with class `hidden` will not be shown.
|
||||
|
||||
## Font-Awesome icons
|
||||
|
||||
mdBook includes a copy of [Font Awesome Free's](https://fontawesome.com)
|
||||
mdBook includes a copy of version 6 of [Font Awesome Free's](https://fontawesome.com)
|
||||
MIT-licensed SVG files. It emulates the `<i>` syntax, but converts the results
|
||||
to inline SVG. Only the regular, solid, and brands icons are included; paid
|
||||
features like the light icons are not.
|
||||
@@ -348,7 +348,9 @@ features like the light icons are not.
|
||||
For example, given this HTML syntax:
|
||||
|
||||
```hbs
|
||||
The result looks like this: <i class="fas fa-print"></i>
|
||||
The result looks like this: <i class="fa-solid fa-print"></i>
|
||||
```
|
||||
|
||||
The result looks like this: <i class="fas fa-print"></i>
|
||||
The result looks like this: <i class="fa-solid fa-print"></i>
|
||||
|
||||
See the [free icon set](https://fontawesome.com/v6/search) for the available icons.
|
||||
|
||||
@@ -95,7 +95,7 @@ MIT-licensed SVG files. It accepts three positional arguments:
|
||||
1. Type: one of "solid", "regular", and "brands" (light and duotone are not
|
||||
currently supported)
|
||||
2. Icon: anything chosen from the
|
||||
[free icon set](https://fontawesome.com/icons?d=gallery&m=free)
|
||||
[free icon set](https://fontawesome.com/v6/search)
|
||||
3. ID (optional): if included, an HTML ID attribute will be added to the
|
||||
icon's wrapping `<span>` tag
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ Tapping the menu bar will scroll the page to the top.
|
||||
## Search
|
||||
|
||||
Each book has a built-in search system.
|
||||
Pressing the search icon (<i class="fa fa-search"></i>) in the menu bar, or pressing the <kbd>/</kbd> or <kbd>S</kbd> key on the keyboard will open an input box for entering search terms.
|
||||
Pressing the search icon <i class="fas fa-magnifying-glass"></i> in the menu bar, or pressing the <kbd>/</kbd> or <kbd>S</kbd> key on the keyboard will open an input box for entering search terms.
|
||||
Typing some terms will show matching chapters and sections in real time.
|
||||
|
||||
Clicking any of the results will jump to that section.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"browser-ui-test": "0.22.2",
|
||||
"browser-ui-test": "0.22.3",
|
||||
"eslint": "^9.34.0"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -41,7 +41,6 @@ pub fn rebuild_on_change(
|
||||
|
||||
loop {
|
||||
std::thread::sleep(Duration::new(1, 0));
|
||||
watcher.set_roots(&book);
|
||||
let start = Instant::now();
|
||||
let paths = watcher.scan();
|
||||
let elapsed = start.elapsed().as_secs_f64();
|
||||
@@ -67,6 +66,7 @@ pub fn rebuild_on_change(
|
||||
post_build();
|
||||
}
|
||||
book = b;
|
||||
watcher.set_roots(&book);
|
||||
}
|
||||
Err(e) => error!("failed to load book config: {e:?}"),
|
||||
}
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
[book]
|
||||
title = "mdBook test book"
|
||||
description = "A demo book to test and validate changes"
|
||||
authors = ["YJDoc2"]
|
||||
language = "en"
|
||||
|
||||
[rust]
|
||||
edition = "2018"
|
||||
|
||||
[output.html]
|
||||
mathjax-support = true
|
||||
hash-files = true
|
||||
|
||||
[output.html.playground]
|
||||
editable = true
|
||||
line-numbers = true
|
||||
|
||||
[output.html.search]
|
||||
limit-results = 20
|
||||
use-boolean-and = true
|
||||
boost-title = 2
|
||||
boost-hierarchy = 2
|
||||
boost-paragraph = 1
|
||||
expand = true
|
||||
heading-split-level = 2
|
||||
|
||||
[output.html.redirect]
|
||||
"/format/config.html" = "../prefix.html"
|
||||
|
||||
# This is a source without a fragment, and one with a fragment that goes to
|
||||
# the same place. The redirect with the fragment is not necessary, since that
|
||||
# is the default behavior.
|
||||
"/pointless-fragment.html" = "prefix.html"
|
||||
"/pointless-fragment.html#foo" = "prefix.html#foo"
|
||||
|
||||
"/rename-page-and-fragment.html" = "prefix.html"
|
||||
"/rename-page-and-fragment.html#orig" = "prefix.html#new"
|
||||
|
||||
"/rename-page-fragment-elsewhere.html" = "prefix.html"
|
||||
"/rename-page-fragment-elsewhere.html#orig" = "suffix.html#new"
|
||||
|
||||
# Rename fragment on an existing page.
|
||||
"/prefix.html#orig" = "prefix.html#new"
|
||||
# Rename fragment on an existing page to another page.
|
||||
"/prefix.html#orig-new-page" = "suffix.html#new"
|
||||
|
||||
"/full-url-with-fragment.html" = "https://www.rust-lang.org/#fragment"
|
||||
|
||||
"/full-url-with-fragment-map.html" = "https://www.rust-lang.org/"
|
||||
"/full-url-with-fragment-map.html#a" = "https://www.rust-lang.org/#new1"
|
||||
"/full-url-with-fragment-map.html#b" = "https://www.rust-lang.org/#new2"
|
||||
@@ -1,12 +0,0 @@
|
||||
# Demo Book
|
||||
|
||||
This is a simple demo book, which is intended to be used for verifying and validating style changes in mdBook.
|
||||
This contains dummy examples of various markdown elements and code languages, so that one can check changes made in mdBook styles.
|
||||
|
||||
This rough outline is :
|
||||
|
||||
- individual : contains basic markdown elements such as headings, paragraphs, links etc.
|
||||
- languages : contains a `hello world` in each of supported language to see changes in syntax highlighting
|
||||
- rust : contains language examples specific to rust, such as play pen, runnable examples etc.
|
||||
|
||||
This is more for checking and fixing style, rather than verifying that correct code is generated for given markdown, that is better handled in tests.
|
||||
@@ -1,42 +0,0 @@
|
||||
# Summary
|
||||
|
||||
[Prefix Chapter](prefix.md)
|
||||
|
||||
---
|
||||
|
||||
- [Introduction](README.md)
|
||||
- [Draft Chapter]()
|
||||
|
||||
# Actual Markdown Tag Examples
|
||||
|
||||
- [Markdown Individual tags](individual/README.md)
|
||||
- [Heading](individual/heading.md)
|
||||
- [Paragraphs](individual/paragraph.md)
|
||||
- [Line Break](individual/linebreak.md)
|
||||
- [Emphasis](individual/emphasis.md)
|
||||
- [Blockquote](individual/blockquote.md)
|
||||
- [List](individual/list.md)
|
||||
- [Code](individual/code.md)
|
||||
- [Image](individual/image.md)
|
||||
- [Links and Horizontal Rule](individual/link_hr.md)
|
||||
- [Tables](individual/table.md)
|
||||
- [Tasks](individual/task.md)
|
||||
- [Strikethrough](individual/strikethrough.md)
|
||||
- [MathJax](individual/mathjax.md)
|
||||
- [Mixed](individual/mixed.md)
|
||||
- [Languages](languages/README.md)
|
||||
- [Syntax Highlight](languages/highlight.md)
|
||||
- [Rust Specific](rust/README.md)
|
||||
- [Rust Codeblocks](rust/rust_codeblock.md)
|
||||
- [Heading Navigation](headings/README.md)
|
||||
- [Empty page](headings/empty.md)
|
||||
- [Large text before first heading](headings/large-intro.md)
|
||||
- [Normal text before first heading](headings/normal-intro.md)
|
||||
- [Collapsed headings](headings/collapsed.md)
|
||||
- [Headings with markup](headings/markup.md)
|
||||
- [Current scrolls to bottom](headings/current-to-bottom.md)
|
||||
- [Last numbered chapter](last.md)
|
||||
|
||||
---
|
||||
|
||||
[Suffix Chapter](suffix.md)
|
||||
@@ -1 +0,0 @@
|
||||
# Heading Navigation
|
||||
@@ -1,17 +0,0 @@
|
||||
# Individual Common mark tags
|
||||
|
||||
This contains following tags:
|
||||
|
||||
- Headings
|
||||
- Paragraphs
|
||||
- Line breaks
|
||||
- Emphasis
|
||||
- Blockquotes
|
||||
- Lists
|
||||
- Code blocks
|
||||
- Images
|
||||
- Links and Horizontal rules
|
||||
- Github tables
|
||||
- Github Task Lists
|
||||
- Strikethrough
|
||||
- Mixed
|
||||
@@ -1,30 +0,0 @@
|
||||
# Blockquote
|
||||
|
||||
> This is a quoted sentence.
|
||||
|
||||
> This is a quoted paragraph
|
||||
>
|
||||
> separated lines
|
||||
> here
|
||||
|
||||
> Nested
|
||||
>
|
||||
> > Quoted
|
||||
> > Paragraph
|
||||
|
||||
> ### And now,
|
||||
>
|
||||
> **Let us _introduce_**
|
||||
> All kinds of
|
||||
>
|
||||
> - tags
|
||||
> - etc
|
||||
> - stuff
|
||||
>
|
||||
> 1. In
|
||||
> 2. The
|
||||
> 3. blockquote
|
||||
>
|
||||
> > cause we can
|
||||
> >
|
||||
> > > Cause we can
|
||||
@@ -1,33 +0,0 @@
|
||||
# Code
|
||||
|
||||
This section only does simple code blocks and inline code, detailed syntax highlight and stuff is in the languages section
|
||||
|
||||
---
|
||||
|
||||
```
|
||||
This is a codeblock
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
This line contains `inline code` mixed with some other stuff. (LTR)
|
||||
|
||||
ושורה זו מכילה `inline code` אבל עם טקסט בשפה שנכתבת מימין לשמאל. (RTL)
|
||||
|
||||
---
|
||||
|
||||
````
|
||||
escaping ``` in ```, fun, isn't it?
|
||||
````
|
||||
|
||||
---
|
||||
|
||||
```bash,editable
|
||||
This is an editable codeblock
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
```rust
|
||||
// This links to a playpen
|
||||
```
|
||||
@@ -1,13 +0,0 @@
|
||||
# Emphasis
|
||||
|
||||
This has **bold text** in between normal.
|
||||
|
||||
This has _italic text_ in between normal.
|
||||
|
||||
A **line** having _both_, bold and italic text.
|
||||
|
||||
**A bold line _having_ italic text**
|
||||
|
||||
_An Italic line having **bold** text_
|
||||
|
||||
Now this is going **_out of hands_**.
|
||||
@@ -1,21 +0,0 @@
|
||||
# Chapter Heading
|
||||
|
||||
---
|
||||
|
||||
# Really Big Heading
|
||||
|
||||
## Big Heading
|
||||
|
||||
### Normal-ish Heading
|
||||
|
||||
#### Small Heading...?
|
||||
|
||||
##### Really Small Heading
|
||||
|
||||
###### Is it even a heading anymore - heading
|
||||
|
||||
## Custom id {#example-id}
|
||||
|
||||
## Custom class {.class1 .class2}
|
||||
|
||||
## Both id and class {#example-id2 .class1 .class2}
|
||||
@@ -1,27 +0,0 @@
|
||||
# Images
|
||||
|
||||
For copyright and trademark information on these images, please check [rust-artwork repository](https://github.com/rust-lang/rust-artworkhttps://github.com/rust-lang/rust-artwork)
|
||||
|
||||
## A 16x16 image
|
||||
|
||||

|
||||
|
||||
## A 32x32 image
|
||||
|
||||

|
||||
|
||||
## A 256x256 image
|
||||
|
||||

|
||||
|
||||
## A 512x512 image
|
||||
|
||||

|
||||
|
||||
## A large image
|
||||
|
||||

|
||||
|
||||
## A SVG image
|
||||
|
||||

|
||||
@@ -1,8 +0,0 @@
|
||||
# Line breaks
|
||||
|
||||
This is a long
|
||||
line with a couple of
|
||||
line breaks in <br/>
|
||||
between : both with two
|
||||
spaces and return, <br/>
|
||||
and with HTML tags.
|
||||
@@ -1,15 +0,0 @@
|
||||
# Links and Horizontal Rule
|
||||
|
||||
This is followed by a Horizontal rule
|
||||
|
||||
---
|
||||
|
||||
And this is preceded by a horizontal rule.
|
||||
|
||||
[This](www.rust-lang.org) should link to rust-lang website
|
||||
[So should this][rl].
|
||||
**[This][rl]** is a strong link.
|
||||
_[This][rl]_ is italic.
|
||||
**_[This][rl]_** is both.
|
||||
|
||||
[rl]: www.rust-lang.org
|
||||
@@ -1,35 +0,0 @@
|
||||
# Lists
|
||||
|
||||
1. A
|
||||
2. Normal
|
||||
3. Ordered
|
||||
4. List
|
||||
|
||||
---
|
||||
|
||||
1. A
|
||||
1. Nested
|
||||
2. List
|
||||
2. But
|
||||
3. Still
|
||||
4. Normal
|
||||
|
||||
---
|
||||
|
||||
- An
|
||||
- Unordered
|
||||
- Normal
|
||||
- List
|
||||
|
||||
---
|
||||
|
||||
- Nested
|
||||
- Unordered
|
||||
- List
|
||||
|
||||
---
|
||||
|
||||
- This
|
||||
1. Is
|
||||
2. Normal
|
||||
- ?!
|
||||
@@ -1,42 +0,0 @@
|
||||
# MathJax
|
||||
|
||||
Fourier Transform
|
||||
|
||||
\\[
|
||||
\begin{aligned}
|
||||
f(x) &= \int_{-\infty}^{\infty}F(s)(-1)^{ 2xs}ds \\\\
|
||||
F(s) &= \int_{-\infty}^{\infty}f(x)(-1)^{-2xs}dx
|
||||
\end{aligned}
|
||||
\\]
|
||||
|
||||
The kernel can also be written as \\(e^{2i\pi xs}\\) which is more frequently used in literature.
|
||||
|
||||
> Proof that \\(e^{ix} = \cos x + i\sin x\\) a.k.a Euler's Formula:
|
||||
>
|
||||
> \\(
|
||||
\begin{aligned}
|
||||
e^x &= \sum_{n=0}^\infty \frac{x^n}{n!} \implies e^{ix} = \sum_{n=0}^\infty \frac{(ix)^n}{n!} \\\\
|
||||
\cos x &= \sum_{m=0}^\infty \frac{(-1)^m x^{2m}}{(2m)!} = \sum_{m=0}^\infty \frac{(ix)^{2m}}{(2m)!} \\\\
|
||||
\sin x &= \sum_{s=0}^\infty \frac{(-1)^s x^{2s+1}}{(2s+1)!} = \sum_{s=0}^\infty \frac{(ix)^{2s+1}}{i(2s+1)!} \\\\
|
||||
\cos x + i\sin x &= \sum_{l=0}^\infty \frac{(ix)^{2l}}{(2l)!} + \sum_{s=0}^\infty \frac{(ix)^{2s+1}}{(2s+1)!} = \sum_{n=0}^\infty \frac{(ix)^{n}}{n!} \\\\
|
||||
&= e^{ix}
|
||||
\end{aligned}
|
||||
\\)
|
||||
>
|
||||
|
||||
|
||||
Pauli Matrices
|
||||
|
||||
\\[
|
||||
\begin{aligned}
|
||||
\sigma_x &= \begin{pmatrix}
|
||||
1 & 0 \\\\ 0 & 1
|
||||
\end{pmatrix} \\\\
|
||||
\sigma_y &= \begin{pmatrix}
|
||||
0 & -i \\\\ i & 0
|
||||
\end{pmatrix} \\\\
|
||||
\sigma_z &= \begin{pmatrix}
|
||||
1 & 0 \\\\ 0 & -1
|
||||
\end{pmatrix}
|
||||
\end{aligned}
|
||||
\\]
|
||||
@@ -1,64 +0,0 @@
|
||||
# Mixed
|
||||
|
||||
This contains all tags randomly mixed together, to make sure style changes in one does not affect others.
|
||||
|
||||
### A heading
|
||||
|
||||
**Quite a Strong statement , to make**
|
||||
|
||||
~~No, cross that~~
|
||||
|
||||
> Whose **quote** is this
|
||||
>
|
||||
> > And ~~this~~
|
||||
> >
|
||||
> > > - and
|
||||
> > > - this
|
||||
> > > - also
|
||||
|
||||
```
|
||||
You encountered a wild codepen
|
||||
```
|
||||
|
||||
```rust,editable
|
||||
// The codepen is editable and runnable
|
||||
fn main(){
|
||||
println!("Hello world!");
|
||||
}
|
||||
```
|
||||
|
||||
<kbd>Ctrl</kbd> + <kbd>S</kbd> saves a file.
|
||||
|
||||
A random image sprinkled in between
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
- ~~An unordered list~~
|
||||
- **Hello**
|
||||
- _World_
|
||||
- What
|
||||
1. Should
|
||||
2. be
|
||||
3. `put`
|
||||
4. here?
|
||||
5. **<kbd>Ctrl</kbd> + <kbd>S</kbd> saves a file.**
|
||||
|
||||
| col1 | col2 | col 3 | col 4 | col 5 | col 6 |
|
||||
| ---- | ---- | ----- | ----- | ----- | ----- |
|
||||
| val1 | val2 | val3 | val5 | val4 | val6 |
|
||||
|
||||
| col1 | col2 | col 3 | An Questionable table header | col 5 | col 6 |
|
||||
| ---- | ---- | ----- | ---------------------------- | ----- | ---------------------------------------- |
|
||||
| val1 | val2 | val3 | val5 | val4 | An equally Questionable long table value |
|
||||
|
||||
### Things to do
|
||||
|
||||
- [x] Add individual tags
|
||||
- [ ] Add language examples
|
||||
- [ ] Add rust specific examples
|
||||
|
||||
And another image
|
||||
|
||||

|
||||
@@ -1,25 +0,0 @@
|
||||
Just a simple paragraph.
|
||||
|
||||
Let's stress test this.
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer elit lorem, eleifend eu leo sit amet, suscipit feugiat libero. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Proin congue lectus sit amet lacus venenatis, ac sollicitudin purus condimentum. Suspendisse pretium volutpat sapien at gravida. In tincidunt, sem non accumsan consectetur, leo libero porttitor dolor, at imperdiet erat nibh quis leo. Cras dictum erat augue, quis pharetra justo porttitor posuere. Aenean sed lacinia justo, vel suscipit nisl. Etiam eleifend id mauris at gravida. Aliquam molestie cursus lorem pulvinar sollicitudin. Nam et ex dignissim, posuere sem non, pellentesque lacus. Morbi vulputate sed lorem et convallis. Duis non turpis eget elit posuere volutpat. Donec accumsan euismod enim, id consequat ex rhoncus ac. Pellentesque ac felis nisl. Duis imperdiet vel tellus ac iaculis.
|
||||
|
||||
Vivamus nec tempus enim. Integer in ligula eget elit ornare vulputate id et est. Proin mi elit, sagittis nec urna et, iaculis imperdiet neque. Vestibulum placerat cursus dolor. Donec eu sodales nulla. Praesent ac tellus eros. Donec venenatis ligula id ex porttitor malesuada. Aliquam maximus, nisi in fringilla finibus, ante elit rhoncus dui, placerat semper nisl tellus quis odio. Cras luctus magna ultrices dolor pharetra volutpat. Maecenas non enim vitae ligula efficitur aliquet id quis quam. In sagittis mollis magna eu porta. Morbi at nulla et ante elementum pharetra in sed est. Nam commodo purus enim.
|
||||
|
||||
Ut non elit sit amet urna luctus facilisis vel et sapien. Morbi nec metus at libero imperdiet sollicitudin eget quis lacus. Donec in ipsum at enim accumsan tempor vel sed magna. Aliquam non imperdiet neque. Etiam pharetra neque sed pretium interdum. Suspendisse potenti. Phasellus varius, lectus quis dapibus faucibus, purus mauris accumsan nibh, vel tempor quam metus nec sem. Nunc sagittis suscipit lorem eu finibus. Nullam augue leo, imperdiet vel diam et, vulputate scelerisque turpis. Nullam ut volutpat diam. Praesent cursus accumsan dui a commodo. Vivamus sed libero sed turpis facilisis rutrum id sed ligula. Ut id sollicitudin dui. Nulla pulvinar commodo lectus. Cras ut quam congue, consectetur dolor ac, consequat ante.
|
||||
|
||||
Curabitur scelerisque sed leo eu facilisis. Nam faucibus neque eget dictum hendrerit. Duis efficitur ex sed vulputate volutpat. Praesent condimentum nisl ac sapien efficitur laoreet. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut ut nibh elit. Nunc a neque lobortis, tempus diam vitae, interdum magna. Aenean eget nisl sed justo volutpat interdum. Mauris malesuada ex nisl, a dignissim dui elementum eget. Suspendisse potenti.
|
||||
|
||||
Praesent congue fringilla sem sed faucibus. Vivamus malesuada eget mauris at molestie. In sed faucibus nulla. Vivamus elementum accumsan metus quis suscipit. Maecenas interdum est nulla. Cras volutpat cursus nibh quis sollicitudin. Morbi vitae massa laoreet, aliquet tellus quis, consectetur ipsum. Mauris euismod congue purus non condimentum. Etiam laoreet mi vel sem consectetur gravida. Vestibulum volutpat magna nunc, vitae ultrices risus commodo eu.
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer elit lorem, eleifend eu leo sit amet, suscipit feugiat libero. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Proin congue lectus sit amet lacus venenatis, ac sollicitudin purus condimentum. Suspendisse pretium volutpat sapien at gravida. In tincidunt, sem non accumsan consectetur, leo libero porttitor dolor, at imperdiet erat nibh quis leo. Cras dictum erat augue, quis pharetra justo porttitor posuere. Aenean sed lacinia justo, vel suscipit nisl. Etiam eleifend id mauris at gravida. Aliquam molestie cursus lorem pulvinar sollicitudin. Nam et ex dignissim, posuere sem non, pellentesque lacus. Morbi vulputate sed lorem et convallis. Duis non turpis eget elit posuere volutpat. Donec accumsan euismod enim, id consequat ex rhoncus ac. Pellentesque ac felis nisl. Duis imperdiet vel tellus ac iaculis.
|
||||
|
||||
Vivamus nec tempus enim. Integer in ligula eget elit ornare vulputate id et est. Proin mi elit, sagittis nec urna et, iaculis imperdiet neque. Vestibulum placerat cursus dolor. Donec eu sodales nulla. Praesent ac tellus eros. Donec venenatis ligula id ex porttitor malesuada. Aliquam maximus, nisi in fringilla finibus, ante elit rhoncus dui, placerat semper nisl tellus quis odio. Cras luctus magna ultrices dolor pharetra volutpat. Maecenas non enim vitae ligula efficitur aliquet id quis quam. In sagittis mollis magna eu porta. Morbi at nulla et ante elementum pharetra in sed est. Nam commodo purus enim.
|
||||
|
||||
Ut non elit sit amet urna luctus facilisis vel et sapien. Morbi nec metus at libero imperdiet sollicitudin eget quis lacus. Donec in ipsum at enim accumsan tempor vel sed magna. Aliquam non imperdiet neque. Etiam pharetra neque sed pretium interdum. Suspendisse potenti. Phasellus varius, lectus quis dapibus faucibus, purus mauris accumsan nibh, vel tempor quam metus nec sem. Nunc sagittis suscipit lorem eu finibus. Nullam augue leo, imperdiet vel diam et, vulputate scelerisque turpis. Nullam ut volutpat diam. Praesent cursus accumsan dui a commodo. Vivamus sed libero sed turpis facilisis rutrum id sed ligula. Ut id sollicitudin dui. Nulla pulvinar commodo lectus. Cras ut quam congue, consectetur dolor ac, consequat ante.
|
||||
|
||||
Curabitur scelerisque sed leo eu facilisis. Nam faucibus neque eget dictum hendrerit. Duis efficitur ex sed vulputate volutpat. Praesent condimentum nisl ac sapien efficitur laoreet. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut ut nibh elit. Nunc a neque lobortis, tempus diam vitae, interdum magna. Aenean eget nisl sed justo volutpat interdum. Mauris malesuada ex nisl, a dignissim dui elementum eget. Suspendisse potenti.
|
||||
|
||||
Praesent congue fringilla sem sed faucibus. Vivamus malesuada eget mauris at molestie. In sed faucibus nulla. Vivamus elementum accumsan metus quis suscipit. Maecenas interdum est nulla. Cras volutpat cursus nibh quis sollicitudin. Morbi vitae massa laoreet, aliquet tellus quis, consectetur ipsum. Mauris euismod congue purus non condimentum. Etiam laoreet mi vel sem consectetur gravida. Vestibulum volutpat magna nunc, vitae ultrices risus commodo eu.
|
||||
|
||||
Hopefully everything above was rendered nicely, on both desktop and mobile.
|
||||
@@ -1,7 +0,0 @@
|
||||
# Strikethrough
|
||||
|
||||
~Single strike~
|
||||
|
||||
~~This is Striked~~
|
||||
|
||||
~~This is **strong**, _italic_ , **_both_** and striked~~
|
||||
@@ -1,28 +0,0 @@
|
||||
# Tables
|
||||
|
||||
| col1 | col2 |
|
||||
| ---- | ---- |
|
||||
|
||||
---
|
||||
|
||||
| col1 | col2 |
|
||||
| ---- | ---- |
|
||||
| val1 | val2 |
|
||||
|
||||
---
|
||||
|
||||
| col1 | col2 | col 3 | col 4 | col 5 | col 6 |
|
||||
| ---- | ---- | ----- | ----- | ----- | ----- |
|
||||
| val1 | val2 | val3 | val5 | val4 | val6 |
|
||||
| val1 | val2 | val3 | val5 | val4 | val6 |
|
||||
| val1 | val2 | val3 | val5 | val4 | val6 |
|
||||
| val1 | val2 | val3 | val5 | val4 | val6 |
|
||||
|
||||
---
|
||||
|
||||
| col1 | col2 | col 3 | col 4 | col 5 | col 6 |
|
||||
| -------------------------------------------------------------------------------------------------------------- | ---- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ----- | -------------------------------------------------------------------------------------------------------------- |
|
||||
| This is a simple demo book, which is intended to be used for verifying and validating style changes in mdBook. | val2 | val3 | val5 | val4 | val6 |
|
||||
| val1 | val2 | val3 | val5 | val4 | val6 |
|
||||
| val1 | val2 | val3 | val5 | val4 | This is a simple demo book, which is intended to be used for verifying and validating style changes in mdBook. |
|
||||
| val1 | val2 | This is a simple demo book, which is intended to be used for verifying and validating style changes in mdBook. | This is a simple demo book, which is intended to be used for verifying and validating style changes in mdBook. | val4 | val6 |
|
||||
@@ -1,11 +0,0 @@
|
||||
# Tasks
|
||||
|
||||
- [ ] Task 1
|
||||
- [ ] Task 2
|
||||
- [x] Completed Task 1
|
||||
- [x] Completed Task 2
|
||||
|
||||
---
|
||||
|
||||
- [ ] **Important Task**
|
||||
- [x] _Completed Important task_
|
||||
@@ -1,49 +0,0 @@
|
||||
# Syntax Highlighting
|
||||
|
||||
This Currently contains following languages
|
||||
|
||||
- apache
|
||||
- armasm
|
||||
- bash
|
||||
- c
|
||||
- coffeescript
|
||||
- cpp
|
||||
- csharp
|
||||
- css
|
||||
- d
|
||||
- diff
|
||||
- go
|
||||
- handlebars
|
||||
- haskell
|
||||
- http
|
||||
- ini
|
||||
- java
|
||||
- javascript
|
||||
- json
|
||||
- julia
|
||||
- kotlin
|
||||
- less
|
||||
- lua
|
||||
- makefile
|
||||
- markdown
|
||||
- nginx
|
||||
- nim
|
||||
- nix
|
||||
- objectivec
|
||||
- perl
|
||||
- php
|
||||
- plaintext
|
||||
- properties
|
||||
- python
|
||||
- r
|
||||
- ruby
|
||||
- rust
|
||||
- scala
|
||||
- scss
|
||||
- shell
|
||||
- sql
|
||||
- swift
|
||||
- typescript
|
||||
- x86asm
|
||||
- xml
|
||||
- yaml
|
||||
@@ -1 +0,0 @@
|
||||
# Last numbered chapter
|
||||
@@ -1,3 +0,0 @@
|
||||
# Prefix Chapter
|
||||
|
||||
This is to verify the placement and style of prefix chapter in book index.
|
||||
@@ -1 +0,0 @@
|
||||
# Rust specific code examples
|
||||
@@ -1,27 +0,0 @@
|
||||
## Rust codeblocks
|
||||
|
||||
This contains various examples of codeblocks, specific to rust
|
||||
|
||||
## Simple
|
||||
|
||||
```rust
|
||||
fn main(){
|
||||
println!("Hello world!");
|
||||
}
|
||||
```
|
||||
|
||||
## With Hidden lines
|
||||
|
||||
```rust
|
||||
# fn main(){
|
||||
println!("Hello world!");
|
||||
# }
|
||||
```
|
||||
|
||||
## Editable
|
||||
|
||||
```rust,editable
|
||||
fn main(){
|
||||
println!("Hello world!");
|
||||
}
|
||||
```
|
||||
@@ -1,3 +0,0 @@
|
||||
# Suffix Chapter
|
||||
|
||||
This is to verify the placement and style of suffix chapter in book index.
|
||||
3
tests/gui/books/all-summary/README.md
Normal file
3
tests/gui/books/all-summary/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# All summary
|
||||
|
||||
This GUI test book tests all the different kinds of book items in the summary.
|
||||
2
tests/gui/books/all-summary/book.toml
Normal file
2
tests/gui/books/all-summary/book.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[book]
|
||||
title = "all-summary"
|
||||
20
tests/gui/books/all-summary/src/SUMMARY.md
Normal file
20
tests/gui/books/all-summary/src/SUMMARY.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Summary
|
||||
|
||||
[Prefix 1](prefix-1.md)
|
||||
[Prefix 2](prefix-2.md)
|
||||
|
||||
- [Introduction](intro.md)
|
||||
- [Draft]()
|
||||
|
||||
# Part 1
|
||||
|
||||
- [P1 C1](part-1/chapter-1.md)
|
||||
|
||||
---
|
||||
|
||||
# Part 2
|
||||
|
||||
- [P2 C1](part-2/chapter-1.md)
|
||||
|
||||
[Suffix 1](suffix-1.md)
|
||||
[Suffix 2](suffix-2.md)
|
||||
1
tests/gui/books/all-summary/src/intro.md
Normal file
1
tests/gui/books/all-summary/src/intro.md
Normal file
@@ -0,0 +1 @@
|
||||
# Introduction
|
||||
1
tests/gui/books/all-summary/src/part-1/chapter-1.md
Normal file
1
tests/gui/books/all-summary/src/part-1/chapter-1.md
Normal file
@@ -0,0 +1 @@
|
||||
# P1 C1
|
||||
1
tests/gui/books/all-summary/src/part-2/chapter-1.md
Normal file
1
tests/gui/books/all-summary/src/part-2/chapter-1.md
Normal file
@@ -0,0 +1 @@
|
||||
# P2 C1
|
||||
1
tests/gui/books/all-summary/src/prefix-1.md
Normal file
1
tests/gui/books/all-summary/src/prefix-1.md
Normal file
@@ -0,0 +1 @@
|
||||
# Prefix 1
|
||||
1
tests/gui/books/all-summary/src/prefix-2.md
Normal file
1
tests/gui/books/all-summary/src/prefix-2.md
Normal file
@@ -0,0 +1 @@
|
||||
# Prefix 2
|
||||
1
tests/gui/books/all-summary/src/suffix-1.md
Normal file
1
tests/gui/books/all-summary/src/suffix-1.md
Normal file
@@ -0,0 +1 @@
|
||||
# Suffix 1
|
||||
1
tests/gui/books/all-summary/src/suffix-2.md
Normal file
1
tests/gui/books/all-summary/src/suffix-2.md
Normal file
@@ -0,0 +1 @@
|
||||
# Suffix 2
|
||||
2
tests/gui/books/basic/book.toml
Normal file
2
tests/gui/books/basic/book.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[book]
|
||||
title = "basic"
|
||||
3
tests/gui/books/basic/src/SUMMARY.md
Normal file
3
tests/gui/books/basic/src/SUMMARY.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Summary
|
||||
|
||||
- [Chapter 1](./chapter_1.md)
|
||||
1
tests/gui/books/basic/src/chapter_1.md
Normal file
1
tests/gui/books/basic/src/chapter_1.md
Normal file
@@ -0,0 +1 @@
|
||||
# Chapter 1
|
||||
6
tests/gui/books/heading-nav-folded/book.toml
Normal file
6
tests/gui/books/heading-nav-folded/book.toml
Normal file
@@ -0,0 +1,6 @@
|
||||
[book]
|
||||
title = "heading-nav-folded"
|
||||
|
||||
[output.html.fold]
|
||||
enable = true
|
||||
level = 0
|
||||
7
tests/gui/books/heading-nav-folded/src/SUMMARY.md
Normal file
7
tests/gui/books/heading-nav-folded/src/SUMMARY.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# Summary
|
||||
|
||||
- [Introduction](./intro.md)
|
||||
- [Sub chapter](./sub/index.md)
|
||||
- [Sub inner](./sub/inner/index.md)
|
||||
- [Sub second chapter](./sub/second.md)
|
||||
- [Next main chapter](./next-main.md)
|
||||
9
tests/gui/books/heading-nav-folded/src/intro.md
Normal file
9
tests/gui/books/heading-nav-folded/src/intro.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Introduction
|
||||
|
||||
## Heading A
|
||||
|
||||
### Heading A2
|
||||
|
||||
### Heading A3
|
||||
|
||||
## Heading B
|
||||
1
tests/gui/books/heading-nav-folded/src/next-main.md
Normal file
1
tests/gui/books/heading-nav-folded/src/next-main.md
Normal file
@@ -0,0 +1 @@
|
||||
# Next main chapter
|
||||
3
tests/gui/books/heading-nav-folded/src/sub/index.md
Normal file
3
tests/gui/books/heading-nav-folded/src/sub/index.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Sub chapter
|
||||
|
||||
## Sub-chapter heading
|
||||
@@ -0,0 +1,3 @@
|
||||
# Sub inner
|
||||
|
||||
## Inner chapter heading
|
||||
3
tests/gui/books/heading-nav-folded/src/sub/second.md
Normal file
3
tests/gui/books/heading-nav-folded/src/sub/second.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Sub second chapter
|
||||
|
||||
## Second chapter heading
|
||||
3
tests/gui/books/heading-nav/README.md
Normal file
3
tests/gui/books/heading-nav/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Heading nav
|
||||
|
||||
This GUI test book is used for testing sidebar heading navigation.
|
||||
2
tests/gui/books/heading-nav/book.toml
Normal file
2
tests/gui/books/heading-nav/book.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[book]
|
||||
title = "heading-nav"
|
||||
10
tests/gui/books/heading-nav/src/SUMMARY.md
Normal file
10
tests/gui/books/heading-nav/src/SUMMARY.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# Summary
|
||||
|
||||
- [Empty page](empty.md)
|
||||
- [Large text before first heading](large-intro.md)
|
||||
- [Normal text before first heading](normal-intro.md)
|
||||
- [Collapsed headings](collapsed.md)
|
||||
- [Headings with markup](markup.md)
|
||||
- [Current scrolls to bottom](current-to-bottom.md)
|
||||
- [Unusual heading levels](unusual-heading-levels.md)
|
||||
- [Filtered headings](filtered-headings.md)
|
||||
5
tests/gui/books/heading-nav/src/filtered-headings.md
Normal file
5
tests/gui/books/heading-nav/src/filtered-headings.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Filtered headings
|
||||
|
||||
## Skateboard
|
||||
|
||||
Checking for search marking.
|
||||
@@ -0,0 +1,9 @@
|
||||
# Unusual heading levels
|
||||
|
||||
### Heading 3
|
||||
|
||||
## Heading 2
|
||||
|
||||
#### Heading 5
|
||||
|
||||
#### Heading 5.1
|
||||
3
tests/gui/books/highlighting/README.md
Normal file
3
tests/gui/books/highlighting/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Syntax Highlighting
|
||||
|
||||
This GUI test book is used for testing syntax highlighting.
|
||||
2
tests/gui/books/highlighting/book.toml
Normal file
2
tests/gui/books/highlighting/book.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[book]
|
||||
title = "Syntax Highlighting"
|
||||
3
tests/gui/books/highlighting/src/SUMMARY.md
Normal file
3
tests/gui/books/highlighting/src/SUMMARY.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Summary
|
||||
|
||||
- [Languages](./languages.md)
|
||||
3
tests/gui/books/redirect/README.md
Normal file
3
tests/gui/books/redirect/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Redirect
|
||||
|
||||
This GUI test book tests the redirect configuration.
|
||||
28
tests/gui/books/redirect/book.toml
Normal file
28
tests/gui/books/redirect/book.toml
Normal file
@@ -0,0 +1,28 @@
|
||||
[book]
|
||||
title = "redirect"
|
||||
|
||||
[output.html.redirect]
|
||||
"/inner/old.html" = "../new-chapter.html"
|
||||
|
||||
# This is a source without a fragment, and one with a fragment that goes to
|
||||
# the same place. The redirect with the fragment is not necessary, since that
|
||||
# is the default behavior.
|
||||
"/pointless-fragment.html" = "new-chapter.html"
|
||||
"/pointless-fragment.html#foo" = "new-chapter.html#foo"
|
||||
|
||||
"/rename-page-and-fragment.html" = "new-chapter.html"
|
||||
"/rename-page-and-fragment.html#orig" = "new-chapter.html#new"
|
||||
|
||||
"/rename-page-fragment-elsewhere.html" = "new-chapter.html"
|
||||
"/rename-page-fragment-elsewhere.html#orig" = "other-chapter.html#new"
|
||||
|
||||
# Rename fragment on an existing page.
|
||||
"/new-chapter.html#orig" = "new-chapter.html#new"
|
||||
# Rename fragment on an existing page to another page.
|
||||
"/new-chapter.html#orig-new-chapter" = "other-chapter.html#new"
|
||||
|
||||
"/full-url-with-fragment.html" = "https://www.rust-lang.org/#fragment"
|
||||
|
||||
"/full-url-with-fragment-map.html" = "https://www.rust-lang.org/"
|
||||
"/full-url-with-fragment-map.html#a" = "https://www.rust-lang.org/#new1"
|
||||
"/full-url-with-fragment-map.html#b" = "https://www.rust-lang.org/#new2"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user