···4455Quality-of-life plugins for your [mdBook] project.
6677-Right now, there are two mdBook [preprocessors], both for generating **correct and
88-versioned** external links from **easy-to-write** markup.
99-107- [**`mdbook-rustdoc-link`**](https://tonywu6.github.io/mdbookkit/rustdoc-link)
118129 _rustdoc_-style linking for Rust APIs: write types and function names, get links to
···16131714 _Permalinks_ for your source tree: write relative paths, get links to GitHub.
18151919-> [!TIP]
2020->
2121-> Preprocessors are standalone programs that mdBook invokes to transform your Markdown
2222-> sources before rendering them.
1616+[](https://crates.io/crates/mdbookkit)
1717+[](https://docs.rs/mdbookkit)
1818+[](/LICENSE-APACHE.md)
23192420## Installation
2521
···4444 return Some(Ok(Cow::Borrowed(&self.source[start..])));
4545 };
46464747+ if start > span.start {
4848+ panic!("span {span:?} is backwards from already yielded span ending at {start}")
4949+ }
5050+4751 let patch = match String::new().pipe(|mut out| cmark(events, &mut out).and(Ok(out))) {
4852 Err(error) => return Some(Err(error)),
4953 Ok(patch) => patch,
···5963impl<'a, S> PatchStream<'a, S> {
6064 /// Create a new patch stream.
6165 ///
6262- /// `stream` should be an [`Iterator`] yielding (`E`, [`Range<usize>`]), where `E` is an
6363- /// [`Iterator`] yielding [`Event`]s.
6666+ /// `stream` should be an [`Iterator`] yielding tuples of (`events`, `range`):
6767+ ///
6868+ /// - `events` is an [`Iterator`] yielding [`Event`]s which is the replacement
6969+ /// Markdown to be rendered into `source` using [`pulldown_cmark_to_cmark`].
7070+ ///
7171+ /// - `range` is a [`Range<usize>`] representing the byte span in `source` that
7272+ /// should be patched.
6473 ///
6565- /// [`Range<usize>`] is the byte span in `source` that should be patched.
7474+ /// **The yielded ranges must not overlap or decrease**, that is, for `span1` and
7575+ /// `span2`, where `span1` is yielded before `span2`, `span1.end <= span2.start`.
6676 ///
6767- /// `E` is the replacement event stream to be rendered into `source`
6868- /// using [`pulldown_cmark_to_cmark`].
7777+ /// ## Panics
7878+ ///
7979+ /// Panic if ranges in `stream` are not monotonically increasing.
6980 pub fn new(source: &'a str, stream: S) -> Self {
7081 Self {
7182 source,
+20-12
crates/mdbookkit/tests/link_forever.rs
···22use log::LevelFilter;
33use tap::Pipe;
4455+use url::Url;
66+57use mdbookkit::{
68 bin::link_forever::{Config, Environment, GitHubPermalink, Pages},
99+ logging::ConsoleLogger,
710 markdown::mdbook_markdown,
811};
99-use url::Url;
1012use util_testing::{portable_snapshots, test_document, CARGO_WORKSPACE_DIR};
11131214#[test]
1315fn test_links() -> Result<()> {
1616+ ConsoleLogger::install("link-forever");
1717+1418 let env = Environment {
1515- book_src: CARGO_WORKSPACE_DIR.join("crates/mdbookkit/tests/")?,
1919+ book_src: CARGO_WORKSPACE_DIR.join("crates/mdbookkit/")?,
1620 vcs_root: CARGO_WORKSPACE_DIR.clone(),
1721 fmt_link: GitHubPermalink::new("lorem", "ipsum", "dolor").pipe(Box::new),
1822 markdown: mdbook_markdown(),
···24282529 let mut pages = Pages::new(mdbook_markdown());
26302727- let main_page = test_document!("tests/link-forever.md");
2828- let side_page = test_document!("tests/ra-known-quirks.md");
3131+ let tests = [
3232+ test_document!("tests/ra-known-quirks.md"), // only for providing anchors
3333+ test_document!("tests/link-forever.md"),
3434+ test_document!("../README.md"),
3535+ ];
29363030- pages.insert(main_page.file.clone(), main_page.source)?;
3131- pages.insert(side_page.file.clone(), side_page.source)?;
3737+ for page in tests.iter() {
3838+ pages.insert(page.file.clone(), page.source)?;
3939+ }
32403341 env.resolve(&mut pages);
34423535- let name = main_page.name.clone();
3636-3737- let output = pages.emit(&main_page.file)?;
4343+ for page in tests {
4444+ let output = pages.emit(&page.file)?;
4545+ let name = page.name;
4646+ portable_snapshots!().test(|| insta::assert_snapshot!(format!("{name}"), output))?;
4747+ }
38483949 let report = env
4050 .report(&pages)
···4555 .build()
4656 .to_report();
47574848- portable_snapshots!().test(|| insta::assert_snapshot!(format!("{name}.stderr"), report))?;
4949-5050- portable_snapshots!().test(|| insta::assert_snapshot!(format!("{name}"), output))?;
5858+ portable_snapshots!().test(|| insta::assert_snapshot!("_stderr", report))?;
51595260 Ok(())
5361}
···11+---
22+source: crates/mdbookkit/tests/link_forever.rs
33+expression: output
44+---
55+# mdbookkit
66+77+
88+99+Quality-of-life plugins for your [mdBook] project.
1010+1111+- [**`mdbook-rustdoc-link`**](https://tonywu6.github.io/mdbookkit/rustdoc-link)
1212+1313+ _rustdoc_-style linking for Rust APIs: write types and function names, get links to
1414+ _docs.rs_
1515+1616+- [**`mdbook-link-forever`**](https://tonywu6.github.io/mdbookkit/link-forever)
1717+1818+ _Permalinks_ for your source tree: write relative paths, get links to GitHub.
1919+2020+[](https://crates.io/crates/mdbookkit)
2121+[](https://docs.rs/mdbookkit)
2222+[](https://github.com/lorem/ipsum/tree/dolor/LICENSE-APACHE.md)
2323+2424+## Installation
2525+2626+If you are interested in any of these plugins, visit their respective pages for usage
2727+instructions, linked above.
2828+2929+If you want to install all of them:
3030+3131+```bash
3232+cargo install mdbookkit --all-features
3333+```
3434+3535+Precompiled binaries are also available from [GitHub releases][gh-releases].
3636+3737+## License
3838+3939+This project is released under the [Apache 2.0 License](https://github.com/lorem/ipsum/tree/dolor/LICENSE-APACHE.md) and the
4040+[MIT License](https://github.com/lorem/ipsum/tree/dolor/LICENSE-MIT.md).
4141+4242+<!-- prettier-ignore-start -->
4343+4444+[mdBook]: https://rust-lang.github.io/mdBook/
4545+[`mdbookkit`]: https://crates.io/crates/mdbookkit
4646+[preprocessors]: https://rust-lang.github.io/mdBook/format/configuration/preprocessors.html
4747+[gh-releases]: https://github.com/tonywu6/mdbookkit/releases
4848+4949+<!-- prettier-ignore-end -->
···11# relative paths
2233-[Cargo.toml](../../Cargo.toml)
44-55-[src/lib.rs](../../src/lib.rs)
33+[Cargo.toml](../../../../Cargo.toml)
6475
86···1917[link_forever.rs](../link_forever.rs)
20182119
2222-2323-<https://commons.wikimedia.org/wiki/File:Macaca_nigra_self-portrait_large.jpg>
24202521# fragments
2622···5753missing: <https://example.org/book/404>
58545955ignored: <https://example.com/book/ra-known-quirks>
5656+5757+# image-in-link
5858+5959+[](https://crates.io/crates/mdbookkit)
6060+6161+[](https://commons.wikimedia.org/wiki/File:Macaca_nigra_self-portrait_large.jpg)
6262+6363+[ <br> Self-portrait of a female Macaca nigra in North Sulawesi (2011)](/crates/mdbookkit/tests/tests/Macaca_nigra_self-portrait_large.jpg)
docs/app/socials.pxd
This is a binary file and will not be displayed.
+1-1
docs/book.toml
···5656command = "cargo bin mdbook-alerts"
57575858[preprocessor.app]
5959-command = "deno run -A app/build/preprocessor.ts"
5959+command = "deno run --allow-all app/build/preprocessor.ts"
60606161[_metadata]
6262base-url = "https://tonywu6.github.io/mdbookkit/"
+3-3
docs/src/link-forever/working-with-include.md
···11# Working with `{{#include}}`
2233-mdBook provides an [`{{#include}}` directive][mdbook-include] that you can embed files
44-in book pages. If the embedded content also contains path-based links, then some extra
55-care may be needed:
33+mdBook provides an [`{{#include}}` directive][mdbook-include] for embedding files in
44+book pages. If the embedded content also contains path-based links, then some extra care
55+may be needed:
6677- The preprocessor does not resolve links relative to the file being included (because
88 it doesn't have enough information to do so). In this case, relative paths could be
docs/src/media/banner.webp
This is a binary file and will not be displayed.
+10-2
utils/mdbook-socials/src/main.rs
···11-//! Postprocess mdBook HTML output to add OpenGraph metadata, for social images, etc.
11+//! Postprocess mdBook HTML output.
22+//!
33+//! Currently does the following:
44+//!
55+//! - Add OpenGraph metadata and link to images for social.
66+//! - Add explicit widths and heights to images: <https://web.dev/articles/optimize-cls#images-without-dimensions>
27//!
38//! mdBook doesn't support frontmatters yet, so this cannot be a preprocessor.
49···165170 element!(r#"img[src]"#, |elem| {
166171 let src = elem.get_attribute("src").unwrap();
167172 let src = url.join(&src)?;
168168- let img = image::open(src.to_file_path().unwrap())?;
173173+ let img = image::open(match src.to_file_path() {
174174+ Ok(path) => path,
175175+ Err(()) => return Ok(()),
176176+ })?;
169177 elem.set_attribute("width", &img.width().to_string())?;
170178 elem.set_attribute("height", &img.height().to_string())?;
171179 Ok(())