Real-World Workflows
Summary: in this tutorial, you will learn put everything together with practical vim workflows for code editing, git integration, multi-file operations, and a comprehensive cheat sheet.
Real-World Workflows
You've learned Vim's individual features — modes, motions, operators, macros, registers, and configuration. Now it's time to put everything together with real-world workflows that show how experienced Vim users actually work day to day.
What you'll learn in this tutorial:
- Common code editing patterns that make you faster
- How to use Vim with Git for version control
- Multi-file editing techniques for project-wide changes
- How to compile and run code from inside Vim
- A comprehensive cheat sheet you can reference anytime
Code Editing Patterns
Renaming a Variable
You have a variable called count and want to rename it to total throughout the file:
:%s/\<count\>/total/gcBreaking it down:
%— every line in the files/old/new/— substitute command\<count\>— the exact word "count" (word boundaries prevent matching "counter" or "account")g— all occurrences per linec— confirm each replacement (so you don't change "count" in comments by accident)
Duplicating a Function
Want to copy a function and modify it?
" Put cursor anywhere inside the function
V " Start line selection
ip " Select the inner paragraph (the whole function block)
y " Yank (copy)
} " Move to the blank line after the function
p " Paste belowOr if the function uses curly braces:
" Put cursor on the opening { of the function
V% " V starts line selection, % jumps to matching }
y " Yank the entire function
}p " Move to the next blank line and pasteAdding a Parameter to a Function
Your function is function process(data) and you want to add a second parameter:
f( " Find the opening parenthesis
% " Jump to the closing parenthesis
i, options<Esc> " Insert before ), type ", options", exit Insert modeResult: function process(data, options)
Commenting/Uncommenting Code
Without plugins, using block visual mode:
" Comment out lines 10-15 (JavaScript // comments)
10G " Go to line 10
Ctrl-v " Block visual mode
5j " Select 5 more lines (6 total)
I// <Esc> " Insert "// " at the start of each line
" Uncomment them
10G " Go to line 10
Ctrl-v " Block visual mode
5j " Select the same lines
2l " Select 3 characters ("// ")
d " Delete the blockWith the vim-commentary plugin (if installed):
10G " Go to line 10
V5j " Select 6 lines
gc " Toggle comments on/offWrapping Text in a Function Call
You have value and want to change it to parseInt(value):
ciw " Change the word (deletes "value", enters Insert mode)
parseInt(<C-r>")<Esc>
" Ctrl-r " pastes the deleted word from the unnamed register
" So you type: parseInt( ... paste "value" ... )Result: parseInt(value)
Aligning Equals Signs
Given this messy code:
const name = "Alice";
const age = 30;
const city = "New York";
const occupation = "Developer";You can use Visual block mode to align the = signs:
" Select the = column using block visual mode
" Position on the first =, Ctrl-v, extend down, then adjust with spaces
" This is easier with a plugin like vim-easy-align, but doable manuallyFor frequent alignment tasks, consider the junegunn/vim-easy-align plugin. You can select lines, press ga, then = to align around equals signs. It handles many alignment patterns automatically.
Sorting Imports
If you have a block of import statements:
" Select the import lines
V " Line visual mode
} " Select to the next blank line
:sort " Sort alphabeticallyDeleting Inside Matching Pairs
These are incredibly common patterns:
ci( " Change inside parentheses: foo(old) → foo(|)
ci{ " Change inside braces: {old} → {|}
ci[ " Change inside brackets: [old] → [|]
ci" " Change inside quotes: "old" → "|"
ci' " Change inside single quotes: 'old' → '|'
dit " Delete inside HTML tags: <div>old</div> → <div></div>The | shows where your cursor ends up in Insert mode.
Working with Git
Viewing Changes
If you have the vim-gitgutter plugin (from the configuration tutorial), you'll see change indicators in the left margin:
+— new lines (added)~— modified lines-— deleted lines
Navigate between changes:
]c " Jump to the next change
[c " Jump to the previous changeRunning Git Commands from Vim
You can run any shell command from Vim using :!:
:!git status " See which files have changed
:!git diff " See what lines changed
:!git add % " Stage the current file (% = current filename)
:!git commit -m "message" " Commit with a message
:!git log --oneline -10 " See the last 10 commitsThe % in :!git add % is a special Vim variable that expands to the current file's name. So if you're editing src/app.js, the command becomes git add src/app.js.
Reviewing a Diff
Open two versions of a file side by side:
:vsp " Split vertically
:e other-version.js " Open the other version
:windo diffthis " Turn on diff mode in both windowsOr from the command line:
vim -d file1.js file2.js " Open both files in diff modeIn diff mode:
- Changed sections are highlighted
]cand[cjump between changesdo— get the change from the other window ("diff obtain")dp— send the change to the other window ("diff put")
Multi-File Operations
Search Across Files
:vimgrep /TODO/ **/*.js " Search all JS files recursively
:copen " Open the results windowIn the results window:
- Press Enter to jump to a result
:cnext(:cn) — go to the next result:cprev(:cp) — go to the previous result:cclose— close the results window
Replace Across Files
To find and replace text across multiple files:
" Step 1: Find all files containing the text
:vimgrep /oldFunction/ **/*.js
" Step 2: Run substitute on all results
:cfdo %s/oldFunction/newFunction/gc | updateBreaking it down:
:cfdo— run a command on every file in the quickfix list%s/old/new/gc— find and replace with confirmation| update— save the file after replacing
Opening Multiple Related Files
# From the terminal — open all JavaScript files
vim **/*.js
# Open all files matching a pattern
vim src/components/*.tsxOr from inside Vim:
:args **/*.js " Add all JS files to the argument list
:argdo %s/old/new/ge | update " Replace in all of themBe careful with multi-file replacements! Always use the c (confirm) flag the first time, or use Git so you can undo changes with git checkout -- . if something goes wrong.
Compiling and Running Code
Running the Current File
:!python3 % " Run the current file with Python
:!node % " Run with Node.js
:!bash % " Run as a shell script
:!gcc % -o output && ./output " Compile and run C codeUsing Vim's :make Command
If your project has a Makefile:
:make " Run the Makefile
:copen " Open the error list
:cnext " Jump to the next error
:cprev " Jump to the previous errorQuickfix Window
The quickfix window shows compile errors, search results, and other lists. It's a central feature for navigating errors:
| Command | What It Does |
|---|---|
:copen | Open the quickfix window |
:cclose | Close it |
:cnext or :cn | Go to the next item |
:cprev or :cp | Go to the previous item |
:cfirst | Jump to the first item |
:clast | Jump to the last item |
Productivity Tips
Use Marks for Key Positions
When working on a large file, set marks at important locations:
mf " Mark the function you're working on
mt " Mark the test section
mc " Mark the config/imports sectionThen quickly jump between them: 'f, 't, 'c
Use the Alternate File
Ctrl-^ switches between the current file and the last file you viewed. This is incredibly useful when:
- Switching between a source file and its test file
- Switching between an HTML file and its CSS
- Checking a function definition and then going back
Terminal Inside Vim
Vim 8+ has a built-in terminal:
:terminal " Open a terminal below
:vert terminal " Open a terminal on the rightIn the terminal window:
- You're in a real terminal — run any command
- Press
Ctrl-w N(orCtrl-\ Ctrl-n) to switch to Normal mode (allows copying text) - Press
iorato go back to terminal input mode - Type
exitto close the terminal
Command-Line Window
Vim keeps a history of all your commands and searches. Press q: to open the command-line window — a buffer containing your command history. You can:
- Navigate with normal motions
- Edit a previous command
- Press Enter to execute it
Press q/ for search history instead.
Accidentally opened the command-line window? It's a common slip to press q: when you meant :q (quit). Just press :q to close it.
Vim Cheat Sheet
Here's a comprehensive reference of the most useful Vim commands. Bookmark this page!
Movement
| Command | Action |
|---|---|
h j k l | Left, Down, Up, Right |
w / b | Next / Previous word |
e / ge | End of word / End of previous word |
0 / $ | Start / End of line |
^ | First non-blank character |
gg / G | Top / Bottom of file |
{number}G | Go to line number |
Ctrl-d / Ctrl-u | Half page down / up |
Ctrl-f / Ctrl-b | Full page down / up |
f{char} / F{char} | Find character forward / backward |
% | Jump to matching bracket |
{ / } | Previous / Next paragraph |
H / M / L | Top / Middle / Bottom of screen |
Editing
| Command | Action |
|---|---|
i / a | Insert before / after cursor |
I / A | Insert at start / end of line |
o / O | New line below / above |
d{motion} | Delete |
c{motion} | Change (delete + insert) |
y{motion} | Yank (copy) |
dd / cc / yy | Delete / Change / Yank entire line |
D / C | Delete / Change to end of line |
x / X | Delete character / previous character |
r{char} | Replace single character |
p / P | Paste after / before |
u / Ctrl-r | Undo / Redo |
. | Repeat last change |
J | Join lines |
Text Objects
| Command | Selects |
|---|---|
iw / aw | Inner / around word |
is / as | Inner / around sentence |
ip / ap | Inner / around paragraph |
i" / a" | Inside / around double quotes |
i( / a( | Inside / around parentheses |
i{ / a{ | Inside / around curly braces |
it / at | Inside / around HTML tags |
Search
| Command | Action |
|---|---|
/pattern | Search forward |
?pattern | Search backward |
n / N | Next / Previous match |
* / # | Search word under cursor forward / backward |
:%s/old/new/g | Replace all in file |
:%s/old/new/gc | Replace with confirmation |
:noh | Clear search highlights |
Windows
| Command | Action |
|---|---|
:sp / :vsp | Horizontal / Vertical split |
Ctrl-w h/j/k/l | Move between windows |
Ctrl-w = | Equalize window sizes |
Ctrl-w o | Close all other windows |
Ctrl-w q | Close current window |
Buffers and Files
| Command | Action |
|---|---|
:e file | Open file |
:ls | List buffers |
:bn / :bp | Next / Previous buffer |
:bd | Close (delete) buffer |
Ctrl-^ | Toggle last two files |
:w | Save |
:q | Quit |
:wq or ZZ | Save and quit |
:q! | Quit without saving |
Visual Mode
| Command | Action |
|---|---|
v | Character selection |
V | Line selection |
Ctrl-v | Block (column) selection |
gv | Reselect last selection |
o | Swap cursor to other end |
Macros
| Command | Action |
|---|---|
q{a-z} | Start recording into register |
q | Stop recording |
@{a-z} | Play macro |
@@ | Repeat last macro |
{n}@{a-z} | Play macro n times |
Marks
| Command | Action |
|---|---|
m{a-z} | Set mark |
'{a-z} | Jump to mark (line) |
`{a-z} | Jump to mark (exact position) |
Ctrl-o | Jump back |
Ctrl-i | Jump forward |
What's Next?
Congratulations — you've completed the Vim tutorial series! Here's how to keep improving:
-
Practice daily. The commands will feel slow at first. After a week of consistent use, they become muscle memory.
-
Learn incrementally. Don't try to memorize everything at once. Pick 2-3 new commands each week and focus on using them until they're automatic.
-
Use
vimtutor. Typevimtutorin your terminal for a built-in interactive tutorial that takes about 30 minutes. -
Read
:help. Vim has incredibly detailed built-in documentation. Type:helpfollowed by any command or topic (e.g.,:help text-objects,:help registers). -
Explore plugins when you feel the need — not before. If you find yourself doing something repetitive that Vim can't handle, there's probably a plugin for it.
The key to Vim mastery: Notice when you're doing something the slow way, then find the Vim way to do it faster. Over time, this curiosity compounds into incredible efficiency.
Practice: Putting It All Together
Create two practice files and try these real-world workflows:
# Create two files
cat > app.js << 'EOF'
function calculateTotal(items) {
var total = 0;
for (var i = 0; i < items.length; i++) {
total += items[i].price;
}
return total;
}
function formatPrice(amount) {
return "$" + amount.toFixed(2);
}
// TODO: add tax calculation
// TODO: add discount support
// TODO: add currency formatting
EOF
cat > test.js << 'EOF'
const { calculateTotal, formatPrice } = require('./app');
test('calculates total', () => {
const items = [{price: 10}, {price: 20}];
expect(calculateTotal(items)).toBe(30);
});
test('formats price', () => {
expect(formatPrice(9.99)).toBe("$9.99");
});
EOFNow try these workflows:
- Open both files:
vim -O app.js test.js - In app.js, rename
vartoconst::%s/\<var\>/const/g - Switch to test.js with
Ctrl-w l - Switch back with
Ctrl-^ - In app.js, use
*on the wordtotalto see all occurrences - Record a macro to change each
TODO:line from a comment to a function stub - Use
:vimgrep /function/ %to find all functions, then:copento see results - Run the file:
:!node % - Set a mark at the
calculateTotalfunction:mf - Jump to the end of the file with
G, then back to the mark with'f
Show Solution
" 1. Open both files side by side
" (from terminal: vim -O app.js test.js)
" 2. Rename var to const in app.js
" Make sure you're in the app.js window
:%s/\<var\>/const/g
" "var total" → "const total", "var i" → "const i"
" 3. Switch to test.js
Ctrl-w l " Move to the right window
" 4. Switch back to app.js
Ctrl-^ " Toggles back to the last file (app.js)
" 5. Search for "total"
" Put cursor on the word "total"
* " Highlights every "total" in the file, jumps to next
n " Next occurrence
N " Previous occurrence
" 6. Macro: convert TODO comments to function stubs
" Go to the first TODO line
qa " Start recording
0 " Go to start of line
c$ " Change the entire line
function todo() {}<Esc> " Type the stub
F} " Move cursor back to before }
i<CR> // implement<CR><Esc> " Add placeholder content
j " Move to next line
q " Stop recording
2@a " Run on the other two TODO lines
" 7. Find all functions
:vimgrep /function/ % " Search current file
:copen " Open quickfix window
" Press Enter on any line to jump to that function
:cclose " Close quickfix when done
" 8. Run the file
:!node % " Runs app.js with Node.js
" (This won't produce output since there's no main call,
" but it checks for syntax errors)
" 9. Set a mark
" Go to the calculateTotal function
mf " Set mark 'f' (for "function")
" 10. Navigate with marks
G " Jump to the bottom of the file
'f " Jump right back to calculateTotal!
:qa! " Quit all files without savingWritten by the ShellRAG Team
The ShellRAG editorial team writes practical, beginner-friendly Vim tutorials with tested code examples and real-world use cases. Every article is technically reviewed for accuracy and updated regularly.
Learn more about us →