[!NOTE]
- Just works. No need to call
setup!- No dependency on
lspconfig.- Lazy initialization by design.
If you are starting out with Rust, Neovim's built-in LSP client API
(see :h lsp) or
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.11rust-analyzer[!NOTE]
For versions that are compatible with older Neovim versions, see previous major version bumps in the changelog.
dot from graphviz,
for crate graphs.cargo,
required for Cargo projects.lldb
or codelldb)
and nvim-dap,
required for debugging.:Rustc unpretty command).
Can be installed using nvim-treesitter,
which also provides highlights, etc.rocks.nvim:Rocks install rustaceanvim
lazy.nvim{
'mrcjkb/rustaceanvim',
version = '^6', -- 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.
For Nix users with flakes enabled, this project provides outputs in the
form of a package and an overlay.
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_analyzersetup or set up the LSP client forrust-analyzermanually, 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.lua[^1]
[^1]: See :help base-directories
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 }
)
vim.keymap.set(
"n",
"K", -- Override Neovim's built-in hover keymap with rustaceanvim's hover actions
function()
vim.cmd.RustLsp({'hover', 'actions'})
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.
debuggables opens a prompt to select from available targets.debug searches 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.
:RustLsp debuggables will only load debug configurations
created by rust-analyzer.require('dap').continue() will load all Rust debug configurations,
including those specified in a .vscode/launch.json
(see :h dap-launch.json).
runnables opens a prompt to select from available targets.run searches 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.
If you set the vim.g.rustaceanvim.tools.test_executor option to 'background',
this plugin will run tests in the background, parse the results,
and - if possible - display failed tests as diagnostics.
: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.
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.
:RustLsp expandMacro
vim.cmd.RustLsp('expandMacro')
:RustLsp rebuildProcMacros
vim.cmd.RustLsp('rebuildProcMacros')
:RustLsp moveItem {up|down}
vim.cmd.RustLsp { 'moveItem', 'up' }
vim.cmd.RustLsp { 'moveItem', 'down' }
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 codeAction
vim.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.
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 actions
vim.cmd.RustLsp { 'hover', 'actions' }
You can invoke a hover action by switching to the hover window and entering <CR>
on the respective line, or with a keymap for the <Plug>RustHoverAction mapping,
which accepts a <count> prefix as the (1-based) index of the hover action to invoke.
For example, if you set the following keymap:
vim.keymap.set('n', '<space>a', '<Plug>RustHoverAction')
you can invoke the third hover action with 3<space>a.
:RustLsp hover range
vim.cmd.RustLsp { 'hover', 'range' }
Display a hover window with explanations from the rust error codes index over error diagnostics (if they have an error code).
:RustLsp explainError {cycle?|cycle_prev?|current?}
vim.cmd.RustLsp('explainError') -- default to 'cycle'
vim.cmd.RustLsp({ 'explainError', 'cycle' })
vim.cmd.RustLsp({ 'explainError', 'cycle_prev' })
vim.cmd.RustLsp({ 'explainError', 'current' })
If called with cycle or no args:
Like vim.diagnostic.goto_next,
explainError will cycle diagnostics,
starting at the cursor position,
until it can find a diagnostic with an error code.
If called with cycle_prev:
Like vim.diagnostic.goto_prev,
searches backwards for a diagnostic with an error code.
If called with current:
Searches for diagnostics only in the
current cursor line.
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?|cycle_prev?|current?}
vim.cmd.RustLsp('renderDiagnostic') -- defaults to 'cycle'
vim.cmd.RustLsp({ 'renderDiagnostic', 'cycle' })
vim.cmd.RustLsp({ 'renderDiagnostic', 'cycle_prev' })
vim.cmd.RustLsp({ 'renderDiagnostic', 'current' })
If called with cycle or no args:
Like vim.diagnostic.goto_next,
renderDiagnostic will cycle diagnostics,
starting at the cursor position,
until it can find a diagnostic with rendered data.
If called with cycle_prev:
Like vim.diagnostic.goto_prev,
searches backwards for a diagnostic with rendered data.
If called with current:
Searches for diagnostics only in the
current cursor line.
Sometimes, rust-analyzer provides related diagnostics in multiple locations.
Using the relatedDiagnostics subcommand, you can navigate between them.
If a diagnostic has more than one related diagnostic, this will populate the quickfix list.
:RustLsp relatedDiagnostics
vim.cmd.RustLsp('relatedDiagnostics')
:RustLsp openCargo
vim.cmd.RustLsp('openCargo')
Open docs.rs documentation for the symbol under the cursor.
:RustLsp openDocs
vim.cmd.RustLsp('openDocs')
:RustLsp parentModule
vim.cmd.RustLsp('parentModule')
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 ]]
}
! will include dependencies in the search.vim.lsp.buf.workspace_symbol()
by setting the rust-analyzer
workspace.symbol.search server option.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 joinLines
vim.cmd.RustLsp('joinLines')

