| # Rust Analyzer | |
| `rules_rust` ships a one-shot installer that configures | |
| [rust-analyzer](https://rust-analyzer.github.io/) to use the project's Bazel | |
| toolchain. After setup, rust-analyzer, the proc-macro server, and rustfmt | |
| all come from Bazel — no host Rust install required. | |
| ## Quick start | |
| Pick your editor below. Each runs the same `setup` tool with a different | |
| subcommand — `setup` is re-runnable any time. | |
| ### VSCode | |
| 1. Install the | |
| [rust-analyzer extension](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer). | |
| 2. ``` | |
| bazel run @rules_rust//tools/rust_analyzer:setup -- vscode | |
| ``` | |
| 3. Reload the VSCode window. | |
| `.vscode/settings.json` is always written; a `*.code-workspace` at | |
| the workspace root is picked up too. Existing user keys and comments | |
| survive re-runs, so `.vscode/settings.json` and `.code-workspace` are | |
| safe to commit. | |
| Add the launcher dir to `.gitignore`: | |
| ``` | |
| .vscode/.rules_rust_analyzer/ | |
| ``` | |
| Re-run `setup` after a toolchain change (rustup update, `MODULE.bazel` | |
| edit, `bazel clean --expunge`). | |
| ### Neovim | |
| ``` | |
| bazel run @rules_rust//tools/rust_analyzer:setup -- neovim | |
| ``` | |
| Prints an `nvim-lspconfig` Lua snippet to stdout. Paste it into your | |
| `init.lua` (or pipe to a file you `require`). Restart Neovim. | |
| For [`rustaceanvim`](https://github.com/mrcjkb/rustaceanvim) users: | |
| pass the printed `cmd` and `settings` table through its `server` | |
| option (`vim.g.rustaceanvim = { server = { cmd = ..., settings = ... } }`). | |
| ### Helix | |
| ``` | |
| bazel run @rules_rust//tools/rust_analyzer:setup -- helix | |
| ``` | |
| Prints a `languages.toml` snippet. Paste it into | |
| `<workspace>/.helix/languages.toml`. Restart Helix. | |
| ### Other editors (`coc.nvim`, `vim-lsp`, ALE, etc.) | |
| ``` | |
| bazel run @rules_rust//tools/rust_analyzer:setup -- print | |
| ``` | |
| Prints a generic JSON snippet using the `rust-analyzer.*` keys VSCode | |
| uses. `coc.nvim` reads them via `coc-settings.json` (open with | |
| `:CocConfig`); `vim-lsp` / ALE / `LanguageClient-neovim` accept the | |
| same keys via plugin-specific config files. | |
| ## Flags | |
| Re-runnable at any time. Global flags work on any subcommand. | |
| | Flag | Effect | | |
| |---|---| | |
| | `--skip-proc-macro-server` | Don't manage the proc-macro key. | | |
| | `--skip-rustfmt` | Don't manage the formatter key (use host rustfmt). | | |
| | `--per-package-workspaces` / `--no-per-package-workspaces` | Opt this developer in/out of per-package workspace splitting (see below). | | |
| | `--clippy` / `--no-clippy` | Opt this developer in/out of running clippy on save and streaming its diagnostics alongside rustc's. | | |
| | `--clean` | Delete `<launcher-dir>/cache/` before running the rest of setup. See Troubleshooting. | | |
| The `--clippy` and `--per-package-workspaces` toggles are **per-user**: they mutate `<launcher-dir>/user_config.json` (gitignored) instead of the shared committed settings file. Two developers on the same workspace can hold different preferences without touching the checked-in configuration. Editing `user_config.json` by hand works too. | |
| The `vscode` subcommand adds: | |
| | Flag | Effect | | |
| |---|---| | |
| | `--settings-json <path>` | Override the settings.json output. Defaults to `<workspace>/.vscode/settings.json`. | | |
| | `--code-workspace <path>` | `.code-workspace` file to also update. Required when the workspace root has more than one. | | |
| | `--no-code-workspace` | Skip the `.code-workspace` write. | | |
| | `--settings-key <key>` | Nest managed keys under this key inside the `.code-workspace` (default: `settings`). | | |
| | `--dry-run` | Print each would-be-written file to stdout. | | |
| | `--replace` | Overwrite managed keys instead of merging. Sibling `folders` / `tasks` / `extensions` in a `.code-workspace` survive. | | |
| ## What you get | |
| - **`▶ Run Tests` / `▶ Run Test`** codelens on every `#[cfg(test)] mod` and | |
| individual `#[test]`. | |
| - **On-save squiggles** from rustc diagnostics. Matches `cargo check` — | |
| errors anywhere in the dep graph surface at their actual file paths. | |
| - **Format-on-save** via the Bazel-toolchain rustfmt. | |
| - **Workspace reload** on watched `BUILD` / `MODULE.bazel` changes. | |
| ## Troubleshooting | |
| ### Symbols / deps look wrong | |
| Restart rust-analyzer (or save a `BUILD` file). If that doesn't fix | |
| it, re-run setup with `--clean` to nuke the discovery cache: | |
| ``` | |
| bazel run @rules_rust//tools/rust_analyzer:setup -- --clean vscode | |
| ``` | |
| Works with any subcommand (`vscode` / `neovim` / `helix` / `print`). | |
| ### Diagnostics stopped appearing | |
| Check `<workspace>/.rules_rust_analyzer/flycheck.log`. | |
| ### After `bazel clean --expunge` or toolchain changes | |
| Re-run `setup`. | |
| ### Noisy `cargo metadata` errors on startup | |
| `setup` does not manage `rust-analyzer.files.excludeDirs`. If your | |
| workspace has stub `Cargo.toml` files that aren't meant to be | |
| auto-loaded (common in `rules_rust` itself under `examples/`, | |
| `crate_universe/`, etc.), rust-analyzer still finds them and logs | |
| errors. Silence them by adding the directory names to `settings.json` | |
| yourself — your entries survive future `setup` runs: | |
| ``` | |
| "rust-analyzer.files.excludeDirs": ["examples", "some_other_dir"] | |
| ``` | |
| Trade-off: `files.excludeDirs` also hides those sources from | |
| rust-analyzer's virtual filesystem, so files under those directories | |
| won't get IDE features even if they're part of a Bazel-discovered | |
| crate. Only exclude directories whose sources you're willing to lose | |
| IDE support on. | |
| ## Workspace splitting | |
| By default the whole project is treated as a single workspace. | |
| For monorepos where indexing the whole graph is too slow, pass | |
| `--per-package-workspaces`. Discover then scopes to the saved file's | |
| package + deps; rust-analyzer reloads when you jump to a different | |
| package. Caveat: _dependents_ of the package you're working on aren't | |
| indexed, so "find usages" can miss callers in other packages. | |
| Switch any time by re-running `setup` with or without the flag. | |
| ## Debugging | |
| The `▶ Debug` codelens VSCode renders next to `#[test]` functions | |
| **does not work** for Bazel projects. Use `.vscode/launch.json` + F5 | |
| instead: | |
| ``` | |
| bazel run @rules_rust//tools/vscode:gen_launch_json | |
| ``` | |
| Install | |
| [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb) | |
| first. Set a breakpoint inside the test and run the target — one | |
| launch config covers every test in that binary. |