DevToolBoxFREE
Blog

Vim Guide: Complete Vim/Neovim Tutorial for Developers

13 min readby DevToolBox

TL;DR

Vim is a modal text editor — you switch between Normal, Insert, Visual, and Command modes. The learning curve is steep but the payoff is massive: editing at the speed of thought without leaving the keyboard. This guide covers everything from exiting Vim to recording macros, configuring Neovim, and building a modern IDE-like workflow with plugins like Telescope and LSP.

Key Takeaways

  • Vim has five modes — Normal is the default; always return to it with Escape
  • Learn text objects (diw, ci", da{}) — they are the most force-multiplying feature
  • Use . (dot) to repeat the last change — combine with text objects for powerful edits
  • Macros (q/@) automate repetitive multi-step edits across many lines
  • :%s/old/new/gc with the c flag lets you confirm each replacement interactively
  • Neovim with Lua config (init.lua) + Lazy.nvim is the modern approach for a full IDE setup
  • Splits + buffers + marks replace tabs in most workflows — learn Ctrl+w navigation
  • Invest 1 week to break the initial barrier — productivity increases exponentially after that

Introduction: Why Learn Vim in 2026?

Vim has been a developer staple since 1991, and its influence has only grown. Every major IDE — VS Code, JetBrains, Xcode — offers a Vim emulation plugin as one of its most-installed extensions. SSH sessions, production servers, and container environments almost always have vi available. Understanding Vim gives you a universal editing superpower.

The core idea is modal editing: instead of using modifier keys (Ctrl, Alt) for every command, Vim switches between modes. In Normal mode, every key is a command. In Insert mode, keys type text. This sounds counterintuitive but enables extremely fast, precise text manipulation using mnemonic single-character commands.

Neovim is a modernized fork of Vim that adds built-in LSP support, async processing, a Lua API, and a vibrant plugin ecosystem. This guide covers both Vim and Neovim, noting differences where they exist. If you are starting fresh, Neovim is the recommended choice.

1. Vim Modes Explained

Understanding Vim's modal system is the single most important concept to grasp. Every confusion beginners face traces back to accidentally being in the wrong mode.

Normal Mode — The Command Hub

Normal mode is the default mode when you open a file. Your keystrokes are interpreted as commands, not text input. Always return here with Escape (or Ctrl+[ as a faster alternative). Most of your time in Vim should be spent in Normal mode — it is the hub you return to between every edit.

Insert Mode — Typing Text

Insert mode works like a conventional text editor: keys type characters. Enter it from Normal mode with several commands, each placing the cursor differently:

KeyAction
iInsert before cursor
IInsert at beginning of line
aAppend after cursor
AAppend at end of line
oOpen new line below and insert
OOpen new line above and insert
sDelete character and insert
SDelete line and insert
c{motion}Change (delete motion, then insert)
giInsert at last insert position

Visual Mode — Selecting Text

Visual mode highlights text for operations. There are three variants:

KeyModeDescription
vCharacter VisualSelect character by character
VLine VisualSelect entire lines
Ctrl+vBlock VisualRectangular column selection — insert/delete in columns simultaneously
gvRe-selectRe-select the previous visual selection

Command-line Mode — Ex Commands

Entered by pressing : (colon) in Normal mode. This is where you run Ex commands: saving, quitting, substitutions, running shell commands, setting options. Press Enter to execute and Escape to cancel.

:w " Save :q " Quit :wq " Save and quit :q! " Quit without saving (discard changes) :e filename " Open file :set number " Enable line numbers :!ls -la " Run shell command :help motion " Open help for 'motion'

Replace Mode

Entered with R from Normal mode. Like Insert mode but overwrites existing characters rather than inserting. Press r (lowercase) to replace a single character and return to Normal mode immediately.

2. Essential Navigation

Effective navigation is what separates Vim novices from experts. The goal is to move to your target with the fewest keystrokes possible.

Basic Movement: h/j/k/l

The four cardinal movement keys work in Normal mode. They were chosen because they are on the home row:

h ← left j ↓ down k ↑ up l → right " All accept a count prefix: 5j " move 5 lines down 10h " move 10 characters left

Word Motions

KeyMotion
wMove to start of next word (stops at punctuation)
WMove to start of next WORD (space-delimited)
bMove backward to start of word
BMove backward to start of WORD
eMove to end of word
EMove to end of WORD
geMove to end of previous word

Line Navigation

0 " Move to start of line (column 0) ^ " Move to first non-whitespace character $ " Move to end of line g_ " Move to last non-whitespace character + " Move to first non-blank of next line - " Move to first non-blank of previous line " Jump to specific column 5| " Move to column 5

File Navigation

gg " Go to first line of file G " Go to last line of file 42G " Go to line 42 42gg " Also go to line 42 Ctrl+f " Scroll forward one full page Ctrl+b " Scroll backward one full page Ctrl+d " Scroll forward half page Ctrl+u " Scroll backward half page Ctrl+e " Scroll screen down one line (cursor stays) Ctrl+y " Scroll screen up one line (cursor stays) zz " Center cursor line on screen zt " Put cursor line at top of screen zb " Put cursor line at bottom of screen

Character Search on Current Line

f{char} " Find next occurrence of char on line (cursor on char) F{char} " Find previous occurrence t{char} " Till: move cursor before next char T{char} " Till backward ; " Repeat last f/F/t/T in same direction , " Repeat last f/F/t/T in opposite direction " Example: to delete from cursor to the next comma: dt, " Delete till comma (not including it) df, " Delete through comma (including it)

Search Navigation

/pattern " Search forward for pattern ?pattern " Search backward for pattern n " Next match (same direction) N " Previous match (opposite direction) * " Search forward for word under cursor # " Search backward for word under cursor g* " Search for partial word under cursor :%s/foo//gn " Count number of occurrences of 'foo'

Jumps and Position History

Ctrl+o " Jump to previous position in jump list Ctrl+i " Jump to next position in jump list :jumps " Show jump list '' " Jump to position before last big jump '. " Jump to last edited position '^ " Jump to last insert position

3. Core Editing Commands

Vim's editing commands follow a verb + motion grammar. Once you internalize this pattern, commands become composable and predictable.

Delete, Yank, and Put

" === DELETE === x " Delete character under cursor (like Del key) X " Delete character before cursor (like Backspace) dd " Delete entire line D " Delete from cursor to end of line d$ " Same as D d0 " Delete from cursor to start of line dw " Delete word (from cursor) db " Delete word backward d3w " Delete 3 words dG " Delete from current line to end of file dgg " Delete from current line to beginning of file " === YANK (copy) === yy " Yank (copy) current line Y " Yank current line (same as yy) yw " Yank word y$ " Yank to end of line y0 " Yank to start of line yG " Yank to end of file y3w " Yank 3 words " === PUT (paste) === p " Put (paste) after cursor / below current line P " Put before cursor / above current line gp " Put after cursor and move cursor after pasted text "+p " Paste from system clipboard (+ register) "0p " Paste the last explicitly yanked text

Change Commands

cc " Change entire line (delete and enter Insert mode) C " Change from cursor to end of line cw " Change word from cursor cb " Change word backward c$ " Change to end of line c0 " Change to beginning of line s " Substitute character (delete + Insert mode) S " Substitute line (same as cc)

Undo and Redo

u " Undo last change U " Undo all changes on current line Ctrl+r " Redo (undo the undo) 5u " Undo last 5 changes :undolist " Show undo history tree (Neovim: telescope undo) " Neovim persistent undo (add to init.lua / .vimrc): " set undofile " set undodir=~/.vim/undo

Replace and Case

r{char} " Replace character under cursor with char R " Enter Replace mode (overwrite characters) ~ " Toggle case of character under cursor g~w " Toggle case of word guw " Lowercase word gUw " Uppercase word guu " Lowercase entire line gUU " Uppercase entire line g~~ " Toggle case of entire line " Visual mode case operations: " Select text in visual mode, then: u " Lowercase selection U " Uppercase selection ~ " Toggle case of selection

Indentation

>> " Indent current line << " Unindent current line >3j " Indent 3 lines down >ip " Indent inner paragraph = " Auto-indent (fix indentation) == " Auto-indent current line =G " Auto-indent from cursor to end of file gg=G " Auto-indent entire file (go to top, indent all)

Joining Lines

J " Join current line with line below (space between) gJ " Join without adding space 3J " Join current line and next 2 lines

4. Text Objects — Vim's Superpower

Text objects are the most powerful feature of Vim that most other editors lack. They let you operate on semantic chunks of text — words, sentences, paragraphs, quoted strings, parenthesized expressions, HTML tags — with a single operator.

The syntax is: operator + i/a + object. The i prefix means inner (excludes surrounding delimiter), while a means around (includes surrounding delimiter and trailing whitespace).

Word and Sentence Objects

" w = word, W = WORD, s = sentence, p = paragraph diw " Delete inner word (just the word, not spaces) daw " Delete a word (word + surrounding space) ciw " Change inner word (replaces word, stays in insert) caw " Change a word including space yiw " Yank inner word viw " Visual select inner word diW " Delete inner WORD (space-delimited) dis " Delete inner sentence das " Delete a sentence (including trailing space) dip " Delete inner paragraph (block separated by blank lines) dap " Delete a paragraph including surrounding blank lines

Delimiter Objects

" Works with: " ' ` ( ) [ ] { } < > t (tag) ci" " Change inside double quotes: "hello" → "" ca" " Change around double quotes (removes quotes too) di' " Delete inside single quotes da' " Delete around single quotes ci( " Change inside parentheses: foo(bar) → foo() ca( " Change around parens: foo(bar) → foo ci[ " Change inside square brackets ci{ " Change inside curly braces ci< " Change inside angle brackets cit " Change inside HTML/XML tag: <p>text</p> → <p></p> cat " Change around tag (removes the tag entirely) " Practical examples: " Cursor anywhere inside: console.log("hello world") ci" " → console.log("") (change content in quotes) " Cursor anywhere inside: function foo(a, b, c) ci( " → function foo() (clear parameters) " Cursor anywhere inside: const obj = { key: "value" } ci{ " → const obj = {} (clear object body)

Custom Text Objects (with plugins)

The vim-textobj-user plugin allows creating custom text objects. Popular community text objects include ae/ie (entire file), al/il (current line), ai/ii (indented block), and af/if (function).

5. Visual Mode Operations

Visual mode makes selection explicit before applying operations, which is helpful for beginners and for complex operations.

Character and Line Visual

" Enter visual modes: v " Character visual V " Line visual Ctrl+v " Block (column) visual gv " Re-select previous visual selection o " In visual mode: jump to other end of selection " Operations on visual selection: d / x " Delete selection y " Yank (copy) selection c " Change selection (delete + insert) > " Indent selection < " Unindent selection = " Auto-indent selection u " Lowercase selection U " Uppercase selection ~ " Toggle case !cmd " Filter selection through external command : " Enter Command mode for range commands

Block Visual Mode — Column Editing

Block Visual mode (Ctrl+v) is one of Vim's most impressive features, enabling simultaneous editing of multiple lines in a column:

" Example: add a '#' comment to the beginning of 5 lines 1. Position cursor at start of first line 2. Ctrl+v " enter block visual 3. 4j " select 5 lines vertically 4. I " capital I = insert at block start 5. # " type the character(s) to insert 6. Escape " apply to all selected lines " Example: delete leading whitespace from a column block 1. Ctrl+v to select the whitespace column 2. d to delete it " Appending to multiple lines: 1. Ctrl+v to select a column 2. $ " extend to end of each line 3. A " append after each line's end 4. type text 5. Escape " applies to all lines

6. Search and Replace

Vim's substitute command is one of the most powerful tools in its arsenal, supporting full regex patterns.

The Substitute Command

" Basic syntax: :[range]s/pattern/replacement/[flags] :s/old/new " Replace first 'old' on current line :s/old/new/g " Replace ALL on current line (g=global) :%s/old/new/g " Replace all in entire file (% = all lines) :%s/old/new/gc " Replace all, confirm each (c=confirm) :%s/old/new/gi " Replace all, case-insensitive (i) :%s/old/new/gI " Replace all, case-sensitive (override smartcase) " Range examples: :1,10s/foo/bar/g " Lines 1-10 :10,20s/foo/bar/g " Lines 10-20 :'<,'>s/foo/bar/g " Visual selection (auto-filled after V-mode :) :.,$s/foo/bar/g " Current line to end of file " Special patterns: :%s/word/new/g " Whole word only ( = word boundary) :%s/^/ /g " Add 2 spaces to beginning of every line :%s/ $//g " Remove trailing whitespace :%s/s+$//e " Remove trailing whitespace (e=no error if not found) :%s/ / /g " Replace double blank lines with single " Using captured groups: :%s/(foo)(bar)/\2\1/g " Swap 'foo' and 'bar' → 'barfoo' :%s/ (foo)(bar)/\2\1/g " Same with very magic ( , less escaping)

Very Magic Mode

" enables 'very magic' mode — most chars have special meaning " so you need less backslash escaping: :%s/ (https?)://(w+)/[\2](\0)/g " Wrap URLs in markdown " Pattern reference: " w = word character, d = digit, s = whitespace " + = one or more, * = zero or more, ? = zero or one " | = alternation (OR), () = capture group " ^ = start of line, $ = end of line

Global Command

:g/pattern/command " Run command on every line matching pattern :g/TODO/d " Delete all lines containing TODO :g/^s*$/d " Delete all blank lines :g/pattern/y A " Yank all matching lines into register A :g!/pattern/d " Delete all lines NOT matching pattern (also :v/) :v/pattern/d " Same as :g!/pattern/d

7. File Operations and Buffers

Saving and Quitting

:w " Write (save) file :w filename " Write to new filename (save as) :w! " Force write (overwrite read-only) :wa " Write all open buffers :q " Quit (fails if unsaved changes) :q! " Quit and discard unsaved changes :wq " Write and quit :wqa " Write all and quit :x " Write only if changed, then quit ZZ " Same as :x (shortcut in Normal mode) ZQ " Quit without saving (same as :q!) " Reload file from disk (discard changes): :e! " Revert to saved version :e " Reload without the ! if file unchanged

Working with Buffers

A buffer is a file loaded in memory. Buffers persist even when their window is closed. This is Vim's equivalent of open tabs in a conventional editor.

:e filename " Open file into new buffer :ls " List all buffers (also :buffers, :files) :b N " Switch to buffer number N :b filename " Switch to buffer by partial name :bn " Next buffer :bp " Previous buffer :bf " First buffer :bl " Last buffer :bd " Close (delete) current buffer :bd N " Close buffer N :bw " Wipe buffer (removes from buffer list) :%bd " Delete all buffers :ball " Open all buffers in split windows " Quick navigation with fzf/Telescope (see plugins section): " :Telescope buffers — fuzzy-find your open buffers

Windows (Splits)

:split " Split horizontally (same file) :split file " Split horizontally, open file :vsplit " Split vertically (same file) :vsplit file " Split vertically, open file :new " New horizontal split with empty buffer :vnew " New vertical split with empty buffer " Keyboard shortcuts (all Ctrl+w followed by key): Ctrl+w h/j/k/l " Navigate to split left/down/up/right Ctrl+w w " Cycle through windows Ctrl+w W " Cycle backward through windows Ctrl+w = " Make all windows equal size Ctrl+w _ " Maximize current window height Ctrl+w | " Maximize current window width Ctrl+w +/- " Increase/decrease window height Ctrl+w >/< " Increase/decrease window width Ctrl+w r " Rotate windows Ctrl+w x " Exchange current window with next Ctrl+w q " Close current window Ctrl+w o " Close all windows except current (:only)

Tabs

:tabnew " Open new empty tab :tabnew file " Open file in new tab :tabclose " Close current tab :tabonly " Close all other tabs gt " Go to next tab gT " Go to previous tab 3gt " Go to tab 3 :tabs " List all tabs and their windows

8. Marks and Jumps

Marks let you bookmark positions in files and jump back to them instantly.

Setting and Using Marks

m{a-z} " Set local mark (lowercase = file-local) m{A-Z} " Set global mark (uppercase = cross-file) '{mark} " Jump to the line of mark `{mark} " Jump to exact position (line + column) of mark :marks " List all marks " Special automatic marks: `. " Position of last change `' " Position before last jump `< " Start of last visual selection `> " End of last visual selection `[ " Start of last yanked/changed text `] " End of last yanked/changed text " Cross-file jumps with global marks: mA " Set global mark A in file1 " (open file2) `A " Jump back to exact position in file1

9. Macros — Automating Repetitive Edits

Macros record a sequence of Normal mode commands (including entering/exiting Insert mode, motions, and Ex commands) and replay them. They are Vim's most powerful automation feature for repetitive structural edits.

Recording and Playing Macros

qa " Start recording into register 'a' " ... perform your sequence of actions ... q " Stop recording @a " Play macro 'a' once @@ " Replay last used macro 5@a " Play macro 'a' 5 times :%normal @a " Apply macro to every line in file " View macro contents (paste register): "ap " Paste register 'a' to see the recorded sequence " Edit a macro: " 1. "ap → paste the macro " 2. Edit the pasted text " 3. "ayy → yank it back into register 'a'

Practical Macro Example

Suppose you have a list of JavaScript variable names and want to wrap each in console.log():

" Initial state (cursor on first line): myVar anotherVar thirdVar " Record macro: qa " start recording to 'a' I " insert at beginning console.log( " type opening Escape " back to normal mode A " append at end ); " type closing Escape " back to normal mode j " move to next line q " stop recording " Result after @a on first line: console.log(myVar); " Apply to all remaining lines: 2@a " or: select all 3 lines and :%normal @a

Advanced Macro Techniques

" Recursive macro (runs until it fails): qaq " Clear register 'a' (record empty macro) qa " Start recording " ... actions ... @a " Call itself at end (recursive!) q " Stop recording @a " This will repeat until an error (e.g., end of file) " Running macro on visual selection lines: V5j " Select 6 lines :normal @a " Apply macro 'a' to each selected line " Running on lines matching pattern: :g/pattern/normal @a " Apply macro to lines matching pattern

10. Registers

Vim has multiple registers (named clipboards) for storing text and macros. Understanding them unlocks powerful copy-paste workflows.

:reg " List all register contents :reg a b c " List specific registers " Named registers (a-z): "ayy " Yank current line into register 'a' "ap " Paste from register 'a' "Ayy " APPEND yank to register 'a' (uppercase appends) " Special registers: "" " Unnamed register (default for d, y, c, x) "0 " Yank register (last explicit yank only, not deletes) "1-"9 " Numbered registers (recent deletes/changes) "+ " System clipboard (X11/Wayland primary selection) "* " System clipboard (middle-click paste on Linux) "_ " Black hole register (discard, like /dev/null) ". " Last inserted text ": " Last Ex command "/ " Last search pattern "% " Current filename "# " Alternate filename " Tip: use "0p after multiple deletes to paste last yank " without the delete overwriting the unnamed register

11. Configuration — .vimrc and init.lua

Your configuration file is where you set options, key mappings, and plugins. Vim uses ~/.vimrc (Vimscript). Neovim uses ~/.config/nvim/init.vim (Vimscript) or ~/.config/nvim/init.lua (Lua — recommended for new setups).

Essential .vimrc Settings

" ~/.vimrc — essential settings " === BASICS === set nocompatible " Not Vi-compatible (enable Vim improvements) filetype plugin indent on " Enable filetype detection, plugins, indenting syntax on " Enable syntax highlighting " === UI === set number " Show line numbers set relativenumber " Show relative line numbers (great for motions) set ruler " Show cursor position in status bar set showcmd " Show incomplete commands set showmode " Show current mode set wildmenu " Enhanced command-line completion set wildmode=list:longest " Complete like shell (list matches) set cursorline " Highlight current line set scrolloff=8 " Keep 8 lines visible above/below cursor set colorcolumn=80,120 " Highlight columns 80 and 120 " === SEARCH === set hlsearch " Highlight search matches set incsearch " Incremental search (highlight as you type) set ignorecase " Case-insensitive search set smartcase " Override ignorecase if uppercase used " === INDENTATION === set tabstop=2 " Tab displays as 2 spaces set shiftwidth=2 " Indent with 2 spaces set expandtab " Use spaces instead of tabs set autoindent " Auto-indent new lines set smartindent " Smart auto-indenting " === FILES === set encoding=utf-8 " Default encoding set hidden " Allow background buffers without saving set noswapfile " Disable swap files set undofile " Persistent undo across sessions set undodir=~/.vim/undo " Where to store undo files set autoread " Auto-reload files changed externally set backup " Keep backup files " === PERFORMANCE === set lazyredraw " Don't redraw during macros set ttyfast " Faster terminal connection " === KEY MAPPINGS === let mapleader = ' ' " Space as leader key (very common) " Quick save and quit nnoremap <leader>w :w<CR> nnoremap <leader>q :q<CR> nnoremap <leader>Q :q!<CR> " Clear search highlight nnoremap <leader>h :nohlsearch<CR> " Better split navigation 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/down nnoremap <A-j> :m .+1<CR>== nnoremap <A-k> :m .-2<CR>== vnoremap <A-j> :m '>+1<CR>gv=gv vnoremap <A-k> :m '<-2<CR>gv=gv " Keep visual selection after indent vnoremap > >gv vnoremap < <gv " Y should yank to end of line (like D and C) nnoremap Y y$ " Center screen on search results nnoremap n nzzzv nnoremap N Nzzzv

Neovim init.lua (Modern Lua Config)

-- ~/.config/nvim/init.lua -- === BASICS === vim.g.mapleader = ' ' vim.g.maplocalleader = ' ' -- === OPTIONS === local opt = vim.opt opt.number = true opt.relativenumber = true opt.tabstop = 2 opt.shiftwidth = 2 opt.expandtab = true opt.autoindent = true opt.smartindent = true opt.hlsearch = true opt.incsearch = true opt.ignorecase = true opt.smartcase = true opt.scrolloff = 8 opt.hidden = true opt.undofile = true opt.swapfile = false opt.backup = false opt.encoding = 'utf-8' opt.cursorline = true opt.colorcolumn = '80' opt.termguicolors = true -- Enable true color support opt.signcolumn = 'yes' -- Always show sign column (for LSP errors) opt.updatetime = 250 -- Faster update for CursorHold events opt.completeopt = 'menuone,noinsert,noselect' -- === KEY MAPPINGS === local map = vim.keymap.set -- 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') -- Quick save/quit map('n', '<leader>w', ':w<CR>') map('n', '<leader>q', ':q<CR>') -- Clear search highlight map('n', '<leader>h', ':nohlsearch<CR>') -- Move lines map('n', '<A-j>', ':m .+1<CR>==') map('n', '<A-k>', ':m .-2<CR>==') map('v', '<A-j>', ":m '>+1<CR>gv=gv") map('v', '<A-k>', ":m '<-2<CR>gv=gv") -- Keep indent in visual mode map('v', '>', '>gv') map('v', '<', '<gv') -- Y = yank to end of line map('n', 'Y', 'y$') -- === PLUGIN MANAGER (Lazy.nvim) === 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({ -- Theme { 'folke/tokyonight.nvim', priority = 1000, config = function() vim.cmd.colorscheme 'tokyonight' end }, -- Fuzzy finder { 'nvim-telescope/telescope.nvim', dependencies = { 'nvim-lua/plenary.nvim' } }, -- File tree { 'nvim-tree/nvim-tree.lua' }, -- Treesitter (better syntax) { 'nvim-treesitter/nvim-treesitter', build = ':TSUpdate' }, -- LSP { 'neovim/nvim-lspconfig' }, -- Completion { 'hrsh7th/nvim-cmp', dependencies = { 'hrsh7th/cmp-nvim-lsp' } }, -- Git { 'tpope/vim-fugitive' }, { 'lewis6991/gitsigns.nvim' }, -- Status line { 'nvim-lualine/lualine.nvim' }, -- Surround { 'tpope/vim-surround' }, -- Auto-pairs { 'windwp/nvim-autopairs' }, })

12. Essential Plugins

Vim's plugin ecosystem transforms it from a text editor into a full development environment. Here are the most impactful plugins every developer should know.

Telescope.nvim — Fuzzy Finder (Neovim)

Telescope is the gold standard for fuzzy finding in Neovim. It searches files, buffers, git commits, LSP symbols, and almost anything else with a beautiful preview.

-- In your init.lua key mappings: local telescope = require('telescope.builtin') vim.keymap.set('n', '<leader>ff', telescope.find_files) -- find files vim.keymap.set('n', '<leader>fg', telescope.live_grep) -- grep in project vim.keymap.set('n', '<leader>fb', telescope.buffers) -- list buffers vim.keymap.set('n', '<leader>fh', telescope.help_tags) -- search help vim.keymap.set('n', '<leader>fs', telescope.lsp_document_symbols) vim.keymap.set('n', '<leader>fr', telescope.oldfiles) -- recent files vim.keymap.set('n', '<leader>gc', telescope.git_commits) -- git log

fzf.vim — Fuzzy Finder (Vim)

" In .vimrc (requires fzf installed separately): Plug 'junegunn/fzf', { 'do': { -> fzf#install() } } Plug 'junegunn/fzf.vim' " Key mappings: nnoremap <C-p> :Files<CR> " Find files nnoremap <leader>b :Buffers<CR> " List buffers nnoremap <leader>g :Rg<CR> " Live grep (requires ripgrep) nnoremap <leader>l :Lines<CR> " Search lines in open buffers

NERDTree / nvim-tree — File Explorer

" NERDTree (Vim and Neovim): Plug 'preservim/nerdtree' nnoremap <leader>e :NERDTreeToggle<CR> nnoremap <leader>f :NERDTreeFind<CR> " Reveal current file " Inside NERDTree: " o / Enter = open file " t = open in new tab " i = open in horizontal split " s = open in vertical split " ma = create file/directory " md = delete " mm = rename/move -- nvim-tree (Lua, modern): require('nvim-tree').setup() vim.keymap.set('n', '<leader>e', ':NvimTreeToggle<CR>')

vim-fugitive — Git Integration

Tim Pope's vim-fugitive is described as "the best Git wrapper of all time." It brings Git commands into Vim seamlessly.

" Essential fugitive commands: :Git status " (or :G) — interactive git status :Git add % " Stage current file :Git commit " Commit with message in split :Git push " Push to remote :Git log " Git log :Git blame " Blame current file (press q to close) :Git diff " Diff working tree :Git diff --staged " Diff staged changes " In :Git status window: " s = stage file " u = unstage file " - = toggle stage " cc = commit " ca = amend commit " dv = diff in vertical split

coc.nvim — Completion and LSP

" coc.nvim works for both Vim and Neovim: Plug 'neoclide/coc.nvim', {'branch': 'release'} " Install language servers: :CocInstall coc-tsserver " TypeScript/JavaScript :CocInstall coc-pyright " Python :CocInstall coc-rust-analyzer " Rust :CocInstall coc-eslint " ESLint :CocInstall coc-prettier " Prettier formatting " Key mappings for coc: nmap <silent> gd <Plug>(coc-definition) " Go to definition nmap <silent> gy <Plug>(coc-type-definition) " Go to type def nmap <silent> gi <Plug>(coc-implementation) " Go to implementation nmap <silent> gr <Plug>(coc-references) " Find references nmap <leader>rn <Plug>(coc-rename) " Rename symbol nmap <leader>f <Plug>(coc-fix-current) " Fix current issue nmap <leader>ac <Plug>(coc-codeaction) " Code action K " Show hover docs (press K in normal mode)

Neovim Native LSP

-- neovim/nvim-lspconfig setup example: local lspconfig = require('lspconfig') -- TypeScript lspconfig.tsserver.setup({ on_attach = function(client, bufnr) -- Key mappings when LSP attaches local opts = { buffer = bufnr } vim.keymap.set('n', 'gd', vim.lsp.buf.definition, opts) vim.keymap.set('n', 'gr', vim.lsp.buf.references, opts) vim.keymap.set('n', 'K', vim.lsp.buf.hover, opts) vim.keymap.set('n', '<leader>rn', vim.lsp.buf.rename, opts) vim.keymap.set('n', '<leader>ca', vim.lsp.buf.code_action, opts) vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, opts) vim.keymap.set('n', ']d', vim.diagnostic.goto_next, opts) end, }) -- Python lspconfig.pyright.setup({}) -- Rust lspconfig.rust_analyzer.setup({})

vim-surround — Surround Text

" Tim Pope's vim-surround allows changing, adding, deleting surrounding chars " Change surroundings: cs'" " Change surrounding ' to " : 'word' → "word" cs({ " Change surrounding ( to { : (word) → { word } cs)} " Change surrounding ) to } : (word) → {word} cst<p> " Change surrounding tag to <p> " Delete surroundings: ds' " Delete surrounding ' : 'word' → word ds( " Delete surrounding ( : (word) → word dst " Delete surrounding tag " Add surroundings (normal mode): ysiw" " Surround inner word with " : word → "word" ysiw( " Surround inner word with ( ) : word → ( word ) ysip<p> " Surround paragraph with <p> " Add surroundings (visual mode): S" " After visual select, surround with " S{ " After visual select, surround with {}

13. Vim vs Neovim Comparison

Both Vim and Neovim are excellent editors. The right choice depends on your needs, workflow, and tolerance for configuration.

FeatureVim 9.xNeovim 0.9+
Config languageVimscript 9 (new syntax)Lua (primary) + Vimscript
Built-in LSPNo (requires coc.nvim)Yes (vim.lsp)
TreesitterPlugin onlyBuilt-in (nvim-treesitter)
Async job controlLimitedFull async API
Plugin ecosystemLarge, matureVery active, Lua-first
DefaultsConservative (Vi compat)Sensible modern defaults
PerformanceExcellentExcellent (faster for Lua plugins)
Floating windowsLimitedFull support (used by Telescope etc.)
EmbeddableNoYes (libneovim)
GUI supportgvimNeovide, Goneovim, etc.
Universal availabilityPre-installed on most systemsMust install separately
Starter configsvimrc examples onlineLazyVim, Kickstart, AstroNvim
Best forServers, scripting, Vimscript familiarityFull development workflow, modern IDE features

Recommendation: If you are new to modal editing, start with Neovim and the kickstart.nvim starter config. It is well-documented and teaches you configuration as you use it. If you primarily edit config files on remote servers, vanilla Vim (which is nearly always present) is perfectly adequate.

14. Developer Workflow Tips

The Dot Command — Most Underrated Feature

" The . command repeats the last change (everything from " entering Insert mode to leaving it counts as one change) " Example: add a semicolon to the end of a line A;<Escape> " Add semicolon at end j. " Move down, repeat: add semicolon to next line j. " Repeat again... " Combined with f/t for powerful workflows: " Add console.log around all 'response' variables: /response " find first occurrence ciw " change inner word console.log(response) " type new text <Escape> n. " find next, repeat change

Abbreviations for Frequent Typos

" In .vimrc / init.lua: iabbrev teh the iabbrev recieve receive iabbrev funciton function iabbrev calback callback " Expand while typing (press space after abbreviation)

Quickfix List — Navigate Errors and Search Results

:copen " Open quickfix window :cclose " Close quickfix window :cnext " Jump to next error/result :cprev " Jump to previous error/result :cfirst " Jump to first :clast " Jump to last " Populate quickfix with grep results: :grep -r "pattern" . " Search and load results into quickfix :Rg pattern " With fzf.vim: results go to quickfix " Location list (window-local quickfix): :lopen / :lclose :lnext / :lprev

Spell Checking

:set spell " Enable spell checking :set spelllang=en_us " Set language ]s " Next misspelled word [s " Previous misspelled word z= " Show spelling suggestions zg " Add word to dictionary zw " Mark word as misspelled

Working with Multiple Files

" Open multiple files from command line: vim file1.js file2.js file3.js " Navigate: :bn :bp :b filename " Open all JS files in project: vim **/*.js " Use argument list: :args **/*.js " Set argument list :next / :prev " Navigate args :argdo %s/foo/bar/g " Apply to all args :argdo w " Save all args " Project-wide search and replace (with quickfix): :grep -r "oldName" . :cfdo %s/oldName/newName/g | w

Frequently Asked Questions

How do I exit Vim?

Press Escape to ensure you are in Normal mode, then: :q (quit, no unsaved changes), :q! (quit, discard changes), :wq or ZZ (save and quit). If everything feels broken, Escape mashed repeatedly then :q! will always work.

What are Vim text objects and why are they powerful?

Text objects let you operate on semantic units: diw deletes a word, ci" changes text inside quotes, da{} deletes a block including braces, yip yanks a paragraph. The pattern is operator + i/a + object. They make editing much faster than manually selecting characters.

How do I search and replace text in Vim?

Use :%s/old/new/g to replace all occurrences in the file. Add c for confirmation (:%s/old/new/gc), i for case-insensitive. Use :s/old/new/g for the current line only. The % means "all lines" and can be replaced with a range like 1,10.

What is the difference between Vim and Neovim?

Neovim is a modernized fork with built-in LSP, Lua configuration, async processing, floating windows, and an active modern plugin ecosystem. Vim is more stable and universally pre-installed. For new development workflows, Neovim is recommended. For quick edits on servers, Vim is always available.

How do Vim macros work?

Record with qa (record into register a), perform actions, stop with q. Replay with @a or @@ for last macro. Apply to multiple lines with a count: 10@a. Apply to all lines: :%normal @a.

How do I split windows and manage buffers?

Split with :split / :vsplit. Navigate splits with Ctrl+w h/j/k/l. List buffers with :ls, switch with :b N or :bn / :bp. Close buffer with :bd. Use Telescope (<leader>fb) for fuzzy buffer switching.

What essential plugins should I install?

For Neovim: Telescope (fuzzy finding), nvim-tree (file explorer), vim-fugitive (Git), nvim-lspconfig + nvim-cmp (LSP + completion), nvim-treesitter (syntax), lualine.nvim (status line), vim-surround (surround text), nvim-autopairs. For a full preset configuration, try LazyVim or Kickstart.nvim.

How do I learn Vim effectively?

Run vimtutor from the terminal — it is a built-in 30-minute interactive tutorial. Focus on one new concept per day rather than trying to learn everything at once. Force yourself to use Vim exclusively for a week; the muscle memory develops quickly. Practice text objects and motions most — they provide the biggest productivity gain.

𝕏 Twitterin LinkedIn
Was this helpful?

Stay Updated

Get weekly dev tips and new tool announcements.

No spam. Unsubscribe anytime.

Try These Related Tools

MDMarkdown to HTML±Text Diff Checker.*Regex Tester

Related Articles

Linux Commands Guide: Essential Command Line Reference for Developers

Master Linux command line with this comprehensive guide. Covers file system navigation, text processing, process management, permissions, networking, SSH, package management, and shell productivity tips.

SSH Key Generator: Generate and Manage SSH Keys — Complete Guide

Master SSH key generation and management. Complete guide with ssh-keygen, Ed25519/RSA comparison, SSH config, node-forge, Python paramiko, Git SSH setup, tunneling, certificate-based SSH, and security best practices.