Write Code Faster in Vim
It often takes a mountain of experimental code (littered with dead ends) before you finally land on the concise, 37-line PR you wanted to make.
That’s a lot of typing, and an opportunity to reclaim time on the calendar.
This tutorial is for engineers who have dabbled with vim here and there, but wouldn’t call themselves an expert yet. You’ve learned how to actually close the application, but everything else still feels a little intimidating.
This post highlights simple techniques you can use while modifying just about any code snippet, and skips over advanced functionality that doesn’t see much use throughout the average coding session.
Situational commands have their place, but they shouldn’t take priority over mastering the fundamentals during your first few months with vim.
Your biggest productivity leaps will come from analyzing basic habits with a critical eye, and finding opportunities to shave 3 seconds off of the small movement patterns you find yourself repeating 600 times every month.
Even if it only takes a second to move your hands off the home row to navigate using the arrow keys, that’s ~60 minutes lost to opportunity cost by the end of the quarter. They feel quick and harmless in the moment, but those micro-inefficiencies stack up quickly over the course of a career.
Navigate and Manipulate Lines Efficiently
Normal mode is where you want to spend most of your time within vim.
Insert mode is great when you actually want to type something, but try to err on the side of hitting CTRL+[
/ CTRL+C
to return to normal mode after (or the ESC
key, if moving your pinky down to CTRL
feels uncomfortable).
When using normal mode, vim remaps your entire keyboard to place as many programmer-centric features around the home row as possible, and the majority of vim’s advanced text manipulation and navigation lives here.
Check out these useful commands to work with lines more efficiently…
These shortcuts will shave 30 seconds off most code snippets, and I’d recommend doing whatever it takes to commit each one to muscle memory.
Also, while navigating character-by-character, try to get into the habit of using h
(left), j
(down), k
(up), and l
(right) instead of the arrow keys.
While awkward at first, most of vim’s advanced text manipulation lives around the home row keys, and you’ll miss out on a lot of the fluidity this editor can offer if you’re always moving your hands around.
Start Visualizing Blocks of Text
If insert mode lets you type new code, and normal mode helps you navigate and manipulate it, visual mode is a powerful way to highlight code snippets before you make modifications to them.
Think about when you select a few lines of code with your mouse before right-clicking to copy/paste. Visual mode is that, but for the power user.
Here are a few scenarios where visual mode can make your life easier…
- Cutting and pasting snippets without needing to use your mouse
- Indenting multiple lines of code at the same time
- Manipulating text wrapped inside two matching curly brackets, parentheses, double-quote pairs, backticks, etc.
- Converting strings and constants to
UPPERCASE
/lowercase
versions - Highlighting specific blocks of text to better illustrate your ideas when pairing with coworkers over Zoom
- Scoping find-and-replace calls to only the code you have highlighted, instead of replacing every matching instance across the entire file
Despite occasionally taking a few extra keystrokes to accomplish a task within visual mode compared to normal mode, it can be a great set of training wheels early on (as you can preview your actions beforehand).
Highlighting Text Within Visual Mode
To start, let’s enter visual line mode by pressing V
Capitalization matters, so we’re essentially typing SHIFT + v
The current line will be now be highlighted. By moving your cursor around with j
(down) / k
(up), you can extend your selection one line at a time.
You can jump to a specific line by typing XG
, replacing the X
with the line number you want to extend your selection to. Want to jump to line 58? 58G
If you change your mind and want to back out of your selection, use your preferred shortcut to return to normal mode: ESC
/ CTRL+[
/ CTRL+C
You can also highlight text within the current line by pressing v
(lowercase) to enter visual character mode, as shown in the screenshot below.
h
(left) and l
(right) will extend your selection one character at a time.
B
(left) and E
(right) will extend your selection by one word at a time.
The line-based navigation shortcuts from the first chapter also work here.
Copy and Paste Snippets
Type y
to copy your selection, or d
to cut it (while still copying its contents).
Once the code is inside your clipboard, press P
to paste it before your cursor, or p
to paste the snippet after your cursor’s current position.
When copying multiple lines at a time, this means the P
shortcut will paste your snippet above the current line, and p
will paste your snippet below it.
Manipulate Indentation Levels
The >
command will indent your selection by one indentation level.
The <
command will unindent your selection by one indentation level.
You can prefix your command with a number to indent by multiple levels.
4>
would indent by 4 levels at once, and 3<
would unindent by 3 levels.
Find and Replace Text
When refactoring, I often want to scope find-and-replace calls to only the code I have highlighted, instead of replacing every match across the file.
When using visual line mode, type :s/fizz/buzz/g
to replace every instance of the word fizz inside your highlighted lines with the word buzz.
Your command will actually look like :’<,’>s/fizz/buzz/g
when you run it, as vim will automatically prefix those special characters for you.
You can also use regular expressions to craft advanced search queries.
If you’re using visual character mode to make selections within a line, try using :s/\%Vfizz/buzz/g
instead. The first approach would include results outside of your selection by mistake (if they lived within the same line).
Manipulate Letter Casing
Last but not least, you can type U
to make all of the letters in your selection UPPERCASE, and u
to convert them into lowercase.
The tilde character ~
can be used to invert existing letter casing, transforming a selection like fizzBUZZ
into FIZZbuzz
Place Bookmarks Within Large Files
Organized folders with bite-sized source files are always appreciated, but opportunity cost often leaves behind 800-line scripts to maintain long-term.
With files that large, it’s easy to get lost in the middle of a big refactor.
Whenever you find yourself jumping wildly across a particular file, try using bookmarks to save your place (instead of constantly scrolling up and down).
Type the m
key, followed by the letter you want to map your bookmark to, and you can easily jump back to that spot in your file moving forward.
Example: ma
will create your bookmark, and 'a
/ `a
will jump to it.
Single-quotes jump to the beginning of the line you placed your bookmark on, and backticks will jump to your bookmark’s exact position in the line.
You can also type :marks
, followed by the Enter key, to view all of your active bookmarks and the letters you mapped them to (as shown below).
Modify Text Surrounded by Special Characters
As a software engineer, you’ll often want to modify code that’s wrapped inside two matching curly brackets, parentheses, double-quote pairs, etc.
Pretend we want to manipulate the Lorem Ipsum
string within this snippet:
After moving our cursor on top of any of the letters contained within the string, we can type vi"
to select all of the text inside the double quotes:
We’re now in visual mode and can manipulate our selection accordingly.
Want to include the double-quote characters within your selection as well? Use the va"
command instead (by swapping out the i
with an a
).
Here a few more useful scenarios where you can apply this technique:
Visual mode isn’t the only possible destination. Swap out the v
at the beginning of your command to perform different actions on your snippet.
If you type di
or da
before your special character, you will delete the enclosed text, and intentionally remain in normal mode afterwards.
You can also use ci
and ca
to delete the enclosed text, and automatically drop into insert mode to change the text you just removed.
Make Precise Cursor Adjustments
To complement the line-based navigation shortcuts mentioned earlier, vim offers another efficient way to manipulate your cursor’s position.
It involves using the search command in an unconventional way, and will help you make complex cursor adjustments across multiple lines at once.
Buckle up. This is a long chapter, and your future self will thank you.
Let’s start with the basics before diving into the advanced stuff.
You can search for text within the current file by typing a forward slash, followed by the text (or regular expression) you’re looking for.
Example: /find-text-AFTER-my-cursor
When you hit ENTER
, vim will instantly jump to the first occurrence of your search query (assuming it comes after your cursor’s current position).
After the initial search, hit the n
key to jump to the next occurrence of the phrase you searched for, or N
to jump to the previous occurrence.
Once you iterate over the last occurrence of your query using the n
key, vim will wrap around and start searching again at the top of your file.
You can also search for text behind your cursor’s position by replacing the forward slash with a question mark: ?find-text-BEHIND-my-cursor
When you use this approach, the n
and N
shortcuts will work in reverse.
The core idea is that searching causes your cursor to jump around the file, and this allows us to use the feature in an unconventional way to save time.
In the next image, our cursor will immediately teleport from its starting position, all the way down to the access token snippet we want to modify.
We know exactly where we want our cursor to go, so let’s place it in that spot with our first command, and shave off a few unnecessary keystrokes.
Instead of chaining together 5 separate navigational commands to arrive at our destination, we’re teleporting there with a single search command.
The phrase /acc
only appeared once, and we jumped to the exact spot in the code we wanted to update (without ever needing to pick up a mouse).
Remember, we’re using the feature to navigate around more efficiently. We’re not actually “searching” for a query string in the traditional sense.
Your cursor moves around whenever you search in vim, and we’re training our brain to notice patterns and opportunities where we can take shortcuts.
If we know exactly where we want our cursor to land, and “search” for a unique string of characters near our destination, we can achieve complex cursor adjustments (across multiple lines) with a single, efficient command.
Let’s chat about some common scenarios where you can use this trick.
How to Find Unique Strings Quickly
In an ideal world, we would craft a short, simple query that would get us to our destination immediately (while not requiring any additional jumps).
However, shorter queries also mean more results you’ll need to tab through.
We searched for /acc
earlier and jumped to our destination instantly.
What happens if we shave off a character, and search for /ac
instead?
While it’s not the end of the world, shaving off one character introduced four more search results we need to tab through with the n
key.
This process is supposed to be efficient, and that query isn’t saving us time.
One quick tip is to always keep an eye out for opportunities to incorporate special characters (like parentheses, spaces, and curly brackets) into the mix.
Strings like /ac
are common, but /(ac
likely only appears once or twice.
Think about all of the special characters in this image: < : = ( . @ _
We’re almost always trying to jump to the beginning or ending of a phrase, and they’re often accompanied by a special character of some sort.
This eliminates a ton of the guesswork involved with finding unique strings, and within a few days you’ll start seeing these opportunities everywhere.
Another trick is to pair your searches with the “Jump to Line” command…
Since /query
searches for text after your cursor’s current position, chaining these two commands together lets us create much simpler query strings.
As soon as we jump to line 8 with 8G
, our /(
command is going to search for the first left parenthesis in the current line. When we’re only talking about a single line, finding a unique string of characters is a piece of cake.
I find this to be the most consistent approach that works every time.
There’s usually a simpler way to get there with fewer keystrokes, but I don’t want to waste brain power finding it. This approach still takes a split second, and is the one I rely on most often to move my cursor between lines.
Store Multiple Snippets In Your Clipboard
While your operating system’s default copy/paste functionality is great for basic tasks, it can be a bottleneck when manipulating complex codebases.
Fortunately, vim lets you copy and paste multiple snippets at the same time.
Type "ay
to copy and map your selection to the letter a, or "ax
to cut it.
"aP
pastes the snippet before your cursor. "ap
pastes it after the cursor.
To store an additional selection within your clipboard, swap out the a
in the previous commands with another letter of your choosing: "by
+ "bp
Consider Installing IDE Plugins
While I love hacking away inside my terminal as much as the next engineer, there are a number of great plugins out there designed to let you use vim’s keybindings natively within most of the popular IDE’s on the market.
vim is still regarded as one of the “gold standard” text editors for a reason, but occasionally comes up short compared to modern-day IDE’s when we’re talking about file navigation, breakpoints, automated code inspections, variable name auto-completion, global find-and-replace, etc.
I’m sure there are a number of great plugins that would make my terminal feel more seamless, but I just don’t have much time to tweak my dev setup these days, and want to focus my limited bandwidth on actual code.
You can only get deeply involved in so many hobbies. If you find yourself in the “I just want it to work out of the box, and don’t care all that much about customization” camp, pairing a gold standard IDE with the keystrokes from an official vim plugin can feel like a match made in heaven.
While your setup will be slightly less configurable in the grand scheme of things, you’ll still retain 90% of what makes vim exceptional, and get to use robust, IDE-specific features that the terminal purists secretly envy. 😉
Don’t Repeat Tedious Work. Record it.
Have you ever burned 28min on a Friday afternoon, manually adjusting hundreds of rows in a CSV file, server config, or raw access log?
Source code is important, but it’s not the only type of text we manipulate throughout the day. Along with regular expressions, vim macros are a must for the cumbersome data requests that pop up once every few weeks.
Cleaning up messy data sources often involves repeating the same work multiple times in a row, and you deserve an easy way to automate it.
Whenever you find yourself wanting to update hundreds of lines with a similar structure, but different content, macros are a great way to save time.
The core idea is that you record yourself manually manipulating text once, and then ask vim to modify all of the subsequent entries automatically.
Pretend you want to make the following tweaks to each row in a CSV file…
- Swap the
first_name
andlast_name
columns - Downcase every letter within the
email_address
field - Prefix the
employer_website
column with https:// - Sanitize the
phone_number
field by removing all non-digit characters
Macros work with every type of file, but CSV’s are a great example to highlight how they can make tedious, repetitive work disappear.
You would start recording by hitting the q
key, followed by the letter you want to save your macro to (like in the bookmark and clipboard examples).
Let’s pretend you started recording your macro to the a
key by typing qa
vim now says recording in the bottom left, which is your cue to manually perform your text manipulations once across the first row of the CSV.
Hit q
again when you’re ready to stop recording.
After manipulating the first non-header row and saving the steps you took, vim can now recreate your manual work across every other line in the file.
@a
will play your recording back once. X@a
repeats it multiple times.
Let’s type 300@a
to repeat your manual work 300 times in a row.
Pretty sick, right? — That GIF wasn’t sped up. It actually happens that fast.
You’ll need to learn a few more concepts to avoid shooting yourself in the foot, but that’s the basic idea behind how macros can make your life easier.
Check out these in-depth video tutorials to learn about the finer details.
Don’t worry if this feels like a lot of information to digest in one sitting.
Macros will save you a tremendous amount of time in the long run, but require a few weeks of fumbling around before everything starts to click.
They also combine most of the other concepts we talked about today, so I’d recommend putting them to the side if you just started your vim journey.
Thanks for making it to the end!
If you found this post valuable, you might enjoy some of my other ones…
Resume Template for Programmers
This part of the job hunt gave me so much anxiety early in my career. If you’re in a similar position, and feel like you don’t know where to start, my hope is that this template can give you a solid jumping off point.
Bridging the Gap Between Junior and Senior Engineers
The value senior engineers provide, and a few reasons to stop worrying about your technical skills becoming obsolete