Explore the docs »
Report Bug
·
Request Feature
·
Ask Question
Supercharge your Rust experience in Neovim!
A heavily modified fork of rust-tools.nvim
🦀
Note
- Just works. No need to call
setup! - No dependency on
lspconfig. - Lazy initialization by design.
- 📝 Prerequisites
- 📥 Installation
- ⚡ Quick setup
- 📚 Usage / Features
- ⚙️ Advanced configuration
- 🩺 Troubleshooting
- 🗨️ FAQ
- 🚣 Migrating from rust-tools
If you are starting out with Rust, nvim-lspconfig.rust_analyzer
is probably enough for you.
It provides the lowest common denominator of LSP support.
This plugin is for those who would like additional non-standard features
that are specific to rust-analyzer.
neovim >= 0.9rust-analyzer
dotfromgraphviz, for crate graphs.cargo, required for Cargo projects.- A debug adapter (e.g.
lldborcodelldb) andnvim-dap, required for debugging. - A tree-sitter parser for Rust (required for the
:Rustc unprettycommand). Can be installed using nvim-treesitter, which also provides highlights, etc.
This plugin is available on LuaRocks:
Example using lazy.nvim:
{
'mrcjkb/rustaceanvim',
version = '^4', -- Recommended
lazy = false, -- This plugin is already lazy
}Tip
It is suggested to pin to tagged releases if you would like to avoid breaking changes.
To manually generate documentation, use :helptags ALL.
Note
For NixOS users with flakes enabled, this project provides outputs in the
form of a package and an overlay; use it as you wish in your NixOS or
home-manager configuration.
It is also available in nixpkgs.
Look at the configuration information below to get started.
This plugin automatically configures the rust-analyzer builtin LSP
client and integrates with other Rust tools.
See the Usage / Features section for more info.
Warning
Do not call the nvim-lspconfig.rust_analyzer
setup or set up the LSP client for rust-analyzer manually,
as doing so may cause conflicts.
This is a filetype plugin that works out of the box,
so there is no need to call a setup function or configure anything
to get this plugin working.
You will most likely want to add some keymaps.
Most keymaps are only useful in rust files,
so I suggest you define them in ~/.config/nvim/after/ftplugin/rust.lua1
Example:
local bufnr = vim.api.nvim_get_current_buf()
vim.keymap.set(
"n",
"<leader>a",
function()
vim.cmd.RustLsp('codeAction') -- supports rust-analyzer's grouping
-- or vim.lsp.buf.codeAction() if you don't want grouping.
end,
{ silent = true, buffer = bufnr }
)Tip
- For more LSP related keymaps, see the
nvim-lspconfigsuggestions. - If you want to share keymaps with
nvim-lspconfig, you can also use thevim.g.rustaceanvim.server.on_attachfunction, or anLspAttachautocommand. - See the Advanced configuration section
or
:h rustaceanvim.configfor more configuration options.
Important
- Do not set
vim.g.rustaceanviminafter/ftplugin/rust.lua, as the file is sourced after the plugin is initialized.
Debugging
debuggablesopens a prompt to select from available targets.debugsearches for a target at the current cursor position.
:RustLsp[!] debuggables {args[]}?
:RustLsp[!] debug {args[]}?vim.cmd.RustLsp('debug')
vim.cmd.RustLsp('debuggables')
-- or, to run the previous debuggable:
vim.cmd.RustLsp { 'debuggables', bang = true }
-- or, to override the executable's args:
vim.cmd.RustLsp {'debuggables', 'arg1', 'arg2' }Calling the command with a bang ! will rerun the last debuggable.
Requires:
By default, this plugin will silently attempt to autoload nvim-dap
configurations when the LSP client attaches.
You can call them with require('dap').continue() or :DapContinue once
they have been loaded. The feature can be disabled by setting
vim.g.rustaceanvim.dap.autoload_configurations = false.
It is disabled by default in neovim 0.9, as it can block the UI.
:RustLsp debuggableswill only load debug configurations created byrust-analyzer.require('dap').continue()will load all Rust debug configurations, including those specified in a.vscode/launch.json(see:h dap-launch.json).- Note that rustaceanvim may only be able to load DAP configurations when rust-analyzer has finished initializing (which may be after the client attaches, in large projects). This means that the DAP configurations may not be loaded immediately upon startup.
Runnables
runnablesopens a prompt to select from available targets.runsearches for a target at the current cursor position.
:RustLsp[!] runnables {args[]}?
:RustLsp[!] run {args[]}?vim.cmd.RustLsp('run')
vim.cmd.RustLsp('runnables')
-- or, to run the previous runnable:
vim.cmd.RustLsp { 'runnables', bang = true }
-- or, to override the executable's args:
vim.cmd.RustLsp {'runnables', 'arg1', 'arg2' }Calling the command with a bang ! will rerun the last runnable.
Testables and failed test diagnostics
If you are using Neovim >= 0.10, you can set the vim.g.rustaceanvim.tools.test_executor
option to 'background', and this plugin will run tests in the background,
parse the results, and - if possible - display failed tests as diagnostics.
This is also possible in Neovim 0.9, but tests won't be run in the background, and will block the UI.
:RustLsp[!] testables {args[]}?vim.cmd.RustLsp('testables')
-- or, to run the previous testables:
vim.cmd.RustLsp { 'testables', bang = true }
-- or, to override the executable's args:
vim.cmd.RustLsp {'testables', 'arg1', 'arg2' }Calling the command with a bang ! will rerun the last testable.
Neotest integration
This plugin provides a neotest adapter, which you can add to neotest as follows:
require('neotest').setup {
-- ...,
adapters = {
-- ...,
require('rustaceanvim.neotest')
},
}Note: If you use rustaceanvim's neotest adapter, do not add neotest-rust.
Here is a comparison between rustaceanvim's adapter and neotest-rust:
| rustaceanvim | neotest-rust | |
|---|---|---|
| Test discovery | rust-analyzer (LSP) | tree-sitter |
| Command construction | rust-analyzer (LSP) | tree-sitter |
| DAP strategy | Automatic DAP detection (reuses debuggables); overridable with vim.g.rustaceanvim.dap |
Defaults to codelldb; manual configuration |
| Test runner | cargo or cargo-nextest, if detected |
cargo-nextest |
If you configure rustaceanvim to use neotest, the tools.test_executor
will default to using neotest for testables and runnables that are tests.
Rebuild proc macros
:RustLsp rebuildProcMacrosvim.cmd.RustLsp('rebuildProcMacros')Move item up/down
:RustLsp moveItem {up|down}vim.cmd.RustLsp { 'moveItem', 'up' }
vim.cmd.RustLsp { 'moveItem', 'down' }Grouped code actions
Sometimes, rust-analyzer groups code actions by category,
which is not supported by Neovim's built-in vim.lsp.buf.codeAction.
This plugin provides a command with a UI that does:
:RustLsp codeActionvim.cmd.RustLsp('codeAction')If you set the option vim.g.rustaceanvim.tools.code_actions.ui_select_fallback
to true (defaults to false), it will fall back to vim.ui.select
if there are no grouped code actions.
Hover actions
Note: To activate hover actions, run the command twice.
This will move you into the window, then press enter on the selection you want.
Alternatively, you can set auto_focus to true in your config and you will
automatically enter the hover actions window.
:RustLsp hover actionsvim.cmd.RustLsp { 'hover', 'actions' }By default, this plugin replaces Neovim's built-in hover handler with hover
actions, so you can also use vim.lsp.buf.hover().
Hover range
:RustLsp hover rangevim.cmd.RustLsp { 'hover', 'range' }Explain errors
Display a hover window with explanations from the rust error codes index over error diagnostics (if they have an error code).
:RustLsp explainError {cycle?|current?}vim.cmd.RustLsp('explainError') -- default to 'cycle'
vim.cmd.RustLsp({ 'explainError', 'cycle' })
vim.cmd.RustLsp({ 'explainError', 'current' })-
If called with
cycleor no args: Likevim.diagnostic.goto_next,explainErrorwill cycle diagnostics, starting at the cursor position, until it can find a diagnostic with an error code. -
If called with
current: Searches for diagnostics only in the current cursor line.
Render diagnostics
Display a hover window with the rendered diagnostic, as displayed
during cargo build.
Useful for solving bugs around borrowing and generics,
as it consolidates the important bits (sometimes across files)
together.
:RustLsp renderDiagnostic {cycle?|current?}vim.cmd.RustLsp('renderDiagnostic') -- defaults to 'cycle'
vim.cmd.RustLsp({ 'renderDiagnostic', 'cycle' })
vim.cmd.RustLsp({ 'renderDiagnostic', 'current' })-
If called with
cycleor no args: Likevim.diagnostic.goto_next,renderDiagnosticwill cycle diagnostics, starting at the cursor position, until it can find a diagnostic with rendered data. -
If called with
current: Searches for diagnostics only in the current cursor line.
Open Cargo.toml
:RustLsp openCargovim.cmd.RustLsp('openCargo')Open docs.rs documentation
Open docs.rs documentation for the symbol under the cursor.
:RustLsp openDocsvim.cmd.RustLsp('openDocs')Parent Module
:RustLsp parentModulevim.cmd.RustLsp('parentModule')Filtered workspace symbol searches
rust-analyzer supports filtering workspace symbol searches.
:RustLsp[!] workspaceSymbol {onlyTypes?|allSymbols?} {query?}vim.cmd.RustLsp('workspaceSymbol')
-- or
vim.cmd.RustLsp {
'workspaceSymbol',
'<onlyTypes|allSymbols>' --[[ optional ]],
'<query>' --[[ optional ]],
bang = true --[[ optional ]]
}- Calling the command with a bang
!will include dependencies in the search. - You can also influence the behaviour of
vim.lsp.buf.workspace_symbol()by setting the rust-analyzerworkspace.symbol.searchserver option.
Join lines
Join selected lines into one, smartly fixing up whitespace, trailing commas, and braces. Works with individual lines in normal mode and multiple lines in visual mode.
:RustLsp joinLinesvim.cmd.RustLsp('joinLines')Structural search replace
- Searches the entire buffer in normal mode.
- Searches the selection in visual mode.
:RustLsp ssr {query}vim.cmd.RustLsp { 'ssr', '<query>' --[[ optional ]] }View crate graph
:RustLsp crateGraph {backend {output}}vim.cmd.RustLsp { 'crateGraph', '[backend]', '[output]' }Requires:
Fly check
Run cargo check or another compatible command (f.x. clippy)
in a background thread and provide LSP diagnostics based on
the output of the command.
Useful in large projects where running cargo check on each save
can be costly.
:RustLsp flyCheck {run?|clear?|cancel?}vim.cmd.RustLsp('flyCheck') -- defaults to 'run'
vim.cmd.RustLsp { 'flyCheck', 'run' }
vim.cmd.RustLsp { 'flyCheck', 'clear' }
vim.cmd.RustLsp { 'flyCheck', 'cancel' }[!NOTE]
This is only useful if you set the option,
['rust-analzyer'].checkOnSave = false.
View HIR / MIR
Opens a buffer with a textual representation of the HIR or MIR of the function containing the cursor. Useful for debugging or when working on rust-analyzer itself.
:RustLsp view {hir|mir}vim.cmd.RustLsp { 'view', 'hir' }
vim.cmd.RustLsp { 'view', 'mir' }Rustc unpretty
Opens a buffer with a textual representation of the MIR or others things, of the function closest to the cursor. Achieves an experience similar to Rust Playground.
NOTE: This currently requires a tree-sitter parser for Rust, and a nightly compiler toolchain.
:Rustc unpretty {hir|mir|...}vim.cmd.Rustc { 'unpretty', 'hir' }
vim.cmd.Rustc { 'unpretty', 'mir' }
-- ...Requires:
- A tree-sitter parser for Rust (required for the
:Rustc unprettycommand). Can be installed using nvim-treesitter.
To modify the default configuration, set vim.g.rustaceanvim.
- See
:help rustaceanvim.configfor a detailed documentation of all available configuration options. You may need to run:helptags ALLif the documentation has not been installed. - The default configuration can be found here (see
RustaceanDefaultConfig). - For detailed descriptions of the language server configs,
see the
rust-analyzerdocumentation.
You only need to specify the keys that you want to be changed, because defaults are applied for keys that are not provided.
Example config:
vim.g.rustaceanvim = {
-- Plugin configuration
tools = {
},
-- LSP configuration
server = {
on_attach = function(client, bufnr)
-- you can also put keymaps in here
end,
default_settings = {
-- rust-analyzer language server configuration
['rust-analyzer'] = {
},
},
},
-- DAP configuration
dap = {
},
}Tip
vim.g.rustaceanvim can also be a function that returns
a table.
For Rust, codelldb from the CodeLLDB VSCode extension
provides a better experience than lldb.
If you are using a distribution that lets you install the codelldb
executable, this plugin will automatically detect it and configure
itself to use it as a debug adapter.
Some examples:
- NixOS:
vscode-extensions.vadimcn.vscode-lldb.adapter - This repository's Nix flake provides a
codelldbpackage. - Arch Linux:
codelldb-bin(AUR) - Using
mason.nvim::MasonInstall codelldb
If your distribution does not have a codelldb package,
you can configure it as follows:
- Install the CodeLLDB VSCode extension.
- Find out where it is installed.
On Linux, this is typically in
$HOME/.vscode/extensions/ - Update your configuration:
vim.g.rustaceanvim = function()
-- Update this path
local extension_path = vim.env.HOME .. '/.vscode/extensions/vadimcn.vscode-lldb-1.10.0/'
local codelldb_path = extension_path .. 'adapter/codelldb'
local liblldb_path = extension_path .. 'lldb/lib/liblldb'
local this_os = vim.uv.os_uname().sysname;
-- The path is different on Windows
if this_os:find "Windows" then
codelldb_path = extension_path .. "adapter\\codelldb.exe"
liblldb_path = extension_path .. "lldb\\bin\\liblldb.dll"
else
-- The liblldb extension is .so for Linux and .dylib for MacOS
liblldb_path = liblldb_path .. (this_os == "Linux" and ".so" or ".dylib")
end
local cfg = require('rustaceanvim.config')
return {
dap = {
adapter = cfg.get_codelldb_adapter(codelldb_path, liblldb_path),
},
}
endBy default, this plugin will look for a rust-analyzer.json2
file in the project root directory, and attempt to load it.
If the file does not exist, or it can't be decoded,
the server.default_settings will be used.
You can change this behaviour with the server.settings config:
vim.g.rustaceanvim = {
-- ...
server = {
---@param project_root string Path to the project root
settings = function(project_root)
local ra = require('rustaceanvim.config.server')
return ra.load_rust_analyzer_settings(project_root, {
settings_file_pattern = 'rust-analyzer.json'
})
end,
},
}For a health check, run :checkhealth rustaceanvim
To open the rust-analyzer log file, run :RustLsp logFile.
To troubleshoot this plugin with a minimal config in a temporary directory, you can try minimal.lua.
mkdir -p /tmp/minimal/
NVIM_DATA_MINIMAL="/tmp/minimal" NVIM_APP_NAME="nvim-minimal" nvim -u NORC -u minimal.luaNote
If you use Nix, you can run
nix run "github:mrcjkb/rustaceanvim#nvim-minimal-stable".
or
nix run "github:mrcjkb/rustaceanvim#nvim-minimal-nightly".
If you cannot reproduce your issue with a minimal config,
it may be caused by another plugin,
or a setting of your plugin manager.
In this case, add additional plugins and configurations to minimal.lua,
until you can reproduce it.
For issues related to rust-analyzer (e.g. LSP features not working), see also the rust-analyzer troubleshooting guide.
As Neovim >= 0.10 supports inlay hints natively (:h lsp-inlay_hint),
I have removed the
code from this plugin.
To enable inlay hints in Neovim < 0.10, see this discussion.
As of #ff097f2091e7a970e5b12960683b4dade5563040,
Neovim has built-in completion based on the triggerCharacters sent by
language servers.
Omni completion is also available for a more traditional vim-like completion experience.
For more extensible and complex autocompletion setups you need a plugin such as nvim-cmp
and a LSP completion source like cmp-nvim-lsp.
This plugin will automatically register the necessary client capabilities
if you have cmp-nvim-lsp installed.
rustaceanvim doesn't implement (auto)completion. Issues with (auto)completion either come from another plugin or rust-analzyer.
See :h rustaceanvim.mason for details about troubleshooting
mason.nvim and nvim-lspconfig issues, or configuring rustaceanvim to use
a rust-analyzer installation that is managed by mason.nvim.
rouge8/neotest-rustAneotestadapter for Rust, usingcargo-nextest.Saecki/crates.nvimvxpm/ferris.nvimGeared towards people who prefer manual LSP client configuration. Has some features that have not yet been implemented by this plugin.adaszko/tree_climber_rust.nvimtree-sitter powered incremental selection tailored for Rust.
rust-tools.nvim draws inspiration from akinsho/flutter-tools.nvim
Footnotes
-
See this example and the rust-analyzer configuration manual. ↩











