You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Vi / Vim / Neovim Cheatsheet — Fellow Analytics Engineer
vi = POSIX baseline (available everywhere). vim-only = requires Vim 8+. nvim-only = Neovim-specific. <leader> defaults to \ — most configs remap it to , or <Space>.
The Mental Model: Modes
Vim is a language, not a list of shortcuts. Commands compose: [count] [operator] [motion] → e.g. 3dw = delete 3 words, ci" = change inside quotes.
Mode
Enter With
Purpose
Normal
Esc / Ctrl+[
Navigate, issue commands — default mode
Insert
iaoIAO
Type text
Visual
vVCtrl+V
Select characters / lines / blocks
Command
:
Ex commands (save, quit, search-replace)
Replace
R
Overwrite text
Operator-pending
after dcy etc.
Waiting for a motion
Analogy: Normal mode is like a CLI — you compose verbs (d, c, y) with nouns (motions like w, }, gg). Insert mode is just a dumb text field.
Saving & Exiting (Survival Kit)
Command
Action
:w
Save (write)
:wq or ZZ
Save and quit
:q! or ZQ
Quit without saving
:w !sudo tee %
Save with sudo (forgot to open as root)
:wa
Save all open buffers
:xa
Save all and exit
Navigation — Normal Mode
Character / Line
Key
Action
h j k l
Left / down / up / right
0 / ^ / $
Start of line / first non-blank / end of line
gg / G
First / last line of file
42G or :42
Jump to line 42
H / M / L
Top / middle / bottom of screen
Ctrl+D / Ctrl+U
Half-page down / up
Ctrl+F / Ctrl+B
Full-page forward / back
zz / zt / zb
Center / top / bottom cursor line on screen
Word Motion
Key
Action
w / W
Next word start (word / WORD)
b / B
Previous word start
e / E
Next word end
ge / gE
Previous word end
word = alphanumeric+underscore; WORD = anything delimited by whitespace. Use W/B to jump over my_column_name as one unit.
File / Block
Key
Action
%
Jump to matching bracket ()[]{}
{ / }
Jump to previous / next blank line (paragraph)
[[ / ]]
Previous / next section (function/class in Python)
Ctrl+O / Ctrl+I
Jump back / forward in jump list
'' or ``
Jump to position before last jump
'.
Jump to last edit position
gd
Go to local definition
gf
Open file under cursor (great for source paths)
Entering Insert Mode
Key
Action
i / a
Insert before / after cursor
I / A
Insert at line start / end
o / O
Open new line below / above
s / S
Substitute char / whole line
C
Change to end of line
gi
Re-enter Insert at last insert position
Operators (Verbs)
Combine with any motion or text object: [operator][motion/object]
Operator
Action
d
Delete (cut)
c
Change (delete + enter Insert)
y
Yank (copy)
> / <
Indent right / left
=
Auto-indent
gU / gu / g~
Uppercase / lowercase / toggle case
!
Filter through external command
Text Objects (Nouns)
Object
Meaning
iw / aw
Inner word / a word (includes surrounding space)
is / as
Inner sentence / a sentence
ip / ap
Inner paragraph / a paragraph
i"i'i`
Inside quotes
i(i[i{
Inside brackets
i<
Inside <tag>
it
Inside HTML/XML tag
Analytics examples: ci" → change SQL string literal da{ → delete a Jinja {% block %} body including braces =ip → re-indent a Python function block gUiw → uppercase a SQL keyword under cursor
Common Edit Patterns
Command
Action
dd
Delete (cut) current line
yy or Y
Yank current line
p / P
Paste after / before cursor
x / X
Delete char under / before cursor
r{c}
Replace char under cursor with c
R
Enter Replace mode (overwrite)
u / Ctrl+R
Undo / redo
U
Undo all changes on current line
.
Repeat last change — the most powerful key in Vim
J
Join next line to current
~
Toggle case of char under cursor
Ctrl+A / Ctrl+X
Increment / decrement number under cursor
Search & Replace
Search (Normal mode)
Command
Action
/pattern
Search forward
?pattern
Search backward
n / N
Next / previous match
* / #
Search word under cursor forward / backward
g* / g#
Like */# but partial match
:noh
Clear search highlight
Regex flavour
Vim uses its own regex. Key differences from Python re:
\+ = one or more (not +)
\| = alternation (not |)
Use \v (very magic) for Python-like syntax: /\vref\(\w+\)/
Substitute (Command mode)
:[range]s/pattern/replacement/[flags]
Example
Action
:s/foo/bar/
Replace first match on current line
:s/foo/bar/g
Replace all on current line
:%s/foo/bar/g
Replace all in file
:%s/foo/bar/gc
Replace all, confirm each
:'<,'>s/foo/bar/g
Replace in visual selection
:5,20s/foo/bar/g
Replace in lines 5–20
:%s/\v(ref|source)\(/func(/g
Regex: rename dbt macros
:%s/foo/bar/gI
Case-sensitive (override ignorecase)
Analytics tip::5,42s/^/-- / comments out a SQL block from lines 5 to 42.
Visual Mode
Key
Mode
v
Character-wise visual
V
Line-wise visual
Ctrl+V
Block (column) visual
gv
Re-select last visual selection
o
Move to other end of selection
With block visual (Ctrl+V):
Action
How
Insert same text in every selected line
Ctrl+V → select lines → I → type → Esc
Delete a column
Ctrl+V → select column → d
Indent a block
V → select lines → > (repeat with .)
dbt tip: Block-insert -- across 10 lines to bulk-comment a CTE block.
Registers & Macros
Registers
Register
Content
"
Default (unnamed)
0
Last yank
1–9
Delete history (1 = most recent)
a–z
Named — use deliberately
+ / *
System clipboard / primary selection
%
Current filename
:
Last command
/
Last search pattern
Usage: "ayy = yank line into register a; "ap = paste from a.
System clipboard: "+y to copy, "+p to paste. (vim-only: requires +clipboard build.)
" Format SQL in buffer via sqlformat
:%!sqlformat -r-k upper --indent_width 4-" Pretty-print JSON (e.g. Airflow task metadata)
:%!python3-m json.tool
" Strip trailing whitespace across file
:%s/\s\+$//e" Comment out dbt SQL block (lines 10-25)
:10,25s/^/-- /
" Uncomment dbt SQL block
:10,25s/^-- //
" Find all {{ ref( calls in dbt model
/\v\{\{[ ]*ref\(" Global yank all lines containing 'TODO' into register t
:let@t="" | :g/TODO/y T
" Count occurrences of a pattern
:%s/pattern//gn
" Open a vertical split with the current dbt model's schema.yml
:vsp schema.yml