Compare commits

..

124 Commits

Author SHA1 Message Date
Eric Huss
5a4ac03c0d Merge pull request #2312 from ehuss/bump-version
Update to 0.4.37
2024-02-07 03:48:57 +00:00
Eric Huss
c5a506e240 Update to 0.4.37 2024-02-06 19:34:15 -08:00
Eric Huss
bc5cd13c16 Merge pull request #2311 from sspaeti/fix-search-with-form
fix input `s` into a form without triggering search
2024-02-07 03:21:41 +00:00
sspaeti
d406c7c09b fix input s into a form without triggering search 2024-02-06 10:15:56 +01:00
Eric Huss
9cf3117636 Merge pull request #2309 from ehuss/update-deps
Update dependencies
2024-02-05 22:41:50 +00:00
Eric Huss
61786ddcdf Update dependencies 2024-02-05 14:37:06 -08:00
Eric Huss
f33281fae2 Merge pull request #2310 from ehuss/update-env-logger
Update env_logger to 0.11
2024-02-05 22:26:31 +00:00
Eric Huss
93bd457a54 Update env_logger to 0.11 2024-02-05 14:22:21 -08:00
Eric Huss
600824bed2 Merge pull request #2308 from ehuss/pulldown_cmark-0.10
Update pulldown_cmark to 0.10
2024-02-05 22:21:55 +00:00
Eric Huss
42e635bb9e Update pulldown_cmark to 0.10 2024-02-05 14:11:27 -08:00
Eric Huss
d48810f045 Merge pull request #2307 from ehuss/backends_receive_render_context_via_stdin
Clean up test backends_receive_render_context_via_stdin
2024-02-05 20:17:35 +00:00
Eric Huss
3387cf373d Clean up test backends_receive_render_context_via_stdin 2024-02-05 09:53:50 -08:00
Eric Huss
7825bd6c5a Merge pull request #2306 from jvstme/master
docs: Fix broken link
2024-02-04 14:09:09 +00:00
Jvst Me
ba14f4ad53 docs: Fix broken link 2024-02-04 16:47:52 +03:00
Eric Huss
02bbc3f777 Merge pull request #2305 from gibbz00/patch-1
Fix minor sentencing issue in build.md
2024-02-04 12:37:31 +00:00
gibbz00
45a2d0b40e Fix minor sentencing issue in build.md 2024-02-04 08:57:50 +01:00
Eric Huss
53eccf7047 Merge pull request #2303 from infogulch/patch-1
summary.md: clarify that part titles must be h1 headers
2024-02-01 23:45:51 +00:00
Joe Taber
63000bc122 summary.md: clarify that part titles must be h1 headers 2024-01-31 01:47:05 -06:00
Eric Huss
220cb4f0c8 Merge pull request #2302 from GeckoEidechse/fix/missing-plus
docs: Add missing `+` in diff code block
2024-01-30 19:55:05 +00:00
GeckoEidechse
7ce3a41184 docs: Add missing + in diff code block
The closing bracket for the `if` statement is also nearly added but the leading `+` to indicate that was forgotten.
2024-01-30 17:43:37 +01:00
Eric Huss
51efaf2e81 Merge pull request #2297 from rust-lang/dependabot/cargo/shlex-1.3.0
Bump shlex from 1.2.0 to 1.3.0
2024-01-22 22:41:27 +00:00
dependabot[bot]
f0d6d428dc Bump shlex from 1.2.0 to 1.3.0
Bumps [shlex](https://github.com/comex/rust-shlex) from 1.2.0 to 1.3.0.
- [Changelog](https://github.com/comex/rust-shlex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/comex/rust-shlex/commits)

---
updated-dependencies:
- dependency-name: shlex
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-22 21:52:27 +00:00
Eric Huss
01778fc90a Merge pull request #2293 from rust-lang/dependabot/cargo/h2-0.3.24
Bump h2 from 0.3.22 to 0.3.24
2024-01-19 17:43:11 +00:00
dependabot[bot]
d9928ad3f9 Bump h2 from 0.3.22 to 0.3.24
Bumps [h2](https://github.com/hyperium/h2) from 0.3.22 to 0.3.24.
- [Release notes](https://github.com/hyperium/h2/releases)
- [Changelog](https://github.com/hyperium/h2/blob/v0.3.24/CHANGELOG.md)
- [Commits](https://github.com/hyperium/h2/compare/v0.3.22...v0.3.24)

---
updated-dependencies:
- dependency-name: h2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-19 16:23:16 +00:00
Eric Huss
77b7876986 Merge pull request #2291 from klensy/watch-me
pathdiff only used with watch feature, so make it optional
2024-01-15 13:37:12 +00:00
klensy
745f7c7313 pathdiff only used with watch feature, so make it optional 2024-01-15 12:49:29 +03:00
Eric Huss
0a96d0e3fa Merge pull request #2290 from klensy/less-clones
removes few more allocs
2024-01-14 14:09:37 +00:00
klensy
e3ad9d097e reduce useless regex allocs
from 474mb to 215mb

==40876== Total:     474,156,323 bytes in 1,521,025 blocks
==40876== At t-gmax: 13,872,954 bytes in 4,655 blocks
==40876== At t-end:  488,516 bytes in 884 blocks
==40876== Reads:     820,933,434 bytes
==40876== Writes:    514,838,350 bytes

to

==57763== Total:     215,292,393 bytes in 1,161,048 blocks
==57763== At t-gmax: 13,872,954 bytes in 4,655 blocks
==57763== At t-end:  1,210,783 bytes in 1,274 blocks
==57763== Reads:     598,542,892 bytes
==57763== Writes:    229,841,910 bytes
2024-01-14 15:17:31 +03:00
klensy
573b6522f9 remove useless alloc
on rust reference book this reduces total allocs from 490mb to 474mb:

==23272== Total:     490,538,699 bytes in 1,760,117 blocks
==23272== At t-gmax: 13,872,954 bytes in 4,655 blocks
==23272== At t-end:  488,516 bytes in 884 blocks
==23272== Reads:     830,509,060 bytes
==23272== Writes:    522,290,614 bytes

to

==40876== Total:     474,156,323 bytes in 1,521,025 blocks
==40876== At t-gmax: 13,872,954 bytes in 4,655 blocks
==40876== At t-end:  488,516 bytes in 884 blocks
==40876== Reads:     820,933,434 bytes
==40876== Writes:    514,838,350 bytes
2024-01-14 15:17:07 +03:00
Eric Huss
59d3717159 Merge pull request #2283 from sunng87/feature/hbd-5
feat: upgrade handlebars to 5.0
2024-01-04 21:00:18 +00:00
Ning Sun
a42eafc316 feat: upgrade handlebars to 5.0 2024-01-04 20:16:34 +08:00
Eric Huss
11f839b9e5 Merge pull request #2282 from max-heller/patch-1
Fix typo in guide
2024-01-04 01:11:14 +00:00
Max Heller
721274239a fix typo in guide 2024-01-03 19:46:10 -05:00
Eric Huss
090eba0db5 Merge pull request #2273 from klensy/useless-clone
remove useless string clone
2023-12-16 14:41:39 +00:00
klensy
88be4ac417 remove useless string clone 2023-12-16 13:29:24 +03:00
Dylan DPC
c1d622e56e Merge pull request #2263 from jhult/theme-dir-warning-check
Remove warning check for theme directory as ./src/theme
2023-12-10 08:33:10 +00:00
Jonathan Hult
91af1c3b54 Remove warning check for theme directory as ./src/theme
This was causing an unnecessary warning if &src_dir was the same as ctx.root
2023-12-09 16:53:57 -06:00
Eric Huss
b7f46213c7 Merge pull request #2253 from ehuss/bump-version
Update to 0.4.36
2023-11-29 22:54:44 +00:00
Eric Huss
aa8982bdb4 Update to 0.4.36 2023-11-29 14:50:26 -08:00
Eric Huss
14826db606 Merge pull request #2252 from ehuss/update-lockfile
Update dependencies
2023-11-29 22:44:41 +00:00
Eric Huss
847a582022 Update msrv to 1.70 2023-11-29 14:36:39 -08:00
Eric Huss
97cd00faeb Update dependencies 2023-11-29 14:29:31 -08:00
Eric Huss
8d4193fb46 Merge pull request #2229 from leonzchang/fix/normalize-path
Fix `mdbook serve` unexpected panic
2023-11-29 22:16:39 +00:00
leonzchang
8d4ae388fa update comment 2023-11-29 11:51:23 +08:00
leonzchang
7082689866 add comment 2023-11-29 11:50:07 +08:00
leonzchang
40c034ed3f apply suggest changes 2023-11-29 11:34:08 +08:00
Dylan DPC
208d5ea7ab Merge pull request #2250 from DuckDuckWhale/master
Dep: fix Tungstenite DoS (RUSTSEC-2023-0065)
2023-11-26 09:42:25 +00:00
DuckDuckWhale
ed51438c8b Dep: fix Tungstenite DoS (RUSTSEC-2023-0065) 2023-11-26 01:05:20 -08:00
Eric Huss
49fce6673a Merge pull request #2209 from cyevgeniy/feat/sidebar-resize-indicator
Add resize indicator to the sidebar
2023-11-24 20:31:14 +00:00
Eric Huss
a016ac0d2b Merge pull request #2173 from 0xpr03/master
upgrade to notify 6.1.1 and watcher-mini 4.1
2023-11-24 20:05:37 +00:00
Eric Huss
ad55f5367e Merge pull request #2162 from ISSOtm/padding-hljs
Fix code blocks "indent" without highlight.js
2023-11-24 19:59:55 +00:00
Eric Huss
660cbfa6ce Merge pull request #2243 from wyfo/patch-1
fix typo
2023-11-19 13:53:15 +00:00
Joseph Perez
982608246e fix typo 2023-11-19 14:46:50 +01:00
Dylan DPC
6f6de2cf05 Merge pull request #2235 from ardcore/improvement/fix-print-margin
Make sure page wrapper transform is removed in print mode
2023-11-16 13:44:27 +00:00
Szymon Pilkowski
ae3e3f8269 Make sure page wrapper transform is removed in print mode 2023-11-10 21:51:00 +01:00
Eric Huss
dc21f1497b Merge pull request #2232 from arnetheduck/add-nim
Add Nim to default languages
2023-11-09 03:32:44 +00:00
Jacek Sieka
5c8941ba16 Add Nim to default languages
Nim is a systems programming language (included in the highlight.js
`system` group), and we're quite happily using `mdBook` in several of
our documentation projects starting with our [style
guide](https://status-im.github.io/nim-style-guide/).

While we can maintain our own highlight.js, including `Nim` in the
default distribution would allow us to promote more mdBook usage in the
Nim community at the cost of a ~2kb increase in the `highlight.js` size.
2023-11-08 15:34:35 +01:00
leonzchang
b0a001c6a4 create relative path through ignore root and path 2023-11-08 13:35:35 +08:00
leonzchang
722c55f85f normalize path to relative 2023-11-01 12:33:13 +08:00
leonzchang
3ab19f3295 Revert "bump version v0.4.36"
This reverts commit 621ffc46c0.
2023-10-31 12:22:08 +08:00
leonzchang
621ffc46c0 bump version v0.4.36 2023-10-31 12:14:28 +08:00
leonzchang
fbb629c02e normalize path in watch cmd 2023-10-31 12:13:25 +08:00
Evgeny Chaban
80d3a86468 fix: hide resize indicator on devices with limited accuracy 2023-10-04 01:55:20 +03:00
Evgeny Chaban
8e8fd2717e fix(style): use calc function 2023-10-04 01:40:16 +03:00
Evgeny Chaban
f92d24e89c feat(sidebar): add sidebar indicator 2023-10-02 18:24:55 +03:00
Eric Huss
94e0a44e15 Merge pull request #2206 from ehuss/bump-version
Update to 0.4.35
2023-09-29 22:43:05 +00:00
Eric Huss
f25181f68d Update to 0.4.35 2023-09-29 14:33:45 -07:00
Eric Huss
cf19eb1386 Fix text-direction in documentation. 2023-09-29 14:33:20 -07:00
Eric Huss
0583119698 Merge pull request #2197 from dluschan/patch-1
Update index.hbs
2023-09-22 17:26:27 +00:00
Dmitry Luschan
3389f3db7f Update index.hbs
Trailing slash on void elements has no effect and interacts badly with unquoted attribute values.
2023-09-19 20:44:39 +06:00
Eric Huss
c642f5f8a3 Merge pull request #2187 from notriddle/notriddle/warning-block
Add `.warning` class for doc author use
2023-09-09 20:13:10 +00:00
Michael Howell
ceb8b509e2 Add more guides to stock CSS classes 2023-09-08 13:27:02 -07:00
Michael Howell
65dae11e47 Add .warning class for doc author use
This is designed to be compatible with rustdoc's version, in
https://github.com/rust-lang/rust/pull/106561
2023-09-08 13:17:21 -07:00
Dylan DPC
d5b1676216 Merge pull request #2168 from pickfire/prefetch
Add prefetch to next link
2023-09-04 18:03:38 +00:00
Eric Huss
09f222baf7 Merge pull request #1641 from cN3rd/rtl
Continued work on "Support right-to-left languages"
2023-09-02 23:57:48 +00:00
Eric Huss
802e7bffc3 Make the arrow keys honor RTL.
At least to my understanding, the pages will flip in the opposite direction.
2023-09-02 16:44:47 -07:00
Eric Huss
fb272d1afa Fix theme selector for RTL. 2023-09-02 16:43:21 -07:00
Eric Huss
b871676def Fix sidebar behavior with RTL. 2023-09-02 16:43:13 -07:00
Eric Huss
869fe2f50d Remove text_drection_from_lang_code
The test above should cover this sufficiently.
2023-09-02 16:42:53 -07:00
Eric Huss
db877b1c9b Update language list to include missing rtl languages. 2023-09-02 16:42:14 -07:00
Eric Huss
4749f9d97a Some minor corrections from code review. 2023-09-02 16:41:59 -07:00
cN3rd
8564a7fb51 Add proper test to inline code within the book. 2023-09-02 14:38:02 -07:00
cN3rd
6be98e0bbd Ensure code segments always render in LTR 2023-09-02 14:37:59 -07:00
cN3rd
5e0c68c45e Fix icons when using RTL 2023-09-02 07:50:23 -07:00
cN3rd
7717b9dcf2 Support text_direction attribute in HTML output 2023-09-02 07:50:21 -07:00
cN3rd
819a108f07 Add text_direction property in general book metadata
Text direction can selected in the config via the `text_direction` attribute in `book.toml`,
or be derived from the book's language.
2023-09-02 07:49:28 -07:00
Tim Crawford
3a99899114 Use CSS selectors to override properties for RTL
Fix behavior of some elements when displaying page in RTL.

Signed-off-by: Tim Crawford <crawfxrd@gmail.com>
2023-09-02 07:49:28 -07:00
Tim Crawford
1088066c69 Move sidebar, js classes from html to body element
This will be necessary for using CSS selectors on root attributes.

Signed-off-by: Tim Crawford <crawfxrd@gmail.com>
2023-09-02 07:49:27 -07:00
Tim Crawford
73d44503fd Use logical CSS properties
Replace phyiscal properties (top/bottom/left/right) with logical
properties (start/end) that can be used in non-LTR contexts (e.g.,
content in Arabic or Hebrew).

Based on the CSS Logical Properties and Values Level 1 specification,
currently an Editor's Draft [1].

Referencing MDN, all major browsers except Internet Explorer support the
margin, padding, and border properties.

[1]: https://drafts.csswg.org/css-logical/

Signed-off-by: Tim Crawford <crawfxrd@gmail.com>
2023-09-02 07:47:12 -07:00
Eric Huss
25aaff0bd6 Merge pull request #2182 from cuishuang/master
remove the repetitive word
2023-09-02 13:41:15 +00:00
cui fliter
29691461c5 remove the repetitive word
Signed-off-by: cui fliter <imcusg@gmail.com>
2023-09-02 14:04:32 +08:00
Dylan DPC
a74e4dcec8 Merge pull request #2181 from tshepang/patch-1
docs: future expansion to non-Rust testing already implied
2023-09-01 08:55:38 +00:00
Tshepang Mbambo
0b0b548d7a docs: future expansion to non-Rust testing already implied 2023-09-01 05:11:18 +02:00
Dylan DPC
02f3823e4c Merge pull request #2175 from qaqland/sidebar-pure-css
Sidebar but Pure CSS, fix rust-lang/mdBook#859
2023-08-24 13:11:14 +00:00
qaqland
36327efe9d Sidebar but Pure CSS, fix rust-lang/mdBook#859
* change sidebar-toggle button by input:checked and label
* change nav-wrappers' CSS selectors
* remove loading animation when page opens with z-index
2023-08-24 16:44:25 +08:00
Aron Heinecke
079f52a191 upgrade to notify 6.1.1 and watcher-mini 4.1 2023-08-21 20:28:56 +02:00
Ivan Tham
c9f1d01346 Add prefetch to next link
Fix #1975
2023-08-17 00:50:47 +08:00
Eldred Habert
9bc68bdd93 Fix code blocks "indent" without highlight.js
The `.hljs` class added by highlight.js adds a `display: block` rule
which makes `padding` apply correctly (left padding on all lines,
not just the first one).
Make sure that rule is applied even if highlight.js isn't run.
2023-08-08 12:31:55 +02:00
Eric Huss
56c225bd34 Merge pull request #2158 from ehuss/bump-version
Update to 0.4.34
2023-08-05 21:54:12 +00:00
Eric Huss
55c017cad1 Update to 0.4.34 2023-08-05 14:34:42 -07:00
Eric Huss
7849d55b99 Merge pull request #2157 from ehuss/macos-notify-copy
Add workaround for macOS notify problem.
2023-08-05 20:35:33 +00:00
Eric Huss
c903cc8827 Add workaround for macOS notify problem. 2023-08-05 13:23:17 -07:00
Eric Huss
4a797b9565 Revert "Merge pull request #2152 from ehuss/macos-notify-kqueue"
This reverts commit 347e7886e1, reversing
changes made to a8fd6038f1.
2023-08-05 12:53:23 -07:00
Eric Huss
57b487eaa3 Merge pull request #2154 from ehuss/bump-version
Update to 0.4.33
2023-08-04 00:11:45 +00:00
Eric Huss
891b7c06f2 Update to 0.4.33 2023-08-03 17:03:40 -07:00
Eric Huss
f7e212ec9c Merge pull request #2150 from proski/header-code-background
Don't use distinct background for code in headers when printing
2023-08-03 22:46:50 +00:00
Pavel Roskin
228538ea62 Don't use distinct background for code in headers when printing
Fixes #1933
2023-08-02 23:31:46 -07:00
Eric Huss
347e7886e1 Merge pull request #2152 from ehuss/macos-notify-kqueue
Switch macOS notify to kqueue.
2023-08-02 22:13:09 +00:00
Eric Huss
bfa5fb8844 Switch macOS notify to kqueue. 2023-08-02 09:21:25 -07:00
Eric Huss
a8fd6038f1 Merge pull request #2151 from ehuss/revert-toml
Revert toml update
2023-08-02 15:49:44 +00:00
Eric Huss
fbfe887084 Add note to not update toml. 2023-08-02 08:39:23 -07:00
Eric Huss
aed991f75f Revert "Merge pull request #2125 from ehuss/update-toml"
This reverts commit 89797064b8, reversing
changes made to 7824aed878.
2023-08-02 08:32:44 -07:00
Eric Huss
ab2cb71c00 Merge pull request #2134 from GiorgioReale/master
Enhancing themes with `color-scheme: light | dark;` implementation in CSS
2023-07-30 22:50:08 +00:00
Giorgio Reale
fcfde083e7 Enhancing themes with color-scheme: light | dark; implementation in CSS 2023-07-30 15:43:51 -07:00
Eric Huss
4614a3637a Merge pull request #2146 from riverbl/fix-extra-watch-dirs
Fix issues with extra-watch-dirs
2023-07-30 17:08:46 +00:00
Eric Huss
d450544d6b Merge pull request #2148 from ehuss/fix-merge-queue
Use a better merge-queue success check.
2023-07-29 16:23:04 +00:00
Eric Huss
9340e6a78d Use a better merge-queue success check. 2023-07-29 09:13:55 -07:00
riverbl
e00b8835cc Fix issues with extra-watch-dirs
Fix paths specified in extra-watch-dirs being relative to the current working directory rather than the book root

If there is an error canonicalising paths in extra-watch-dirs, log the error and exit rather than panicking
2023-07-28 20:07:20 +01:00
Eric Huss
429ca06289 Merge pull request #2140 from ehuss/merge-queue-workflow
Prepare CI workflows to support merge queues.
2023-07-24 20:35:16 -07:00
Eric Huss
0fbfc90bea Prepare CI workflows to support merge queues. 2023-07-24 20:16:07 -07:00
Eric Huss
581e5025a2 Merge pull request #2139 from tshepang/patch-1
misplaced bracket
2023-07-21 07:32:56 -07:00
Tshepang Mbambo
e57fce290b misplaced bracket 2023-07-21 15:29:56 +02:00
Eric Huss
d5a3682de9 Merge pull request #2137 from ehuss/mdbook-case-link
Fix link on case-sensitive filesystems.
2023-07-19 08:06:35 -07:00
Eric Huss
75f5862218 Fix link on case-sensitive filesystems. 2023-07-19 07:54:39 -07:00
41 changed files with 1577 additions and 819 deletions

View File

@@ -1,7 +1,5 @@
name: CI
on:
push:
branches-ignore: [master]
pull_request:
merge_group:
@@ -31,7 +29,7 @@ jobs:
- build: msrv
os: ubuntu-20.04
# sync MSRV with docs: guide/src/guide/installation.md and Cargo.toml
rust: 1.66.0
rust: 1.71.0
steps:
- uses: actions/checkout@v3
- name: Install Rust
@@ -49,3 +47,20 @@ jobs:
- name: Install Rust
run: rustup update stable && rustup default stable && rustup component add rustfmt
- run: cargo fmt --check
# The success job is here to consolidate the total success/failure state of
# all other jobs. This job is then included in the GitHub branch protection
# rule which prevents merges unless all other jobs are passing. This makes
# it easier to manage the list of jobs via this yml file and to prevent
# accidentally adding new jobs without also updating the branch protections.
success:
name: Success gate
if: always()
needs:
- test
- rustfmt
runs-on: ubuntu-latest
steps:
- run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
- name: Done
run: exit 0

View File

@@ -1,5 +1,91 @@
# Changelog
## mdBook 0.4.37
[v0.4.36...v0.4.37](https://github.com/rust-lang/mdBook/compare/v0.4.36...v0.4.37)
### Changed
- ❗️ Updated the markdown parser. This brings in many changes to more closely follow the CommonMark spec. This may cause some small rendering changes. It is recommended to compare the output of the old and new version to check for changes. See <https://github.com/raphlinus/pulldown-cmark/releases/tag/v0.10.0> for more information.
[#2308](https://github.com/rust-lang/mdBook/pull/2308)
- The warning about the legacy `src/theme` directory has been removed.
[#2263](https://github.com/rust-lang/mdBook/pull/2263)
- Updated dependencies. MSRV raised to 1.71.0.
[#2283](https://github.com/rust-lang/mdBook/pull/2283)
[#2293](https://github.com/rust-lang/mdBook/pull/2293)
[#2297](https://github.com/rust-lang/mdBook/pull/2297)
[#2310](https://github.com/rust-lang/mdBook/pull/2310)
[#2309](https://github.com/rust-lang/mdBook/pull/2309)
- Some internal performance/memory improvements.
[#2273](https://github.com/rust-lang/mdBook/pull/2273)
[#2290](https://github.com/rust-lang/mdBook/pull/2290)
- Made the `pathdiff` dependency optional based on the `watch` feature.
[#2291](https://github.com/rust-lang/mdBook/pull/2291)
### Fixed
- The `s` shortcut key handler should not trigger when focus is in an HTML form.
[#2311](https://github.com/rust-lang/mdBook/pull/2311)
## mdBook 0.4.36
[v0.4.35...v0.4.36](https://github.com/rust-lang/mdBook/compare/v0.4.35...v0.4.36)
### Added
- Added Nim to the default highlighted languages.
[#2232](https://github.com/rust-lang/mdBook/pull/2232)
- Added a small indicator for the sidebar resize handle.
[#2209](https://github.com/rust-lang/mdBook/pull/2209)
### Changed
- Updated dependencies. MSRV raised to 1.70.0.
[#2173](https://github.com/rust-lang/mdBook/pull/2173)
[#2250](https://github.com/rust-lang/mdBook/pull/2250)
[#2252](https://github.com/rust-lang/mdBook/pull/2252)
### Fixed
- Fixed blank column in print page when the sidebar was visible.
[#2235](https://github.com/rust-lang/mdBook/pull/2235)
- Fixed indentation of code blocks when Javascript is disabled.
[#2162](https://github.com/rust-lang/mdBook/pull/2162)
- Fixed a panic when `mdbook serve` or `mdbook watch` were given certain kinds of paths.
[#2229](https://github.com/rust-lang/mdBook/pull/2229)
## mdBook 0.4.35
[v0.4.34...v0.4.35](https://github.com/rust-lang/mdBook/compare/v0.4.34...v0.4.35)
### Added
- Added the `book.text-direction` setting for explicit support for right-to-left languages.
[#1641](https://github.com/rust-lang/mdBook/pull/1641)
- Added `rel=prefetch` to the "next" links to potentially improve browser performance.
[#2168](https://github.com/rust-lang/mdBook/pull/2168)
- Added a `.warning` CSS class which is styled for displaying warning blocks.
[#2187](https://github.com/rust-lang/mdBook/pull/2187)
### Changed
- Better support of the sidebar when JavaScript is disabled.
[#2175](https://github.com/rust-lang/mdBook/pull/2175)
## mdBook 0.4.34
[v0.4.33...v0.4.34](https://github.com/rust-lang/mdBook/compare/v0.4.33...v0.4.34)
### Fixed
- Fixed file change watcher failing on macOS with a large number of files.
[#2157](https://github.com/rust-lang/mdBook/pull/2157)
## mdBook 0.4.33
[v0.4.32...v0.4.33](https://github.com/rust-lang/mdBook/compare/v0.4.32...v0.4.33)
### Added
- The `color-scheme` CSS property is now set based on the light/dark theme, which applies some slight color differences in browser elements like scroll bars on some browsers.
[#2134](https://github.com/rust-lang/mdBook/pull/2134)
### Fixed
- Fixed watching of extra-watch-dirs when not running in the book root directory.
[#2146](https://github.com/rust-lang/mdBook/pull/2146)
- Reverted the dependency update to the `toml` crate (again!). This was an unintentional breaking change in 0.4.32.
[#2021](https://github.com/rust-lang/mdBook/pull/2021)
- Changed macOS change notifications to use the kqueue implementation which should fix some issues with repeated rebuilds when a file changed.
[#2152](https://github.com/rust-lang/mdBook/pull/2152)
- Don't set a background color in the print page for code blocks in a header.
[#2150](https://github.com/rust-lang/mdBook/pull/2150)
## mdBook 0.4.32
[v0.4.31...v0.4.32](https://github.com/rust-lang/mdBook/compare/v0.4.31...v0.4.32)
@@ -240,7 +326,7 @@
[#1771](https://github.com/rust-lang/mdBook/pull/1771)
- The 404 not-found page now includes the books title in the HTML title tag.
[#1693](https://github.com/rust-lang/mdBook/pull/1693)
- Migrated to clap 3.0 which which handles CLI option parsing.
- Migrated to clap 3.0 which handles CLI option parsing.
[#1731](https://github.com/rust-lang/mdBook/pull/1731)
### Fixed

View File

@@ -148,7 +148,7 @@ The following are instructions for updating [highlight.js](https://highlightjs.o
1. Clone the repository at <https://github.com/highlightjs/highlight.js>
1. Check out a tagged release (like `10.1.1`).
1. Run `npm install`
1. Run `node tools/build.js :common apache armasm coffeescript d handlebars haskell http julia nginx properties r scala x86asm yaml`
1. Run `node tools/build.js :common apache armasm coffeescript d handlebars haskell http julia nginx nim properties r scala x86asm yaml`
1. Compare the language list that it spits out to the one in [`syntax-highlighting.md`](https://github.com/camelid/mdBook/blob/master/guide/src/format/theme/syntax-highlighting.md). If any are missing, add them to the list and rebuild (and update these docs). If any are added to the common set, add them to `syntax-highlighting.md`.
1. Copy `build/highlight.min.js` to mdbook's directory [`highlight.js`](https://github.com/rust-lang/mdBook/blob/master/src/theme/highlight.js).
1. Be sure to check the highlight.js [CHANGES](https://github.com/highlightjs/highlight.js/blob/main/CHANGES.md) for any breaking changes. Breaking changes that would affect users will need to wait until the next major release.

965
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package]
name = "mdbook"
version = "0.4.32"
version = "0.4.37"
authors = [
"Mathieu David <mathieudavid@mathieudavid.org>",
"Michael-F-Bryan <michaelfbryan@gmail.com>",
@@ -14,7 +14,7 @@ license = "MPL-2.0"
readme = "README.md"
repository = "https://github.com/rust-lang/mdBook"
description = "Creates a book from markdown files"
rust-version = "1.66"
rust-version = "1.71"
[dependencies]
anyhow = "1.0.71"
@@ -22,29 +22,30 @@ chrono = { version = "0.4.24", default-features = false, features = ["clock"] }
clap = { version = "4.3.12", features = ["cargo", "wrap_help"] }
clap_complete = "4.3.2"
once_cell = "1.17.1"
env_logger = "0.10.0"
handlebars = "4.3.7"
env_logger = "0.11.1"
handlebars = "5.0"
log = "0.4.17"
memchr = "2.5.0"
opener = "0.6.1"
pulldown-cmark = { version = "0.9.3", default-features = false }
pulldown-cmark = { version = "0.10.0", default-features = false, features = ["html"] }
regex = "1.8.1"
serde = { version = "1.0.163", features = ["derive"] }
serde_json = "1.0.96"
shlex = "1.1.0"
shlex = "1.3.0"
tempfile = "3.4.0"
toml = "0.7.6"
toml = "0.5.11" # Do not update, see https://github.com/rust-lang/mdBook/issues/2037
topological-sort = "0.2.2"
# Watch feature
notify = { version = "6.0.1", optional = true }
notify-debouncer-mini = { version = "0.3.0", optional = true }
notify = { version = "6.1.1", optional = true }
notify-debouncer-mini = { version = "0.4.1", optional = true }
ignore = { version = "0.4.20", optional = true }
pathdiff = { version = "0.2.1", optional = true }
# Serve feature
futures-util = { version = "0.3.28", optional = true }
tokio = { version = "1.28.1", features = ["macros", "rt-multi-thread"], optional = true }
warp = { version = "0.3.5", default-features = false, features = ["websocket"], optional = true }
warp = { version = "0.3.6", default-features = false, features = ["websocket"], optional = true }
# Search feature
elasticlunr-rs = { version = "3.0.2", optional = true }
@@ -60,7 +61,7 @@ walkdir = "2.3.3"
[features]
default = ["watch", "serve", "search"]
watch = ["dep:notify", "dep:notify-debouncer-mini", "dep:ignore"]
watch = ["dep:notify", "dep:notify-debouncer-mini", "dep:ignore", "dep:pathdiff"]
serve = ["dep:futures-util", "dep:tokio", "dep:warp"]
search = ["dep:elasticlunr-rs", "dep:ammonia"]

View File

@@ -7,8 +7,8 @@ mdbook build
```
It will try to parse your `SUMMARY.md` file to understand the structure of your
book and fetch the corresponding files. Note that files mentioned in `SUMMARY.md`
but not present will be created.
book and fetch the corresponding files. Note that this will also create files
mentioned in `SUMMARY.md` which are not yet present.
The rendered output will maintain the same directory structure as the source for
convenience. Large books will therefore remain structured when rendered.

View File

@@ -6,8 +6,7 @@ of code examples that could get outdated. Therefore it is very important for
them to be able to automatically test these code examples.
mdBook supports a `test` command that will run all available tests in a book. At
the moment, only rustdoc tests are supported, but this may be expanded upon in
the future.
the moment, only Rust tests are supported.
#### Disable tests on a code block
@@ -65,4 +64,4 @@ not specified it will default to the value of the `build.build-dir` key in
#### --chapter
The `--chapter` (`-c`) option allows you to test a specific chapter of the
book using the chapter name or the relative path to the chapter.
book using the chapter name or the relative path to the chapter.

View File

@@ -21,7 +21,7 @@ A simple approach would be to use the popular `curl` CLI tool to download the ex
```sh
mkdir bin
curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.32/mdbook-v0.4.32-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=bin
curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.37/mdbook-v0.4.37-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=bin
bin/mdbook build
```

View File

@@ -287,7 +287,7 @@ like this:
+ if cfg.deny_odds && num_words % 2 == 1 {
+ eprintln!("{} has an odd number of words!", ch.name);
+ process::exit(1);
}
+ }
}
}
}

View File

@@ -46,6 +46,9 @@ This is general information about your book.
`src` directly under the root folder. But this is configurable with the `src`
key in the configuration file.
- **language:** The main language of the book, which is used as a language attribute `<html lang="en">` for example.
This is also used to derive the direction of text (RTL, LTR) within the book.
- **text-direction**: The direction of text in the book: Left-to-right (LTR) or Right-to-left (RTL). Possible values: `ltr`, `rtl`.
When not specified, the text direction is derived from the book's `language` attribute.
**book.toml**
```toml
@@ -55,6 +58,7 @@ authors = ["John Doe", "Jane Doe"]
description = "The example book covers examples."
src = "my-src" # the source files will be found in `root/my-src` instead of `root/src`
language = "en"
text-direction = "ltr"
```
### Rust options
@@ -97,7 +101,7 @@ extra-watch-dirs = [] # directories to watch for triggering builds
will be created when the book is built (i.e. `create-missing = true`). If this
is `false` then the build process will instead exit with an error if any files
do not exist.
- **use-default-preprocessors:** Disable the default preprocessors of (`links` &
- **use-default-preprocessors:** Disable the default preprocessors (of `links` &
`index`) by setting this option to `false`.
If you have the same, and/or other preprocessors declared via their table
@@ -111,4 +115,4 @@ extra-watch-dirs = [] # directories to watch for triggering builds
`use-default-preprocessors` that `links` it will run.
- **extra-watch-dirs**: A list of paths to directories that will be watched in
the `watch` and `serve` commands. Changes to files under these directories will
trigger rebuilds. Useful if your book depends on files outside its `src` directory.
trigger rebuilds. Useful if your book depends on files outside its `src` directory.

View File

@@ -73,14 +73,14 @@ Linking to a URL or local file is easy:
```markdown
Use [mdBook](https://github.com/rust-lang/mdBook).
Read about [mdBook](mdBook.md).
Read about [mdBook](mdbook.md).
A bare url: <https://www.rust-lang.org>.
```
Use [mdBook](https://github.com/rust-lang/mdBook).
Read about [mdBook](mdBook.md).
Read about [mdBook](mdbook.md).
A bare url: <https://www.rust-lang.org>.
@@ -232,4 +232,4 @@ Example:
This makes the level 1 heading with the content `Example heading`, ID `first`, and classes `class1` and `class2`. Note that the attributes should be space-separated.
More information can be found in the [heading attrs spec page](https://github.com/raphlinus/pulldown-cmark/blob/master/specs/heading_attrs.txt).
More information can be found in the [heading attrs spec page](https://github.com/raphlinus/pulldown-cmark/blob/master/pulldown-cmark/specs/heading_attrs.txt).

View File

@@ -314,3 +314,51 @@ contents (sidebar) by including a `\{{#title ...}}` near the top of the page.
```hbs
\{{#title My Title}}
```
## HTML classes provided by mdBook
<img class="right" src="images/rust-logo-blk.svg" alt="The Rust logo">
### `class="left"` and `"right"`
These classes are provided by default, for inline HTML to float images.
```html
<img class="right" src="images/rust-logo-blk.svg" alt="The Rust logo">
```
### `class="hidden"`
HTML tags with class `hidden` will not be shown.
```html
<div class="hidden">This will not be seen.</div>
```
<div class="hidden">This will not be seen.</div>
### `class="warning"`
To make a warning or similar note stand out, wrap it in a warning div.
```html
<div class="warning">
This is a bad thing that you should pay attention to.
Warning blocks should be used sparingly in documentation, to avoid "warning
fatigue," where people are trained to ignore them because they usually don't
matter for what they're doing.
</div>
```
<div class="warning">
This is a bad thing that you should pay attention to.
Warning blocks should be used sparingly in documentation, to avoid "warning
fatigue," where people are trained to ignore them because they usually don't
matter for what they're doing.
</div>

View File

@@ -29,11 +29,12 @@ to be ignored at best, or may cause an error when attempting to build the book.
- [First Chapter](relative/path/to/markdown2.md)
```
1. ***Part Title*** - Headers can be used as a title for the following numbered
chapters. This can be used to logically separate different sections
of the book. The title is rendered as unclickable text.
Titles are optional, and the numbered chapters can be broken into as many
parts as desired.
1. ***Part Title*** -
Level 1 headers can be used as a title for the following numbered chapters.
This can be used to logically separate different sections of the book.
The title is rendered as unclickable text.
Titles are optional, and the numbered chapters can be broken into as many parts as desired.
Part titles must be h1 headers (one `#`), other heading levels are ignored.
```markdown
# My Part Title

View File

@@ -44,6 +44,7 @@ your own `highlight.js` file:
- makefile
- markdown
- nginx
- nim
- objectivec
- perl
- php

View File

@@ -20,7 +20,7 @@ To make it easier to run, put the path to the binary into your `PATH`.
To build the `mdbook` executable from source, you will first need to install Rust and Cargo.
Follow the instructions on the [Rust installation page].
mdBook currently requires at least Rust version 1.66.
mdBook currently requires at least Rust version 1.71.
Once you have installed Rust, the following command can be used to build and install mdBook:

View File

@@ -99,11 +99,12 @@ impl BookBuilder {
fn write_book_toml(&self) -> Result<()> {
debug!("Writing book.toml");
let book_toml = self.root.join("book.toml");
let cfg =
toml::to_string(&self.config).with_context(|| "Unable to serialize the config")?;
let cfg = toml::to_vec(&self.config).with_context(|| "Unable to serialize the config")?;
fs::write(&book_toml, cfg)
.with_context(|| format!("failed to write {}", book_toml.display()))?;
File::create(book_toml)
.with_context(|| "Couldn't create book.toml")?
.write_all(&cfg)
.with_context(|| "Unable to write config to book.toml")?;
Ok(())
}

View File

@@ -1,7 +1,7 @@
use crate::errors::*;
use log::{debug, trace, warn};
use memchr::{self, Memchr};
use pulldown_cmark::{self, Event, HeadingLevel, Tag};
use memchr::Memchr;
use pulldown_cmark::{DefaultBrokenLinkCallback, Event, HeadingLevel, Tag, TagEnd};
use serde::{Deserialize, Serialize};
use std::fmt::{self, Display, Formatter};
use std::iter::FromIterator;
@@ -163,7 +163,7 @@ impl From<Link> for SummaryItem {
/// > match the following regex: "[^<>\n[]]+".
struct SummaryParser<'a> {
src: &'a str,
stream: pulldown_cmark::OffsetIter<'a, 'a>,
stream: pulldown_cmark::OffsetIter<'a, DefaultBrokenLinkCallback>,
offset: usize,
/// We can't actually put an event back into the `OffsetIter` stream, so instead we store it
@@ -210,7 +210,7 @@ macro_rules! collect_events {
}
impl<'a> SummaryParser<'a> {
fn new(text: &str) -> SummaryParser<'_> {
fn new(text: &'a str) -> SummaryParser<'a> {
let pulldown_parser = pulldown_cmark::Parser::new(text).into_offset_iter();
SummaryParser {
@@ -265,7 +265,12 @@ impl<'a> SummaryParser<'a> {
loop {
match self.next_event() {
Some(ev @ Event::Start(Tag::List(..)))
| Some(ev @ Event::Start(Tag::Heading(HeadingLevel::H1, ..))) => {
| Some(
ev @ Event::Start(Tag::Heading {
level: HeadingLevel::H1,
..
}),
) => {
if is_prefix {
// we've finished prefix chapters and are at the start
// of the numbered section.
@@ -275,8 +280,8 @@ impl<'a> SummaryParser<'a> {
bail!(self.parse_error("Suffix chapters cannot be followed by a list"));
}
}
Some(Event::Start(Tag::Link(_type, href, _title))) => {
let link = self.parse_link(href.to_string());
Some(Event::Start(Tag::Link { dest_url, .. })) => {
let link = self.parse_link(dest_url.to_string());
items.push(SummaryItem::Link(link));
}
Some(Event::Rule) => items.push(SummaryItem::Separator),
@@ -304,10 +309,13 @@ impl<'a> SummaryParser<'a> {
break;
}
Some(Event::Start(Tag::Heading(HeadingLevel::H1, ..))) => {
Some(Event::Start(Tag::Heading {
level: HeadingLevel::H1,
..
})) => {
debug!("Found a h1 in the SUMMARY");
let tags = collect_events!(self.stream, end Tag::Heading(HeadingLevel::H1, ..));
let tags = collect_events!(self.stream, end TagEnd::Heading(HeadingLevel::H1));
Some(stringify_events(tags))
}
@@ -336,7 +344,7 @@ impl<'a> SummaryParser<'a> {
/// Finishes parsing a link once the `Event::Start(Tag::Link(..))` has been opened.
fn parse_link(&mut self, href: String) -> Link {
let href = href.replace("%20", " ");
let link_content = collect_events!(self.stream, end Tag::Link(..));
let link_content = collect_events!(self.stream, end TagEnd::Link);
let name = stringify_events(link_content);
let path = if href.is_empty() {
@@ -377,7 +385,12 @@ impl<'a> SummaryParser<'a> {
}
// The expectation is that pulldown cmark will terminate a paragraph before a new
// heading, so we can always count on this to return without skipping headings.
Some(ev @ Event::Start(Tag::Heading(HeadingLevel::H1, ..))) => {
Some(
ev @ Event::Start(Tag::Heading {
level: HeadingLevel::H1,
..
}),
) => {
// we're starting a new part
self.back(ev);
break;
@@ -398,7 +411,7 @@ impl<'a> SummaryParser<'a> {
// Skip over the contents of this tag
while let Some(event) = self.next_event() {
if event == Event::End(other_tag.clone()) {
if event == Event::End(other_tag.clone().into()) {
break;
}
}
@@ -469,7 +482,7 @@ impl<'a> SummaryParser<'a> {
last_item.nested_items = sub_items;
}
Some(Event::End(Tag::List(..))) => break,
Some(Event::End(TagEnd::List(..))) => break,
Some(_) => {}
None => break,
}
@@ -486,8 +499,8 @@ impl<'a> SummaryParser<'a> {
loop {
match self.next_event() {
Some(Event::Start(Tag::Paragraph)) => continue,
Some(Event::Start(Tag::Link(_type, href, _title))) => {
let mut link = self.parse_link(href.to_string());
Some(Event::Start(Tag::Link { dest_url, .. })) => {
let mut link = self.parse_link(dest_url.to_string());
let mut number = parent.clone();
number.0.push(num_existing_items as u32 + 1);
@@ -529,14 +542,18 @@ impl<'a> SummaryParser<'a> {
fn parse_title(&mut self) -> Option<String> {
loop {
match self.next_event() {
Some(Event::Start(Tag::Heading(HeadingLevel::H1, ..))) => {
Some(Event::Start(Tag::Heading {
level: HeadingLevel::H1,
..
})) => {
debug!("Found a h1 in the SUMMARY");
let tags = collect_events!(self.stream, end Tag::Heading(HeadingLevel::H1, ..));
let tags = collect_events!(self.stream, end TagEnd::Heading(HeadingLevel::H1));
return Some(stringify_events(tags));
}
// Skip a HTML element such as a comment line.
Some(Event::Html(_)) => {}
Some(Event::Html(_) | Event::InlineHtml(_))
| Some(Event::Start(Tag::HtmlBlock) | Event::End(TagEnd::HtmlBlock)) => {}
// Otherwise, no title.
Some(ev) => {
self.back(ev);
@@ -744,7 +761,7 @@ mod tests {
let _ = parser.stream.next(); // Discard opening paragraph
let href = match parser.stream.next() {
Some((Event::Start(Tag::Link(_type, href, _title)), _range)) => href.to_string(),
Some((Event::Start(Tag::Link { dest_url, .. }), _range)) => dest_url.to_string(),
other => panic!("Unreachable, {:?}", other),
};

View File

@@ -4,6 +4,7 @@ use ignore::gitignore::Gitignore;
use mdbook::errors::Result;
use mdbook::utils;
use mdbook::MDBook;
use pathdiff::diff_paths;
use std::path::{Path, PathBuf};
use std::sync::mpsc::channel;
use std::thread::sleep;
@@ -86,12 +87,21 @@ fn find_gitignore(book_root: &Path) -> Option<PathBuf> {
.find(|p| p.exists())
}
// Note: The usage of `canonicalize` may encounter occasional failures on the Windows platform, presenting a potential risk.
// For more details, refer to [Pull Request #2229](https://github.com/rust-lang/mdBook/pull/2229#discussion_r1408665981).
fn filter_ignored_files(ignore: Gitignore, paths: &[PathBuf]) -> Vec<PathBuf> {
let ignore_root = ignore
.path()
.canonicalize()
.expect("ignore root canonicalize error");
paths
.iter()
.filter(|path| {
let relative_path =
diff_paths(&path, &ignore_root).expect("One of the paths should be an absolute");
!ignore
.matched_path_or_any_parents(path, path.is_dir())
.matched_path_or_any_parents(&relative_path, relative_path.is_dir())
.is_ignore()
})
.map(|path| path.to_path_buf())
@@ -108,8 +118,7 @@ where
// Create a channel to receive the events.
let (tx, rx) = channel();
let mut debouncer = match notify_debouncer_mini::new_debouncer(Duration::from_secs(1), None, tx)
{
let mut debouncer = match notify_debouncer_mini::new_debouncer(Duration::from_secs(1), tx) {
Ok(d) => d,
Err(e) => {
error!("Error while trying to watch the files:\n\n\t{:?}", e);
@@ -130,11 +139,16 @@ where
let _ = watcher.watch(&book.root.join("book.toml"), NonRecursive);
for dir in &book.config.build.extra_watch_dirs {
let path = dir.canonicalize().unwrap();
if let Err(e) = watcher.watch(&path, Recursive) {
let path = book.root.join(dir);
let canonical_path = path.canonicalize().unwrap_or_else(|e| {
error!("Error while watching extra directory {path:?}:\n {e}");
std::process::exit(1);
});
if let Err(e) = watcher.watch(&canonical_path, Recursive) {
error!(
"Error while watching extra directory {:?}:\n {:?}",
path, e
canonical_path, e
);
std::process::exit(1);
}
@@ -152,10 +166,8 @@ where
let paths: Vec<_> = all_events
.filter_map(|event| match event {
Ok(events) => Some(events),
Err(errors) => {
for error in errors {
log::warn!("error while watching for changes: {error}");
}
Err(error) => {
log::warn!("error while watching for changes: {error}");
None
}
})
@@ -174,3 +186,44 @@ where
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use ignore::gitignore::GitignoreBuilder;
use std::env;
#[test]
fn test_filter_ignored_files() {
let current_dir = env::current_dir().unwrap();
let ignore = GitignoreBuilder::new(&current_dir)
.add_line(None, "*.html")
.unwrap()
.build()
.unwrap();
let should_remain = current_dir.join("record.text");
let should_filter = current_dir.join("index.html");
let remain = filter_ignored_files(ignore, &[should_remain.clone(), should_filter]);
assert_eq!(remain, vec![should_remain])
}
#[test]
fn filter_ignored_files_should_handle_parent_dir() {
let current_dir = env::current_dir().unwrap();
let ignore = GitignoreBuilder::new(&current_dir)
.add_line(None, "*.html")
.unwrap()
.build()
.unwrap();
let parent_dir = current_dir.join("..");
let should_remain = parent_dir.join("record.text");
let should_filter = parent_dir.join("index.html");
let remain = filter_ignored_files(ignore, &[should_remain.clone(), should_filter]);
assert_eq!(remain, vec![should_remain])
}
}

View File

@@ -411,6 +411,9 @@ pub struct BookConfig {
pub multilingual: bool,
/// The main language of the book.
pub language: Option<String>,
/// The direction of text in the book: Left-to-right (LTR) or Right-to-left (RTL).
/// When not specified, the text direction is derived from [`BookConfig::language`].
pub text_direction: Option<TextDirection>,
}
impl Default for BookConfig {
@@ -422,6 +425,43 @@ impl Default for BookConfig {
src: PathBuf::from("src"),
multilingual: false,
language: Some(String::from("en")),
text_direction: None,
}
}
}
impl BookConfig {
/// Gets the realized text direction, either from [`BookConfig::text_direction`]
/// or derived from [`BookConfig::language`], to be used by templating engines.
pub fn realized_text_direction(&self) -> TextDirection {
if let Some(direction) = self.text_direction {
direction
} else {
TextDirection::from_lang_code(self.language.as_deref().unwrap_or_default())
}
}
}
/// Text direction to use for HTML output
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
pub enum TextDirection {
/// Left to right.
#[serde(rename = "ltr")]
LeftToRight,
/// Right to left
#[serde(rename = "rtl")]
RightToLeft,
}
impl TextDirection {
/// Gets the text direction from language code
pub fn from_lang_code(code: &str) -> Self {
match code {
// list sourced from here: https://github.com/abarrak/rtl/blob/master/lib/rtl/core.rb#L16
"ar" | "ara" | "arc" | "ae" | "ave" | "egy" | "he" | "heb" | "nqo" | "pal" | "phn"
| "sam" | "syc" | "syr" | "fa" | "per" | "fas" | "ku" | "kur" | "ur" | "urd"
| "pus" | "ps" | "yi" | "yid" => TextDirection::RightToLeft,
_ => TextDirection::LeftToRight,
}
}
}
@@ -788,6 +828,7 @@ mod tests {
multilingual: true,
src: PathBuf::from("source"),
language: Some(String::from("ja")),
text_direction: None,
};
let build_should_be = BuildConfig {
build_dir: PathBuf::from("outputs"),
@@ -1140,6 +1181,73 @@ mod tests {
assert_eq!(&get_404_output_file(&html_config.input_404), "missing.html");
}
#[test]
fn text_direction_ltr() {
let src = r#"
[book]
text-direction = "ltr"
"#;
let got = Config::from_str(src).unwrap();
assert_eq!(got.book.text_direction, Some(TextDirection::LeftToRight));
}
#[test]
fn text_direction_rtl() {
let src = r#"
[book]
text-direction = "rtl"
"#;
let got = Config::from_str(src).unwrap();
assert_eq!(got.book.text_direction, Some(TextDirection::RightToLeft));
}
#[test]
fn text_direction_none() {
let src = r#"
[book]
"#;
let got = Config::from_str(src).unwrap();
assert_eq!(got.book.text_direction, None);
}
#[test]
fn test_text_direction() {
let mut cfg = BookConfig::default();
// test deriving the text direction from language codes
cfg.language = Some("ar".into());
assert_eq!(cfg.realized_text_direction(), TextDirection::RightToLeft);
cfg.language = Some("he".into());
assert_eq!(cfg.realized_text_direction(), TextDirection::RightToLeft);
cfg.language = Some("en".into());
assert_eq!(cfg.realized_text_direction(), TextDirection::LeftToRight);
cfg.language = Some("ja".into());
assert_eq!(cfg.realized_text_direction(), TextDirection::LeftToRight);
// test forced direction
cfg.language = Some("ar".into());
cfg.text_direction = Some(TextDirection::LeftToRight);
assert_eq!(cfg.realized_text_direction(), TextDirection::LeftToRight);
cfg.language = Some("ar".into());
cfg.text_direction = Some(TextDirection::RightToLeft);
assert_eq!(cfg.realized_text_direction(), TextDirection::RightToLeft);
cfg.language = Some("en".into());
cfg.text_direction = Some(TextDirection::LeftToRight);
assert_eq!(cfg.realized_text_direction(), TextDirection::LeftToRight);
cfg.language = Some("en".into());
cfg.text_direction = Some(TextDirection::RightToLeft);
assert_eq!(cfg.realized_text_direction(), TextDirection::RightToLeft);
}
#[test]
#[should_panic(expected = "Invalid configuration file")]
fn invalid_language_type_error() {

View File

@@ -54,8 +54,7 @@ impl HtmlHandlebars {
.insert("git_repository_edit_url".to_owned(), json!(edit_url));
}
let content = ch.content.clone();
let content = utils::render_markdown(&content, ctx.html_config.curly_quotes);
let content = utils::render_markdown(&ch.content, ctx.html_config.curly_quotes);
let fixed_content =
utils::render_markdown_with_path(&ch.content, ctx.html_config.curly_quotes, Some(path));
@@ -478,25 +477,6 @@ impl HtmlHandlebars {
}
}
// TODO(mattico): Remove some time after the 0.1.8 release
fn maybe_wrong_theme_dir(dir: &Path) -> Result<bool> {
fn entry_is_maybe_book_file(entry: fs::DirEntry) -> Result<bool> {
Ok(entry.file_type()?.is_file()
&& entry.path().extension().map_or(false, |ext| ext == "md"))
}
if dir.is_dir() {
for entry in fs::read_dir(dir)? {
if entry_is_maybe_book_file(entry?).unwrap_or(false) {
return Ok(false);
}
}
Ok(true)
} else {
Ok(false)
}
}
impl Renderer for HtmlHandlebars {
fn name(&self) -> &str {
"html"
@@ -529,16 +509,6 @@ impl Renderer for HtmlHandlebars {
None => ctx.root.join("theme"),
};
if html_config.theme.is_none()
&& maybe_wrong_theme_dir(&src_dir.join("theme")).unwrap_or(false)
{
warn!(
"Previous versions of mdBook erroneously accepted `./src/theme` as an automatic \
theme directory"
);
warn!("Please move your theme files to `./theme` for them to continue being used");
}
let theme = theme::Theme::new(theme_dir);
debug!("Register the index handlebars template");
@@ -648,6 +618,10 @@ fn make_data(
"language".to_owned(),
json!(config.book.language.clone().unwrap_or_default()),
);
data.insert(
"text_direction".to_owned(),
json!(config.book.realized_text_direction()),
);
data.insert(
"book_title".to_owned(),
json!(config.book.title.clone().unwrap_or_default()),
@@ -961,8 +935,9 @@ fn add_playground_pre(
/// Modifies all `<code>` blocks to convert "hidden" lines and to wrap them in
/// a `<span class="boring">`.
fn hide_lines(html: &str, code_config: &Code) -> String {
let language_regex = Regex::new(r"\blanguage-(\w+)\b").unwrap();
let hidelines_regex = Regex::new(r"\bhidelines=(\S+)").unwrap();
static LANGUAGE_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"\blanguage-(\w+)\b").unwrap());
static HIDELINES_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"\bhidelines=(\S+)").unwrap());
CODE_BLOCK_RE
.replace_all(html, |caps: &Captures<'_>| {
let text = &caps[1];
@@ -977,12 +952,12 @@ fn hide_lines(html: &str, code_config: &Code) -> String {
)
} else {
// First try to get the prefix from the code block
let hidelines_capture = hidelines_regex.captures(classes);
let hidelines_capture = HIDELINES_REGEX.captures(classes);
let hidelines_prefix = match &hidelines_capture {
Some(capture) => Some(&capture[1]),
None => {
// Then look up the prefix by language
language_regex.captures(classes).and_then(|capture| {
LANGUAGE_REGEX.captures(classes).and_then(|capture| {
code_config.hidelines.get(&capture[1]).map(|p| p.as_str())
})
}
@@ -1088,6 +1063,8 @@ struct RenderItemContext<'a> {
#[cfg(test)]
mod tests {
use crate::config::TextDirection;
use super::*;
use pretty_assertions::assert_eq;
@@ -1299,4 +1276,10 @@ mod tests {
assert_eq!(&*got, *should_be);
}
}
#[test]
fn test_json_direction() {
assert_eq!(json!(TextDirection::RightToLeft), json!("rtl"));
assert_eq!(json!(TextDirection::LeftToRight), json!("ltr"));
}
}

View File

@@ -1,7 +1,9 @@
use std::collections::BTreeMap;
use std::path::Path;
use handlebars::{Context, Handlebars, Helper, Output, RenderContext, RenderError, Renderable};
use handlebars::{
Context, Handlebars, Helper, Output, RenderContext, RenderError, RenderErrorReason, Renderable,
};
use crate::utils;
use log::{debug, trace};
@@ -26,9 +28,9 @@ impl Target {
) -> Result<Option<StringMap>, RenderError> {
match *self {
Target::Next => {
let previous_path = previous_item
.get("path")
.ok_or_else(|| RenderError::new("No path found for chapter in JSON data"))?;
let previous_path = previous_item.get("path").ok_or_else(|| {
RenderErrorReason::Other("No path found for chapter in JSON data".to_owned())
})?;
if previous_path == base_path {
return Ok(Some(current_item.clone()));
@@ -54,15 +56,18 @@ fn find_chapter(
debug!("Get data from context");
let chapters = rc.evaluate(ctx, "@root/chapters").and_then(|c| {
serde_json::value::from_value::<Vec<StringMap>>(c.as_json().clone())
.map_err(|_| RenderError::new("Could not decode the JSON data"))
serde_json::value::from_value::<Vec<StringMap>>(c.as_json().clone()).map_err(|_| {
RenderErrorReason::Other("Could not decode the JSON data".to_owned()).into()
})
})?;
let base_path = rc
.evaluate(ctx, "@root/path")?
.as_json()
.as_str()
.ok_or_else(|| RenderError::new("Type error for `path`, string expected"))?
.ok_or_else(|| {
RenderErrorReason::Other("Type error for `path`, string expected".to_owned())
})?
.replace('\"', "");
if !rc.evaluate(ctx, "@root/is_index")?.is_missing() {
@@ -98,7 +103,7 @@ fn find_chapter(
}
}
previous = Some(item.clone());
previous = Some(item);
}
_ => continue,
}
@@ -108,7 +113,7 @@ fn find_chapter(
}
fn render(
_h: &Helper<'_, '_>,
_h: &Helper<'_>,
r: &Handlebars<'_>,
ctx: &Context,
rc: &mut RenderContext<'_, '_>,
@@ -122,7 +127,9 @@ fn render(
.evaluate(ctx, "@root/path")?
.as_json()
.as_str()
.ok_or_else(|| RenderError::new("Type error for `path`, string expected"))?
.ok_or_else(|| {
RenderErrorReason::Other("Type error for `path`, string expected".to_owned())
})?
.replace('\"', "");
context.insert(
@@ -132,17 +139,23 @@ fn render(
chapter
.get("name")
.ok_or_else(|| RenderError::new("No title found for chapter in JSON data"))
.ok_or_else(|| {
RenderErrorReason::Other("No title found for chapter in JSON data".to_owned())
})
.map(|name| context.insert("title".to_owned(), json!(name)))?;
chapter
.get("path")
.ok_or_else(|| RenderError::new("No path found for chapter in JSON data"))
.ok_or_else(|| {
RenderErrorReason::Other("No path found for chapter in JSON data".to_owned())
})
.and_then(|p| {
Path::new(p)
.with_extension("html")
.to_str()
.ok_or_else(|| RenderError::new("Link could not be converted to str"))
.ok_or_else(|| {
RenderErrorReason::Other("Link could not be converted to str".to_owned())
})
.map(|p| context.insert("link".to_owned(), json!(p.replace('\\', "/"))))
})?;
@@ -150,14 +163,14 @@ fn render(
let t = _h
.template()
.ok_or_else(|| RenderError::new("Error with the handlebars template"))?;
.ok_or_else(|| RenderErrorReason::Other("Error with the handlebars template".to_owned()))?;
let local_ctx = Context::wraps(&context)?;
let mut local_rc = rc.clone();
t.render(r, &local_ctx, &mut local_rc, out)
}
pub fn previous(
_h: &Helper<'_, '_>,
_h: &Helper<'_>,
r: &Handlebars<'_>,
ctx: &Context,
rc: &mut RenderContext<'_, '_>,
@@ -173,7 +186,7 @@ pub fn previous(
}
pub fn next(
_h: &Helper<'_, '_>,
_h: &Helper<'_>,
r: &Handlebars<'_>,
ctx: &Context,
rc: &mut RenderContext<'_, '_>,

View File

@@ -1,8 +1,10 @@
use handlebars::{Context, Handlebars, Helper, Output, RenderContext, RenderError};
use handlebars::{
Context, Handlebars, Helper, Output, RenderContext, RenderError, RenderErrorReason,
};
use log::trace;
pub fn theme_option(
h: &Helper<'_, '_>,
h: &Helper<'_>,
_r: &Handlebars<'_>,
ctx: &Context,
rc: &mut RenderContext<'_, '_>,
@@ -11,14 +13,21 @@ pub fn theme_option(
trace!("theme_option (handlebars helper)");
let param = h.param(0).and_then(|v| v.value().as_str()).ok_or_else(|| {
RenderError::new("Param 0 with String type is required for theme_option helper.")
RenderErrorReason::ParamTypeMismatchForName(
"theme_option",
"0".to_owned(),
"string".to_owned(),
)
})?;
let default_theme = rc.evaluate(ctx, "@root/default_theme")?;
let default_theme_name = default_theme
.as_json()
.as_str()
.ok_or_else(|| RenderError::new("Type error for `default_theme`, string expected"))?;
let default_theme_name = default_theme.as_json().as_str().ok_or_else(|| {
RenderErrorReason::ParamTypeMismatchForName(
"theme_option",
"default_theme".to_owned(),
"string".to_owned(),
)
})?;
out.write(param)?;
if param.to_lowercase() == default_theme_name.to_lowercase() {

View File

@@ -4,7 +4,9 @@ use std::{cmp::Ordering, collections::BTreeMap};
use crate::utils;
use crate::utils::bracket_escape;
use handlebars::{Context, Handlebars, Helper, HelperDef, Output, RenderContext, RenderError};
use handlebars::{
Context, Handlebars, Helper, HelperDef, Output, RenderContext, RenderError, RenderErrorReason,
};
// Handlebars helper to construct TOC
#[derive(Clone, Copy)]
@@ -15,7 +17,7 @@ pub struct RenderToc {
impl HelperDef for RenderToc {
fn call<'reg: 'rc, 'rc>(
&self,
_h: &Helper<'reg, 'rc>,
_h: &Helper<'rc>,
_r: &'reg Handlebars<'_>,
ctx: &'rc Context,
rc: &mut RenderContext<'reg, 'rc>,
@@ -26,13 +28,17 @@ impl HelperDef for RenderToc {
// param is the key of value you want to display
let chapters = rc.evaluate(ctx, "@root/chapters").and_then(|c| {
serde_json::value::from_value::<Vec<BTreeMap<String, String>>>(c.as_json().clone())
.map_err(|_| RenderError::new("Could not decode the JSON data"))
.map_err(|_| {
RenderErrorReason::Other("Could not decode the JSON data".to_owned()).into()
})
})?;
let current_path = rc
.evaluate(ctx, "@root/path")?
.as_json()
.as_str()
.ok_or_else(|| RenderError::new("Type error for `path`, string expected"))?
.ok_or_else(|| {
RenderErrorReason::Other("Type error for `path`, string expected".to_owned())
})?
.replace('\"', "");
let current_section = rc
@@ -46,13 +52,17 @@ impl HelperDef for RenderToc {
.evaluate(ctx, "@root/fold_enable")?
.as_json()
.as_bool()
.ok_or_else(|| RenderError::new("Type error for `fold_enable`, bool expected"))?;
.ok_or_else(|| {
RenderErrorReason::Other("Type error for `fold_enable`, bool expected".to_owned())
})?;
let fold_level = rc
.evaluate(ctx, "@root/fold_level")?
.as_json()
.as_u64()
.ok_or_else(|| RenderError::new("Type error for `fold_level`, u64 expected"))?;
.ok_or_else(|| {
RenderErrorReason::Other("Type error for `fold_level`, u64 expected".to_owned())
})?;
out.write("<ol class=\"chapter\">")?;

View File

@@ -66,10 +66,23 @@ fn add_doc(
index: &mut Index,
doc_urls: &mut Vec<String>,
anchor_base: &str,
section_id: &Option<String>,
heading: &str,
id_counter: &mut HashMap<String, usize>,
section_id: &Option<CowStr<'_>>,
items: &[&str],
) {
let url = if let Some(ref id) = *section_id {
// Either use the explicit section id the user specified, or generate one
// from the heading content.
let section_id = section_id.as_ref().map(|id| id.to_string()).or_else(|| {
if heading.is_empty() {
// In the case where a chapter has no heading, don't set a section id.
None
} else {
Some(utils::unique_id_from_content(heading, id_counter))
}
});
let url = if let Some(id) = section_id {
Cow::Owned(format!("{}#{}", anchor_base, id))
} else {
Cow::Borrowed(anchor_base)
@@ -119,7 +132,7 @@ fn render_item(
let mut id_counter = HashMap::new();
while let Some(event) = p.next() {
match event {
Event::Start(Tag::Heading(i, ..)) if i as u32 <= max_section_depth => {
Event::Start(Tag::Heading { level, id, .. }) if level as u32 <= max_section_depth => {
if !heading.is_empty() {
// Section finished, the next heading is following now
// Write the data to the index, and clear it for the next section
@@ -127,22 +140,21 @@ fn render_item(
index,
doc_urls,
&anchor_base,
&heading,
&mut id_counter,
&section_id,
&[&heading, &body, &breadcrumbs.join(" » ")],
);
section_id = None;
heading.clear();
body.clear();
breadcrumbs.pop();
}
section_id = id;
in_heading = true;
}
Event::End(Tag::Heading(i, id, _classes)) if i as u32 <= max_section_depth => {
Event::End(TagEnd::Heading(level)) if level as u32 <= max_section_depth => {
in_heading = false;
section_id = id
.map(|id| id.to_string())
.or_else(|| Some(utils::unique_id_from_content(&heading, &mut id_counter)));
breadcrumbs.push(heading.clone());
}
Event::Start(Tag::FootnoteDefinition(name)) => {
@@ -159,9 +171,19 @@ fn render_item(
html_block.push_str(html);
p.next();
}
body.push_str(&clean_html(&html_block));
}
Event::InlineHtml(html) => {
// This is not capable of cleaning inline tags like
// `foo <script>…</script>`. The `<script>` tags show up as
// individual InlineHtml events, and the content inside is
// just a regular Text event. There isn't a very good way to
// know how to collect all the content in-between. I'm not
// sure if this is easily fixable. It should be extremely
// rare, since script and style tags should almost always be
// blocks, and worse case you have some noise in the index.
body.push_str(&clean_html(&html));
}
Event::Start(_) | Event::End(_) | Event::Rule | Event::SoftBreak | Event::HardBreak => {
// Insert spaces where HTML output would usually separate text
// to ensure words don't get merged together
@@ -188,18 +210,24 @@ fn render_item(
}
if !body.is_empty() || !heading.is_empty() {
if heading.is_empty() {
let title = if heading.is_empty() {
if let Some(chapter) = breadcrumbs.first() {
heading = chapter.clone();
chapter
} else {
""
}
}
} else {
&heading
};
// Make sure the last section is added to the index
add_doc(
index,
doc_urls,
&anchor_base,
&heading,
&mut id_counter,
&section_id,
&[&heading, &body, &breadcrumbs.join(" » ")],
&[title, &body, &breadcrumbs.join(" » ")],
);
}

View File

@@ -441,7 +441,7 @@ function playground_text(playground, hidden = true) {
})();
(function sidebar() {
var html = document.querySelector("html");
var body = document.querySelector("body");
var sidebar = document.getElementById("sidebar");
var sidebarLinks = document.querySelectorAll('#sidebar a');
var sidebarToggleButton = document.getElementById("sidebar-toggle");
@@ -449,8 +449,8 @@ function playground_text(playground, hidden = true) {
var firstContact = null;
function showSidebar() {
html.classList.remove('sidebar-hidden')
html.classList.add('sidebar-visible');
body.classList.remove('sidebar-hidden')
body.classList.add('sidebar-visible');
Array.from(sidebarLinks).forEach(function (link) {
link.setAttribute('tabIndex', 0);
});
@@ -471,8 +471,8 @@ function playground_text(playground, hidden = true) {
});
function hideSidebar() {
html.classList.remove('sidebar-visible')
html.classList.add('sidebar-hidden');
body.classList.remove('sidebar-visible')
body.classList.add('sidebar-hidden');
Array.from(sidebarLinks).forEach(function (link) {
link.setAttribute('tabIndex', -1);
});
@@ -483,14 +483,14 @@ function playground_text(playground, hidden = true) {
// Toggle sidebar
sidebarToggleButton.addEventListener('click', function sidebarToggle() {
if (html.classList.contains("sidebar-hidden")) {
if (body.classList.contains("sidebar-hidden")) {
var current_width = parseInt(
document.documentElement.style.getPropertyValue('--sidebar-width'), 10);
if (current_width < 150) {
document.documentElement.style.setProperty('--sidebar-width', '150px');
}
showSidebar();
} else if (html.classList.contains("sidebar-visible")) {
} else if (body.classList.contains("sidebar-visible")) {
hideSidebar();
} else {
if (getComputedStyle(sidebar)['transform'] === 'none') {
@@ -506,14 +506,14 @@ function playground_text(playground, hidden = true) {
function initResize(e) {
window.addEventListener('mousemove', resize, false);
window.addEventListener('mouseup', stopResize, false);
html.classList.add('sidebar-resizing');
body.classList.add('sidebar-resizing');
}
function resize(e) {
var pos = (e.clientX - sidebar.offsetLeft);
if (pos < 20) {
hideSidebar();
} else {
if (html.classList.contains("sidebar-hidden")) {
if (body.classList.contains("sidebar-hidden")) {
showSidebar();
}
pos = Math.min(pos, window.innerWidth - 100);
@@ -522,7 +522,7 @@ function playground_text(playground, hidden = true) {
}
//on mouseup remove windows functions mousemove & mouseup
function stopResize(e) {
html.classList.remove('sidebar-resizing');
body.classList.remove('sidebar-resizing');
window.removeEventListener('mousemove', resize, false);
window.removeEventListener('mouseup', stopResize, false);
}
@@ -557,20 +557,35 @@ function playground_text(playground, hidden = true) {
document.addEventListener('keydown', function (e) {
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; }
if (window.search && window.search.hasFocus()) { return; }
var html = document.querySelector('html');
function next() {
var nextButton = document.querySelector('.nav-chapters.next');
if (nextButton) {
window.location.href = nextButton.href;
}
}
function prev() {
var previousButton = document.querySelector('.nav-chapters.previous');
if (previousButton) {
window.location.href = previousButton.href;
}
}
switch (e.key) {
case 'ArrowRight':
e.preventDefault();
var nextButton = document.querySelector('.nav-chapters.next');
if (nextButton) {
window.location.href = nextButton.href;
if (html.dir == 'rtl') {
prev();
} else {
next();
}
break;
case 'ArrowLeft':
e.preventDefault();
var previousButton = document.querySelector('.nav-chapters.previous');
if (previousButton) {
window.location.href = previousButton.href;
if (html.dir == 'rtl') {
next();
} else {
prev();
}
break;
}

View File

@@ -37,9 +37,9 @@ a > .hljs {
display: flex;
flex-wrap: wrap;
background-color: var(--bg);
border-bottom-color: var(--bg);
border-bottom-width: 1px;
border-bottom-style: solid;
border-block-end-color: var(--bg);
border-block-end-width: 1px;
border-block-end-style: solid;
}
#menu-bar.sticky,
.js #menu-bar-hover-placeholder:hover + #menu-bar,
@@ -56,7 +56,7 @@ a > .hljs {
height: var(--menu-bar-height);
}
#menu-bar.bordered {
border-bottom-color: var(--table-border-color);
border-block-end-color: var(--table-border-color);
}
#menu-bar i, #menu-bar .icon-button {
position: relative;
@@ -93,7 +93,7 @@ a > .hljs {
display: flex;
margin: 0 5px;
}
.no-js .left-buttons {
.no-js .left-buttons button {
display: none;
}
@@ -160,7 +160,7 @@ a > .hljs {
}
.nav-wrapper {
margin-top: 50px;
margin-block-start: 50px;
display: none;
}
@@ -173,23 +173,34 @@ a > .hljs {
background-color: var(--sidebar-bg);
}
.previous {
float: left;
}
/* Only Firefox supports flow-relative values */
.previous { float: left; }
[dir=rtl] .previous { float: right; }
/* Only Firefox supports flow-relative values */
.next {
float: right;
right: var(--page-padding);
}
[dir=rtl] .next {
float: left;
right: unset;
left: var(--page-padding);
}
/* Use the correct buttons for RTL layouts*/
[dir=rtl] .previous i.fa-angle-left:before {content:"\f105";}
[dir=rtl] .next i.fa-angle-right:before { content:"\f104"; }
@media only screen and (max-width: 1080px) {
.nav-wide-wrapper { display: none; }
.nav-wrapper { display: block; }
}
/* sidebar-visible */
@media only screen and (max-width: 1380px) {
.sidebar-visible .nav-wide-wrapper { display: none; }
.sidebar-visible .nav-wrapper { display: block; }
#sidebar-toggle-anchor:checked ~ .page-wrapper .nav-wide-wrapper { display: none; }
#sidebar-toggle-anchor:checked ~ .page-wrapper .nav-wrapper { display: block; }
}
/* Inline code */
@@ -236,7 +247,7 @@ pre > .buttons :hover {
background-color: var(--theme-hover);
}
pre > .buttons i {
margin-left: 8px;
margin-inline-start: 8px;
}
pre > .buttons button {
cursor: inherit;
@@ -258,8 +269,14 @@ pre > .buttons button {
/* On mobile, make it easier to tap buttons. */
padding: 0.3rem 1rem;
}
.sidebar-resize-indicator {
/* Hide resize indicator on devices with limited accuracy */
display: none;
}
}
pre > code {
display: block;
padding: 1rem;
}
@@ -273,7 +290,7 @@ pre > code {
}
pre > .result {
margin-top: 10px;
margin-block-start: 10px;
}
/* Search */
@@ -284,8 +301,14 @@ pre > .result {
mark {
border-radius: 2px;
padding: 0 3px 1px 3px;
margin: 0 -3px -1px -3px;
padding-block-start: 0;
padding-block-end: 1px;
padding-inline-start: 3px;
padding-inline-end: 3px;
margin-block-start: 0;
margin-block-end: -1px;
margin-inline-start: -3px;
margin-inline-end: -3px;
background-color: var(--search-mark-bg);
transition: background-color 300ms linear;
cursor: pointer;
@@ -297,14 +320,17 @@ mark.fade-out {
}
.searchbar-outer {
margin-left: auto;
margin-right: auto;
margin-inline-start: auto;
margin-inline-end: auto;
max-width: var(--content-max-width);
}
#searchbar {
width: 100%;
margin: 5px auto 0px auto;
margin-block-start: 5px;
margin-block-end: 0;
margin-inline-start: auto;
margin-inline-end: auto;
padding: 10px 16px;
transition: box-shadow 300ms ease-in-out;
border: 1px solid var(--searchbar-border-color);
@@ -320,20 +346,23 @@ mark.fade-out {
.searchresults-header {
font-weight: bold;
font-size: 1em;
padding: 18px 0 0 5px;
padding-block-start: 18px;
padding-block-end: 0;
padding-inline-start: 5px;
padding-inline-end: 0;
color: var(--searchresults-header-fg);
}
.searchresults-outer {
margin-left: auto;
margin-right: auto;
margin-inline-start: auto;
margin-inline-end: auto;
max-width: var(--content-max-width);
border-bottom: 1px dashed var(--searchresults-border-color);
border-block-end: 1px dashed var(--searchresults-border-color);
}
ul#searchresults {
list-style: none;
padding-left: 20px;
padding-inline-start: 20px;
}
ul#searchresults li {
margin: 10px 0px;
@@ -346,7 +375,10 @@ ul#searchresults li.focus {
ul#searchresults span.teaser {
display: block;
clear: both;
margin: 5px 0 0 20px;
margin-block-start: 5px;
margin-block-end: 0;
margin-inline-start: 20px;
margin-inline-end: 0;
font-size: 0.8em;
}
ul#searchresults span.teaser em {
@@ -369,12 +401,14 @@ ul#searchresults span.teaser em {
background-color: var(--sidebar-bg);
color: var(--sidebar-fg);
}
[dir=rtl] .sidebar { left: unset; right: 0; }
.sidebar-resizing {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
.no-js .sidebar,
.js:not(.sidebar-resizing) .sidebar {
transition: transform 0.3s; /* Animation: slide away */
}
@@ -394,16 +428,35 @@ ul#searchresults span.teaser em {
position: absolute;
cursor: col-resize;
width: 0;
right: 0;
right: calc(var(--sidebar-resize-indicator-width) * -1);
top: 0;
bottom: 0;
display: flex;
align-items: center;
}
.sidebar-resize-handle .sidebar-resize-indicator {
width: 100%;
height: 12px;
background-color: var(--icons);
margin-inline-start: var(--sidebar-resize-indicator-space);
}
[dir=rtl] .sidebar .sidebar-resize-handle {
left: calc(var(--sidebar-resize-indicator-width) * -1);
right: unset;
}
.js .sidebar .sidebar-resize-handle {
cursor: col-resize;
width: 5px;
width: calc(var(--sidebar-resize-indicator-width) - var(--sidebar-resize-indicator-space));
}
.sidebar-hidden .sidebar {
transform: translateX(calc(0px - var(--sidebar-width)));
/* sidebar-hidden */
#sidebar-toggle-anchor:not(:checked) ~ .sidebar {
transform: translateX(calc(0px - var(--sidebar-width) - var(--sidebar-resize-indicator-width)));
z-index: -1;
}
[dir=rtl] #sidebar-toggle-anchor:not(:checked) ~ .sidebar {
transform: translateX(calc(var(--sidebar-width) + var(--sidebar-resize-indicator-width)));
}
.sidebar::-webkit-scrollbar {
background: var(--sidebar-bg);
@@ -412,19 +465,26 @@ ul#searchresults span.teaser em {
background: var(--scrollbar);
}
.sidebar-visible .page-wrapper {
transform: translateX(var(--sidebar-width));
/* sidebar-visible */
#sidebar-toggle-anchor:checked ~ .page-wrapper {
transform: translateX(calc(var(--sidebar-width) + var(--sidebar-resize-indicator-width)));
}
[dir=rtl] #sidebar-toggle-anchor:checked ~ .page-wrapper {
transform: translateX(calc(0px - var(--sidebar-width) - var(--sidebar-resize-indicator-width)));
}
@media only screen and (min-width: 620px) {
.sidebar-visible .page-wrapper {
#sidebar-toggle-anchor:checked ~ .page-wrapper {
transform: none;
margin-inline-start: calc(var(--sidebar-width) + var(--sidebar-resize-indicator-width));
}
[dir=rtl] #sidebar-toggle-anchor:checked ~ .page-wrapper {
transform: none;
margin-left: var(--sidebar-width);
}
}
.chapter {
list-style: none outside none;
padding-left: 0;
padding-inline-start: 0;
line-height: 2.2em;
}
@@ -454,7 +514,7 @@ ul#searchresults span.teaser em {
.chapter li > a.toggle {
cursor: pointer;
display: block;
margin-left: auto;
margin-inline-start: auto;
padding: 0 10px;
user-select: none;
opacity: 0.68;
@@ -471,7 +531,7 @@ ul#searchresults span.teaser em {
.chapter li.chapter-item {
line-height: 1.5em;
margin-top: 0.6em;
margin-block-start: 0.6em;
}
.chapter li.expanded > a.toggle div {
@@ -494,7 +554,7 @@ ul#searchresults span.teaser em {
.section {
list-style: none outside none;
padding-left: 20px;
padding-inline-start: 20px;
line-height: 1.9em;
}
@@ -517,6 +577,7 @@ ul#searchresults span.teaser em {
/* Don't let the children's background extend past the rounded corners. */
overflow: hidden;
}
[dir=rtl] .theme-popup { left: unset; right: 10px; }
.theme-popup .default {
color: var(--icons);
}
@@ -527,7 +588,7 @@ ul#searchresults span.teaser em {
padding: 2px 20px;
line-height: 25px;
white-space: nowrap;
text-align: left;
text-align: start;
cursor: pointer;
color: inherit;
background: inherit;
@@ -540,6 +601,6 @@ ul#searchresults span.teaser em {
.theme-selected::before {
display: inline-block;
content: "✓";
margin-left: -14px;
margin-inline-start: -14px;
width: 14px;
}

View File

@@ -5,6 +5,7 @@
:root {
/* Browser default font-size is 16px, this way 1 rem = 10px */
font-size: 62.5%;
color-scheme: var(--color-scheme);
}
html {
@@ -24,6 +25,7 @@ body {
code {
font-family: var(--mono-font) !important;
font-size: var(--code-font-size);
direction: ltr !important;
}
/* make long words/inline code not x overflow */
@@ -47,13 +49,13 @@ h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
.hide-boring .boring { display: none; }
.hidden { display: none !important; }
h2, h3 { margin-top: 2.5em; }
h4, h5 { margin-top: 2em; }
h2, h3 { margin-block-start: 2.5em; }
h4, h5 { margin-block-start: 2em; }
.header + .header h3,
.header + .header h4,
.header + .header h5 {
margin-top: 1em;
margin-block-start: 1em;
}
h1:target::before,
@@ -64,7 +66,7 @@ h5:target::before,
h6:target::before {
display: inline-block;
content: "»";
margin-left: -30px;
margin-inline-start: -30px;
width: 30px;
}
@@ -73,28 +75,34 @@ h6:target::before {
https://bugs.webkit.org/show_bug.cgi?id=218076
*/
:target {
/* Safari does not support logical properties */
scroll-margin-top: calc(var(--menu-bar-height) + 0.5em);
}
.page {
outline: 0;
padding: 0 var(--page-padding);
margin-top: calc(0px - var(--menu-bar-height)); /* Compensate for the #menu-bar-hover-placeholder */
margin-block-start: calc(0px - var(--menu-bar-height)); /* Compensate for the #menu-bar-hover-placeholder */
}
.page-wrapper {
box-sizing: border-box;
background-color: var(--bg);
}
.no-js .page-wrapper,
.js:not(.sidebar-resizing) .page-wrapper {
transition: margin-left 0.3s ease, transform 0.3s ease; /* Animation: slide away */
}
[dir=rtl] .js:not(.sidebar-resizing) .page-wrapper {
transition: margin-right 0.3s ease, transform 0.3s ease; /* Animation: slide away */
}
.content {
overflow-y: auto;
padding: 0 5px 50px 5px;
}
.content main {
margin-left: auto;
margin-right: auto;
margin-inline-start: auto;
margin-inline-end: auto;
max-width: var(--content-max-width);
}
.content p { line-height: 1.45em; }
@@ -144,8 +152,31 @@ blockquote {
padding: 0 20px;
color: var(--fg);
background-color: var(--quote-bg);
border-top: .1em solid var(--quote-border);
border-bottom: .1em solid var(--quote-border);
border-block-start: .1em solid var(--quote-border);
border-block-end: .1em solid var(--quote-border);
}
.warning {
margin: 20px;
padding: 0 20px;
border-inline-start: 2px solid var(--warning-border);
}
.warning:before {
position: absolute;
width: 3rem;
height: 3rem;
margin-inline-start: calc(-1.5rem - 21px);
content: "ⓘ";
text-align: center;
background-color: var(--bg);
color: var(--warning-border);
font-weight: bold;
font-size: 2rem;
}
blockquote .warning:before {
background-color: var(--quote-bg);
}
kbd {
@@ -163,7 +194,7 @@ kbd {
:not(.footnote-definition) + .footnote-definition,
.footnote-definition + :not(.footnote-definition) {
margin-top: 2em;
margin-block-start: 2em;
}
.footnote-definition {
font-size: 0.9em;

View File

@@ -7,8 +7,8 @@
}
#page-wrapper.page-wrapper {
transform: none;
margin-left: 0px;
transform: none !important;
margin-inline-start: 0px;
overflow-y: initial;
}
@@ -23,11 +23,7 @@
}
code {
background-color: #666666;
border-radius: 5px;
/* Force background to be printed in Chrome */
-webkit-print-color-adjust: exact;
direction: ltr !important;
}
pre > .buttons {

View File

@@ -3,6 +3,8 @@
:root {
--sidebar-width: 300px;
--sidebar-resize-indicator-width: 8px;
--sidebar-resize-indicator-space: 2px;
--page-padding: 15px;
--content-max-width: 750px;
--menu-bar-height: 50px;
@@ -38,6 +40,8 @@
--quote-bg: hsl(226, 15%, 17%);
--quote-border: hsl(226, 15%, 22%);
--warning-border: #ff8e00;
--table-border-color: hsl(210, 25%, 13%);
--table-header-bg: hsl(210, 25%, 28%);
--table-alternate-bg: hsl(210, 25%, 11%);
@@ -50,6 +54,8 @@
--searchresults-border-color: #888;
--searchresults-li-bg: #252932;
--search-mark-bg: #e3b171;
--color-scheme: dark;
}
.coal {
@@ -78,6 +84,8 @@
--quote-bg: hsl(234, 21%, 18%);
--quote-border: hsl(234, 21%, 23%);
--warning-border: #ff8e00;
--table-border-color: hsl(200, 7%, 13%);
--table-header-bg: hsl(200, 7%, 28%);
--table-alternate-bg: hsl(200, 7%, 11%);
@@ -90,6 +98,8 @@
--searchresults-border-color: #98a3ad;
--searchresults-li-bg: #2b2b2f;
--search-mark-bg: #355c7d;
--color-scheme: dark;
}
.light {
@@ -118,6 +128,8 @@
--quote-bg: hsl(197, 37%, 96%);
--quote-border: hsl(197, 37%, 91%);
--warning-border: #ff8e00;
--table-border-color: hsl(0, 0%, 95%);
--table-header-bg: hsl(0, 0%, 80%);
--table-alternate-bg: hsl(0, 0%, 97%);
@@ -130,6 +142,8 @@
--searchresults-border-color: #888;
--searchresults-li-bg: #e4f2fe;
--search-mark-bg: #a2cff5;
--color-scheme: light;
}
.navy {
@@ -158,6 +172,8 @@
--quote-bg: hsl(226, 15%, 17%);
--quote-border: hsl(226, 15%, 22%);
--warning-border: #ff8e00;
--table-border-color: hsl(226, 23%, 16%);
--table-header-bg: hsl(226, 23%, 31%);
--table-alternate-bg: hsl(226, 23%, 14%);
@@ -170,6 +186,8 @@
--searchresults-border-color: #5c5c68;
--searchresults-li-bg: #242430;
--search-mark-bg: #a2cff5;
--color-scheme: dark;
}
.rust {
@@ -198,6 +216,8 @@
--quote-bg: hsl(60, 5%, 75%);
--quote-border: hsl(60, 5%, 70%);
--warning-border: #ff8e00;
--table-border-color: hsl(60, 9%, 82%);
--table-header-bg: #b3a497;
--table-alternate-bg: hsl(60, 9%, 84%);
@@ -210,6 +230,8 @@
--searchresults-border-color: #888;
--searchresults-li-bg: #dec2a2;
--search-mark-bg: #e69f67;
--color-scheme: light;
}
@media (prefers-color-scheme: dark) {
@@ -239,6 +261,8 @@
--quote-bg: hsl(234, 21%, 18%);
--quote-border: hsl(234, 21%, 23%);
--warning-border: #ff8e00;
--table-border-color: hsl(200, 7%, 13%);
--table-header-bg: hsl(200, 7%, 28%);
--table-alternate-bg: hsl(200, 7%, 11%);

File diff suppressed because one or more lines are too long

View File

@@ -1,11 +1,11 @@
<!DOCTYPE HTML>
<html lang="{{ language }}" class="sidebar-visible no-js {{ default_theme }}">
<html lang="{{ language }}" class="{{ default_theme }}" dir="{{ text_direction }}">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>{{ title }}</title>
{{#if is_print }}
<meta name="robots" content="noindex" />
<meta name="robots" content="noindex">
{{/if}}
{{#if base_url}}
<base href="{{ base_url }}">
@@ -17,7 +17,7 @@
<meta name="description" content="{{ description }}">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff" />
<meta name="theme-color" content="#ffffff">
{{#if favicon_svg}}
<link rel="icon" href="{{ path_to_root }}favicon.svg">
@@ -53,7 +53,7 @@
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
{{/if}}
</head>
<body>
<body class="sidebar-visible no-js">
<div id="body-container">
<!-- Provide site root to javascript -->
<script>
@@ -83,31 +83,38 @@
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('no-js')
html.classList.remove('{{ default_theme }}')
html.classList.add(theme);
html.classList.add('js');
var body = document.querySelector('body');
body.classList.remove('no-js')
body.classList.add('js');
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var html = document.querySelector('html');
var body = document.querySelector('body');
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
sidebar_toggle.checked = sidebar === 'visible';
body.classList.remove('sidebar-visible');
body.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
{{#toc}}{{/toc}}
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<!-- Track and set sidebar scroll position -->
@@ -139,9 +146,9 @@
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
@@ -217,7 +224,7 @@
{{/previous}}
{{#next}}
<a rel="next" href="{{ path_to_root }}{{link}}" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="{{ path_to_root }}{{link}}" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
{{/next}}
@@ -235,7 +242,7 @@
{{/previous}}
{{#next}}
<a rel="next" href="{{ path_to_root }}{{link}}" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="{{ path_to_root }}{{link}}" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
{{/next}}

View File

@@ -316,7 +316,7 @@ window.search = window.search || {};
// Eventhandler for keyevents on `document`
function globalKeyHandler(e) {
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey || e.target.type === 'textarea' || e.target.type === 'text') { return; }
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey || e.target.type === 'textarea' || e.target.type === 'text' || !hasFocus() && /^(?:input|select|textarea)$/i.test(e.target.nodeName)) { return; }
if (e.keyCode === ESCAPE_KEYCODE) {
e.preventDefault();

View File

@@ -166,7 +166,7 @@ pub fn copy_files_except_ext(
.expect("a file should have a file name...")
)
);
fs::copy(
copy(
entry.path(),
&to.join(
entry
@@ -180,6 +180,62 @@ pub fn copy_files_except_ext(
Ok(())
}
/// Copies a file.
fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<()> {
let from = from.as_ref();
let to = to.as_ref();
return copy_inner(from, to)
.with_context(|| format!("failed to copy `{}` to `{}`", from.display(), to.display()));
// This is a workaround for an issue with the macOS file watcher.
// Rust's `std::fs::copy` function uses `fclonefileat`, which creates
// clones on APFS. Unfortunately fs events seem to trigger on both
// sides of the clone, and there doesn't seem to be a way to differentiate
// which side it is.
// https://github.com/notify-rs/notify/issues/465#issuecomment-1657261035
// contains more information.
//
// This is essentially a copy of the simple copy code path in Rust's
// standard library.
#[cfg(target_os = "macos")]
fn copy_inner(from: &Path, to: &Path) -> Result<()> {
use std::fs::OpenOptions;
use std::os::unix::fs::{OpenOptionsExt, PermissionsExt};
let mut reader = File::open(from)?;
let metadata = reader.metadata()?;
if !metadata.is_file() {
anyhow::bail!(
"expected a file, `{}` appears to be {:?}",
from.display(),
metadata.file_type()
);
}
let perm = metadata.permissions();
let mut writer = OpenOptions::new()
.mode(perm.mode())
.write(true)
.create(true)
.truncate(true)
.open(to)?;
let writer_metadata = writer.metadata()?;
if writer_metadata.is_file() {
// Set the correct file permissions, in case the file already existed.
// Don't set the permissions on already existing non-files like
// pipes/FIFOs or device nodes.
writer.set_permissions(perm)?;
}
std::io::copy(&mut reader, &mut writer)?;
Ok(())
}
#[cfg(not(target_os = "macos"))]
fn copy_inner(from: &Path, to: &Path) -> Result<()> {
fs::copy(from, to)?;
Ok(())
}
}
pub fn get_404_output_file(input_404: &Option<String>) -> String {
input_404
.as_ref()

View File

@@ -6,7 +6,7 @@ pub(crate) mod toml_ext;
use crate::errors::Error;
use log::error;
use once_cell::sync::Lazy;
use pulldown_cmark::{html, CodeBlockKind, CowStr, Event, Options, Parser, Tag};
use pulldown_cmark::{html, CodeBlockKind, CowStr, Event, Options, Parser, Tag, TagEnd};
use regex::Regex;
use std::borrow::Cow;
@@ -161,13 +161,30 @@ fn adjust_links<'a>(event: Event<'a>, path: Option<&Path>) -> Event<'a> {
}
match event {
Event::Start(Tag::Link(link_type, dest, title)) => {
Event::Start(Tag::Link(link_type, fix(dest, path), title))
}
Event::Start(Tag::Image(link_type, dest, title)) => {
Event::Start(Tag::Image(link_type, fix(dest, path), title))
}
Event::Start(Tag::Link {
link_type,
dest_url,
title,
id,
}) => Event::Start(Tag::Link {
link_type,
dest_url: fix(dest_url, path),
title,
id,
}),
Event::Start(Tag::Image {
link_type,
dest_url,
title,
id,
}) => Event::Start(Tag::Image {
link_type,
dest_url: fix(dest_url, path),
title,
id,
}),
Event::Html(html) => Event::Html(fix_html(html, path)),
Event::InlineHtml(html) => Event::InlineHtml(fix_html(html, path)),
_ => event,
}
}
@@ -177,7 +194,7 @@ pub fn render_markdown(text: &str, curly_quotes: bool) -> String {
render_markdown_with_path(text, curly_quotes, None)
}
pub fn new_cmark_parser(text: &str, curly_quotes: bool) -> Parser<'_, '_> {
pub fn new_cmark_parser(text: &str, curly_quotes: bool) -> Parser<'_> {
let mut opts = Options::empty();
opts.insert(Options::ENABLE_TABLES);
opts.insert(Options::ENABLE_FOOTNOTES);
@@ -212,7 +229,7 @@ fn wrap_tables(event: Event<'_>) -> (Option<Event<'_>>, Option<Event<'_>>) {
Some(Event::Html(r#"<div class="table-wrapper">"#.into())),
Some(event),
),
Event::End(Tag::Table(_)) => (Some(event), Some(Event::Html(r#"</div>"#.into()))),
Event::End(TagEnd::Table) => (Some(event), Some(Event::Html(r#"</div>"#.into()))),
_ => (Some(event), None),
}
}

View File

@@ -10,7 +10,9 @@ This is a codeblock
---
This line contains `inline code`
This line contains `inline code` mixed with some other stuff. (LTR)
ושורה זו מכילה `inline code` אבל עם טקסט בשפה שנכתבת מימין לשמאל. (RTL)
---

View File

@@ -27,6 +27,7 @@ This Currently contains following languages
- makefile
- markdown
- nginx
- nim
- objectivec
- perl
- php

View File

@@ -529,6 +529,26 @@ http {
var doors {.compileTime.}: array[1..numDoors, bool]
proc calcDoors(): string =
for pass in 1..numDoors:
for door in countup(pass, numDoors, pass):
doors[door] = not doors[door]
for door in 1..numDoors:
result.add("Door $1 is $2.\n" % [$door, if doors[door]: "open" else: "closed"])
const outputString: string = calcDoors()
echo outputString
```
## objectivec
```objectivec
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@mylak {
NSLog(@"Hello World!");
}
return 0;
}

View File

@@ -39,29 +39,27 @@ fn alternate_backend_with_arguments() {
md.build().unwrap();
}
/// Get a command which will pipe `stdin` to the provided file.
#[cfg(not(windows))]
fn tee_command<P: AsRef<Path>>(out_file: P) -> String {
let out_file = out_file.as_ref();
if cfg!(windows) {
format!("cmd.exe /c \"type > {}\"", out_file.display())
} else {
format!("tee {}", out_file.display())
}
}
#[test]
#[cfg(not(windows))]
fn backends_receive_render_context_via_stdin() {
use mdbook::renderer::RenderContext;
use std::fs::File;
let temp = TempFileBuilder::new().prefix("output").tempdir().unwrap();
let out_file = temp.path().join("out.txt");
let cmd = tee_command(&out_file);
let (md, temp) = dummy_book_with_backend("cat-to-file", "renderers/myrenderer", false);
let (md, _temp) = dummy_book_with_backend("cat-to-file", &cmd, false);
let renderers = temp.path().join("renderers");
fs::create_dir(&renderers).unwrap();
rust_exe(
&renderers,
"myrenderer",
r#"fn main() {
use std::io::Read;
let mut s = String::new();
std::io::stdin().read_to_string(&mut s).unwrap();
std::fs::write("out.txt", s).unwrap();
}"#,
);
let out_file = temp.path().join("book/out.txt");
assert!(!out_file.exists());
md.build().unwrap();

View File

@@ -18,3 +18,7 @@ css looks, like this {
}
*/
</style>
Sneaky inline event <script>alert("inline");</script>.
But regular <b>inline</b> is indexed.

View File

@@ -375,10 +375,7 @@ fn able_to_include_playground_files_in_chapters() {
let second = temp.path().join("book/second.html");
let playground_strings = &[
r#"class="playground""#,
r#"println!(&quot;Hello World!&quot;);"#,
];
let playground_strings = &[r#"class="playground""#, r#"println!("Hello World!");"#];
assert_contains_strings(&second, playground_strings);
assert_doesnt_contain_strings(&second, &["{{#playground example.rs}}"]);
@@ -745,6 +742,7 @@ mod search {
let index = read_book_index(temp.path());
let doc_urls = index["doc_urls"].as_array().unwrap();
eprintln!("doc_urls={doc_urls:#?}",);
let get_doc_ref =
|url: &str| -> String { doc_urls.iter().position(|s| s == url).unwrap().to_string() };
@@ -774,7 +772,10 @@ mod search {
docs[&summary]["breadcrumbs"],
"First Chapter » Includes » Summary"
);
assert_eq!(docs[&conclusion]["body"], "I put &lt;HTML&gt; in here!");
// See note about InlineHtml in search.rs. Ideally the `alert()` part
// should not be in the index, but we don't have a way to scrub inline
// html.
assert_eq!(docs[&conclusion]["body"], "I put &lt;HTML&gt; in here! Sneaky inline event alert(\"inline\");. But regular inline is indexed.");
assert_eq!(
docs[&no_headers]["breadcrumbs"],
"First Chapter » No Headers"

View File

@@ -145,7 +145,7 @@
"title": 1
},
"29": {
"body": 3,
"body": 10,
"breadcrumbs": 2,
"title": 1
},
@@ -319,7 +319,7 @@
"title": "Some section"
},
"29": {
"body": "I put &lt;HTML&gt; in here!",
"body": "I put &lt;HTML&gt; in here! Sneaky inline event alert(\"inline\");. But regular inline is indexed.",
"breadcrumbs": "Conclusion » Conclusion",
"id": "29",
"title": "Conclusion"
@@ -412,6 +412,54 @@
},
"df": 0,
"docs": {},
"l": {
"df": 0,
"docs": {},
"e": {
"df": 0,
"docs": {},
"r": {
"df": 0,
"docs": {},
"t": {
"(": {
"\"": {
"df": 0,
"docs": {},
"i": {
"df": 0,
"docs": {},
"n": {
"df": 0,
"docs": {},
"l": {
"df": 0,
"docs": {},
"i": {
"df": 0,
"docs": {},
"n": {
"df": 1,
"docs": {
"29": {
"tf": 1.0
}
}
}
}
}
}
}
},
"df": 0,
"docs": {}
},
"df": 0,
"docs": {}
}
}
}
},
"n": {
"c": {
"df": 0,
@@ -1212,6 +1260,14 @@
"26": {
"tf": 1.0
}
},
"t": {
"df": 1,
"docs": {
"29": {
"tf": 1.0
}
}
}
}
}
@@ -1684,10 +1740,13 @@
"df": 0,
"docs": {},
"x": {
"df": 1,
"df": 2,
"docs": {
"0": {
"tf": 1.0
},
"29": {
"tf": 1.0
}
}
}
@@ -1695,6 +1754,22 @@
},
"df": 0,
"docs": {},
"l": {
"df": 0,
"docs": {},
"i": {
"df": 0,
"docs": {},
"n": {
"df": 1,
"docs": {
"29": {
"tf": 1.4142135623730951
}
}
}
}
},
"s": {
"df": 0,
"docs": {},
@@ -2359,6 +2434,30 @@
},
"df": 0,
"docs": {},
"g": {
"df": 0,
"docs": {},
"u": {
"df": 0,
"docs": {},
"l": {
"a": {
"df": 0,
"docs": {},
"r": {
"df": 1,
"docs": {
"29": {
"tf": 1.0
}
}
}
},
"df": 0,
"docs": {}
}
}
},
"l": {
"df": 1,
"docs": {
@@ -2590,6 +2689,26 @@
"n": {
"df": 0,
"docs": {},
"e": {
"a": {
"df": 0,
"docs": {},
"k": {
"df": 0,
"docs": {},
"i": {
"df": 1,
"docs": {
"29": {
"tf": 1.0
}
}
}
}
},
"df": 0,
"docs": {}
},
"i": {
"df": 0,
"docs": {},
@@ -3252,6 +3371,54 @@
},
"df": 0,
"docs": {},
"l": {
"df": 0,
"docs": {},
"e": {
"df": 0,
"docs": {},
"r": {
"df": 0,
"docs": {},
"t": {
"(": {
"\"": {
"df": 0,
"docs": {},
"i": {
"df": 0,
"docs": {},
"n": {
"df": 0,
"docs": {},
"l": {
"df": 0,
"docs": {},
"i": {
"df": 0,
"docs": {},
"n": {
"df": 1,
"docs": {
"29": {
"tf": 1.0
}
}
}
}
}
}
}
},
"df": 0,
"docs": {}
},
"df": 0,
"docs": {}
}
}
}
},
"n": {
"c": {
"df": 0,
@@ -4130,6 +4297,14 @@
"26": {
"tf": 1.0
}
},
"t": {
"df": 1,
"docs": {
"29": {
"tf": 1.0
}
}
}
}
}
@@ -4665,10 +4840,13 @@
"df": 0,
"docs": {},
"x": {
"df": 1,
"df": 2,
"docs": {
"0": {
"tf": 1.0
},
"29": {
"tf": 1.0
}
}
}
@@ -4676,6 +4854,22 @@
},
"df": 0,
"docs": {},
"l": {
"df": 0,
"docs": {},
"i": {
"df": 0,
"docs": {},
"n": {
"df": 1,
"docs": {
"29": {
"tf": 1.4142135623730951
}
}
}
}
},
"s": {
"df": 0,
"docs": {},
@@ -5373,6 +5567,30 @@
},
"df": 0,
"docs": {},
"g": {
"df": 0,
"docs": {},
"u": {
"df": 0,
"docs": {},
"l": {
"a": {
"df": 0,
"docs": {},
"r": {
"df": 1,
"docs": {
"29": {
"tf": 1.0
}
}
}
},
"df": 0,
"docs": {}
}
}
},
"l": {
"df": 1,
"docs": {
@@ -5610,6 +5828,26 @@
"n": {
"df": 0,
"docs": {},
"e": {
"a": {
"df": 0,
"docs": {},
"k": {
"df": 0,
"docs": {},
"i": {
"df": 1,
"docs": {
"29": {
"tf": 1.0
}
}
}
}
},
"df": 0,
"docs": {}
},
"i": {
"df": 0,
"docs": {},