🧱 Core Vim Hacks¶
The fundamentals that make Vim a text manipulation language, not just a text editor.
📌 Table of Contents¶
- The Vim Grammar
- Motions How You Move
- Text Objects Surgical Precision
- The Dot Command Repeat Anything
- Registers 48 Clipboards
- Marks Teleportation Points
- Visual Mode Selection Done Right
- Search Find Anything Instantly
- Undo & Redo Fearless Editing
The Vim Grammar¶
Vim commands follow a grammar: {operator}{count}{motion/text-object}
d 3 w
│ │ │
│ │ └── motion: word
│ └────────── count: 3 times
└────────────────── operator: delete
Learn 10 operators × 10 motions = 100 commands. This is why Vim scales.
Operators¶
| Key | Operator |
|---|---|
d |
Delete |
c |
Change (delete + enter insert mode) |
y |
Yank (copy) |
v |
Visual select |
> |
Indent right |
< |
Indent left |
= |
Auto-indent |
gU |
Uppercase |
gu |
Lowercase |
g~ |
Toggle case |
gq |
Format/wrap text |
The Rule¶
Every operator works with every motion and every text object. Learn them independently, combine them infinitely.
Motions How You Move¶
Character-Level¶
| Key | Motion |
|---|---|
h j k l |
Left, down, up, right |
f{char} |
Jump to next {char} on line |
F{char} |
Jump to previous {char} on line |
t{char} |
Jump till (before) next {char} |
T{char} |
Jump till (after) previous {char} |
; |
Repeat last f/F/t/T forward |
, |
Repeat last f/F/t/T backward |
Word-Level¶
| Key | Motion |
|---|---|
w |
Next word start |
W |
Next WORD start (space-delimited) |
b |
Previous word start |
B |
Previous WORD start |
e |
End of word |
E |
End of WORD |
ge |
End of previous word |
Line-Level¶
| Key | Motion |
|---|---|
0 |
Start of line |
^ |
First non-blank character |
$ |
End of line |
g_ |
Last non-blank character |
+ |
First non-blank of next line |
- |
First non-blank of previous line |
Block-Level¶
| Key | Motion |
|---|---|
{ |
Previous blank line (paragraph up) |
} |
Next blank line (paragraph down) |
% |
Matching bracket () {} [] |
[[ |
Previous section/function start |
]] |
Next section/function start |
File-Level¶
| Key | Motion |
|---|---|
gg |
First line of file |
G |
Last line of file |
42G or :42 |
Go to line 42 |
H |
Top of visible screen |
M |
Middle of visible screen |
L |
Bottom of visible screen |
<C-d> |
Half-page down |
<C-u> |
Half-page up |
<C-f> |
Full page down |
<C-b> |
Full page up |
Combining Operators + Motions¶
dw " Delete to next word
d$ " Delete to end of line
d} " Delete to next blank line
ct) " Change till closing paren
yf; " Yank to next semicolon (inclusive)
gUw " Uppercase next word
>} " Indent to next blank line
=G " Auto-indent from here to end of file
Text Objects Surgical Precision¶
Text objects define a region of text. They come in two flavors:
- i = inner (inside the delimiters)
- a = around (includes the delimiters)
Paired Delimiters¶
| Text Object | Inner (i) |
Around (a) |
|---|---|---|
" |
ci" → change inside quotes |
ca" → change including quotes |
' |
di' → delete inside single quotes |
da' → delete including quotes |
` |
ci`` → change inside backticks |
ca`` → includes backticks |
( or ) |
ci( → change inside parens |
ca( → includes parens |
{ or } |
di{ → delete inside braces |
da{ → includes braces |
[ or ] |
yi[ → yank inside brackets |
ya[ → includes brackets |
< or > |
ci< → change inside angle brackets |
ca< → includes angles |
t (tag) |
cit → change inside HTML tag |
cat → includes the tags |
Word/Sentence/Paragraph¶
| Text Object | Meaning |
|---|---|
iw |
Inner word |
aw |
A word (includes trailing space) |
iW |
Inner WORD (space-delimited) |
aW |
A WORD |
is |
Inner sentence |
as |
A sentence |
ip |
Inner paragraph |
ap |
A paragraph (includes trailing blank line) |
Real-World Examples¶
" You're inside: function(arg1, arg2, arg3)
ci( " Delete all args, start typing new ones
" You're inside: "Hello, World!"
ci" " Replace string content, keep quotes
" You're inside: <div class="container">content</div>
cit " Replace tag content, keep tags
" You're inside a paragraph of text
dap " Delete entire paragraph
" You're on: const name = "value";
ciw " Replace just the word under cursor
" Indent inside braces
>i{ " Indent everything inside {}
" Yank a function body
yi{ " Copy everything inside the braces
The Dot Command Repeat Anything¶
. repeats your last change. The key insight: design your edits to be dot-repeatable.
Pattern 1: Change + Find + Repeat¶
/pattern<CR> " Find first occurrence
cgn replacement<Esc> " Change it (cgn = change next match)
. " Repeat on next match
. " And the next
n " Skip one (just move, don't change)
. " Change this one
cgn is magical because it's a single change operation that includes the search making . repeat both the find and the replace.
Pattern 2: Append + Move + Repeat¶
Pattern 3: Surround + Repeat¶
What Counts as a "Change"¶
A change is everything from entering insert mode to leaving it, OR a single normal-mode command that modifies text:
ddone change (delete line)iHello World<Esc>one change (insert text)ciwreplacement<Esc>one change (change word)3xone change (delete 3 chars)>apone change (indent paragraph)
Anti-Pattern: Breaking Repeatability¶
" BAD: Multiple separate changes
i(<Esc>ea)<Esc> " Two changes dot only repeats the second
" GOOD: One atomic change
ysiw) " One surround operation dot repeats it all
Registers 48 Clipboards¶
Every delete, yank, and change goes into a register. You have dozens of them.
Named Registers (a-z)¶
"ayy " Yank line into register 'a'
"bdd " Delete line into register 'b'
"ap " Paste from register 'a'
"bp " Paste from register 'b'
" Uppercase = APPEND to register
"Ayy " Append this line to register 'a'
Special Registers¶
| Register | Contains |
|---|---|
"" |
Last deleted/yanked text (default) |
"0 |
Last yanked text (yank-only) |
"1-"9 |
Delete history (1 = most recent) |
"_ |
Black hole (delete without saving) |
"+ |
System clipboard |
"* |
Selection clipboard (X11) |
"% |
Current filename |
"# |
Alternate filename |
". |
Last inserted text |
": |
Last ex command |
"/ |
Last search pattern |
"= |
Expression register |
Practical Uses¶
" Delete without polluting default register
"_dd " Line gone, registers untouched
" Paste from yank register (ignores deletes)
"0p " Always pastes what you last yanked, not deleted
" Paste in insert mode
<C-r>a " Insert contents of register 'a'
<C-r>" " Insert default register
<C-r>=5*42<CR> " Insert result of expression (210)
<C-r>=system('date')<CR> " Insert shell command output
" View all registers
:registers
The Yank/Delete Problem (Solved)¶
The classic frustration: you yank text, delete something, then paste and get the deleted text instead.
Solution 1: Use "0p register 0 always holds the last yank.
Solution 2: This config maps visual-mode paste to not overwrite:
Marks Teleportation Points¶
Local Marks (a-z) Per Buffer¶
Global Marks (A-Z) Cross-File¶
Strategy: Use global marks for your working set:
- mM Main file you're editing
- mT Test file
- mH Header file
- mC Config file
Jump between them instantly: 'M, 'T, 'H, 'C.
Automatic Marks¶
| Mark | Position |
|---|---|
`` |
Position before last jump |
'. |
Position of last edit |
'^ |
Position where insert mode was last exited |
'[ '] |
Start/end of last changed or yanked text |
'< '> |
Start/end of last visual selection |
Jump List¶
Every gd, /search, gg, G, 'mark adds to the jump list. <C-o> is your "back button."
Visual Mode Selection Done Right¶
Three Flavors¶
| Key | Mode | Selects |
|---|---|---|
v |
Character-wise | Individual characters |
V |
Line-wise | Entire lines |
<C-v> |
Block-wise | Rectangular columns |
Visual + Operators¶
" Select then operate
viw " Select word
vip " Select paragraph
vi{ " Select inside braces
V5j " Select 5 lines down
" Then apply operator
d " Delete selection
c " Change selection
y " Yank selection
> " Indent selection
U " Uppercase selection
u " Lowercase selection
: " Run ex command on selection
Block Mode (Column Editing)¶
<C-v>jjjI// <Esc> " Insert '//' at start of 4 lines (comment)
<C-v>jjjA;<Esc> " Append ';' to end of 4 lines
<C-v>jjjd " Delete a column
<C-v>jjjr* " Replace column with '*'
<C-v>jjjg<C-a> " Increment numbers: 0,0,0,0 → 1,2,3,4
Reselect Last Selection¶
Search Find Anything Instantly¶
Basic Search¶
| Key | Action |
|---|---|
/pattern |
Search forward |
?pattern |
Search backward |
n |
Next match |
N |
Previous match |
* |
Search word under cursor (forward) |
# |
Search word under cursor (backward) |
Search Modifiers¶
/\cpattern " Case insensitive (regardless of smartcase)
/\Cpattern " Case sensitive (force)
/\<word\> " Whole word only (word boundaries)
/\vpattern " Very magic (regex without escaping)
Useful Search Patterns¶
/\v\w+\( " Find function calls
/\vTODO|FIXME " Find all TODOs and FIXMEs
/\v^\s*$ " Find blank lines
/\v\S+\s*$ " Find trailing whitespace
/\v(.)\1+ " Find repeated characters
Search and Replace¶
:%s/old/new/g " Replace all in file
:%s/old/new/gc " Replace all with confirmation
:'<,'>s/old/new/g " Replace in visual selection
Undo & Redo Fearless Editing¶
Basic¶
| Key | Action |
|---|---|
u |
Undo |
<C-r> |
Redo |
U |
Undo all changes on current line |
Undo Tree (this config)¶
Vim's undo is a tree, not a linear stack. Every branch is preserved.
Persistent Undo¶
This config enables persistent undo your undo history survives Vim restarts. Close Vim, reopen the file next week, and u still works back to your first edit.
Time Travel¶
:earlier 5m " Revert to state 5 minutes ago
:later 5m " Go forward 5 minutes
:earlier 10 " Go back 10 changes
🎯 The Core Vim Mindset¶
- Think in text objects Don't "move cursor, select, delete." Think
dap(delete a paragraph). - Compose, don't memorize
d+iw= delete inner word.c+i"= change inside quotes. Same grammar, infinite combinations. - Make it repeatable Design edits so
.does what you want next. - Use counts
5ddnotdd dd dd dd dd.3wnotw w w. - Stay in normal mode Insert mode is for inserting text. Everything else happens in normal mode.
- Trust the undo tree Be bold. Experiment.
ualways has your back.
"Vim is not about typing faster. It's about thinking in text transformations."