Introduction
VIM is intimidating at first. Once basic motions click, you edit faster than any mouse user.
This guide covers the shortcuts that matter most.
Pro Tip: Don’t try to memorize everything at once. Pick 3-5 commands from each section and practice them daily. Muscle memory will develop naturally over time.
VIM Modes Overview
VIM has four modes:
| Mode | Description | How to Enter |
|---|---|---|
| Normal | Navigate and execute commands | Esc |
| Insert | Type text like a regular editor | i, a, o |
| Visual | Select text | v, V, Ctrl+v |
| Command | Execute Ex commands | : |
Golden Rule: Always return to Normal mode after editing. Hit Esc frequently!
Basic Movement (Normal Mode)
Character-Level Movement
| Command | Action | Example |
|---|---|---|
h | Move left | Move 1 character left |
l | Move right | Move 1 character right |
j | Move down | Move 1 line down |
k | Move up | Move 1 line up |
j as a down arrow (↓) and k as an up arrow (↑).Fast Movement Within Lines
| Command | Action | Use Case |
|---|---|---|
0 | Start of line (column 0) | Jump to very beginning |
^ | First non-blank character | Skip indentation |
$ | End of line | Jump to line end |
g_ | Last non-blank character | Skip trailing spaces |
Example:
const message = "Hello World";
0→ column 0 (before spaces)^→ ‘c’ in ‘const’$→ after ’;’ and spacesg_→ the ’;‘
Word-Level Movement
| Command | Action | Example |
|---|---|---|
w | Next word (forward) | const → message |
b | Previous word (backward) | message → const |
e | End of word | Move to last char of word |
W | Next WORD (space-delimited) | Skip punctuation |
B | Previous WORD | Backward, skip punctuation |
w vs W:
const user.name = "John-Doe";
w:user,.,name,=,",John,-,Doeare separate wordsW:user.name,=,"John-Doe"are WORDS (space-delimited)
Line-Level Movement
| Command | Action | Tip |
|---|---|---|
gg | First line of file | Jump to top |
G | Last line of file | Jump to bottom |
42G or :42 | Line 42 | Go to specific line |
50% | 50% of file | Jump to middle |
H | Top of screen (High) | Visible area only |
M | Middle of screen | Visible area only |
L | Bottom of screen (Low) | Visible area only |
Search-Based Movement
| Command | Action | Example |
|---|---|---|
f{char} | Find forward to char | fa → find next ‘a’ |
F{char} | Find backward to char | Fa → find previous ‘a’ |
t{char} | Till forward (before char) | ta → move before ‘a’ |
T{char} | Till backward (after char) | Ta → move after ‘a’ |
; | Repeat last f/t/F/T | Find next occurrence |
, | Reverse last f/t/F/T | Find previous occurrence |
Example:
const userName = 'JohnDoe'
Cursor on ‘c’, type fe → jumps to ‘e’ in ‘userName’.
Type ; → jumps to ‘e’ in ‘“JohnDoe”’.
Search with / and ?
| Command | Action | Notes |
|---|---|---|
/pattern | Search forward | Type pattern, press Enter |
?pattern | Search backward | Reverse search |
n | Next match | Same direction |
N | Previous match | Opposite direction |
* | Search word under cursor (forward) | Quick search |
# | Search word under cursor (backward) | Quick search |
Example Workflow:
- Cursor on
userName *→ highlights all occurrencesn→ next occurrenceN→ previous occurrence
Fast Editing (Normal Mode)
Insert Mode Shortcuts
| Command | Action | Cursor Position |
|---|---|---|
i | Insert before cursor | Current position |
I | Insert at line start | First non-blank char |
a | Append after cursor | One char right |
A | Append at line end | End of line |
o | Open line below | New line below |
O | Open line above | New line above |
s | Substitute char | Delete char + insert |
S | Substitute line | Delete line + insert |
Use A instead of $a. Use I instead of ^i.
Deletion Commands
| Command | Action | Memory Aid |
|---|---|---|
x | Delete character | Cut char under cursor |
X | Delete char before | Backspace in normal mode |
dd | Delete line | Cut entire line |
dw | Delete word | From cursor to word end |
db | Delete word backward | To word start |
d$ or D | Delete to line end | From cursor to EOL |
d0 | Delete to line start | From cursor to start |
dG | Delete to file end | From cursor to EOF |
dgg | Delete to file start | From cursor to top |
Change Commands (Delete + Insert)
| Command | Action | Equivalent |
|---|---|---|
cw | Change word | dwi |
c$ or C | Change to line end | d$i |
cc or S | Change entire line | ddi |
ciw | Change inner word | Delete word under cursor |
ci" | Change inside quotes | Replace text in ”…” |
ci{ | Change inside braces | Replace text in {...} |
cit | Change inside tag | Replace HTML tag content |
Example:
const message = 'Hello World'
- Cursor on any char in “Hello World”
ci"→ deletes “Hello World”, enters insert mode- Type new text →
"New Message"
Copy (Yank) and Paste
| Command | Action | Notes |
|---|---|---|
yy or Y | Yank (copy) line | Copy entire line |
yw | Yank word | From cursor to word end |
y$ | Yank to line end | From cursor to EOL |
ygg | Yank to file start | From cursor to top |
yG | Yank to file end | From cursor to bottom |
p | Paste after cursor | Paste below line |
P | Paste before cursor | Paste above line |
System Clipboard:
"+y→ Copy to system clipboard"+p→ Paste from system clipboard
Undo and Redo
| Command | Action |
|---|---|
u | Undo last change |
Ctrl+r | Redo (undo the undo) |
U | Undo all changes on line |
Repeat Last Command
| Command | Action | Use Case |
|---|---|---|
. | Repeat last change | Super powerful! |
Example:
dw→ delete word- Move to another word
.→ deletes that word too
Works with any change: dd, ciw, x, etc.
Visual Mode Shortcuts
Entering Visual Mode
| Command | Mode | Selection Type |
|---|---|---|
v | Visual | Character-wise |
V | Visual Line | Line-wise |
Ctrl+v | Visual Block | Column-wise (rectangle) |
Operating on Visual Selections
After selecting:
| Command | Action |
|---|---|
d | Delete selection |
c | Change selection |
y | Yank (copy) selection |
> | Indent right |
< | Indent left |
= | Auto-indent |
u | Lowercase |
U | Uppercase |
~ | Toggle case |
Example - Comment Multiple Lines:
Ctrl+v→ enter visual block modejjj→ select 4 linesI→ insert at start of block#→ type comment characterEsc→ apply to all lines
Text Objects (Game Changer!)
Operate on logical chunks of text instead of character-by-character.
Syntax
| Pattern | Meaning |
|---|---|
i | Inner (excludes delimiters) |
a | Around (includes delimiters) |
Common Text Objects
| Object | Description | Example |
|---|---|---|
iw | Inner word | Word under cursor |
aw | A word (with space) | Word + trailing space |
is | Inner sentence | Current sentence |
as | A sentence | Sentence + space |
ip | Inner paragraph | Paragraph (blank-delimited) |
ap | A paragraph | Paragraph + blank line |
i" | Inner quotes | Text inside ”…” |
a" | Around quotes | Text + ”…” |
i( or ib | Inner parentheses | Text inside (…) |
a( or ab | Around parentheses | Text + (…) |
i{ or iB | Inner braces | Text inside {...} |
a{ or aB | Around braces | Text + {...} |
it | Inner tag | Inside HTML tag |
at | Around tag | HTML tag + content |
Powerful Combinations
| Command | Action | Example |
|---|---|---|
ciw | Change inner word | Replace word |
daw | Delete a word | Delete word + space |
di" | Delete inside quotes | Clear “text” |
da" | Delete around quotes | Remove “text” entirely |
ci{ | Change inside braces | Replace {...} content |
dit | Delete inside tag | Clear <p>text</p> |
vit | Select inside tag | Select tag content |
yip | Yank inner paragraph | Copy paragraph |
Real-World Example:
const user = {
name: 'John Doe',
email: 'john@example.com',
}
- Cursor anywhere inside
{...} ci{→ deletes content, stays in{...}- Type new object content
Search and Replace
Basic Find/Replace
| Command | Action | Scope |
|---|---|---|
:s/old/new/ | Replace first on line | Current line |
:s/old/new/g | Replace all on line | Current line |
:%s/old/new/g | Replace all in file | Entire file |
:%s/old/new/gc | Replace with confirmation | Interactive |
:5,10s/old/new/g | Replace in lines 5-10 | Range |
Visual Selection Replace
- Select text with
vorV - Type
:(shows:'<,'>) - Type
s/old/new/g - Press Enter
Case-Insensitive Search
| Command | Action |
|---|---|
/pattern\c | Case-insensitive search |
/pattern\C | Case-sensitive search |
:set ic | Set ignore case globally |
:set noic | Turn off ignore case |
Numbers as Multipliers
Prefix any command with a number to repeat it.
| Command | Action |
|---|---|
5j | Move down 5 lines |
3w | Move forward 3 words |
10dd | Delete 10 lines |
2yy | Yank 2 lines |
4x | Delete 4 characters |
80i-[Esc] | Insert 80 dashes |
3p | Paste 3 times |
5>> | Indent 5 lines right |
Practical Example:
# Need to insert 50 equals signs
50i=[Esc]
Result: ==================================================
Marks and Jumps
Marks (Bookmarks)
| Command | Action | Scope |
|---|---|---|
ma | Set mark ‘a’ | Local to file |
mA | Set mark ‘A’ | Global (across files) |
`a | Jump to mark ‘a’ | Exact position |
'a | Jump to line of mark ‘a’ | First non-blank |
:marks | List all marks | Show marks |
Jump List
| Command | Action |
|---|---|
Ctrl+o | Jump to older position |
Ctrl+i | Jump to newer position |
:jumps | Show jump list |
Change List
| Command | Action |
|---|---|
g; | Jump to older change position |
g, | Jump to newer change position |
:changes | Show change list |
Window and Buffer Management
Split Windows
| Command | Action |
|---|---|
:split or :sp | Horizontal split |
:vsplit or :vsp | Vertical split |
Ctrl+w s | Horizontal split |
Ctrl+w v | Vertical split |
Ctrl+w w | Switch to next window |
Ctrl+w h/j/k/l | Navigate windows |
Ctrl+w q | Close current window |
Ctrl+w = | Equalize window sizes |
Buffer Navigation
| Command | Action |
|---|---|
:ls or :buffers | List all buffers |
:b 2 | Switch to buffer 2 |
:bn | Next buffer |
:bp | Previous buffer |
:bd | Delete (close) buffer |
:b filename | Switch to buffer by name |
Advanced Efficiency Tips
Macros (Record and Replay)
| Command | Action |
|---|---|
qa | Start recording to register ‘a’ |
q | Stop recording |
@a | Play macro from register ‘a’ |
@@ | Repeat last macro |
5@a | Play macro ‘a’ 5 times |
Example - Add semicolons to multiple lines:
qa→ start recording to register ‘a’A;[Esc]→ append semicolonj→ move downq→ stop recording10@a→ repeat 10 times
Global Commands
| Command | Action | Example |
|---|---|---|
:g/pattern/d | Delete lines matching pattern | Remove all console.log |
:v/pattern/d | Delete lines not matching pattern | Keep only pattern |
:g/TODO/p | Print lines matching pattern | Find all TODOs |
:g/^$/d | Delete empty lines | Clean up |
Example:
:g/console.log/d # Delete all lines with console.log
:v/^import/d # Delete all lines except imports
:g/TODO:/norm A !!! # Append !!! to all TODO lines
Sorting and Filtering
| Command | Action |
|---|---|
:sort | Sort lines alphabetically |
:sort! | Sort in reverse |
:sort u | Sort and remove duplicates |
:%!sort | Sort using external command |
Auto-Completion (Insert Mode)
| Command | Completion Type |
|---|---|
Ctrl+n | Next word completion |
Ctrl+p | Previous word completion |
Ctrl+x Ctrl+f | File name completion |
Ctrl+x Ctrl+l | Line completion |
Quick Reference Cheat Sheet
Movement Quick Reference
Character: h ← | j ↓ | k ↑ | l →
Line: 0 start | ^ first-char | $ end | g_ last-char
Word: w next | b previous | e end
Search: f{char} | F{char} | t{char} | T{char} | ; | ,
Jump: gg top | G bottom | {n}G line | H/M/L screen
Find: /{pattern} | n next | N previous | * word | # word
Editing Quick Reference
Insert: i | I | a | A | o | O | s | S
Delete: x | X | dd | dw | db | D | d$ | d0
Change: cw | cc | C | c$ | ciw | ci" | ci{
Yank/Paste: yy | yw | y$ | p | P | "+y | "+p
Undo/Redo: u | Ctrl+r | U
Repeat: . (dot command)
Visual Mode Quick Reference
Enter: v char | V line | Ctrl+v block
Actions: d delete | c change | y yank | > indent | < outdent
Case: u lower | U upper | ~ toggle
Practice Exercises
Exercise 1: Navigation Basics
Open any code file and try:
- First line:
gg - Last line:
G - Line 50:
50G - Find “function”:
/function - Next match:
n - Previous match:
N
Exercise 2: Editing Workflow
Given:
const userName = 'JohnDoe'
Try:
- Change “JohnDoe” to “JaneSmith”:
ci"JaneSmith[Esc] - Change variable name:
ciwuserEmail[Esc] - Delete line:
dd - Undo:
u
Exercise 3: Text Objects
Given:
function greet(name) {
return 'Hello, ' + name + '!'
}
Try:
- Cursor on any char in “Hello, ”
- Change string:
ci"Goodbye[Esc] - Delete function body:
ci{[Esc] - Delete entire function:
da{
Exercise 4: Macro Recording
Task: Add // TODO: to the start of 5 lines.
qa→ start recordingI// TODO: [Esc]→ insert at line startj→ move downq→ stop recording4@a→ repeat 4 more times
VIM Configuration Tips
Add these to your ~/.vimrc:
" Line numbers
set number
set relativenumber
" Search improvements
set ignorecase " Case-insensitive search
set smartcase " Case-sensitive if uppercase used
set incsearch " Incremental search
set hlsearch " Highlight search results
" Indentation
set expandtab " Use spaces instead of tabs
set tabstop=2 " Tab width = 2 spaces
set shiftwidth=2 " Indent width = 2 spaces
set autoindent " Auto-indent new lines
" Performance
set lazyredraw " Don't redraw during macros
" Quality of life
set clipboard=unnamedplus " Use system clipboard
set mouse=a " Enable mouse support
set scrolloff=8 " Keep 8 lines visible when scrolling
" Map leader key
let mapleader = " "
" Quick save and quit
nnoremap <leader>w :w<CR>
nnoremap <leader>q :q<CR>
" Clear search highlighting
nnoremap <leader>h :noh<CR>
Common Patterns and Workflows
Refactoring Variable Name
Rename userName to userEmail across a file:
:%s/userName/userEmail/gc
%→ entire fileg→ all occurrences per linec→ confirm each
Delete All Comments
Single-line comments (//):
:g/^[ \t]*\/\//d
Format JSON
:%!python -m json.tool
Remove Trailing Whitespace
:%s/\s\+$//
Swap Two Words
Cursor on first word:
dawwP
daw→ delete a wordw→ next wordP→ paste before
Conclusion
VIM’s power is composability: movements + actions + text objects combine into endless efficient edits.
Key Takeaways:
- Master movement first:
h/j/k/l,w/b,0/$,gg/G - Use text objects:
ciw,di",ci{are the big wins - Use the dot command:
.repeats your last change - Visual mode for complex edits: select, then operate
- Practice daily: muscle memory beats memorization
Next Steps:
- Run
vimtutorin your terminal - Practice 15 minutes daily for 2 weeks
- Learn one new command per day
- Use VIM keybindings in your IDE (VS Code, IntelliJ have VIM plugins)