One of my favorite things about Rust is the stellar tooling, and it’s led to a Vim setup I’m pretty happy with. A lot of this is similar to my setup for Scala the notable additions are Neomake and Racer.
My flavor of Vim is Neovim and my full init.vim + dotfiles are over on Github. For working in Rust in Vim, I use:
1. Syntax
rust-lang/rust.vim I’m just using the syntax support, but it also has Syntastic and rustfmt support if that’s your thing.
2. Completion
If there’s one thing to have, it’s Racer. Racer provides context sensitive Rust code completion (for your code, standard library and dependencies). I pair this with deoplete out of personal preference.
From what I can tell, deoplete alone completes previously used words. Racer adds completions based on context, available definitions from imports, and dependencies:
3. Jump to File
FZF works really well and really fast. I’ll still fall back onto CtrlP when I don’t have the FZF binary installed.
4. Jump to Definition
Racer also provides code navigation via jump to definition and opening docs.
Honestly, even though Racer is superior, I still end up using FZF + ctags because I do the same
thing for Scala. If you haven’t heard of ctags, it’s
essentially doing a one time regex search for definitions (e.g. functions, traits) to create an
index that you can efficiently search through later (e.g. here with FZF). I’ve heard of some ctag
plugins for rust like rusty-tags, but I just end up using
these rules in my ~/.ctags
:
--langdef=Rust
--langmap=Rust:.rs
--regex-Rust=/^[ \t]*(#\[[^\]]\][ \t]*)*(pub[ \t]+)?(extern[ \t]+)?("[^"]+"[ \t]+)?(unsafe[ \t]+)?fn[ \t]+([a-zA-Z0-9_]+)/\6/f,functions,function definitions/
--regex-Rust=/^[ \t]*(pub[ \t]+)?type[ \t]+([a-zA-Z0-9_]+)/\2/T,types,type definitions/
--regex-Rust=/^[ \t]*(pub[ \t]+)?enum[ \t]+([a-zA-Z0-9_]+)/\2/g,enum,enumeration names/
--regex-Rust=/^[ \t]*(pub[ \t]+)?struct[ \t]+([a-zA-Z0-9_]+)/\2/s,structure names/
--regex-Rust=/^[ \t]*(pub[ \t]+)?mod[ \t]+([a-zA-Z0-9_]+)/\2/m,modules,module names/
--regex-Rust=/^[ \t]*(pub[ \t]+)?(static|const)[ \t]+(mut[ \t]+)?([a-zA-Z0-9_]+)/\4/c,consts,static constants/
--regex-Rust=/^[ \t]*(pub[ \t]+)?(unsafe[ \t]+)?trait[ \t]+([a-zA-Z0-9_]+)/\3/t,traits,traits/
--regex-Rust=/^[ \t]*(pub[ \t]+)?(unsafe[ \t]+)?impl([ \t\n]*<[^>]*>)?[ \t]+(([a-zA-Z0-9_:]+)[ \t]*(<[^>]*>)?[ \t]+(for)[ \t]+)?([a-zA-Z0-9_]+)/\5 \7 \8/i,impls,trait implementations/
--regex-Rust=/^[ \t]*macro_rules![ \t]+([a-zA-Z0-9_]+)/\1/d,macros,macro definitions/
5. Compile on save + Jump to Error
For Rust, I’ve been using Neomake which I have compile on
every save. Errors and warnings populate the location list, which you can use to jump to error, and
a sidebar for visual feedback. I also find
vim-togglelist a nice addition for toggling the
location list with <leader>l
.
However, it wouldn’t be Vim without having some bizarre edge case. When exitting with :wq
Neomake
kicks off a Cargo check process that holds the lock and never exits, and I would have to manually
kill it to be able to compile again. This led me to this fun snippet:
" Neomake
" Gross hack to stop Neomake running when exitting because it creates a zombie cargo check process
" which holds the lock and never exits. But then, if you only have QuitPre, closing one pane will
" disable neomake, so BufEnter reenables when you enter another buffer.
let s:quitting = 0
au QuitPre *.rs let s:quitting = 1
au BufEnter *.rs let s:quitting = 0
au BufWritePost *.rs if ! s:quitting | Neomake | else | echom "Neomake disabled"| endif
let g:neomake_warning_sign = {'text': '?'}
Other
Debugging + Types
Most of the time, I’m getting by with println!
for debugging. I rarely need type inspection in
Rust, but when I do, I do my typical hack of putting in a bogus type like int and seeing what
the compilers gives as an expected and actual type.
Cargo Watch
I’m always working in a tmux session, so I use cargo-watch
in separate window (e.g. cargo watch -x check
). For check
this is redundant with Neomake, but
you still may want to scroll through errors or use another command like cargo watch -x test