Vim
Vim is a modal text editor. Mainstream text editing paradigms dictate that the keyboard constantly inputs text, relying on modifier keys (Ctrl, Alt) to invoke commands. Vim inverts this architecture. The keyboard’s default state is Command mode: every key functions as a verb, a motion, or an operator. You enter text only by explicitly stepping into Insert mode. When the edit is complete, you leave.
This inversion drives Vim’s efficiency. It operates like a biological reflex arc: Normal mode is the resting state; Insert mode is deliberate action. The transition between them is fast, intentional, and entirely reversible. Mainstream editors optimize for typing. Vim optimizes for navigating and transforming code, aligning perfectly with how developers actually spend their time.
Neovim is the modern continuation of Vim. It preserves complete compatibility while introducing a native Lua API, a built-in LSP client, Tree-sitter integration, asynchronous job control, and a vastly superior plugin ecosystem. For any new setup, Neovim is the required standard. All commands in this manual apply to Neovim unless explicitly stated otherwise.
1. Installation
Alpine Linux
# Vim
apk add vim
# Neovim
apk add neovim
Arch Linux
# Vim
sudo pacman -S vim
# Neovim
sudo pacman -S neovim
# Optional: language support dependencies
sudo pacman -S python-pynvim nodejs npm
Ubuntu / Debian
# Vim
sudo apt install vim
# Neovim (stable from apt -- may be outdated)
sudo apt install neovim
# Neovim (latest release via PPA -- recommended)
sudo add-apt-repository ppa:neovim-ppa/stable
sudo apt update && sudo apt install neovim
# Python provider
sudo apt install python3-neovim
pip3 install pynvim
Rocky Linux / RHEL
# Vim
sudo dnf install vim-enhanced
# Neovim (via EPEL or direct)
sudo dnf install epel-release
sudo dnf install neovim
# Neovim latest (download AppImage from GitHub releases as alternative)
curl -LO https://github.com/neovim/neovim/releases/latest/download/nvim-linux-x86_64.appimage
chmod +x nvim-linux-x86_64.appimage
sudo mv nvim-linux-x86_64.appimage /usr/local/bin/nvim
Post-Install: Check Health (Neovim)
nvim
:checkhealth
This runs Neovim’s self-diagnostic. Fix any warnings about providers or missing tools.
2. The Modal System
Vim has several modes. Understanding them completely is understanding Vim.
| Mode | How to Enter | Description |
|---|---|---|
| Normal | Esc / Ctrl+[ | Default. Keys are commands, not text. |
| Insert | i, a, o, I, A, O, s, c | Keys input text. |
| Visual | v, V, Ctrl+V | Select text regions. |
| Visual Line | V | Select whole lines. |
| Visual Block | Ctrl+V | Select rectangular blocks. |
| Command | : | Run Ex commands. |
| Replace | R | Overwrite characters as you type. |
| Operator-pending | After an operator (d, y, c) | Waiting for a motion. |
Always return to Normal mode with Esc. Get in the habit. In Neovim, Ctrl+[ is equivalent and faster on standard keyboards.
3. Opening and Closing
Open a file:
vim filename
nvim filename
Open multiple files in buffers:
nvim file1 file2 file3
Open in a split:
nvim -O file1 file2 # vertical split
nvim -o file1 file2 # horizontal split
Open at a specific line:
nvim +42 filename
nvim +/searchterm filename # open at first match
Open read-only:
nvim -R filename
view filename
Closing
Quit (no unsaved changes):
:q
Save and quit:
:wq
:x (save only if changed, then quit -- preferred)
ZZ (same as :x from Normal mode)
Quit without saving:
:q!
ZQ
Quit all buffers:
:qa
:qa! (discard all)
Save without quitting:
:w
:w filename (save to a new file)
:w !sudo tee % (save as root when you forgot to open with sudo)
4. Movement – Normal Mode
Character Movement
h left
l right
j down
k up
Word Movement
w forward to start of next word
W forward to start of next WORD (space-delimited)
b backward to start of previous word
B backward to start of previous WORD
e forward to end of current/next word
E forward to end of current/next WORD
ge backward to end of previous word
Word = alphanumeric + underscore. WORD = any non-whitespace sequence.
Line Movement
0 start of line (column 0)
^ first non-blank character of line
$ end of line
g_ last non-blank character of line
| column 1 (or N| for column N)
Screen / File Movement
gg go to first line
G go to last line
42G go to line 42
:42 go to line 42 (command mode)
H top of screen (High)
M middle of screen (Middle)
L bottom of screen (Low)
Ctrl+F page forward (down)
Ctrl+B page backward (up)
Ctrl+D half-page down
Ctrl+U half-page up
Ctrl+E scroll screen down one line (cursor stays)
Ctrl+Y scroll screen up one line (cursor stays)
zz centre current line on screen
zt scroll current line to top
zb scroll current line to bottom
Search-Based Movement
f{char} find {char} forward on line (cursor lands on it)
F{char} find {char} backward on line
t{char} till {char} forward (cursor stops before it)
T{char} till {char} backward
; repeat last f/F/t/T forward
, repeat last f/F/t/T backward
Paragraph / Section Movement
{ move to previous empty line (paragraph start)
} move to next empty line (paragraph end)
move to previous section (function, etc.)
move to next section
[] move to end of previous section
][ move to start of next section
Marks
m{a-z} set mark {a-z} at cursor (local to file)
m{A-Z} set global mark (works across files)
'{mark} jump to line of mark
`{mark} jump to exact position of mark
'' jump back to position before last big jump
`` exact position of last big jump
'. jump to last edit position
5. Entering Insert Mode
Every method puts you in insert mode at a different cursor position:
i insert before cursor
a insert after cursor (append)
I insert at first non-blank of line
A insert at end of line
o open new line below and insert
O open new line above and insert
s substitute character (delete char under cursor, enter insert)
S substitute line (clear line, enter insert) -- same as cc
gi insert at last insert position
Useful shortcuts inside Insert mode:
Ctrl+H delete character before cursor (backspace)
Ctrl+W delete word before cursor
Ctrl+U delete to beginning of line
Ctrl+T indent current line
Ctrl+D dedent current line
Ctrl+N autocomplete (next match)
Ctrl+P autocomplete (previous match)
Ctrl+R {reg} insert content of register
Ctrl+O execute one Normal mode command, return to Insert
6. Operators, Motions, and Text Objects
Vim’s grammar: [count] operator [motion/text object]
Operators
d delete (cuts to register)
y yank (copy)
c change (delete + enter insert)
> indent right
< indent left
= auto-indent
! filter through external command
gU uppercase
gu lowercase
g~ toggle case
Operator + Motion Examples
dw delete from cursor to start of next word
db delete back to start of previous word
d$ delete to end of line
d^ delete to first non-blank of line
d0 delete to start of line
5dw delete 5 words
yy yank current line
y3j yank current line + 3 below (4 lines total)
cc change entire line
cw change word (from cursor to end of word)
>> indent current line
3>> indent 3 lines
gU$ uppercase to end of line
Text Objects
Text objects are semantic selections – they understand brackets, quotes, words, paragraphs.
Pattern: {operator}i{object} (inside) or {operator}a{object} (around/including delimiters).
iw inner word
aw a word (includes surrounding whitespace)
iW inner WORD
aW a WORD
is inner sentence
as a sentence
ip inner paragraph
ap a paragraph
i( inner parentheses (also: ib)
a( around parentheses (includes the parens)
i[ inner square brackets
a[ around square brackets
i{ inner curly braces (also: iB)
a{ around curly braces
i" inner double quotes
a" around double quotes (includes the quotes)
i' inner single quotes
a' around single quotes
i` inner backticks
a` around backticks
it inner tag (HTML/XML)
at around tag
Examples:
di" delete everything inside double quotes
da" delete including the double quotes
ci( change everything inside parentheses
yi{ yank everything inside curly braces
>ap indent a paragraph
=i{ auto-indent contents of curly braces
7. Deleting, Yanking, Pasting
Deleting
x delete character under cursor
X delete character before cursor
dd delete current line
D delete from cursor to end of line
dG delete from current line to end of file
dgg delete from current line to start of file
Yanking (Copying)
yy yank current line (also: Y)
yw yank from cursor to start of next word
y$ yank to end of line
y^ yank to first non-blank
yG yank to end of file
Pasting
p paste after cursor (or below current line for line yanks)
P paste before cursor (or above current line for line yanks)
gp paste after and move cursor to end of pasted text
gP paste before and move cursor to end of pasted text
]p paste with indentation adjusted to current context
Registers
Vim/Neovim have named registers – persistent clipboards.
"{a-z} use named register a-z for next yank/delete/paste
"" unnamed register (default)
"0 yank register (only updated by y, not d)
"* system primary clipboard (X11 selection)
"+ system clipboard (Ctrl+C/Ctrl+V clipboard)
". last inserted text
"% current file name
"# alternate file name
": last command
"/ last search pattern
"_ black hole register (discard)
Examples:
"ayy yank current line into register a
"ap paste from register a
"+yy yank current line to system clipboard
"+p paste from system clipboard
"_dd delete line without overwriting default register
View register contents:
:registers
:reg a b c (show specific registers)
8. Undo and Redo
u undo
Ctrl+R redo
U undo all changes on current line (one step in undo tree)
Vim and Neovim have a full undo tree – branching history, not linear. The undotree plugin makes this visual.
Persistent undo (changes survive file close):
set undofile
set undodir=~/.vim/undodir " Vim
-- Neovim: vim.opt.undodir = vim.fn.stdpath('data') .. '/undodir'
9. Visual Mode
Visual mode lets you select a region, then apply an operator.
v character-wise visual
V line-wise visual
Ctrl+V block-wise visual
gv re-select last visual selection
o move to other end of selection
O in block mode: move to other corner
Visual Mode Operations
d / x delete selection
y yank selection
c change selection (delete + insert)
> indent selection
< dedent selection
= auto-indent selection
! filter through external command
U uppercase selection
u lowercase selection
~ toggle case
r{char} replace all chars in selection with {char}
Visual Block Mode (Ctrl+V)
Extremely useful for editing columns, comment/uncomment multiple lines, and inserting text at identical positions.
Insert the same text on multiple lines:
Ctrl+V select block (move down with j)
I enter insert at block start
type text
Esc text is inserted on all selected lines
Append text at end of multiple lines:
Ctrl+V select block
$ extend selection to end of each line
A append mode
type text
Esc
10. Search and Replace
Searching
/pattern search forward
?pattern search backward
n next match
N previous match
* search forward for word under cursor
# search backward for word under cursor
g* search forward for partial word under cursor
gd go to definition of word under cursor (local)
gD go to definition (global, file scope)
Clear search highlight:
:nohl
:nohlsearch
Patterns
Vim uses its own regex dialect. Key patterns:
. any character
* zero or more (greedy)
\+ one or more
\? zero or one
\{n,m\} n to m repetitions
^ start of line
$ end of line
\< start of word
\> end of word
\b word boundary (Neovim/very magic)
[abc] character class
[^abc] negated class
\d digit
\w word character
\s whitespace
\n newline
\t tab
Very magic mode (closer to PCRE – fewer escapes needed):
/\vpattern very magic (+ ? { } ( ) | don't need escaping)
Substitution
Basic substitute:
:s/old/new/ replace first match 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
:1,20s/old/new/g replace in lines 1-20
Substitute flags:
g global (all occurrences per line)
c confirm each
i case-insensitive
I case-sensitive (override ignorecase)
n count matches without replacing
e don't error if no match
Substitute with capture groups:
:%s/\(foo\)\(bar\)/\2\1/g swap foo and bar
:%s/\v(foo)(bar)/\2\1/g same with very magic
Case modifiers in replacement:
\u uppercase next character
\l lowercase next character
\U uppercase until \E
\L lowercase until \E
\E end case modification
:%s/\v(\w+)/\u\1/g capitalise first letter of every word
Delete blank lines:
:g/^$/d
Delete lines matching a pattern:
:g/pattern/d
Execute a command on all matching lines:
:g/pattern/command
:g/TODO/yank A (append all TODO lines to register a)
Execute on non-matching lines:
:v/pattern/d (delete lines that do NOT match)
:g!/pattern/d (same)
11. Multiple Files: Buffers, Windows, Tabs
Buffers
A buffer is an in-memory file. You can have hundreds open simultaneously.
:e filename open a file (new buffer)
:ls list all buffers
:buffers same
:b filename switch to buffer by name (tab-complete)
:b2 switch to buffer 2
:bn next buffer
:bp previous buffer
:bd delete (close) current buffer
:bd 2 close buffer 2
:bufdo %s/foo/bar/g run substitution on all buffers
Buffer status flags in :ls:
a active (loaded and visible)
h hidden (loaded, not visible)
% current buffer
# alternate buffer (last used)
+ modified (unsaved changes)
Windows (Splits)
:sp filename horizontal split, open file
:vsp filename vertical split, open file
Ctrl+W s horizontal split (same file)
Ctrl+W v vertical split (same file)
Ctrl+W h/j/k/l navigate to split in direction
Ctrl+W H/J/K/L move current split to direction
Ctrl+W = equalise all split sizes
Ctrl+W _ maximise current split height
Ctrl+W | maximise current split width
Ctrl+W +/- increase/decrease split height
Ctrl+W >/< increase/decrease split width
Ctrl+W r rotate splits
Ctrl+W o close all other windows (keep current)
:q close current window/split
Tabs
Tabs in Vim are layout containers, not file containers. Each tab can hold multiple splits.
:tabnew open new tab
:tabnew filename open file in new tab
:tabn next tab
:tabp previous tab
:tabclose close current tab
:tabonly close all other tabs
gt next tab (Normal mode)
gT previous tab (Normal mode)
{n}gt go to tab n
:tabs list all tabs
12. Macros
Macros record a sequence of keystrokes and replay them.
Record a macro into register a:
qa start recording into register a
... keystrokes ...
q stop recording
Replay the macro:
@a replay register a
@@ replay last-used macro
10@a replay 10 times
Recursive macro (replays itself until it fails):
qq record into q
... do some action...
@q (at the end of the macro, call itself)
q stop
@q run -- it repeats until a motion fails (e.g., j at end of file)
Edit a macro: yanks into a buffer, edit, yank back:
"ap paste macro a to a line
... edit it ...
"ayy yank the corrected macro back into register a
13. Indentation and Formatting
Indent Commands
>> indent current line
<< dedent current line
>% indent to matching bracket
=% auto-indent to matching bracket
=G auto-indent from cursor to end of file
gg=G auto-indent entire file
>ap indent a paragraph
Indentation Settings
set tabstop=4 " tab character = 4 spaces wide
set shiftwidth=4 " indent operation (>>) = 4 spaces
set expandtab " expand tab key to spaces
set softtabstop=4 " backspace deletes 4 spaces at once
set smartindent " language-aware auto-indent
set autoindent " carry indent from previous line
Neovim (Lua):
vim.opt.tabstop = 4
vim.opt.shiftwidth = 4
vim.opt.expandtab = true
vim.opt.softtabstop = 4
vim.opt.smartindent = true
Formatting Prose
Reflow current paragraph to textwidth:
gqap
Reflow visual selection:
gq
Set text width:
set textwidth=80
14. Folding
Folds collapse sections of the file to reduce visual noise.
zf{motion} create a fold manually
zd delete fold at cursor
zD delete all folds at cursor recursively
za toggle fold open/closed
zo open fold
zc close fold
zO open all folds under cursor recursively
zC close all folds under cursor recursively
zR open all folds in file
zM close all folds in file
zj move to next fold
zk move to previous fold
[z move to start of current fold
]z move to end of current fold
Fold methods:
set foldmethod=indent " fold by indentation (Python-friendly)
set foldmethod=syntax " fold by syntax (requires filetype plugin)
set foldmethod=marker " fold by {{{ and }}} markers
set foldmethod=manual " manually defined folds
set foldmethod=expr " fold by expression (Neovim tree-sitter)
15. The Command Line (:)
The : command line is where Ex commands run. It is a full command language.
File Operations
:e! reload file from disk (discard changes)
:w write/save
:wa write all buffers
:r filename read file content and insert below cursor
:r !command insert output of shell command
:!command run shell command (pause editor)
:.!command filter current line through shell command
:%!command filter entire file through shell command
Ranges
:1,10 command lines 1 to 10
:.,$ command current line to end
:'a,'b command from mark a to mark b
:% command entire file (shorthand for 1,$)
Useful Ex Commands
:sort sort lines
:sort! sort reversed
:sort u sort and remove duplicates
:sort n sort numerically
:center 80 centre lines within 80 columns
:left
:right
:retab convert tabs to spaces (or vice versa, per settings)
:set list show hidden characters (tabs, trailing spaces)
:set nolist
:echo &option print value of an option
:set option? same
:verbose set option? show where option was set (debug)
Shell Integration
:!ls -la run ls in a shell, display output
:r !ls -la insert ls output into buffer
:%!python3 filter entire file through python3
:shell open a subshell (Ctrl+D to return)
:terminal open a terminal buffer (Neovim)
16. Configuration
Vim: ~/.vimrc
" General
set nocompatible
set encoding=utf-8
set fileencoding=utf-8
set history=1000
set undofile
set undodir=~/.vim/undodir
" Appearance
set number
set relativenumber
set cursorline
set signcolumn=yes
set scrolloff=8
set colorcolumn=80
set termguicolors
syntax on
set background=dark
" Indentation
set tabstop=4
set shiftwidth=4
set expandtab
set smartindent
set autoindent
" Search
set hlsearch
set incsearch
set ignorecase
set smartcase
" Splits
set splitright
set splitbelow
" Line wrapping
set nowrap
set linebreak
" Performance
set lazyredraw
set updatetime=250
set timeoutlen=500
" File handling
set noswapfile
set nobackup
set autoread
" Clipboard
set clipboard=unnamedplus
" Wildmenu
set wildmenu
set wildmode=longest:full,full
" Show matching brackets
set showmatch
" Status line
set laststatus=2
set ruler
set showcmd
" Mouse
set mouse=a
Neovim: ~/.config/nvim/
Neovim uses Lua. Recommended structure:
~/.config/nvim/
├── init.lua
└── lua/
└── config/
├── options.lua
├── keymaps.lua
├── autocmds.lua
└── plugins/
└── init.lua (lazy.nvim plugin spec)
init.lua
require("config.options")
require("config.keymaps")
require("config.autocmds")
require("config.plugins")
options.lua
local opt = vim.opt
-- Encoding
opt.encoding = "utf-8"
opt.fileencoding = "utf-8"
-- Appearance
opt.number = true
opt.relativenumber = true
opt.cursorline = true
opt.signcolumn = "yes"
opt.scrolloff = 8
opt.colorcolumn = "80"
opt.termguicolors = true
opt.background = "dark"
opt.showmode = false -- mode shown by statusline instead
-- Indentation
opt.tabstop = 4
opt.shiftwidth = 4
opt.expandtab = true
opt.smartindent = true
opt.autoindent = true
-- Search
opt.hlsearch = true
opt.incsearch = true
opt.ignorecase = true
opt.smartcase = true
-- Splits
opt.splitright = true
opt.splitbelow = true
-- Line wrap
opt.wrap = false
opt.linebreak = true
-- Performance
opt.updatetime = 100
opt.timeoutlen = 400
-- Files
opt.swapfile = false
opt.backup = false
opt.undofile = true
opt.undodir = vim.fn.stdpath("data") .. "/undodir"
opt.autoread = true
-- Clipboard
opt.clipboard = "unnamedplus"
-- Completion
opt.completeopt = { "menuone", "noselect" }
opt.pumheight = 10
-- Wildmenu
opt.wildmode = "longest:full,full"
-- Folding (tree-sitter-aware in Neovim)
opt.foldmethod = "expr"
opt.foldexpr = "nvim_treesitter#foldexpr()"
opt.foldenable = false -- start with all folds open
opt.foldlevel = 99
-- Misc
opt.mouse = "a"
opt.showmatch = true
opt.laststatus = 3 -- global statusline (Neovim 0.7+)
opt.conceallevel = 0
opt.pumblend = 10
opt.winblend = 10
keymaps.lua
local map = vim.keymap.set
-- Leader
vim.g.mapleader = " "
vim.g.maplocalleader = " "
-- Normal mode
map("n", "<Esc>", "<cmd>nohlsearch<CR>") -- clear search highlight
map("n", "<leader>w", "<cmd>w<CR>") -- save
map("n", "<leader>q", "<cmd>q<CR>") -- quit
map("n", "<leader>Q", "<cmd>qa!<CR>") -- force quit all
-- Better window navigation
map("n", "<C-h>", "<C-w>h")
map("n", "<C-j>", "<C-w>j")
map("n", "<C-k>", "<C-w>k")
map("n", "<C-l>", "<C-w>l")
-- Resize splits
map("n", "<C-Up>", ":resize +2<CR>")
map("n", "<C-Down>", ":resize -2<CR>")
map("n", "<C-Left>", ":vertical resize -2<CR>")
map("n", "<C-Right>", ":vertical resize +2<CR>")
-- Buffer navigation
map("n", "<S-l>", ":bnext<CR>")
map("n", "<S-h>", ":bprevious<CR>")
map("n", "<leader>bd", ":bd<CR>")
-- Move lines in visual mode
map("v", "J", ":m '>+1<CR>gv=gv")
map("v", "K", ":m '<-2<CR>gv=gv")
-- Keep selection after indent
map("v", "<", "<gv")
map("v", ">", ">gv")
-- Paste without replacing clipboard
map("v", "p", '"_dP')
-- Better line navigation (treat wrapped lines as separate)
map("n", "j", "gj")
map("n", "k", "gk")
-- Centre screen on navigation
map("n", "<C-d>", "<C-d>zz")
map("n", "<C-u>", "<C-u>zz")
map("n", "n", "nzzzv")
map("n", "N", "Nzzzv")
-- Diagnostics (LSP)
map("n", "[d", vim.diagnostic.goto_prev)
map("n", "]d", vim.diagnostic.goto_next)
map("n", "<leader>e", vim.diagnostic.open_float)
map("n", "<leader>dl", vim.diagnostic.setloclist)
17. Plugins – lazy.nvim (Neovim)
lazy.nvim is the modern plugin manager for Neovim. It supports lazy-loading, dependency management, and lockfiles.
Bootstrap
-- In init.lua or plugins/init.lua
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
vim.fn.system({
"git", "clone",
"--filter=blob:none",
"https://github.com/folke/lazy.nvim.git",
"--branch=stable",
lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
require("lazy").setup("config.plugins")
Essential Plugin Spec (~/.config/nvim/lua/config/plugins/init.lua)
return {
-- Colour scheme
{
"catppuccin/nvim",
name = "catppuccin",
priority = 1000,
config = function()
require("catppuccin").setup({ flavour = "mocha" })
vim.cmd.colorscheme("catppuccin")
end,
},
-- Treesitter (syntax highlighting, folding, text objects)
{
"nvim-treesitter/nvim-treesitter",
build = ":TSUpdate",
config = function()
require("nvim-treesitter.configs").setup({
ensure_installed = { "lua", "python", "bash", "vim", "html", "css", "json" },
highlight = { enable = true },
indent = { enable = true },
})
end,
},
-- LSP
{
"neovim/nvim-lspconfig",
dependencies = {
"williamboman/mason.nvim",
"williamboman/mason-lspconfig.nvim",
},
},
-- Autocompletion
{
"hrsh7th/nvim-cmp",
dependencies = {
"hrsh7th/cmp-nvim-lsp",
"hrsh7th/cmp-buffer",
"hrsh7th/cmp-path",
"L3MON4D3/LuaSnip",
"saadparwaiz1/cmp_luasnip",
},
},
-- Fuzzy finder
{
"nvim-telescope/telescope.nvim",
branch = "0.1.x",
dependencies = { "nvim-lua/plenary.nvim" },
keys = {
{ "<leader>ff", "<cmd>Telescope find_files<cr>" },
{ "<leader>fg", "<cmd>Telescope live_grep<cr>" },
{ "<leader>fb", "<cmd>Telescope buffers<cr>" },
{ "<leader>fh", "<cmd>Telescope help_tags<cr>" },
},
},
-- File tree
{
"nvim-tree/nvim-tree.lua",
dependencies = { "nvim-tree/nvim-web-devicons" },
keys = { { "<leader>e", "<cmd>NvimTreeToggle<cr>" } },
},
-- Status line
{
"nvim-lualine/lualine.nvim",
dependencies = { "nvim-tree/nvim-web-devicons" },
config = true,
},
-- Git integration
{
"lewis6991/gitsigns.nvim",
config = true,
},
-- Comment toggling
{
"numToStr/Comment.nvim",
config = true,
keys = { "gc", "gb" },
},
-- Autopairs
{
"windwp/nvim-autopairs",
event = "InsertEnter",
config = true,
},
-- Which-key (keybinding helper)
{
"folke/which-key.nvim",
event = "VeryLazy",
config = true,
},
-- Indent guides
{
"lukas-reineke/indent-blankline.nvim",
main = "ibl",
config = true,
},
-- Undo tree visualiser
{
"mbbill/undotree",
keys = { { "<leader>u", "<cmd>UndotreeToggle<cr>" } },
},
-- Surround motions
{
"kylechui/nvim-surround",
event = "VeryLazy",
config = true,
},
}
lazy.nvim Commands
:Lazy open the plugin dashboard
:Lazy update update all plugins
:Lazy sync install missing + update + clean
:Lazy clean remove unused plugins
:Lazy restore restore from lockfile
vim-plug (Vim)
" Install vim-plug
call plug#begin('~/.vim/plugged')
Plug 'catppuccin/vim', { 'as': 'catppuccin' }
Plug 'preservim/nerdtree'
Plug 'vim-airline/vim-airline'
Plug 'tpope/vim-fugitive'
Plug 'tpope/vim-surround'
Plug 'tpope/vim-commentary'
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
Plug 'junegunn/fzf.vim'
call plug#end()
:PlugInstall
:PlugUpdate
:PlugClean
18. LSP in Neovim
The built-in LSP client (:help lsp) connects Neovim to language servers for diagnostics, completion, go-to-definition, and refactoring.
Install Language Servers via Mason
:Mason
Search and install servers: pylsp, lua_ls, bashls, html, cssls, jsonls.
LSP Keymaps (applied on LspAttach)
vim.api.nvim_create_autocmd("LspAttach", {
callback = function(ev)
local map = function(keys, func) vim.keymap.set("n", keys, func, { buffer = ev.buf }) end
map("gd", vim.lsp.buf.definition)
map("gD", vim.lsp.buf.declaration)
map("gi", vim.lsp.buf.implementation)
map("gr", vim.lsp.buf.references)
map("K", vim.lsp.buf.hover)
map("<C-k>", vim.lsp.buf.signature_help)
map("<leader>rn", vim.lsp.buf.rename)
map("<leader>ca", vim.lsp.buf.code_action)
map("<leader>f", function() vim.lsp.buf.format({ async = true }) end)
end,
})
LSP Diagnostics
:lua vim.diagnostic.open_float() -- show diagnostic at cursor
]d / [d -- next / previous diagnostic
:lua vim.diagnostic.setqflist() -- send all diagnostics to quickfix list
19. Neovim Terminal Mode
Neovim has a built-in terminal:
:terminal
:vsp | terminal -- vertical split terminal
:sp | terminal -- horizontal split terminal
Enter terminal mode: automatically active when terminal buffer is opened.
Exit terminal mode to normal: Ctrl+\ Ctrl+N.
Useful mapping:
map("t", "<Esc>", "<C-\\><C-N>") -- escape to normal from terminal
20. Spellcheck
set spell
set spelllang=en_gb " British English
set spellfile=~/.vim/spell/en.utf-8.add
]s next misspelled word
[s previous misspelled word
z= suggest corrections
zg add word to dictionary (good word)
zw mark word as bad
zug undo good-word addition
21. Quickfix and Location Lists
The quickfix list is a global list of positions (errors, search results, grep output). The location list is window-local.
:copen open quickfix list
:cclose close it
:cnext next entry
:cprev previous entry
:cfirst
:clast
:cc {n} jump to entry n
Grep into quickfix:
:grep pattern files
:vimgrep /pattern/gj **/*.py " Vim's built-in grep (slow but portable)
With ripgrep and Telescope, this is largely replaced by :Telescope live_grep.
22. Useful Commands Reference
. repeat last change
& repeat last substitution
@: repeat last command-line command
Ctrl+A increment number under cursor
Ctrl+X decrement number under cursor
ga show ASCII/Unicode value of char under cursor
g8 show UTF-8 encoding of char under cursor
gf go to file under cursor (open it)
gx open URL under cursor in browser
K look up word under cursor in man (default) or LSP hover
J join current line with next line
gJ join without adding space
~ toggle case of character under cursor
g~~ toggle case of line
23. Vim vs Neovim Differences
| Feature | Vim | Neovim |
|---|---|---|
| Config | .vimrc (Vimscript) | init.lua (Lua preferred) or init.vim |
| Plugin manager | vim-plug, Vundle | lazy.nvim (recommended) |
| LSP | Via plugins (coc.nvim) | Built-in |
| Tree-sitter | Via plugin | Built-in |
| Terminal | Basic :terminal | Full terminal mode |
| Async jobs | Limited | Full async API |
| Lua API | No | Full Lua 5.1 runtime |
| GUI protocol | No | Ext UI / msgpack RPC |
| Config location | ~/.vimrc | ~/.config/nvim/init.lua |
| Data directory | ~/.vim/ | ~/.local/share/nvim/ |
24. Quick Reference Cheatsheet
Movement
h j k l ← ↓ ↑ →
w / b next / prev word
e end of word
0 / ^ / $ line start / first non-blank / line end
gg / G file start / file end
{N}G line N
Ctrl+D/U half page down/up
Ctrl+F/B full page down/up
f{c} / t{c} find char / till char on line
* / # search word under cursor fwd/bwd
Operators
d delete y yank c change
> indent < dedent = auto-indent
gU uppercase gu lowercase
Text Objects
iw/aw word is/as sentence ip/ap paragraph
i(/a( parens i[/a[ brackets i{/a{ braces
i"/a" dquotes i'/a' squotes it/at HTML tag
Insert Entry Points
i before cursor a after cursor
I line start A line end
o line below O line above
s substitute char S substitute line
Save / Quit
:w save :q quit :wq / ZZ save+quit
:q! force quit ZQ force quit :qa! quit all
Related Manuals
- 202601162325: Vim is the default editor for git commits. Configure with
git config --global core.editor nvim. - tmux Manual: Run Neovim inside a tmux pane for persistent editor sessions.
- 202603161901: Use
:terminalor:!to run process management commands without leaving the editor.