A batteries-included Neovim configuration for Rust development.
Built on NvChad Β· rustaceanvim Β· blink.cmp Β· LuaSnip Β· nvim-dap
- β¨ Features
- πΈ Preview
- π Prerequisites
- π Installation
- π Uninstallation
- β‘ Quick Start
- π¬ Practical Examples
- β¨ Full Keymap Reference
- π Snippet Catalog
- π Directory Structure
- π§ Customization
- β FAQ
- π Credits
| Feature | Description | |
|---|---|---|
| π― | Zero-config | Clone and launch β Mason auto-installs rust-analyzer, codelldb, and formatters |
| π§ | Smart completion | blink.cmp + LuaSnip β Tab to navigate list, Tab to jump snippet placeholders, LSP/snippet dedup |
| π¦ | Full LSP | rustaceanvim: memory layout hover, clippy diagnostics, code lens, macro expand, joinLines |
| π¨ | Save-to-rerun | <leader>rr starts cargo run; saving .rs auto-restarts the process |
| π | Debugging | codelldb integration, cross-platform (macOS / Linux / Windows / WSL) |
| π§ͺ | Test integration | neotest + rustaceanvim adapter β single-key run / debug nearest test |
| π¦ | Dependency management | crates.nvim: upgrade / downgrade / view features in Cargo.toml |
| π | 269 Rust snippets | Stdlib macros, fn defs, control flow, iterator chains, design patterns, unsafe/FFI, tokio async, serde, trait impls, error types, closures, generics, memory ops |
| π | Global search | Telescope + ripgrep + LSP symbols / references / call hierarchy |
| π | Diagnostics panel | trouble.nvim for workspace diagnostics, references, call chain |
| π³ | Treesitter | Code object select / jump / swap (Rust, TOML, HTML, CSS, JS/TS, TSX) |
| π | Frontend support | HTML, CSS, JavaScript, TypeScript, Tailwind CSS β LSP + Prettier formatting |
| π | Beautiful UI | NvChad theming, cursor line bar, inlay hints, semantic highlighting |
Snippet expansion & Tab navigation
| Dependency | Min Version | macOS | Ubuntu / Debian | Fedora | Arch |
|---|---|---|---|---|---|
| Neovim | 0.10+ | brew install neovim |
Guide | dnf install neovim |
pacman -S neovim |
| Rust toolchain | stable | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh |
same | same | same |
| ripgrep | any | brew install ripgrep |
apt install ripgrep |
dnf install ripgrep |
pacman -S ripgrep |
| git | 2.20+ | brew install git |
apt install git |
dnf install git |
pacman -S git |
| Nerd Font | any | brew install --cask font-jetbrains-mono-nerd-font |
Download | same | same |
β You must install a Nerd Font and set it as your terminal font, otherwise icons will show as boxes.
π¦ Quick install all dependencies (click to expand)
macOS:
brew install neovim ripgrep git fd node
brew install --cask font-jetbrains-mono-nerd-font
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shUbuntu / Debian:
sudo apt update
sudo apt install -y ripgrep git fd-find nodejs
# Neovim 0.10+ may need PPA or AppImage:
curl -LO https://github.com/neovim/neovim/releases/latest/download/nvim-linux-x86_64.appimage
chmod u+x nvim-linux-x86_64.appimage
sudo mv nvim-linux-x86_64.appimage /usr/local/bin/nvim
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shFedora:
sudo dnf install -y neovim ripgrep git fd-find nodejs
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shArch:
sudo pacman -S --needed neovim ripgrep git fd nodejs rustup
rustup default stable| Dependency | Purpose | Install |
|---|---|---|
| fd | Faster Telescope file search | brew install fd / apt install fd-find |
| Node.js 18+ | Some Mason packages depend on it | brew install node / apt install nodejs |
Installed by mason-tool-installer 3 seconds after first launch:
| Tool | Purpose |
|---|---|
rust-analyzer |
Rust language server (LSP) |
codelldb |
Rust debugger (DAP) |
stylua |
Lua formatter |
taplo |
TOML formatter |
biome |
JSON formatter |
prettier |
HTML / CSS / JS / TS formatter |
typescript-language-server |
JavaScript & TypeScript LSP |
tailwindcss-language-server |
Tailwind CSS LSP |
curl -fsSL https://raw.githubusercontent.com/lisering/rusty-nvim/main/install.sh | bashgit clone https://github.com/lisering/rusty-nvim.git
cd rusty-nvim && bash install.sh# Backup existing config
mv ~/.config/nvim ~/.config/nvim.bak 2>/dev/null || true
# Clone and copy only the nvim/ config folder
git clone https://github.com/lisering/rusty-nvim.git /tmp/rusty-nvim
cp -r /tmp/rusty-nvim/nvim/. ~/.config/nvim/
rm -rf /tmp/rusty-nvim
# Launch β plugins auto-install on first run
nvimπ₯ Windows / WSL instructions
WSL (recommended for Windows users):
wsl --install
# Inside WSL:
sudo apt update && sudo apt install -y ripgrep git fd-find
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Install Neovim 0.10+ via AppImage (see Prerequisites)
curl -fsSL https://raw.githubusercontent.com/lisering/rusty-nvim/main/install.sh | bash
nvimNative Windows (experimental β paths use %LOCALAPPDATA%\nvim):
git clone https://github.com/lisering/rusty-nvim.git $env:TEMP\rusty-nvim
New-Item -ItemType Directory -Force $env:LOCALAPPDATA\nvim
copy-item -Path $env:TEMP\rusty-nvim\nvim\* -Destination $env:LOCALAPPDATA\nvim -Recurse
nvimβ Native Windows is not fully tested. WSL is recommended.
Launch nvim
ββ nvdash dashboard shows RUSTY ASCII art header
ββ lazy.nvim auto-clones all plugins (~30s)
ββ Treesitter auto-installs parsers:
β ββ rust, toml, lua
β ββ html, css, javascript, typescript, tsx
ββ 3s later, mason-tool-installer installs:
ββ rust-analyzer, codelldb
ββ stylua, taplo, biome
ββ prettier (HTML/CSS/JS/TS formatter)
ββ typescript-language-server
ββ tailwindcss-language-server
ββ β
Done! Open a .rs or .tsx file and start coding
π‘ Plugin issues after install? If any plugin failed to install or behaves unexpectedly, run these inside Neovim:
:Lazy syncβ re-install missing plugins and clean up stale ones:Lazy updateβ update all plugins to latest version:Lazyβ open the plugin manager UI to inspect status:Masonβ check LSP / DAP / formatter installation status
curl -fsSL https://raw.githubusercontent.com/lisering/rusty-nvim/main/uninstall.sh | bashcd ~/.config/nvim && bash uninstall.shTo skip the confirmation prompt:
bash uninstall.sh --forcerm -rf ~/.config/nvim{,.bak}
rm -rf ~/.local/share/nvim{,.bak}
rm -rf ~/.local/state/nvim{,.bak}
rm -rf ~/.cache/nvim{,.bak}This removes the config, plugins, cache, state, and all backups. Neovim itself is not uninstalled.
After installation, verify everything works in 60 seconds:
# 1. Create a Rust project
cargo new hello_rusty && cd hello_rusty
# 2. Open in Neovim
nvim src/main.rs
# 3. Wait ~10s for rust-analyzer to index (watch the statusline)
# 4. Try these keys:
# K β hover (type info + memory layout)
# <Space>rr β cargo run (bottom terminal opens)
# <Space>ca β code action menu
# <Space>ff β find files
# <Space>fw β live grep
# <Space>e β toggle file tree
<leader>= Space
cargo new hello_world
cd hello_world
nvim src/main.rs// In nvim, editing src/main.rs
// 1. Type "println" β completion menu appears β Enter to accept
// Expands to: println!("");
// ^ cursor here, type format string
// 2. Type "hello world"
println!("hello world");
// 3. Press jk to return to Normal mode
// 4. Press <Space>rr β bottom terminal opens with cargo run
// Output: hello world
// 5. Modify code β <C-s> to save β terminal auto Ctrl+C and re-runs cargo run// 1. Type "testmod" β Enter β expands to full test module:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
todo!()
}
}
// 2. Tab β cursor on "it_works" β rename to "test_add"
// 3. Tab β cursor on "todo!()" β write test logic
// 4. Type "assert_eq" β Enter β expands to:
// assert_eq!(left, right);
// 5. Tab β cursor on "left" β type 1 + 1
// 6. Tab β cursor on "right" β type 2
// Final result:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(1 + 1, 2);
}
}
// 7. <Space>tt β run nearest test β neotest shows βfn factorial(n: u32) -> u32 {
if n <= 1 {
1
} else {
n * factorial(n - 1)
}
}
fn main() {
let result = factorial(5);
println!("5! = {}", result);
}1. Move cursor to "n * factorial(n - 1)" line
2. <Space>db β breakpoint appears (red dot)
3. <Space>dc β start debugging β program stops at breakpoint
4. DAP UI auto-opens: variables panel (left), call stack (bottom)
5. <Space>dj β step over β variables update
6. <Space>dl β step into factorial function
7. <Space>dk β step out
8. <Space>de β terminate debug session
let numbers = vec![1, 2, 3];
let sum: i32 = numbers.sum(); // β rust-analyzer marks yellow1. ]t β jump to next diagnostic
2. K β hover popup β shows error message and fix suggestions
3. <Space>ca β Code Action menu β select a fix
Advanced:
4. <Space>cd β copy diagnostic message to clipboard
5. <Space>xx β open diagnostics panel β see all project issues
6. ]t / [t β navigate through diagnostics panel
1. <Space>gt β open Git status (Telescope) β see changed files
2. Select file β Enter β jump to file
3. ]h β jump to next modified hunk
4. <Space>hp β preview hunk β diff window pops up
5. <Space>hs β stage that hunk
6. <Space>hr β reset that hunk
7. <Space>hb β view git blame for current line
8. <Space>cm β open Git commit history (Telescope)
# Cargo.toml
[dependencies]
serde = "1.0" # β cursor on this line
tokio = "1.0"1. Open Cargo.toml β crates.nvim auto-shows latest versions
2. Move cursor to serde line
3. <Space>Cu β upgrade serde to latest
4. <Space>CU β upgrade all dependencies
5. <Space>Cf β view serde's features list
6. <Space>Co β open docs.rs/serde in browser
7. <Space>Cr β open serde's GitHub repo
π View Memory Layout with Hover
struct User {
name: String,
age: u32,
emails: Vec<String>,
}1. Place cursor on "User"
2. K β hover popup appears
Shows: struct definition + field types
Bottom: memory layout (size/offset/alignment/padding/niches)
3. <C-f> β scroll documentation down
4. <C-b> β scroll up
5. jk β close hover
π§ Expand Macros
// println! is a macro β see what it expands to:
1. Place cursor on println!
2. <Space>re β macro expansion window appearsπ View Call Hierarchy
1. Place cursor on a function name
2. <Space>fI β who calls this function (incoming calls)
3. <Space>fO β what does this function call (outgoing calls)
4. Telescope popup β select entry β jump
π³ Select Functions with Treesitter
1. In Normal mode
2. vaf β visually select entire function (with signature and body)
3. vif β visually select function interior (without signature)
4. ]f β jump to next function
5. [f β jump to previous function
6. <Space>na β swap current parameter with next
<leader>= Space |<C-x>= Ctrl+x |<S-Tab>= Shift+Tab
| Key | Action |
|---|---|
jk |
Exit insert mode |
<C-s> |
Save (silent, no hit-enter prompt) |
; |
Enter command mode |
gd |
Go to definition |
K |
Hover β type / docs / memory layout |
<leader>ca |
Code Action |
<F2> |
Rename (live preview) |
<leader>rr |
cargo run (auto-rerun on save) |
<leader>rc |
cargo check |
<leader>rf |
fly check (clippy instant check) |
<leader>rt |
cargo test |
<leader>tt |
Run nearest test |
<leader>db |
Toggle breakpoint |
<leader>dc |
Start / continue debugging |
Tab |
Next completion / Snippet placeholder forward |
<leader>ff |
Find files |
<leader>fw |
Live grep |
<leader>e |
Toggle file tree |
<leader>/ |
Toggle comment |
<leader>fm |
Format file |
<leader>xx |
Diagnostics panel |
<leader>cd |
Copy diagnostics to clipboard |
<leader>ra |
Rename (live preview) |
]t / [t |
Next / prev diagnostic |
| Key | Action |
|---|---|
Tab |
Next completion / Snippet placeholder forward |
S-Tab |
Prev completion / Snippet placeholder backward |
<CR> |
Accept completion (or newline if menu hidden) |
<C-l> |
Force snippet forward (ignores menu visibility) |
<C-Space> |
Trigger completion + docs |
<C-e> |
Close completion menu |
<C-k> |
Signature help |
<C-b> / <C-f> |
Scroll docs up / down |
<C-u> / <C-d> |
Scroll signature up / down |
| Key | Action |
|---|---|
gd |
Go to definition |
gD |
Go to declaration |
<leader>D |
Go to type definition |
<leader>gr |
Find references |
<leader>gi |
Find implementations (trait impls) |
<leader>fs |
Document symbols |
<leader>fS |
Workspace symbols |
<leader>fr |
Telescope references |
<leader>fI |
Incoming calls (who calls this) |
<leader>fO |
Outgoing calls (what does this call) |
<leader>rp |
Go to parent module |
| Key | Action |
|---|---|
<leader>rr |
cargo run (reuses terminal, auto-rerun on save) |
<leader>rq |
Kill cargo terminal |
<leader>rc |
cargo check |
<leader>rf |
fly check (clippy) |
<leader>rt |
cargo test |
<leader>rl |
List runnables |
| Key | Action |
|---|---|
<leader>rh |
Hover actions (run / debug / goto) |
<leader>re |
Expand macro |
<leader>rd |
Open docs.rs |
<leader>rx |
Explain error |
<leader>rj |
Join lines smartly |
<leader>rp |
Go to parent module |
<leader>rC |
Open Cargo.toml |
<leader>rs |
Syntax tree |
<leader>rw |
Reload workspace |
<leader>rT |
Related tests |
<leader>rR |
Related diagnostics |
<leader>rD |
Render diagnostic |
<leader>rg |
Debuggables (DAP) |
<leader>rmu |
Move item up |
<leader>rmd |
Move item down |
<leader>ri |
Toggle inlay hints |
<leader>ra |
Rename (inc-rename preview) |
| Key | Action |
|---|---|
<leader>tt |
Run nearest test |
<leader>tf |
Run all tests in file |
<leader>td |
Debug nearest test |
<leader>ts |
Test summary panel |
<leader>to |
Test output |
]T / [T |
Next / prev failed test |
| Key | Action |
|---|---|
<leader>db |
Toggle breakpoint |
<leader>dd |
Conditional breakpoint |
<leader>dc |
Start / continue |
<leader>dl |
Step into |
<leader>dj |
Step over |
<leader>dk |
Step out |
<leader>de |
Terminate |
<leader>dr |
Run last |
<leader>dt |
List debuggable testables |
| Key | Action |
|---|---|
<leader>xx |
Workspace diagnostics panel |
<leader>xX |
Buffer diagnostics panel |
<leader>cd |
Copy diagnostics to clipboard |
]t / [t |
Next / prev diagnostic |
<leader>ca |
Code Action |
<F2> |
Rename (live preview) |
<leader>fm |
Format file |
<leader>xr |
References panel |
<leader>xi / <leader>xo |
Call hierarchy (in / out) |
<leader>xs |
Symbols panel |
<leader>xq |
Quickfix panel |
| Key | Action |
|---|---|
]h / [h |
Next / prev hunk |
<leader>hs |
Stage hunk |
<leader>hr |
Reset hunk |
<leader>hp |
Preview hunk |
<leader>hb |
Blame line |
<leader>hd |
Diff this file |
<leader>ht |
Toggle line blame |
<leader>gt |
Git status |
<leader>cm |
Git commit history |
<leader>gb |
Buffer commit history |
<leader>gB |
Branch switch |
| Key | Action |
|---|---|
<leader>e |
Toggle file tree |
<leader>ff |
Find files |
<leader>fa |
Find all files (incl. hidden) |
<leader>fw |
Live grep |
<leader>fb |
Find buffers |
<leader>fo |
Recent files |
<leader>fz |
Fuzzy search in buffer |
| Key | Action |
|---|---|
<C-h> / <C-l> |
Left / right window |
<C-j> / <C-k> |
Down / up window |
<C-w>s |
Horizontal split |
<C-w>v |
Vertical split |
<C-w>c |
Close window |
<C-w>o |
Close other windows |
Tab / S-Tab |
Next / prev buffer (Normal mode) |
<leader>x |
Close buffer |
<leader>b |
New buffer |
| Key | Action |
|---|---|
<A-i> |
Toggle float terminal |
<A-v> |
Toggle vertical terminal |
<A-h> |
Toggle horizontal terminal |
<leader>h |
New horizontal terminal |
<leader>v |
New vertical terminal |
<C-x> |
Terminal β Normal mode |
| Key | Action |
|---|---|
<leader>Cu |
Upgrade crate |
<leader>CU |
Upgrade all crates |
<leader>Cd |
Downgrade crate |
<leader>Cf |
Show crate features |
<leader>Co |
Open crate docs |
<leader>Cr |
Open crate repo |
<leader>Ca |
Refresh crate info |
π Full Treesitter keymaps (click to expand)
| Key | Object |
|---|---|
af / if |
Function (with / without signature) |
ac / ic |
Class |
aa / ia |
Parameter |
al / il |
Loop |
ab / ib |
Block |
aC / iC |
Comment |
am / im |
Call |
as |
Statement |
| Key | Target |
|---|---|
]f / [f |
Next / prev function |
]k / [k |
Next / prev class |
]a / [a |
Next / prev parameter |
]l / [l |
Next / prev loop |
]s / [s |
Next / prev statement |
]m / [m |
Next / prev call |
| Key | Action |
|---|---|
<leader>na |
Swap parameter (forward) |
<leader>nf |
Swap function (forward) |
<leader>nk |
Swap class (forward) |
<leader>Na |
Swap parameter (backward) |
<leader>Nf |
Swap function (backward) |
<leader>Nk |
Swap class (backward) |
| Key | Action |
|---|---|
sa{char} |
Add surround (e.g. sa" adds quotes) |
sd{char} |
Delete surround |
sr{old}{new} |
Replace surround |
sf{char} |
Find right surround |
sF{char} |
Find left surround |
sh{char} |
Highlight surround |
Full keymap cheat sheet: KEYMAPS.md
Type trigger β Enter to accept β Tab to jump placeholders β S-Tab to go back
Only Rust snippets are loaded. Other language snippets (friendly-snippets, VSCode, snipmate) are disabled.
| Trigger | Expands to |
|---|---|
println |
println!(""); (cursor in quotes) |
printlnf |
println!("", args); (two placeholders) |
eprintln |
eprintln!(""); |
dbg |
dbg!(); |
assert_eq |
assert_eq!(left, right); (Tab jumps leftβright) |
assert_ne |
assert_ne!(left, right); |
vec |
vec![]; |
format |
format!("") |
todo |
todo!() |
panic |
panic!(""); |
matches |
matches!(expr, pattern) |
cfg |
cfg!() |
env |
env!("") |
include_str |
include_str!("") |
| Trigger | Expands to |
|---|---|
derive |
#[derive()] |
derive_debug |
#[derive(Debug)] |
derive_clone |
#[derive(Clone)] |
derive_copy |
#[derive(Copy, Clone)] |
derive_default |
#[derive(Default)] |
derive_eq |
#[derive(PartialEq, Eq)] |
derive_serde |
#[derive(serde::Serialize, serde::Deserialize)] |
derive_all |
#[derive(Debug, Clone, PartialEq, Eq, Hash)] |
inline |
#[inline] |
must_use |
#[must_use] |
no_std |
#![no_std] |
| Trigger | Expands to |
|---|---|
fn |
fn name(args) -> Ret { todo!() } (4 placeholders) |
pfn |
pub fn name(args) -> Ret { todo!() } |
afn |
async fn name(args) -> Ret { todo!() } |
pafn |
pub async fn name(args) -> Ret { todo!() } |
main |
fn main() { } |
extern_fn |
extern "C" fn name(...) -> RetType { } |
unsafe_fn |
unsafe fn name(...) -> Ret { } |
resultfn |
fn name() -> Result<T, E> { } |
optionfn |
fn name() -> Option<T> { } |
| Trigger | Expands to |
|---|---|
struct |
#[derive(Debug)] struct Name { field: Type } |
struct_tuple |
struct Name(Type); |
struct_unit |
struct Name; |
enum |
#[derive(Debug)] enum Name { Variant1, Variant2 } |
impl |
impl Type { } |
trait |
trait Name { } |
traitimpl |
impl Trait for Type { } |
mod |
mod name { } |
const |
const NAME: Type = init; |
typealias |
type Alias = Type; |
error_enum |
#[derive(Debug, thiserror::Error)] enum Error { } |
| Trigger | Expands to |
|---|---|
if |
if condition { todo!() } |
iflet |
if let Some(x) = expr { todo!() } |
while |
while condition { todo!() } |
for |
for pat in expr { todo!() } |
loop |
loop { } |
match |
match expr { Pattern => todo!(), _ => todo!() } |
match_opt |
match expr { Some(x) => ..., None => ... } |
match_res |
match expr { Ok(val) => ..., Err(e) => ... } |
unsafe_block |
unsafe { } |
| Trigger | Expands to |
|---|---|
test |
#[test] fn name() { todo!() } |
testmod |
#[cfg(test)] mod tests { use super::*; #[test] fn it_works() { } } |
tokiotest |
#[tokio::test] async fn name() { } |
| Trigger | Expands to |
|---|---|
some / none |
Some() / None |
ok / err |
Ok() / Err() |
context |
.context("") |
with_context |
.with_context(|| "")? |
map_err |
.map_err(|e| todo!()) |
unwrap_or |
.unwrap_or(default) |
question |
? |
anyhow_result |
anyhow::Result<T> |
anyhow_bail |
anyhow::bail!("msg"); |
anyhow_ensure |
anyhow::ensure!(cond, "msg"); |
| Trigger | Expands to |
|---|---|
hashmap |
let mut map: HashMap<Key, Value> = HashMap::new(); |
btreemap |
let mut map: BTreeMap<Key, Value> = BTreeMap::new(); |
hashset |
let mut set: HashSet<T> = HashSet::new(); |
vecnew |
let v: Vec<T> = Vec::new(); |
entry |
.entry(key).or_insert(default) |
| Trigger | Expands to |
|---|---|
itermap |
.iter().map(|x| todo!()) |
iterfilter |
.iter().filter(|x| todo!()) |
iterfold |
.iter().fold(init, |acc, x| todo!()) |
itercollect |
.iter().collect::<Vec<_>>() |
iterenum |
.iter().enumerate() |
iterzip |
.iter().zip(other) |
iterany |
.iter().any(|x| todo!()) |
iterall |
.iter().all(|x| todo!()) |
itersum |
.iter().sum::<T>() |
itermax |
.iter().max() |
| Trigger | Expands to |
|---|---|
arc |
Arc::new(value) |
arcmutex |
Arc::new(Mutex::new(value)) |
channel |
let (tx, rx) = mpsc::channel(); |
send |
tx.send(value).unwrap(); |
atomic |
AtomicUsize::new(0) |
thread_spawn |
std::thread::spawn(move || { }); |
| Trigger | Expands to |
|---|---|
builder |
Full Builder pattern (struct + impl + new + setter + build) |
newtype |
Newtype pattern (struct + new + inner) |
display |
impl Display for Type { ... } |
defaultimpl |
impl Default for Type { ... } |
fromimpl |
impl From<T> for Dest { ... } |
| Trigger | Expands to |
|---|---|
lifefn |
fn name<'a>(x: &'a T) -> &'a U { } |
genfn |
fn name<T>(x: T) -> Ret { } |
genstruct |
struct Name<T> { field: T } |
genimpl |
impl<T> Name<T> { } |
where |
where T: Trait |
const_generic |
struct Name<const N: usize> { } |
assoc_type |
type Item = T; |
| Trigger | Expands to |
|---|---|
unsafe_fn |
unsafe fn name(...) -> Ret { } |
unsafe_block |
unsafe { } |
unsafe_impl |
unsafe impl Trait for Type { } |
static_mut |
static mut NAME: Type = init; |
| Trigger | Expands to |
|---|---|
tokio_main |
#[tokio::main] async fn main() |
tokio_select |
tokio::select! { ... } |
tokio_join |
tokio::join!(a, b) |
tokio_try_join |
tokio::try_join!(a, b) |
pin |
Pin<Box<T>> |
pin_box |
Box::pin(async { }) |
tokio_sleep |
tokio::time::sleep(Duration).await |
tokio_interval |
tokio::time::interval(Duration) |
| Trigger | Expands to |
|---|---|
serde_rename |
#[serde(rename = "")] |
serde_rename_all |
#[serde(rename_all = "")] |
serde_skip |
#[serde(skip)] |
serde_default |
#[serde(default)] |
serde_flatten |
#[serde(flatten)] |
serde_with |
#[serde(with = "")] |
serde_skip_if |
#[serde(skip_serializing_if = "")] |
serde_tag |
#[serde(tag = "")] |
| Trigger | Expands to |
|---|---|
refcell |
RefCell::new(value) |
cell |
Cell::new(value) |
rc |
Rc::new(value) |
phantom |
PhantomData::<T> |
once_cell |
static VAR: OnceLock<T> = OnceLock::new(); |
lazy_lock |
static VAR: LazyLock<T> = LazyLock::new(|| init); |
| Trigger | Expands to |
|---|---|
iterator_impl |
impl Iterator for Type { type Item; fn next } |
index_impl |
impl Index<usize> for Type { } |
deref_impl |
impl Deref for Type { } |
drop_impl |
impl Drop for Type { } |
fromstr_impl |
impl FromStr for Type { } |
clone_impl |
impl Clone for Type { } |
partial_eq_impl |
impl PartialEq for Type { } |
| Trigger | Expands to |
|---|---|
use_std |
use std::...; |
use_crate |
use crate::...; |
use_super |
use super::...; |
use_self |
use self::...; |
use_prelude |
use crate::prelude::*; |
π More snippets (click to expand)
| Trigger | Expands to |
|---|---|
let_mut |
let mut x = init; |
let_ref |
let x = &init; |
let_mut_ref |
let x = &mut init; |
destruct_tuple |
let (a, b) = tuple; |
destruct_struct |
let Foo { x, y } = foo; |
return_ok |
return Ok(value); |
return_err |
return Err(...); |
return_some / return_none |
return Some(...) / return None; |
as_int |
as i32 |
try_into |
.try_into().unwrap() |
into / from |
.into() / From::from(value) |
transmute |
std::mem::transmute(value) |
mem_swap |
std::mem::swap(&mut a, &mut b); |
mem_take |
std::mem::take(&mut value) |
size_of / align_of |
std::mem::size_of::<T>() etc. |
closure |
|args| expr |
closure_move |
move |args| expr |
range |
start..end |
range_inclusive |
start..=end |
cfg_test |
#[cfg(test)] |
cfg_feature |
#[cfg(feature = "")] |
cold |
#[cold] |
track_caller |
#[track_caller] |
doc |
/// (line doc comment) |
docmod |
//! (module doc comment) |
See KEYMAPS.md for the complete list of all 269 snippets.
~/.config/nvim/ # Installed config (copied from repo's nvim/ folder)
βββ init.lua # Entry: bootstrap lazy.nvim + load modules
βββ .stylua.toml # Lua formatting config (for stylua)
βββ lua/
β βββ autocmds.lua # Autocmds: save-rerun / inlay hints / cursor bar
β βββ chadrc.lua # NvChad theme / UI / nvdash dashboard config
β βββ configs/
β β βββ conform.lua # Formatting: rustfmt / stylua / taplo / biome / prettier
β β βββ lazy.lua # lazy.nvim config
β β βββ lspconfig.lua # LSP: html / cssls / ts_ls / tailwindcss
β βββ mappings.lua # All custom keymaps
β βββ options.lua # Neovim options
β βββ plugins/
β βββ init.lua # All plugin configs
βββ luasnippets/
β βββ rust.lua # Rust custom snippets (269, Rust-only)
βββ lazy-lock.json # Plugin version lockfile
Repo structure (what you clone from GitHub):
rusty-nvim/
βββ nvim/ # β Pure Neovim config (copied to ~/.config/nvim/)
β βββ init.lua
β βββ .stylua.toml
β βββ lazy-lock.json
β βββ lua/ # ... (same as installed layout above)
β βββ luasnippets/
βββ install.sh # One-click installer
βββ uninstall.sh # One-click uninstaller
βββ gifs/ # Demo GIFs for README
βββ KEYMAPS.md / KEYMAPS_zh.md # Keymap cheat sheets
βββ README.md / README_zh.md # Documentation
βββ LICENSE
This is the NvChad convention. init.lua sets vim.g.lua_snippets_path to point here. LuaSnip's from_lua loader expects a standalone directory of .lua files (each returns a table of snippets for one filetype), not a Lua module path under lua/.
Edit lua/chadrc.lua:
M.base46 = {
theme = "onedark", -- "catppuccin", "tokyonight", "gruvbox", etc.
}Edit the M.nvdash.header table in lua/chadrc.lua:
M.nvdash = {
load_on_startup = true,
header = {
" your ASCII art here ",
},
buttons = {
{ txt = "βΈ Find File", keys = "ff", cmd = "Telescope find_files" },
-- add or remove buttons
{ txt = "βΈ Quit", keys = "q", cmd = "qa" },
},
}Create a new file in luasnippets/, e.g. luasnippets/python.lua:
local ls = require("luasnip")
local parse = ls.parser.parse_snippet
return {
parse({ trig = "ifmain" }, 'if __name__ == "__main__":\n $0'),
}Edit the default_settings section in lua/plugins/init.lua under the rustaceanvim plugin spec.
Edit the ensure_installed list in the mason-tool-installer section of lua/plugins/init.lua.
No completion after opening a .rs file?
rust-analyzer is indexing the project. Check the statusline for progress. Large projects may take 10-30 seconds.
Icons show as boxes/question marks?
No Nerd Font installed. Run brew install --cask font-jetbrains-mono-nerd-font and set it as your terminal font.
<leader>rr does nothing?
You need to open a file inside a Rust project (containing Cargo.toml). The script searches upward for the package directory.
Debugger errors?
codelldb may still be installing. Run :Mason to check, or :MasonInstall codelldb manually.
Tab sometimes navigates the list, sometimes jumps snippets β how to tell?
When the menu is visible, Tab navigates the list; when the menu is not visible and you're in a snippet, Tab jumps placeholders. If the menu blocks snippet jumping, use <C-l> to force-jump.
How to update all plugins?
Run :Lazy sync β this updates all plugins, installs any missing ones, and cleans up stale plugins.
If you only want to update plugin versions without installing/removing: :Lazy update.
How to update rust-analyzer and other tools?
Run :MasonUpdate or :Mason then press U.
After :w there's a "3L, 46B written" prompt?
No. The config uses cnoreabbrev to turn :w into silent! w, eliminating the hit-enter prompt.
Does saving .rs auto-rerun cargo?
Only after you press <leader>rr first. Press <leader>rq to stop auto-rerun.
- NvChad β UI framework
- rustaceanvim β Rust LSP integration
- blink.cmp β Completion engine
- LuaSnip β Snippet engine
- nvim-dap β Debug adapter protocol
- Telescope β Fuzzy finder
- trouble.nvim β Diagnostics panel
- crates.nvim β Dependency management
- neotest β Test runner framework
- which-key.nvim β Keymap discovery
- mini.surround β Surround operations
If this config helps you, please β Star the repo!

