# Rustdocs for Obsidian Rustdocs is a desktop-only Obsidian plugin that turns one or more local Cargo projects into linked, searchable Markdown API documentation. It reads Cargo workspace metadata and nightly rustdoc JSON, then creates package/module indexes and individual pages for Rust API items. ## AI development disclaimer This project was developed entirely using AI coding agents, with human direction. Its implementation, tests, and documentation were AI-generated. Passing tests do not guarantee correctness or security. Review the code, back up your vault, and try the plugin in a test vault before relying on it with important notes. ## What it generates - One workspace index and one index per crate/module. - Separate pages for structs, enums, unions, traits, functions, type aliases, constants, statics, declarative/procedural macros, primitives, and trait aliases. - Signatures, documentation comments, fields, variants, impls, methods, intra-doc relationships, and source locations when rustdoc exposes them. - Stable block-targeted Markdown links, YAML frontmatter, and deterministic collision-safe filenames. Filenames preserve Rust names: `Client.md`, `State.md`, `default_client.md`, and `MAX_PEERS.md`. Type suffixes appear only for naming collisions, such as `parse (function).md` and `parse (macro).md`. Modules keep their folder and `index.md`. After updating from the old `client--struct.md` naming scheme, generate again to replace managed pages and refresh generated links. Old unedited generated pages go to the vault trash; edited pages remain protected. Links from your own notes to old filenames may need updating. Every managed note contains a generated marker. A `.rustdocs-manifest.json` file records ownership and content hashes. Rustdocs checks all conflicts before changing files, preserves manually edited notes, and refuses to share an output folder between different profiles. Stale notes go to the vault trash. An interrupted generation can be retried using the ownership journal. ## Requirements - Obsidian Desktop 1.8 or newer. Mobile is intentionally unsupported because Cargo must run as a local process. - `cargo` available on the `PATH` inherited by Obsidian. - Nightly Rust, because rustdoc JSON remains experimental. For rustup installations: ```sh rustup toolchain install nightly-2026-09-12 ``` Keep the profile’s **Rustup toolchain** value set to `nightly-2026-09-12`. If `cargo` itself is the pinned Nix nightly from this repository, leave the field blank so no rustup `+toolchain` selector is added. New profiles automatically use direct Cargo when Obsidian inherits this repository's Nix shell environment. ## Install Until this plugin is published in the Obsidian community catalog: 1. Download or build the release bundle. 2. Copy `main.js`, `manifest.json`, `versions.json`, and `styles.css` into `/.obsidian/plugins/rustdocs/`. 3. Restart Obsidian and enable **Rustdocs** under Community plugins. Build a local bundle with `npm run package`; files are written to `dist/rustdocs/`. ## Use 1. Open **Settings → Rustdocs → Manage projects**. 2. Add a name, absolute Cargo project/workspace path, and vault-relative output folder. 3. Optionally select packages, a target, features, private items, and a default profile. 4. Click the book ribbon icon. With one/default profile it runs immediately; otherwise choose a project. Commands are also available for choosing a project, managing profiles, and cancelling an active run. Generation progress appears in a modal. On success, Rustdocs can open the generated workspace index automatically. Do not put hand-written notes inside a generated subtree under filenames that Rustdocs needs. Separate profiles must use separate output folders. ### Source navigation Every item with a rustdoc span has a visible **Source** reference, including fields, variants, impls, and associated items. References show `src/lib.rs:42` or `src/lib.rs:42-67`; page frontmatter also records the original filename and start/end lines. Existing source files inside the vault become clickable vault links. Outside, missing, or compiler-remapped files remain textual locations; no source files are copied or modified. Generated navigation targets deterministic Obsidian blocks (`file.md#^item-…`). Item and Source block IDs derive from the package, Rust path, and item kind, not rustdoc's transient numeric IDs or source line numbers. Associated items include their impl context. Rebuilding unchanged sources produces identical Markdown; moving an item to different source lines does not change its navigation IDs. Source links open the file, while the adjacent range identifies the Rust lines; they do not pretend to jump to a Markdown line. For `.rs` files, Obsidian may use the system's default app; enable **Files and links → Detect all file extensions** if needed. Block IDs are added only to generated Markdown. See [Obsidian's internal-link syntax](https://obsidian.md/help/links). ## Nix development `flake.nix` and `flake.lock` define the canonical toolchain. No global Node or Rust installation is required: ```sh nix develop npm ci npm run check npm run package nix flake check nix build ``` The shell pins Node, npm, nightly Rust, Cargo, rustfmt, Clippy, rust-src, Git, jq, and cargo-deny. Integration tests run actual rustdoc JSON generation when `RUSTDOCS_DIRECT_TOOLCHAIN=1`, which the Nix shell sets. For an Obsidian smoke test, run `npm run package`, install the resulting folder in a test vault, configure both `tests/fixtures/basic` and `tests/fixtures/workspace`, and generate each profile. Verify the indexes, item links, and stale-page cleanup after renaming an item. To check source navigation, place a fixture project inside the test vault. Verify its Source links resolve to `.rs` files and its generated `#^item-…` / `#^source-…` targets appear in Obsidian's block picker. Generate twice and compare the Markdown byte-for-byte (only the ownership manifest timestamp may differ). ## Troubleshooting - **Cargo not found:** launch Obsidian from an environment where `cargo` is on `PATH`. - **Toolchain/unstable option error:** install `nightly-2026-09-12` and select it in the profile, or enter `nix develop` and leave that field blank. - **No targets:** select a package with a library or binary target, and verify any configured target name. - **Refusing to change a note:** move edited notes outside the generated subtree before retrying. Copying the generated marker alone does not establish ownership. Keep the ownership manifest so future runs can update the remaining pages. - **Dependency/build failure:** run the matching `cargo rustdoc` command in the project to resolve native dependencies or feature errors, then retry. Rustdoc JSON’s schema is unstable. This project pins nightly 2026-09-12 and accepts JSON format 61. Other formats fail with a toolchain hint before any vault writes. Output paths cannot traverse hidden folders or symbolic links. ## Contributing and security See [CONTRIBUTING.md](CONTRIBUTING.md), [SECURITY.md](SECURITY.md), and [docs/architecture.md](docs/architecture.md). Rustdocs is available under the MIT license.