/cargo-intraconv

A simple helper to transform Markdown links to intra-doc links in Rust projects when appropriate.

Primary LanguageRustMIT LicenseMIT

CI crates.io crates.io

Cargo intraconv

cargo-intraconv is a simple helper which will transform Markdown links to intra-doc links in Rust projects when appropriate.

Intra-doc links have been stabilized in Rust 1.48.0, see the blog post annoucing it for more information.

What are intra-doc links ?

Previously the only way to write links to other elements of your crate (or other crates) was the following, the path depending on the current and target files:

/// [`make_ascii_uppercase`]: #method.make_ascii_uppercase

/// [`Path::ancestors`]: https://doc.rust-lang.org/stable/std/path/struct.Path.html#method.ancestors

/// See [the `Rotation` type](../struct.Rotation.html)

It is now possible to write them with Rust paths, depending on the path of the targeted item and what's in scope (which means items like String which are in the prelude are just a [String] away). Those links are clearer for both the person writing them in the first place and subsequent readers reviewing them. They are also easier to reason about since file hierachy does not affect them. Below is the intra-doc links version of the examples above:

/// [`make_ascii_uppercase`]: u8::make_ascii_uppercase()

/// [`Path::ancestors`]: std::path::Path::ancestors()

/// See [the `Rotation` type](super::Rotation)

When both side of the link are the same, it is possible to be even shorter:

/// See [`Rotation`]
///
- /// [`Rotation`]: struct.Rotation.html

- /// See [`Rotation`](struct.Rotation.html)
+ /// See [`Rotation`]

Why this crate ?

Changing all the existing links can be tedious and can be automated. This crate is here to help you update your documentation to intra-doc links as painlessly as possible.

Usage

By default the binary produced by the crate will not modify the given files, only show what would change:

# Call `cargo-intraconv` for a whole crate or workspace. Crate names will be
# discovered from `Cargo.toml` files.
cargo intraconv

# Call `cargo-intraconv` for specific file. No automatic crate name discovery.
cargo intraconv path/to/std/file.rs

# Specifying the root crate.
cargo intraconv path/to/core/file.rs -c core

# Applying the changes.
cargo intraconv path/to/std/file.rs -a

# Disambiguate links by prefixing them with their rustdoc group ('type@', ...).
cargo intraconv path/to/my/file.rs -d

# Do not transform favored links to intra-doc links (see below for more).
cargo intravonc path/to/my/file.rs -f

# Do not display changes, only errors.
cargo intraconv path/to/my/file.rs -q

# Give a file containing links to ignore.
#
# Note: `intraconv.toml` is read by default when present.
cargo intraconv path/to/my/file.rs -i intraconv.toml

It is possible to give multiple paths to files or directories. When searching exact paths, cargo-intraconv will use the crate name given with -c. For directories it will try to find the crate name in a Cargo.toml, falling back to the default of -c if the name cannot be transformed to a valid Rust identifier.

Note: intraconv will accept any file, no just .rs ones: you can use it on markdown files that are included as docs in Rust files for example.

Favored links

By default the crate will transform favored http(s):// links to intra-doc links (like those from docs.rs). To disable this behaviour use the -f (--no-favored) flag.

Ignoring links

cargo-intraconv is not perfect and will sometimes wrongly transform links, as in #31. To fix that you can either do it manually if you run it only once but if you start to run it several times because the changes are significative it will quickly become repetitive and error-prone. For a tool designed to reduce repetitive and error prone work, this is a sad thing !

When the --ignore-file (-i) is not passed, cargo-intraconv will read ìntraconv.toml by default (though it will not produce an error nor warning if it's missing since it's a default check).

To fix this, you can write a file in the TOML format with links to ignore:

# Global ignores, applied everywhere.
[ignore]
# Will be deleted by the second instance of `"name"`.
"name" = [ "link 1" ] # Must be an array, a single value will not work,
                      # this allows for multiples values easily.
"name" = [ "link 2" ]
# Will only keep one instance of 'link 3'.
"other name" = [ "link 3", "link 3", "link 1" ]

# Will match exactly the lib.rs file in tracing-core.
# NOTE: this path must either be absolute OR relative to the EXACT directory
# from which `cargo-intraconv` is called.
#
# Paths must be unique whether canonicalized (for paths with more than one
# component) or not (paths with a single component, as `lib.rs` below).
["tracing-core/src/lib.rs"]
# Will match both 'downcast_ref' and '`downcast_ref`' links.
"downcast_ref" = [ "#method.downcast_ref" ] # Must be an array.

# Will match EVERY lib.rs file found.
["lib.rs"]
"downcast_ref" = [ "#method.downcast_ref" ]

Using backticks (`) around the link names is not supported: this will never match any links:

[ignore]
# NEVER matches.
"`downcast_ref`" = [ "#method.downcast_ref" ]

Known issues

Both intra-doc links and this crate have several known issues, most of which should be adressed in future versions of either the crate or Rust itself.

For issues about intra-doc links you should look-up the issues at rust-lang/rust.

For issues about this crate, here is one:

  • #method.method_name links will sometimes be transformed to point to the wrong item. This is because intraconv uses regexes to find links and the types related to them, which is not perfect.

Drawbacks

It is not an official tool and the way it works right now is based on regexes. This approach means it is simple to understand but it has several drawbacks. For example cargo-intraconv is not aware of uses and will happily ignore them, even when they could shorten or remove links.

See Also

cargo-deadlinks is another tool for documentation and links. It works very well in conjunction with cargo-intraconv !

Contributing

Any form of contribution is appreciated ! You can open issues or PR and I'll try to answer you quickly !

License

See LICENSE at the repository's root.