Name resolution
mdbook-rustdoc-link
resolves items in the context of your crate's "entrypoint", which
is usually your lib.rs
or main.rs
(the specific rules are
mentioned below).
tip
If you use Cargo workspaces, or if your source tree has special layout, see Workspace layout for more information.
An item must be in scope in the entrypoint for the proprocessor to generate a link for it.
Let's say you have the following as your lib.rs
:
use anyhow::Context;
/// Type that can provide links.
pub trait Resolver {}
mod env {
/// Options for the preprocessor.
pub struct Config {}
}
Items in the entrypoint can be linked to with just their names:
[`Resolver`] — Type that can provide links. This crate also uses the [`Context`] trait from [`anyhow`].
Resolver
— Type that can provide links.
This includes items from the prelude (unless you are using #![no_implicit_prelude]
):
[`FromIterator`] is in the prelude starting from Rust 2021.
FromIterator
is in the prelude starting from Rust 2021.
Though technically not required — to make items from your crate more distinguishable
from others in your Markdown source, you can write crate::*
:
[Configurations](configuration.md) for the preprocessor is defined in the [`Config`][crate::env::Config] type.
Configurations for the preprocessor is defined in the
Config
type.
For everything else, provide its full path, as if you were writing a use
declaration:
[`JoinSet`][tokio::task::JoinSet] is analogous to `asyncio.as_completed`.
JoinSet
is analogous toasyncio.as_completed
.
tip
In short, write links the way you use
an item in your lib.rs
or main.rs
.
The preprocessor will emit a warning if an item cannot be resolved:
Formatting of diagnostics powered by miette
This is something to remember especially if you are including doc comments as part of your Markdown docs. Only rustdoc has the ability to resolve names from where the comments are written, so links that work in doc comments may not work when using this preprocessor!
Feature-gated items
To link to items that are gated behind features, use the
cargo-features
option in book.toml
.
For example, clap is known for providing guide-level documentation through docs.rs.
The tutorial for its Derive API is gated behind the unstable-doc
feature. To link to
such items, configure the necessary features:
[preprocessor.rustdoc-link]
cargo-features = ["clap/unstable-doc"]
Then, specify the item as normal:
[Tutorial for clap's Derive API][clap::_derive::_tutorial]
Which entrypoint
For this preprocessor, the "entrypoint" is usually src/lib.rs
or src/main.rs
.
- If your crate has multiple
bin
targets, it will use the first one listed in yourCargo.toml
. - If your crate has both
lib
andbin
s, it will preferlib
. - If your crate has custom paths in
Cargo.toml
instead of the defaultsrc/lib.rs
orsrc/main.rs
, it will honor that.
How it works
note
The following are implementation details. See rustdoc_link/mod.rs.
mdbook-rustdoc-link
parses your book and collects every link that looks like a Rust
item. Then it synthesizes a Rust function that spells out all the items, which looks
roughly like this:
fn __ded48f4d_0c4f_4950_b17d_55fd3b2a0c86__ () {
Result::<T, E>;
core::net::Ipv4Addr::LOCALHOST;
std::vec!();
serde::Serialize!();
<Vec<()> as IntoIterator>::into_iter;
// ...
}
Note that this is barely valid Rust —
Result::<T, E>;
is a type without a value, and you wouldn't useserde::Serialize
as a regular macro.This is where language servers like rust-analyzer excel — they can provide maximally useful information out of badly-shaped code.
The preprocessor appends this fake function to your lib.rs
or main.rs
(in memory, it
doesn't modify your file) and sends it to rust-analyzer. Then, for each item
that needs to be resolved, the preprocessor sends an external documentation
request.
{
"jsonrpc": "2.0",
"method": "experimental/externalDocs",
"params": {
"textDocument": { "uri": "file:///src/lib.rs" },
"position": { "line": 6, "character": 17 }
}
}
Hence item names in your book must be resolvable from your crate entrypoint!
This process is as if you had typed a name into your source file and used the "Open Docs" feature — except it's fully automated.
