Skip to content

Vim Setup

Published: February 25, 2026 · Last edited: February 25, 2026

A practical Vim configuration that gives you visual feedback, prevents common mistakes, and gets out of your way.

Core Philosophy

  • Always know your state — mode, file status, and cursor position always visible
  • Sensible defaults — every setting has a clear reason; no cargo-culting
  • Safety nets — persistent undo, central backups, no silent overwrites
  • Muscle memory over mnemonics — keymaps grouped by how you actually work
  • Minimal plugins, maximum value — only add a plugin if it removes daily friction

1. Installation

bash
# macOS
brew install vim

# Ubuntu/Debian
sudo apt install vim

# Check version (Vim 8+ recommended for async support)
vim --version | head -1

If you're on macOS, the system Vim is old. Use the Homebrew version.

2. Core .vimrc

Create ~/.vimrc:

vim
" ============================================================
" GENERAL
" ============================================================

set nocompatible              " Be Vim, not Vi
filetype plugin indent on     " Enable filetype detection
syntax on                     " Syntax highlighting

set encoding=utf-8            " Always UTF-8
set history=10000             " Long undo history across sessions
set autoread                  " Reload file if changed outside Vim
set hidden                    " Allow switching buffers without saving


" ============================================================
" VISUAL FEEDBACK
" ============================================================

set number                    " Show absolute line number on current line
set relativenumber            " Show relative line numbers for easy jumps
set cursorline                " Highlight the current line
set showcmd                   " Show partial command in bottom bar
set showmatch                 " Highlight matching bracket
set laststatus=2              " Always show status line
set ruler                     " Show line/column in status line
set wildmenu                  " Visual autocomplete for command menu
set scrolloff=8               " Keep 8 lines visible above/below cursor
set sidescrolloff=5           " Keep 5 columns visible left/right


" ============================================================
" STATUS LINE
" ============================================================

set statusline=               " Reset
set statusline+=%#PmenuSel#   " Colour: active
set statusline+=\ %f\         " Filename (relative)
set statusline+=%m            " Modified flag [+]
set statusline+=%r            " Readonly flag [RO]
set statusline+=%=            " Switch to right side
set statusline+=%y\           " Filetype [python]
set statusline+=L%l/%L\       " Current line / total lines
set statusline+=C%c\          " Column number


" ============================================================
" SEARCH
" ============================================================

set incsearch                 " Search as you type
set hlsearch                  " Highlight all matches
set ignorecase                " Case-insensitive search...
set smartcase                 " ...unless you type a capital letter

" Clear search highlight with Enter
nnoremap <CR> :nohlsearch<CR><CR>


" ============================================================
" INDENTATION
" ============================================================

set expandtab                 " Use spaces, not tabs
set tabstop=4                 " Display tabs as 4 spaces
set shiftwidth=4              " Indent/dedent by 4 spaces
set softtabstop=4             " Backspace deletes 4 spaces at a time
set autoindent                " Maintain indent from previous line
set smartindent               " Indent after { and before }

" Two-space indent for common web/config files
autocmd FileType yaml,json,html,css,javascript,typescript setlocal
    \ tabstop=2 shiftwidth=2 softtabstop=2


" ============================================================
" SAFETY NETS
" ============================================================

" Central backup and undo directories — keep project dirs clean
silent !mkdir -p ~/.vim/backup ~/.vim/swap ~/.vim/undo
set backupdir=~/.vim/backup//
set directory=~/.vim/swap//
set undodir=~/.vim/undo//

set undofile                  " Persist undo history across sessions
set undolevels=10000          " Deep undo
set noswapfile                " Skip swap files (undo file is enough)
set writebackup               " Write backup before saving, remove after


" ============================================================
" BEHAVIOUR
" ============================================================

set backspace=indent,eol,start  " Backspace works as expected in insert mode
set clipboard=unnamed           " Use system clipboard (macOS / X11 with +clipboard)
set splitright                  " New vertical splits open to the right
set splitbelow                  " New horizontal splits open below
set nowrap                      " Don't wrap long lines
set list                        " Show invisible characters
set listchars=tab:›\ ,trail:·,nbsp:·   " Mark tabs, trailing spaces


