Vim stands for Vi IMproved. It is a modal text editor, which means you use different modes for moving, editing, selecting, and running commands.
Neovim is a modern fork of Vim with cleaner defaults, Lua configuration, built-in LSP support, and strong plugin support. If you are starting today, Neovim is usually the smoother daily editor, while basic Vim is still useful on servers.
| Reason | Explanation |
|---|---|
| Editing flow | Move, change, delete, and repeat edits without leaving the keyboard. |
| Ubiquity | Available on every Unix system, SSH servers, containers |
| Efficiency | Useful for config files, logs, scripts, and remote troubleshooting. |
| Extensibility | Plugins can turn Neovim into a focused coding environment. |
| Portability | Your config travels with you |
Vim commands combine like a small editing language. For example, d means delete and w means word, so dw deletes a word. Once that idea clicks, the command list starts to feel less random.
| Feature | Vim | Neovim |
|---|---|---|
| Configuration | Vimscript (.vimrc) | Lua or Vimscript (init.lua) |
| LSP Support | Via plugins (CoC) | Built-in native LSP |
| Async Plugins | Limited | Native async support |
| Modern Features | Classic | Floating windows, tree-sitter |
| Plugin Ecosystem | Mature | Growing rapidly |
| Default Settings | Minimal | Sensible defaults |
Beginners: Start with Neovim if you want a modern editor for daily work.
Servers and SSH: Learn basic Vim because it is often available by default when you are editing config files remotely.
# Vim
sudo apt install vim # Debian/Ubuntu
sudo pacman -S vim # Arch
sudo dnf install vim # Fedora
# Neovim
sudo apt install neovim
sudo pacman -S neovim
sudo dnf install neovim
brew install vim
brew install neovim
# Using Chocolatey
choco install vim
choco install neovim
# Using Scoop
scoop install vim
scoop install neovim
# Using winget
winget install vim.vim
winget install Neovim.Neovim
vim --version
nvim --version
Vim is a modal editor, which means different modes handle different tasks. Normal mode is for movement and commands, Insert mode is for typing, and Visual mode is for selecting text.
| Mode | Purpose | Enter With | Exit With |
|---|---|---|---|
| Normal | Navigation, commands | Esc | Already there |
| Insert | Type text | i, a, o | Esc |
| Visual | Select text | v, V, Ctrl+v | Esc |
| Command | Ex commands | : | Enter or Esc |
| Replace | Overwrite text | R | Esc |
A common beginner mistake is staying in Insert mode. Normal mode is your home base. Get used to tapping Esc, or remap it to jk if that feels better.
| Key | Action |
|---|---|
| i | Insert before cursor |
| I | Insert at beginning of line |
| a | Append after cursor |
| A | Append at end of line |
| o | Open new line below |
| O | Open new line above |
| s | Substitute character (delete & insert) |
| S | Substitute entire line |
| Key | Action | Mnemonic |
|---|---|---|
| h | Move left | left |
| j | Move down | down (j hangs down) |
| k | Move up | up (k points up) |
| l | Move right | right |
| Key | Action |
|---|---|
| w | Next word (start) |
| W | Next WORD (whitespace-separated) |
| e | End of word |
| E | End of WORD |
| b | Back to start of word |
| B | Back to start of WORD |
| Key | Action |
|---|---|
| 0 | Start of line |
| ^ | First non-blank character |
| $ | End of line |
| g_ | Last non-blank character |
| Key | Action |
|---|---|
| gg | Go to first line |
| G | Go to last line |
| :n | Go to line n |
| Ctrl+d | Scroll down half page |
| Ctrl+u | Scroll up half page |
| Ctrl+f | Scroll forward full page |
| Ctrl+b | Scroll backward full page |
| H | Top of screen (High) |
| M | Middle of screen |
| L | Bottom of screen (Low) |
| zz | Center cursor on screen |
Prefix any motion with a number: 5j = move 5 lines down, 3w = move 3 words forward, 10G = go to line 10.
| Command | Action |
|---|---|
| x | Delete character under cursor |
| X | Delete character before cursor |
| dd | Delete entire line |
| D | Delete from cursor to end of line |
| dw | Delete word |
| d$ | Delete to end of line |
| d0 | Delete to start of line |
| dG | Delete to end of file |
| dgg | Delete to start of file |
Change = Delete + Enter Insert mode
| Command | Action |
|---|---|
| cc | Change entire line |
| C | Change from cursor to end of line |
| cw | Change word |
| ciw | Change inner word |
| ci" | Change inside quotes |
| ci( | Change inside parentheses |
| Command | Action |
|---|---|
| yy | Yank (copy) line |
| Y | Yank line (same as yy) |
| yw | Yank word |
| y$ | Yank to end of line |
| p | Paste after cursor |
| P | Paste before cursor |
| Command | Action |
|---|---|
| u | Undo |
| Ctrl+r | Redo |
| U | Undo all changes on line |
| . | Repeat last command (useful) |
The . command repeats your last change. Example: ciwhelloEsc then navigate to another word and press . to replace it with "hello" too.
Operator + Motion = Action
# Operators
d = delete
c = change
y = yank (copy)
v = visual select
> = indent right
< = indent left
# Formula: operator + [count] + motion
d2w = delete 2 words
c3j = change 3 lines down
y5l = yank 5 characters right
Text objects let you operate on semantic units of text.
| Object | Meaning | Example |
|---|---|---|
| iw | inner word | diw = delete word |
| aw | a word (includes space) | daw = delete word + space |
| is | inner sentence | cis = change sentence |
| ip | inner paragraph | yip = yank paragraph |
| i" | inside quotes | ci" = change inside quotes |
| a" | around quotes | da" = delete including quotes |
| i( | inside parentheses | di( = delete inside parens |
| i{ | inside curly braces | ci{ = change inside braces |
| i[ | inside brackets | yi[ = yank inside brackets |
| it | inside HTML tag | cit = change tag content |
| at | around HTML tag | dat = delete entire tag |
Instead of moving character by character, use ci" anywhere inside quotes to change that quoted text. dap deletes a whole paragraph. These are small commands, but they remove a lot of repeated movement.
| Command | Action |
|---|---|
| f{char} | Jump to next {char} on line |
| F{char} | Jump to previous {char} |
| t{char} | Jump till (before) next {char} |
| T{char} | Jump till previous {char} |
| ; | Repeat last f/t motion |
| , | Repeat f/t in reverse direction |
# Delete until comma
dt,
# Change to next quote
ct"
# Delete including the comma
df,
| Command | Action |
|---|---|
| /pattern | Search forward |
| ?pattern | Search backward |
| n | Next match |
| N | Previous match |
| * | Search word under cursor (forward) |
| # | Search word under cursor (backward) |
# Basic syntax
:s/old/new/ # Replace first on current line
:s/old/new/g # Replace all on current line
:%s/old/new/g # Replace all in file
:%s/old/new/gc # Replace all with confirmation
# Case insensitive
:%s/old/new/gi
# Replace in range (lines 5-20)
:5,20s/old/new/g
# Replace in visual selection
:'<,'>s/old/new/g
# Word boundaries
/\ # Exact word match
# Case insensitive
/pattern\c
# Very magic mode (better regex)
/\v(pattern1|pattern2)
After searching, clear the highlight with :noh or :nohlsearch. If you search often, map this to a key like <leader>h.
| Key | Mode | Use Case |
|---|---|---|
| v | Character-wise | Select characters |
| V | Line-wise | Select entire lines |
| Ctrl+v | Block (column) | Select columns/rectangles |
# Select and operate
v + motion + operator
viw + y # Select inner word, yank
V5j + d # Select 5 lines, delete
# Block mode magic (Ctrl+v)
Ctrl+v + 3j + I + // + Esc # Comment 4 lines
Ctrl+v + 3j + $ + A + ; + Esc # Add semicolon to 4 lines
Ctrl+v lets you edit multiple lines at once. Select a column, press I to insert, type text, press Esc - text appears on all selected lines.
| Command | Action |
|---|---|
| o | Move to other end of selection |
| O | Move to other corner (block mode) |
| gv | Reselect last visual selection |
| > | Indent selection |
| < | Unindent selection |
| = | Auto-indent selection |
| ~ | Toggle case |
| U | Uppercase |
| u | Lowercase |
Vim has multiple "clipboards" called registers.
| Register | Description |
|---|---|
| " | Default (unnamed) register |
| 0 | Yank register (last yanked text) |
| 1-9 | Delete history (1 = most recent) |
| a-z | Named registers (you control) |
| A-Z | Append to named register |
| + | System clipboard |
| * | Primary selection (X11) |
| _ | Black hole (delete without saving) |
| / | Last search pattern |
# View all registers
:registers
:reg
# Yank to register a
"ayy
# Paste from register a
"ap
# Yank to system clipboard
"+yy
# Paste from system clipboard
"+p
# Delete without affecting registers
"_dd
When you yank text, it goes to register 0. When you delete, it goes to ". Use "0p to paste your last yank even after deleting!
Macros record keystrokes and replay them. This is useful when the same edit repeats across many lines.
# 1. Start recording to register q
qq
# 2. Perform your actions
...edit commands...
# 3. Stop recording
q
# 4. Replay macro
@q
# 5. Replay again
@@
# 6. Replay 10 times
10@q
# Starting position: cursor on first line
qq # Start recording
A; # Go to end, insert semicolon
Esc # Exit insert mode
j # Move to next line
q # Stop recording
99@q # Apply to next 99 lines
1. Start macros at line beginning (0) or on a word (b)
2. Use /pattern<CR> to jump consistently
3. End with motion to next target for chaining
4. Save macros in your vimrc: let @q = 'A;^[j'
# List buffers
:ls
:buffers
# Switch buffers
:b [number] # Go to buffer number
:b [name] # Go to buffer by name
:bn # Next buffer
:bp # Previous buffer
:bd # Delete (close) buffer
# Open file in new buffer
:e filename
# Split windows
:sp [file] # Horizontal split
:vsp [file] # Vertical split
Ctrl+w s # Horizontal split
Ctrl+w v # Vertical split
# Navigate windows
Ctrl+w h # Move left
Ctrl+w j # Move down
Ctrl+w k # Move up
Ctrl+w l # Move right
Ctrl+w w # Cycle windows
# Resize
Ctrl+w = # Equal size
Ctrl+w > # Wider
Ctrl+w < # Narrower
Ctrl+w + # Taller
Ctrl+w - # Shorter
# Close
:q # Close window
:only # Close all other windows
:tabnew [file] # New tab
:tabn # Next tab
:tabp # Previous tab
gt # Next tab
gT # Previous tab
:tabclose # Close tab
# Vim
~/.vimrc # Linux/Mac
~/_vimrc # Windows
# Neovim
~/.config/nvim/init.vim # Vimscript
~/.config/nvim/init.lua # Lua (recommended)
" Basic settings
set nocompatible
set number relativenumber " Line numbers
set tabstop=4 " Tab width
set shiftwidth=4 " Indent width
set expandtab " Spaces instead of tabs
set autoindent " Auto indent
set smartindent " Smart indent
set wrap " Wrap lines
set linebreak " Wrap at word boundaries
" Search
set ignorecase " Case insensitive
set smartcase " Unless uppercase used
set hlsearch " Highlight matches
set incsearch " Incremental search
" UI
set cursorline " Highlight current line
set showmatch " Show matching brackets
set wildmenu " Command completion
set scrolloff=8 " Keep 8 lines visible
set signcolumn=yes " Always show sign column
set colorcolumn=80 " Show column marker
" Performance
set lazyredraw " Don't redraw during macros
set updatetime=300 " Faster updates
" Key mappings
let mapleader = " " " Space as leader
inoremap jk <Esc> " jk to escape
nnoremap <leader>w :w<CR> " Quick save
nnoremap <leader>h :noh<CR> " Clear search
-- Basic options
vim.opt.number = true
vim.opt.relativenumber = true
vim.opt.tabstop = 4
vim.opt.shiftwidth = 4
vim.opt.expandtab = true
vim.opt.smartindent = true
vim.opt.cursorline = true
vim.opt.ignorecase = true
vim.opt.smartcase = true
-- Leader key
vim.g.mapleader = " "
-- Key mappings
vim.keymap.set('i', 'jk', '<Esc>')
vim.keymap.set('n', '<leader>w', ':w<CR>')
vim.keymap.set('n', '<leader>h', ':noh<CR>')
| Manager | For |
|---|---|
| vim-plug | Vim & Neovim |
| packer.nvim | Neovim (Lua) |
| lazy.nvim | Neovim (modern, recommended) |
| Plugin | Purpose |
|---|---|
| nvim-treesitter | Better syntax highlighting |
| nvim-lspconfig | Language Server Protocol |
| telescope.nvim | Fuzzy finder (files, grep, etc.) |
| nvim-cmp | Autocompletion |
| nvim-tree / neo-tree | File explorer |
| lualine.nvim | Status line |
| gitsigns.nvim | Git integration |
| vim-surround | Surround text objects |
| comment.nvim | Easy commenting |
| which-key.nvim | Keybinding hints |
You do not have to build from scratch. Try these preconfigured Neovim distros:
- LazyVim - Modern, fast, well-maintained
- NvChad - Beautiful, beginner-friendly
- AstroNvim - Feature-rich, extensible
- LunarVim - IDE-like experience
ciw, dap, and yi" instead of selecting manually5dd, 3yy, or 10j when you need repetition.inoremap jk <Esc>
This keeps the escape action close to the home row.
let mapleader = " "
nnoremap <leader>w :w<CR> " Save
nnoremap <leader>q :q<CR> " Quit
nnoremap <leader>e :Ex<CR> " File explorer
/ and ? # Search to jump
* # Jump to word under cursor
f and t # Line-level precision
{ } # Jump paragraphs
]] [[ # Jump sections/functions
gd # Go to definition
Ctrl+o Ctrl+i # Jump list back/forward
ma # Set mark 'a' at cursor
'a # Jump to line of mark 'a'
`a # Jump to exact position of mark 'a'
'' # Jump to last position
'. # Jump to last edit
These commands are worth practicing first:
ciw # Change word (anywhere in word)
ci" # Change inside quotes
ci( # Change inside parentheses
ci{ # Change inside braces
cit # Change inside HTML tag
~ # Toggle case of character
xp # Swap two characters
ddp # Swap two lines
J # Join lines
gU{motion} # Uppercase
gu{motion} # Lowercase
:g/pattern/d # Delete all lines matching pattern
:g!/pattern/d # Delete lines NOT matching
:g/pattern/normal A; # Append ; to matching lines
Level 1: hjkl instead of arrows
Level 2: word motions (w, b, e)
Level 3: text objects (ciw, ci", dap)
Level 4: search/find motions (/, f, t)
Level 5: marks and jumps
Level 6: macros and global commands
Final step: Thinking in Vim grammar
Open a file with 50+ lines. Navigate using only hjkl for 5 minutes. Use hjkl only for this drill.
Goal: Build muscle memory for basic movement.
Move through a paragraph using only w, b, and e. Count how many keystrokes to get from start to end.
Create lines of text. Practice: dd, 3dd, dw, d$, d0
Given: const name = "John Doe";
Change "John Doe" to "Jane Smith" using only ci"
Given a function with content in curly braces:
function test() { old content here }
Replace all content inside {} using ci{
Replace all occurrences of "foo" with "bar" in a file.
:%s/foo/bar/g
Add // comment prefix to 10 consecutive lines using Ctrl+v
Ctrl+v -> 9j -> I -> // -> Esc
You have 20 lines like: item1, item2...
Convert all to: - [ ] item1
Record macro, apply to all lines.
qq0i- [ ] <Esc>jq
19@q
Yank a line to register "a", yank another to "b". Paste both in different locations.
"ayy # Yank to a
"byy # Yank to b
"ap # Paste from a
"bp # Paste from b
Change "old" to "new" on 5 different lines using ciw once, then n. for others.
/old<CR> # Find first
ciwnew<Esc> # Change it
n. # Find next, repeat change
n. # Repeat...
vimtutor in terminal (built in)| Command | Action |
|---|---|
| :w | Save |
| :q | Quit |
| :wq | Save and quit |
| :q! | Quit without saving |
| u | Undo |
| Ctrl+r | Redo |
| Esc | Return to Normal mode |
| Command | Action |
|---|---|
| hjkl | Left/Down/Up/Right |
| w / b | Next/Previous word |
| 0 / $ | Start/End of line |
| gg / G | Start/End of file |
| Ctrl+d / Ctrl+u | Half page down/up |
| f{char} / t{char} | Find/Till character |
| Command | Action |
|---|---|
| i / a | Insert before/after cursor |
| o / O | New line below/above |
| dd / yy / p | Delete/Yank/Paste line |
| ciw / diw | Change/Delete inner word |
| ci" / di" | Change/Delete inside quotes |
| . | Repeat last change |
| Command | Action |
|---|---|
| /pattern | Search forward |
| n / N | Next/Previous match |
| * | Search word under cursor |
| :%s/old/new/g | Replace all |
| Command | Action |
|---|---|
| :sp / :vsp | Horizontal/Vertical split |
| Ctrl+w hjkl | Navigate splits |
| Ctrl+w q | Close split |
Vim practice takes time. Learn one small command, use it for real edits, and let the habit build slowly. The goal is not to memorize everything at once.
Keep practicing. The goal is controlled, confident editing, not memorizing every command at once.