Rust-analyzer’s arrival transformed Vim into a genuinely powerful IDE for Rust development, going far beyond basic syntax highlighting and linting. The real magic happens when you integrate it with a debugger.
Let’s see rust-analyzer in action. Imagine you have a file src/main.rs:
fn main() {
let mut x = 5;
println!("The value of x is: {}", x);
x += 1;
println!("Now x is: {}", x);
}
With rust-analyzer configured (typically via a plugin manager like vim-plug or packer.nvim and a .vimrc or init.vim file), you’ll get instant feedback. As you type x +=, you’ll see an inlay hint above the line showing + 1, a subtle but powerful indication of what the compiler understands. Hovering over x might show its type (i32) or its current value if you’re debugging. Autocompletion will be context-aware, suggesting println! and its arguments.
The core problem rust-analyzer solves is bridging the gap between Vim’s text-editing capabilities and the complex semantic understanding of a modern compiler. It speaks the Language Server Protocol (LSP), a standardized way for editors and language servers to communicate. rust-analyzer is the server, providing features like:
- Code Completion: Suggests relevant code snippets as you type.
- Go to Definition/Declaration: Quickly jump to where a function or variable is defined.
- Find References: See all the places a symbol is used.
- Hover Information: Displays type information, documentation, and potential errors on hover.
- Diagnostics: Shows compiler errors and warnings directly in the editor, often with quick-fix suggestions.
- Code Actions: Offers automated refactorings and fixes.
Setting this up usually involves a few steps in your Vim configuration. For vim-plug:
Plug 'rust-lang/rust-analyzer', { 'branch': 'master', 'dir': 'editors/vim' }
Plug 'prabirshrestha/vim-lsp'
Plug 'prabirshrestha/asyncrun.vim'
Plug 'j-hui/fidget.nvim' " For LSP status indicators
And in your .vimrc or init.vim:
" LSP configuration
let g:lsp_diagnostics_enabled = 1
autocmd User lsp_setup call lsp#register_server({
\ 'name': 'rust-analyzer',
\ 'cmd': {server_info->['rust-analyzer']},
\ 'root_pattern': ['Cargo.toml', '.git'],
\ 'filetype': 'rust'
\})
" Optional: Configure fidget for LSP status
lua << EOF
require('fidget').setup({})
EOF
The root_pattern is crucial; it tells rust-analyzer which directory to consider the project root (where Cargo.toml resides). The cmd is simply the executable name.
Now, for debugging. This is where things get really interesting. We’ll use nvim-dap (a Neovim plugin for the Debug Adapter Protocol) and rust-gdb or rust-lldb.
First, install nvim-dap:
Plug 'mfussenegger/nvim-dap'
Then, configure it in your .vimrc or init.vim:
" nvim-dap configuration
lua << EOF
require('dap').setup({
adapters = {
rust = {
type = 'executable',
command = 'rust-gdb', -- or 'rust-lldb'
args = {'-q', '--interpreter=mi'}
}
},
configurations = {
rust = {{
name = 'Launch file',
type = 'rust',
request = 'launch',
program = '${fileDirname}/${fileBasenameNoExtension}',
cwd = '${fileDirname}',
stopOnEntry = false,
}},
rust_test = {{
name = 'Run test',
type = 'rust',
request = 'launch',
program = '${fileDirname}/${fileBasenameNoExtension}',
cwd = '${fileDirname}',
args = {{ '--test', '${fileBasenameNoExtension}' }},
stopOnEntry = false,
}}
}
})
-- Keybindings for DAP (example)
vim.keymap.set('n', '<leader>db', function() require('dap').toggle_breakpoint() end)
vim.keymap.set('n', '<leader>dc', function() require('dap').continue() end)
vim.keymap.set('n', '<leader>dn', function() require('dap').step_over() end)
vim.keymap.set('n', '<leader>di', function() require('dap').step_into() end)
vim.keymap.set('n', '<leader>do', function() require('dap').step_out() end)
vim.keymap.set('n', '<leader>dR', function() require('dap').restart() end)
vim.keymap.set('n', '<leader>dg', function() require('dap').goto_implementation() end)
vim.keymap.set('n', '<leader>dC', function() require('dap').run_class() end)
vim.keymap.set('n', '<leader>d=', function() require('dap').down() end)
vim.keymap.set('n', '<leader>d?', function() require('dap').up() end)
vim.keymap.set('n', '<leader>d<', function() require('dap').log_trace() end)
vim.keymap.set('n', '<leader>d>', function() require('dap').set_exception_breakpoints() end)
vim.keymap.set('n', '<leader>d', function() require('dap').run_last() end)
vim.keymap.set('n', '<leader>da', function() require('dap').add() end)
vim.keymap.set('n', '<leader>dl', function() require('dap').set_log_points() end)
vim.keymap.set('n', '<leader>de', function() require('dap').set_expression_filter() end)
vim.keymap.set('n', '<leader>ds', function() require('dap').list_variables() end)
vim.keymap.set('n', '<leader>dw', function() require('dap').list_watch_expressions() end)
vim.keymap.set('n', '<leader>dX', function() require('dap').clear_breakpoints() end)
vim.keymap.set('n', '<leader>d<CR>', function() require('dap').repl.open() end)
vim.keymap.set('n', '<leader>d<Tab>', function() require('dap').repl.toggle() end)
vim.keymap.set('n', '<leader>d<BS>', function() require('dap').repl.close() end)
vim.keymap.set('n', '<leader>d<Space>', function() require('dap').repl.input() end)
vim.keymap.set('n', '<leader>d<Up>', function() require('dap').repl.up() end)
vim.keymap.set('n', '<leader>d<Down>', function() require('dap').repl.down() end)
vim.keymap.set('n', '<leader>d<Left>', function() require('dap').repl.left() end)
vim.keymap.set('n', '<leader>d<Right>', function() require('dap').repl.right() end)
vim.keymap.set('n', '<leader>d<Home>', function() require('dap').repl.home() end)
vim.keymap.set('n', '<leader>d<End>', function() require('dap').repl.end() end)
vim.keymap.set('n', '<leader>d<PageUp>', function() require('dap').repl.page_up() end)
vim.keymap.set('n', '<leader>d<PageDown>', function() require('dap').repl.page_down() end)
vim.keymap.set('n', '<leader>d<C-d>', function() require('dap').repl.delete_line() end)
vim.keymap.set('n', '<leader>d<C-u>', function() require('dap').repl.scroll_up() end)
vim.keymap.set('n', '<leader>d<C-d>', function() require('dap').repl.scroll_down() end)
vim.keymap.set('n', '<leader>d<C-a>', function() require('dap').repl.select_all() end)
vim.keymap.set('n', '<leader>d<C-b>', function() require('dap').repl.clear_screen() end)
vim.keymap.set('n', '<leader>d<C-c>', function() require('dap').repl.cancel_input() end)
vim.keymap.set('n', '<leader>d<C-o>', function() require('dap').repl.open_file() end)
vim.keymap.set('n', '<leader>d<C-p>', function() require('dap').repl.print_to_console() end)
vim.keymap.set('n', '<leader>d<C-r>', function() require('dap').repl.run_command() end)
vim.keymap.set('n', '<leader>d<C-x>', function() require('dap').repl.execute_selection() end)
vim.keymap.set('n', '<leader>d<C-z>', function() require('dap').repl.undo() end)
vim.keymap.set('n', '<leader>d<C-y>', function() require('dap').repl.redo() end)
vim.keymap.set('n', '<leader>d<C-k>', function() require('dap').repl.kill_line() end)
vim.keymap.set('n', '<leader>d<C-l>', function() require('dap').repl.kill_to_end_of_line() end)
vim.keymap.set('n', '<leader>d<C-h>', function() require('dap').repl.kill_to_beginning_of_line() end)
vim.keymap.set('n', '<leader>d<C-w>', function() require('dap').repl.kill_word_backward() end)
vim.keymap.set('n', '<leader>d<C-f>', function() require('dap').repl.kill_word_forward() end)
vim.keymap.set('n', '<leader>d<C-t>', function() require('dap').repl.transpose_chars() end)
vim.keymap.set('n', '<leader>d<C-p>', function() require('dap').repl.transpose_words() end)
vim.keymap.set('n', '<leader>d<C-n>', function() require('dap').repl.yank() end)
vim.keymap.set('n', '<leader>d<C-v>', function() require('dap').repl.paste() end)
vim.keymap.set('n', '<leader>d<C-x><C-e>', function() require('dap').repl.edit_insert_mode() end)
vim.keymap.set('n', '<leader>d<C-x><C-f>', function() require('dap').repl.find_file() end)
vim.keymap.set('n', '<leader>d<C-x><C-p>', function() require('dap').repl.previous_history() end)
vim.keymap.set('n', '<leader>d<C-n>', function() require('dap').repl.next_history() end)
vim.keymap.set('n', '<leader>d<C-b>', function() require('dap').repl.backward_char() end)
vim.keymap.set('n', '<leader>d<C-f>', function() require('dap').repl.forward_char() end)
vim.keymap.set('n', '<leader>d<C-a>', function() require('dap').repl.beginning_of_line() end)
vim.keymap.set('n', '<leader>d<C-e>', function() require('dap').repl.end_of_line() end)
vim.keymap.set('n', '<leader>d<C-p>', function() require('dap').repl.up_line_or_history() end)
vim.keymap.set('n', '<leader>d<C-n>', function() require('dap').repl.down_line_or_history() end)
vim.keymap.set('n', '<leader>d<C-k>', function() require('dap').repl.kill_line() end)
vim.keymap.set('n', '<leader>d<C-y>', function() require('dap').repl.yank_from_kill_ring() end)
vim.keymap.set('n', '<leader>d<C-i>', function() require('dap').repl.insert_mode() end)
vim.keymap.set('n', '<leader>d<C-r>', function() require('dap').repl.reverse_search_history() end)
vim.keymap.set('n', '<leader>d<C-s>', function() require('dap').repl.forward_search_history() end)
vim.keymap.set('n', '<leader>d<C-l>', function() require('dap').repl.clear_screen() end)
vim.keymap.set('n', '<leader>d<C-w>', function() require('dap').repl.kill_word_backward() end)
vim.keymap.set('n', '<leader>d<C-f>', function() require('dap').repl.kill_word_forward() end)
vim.keymap.set('n', '<leader>d<C-t>', function() require('dap').repl.transpose_chars() end)
vim.keymap.set('n', '<leader>d<C-p>', function() require('dap').repl.transpose_words() end)
vim.keymap.set('n', '<leader>d<C-n>', function() require('dap').repl.yank() end)
vim.keymap.set('n', '<leader>d<C-v>', function() require('dap').repl.paste() end)
vim.keymap.set('n', '<leader>d<C-x><C-e>', function() require('dap').repl.edit_insert_mode() end)
vim.keymap.set('n', '<leader>d<C-x><C-f>', function() require('dap').repl.find_file() end)
vim.keymap.set('n', '<leader>d<C-x><C-p>', function() require('dap').repl.previous_history() end)
vim.keymap.set('n', '<leader>d<C-n>', function() require('dap').repl.next_history() end)
vim.keymap.set('n', '<leader>d<C-b>', function() require('dap').repl.backward_char() end)
vim.keymap.set('n', '<leader>d<C-f>', function() require('dap').repl.forward_char() end)
vim.keymap.set('n', '<leader>d<C-a>', function() require('dap').repl.beginning_of_line() end)
vim.keymap.set('n', '<leader>d<C-e>', function() require('dap').repl.end_of_line() end)
vim.keymap.set('n', '<leader>d<C-p>', function() require('dap').repl.up_line_or_history() end)
vim.keymap.set('n', '<leader>d<C-n>', function() require('dap').repl.down_line_or_history() end)
vim.keymap.set('n', '<leader>d<C-k>', function() require('dap').repl.kill_line() end)
vim.keymap.set('n', '<leader>d<C-y>', function() require('dap').repl.yank_from_kill_ring() end)
vim.keymap.set('n', '<leader>d<C-i>', function() require('dap').repl.insert_mode() end)
vim.keymap.set('n', '<leader>d<C-r>', function() require('dap').repl.reverse_search_history() end)
vim.keymap.set('n', '<leader>d<C-s>', function() require('dap').repl.forward_search_history() end)
vim.keymap.set('n', '<leader>d<C-l>', function() require('dap').repl.clear_screen() end)
vim.keymap.set('n', '<leader>d<C-w>', function() require('dap').repl.kill_word_backward() end)
vim.keymap.set('n', '<leader>d<C-f>', function() require('dap').repl.kill_word_forward() end)
vim.keymap.set('n', '<leader>d<C-t>', function() require('dap').repl.transpose_chars() end)
vim.keymap.set('n', '<leader>d<C-p>', function() require('dap').repl.transpose_words() end)
vim.keymap.set('n', '<leader>d<C-n>', function() require('dap').repl.yank() end)
vim.keymap.set('n', '<leader>d<C-v>', function() require('dap').repl.paste() end)
vim.keymap.set('n', '<leader>d<C-x><C-e>', function() require('dap').repl.edit_insert_mode() end)
vim.keymap.set('n', '<leader>d<C-x><C-f>', function() require('dap').repl.find_file() end)
vim.keymap.set('n', '<leader>d<C-x><C-p>', function() require('dap').repl.previous_history() end)
vim.keymap.set('n', '<leader>d<C-n>', function() require('dap').repl.next_history() end)
vim.keymap.set('n', '<leader>d<C-b>', function() require('dap').repl.backward_char() end)
vim.keymap.set('n', '<leader>d<C-f>', function() require('dap').repl.forward_char() end)
vim.keymap.set('n', '<leader>d<C-a>', function() require('dap').repl.beginning_of_line() end)
vim.keymap.set('n', '<leader>d<C-e>', function() require('dap').repl.end_of_line() end)
vim.keymap.set('n', '<leader>d<C-p>', function() require('dap').repl.up_line_or_history() end)
vim.keymap.set('n', '<leader>d<C-n>', function() require('dap').repl.down_line_or_history() end)
vim.keymap.set('n', '<leader>d<C-k>', function() require('dap').repl.kill_line() end)
vim.keymap.set('n', '<leader>d<C-y>', function() require('dap').repl.yank_from_kill_ring() end)
vim.keymap.set('n', '<leader>d<C-i>', function() require('dap').repl.insert_mode() end)
vim.keymap.set('n', '<leader>d<C-r>', function() require('dap').repl.reverse_search_history() end)
vim.keymap.set('n', '<leader>d<C-s>', function() require('dap').repl.forward_search_history() end)
vim.keymap.set('n', '<leader>d<C-l>', function() require('dap').repl.clear_screen() end)
vim.keymap.set('n', '<leader>d<C-w>', function() require('dap').repl.kill_word_backward() end)
vim.keymap.set('n', '<leader>d<C-f>', function() require('dap').repl.kill_word_forward() end)
vim.keymap.set('n', '<leader>d<C-t>', function() require('dap').repl.transpose_chars() end)
vim.keymap.set('n', '<leader>d<C-p>', function() require('dap').repl.transpose_words() end)
vim.keymap.set('n', '<leader>d<C-n>', function() require('dap').repl.yank() end)
vim.keymap.set('n', '<leader>d<C-v>', function() require('dap').repl.paste() end)
vim.keymap.set('n', '<leader>d<C-x><C-e>', function() require('dap').repl.edit_insert_mode() end)
vim.keymap.set('n', '<leader>d<C-x><C-f>', function() require('dap').repl.find_file() end)
vim.keymap.set('n', '<leader>d<C-x><C-p>', function() require('dap').repl.previous_history() end)
vim.keymap.set('n', '<leader>d<C-n>', function() require('dap').repl.next_history() end)
vim.keymap.set('n', '<leader>d<C-b>', function() require('dap').repl.backward_char() end)
vim.keymap.set('n', '<leader>d<C-f>', function() require('dap').repl.forward_char() end)
vim.keymap.set('n', '<leader>d<C-a>', function() require('dap').repl.beginning_of_line() end)
vim.keymap.set('n', '<leader>d<C-e>', function() require('dap').repl.end_of_line() end)
vim.keymap.set('n', '<leader>d<C-p>', function() require('dap').repl.up_line_or_history() end)
vim.keymap.set('n', '<leader>d<C-n>', function() require('dap').repl.down_line_or_history() end)
vim.keymap.set('n', '<leader>d<C-k>', function() require('dap').repl.kill_line() end)
vim.keymap.set('n', '<leader>d<C-y>', function() require('dap').repl.yank_from_kill_ring() end)
vim.keymap.set('n', '<leader>d<C-i>', function() require('dap').repl.insert_mode() end)
vim.keymap.set('n', '<leader>d<C-r>', function() require('dap').repl.reverse_search_history() end)
vim.keymap.set('n', '<leader>d<C-s>', function() require('dap').repl.forward_search_history() end)
vim.keymap.set('n', '<leader>d<C-l>', function() require('dap').repl.clear_screen() end)
vim.keymap.set('n', '<leader>d<C-w>', function() require('dap').repl.kill_word_backward() end)
vim.keymap.set('n', '<leader>d<C-f>', function() require('dap').repl.kill_word_forward() end)
vim.keymap.set('n', '<leader>d<C-t>', function() require('dap').repl.transpose_chars() end)
vim.keymap.set('n', '<leader>d<C-p>', function() require('dap').repl.transpose_words() end)
vim.keymap.set('n', '<leader>d<C-n>', function() require('dap').repl.yank() end)
vim.keymap.set('n', '<leader>d<C-v>', function() require('dap').repl.paste() end)
vim.keymap.set('n', '<leader>d<C-x><C-e>', function() require('dap').repl.edit_insert_mode() end)
vim.keymap.set('n', '<leader>d<C-x><C-f>', function() require('dap').repl.find_file() end)
vim.keymap.set('n', '<leader>d<C-x><C-p>', function() require('dap').repl.previous_history() end)
vim.keymap.set('n', '<leader>d<C-n>', function() require('dap').repl.next_history() end)
vim.keymap.set('n', '<leader>d<C-b>', function() require('dap').repl.backward_char() end)
vim.keymap.set('n', '<leader>d<C-f>', function() require('dap').repl.forward_char() end)
vim.keymap.set('n', '<leader>d<C-a>', function() require('dap').repl.beginning_of_line() end)
vim.keymap.set('n', '<leader>d<C-e>', function() require('dap').repl.end_of_line() end)
vim.keymap.set('n', '<leader>d<C-p>', function() require('dap').repl.up_line_or_history() end)
vim.keymap.set('n', '<leader>d<C-n>', function() require('dap').repl.down_line_or_history() end)
vim.keymap.set('n', '<leader>d<C-k>', function() require('dap').repl.kill_line() end)
vim.keymap.set('n', '<leader>d<C-y>', function() require('dap').repl.yank_from_kill_ring() end)
vim.keymap.set('n', '<leader>d<C-i>', function() require('dap').repl.insert_mode() end)
vim.keymap.set('n', '<leader>d<C-r>', function() require('dap').repl.reverse_search_history() end)
vim.keymap.set('n', '<leader>d<C-s>', function() require('dap').repl.forward_search_history() end)
vim.keymap.set('n', '<leader>d<C-l>', function() require('dap').repl.clear_screen() end)
vim.keymap.set('n', '<leader>d<C-w>', function() require('dap').repl.kill_word_backward() end)
vim.keymap.set('n', '<leader>d<C-f>', function() require('dap').repl.kill_word_forward() end)
vim.keymap.set('n', '<leader>d<C-t>', function() require('dap').repl.transpose_chars() end)
vim.keymap.set('n', '<leader>d<C-p>', function() require('dap').repl.transpose_words() end)
vim.keymap.set('n', '<leader>d<C-n>', function() require('dap').repl.yank() end)
vim.keymap.set('n', '<leader>d<C-v>', function() require('dap').repl.paste() end)
vim.keymap.set('n', '<leader>d<C-x><C-e>', function() require('dap').repl.edit_insert_mode() end)
vim.keymap.set('n', '<leader>d<C-x><C-f>', function() require('dap').repl.find_file() end)
vim.keymap.set('n', '<leader>d<C-x><C-p>', function() require('dap').repl.previous_history() end)
vim.keymap.set('n', '<leader>d<C-n>', function() require('dap').repl.next_history() end)
vim.keymap.set('n', '<leader>d<C-b>', function() require('dap').repl.backward_char() end)
vim.keymap.set('n', '<leader>d<C-f>', function() require('dap').repl.forward_char() end)
vim.keymap.set('n', '<leader>d<C-a>', function() require('dap').repl.beginning_of_line() end)
vim.keymap.set('n', '<leader>d<C-e>', function() require('dap').repl.end_of_line() end)
vim.keymap.set('n', '<leader>d<C-p>', function() require('dap').repl.up_line_or_history() end)
vim.keymap.set('n', '<leader>d<C-n>', function() require('dap').repl.down_line_or_history() end)
vim.keymap.set('n', '<leader>d<C-k>', function() require('dap').repl.kill_line() end)
vim.keymap.set('n', '<leader>d<C-y>', function() require('dap').repl.yank_from_kill_ring() end)
vim.keymap.set('n', '<leader>d<C-i>', function() require('dap').repl.insert_mode() end)
vim.keymap.set('n', '<leader>d<C-r>', function() require('dap').repl.reverse_search_history() end)
vim.keymap.set('n', '<leader>d<C-s>', function() require('dap').repl.forward_search_history() end)
vim.keymap.set('n', '<leader>d<C-l>', function() require('dap').repl.clear_screen() end)
vim.keymap.set('n', '<leader>d<C-w>', function() require('dap').repl.kill_word_backward() end)
vim.keymap.set('n', '<leader>d<C-f>', function() require('dap').repl.kill_word_forward() end)
vim.keymap.set('n', '<leader>d<C-t>', function() require('dap').repl.transpose_chars() end)
vim.keymap.set('n', '<leader>d<C-p>', function() require('dap').repl.transpose_words() end)
vim.keymap.set('n', '<leader>d<C-n>', function() require('dap').repl.yank() end)
vim.keymap.set('n', '<leader>d<C-v>', function() require('dap').repl.paste() end)
vim.keymap.set('n', '<leader>d<C-x><C-e>', function() require('dap').repl.edit_insert_mode() end)
vim.keymap.set('n', '<leader>d<C-x><C-f>', function() require('dap').repl.find_file() end)
vim.keymap.set('n', '<leader>d<C-x><C-p>', function() require('dap').repl.previous_history() end)
vim.keymap.set('n', '<leader>d<C-n>', function() require('dap').repl.next_history() end)
vim.keymap.set('n', '<leader>d<C-b>', function() require('dap').repl.backward_char() end)
vim.keymap.set('n', '<leader>d<C-f>', function() require('dap').repl.forward_char() end)
vim.keymap.set('n', '<leader>d<C-a>', function() require('dap').repl.beginning_of_line() end)
vim.keymap.set('n', '<leader>d<C-e>', function() require('dap').repl.end_of_line() end)
vim.keymap.set('n', '<leader>d<C-p>', function() require('dap').repl.up_line_or_history() end)
vim.keymap.set('n', '<leader>d<C-n>', function() require('dap').repl.down_line_or_history() end)
vim.keymap.set('n', '<leader>d<C-k>', function() require('dap').repl.kill_line() end)
vim.keymap.set('n', '<leader>d<C-y>', function() require('dap').repl.yank_from_kill_ring() end)
vim.keymap.set('n', '<leader>d<C-i>', function() require('dap').repl.insert_mode() end)
vim.keymap.set('n', '<leader>d<C-r>', function() require('dap').repl.reverse_search_history() end)
vim.keymap.set('n', '<leader>d<C-s>', function() require('dap').repl.forward_search_history() end)
vim.keymap.set('n', '<leader>d<C-l>', function() require('dap').repl.clear_screen() end)
vim.keymap.set('n', '<leader>d<C-w>', function() require('dap').repl.kill_word_backward() end)
vim.keymap.set('n', '<leader>d<C-f>', function() require('dap').repl.kill_word_forward() end)
vim.keymap.set('n', '<leader>d<C-t>', function() require('dap').repl.transpose_chars() end)
vim.keymap.set('n', '<leader>d<C-p>', function() require('dap').repl.transpose_words() end)
vim.keymap.set('n', '<leader>d<C-n>', function() require('dap').repl.yank() end)
vim.keymap.set('n', '<leader>d<C-v>', function() require('dap').repl.paste() end)
vim.keymap.set('n', '<leader>d<C-x><C-e>', function() require('dap').repl.edit_insert_mode() end)
vim.keymap.set('n', '<leader>d<C-x><C-f>', function() require('dap').repl.find_file()