" ============================================================
" KEY MAPPINGS
" ============================================================

" Leader key — space is easiest to reach
let mapleader = " "

" Fast save and quit
nnoremap <leader>w :w<CR>
nnoremap <leader>q :q<CR>
nnoremap <leader>Q :q!<CR>

" Save as sudo if you forgot to open with sudo
cnoremap w!! execute 'silent! write !sudo tee % >/dev/null' <bar> edit!

" Navigate splits with Ctrl+hjkl (no need for Ctrl+W first)
nnoremap <C-h> <C-w>h
nnoremap <C-j> <C-w>j
nnoremap <C-k> <C-w>k
nnoremap <C-l> <C-w>l

" Move lines up and down in visual mode with J/K
vnoremap J :m '>+1<CR>gv=gv
vnoremap K :m '<-2<CR>gv=gv

" Keep cursor centred when jumping
nnoremap <C-d> <C-d>zz
nnoremap <C-u> <C-u>zz
nnoremap n nzzzv
nnoremap N Nzzzv

" Paste without replacing the register in visual mode
vnoremap <leader>p "_dP

" Yank to end of line (consistent with D and C)
nnoremap Y y$

" Indent without losing selection
vnoremap < <gv
vnoremap > >gv

" Next/previous buffer
nnoremap <leader>] :bnext<CR>
nnoremap <leader>[ :bprev<CR>

" Toggle line numbers between absolute and relative
nnoremap <leader>n :set relativenumber!<CR>

" Toggle word wrap
nnoremap <leader>W :set wrap!<CR>

" Open netrw file browser in the current window
nnoremap <leader>e :Explore<CR>

3. Plugin Setup

Use vim-plug — one file, no dependencies.

Install vim-plug

bash
curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
    https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim

Add to ~/.vimrc (before other config)

vim
" ============================================================
" PLUGINS
" ============================================================

call plug#begin('~/.vim/plugged')

" Fuzzy file/buffer/history search (integrates with fzf from CLI setup)
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
Plug 'junegunn/fzf.vim'

" gc to comment/uncomment lines and motions
Plug 'tpope/vim-commentary'

" cs, ds, ys to change/delete/add surrounding brackets/quotes
Plug 'tpope/vim-surround'

" Shows git diff in the gutter (+, -, ~)
Plug 'airblade/vim-gitgutter'

" Color scheme
Plug 'morhetz/gruvbox'

call plug#end()

Install plugins: open Vim and run :PlugInstall

Plugin Key Mappings

Add after the call plug#end() line:

vim
" --- FZF ---
nnoremap <leader>f :Files<CR>       " Fuzzy-find files
nnoremap <leader>b :Buffers<CR>     " Fuzzy-find open buffers
nnoremap <leader>r :Rg<CR>          " Ripgrep across project
nnoremap <leader>h :History<CR>     " Recently opened files

" --- Gruvbox ---
set background=dark
colorscheme gruvbox

4. Netrw File Browser

Vim's built-in file browser is good enough for most tasks. No plugin needed.

vim
" Add to ~/.vimrc
let g:netrw_banner = 0          " Hide the help banner
let g:netrw_liststyle = 3       " Tree view
let g:netrw_winsize = 25        " 25% width when split

Useful commands inside netrw:

KeyAction
<Enter>Open file
vOpen in vertical split
oOpen in horizontal split
tOpen in new tab
dCreate directory
%Create new file
DDelete file/directory
RRename file
-Go up one directory

5. Complete .vimrc

The sections above are meant to be read in order, but here is everything in one block ready to paste:

vim
" ============================================================
" PLUGINS
" ============================================================

call plug#begin('~/.vim/plugged')
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
Plug 'junegunn/fzf.vim'
Plug 'tpope/vim-commentary'
Plug 'tpope/vim-surround'
Plug 'airblade/vim-gitgutter'
Plug 'morhetz/gruvbox'
call plug#end()


" ============================================================
" GENERAL
" ============================================================

set nocompatible
filetype plugin indent on
syntax on
set encoding=utf-8
set history=10000
set autoread
set hidden


" ============================================================
" VISUAL FEEDBACK
" ============================================================

set number
set relativenumber
set cursorline
set showcmd
set showmatch
set laststatus=2
set ruler
set wildmenu
set scrolloff=8
set sidescrolloff=5


" ============================================================
" STATUS LINE
" ============================================================

set statusline=
set statusline+=%#PmenuSel#
set statusline+=\ %f\
set statusline+=%m
set statusline+=%r
set statusline+=%=
set statusline+=%y\
set statusline+=L%l/%L\
set statusline+=C%c\


" ============================================================
" SEARCH
" ============================================================

set incsearch
set hlsearch
set ignorecase
set smartcase
nnoremap <CR> :nohlsearch<CR><CR>


" ============================================================
" INDENTATION
" ============================================================

set expandtab
set tabstop=4
set shiftwidth=4
set softtabstop=4
set autoindent
set smartindent
autocmd FileType yaml,json,html,css,javascript,typescript setlocal
    \ tabstop=2 shiftwidth=2 softtabstop=2


" ============================================================
" SAFETY NETS
" ============================================================

silent !mkdir -p ~/.vim/backup ~/.vim/swap ~/.vim/undo
set backupdir=~/.vim/backup//
set directory=~/.vim/swap//
set undodir=~/.vim/undo//
set undofile
set undolevels=10000
set noswapfile
set writebackup


" ============================================================
" BEHAVIOUR
" ============================================================

set backspace=indent,eol,start
set clipboard=unnamed
set splitright
set splitbelow
set nowrap
set list
set listchars=tab:›\ ,trail:·,nbsp:·


" ============================================================
" KEY MAPPINGS
" ============================================================

let mapleader = " "

nnoremap <leader>w :w<CR>
nnoremap <leader>q :q<CR>
nnoremap <leader>Q :q!<CR>
cnoremap w!! execute 'silent! write !sudo tee % >/dev/null' <bar> edit!

nnoremap <C-h> <C-w>h
nnoremap <C-j> <C-w>j
nnoremap <C-k> <C-w>k
nnoremap <C-l> <C-w>l

vnoremap J :m '>+1<CR>gv=gv
vnoremap K :m '<-2<CR>gv=gv

nnoremap <C-d> <C-d>zz
nnoremap <C-u> <C-u>zz
nnoremap n nzzzv
nnoremap N Nzzzv

vnoremap <leader>p "_dP
nnoremap Y y$
vnoremap < <gv
vnoremap > >gv

nnoremap <leader>] :bnext<CR>
nnoremap <leader>[ :bprev<CR>
nnoremap <leader>n :set relativenumber!<CR>
nnoremap <leader>W :set wrap!<CR>
nnoremap <leader>e :Explore<CR>


" ============================================================
" PLUGINS CONFIG
" ============================================================

" FZF
nnoremap <leader>f :Files<CR>
nnoremap <leader>b :Buffers<CR>
nnoremap <leader>r :Rg<CR>
nnoremap <leader>h :History<CR>

" Netrw
let g:netrw_banner = 0
let g:netrw_liststyle = 3
let g:netrw_winsize = 25

" Gruvbox
set background=dark
colorscheme gruvbox

6. Daily Workflow Tips

  1. Open a project: vim . opens netrw; press <leader>e inside Vim to return to it
  2. Find a file fast: <leader>f fuzzy-finds files, <leader>r searches file contents
  3. Jump around: <leader>h shows recently opened files
  4. Work in splits: Ctrl+W v for vertical, Ctrl+W s for horizontal; navigate with Ctrl+hjkl
  5. Undo anything: :earlier 5m takes you back 5 minutes; undo survives closing Vim
  6. Comment out quickly: gcc toggles a line, gc5j comments 5 lines down

7. Customization

Adjust based on your habits:

  • Tab width: Change shiftwidth and tabstop for your preferred indentation
  • Color scheme: Try :colorscheme + Tab to cycle through installed themes
  • Wrap long lines: :set wrap linebreak for prose; unwrap for code
  • Clipboard: If set clipboard=unnamed doesn't work on Linux, try set clipboard=unnamedplus
  • Language servers: Add vim-lsp if you want IDE-style completion

Remember: add to this config only when you hit friction, not before.