:RustLsp ssr {query}
vim.cmd.RustLsp { 'ssr', '<query>' --[[ optional ]] }
:RustLsp crateGraph {backend {output}}
vim.cmd.RustLsp { 'crateGraph', '[backend]', '[output]' }
Requires:
Requires rust-analyzer >= 2025-01-20.
:RustLsp syntaxTree
vim.cmd.RustLsp('syntaxTree')
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.
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' }
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:
:Rustc unpretty command).
Can be installed using nvim-treesitter. On Linux and MacOS, rustaceanvim can auto-detect and connect to a
running ra-multiplex server.
By default, it will try to do so automatically if the vim.g.rustaceanvim.server.cmd
option is unset.
See also :h rustaceanvim.ra_multiplex.
You can configure rust-analyzer on the fly using the :RustAnalyzer config subcommand.
The command takes a Lua table as an argument (it does not validate it!).
For example:
:RustAnalyzer config { checkOnSave = false }
vim.cmd.RustAnalyzer { 'config', '{ checkOnSave = false }' }
See also: rust-analyzer configuration.
To modify the default configuration, set vim.g.rustaceanvim.
:h rustaceanvim for a detailed
documentation of all available configuration options.
You may need to run :helptags ALL if the documentation has not been installed.RustaceanDefaultConfig).rust-analyzer documentation.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.rustaceanvimcan also be a function that returns a table.You can also use
:h vim.lsp.configto configurevim.g.rustaceanvim.serveroptions. For example,vim.lsp.config("*", {})orvim.lsp.config("rust-analyzer", {}).
codelldb for debuggingFor 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:
vscode-extensions.vadimcn.vscode-lldb.adaptercodelldb package.codelldb-bin (AUR)mason.nvim:
:MasonInstall codelldbIf your distribution does not have a codelldb package,
you can configure it as follows:
$HOME/.vscode/extensions/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),
},
}
end
rust-analyzer settings per projectBy default, this plugin will look for a .vscode/settings.json[^2]
file and attempt to load it.
If the file does not exist, or it can't be decoded,
the server.default_settings will be used.
[^2]: See this example and the rust-analyzer configuration manual. Note that JSON5 is currently not supported by Neovim.
Another option is to use :h exrc.
For a health check, run :checkhealth rustaceanvim
rust-analyzer log fileTo 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.
nvim -u minimal.lua
[!IMPORTANT]
I strongly recommend against using rust-analyzer managed my mason.nvim, as version mismatches between rust-analyzer and your project toolchain can and most likely will lead to subtle issues.
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.
Or, bisect your existing plugins and config.
[!NOTE]
If you use Nix, you can run
nix run "github:mrcjkb/rustaceanvim#nvim-minimal-stable". ornix run "github:mrcjkb/rustaceanvim#nvim-minimal-nightly".
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,
I have removed the code from this plugin.
See :h lsp-inlay_hint).
You can use the nvim-lsp-endhints
plugin.
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,
or you may use blink.cmp.
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.
rust-analyzer has limited support for standalone files. Many diagnostics come from Cargo. If you're not in a Cargo project, you won't see any Cargo diagnostics.
cordx56/rustowl
Language server to visualize ownership and lifetimes
for debugging and optimization.
Comes with a Neovim plugin.rouge8/neotest-rust
neotest
adapter for Rust, using cargo-nextest.Saecki/crates.nvim
Neovim plugin that helps managing crates.io dependenciesvxpm/ferris.nvim
Geared towards people who prefer manual LSP client configuration.
Has some features that have not yet
been implemented by this plugin.adaszko/tree_climber_rust.nvim
tree-sitter powered incremental selection tailored for Rust.rust-tools.nvim draws inspiration from akinsho/flutter-tools.nvim