slop-stuff / Editors
Neovim
Edit at the speed of thought.
Modes, motions, operators, text objects, config, and LSP.
Neovim is a modal editor: every keypress is a command, not a character. Learn the modes and motions once, and your hands never leave the home row again.
The everyday keys, at a glance
Nine blocks cover the daily surface — modes, movement, operators, text objects, search, replace, splits, config, and LSP. Skim it once, then dive into the sections below for depth.
Modes
Esc " back to Normal (always)
i a o " insert before / after / new line
v V Ctrl-v " visual: char / line / block
: " command-line mode
Move
h j k l " left / down / up / right
w b e " word: next / back / end
0 $ ^ " line start / end / first char
gg G 12G " top / bottom / line 12
Operators
d c y " delete / change / yank
x p P " char / put after / before
u Ctrl-r " undo / redo
. " repeat last change
Text objects
ciw ci" " change word / string
di( di{ " delete inside ( / {
yap yit " yank paragraph / tag
cit " change tag content
Search
/pattern " search forward
?pattern " search backward
n N " next / previous match
* # " word under cursor fwd/back
:noh " clear highlight
Replace
:s/old/new/ " current line, first
:%s/old/new/g " whole file
:%s/old/new/gc " whole file, confirm
& " repeat last :s
Splits
:sp :vsp " split horizontal / vertical
Ctrl-w h j k l " move focus
Ctrl-w q o " close / only window
Ctrl-w = " equalize sizes
init.lua
~/.config/nvim/init.lua " entry point
vim.opt.number = true " options
vim.keymap.set("n", ...) " keymaps
require("lazy").setup("plugins")
LSP
gd gr " definition / references
K " hover docs
<leader>rn " rename symbol
:LspInstall srv " install a server
:LspInfo " what's attached
KEY: The grammar of every command:
count+operator+motion.d3wdeletes three words,ci"changes inside the quotes — everything else is a refinement of that one sentence.
Modes & help
Neovim is modal. You read and move in Normal, type in Insert, select in Visual, and run commands from the : command line.
1. Modes
Esc " back to Normal (always works)
i a o " insert before / after / new line
v V Ctrl-v " visual: char / line / block
: " command-line mode
2. Open & quit
nvim main.rs " open a file
:w " save (write)
:q " quit
:wq " save and quit (:x too)
:q! " quit, discard changes
3. Help
:help " open the manual
:help :w " help for the :w command
:help quickref " one-page quick reference
:help user-manual
4. Shell
:!ls -la " run a command, return
:terminal " open a real shell
:term " ...in a split
KEY: Neovim is modal. In Normal mode every key is a command, and most commands combine a
count, anoperator, and amotion—d3wmeans “delete 3 words”.Escalways returns you to Normal mode.
Motions
Motions move the cursor. Prefix any of them with a count to repeat: 5j, 3w, 12G.
Cursor
- Left / down / up / right — hjkl
- Next word / back / end — wbe
- WORD (ignore punctuation) — WBE
- Beginning of line (0) / end ($) — 0$
- First non-blank character — ^
Line & find
- Find char (forward) — fchar
- Until char (forward) — tchar
- Find / until (backward) — FT
- Repeat last f/t forward — ;
- Repeat last f/t backward — ,
File jumps
- Top of file / bottom — ggG
- Jump to line N — NG
- Match bracket / paren — %
- Previous / next paragraph — {}
- Page down / up — Ctrl-fCtrl-b
3×: Counts multiply anything.
5jmoves down five lines,3wadvances three words,12Gjumps to line 12.fandtland on a character in the current line; repeat them with;(forward) and,(backward).
Operators & text objects
An operator is a verb, a text object is a noun. Pair d, c, or y with a motion or a text object: dw, ciw, yap.
Operators
- Delete — dmotion
- Change (delete + insert) — cmotion
- Yank (copy) — ymotion
- Delete character — x
- Put after / before cursor — pP
Lines & repeat
- Delete / change / yank line — ddccyy
- Delete / change to end of line — DC
- Undo / redo — uCtrl-r
- Repeat last change — .
- Delete 3 words — 3dw
Registers
- Yank into register a — "ay
- Paste from register a — "ap
- System clipboard — "+y
- List all registers — :reg
- Last yank / delete — "0p
| Text object | Selects | Example |
|---|---|---|
iw / aw | inner / a word | ciw retype the word |
ip / ap | inner / a paragraph | dip delete paragraph |
i" / a" | inside / around quotes | ci" replace a string |
i) / a) | inside / around parens | di( clear the contents |
it / at | inner / around HTML tag | cit change the tag body |
.: The dot command repeats the last change — not the last motion.
ciw foothenj.rewrites each word as you walk down. Registers named"a–"zpersist between edits;"+is your system clipboard.
Search & replace
Search with /, jump between hits with n / N, then rewrite with :s when you need a change across the file.
Find
- Search forward / backward — /pattern/?
- Next / previous match — nN
- Clear highlight — :noh
- Find next occurrence of word — *#
- Partial word (forward/back) — g*/g#
Pattern flags
- Ignore case — </kbd>c
- Match case — </kbd>C
- Very magic (regex) — </kbd>v
- Very nomagic (literal) — </kbd>V
- Word boundary — </kbd>«/kbd></kbd>>
Replace
- Replace in line — :s/old/new/
- Replace all in line — :s/old/new/g
- Replace all in file — :%s/old/new/g
- Confirm each match — :%s/old/new/gc
- Delete matching lines — :g/pattern/d
/: Slash inside a pattern? Use any delimiter —
:s#/usr/bin#/usr/local/bin#g— or escape it as\/. Thecflag confirms each replacement;njust counts matches.
Buffers, windows & tabs
A buffer holds a file, a window shows a buffer, and a tab groups windows. One buffer can appear in many windows.
Buffers
- Edit / open a file — :efile
- Next / previous buffer — :bn/:bp
- List buffers — :ls
- Delete buffer — :bd
- Delete buffer, discard changes — :bd!
Windows
- Split horizontal / vertical — :sp/:vsp
- Move focus — Ctrl-wh j k l
- Close / only window — Ctrl-wq/o
- Equalize sizes — Ctrl-w=
- Rotate / swap windows — Ctrl-wr
Tabs & marks
- New tab — :tabnew
- Next / previous tab — gt/gT
- Set mark a — ma
- Jump to mark a — `a
- Jump to mark’s line — ’a
m: Marks are bookmarks.
ma drops mark a at the cursor,\areturns to its exact position,‘ato its line.``jumps back to your previous jump, lowercase marks stay with the buffer, and uppercasemA` work across files.
init.lua config
Neovim is configured in Lua. Start at ~/.config/nvim/init.lua, set options with vim.opt, and bind keys with vim.keymap.set.
vim.opt
Options are Lua table fields. Reload with :source %.
vim.opt.number = true -- line numbers
vim.opt.relativenumber = true -- relative jumps
vim.opt.shiftwidth = 2 -- indent width
vim.opt.tabstop = 2
vim.opt.expandtab = true -- spaces, not tabs
vim.opt.smartindent = true
vim.opt.ignorecase = true -- search…
vim.opt.smartcase = true -- …unless uppercase
vim.keymap.set
Signature: vim.keymap.set(mode, lhs, rhs, opts).
vim.keymap.set("n", "<leader>w", ":w<CR>", { desc = "Save" })
vim.keymap.set("n", "<leader>q", ":q<CR>", { desc = "Quit" })
vim.keymap.set("n", "Y", "y$", { desc = "Yank to EOL" })
vim.keymap.set("v", "J", ":m '>+1<CR>gv=gv",
{ desc = "Move line down" })
Leader key
A leader gives every custom map a namespace. <leader> expands to your chosen key.
Space then w saves
vim.g.mapleader = " "
vim.g.maplocalleader = "\\"
-- <leader>w means: space, then w
vim.keymap.set("n", "<leader>e", vim.cmd.Ex,
{ desc = "File explorer" })
lazy.nvim
Plugin manager. Bootstrap once, then declare plugins in ~/.config/nvim/lua/plugins/.
local lazypath = vim.fn.stdpath("data")
.. "/lazy/lazy.nvim"
if not (vim.uv or vim.loop).fs_stat(lazypath) then
vim.fn.system({ "git", "clone",
"--filter=blob:none",
"https://github.com/folke/lazy.nvim.git",
"--branch=stable", lazypath })
end
vim.opt.rtp:prepend(lazypath)
require("lazy").setup("plugins")
lua: Where does config live?
~/.config/nvim/init.luais the entry point;require("plugins")pulls fromlua/plugins/. After edits,:source %reloads the current file — or restart Neovim and run:checkhealthto catch mistakes.
LSP, treesitter & completion
Language servers give you go-to-definition, references, rename, and diagnostics; treesitter adds real syntax parsing; nvim-cmp ties it into completion.
mason + lspconfig
Install servers with :LspInstall, then attach them per buffer — or use the built-in vim.lsp.enable on 0.11+.
require("mason").setup()
require("mason-lspconfig").setup({
ensure_installed = { "lua_ls", "rust_analyzer" },
})
require("lspconfig").lua_ls.setup({})
require("lspconfig").rust_analyzer.setup({})
treesitter
Built into core since 0.11 — parsers for C, Lua, Vimscript, and Vimdoc ship with Neovim, and treesitter highlighting is the default in 0.12. The nvim-treesitter plugin was archived in 2026; keep it only for extra parsers via :TSInstall.
-- 0.11+ / 0.12: nothing to configure
-- parsing + highlighting are built in
-- extra parsers still need the plugin:
-- :TSInstall rust
nvim-cmp
Completion engine fed by LSP, buffer words, and paths.
local cmp = require("cmp")
cmp.setup({
sources = {
{ name = "nvim_lsp" },
{ name = "buffer" },
{ name = "path" },
},
})
Go to
- Go to definition — gd
- Go to references — gr
- Go to declaration — gD
- Go to type definition — gy
- Go to implementation — gi
Hover & actions
- Hover documentation — K
- Rename symbol — leaderrn
- Code action — leaderca
- Signature help — Ctrl-k
- List LSP servers — :LspInfo
Diagnostics
- Next / previous diagnostic — ]d/[d
- Open diagnostics list — leaderd
- Format buffer — leaderf
- Open LSP log — :LspLog
- Restart LSP client — :LspRestart
LSP: Zero-config setup:
:LspInstall rust_analyzerinstalls a server,:LspInfoshows what’s attached, and:LspLogreveals errors when a server won’t start. On 0.11+ you can skip lspconfig entirely with the built-invim.lsp.config()+vim.lsp.enable("rust_analyzer").
Pitfalls
Small behaviors that bite everyone once — usually right after a destructive command.
:q! vs :qa!
:q! discards changes and quits the current window. With splits or tabs open, the others stay behind. :qa! quits every window and buffer without saving.
:q! " quit this window, discard
:qa! " quit everything, discard
:qa " quit everything (only if saved)
Stuck in insert mode
If typing does nothing, you’re probably in Normal mode; if keys appear as text, you’re in Insert. Double-tap Esc or use Ctrl-[ to get back. :set showmode shows the mode in the status line.
Esc Esc " always returns to Normal
Ctrl-[ " same as Esc
Ctrl-c " also exits insert mode
Undo is a tree
Undo isn’t a linear stack — it branches. If you undo then edit again, the old path still exists. Time-travel with :earlier / :later.
:undolist " every undo state
:earlier 10m " back ten minutes
:later 5s " forward five seconds
u Ctrl-r " undo / redo
Registers & dot
. repeats only the last change — motions don’t count, and undo doesn’t count either. Pasted text lands in "+ only if your build has clipboard support; check with :checkhealth.
"ap " paste register a
:reg " list all registers
. " repeat the last change only
:s scope surprises
:s substitutes on the current line only, and only the first match unless you add g. :%s reaches the whole file, and & repeats the last substitution.
:s/old/new/ " this line, first hit
:s/old/new/g " this line, all
:%s/old/new/g " whole file
& " repeat last :s
Silent config errors
A typo in init.lua stops the file mid-way with no loud alarm — half your keymaps just won’t exist. Read the messages with :messages, trace an option with :verbose set nu?, and run :checkhealth after big edits.
:messages " recent errors + messages
:verbose set nu? " where 'number' was set
:checkhealth " LSP / provider report
!: Lost your way?
:q!discards only the current window’s changes. IfCtrl-cwon’t leave insert mode you may be in-- TERMINAL --; pressCtrl-\ Ctrl-nto escape a terminal back to Normal mode.