This article was originally posted in barbarianmeetscoding.com. 😊 The videos should autoplay, but it looks like I can't add a video tag linked to my blog so I uploaded them to youtube and you'll need to play them manually 😅 .
Welcome to the Exploring Vim Series!
If you haven't checked them out yet. Take a look at the previous articles in this series. Happy vim-ing!
The struggle is real. The dip is real. Every time we adopt a new tool, a new framework, learn a new skill, there's gonna be that period of time in which our productivity is going to drop and we're going to suck. No one can be consistently awesome at something for the first time. The question is: Do you have the patience and grit to push through the other side, beyond the dip, where skill, productivity and mastery await?
Getting Through the Dip Can Be Preeeettyyyy tough...
You probably recognize this pattern. You find out about a new thing 1. You are full of excitement and enthusiasm and you hungrily start trying it out and learning about it. After a while, the excitement fades, the enthusiasm disappears and, all of the sudden, you find yourself procrastrinating and finding excuses not to do it any more. That's the dip right there.
So will you quit or will you push through? You are the only one who can make this decision. Is it worthy to you? Envision yourself empowered by that new tool, that new skill. Now, is it worthy?
If it is not, then better to quit right away, before you have wasted more time. If it is worthy, then roll up your sleeves and let's kick some ass.
Exceptional benefits accrue to the tiny minority of people who are able to push just a tiny bit longer than most. Seth Godin, The Dip.
In this article I've gathered a set of vim skills to ease your journey through the dip. Learn these skills first, practice, get to a moderate level of competence and you'll be over the dip and on your way to awesome text editing fu.
You don't need to learn them all at once. Just read the article, get familiar with the things that are available and go incorporating them in your workflow as it makes sense to you. If you've read some of my previous articles you may find some repetition. Worry not. Repetition is good. Repetition is how you learn. The biggest productivity gains with vim come when the commands become part of your muscle memory and for that you need lots of practice and repetition. At the end of the article I will also share some tips of how to approach learning and becoming better at vim in more general terms.
Oh one last thing before we proceed. This article works both for those interested in using vim as their primary editor or those of you that don't really feel like taking the leap but are still interested in using vim within your current editor (like VSCode). If you are in the latter camp, then just pick and choose the features that complete your current workflow (f.i. normal mode operators and motions are a perfect candidate to start).
A Note on Notation
Whenever you see a reference to a key combination like so
<C-R>
, it means that you have to press the CTRL and R keys simultaneously. That is, whatever inside < and > refers to a key combination. When denoted like this, you're not supposed to type < and >.
Ok! Let's get started! First things firsts... in order to use vim, you need to open it!
Opening, Creating and Saving Files in Vim
The most common way to open vim is through the terminal, using either vim
(or nvim
if you're using neovim). Alternatively, you can use gvim
or mvim
for the GUI counterparts of vim.
So:
$ vim
will open vim in the current directory (you can verify that by typing the :pwd
command which stands for print working directory. :h pwd
for more info).
Aliasing for the win
Find yourself typing the same things within your terminal over and over? Then consider creating an alias.
For instance, use v instead of vim or nvim. Creating an alias in zsh is as easy as writing the following bit in your
zshrc
:
alias v="nvim"
Create once, enjoy for ever.
A slightly better approach is to specify the current directory as follows:
$ vim .
This improves the previous example in that now you'll be able to see a file explorer that you can navigate through to open a specific file. In order to do that, you use the same motions that you use whenever you're in normal mode. For instance, jk
allow you to move the cursor up and down whilst <ENTER>
will open a file:
Normal Mode
As you learned in previous articles in the series, vim is a modal editor. That means that vim has different modes in which you do different things like changing text, inserting text, selecting text, operating on lines of text, etc. By having separate modes for performing different tasks, vim can provide key bindings that are very easy to type as they fall comfortably under the keyboard home row and its proximity.
The most common mode within vim is normal mode. In this mode you use the keyboard to navigate swiftly through a file performing text changes with surgical precision. If you need a refresher about normal mode take a look at Exploring Vim.
Vim comes with a built-in file explorer called netrw but you may want to check the NERDTree plugin. NERDTree gives you a nicer user experience, more akin to what you can find in modern editors:
Anyhow, better than opening a folder is to open a file or a collection of files directly:
# open a file
$ vim src/hello.js
# open multiple files in separate tabs
$ vim -p src/hello.js src/world.js
# open multiple files in separate windows split horizontally
$ vim -o src/hello.js src/world.js
# open multiple files in separate windows split vertically
$ vim -O src/hello.js src/world.js
# open multiple files using a glob pattern
# This particular glob means, open all js files in the src folder
# The -O opens them in separate windows split vertically
# you can also use -o and -p
$ vim -O src/*.js
Surprisingly you can also open files from within vim (Woaaaa!). You can achieve this feat using the :edit {pathToFile}
(shorthand :e
) which will open a file in your current window. This command, like many others, supports TAB completion. If you write :edit <TAB>
you'll be offered a list of choices just like you do when you're in the terminal.
You can use the same command to create a new file. Type :e {pathOfTheNewFile}
and voila, a new file springs to life. Beware though! The new file will be kept only in memory until you save it with :write
(shorthand :w
).
The :e
command expects a full path in relation to your working directory (remember :pwd
?). A useful command for creating new files in the same folder as the one you're currently editing is to use :e %:h\{newFileName}
. The %
stands for current file, the :h
is a modifier that gives you its path, and then we just append the name of the new file we're interested in creating.
When you're done editing things you can either:
- save a file and quit with
:exit
(shorthand:x
). - quit without saving
:quit!
(shorthand:q!
).
If there are multiple files you can:
- use
:xall
(shorthand:xa
) to save all of them and quit - or, use
:qall!
(shorthand:qa!
) to quit without saving
There's a lot of combinations of :write
and :quit
which will prompt you whether you want to save or quit under different conditions. If you are curious you can take a look at the help for these commands but knowing the commands above should be enough 99% of the times.
So now you can open AND more importantly exit vim. No more getting trapped inside vim. Ever. Again.
Overwhelmed by all the commands?
I know! There are loooooads of commands. But bear with me. A lot of the commands are easy to learn by just guessing. Think about what you want to do or the action that you want to perform. It is very likely that the word you're thinking is the name of the command you're looking for: edit a file, close or quit the current window, etc.
When in doubt, use vim's help.
So! We're inside a code file. What can we do next?
Moving Swiftly Inside A File With Vim Motions
Are you a Touch Typist?
Can you touch type? Touch typing is extremely helpful when learning and using vim. For being the most effective with vim, your hands must rest in the home row and your fingers should reach up and down like a touch typists'. In Exploring Vim I shared a bunch of resources that can help you become a better touch typists. Go take a look if you haven't read it!
hjkl
is the name of the game. These 4 keys are your new religion. Naaaah. They're not. They're great for short distance movements but there are far greater ways to move around in vim.
To move horizontally (that is left-right or right-left), you can jump from one word2 to the next by typing w
(as in word) or use b
to go backwards (as in back). Alternatively, you can jump to the end of the next word using e
(as in end) or use ge
to go backwards.
On Notes, Melodies And Chords
Vim is quite special. If you've used other editors you're probably accustomed to typing chords of keys. That is, typing a combination of keys at the same time. For instance, CTRL-C to copy and CTRL-V to paste. Vim uses chords as well but relies even more on melodies of keys.
If you think of keys as notes, a melody is a series of notes one after the other. That's the most common way to work with vim when you're in normal mode. So, when you read that you need to type
f{char}
to find a character in a line it means that first you typef
and then you type the character{char}
. This, although unfamiliar and kind of strange, is very convenient as controlling the editor suddenly feels like just typing text. It is also great for your wrists' health.
To move horizontally faster you can use f
and t
(which have the F
and T
variants to go backwards). f
lets you find the next occurrence of a character in the line you're in. f{char}
(as in f"
f.i.) brings you to the next occurrence of that character ("
in our example).
You can then type ;
to go to the next occurrence or ,
to go to the previous. You can see the ;
and ,
as repeating a search.
The t
motion is very much like f
. The only difference is that f
places the cursor on top of the character you want to find whereas t
(think un*t*ill) places it just before. Knowing the difference will be helpful when combining these motions with operators such as delete and change as you'll see in a bit.
To move extremely horizontally, that is, to the beginning or the end of a line you can use:
-
0
moves to the first character of a line -
^
moves to the first non-blank character of a line (so it would exclude the indentation of a line of code for instance) -
$
moves to the end of a line -
g_
moves to the non-blank character at the end of a line
Since these keys are slightly hard to type, I prefer to use these mappings playing with the idea that H
and L
are stronger versions of h
and l
:
nnoremap H ^
nnoremap L g_
So where h
moves you one character to the left, H
takes you to the beginning of a line. Where l
moves you one character to the right L
takes you to the end of a line.
Why map stuff early on?
Why bother with custom mappings early on instead of using defaults? Muscle memory! Practice doesn't make perfect, practice makes permanent. You don't want to spend time using inefficient mappings because you'll get accustomed to them, and then you'll need to unlearn that behavior before you can improve.
Much better to use and learn better mappings from the start.
Since H
and L
normal mappings aren't extremely helpful we don't need to remap them (H
takes you to the top of the window whereas L
takes you to the bottom of the window). If you still want to, try these ones:
nnoremap <Leader>H H
nnoremap <Leader>L L
To move vertically you can use {
and }
to jump paragraphs forwards and backwards. These two have a couple of disadvantages, in my opinion:
- The
{
and}
are hard to type (they require you to flex both of those pinky fingers) - Moving down a paragraph may take you too far. For instance, if you have a long-ish method with no whitespace you may be brough to the end of the method, or even worse the end of the class after many other methods. That's probably not what you want.
What you want is to have a reliable way to browse code up and down. A great way to do that is by creating the following mappings in your vimrc
file:
nmap J 5j
nmap K 5k
vmap J 5j
vmap K 5k
Now whenever you type J
you go down 5 lines and likewise whenever you type K
you go up 5 lines. Those are really nice mappings for browsing code.
But oops! Remapping something does come at a price. The J
and K
letters do stuff that some people (like me) could call useful:
-
J
let's you join a line with the next line (which I find myself using all the time when writing articles in vim). -
K
allows you to quickly navigate to help for the word that is under the cursor (by default it works with vim's help but there's nothing stopping you from configuring it to work with other documentation).
A nice way to keep these bindings near your fingertips is to take advantage of the <Leader>
key as follows:
nnoremap <Leader>J J
nnoremap <Leader>K K
vnoremap <Leader>J J
vnoremap <Leader>K K
vimrc? Leader? Map and Noremap?
Are these terms confusing to you? Don't worry! The previous article in this series explains all of them!
To move vertically faster when you actually have a target in mind, your best option is to search with the /{pattern}
and ?{pattern}
commands (to search forward and backward respectively).
Try using /{pattern}
to find something in a file (f.i. /cucumber
). You'll see that as you type, the patterns matched by whatever you write appear highlighted within vim. When you find what you want, you can type <Enter>
and your cursor will jump to the first match in the search. There you can perform some editing if you want and later use n
to jump to the next match (or N
for the previous). You can think of n
as repeating a search. And, as with many other commands, you can combine n
and N
with counts (f.i. 2n
sends you to the next second match).
Vim loves saving you time so if you happen to have the cursor on top a word, and you want to see where other instances of that word appear within the document you can type *
. The asterisk will trigger a search for that word equivalent to /{wordUnderTheCursor}
and send you flying to the next occurrence of that word.
Not Seeing Any Highlights When Searching?
Depending on how your vim is configured you may not see the pattern being highlighted as you type. If that is the case, try adding the following to your vimrc:
" highlight matches as you type set incsearch " highlight matches once a search is complete set hlsearch
Before we move forward here's a great tip: When you do a search, the pattern that you're looking for will be highlighted FOR EVER until you say otherwise. The reason for this is that it's helpful when you're repeating searches with n
and N
. But eventually you'll want those highlights gone so you can continue working peacefully on something else.
There's a command called :nohlsearch
or :noh
for short that can help you clear all the highlighted text from the previous search (see :h :noh
for more info). This is something so common that you will definitely want to have a faster mapping for it. This is the one I use:
nnoremap <Leader><Space> :noh<CR>
The last great motions to know about take advantage of Vim's jumplist and changelist and let you go back where you were a moment ago, or where you changed something a moment ago.
The jumplist is a place where vim records where you've been within vim, a collection of all motions. You can move backwards and forwards this jumplist using:
-
<C-O>
to go back the jumplist -
<TAB>
or<C-I>
to move forward within the jumplist
In a similar way, the changelist keeps a record of where you've made all the changes within vim. You can move to and fro within this list using:
-
g;
to go back the changelist -
g,
to go forward the changelist
If you want to find more about either list, use the help: :h jumplist
and :h changelist
.
There's a couple more commands that you may use occasionally. They aren't life altering but they are good to know:
-
%
helps you move between matching brackets. It can be helpful if you want to move to the end of a method or class. -
gg
sends you to the beginning of a file whileG
sends you to the end. This can be helpful if you want to perform actions on a whole file:gg{action}G
. gg also works with counts, if you type{count}gg
it sends you to a specific code line within a file.
Ok! So now you have an awesome foundation in moving quickly around a file. Which is in itself pretty cool but wouldn't it be better if you could combine that with actual text editing? Let's take a look at that next!
Text Editing Like There's No Tomorrow
Let's start with a command that is very straightforward: delete or d
. Delete lets you delete characters, words, sentences, and other stuff into oblivion. But it doesn't make sense to just use the delete command on its own, you need to combine it with something that specifies what you want to delete. Well, you've just learned a bunch of motion commands that, if you think about it, represent positions of the cursor. Yes! Motions are perfect for defining what we want to delete!
Combine the delete command with l
and you delete one letter. But that isn't exactly what it is happening (although it makes for an awesome mnemonic). dl
or d{motion}
actually means delete text that {motion}
moves over.
Where do I want to get to with this? To the realization that we can also do dh
to delete the previous letter or dj
and dk
to delete up and down. Vim doesn't give you a bunch of arbitrary commands that you need to memorize, it gives you lego pieces that you can combine together to achieve expected results. What happens when you combine a piece of meat with salt? You get salty meat. What happens when you combine d
(delete) and w
(move to next word)? You delete everything until the next word. And so:
-
dJ
as remapped previously deletes 5 lines down -
df'
deletes everything in the current line until the first occurrence of the'
character (including the character) -
dt'
would do like above but excluding the character (so up until just before) -
d/hello
deletes everything until the first occurrence ofhello
-
ggdG
deletes a complete document
Isn't that super cool?! This amazing command composability is one of the most awesome features in vim.
In addition to combining operators with motions, operators have two other variants:
- The linewise operator that applies an operator over a complete line. You get it if you "double" the original operator. For instance, in the case of
d
the linewise variant isdd
which deletes the current line. - The uppercase operator which is a stronger version of the original one and applies it from the cursor to the end of the line (I use this ALL. THE. TIME). In the case of
d
, the uppercase variant isD
which deletes from the cursor to the end of the line.
There's a couple more interesting things to discover when combining operators and motions: counts and text objects.
You saw earlier how we can use counts with motions so that we can, for instance, go down 5 lines with 5j
. Likewise we can use counts with operators and delete 5 words 5dw
or 5 lines 5dd
.
Finally we have text objects. I'll be honest with you, the name sounds scary and complicated (at least it does to me). Text objects means structured pieces of text or, if you will, the entities of a document domain model. What is a document composed of? Words, sentences, quoted text, paragraphs, blocks, (HTML) tags, etc. These are text objects.
The way that you specify a text object within a command is by combining the letter a
(which represents the text object plus whitespace) or i
(inner object without whitespace) with a character that represents a text object itself: w
for word, s
for sentence, '
"
for quotes, p
for paragraph, b
for block surrounded by (
, B
for block surrounded by {
and t
for tag. So to delete different bits of text you could:
-
daw
to delete a word (plus trailing whitespace) -
diw
to delete inner word -
das
to delete a sentence (dis
delete inner sentence) -
da"
to delete something in double quotes including the quotes -
di"
to delete something inside double quotes -
dap
to delete a paragraph -
dab
da(
orda)
to delete a block surrounded by(
-
daB
da{
orda}
to delete a block surrounded by{
-
dat
to delete an HTML tag -
dit
to delete the contents of an HTML tag
Combining text objects with operators is extremely powerful and you'll use them very often. Stuff like cit
, ci"
and cib
is just brilliant.
What's the advantage of using text objects over regular motions? If this is the first time you hear about text objects you may be confused with dw
and daw
. What is the difference? Doesn't dw
also delete a word? Your confusion is perfectly justified because I glossed over a small detail earlier for the sake of simplicity. Here's how it goes:
-
dw
deletes from the current position of the cursor to the beginning of the next word. -
daw
deletes the word + trailing whitespace of the word the cursor is on top of regardless of where the cursor is.
When are dw
and daw
equivalent, then? The results of dw
and daw
coincide when the cursor is placed at the beginning of a word. (Careful though, we'll later see how the repeat operator makes daw
be far more useful than dw
).
Finally, vim has yet another trick in store for thee that has put up with all this text up until here aimed at saving you more keystrokes: The magic .
command. The .
command allows you to repeat the last change you made. Imagine that you run dd
to delete a line. You could type dd
again to delete another line but you could also use .
which is just a single keystroke. Ok, you save one keystroke, so what? Well, you can use the .
command to repeat any type of change, not just single commands. For instance, you could change a word for "Awesome" like so cawAwesome<CR>
, and then repeat that whole command with all those keystrokes by just using .
. Think of the possibilities!
The .
command works great in combination with the repeat search commands (;
, ,
, n
or N
). Imagine that you want to delete all occurrences of cucumber
. An alternative3 would be to search for cucumber /cucumber
then delete it with daw
. From then on you can use n
to go to the next match and .
to delete it! Two keystrokes!?! Again think of the possibilities!!
As we mentioned earlier, the dot command .
makes text objects far better than motions because operators are more repeatable in combination with text objects that they are with motions. That is, text objects are more likely to result in the desired behavior when repeated on other pieces of text (since you don't need to care as much where the cursor is positioned).
Now! Let's look at a slightly more involved and better command: c
stands for change. Why is c
better than d
? Because c
allows you to do two things at once. It lets you change bits of text which is the equivalent to deleting something (d
) and inserting something (i
). Do more with less commands? Sounds good to me. The mechanics of c
are as follows. You type:
{count}c{motion or text-object}
And you delete the bit of text specified by the count and motion/text-objects just like the d
command. But in addition to that, you automatically change to insert mode where you can type stuff. For instance, let's say that we want to change the contents of this string below:
const salute = 'I salute you oh Mighty Warrior'
We could use (1) d
+ i
:
f'di'iHi<ESC>
Or (2) c
:
f'ci'Hi<ESC>
Both result in a new string:
const salute = 'Hi!'
We saved one character but there's something even more important at play. By using c
instead of d
+ i
we've made the change more repeatable. Using the .
command with the first example (1) would've just inserted Hi
, whereas with (2) the .
command encapsulates changing any string for Hi
. It may seem weird right now all this fixation in saving keystrokes and making repeatable changes but it is something that will come naturally to you as you become more adept at using vim. After a while these things will move from your consciousness into muscle memory and your subconscious and you'll just do them as second nature.
In addition to this, c
works with all the motions and text-objects that we've seen thus far: caw
changes a word, cas
changes a sentence, c/wop
changes everything until something that matches /wop
, cc
changes a complete line and C
changes everything from the cursor to the end of the line.
As the lasts commands in this section we're going to look at y
and p
. y
is the yank command, or copy in vim jargon. p
is the put command, or paste in vim jargon.
You can combine y
with any of the motions and text-objects we've seen thus far to yank (copy) stuff to you heart's content: yaw
yanks a word, yas
yanks a sentence and so on.
The p
command on the other hand lets you paste stuff after the cursor (and P
before the cursor). A cool thing about p
and P
is that they work with counts as well. That is, using y
in combination with {count}p
allows you to easily duplicate stuff tons of times.
If y
copies stuff... how do you cut stuff in vim? Aha! Here comes a surprise. Do you remember d
and c
from 30 seconds ago? Well, when I said that they deleted text into oblivion I LIED! They actually cut text into a register. Text that you can later paste if that is what you want (mindblown).
There's a lot of interesting things that you can do with the 10 different types of registers that are available in vim but that is stuff for another article. For starters, knowing d
, c
, y
and p
is more than enough.
One thing that is super convenient is to have your system copy and paste use the same register that d
,c
,y
and p
do (which is called the unnamed register). That makes it very easy to copy stuff from vim into other applications and vice versa. If you are using neovim you can enable this behavior in your vimrc:
set clipboard+=unnamedplus " use system clipboard
Likewise in traditional vim:
set clipboard=unnamed " use system clipboard
Copy and Pasting Characters vs Lines
One thing that you may want to look out for is how pasting works slightly different depending on what you've copied. If you copy some characters then pasting works character-wise, that is, when you paste them they'll be positioned after the cursor within the same line. If you, however, copy complete lines, then pasting works line-wise. In this case the copied lines will be pasted in the line below the cursor.
If you copy a line and want to append it after the cursor within the same line, you can do that by going into insert mode and pasting from insert mode with
CTRL-R "
.
There are more secondary operators available like =
(format code), <
>
(decrease and increase indentation), ~
(toggle caps), x
(delete a character) and s
(change a character) but you don't need to learn them right away. With what we've seen thus far in this chapter you are good to start your editing adventure and kick ass like the Hero of Ages.
An Amazing Way To Extend Vim...
One awesome thing about vim is its infinite extensibility. A very interesting way to extend vim is by creating your own operators and text-objects. For instance, you can create a new operator to surround stuff with characters like quotes, parentheses or even HTML tags. Or you can create new text-objects like a complete document, or a Markdown title, or a JavaScript function, etc...
Why is this so cool?
Because you can combine these new operators and text-objects with all the existing ones, and even with those yet to be invented. Having defined a new operator surround allows you to surround a word, a sentence, a block, and HTML tag and so on. Having defined a Markdown Title text-object you could change it, delete it and so on. Awesome!!
Inserting Code a.k.a. Writing Code
Sooner or later you will have to write some code. In vim, you write code in insert mode. You've seen a little bit of insert mode when using the c
command but let's look at it some more. There's two core commands that put you into insert mode: i
for insert and a
for append.
The i
insert command puts you in insert mode before the cursor. While the a
append command puts you in insert mode after the cursor (as if to append stuff wherever the cursor is placed). From then on you're in insert mode and vim pretty much behaves like any other editor.
Like with many other vim commands i
and a
have uppercase counterparts that do stronger versions of insert and appending. I
puts you in insert mode at the beginning of the current line whilst A
puts you in insert mode at the end.
In addition to i
and a
there are another three super useful commands that I love to use to drop into insert mode:
-
o
inserts a new line below the current one and drops you into insert mode (mnemonic open a line below) -
O
inserts a new line above the current one and also drops you into insert mode -
gi
puts you into insert mode at the last place you left insert mode. This is great if you drop of insert mode by mistake and want to go back where you were and continue typing.
Ok, so let's say that now you are in insert mode, typing away and you make a mistake, like a typo. Do you go back to normal mode, fix the typo and go back into insert mode? No! There's a couple of bindings that can help you fix an error right from within insert mode:
-
C-h
lets you delete the last character you typed -
C-w
lets you delete the last word you typed -
C-u
lets you delete the last line you typed
Now you continue typing and you want to paste something that you've copied previously. You've learned that you paste with the p
command but that only works in normal mode. What to do? Well, in some instances (f.i. gvim and mvim) you may be able to use your system copy/paste key bindings, but you can always rely on <C-R>"
to paste from the unnamed register (which is the one you use when you copy with y
, d
or c
). The R stands for Register and "
represents the unnamed register. I won't expand on registers in this article but if you're interested take a look at :h registers
.
Autocompletion?
Did you know that vim has support for autocompletion? I won't cover it in this article but if you're interested take a look at the user manual
:h 24.3
.
Eventually though you'll want to exit insert mode and do other stuff. There are three ways to do it: <ESC>
, C-[
and C-C
. Of all of this, the easier to type is C-C
but for something that you do sooooo very often as leaving insert mode it is better to create a nifty mapping:
" Thank to Steve Losh from Learn Vimscript the Hardway for this one!
" I was using jj before, but this one is so much nicer...
" map jk to <ESC>
inoremap jk <ESC>
" burn the ships so you can't go back
inoremap <ESC> <nop>
Now whenever you're in insert mode you go and type jk
and voila. Back in normal nome. The jk
is so natural and swift that you won't understand how you ever used <ESC>
in the first place.
Undoing and Redoing
Also sooner or later you will make mistakes. The command for undoing stuff in vim couldn't be more intuitive. Nope, it's not C-Z
or Command-Z
. It is u
for undo. If you need to redo you can use C-R
(R
for redo), although if you only need to redo once you can use the .
command to repeat the last change (that yo just undid). Again, as usual U
is a stronger version of u
and undoes all changes made to the last line that you changed.
Vim is very special in that provides multi-level undo, that is, every time that you undo stuff and start doing something different you create a new branch of undos. Vim keeps all of these branches available for you to tinker with so no change is lost. You can find more info about this topic in :h undo-branches
. One nugget: If you use :earlier 1f
you can undo all changes you did from the last time you saved a file. Fear not for you can do :later 1f
to go forward in time. (You can also repeat any of these commands to go backwards and forward in time. Cool or what?).
Abbreviations. They Sound Boring But They Are Awesome
Abbreviations are the snippets of vim. They are probably a simpler version of snippets you find in other editors and IDEs (there's vim plugins for that) but they're very handy nonetheless. A cool thing about abbreviations is that they are expanded automatically after typing them and pressing <space>
which fits in perfectly with the natural flow of typing text. Although they can expanded explicitly by typing C-]
if that's what you want.
You define abbreviations using the :iabbrev
(shorthand :iab
) command. The i
in iab
stands for insert mode as these are abbreviations that are only applied to insert mode. For instance:
:iab konw know
Now every time that I misspell the word 'know' as I often do, vim will come to the rescue and fix it for me. I don't even need to do anything myself. I just type konw
and vim will just fix it.
But abbreviations aren't just for mispellings. You can use them as, well, abbreviations:
:iab bmc http://www.barbarianmeetscoding.com/
Or snippets:
" The Left command puts the cursor
" inside the function argument section
:iab f function(){}<Left><Left><Left>
Snippets work quite well in tandem with autocommands or filetype plugins so they're only loaded in file types where they make sense. That is, you want your JavaScript snippets to be available only when in JavaScript. For now however we shan't go deeper into these waters. We'll keep autocommands and filetype plugins for later articles. (But if you can't wait, go take a look at this and this and this)
Up until now we've just defined abbreviations ad hoc using Ex commands. Since it is very likely that you want to reuse your abbreviations. You'll want to add them to your vimrc file (you may even want to have them in a separate file sourced from your vimrc):
iab konw know
iab bmc http://www.barbarianmeetscoding.com/
iab f function(){}<Left><Left><Left>
Windows And Tabs Wizardry
One amazing feature in vim is it's wondrous facility for spawning windows and tabs. Let's look at windows first because they're definitely a favorite of mine.
Earlier we saw how you could open a file in the current window using the :edit
command. Well there's an alternative command that opens a file in a horizontal split :split
(shorthand :sp
) and yet another one that does the same thing but in a vertical split :vsplit
(shorthand :vs
). This is much easier to see with a diagram:
And with a video:
You can split your workspace to your heart's content. When you want to move from one split to the next you can use the following bindings:
-
<C-W>h
takes you to the split on the left (also<C-W><C-H>
) -
<C-W>j
takes you to the split below (also<C-W><C-J>
) -
<C-W>k
takes you to the split above (also<C-W><C-K>
) -
<C-W>l
takes you to the split on the right (also<C-W><C-L>
) -
<C-W>W
lets you switch windows (also<C-W><C-W>
)
These are great but can be made better. Let's remap them:
nnoremap <c-h> <c-w>h
nnoremap <c-j> <c-w>j
nnoremap <c-k> <c-w>k
nnoremap <c-l> <c-w>l
nnoremap <c-\> <c-w>w
Another useful window related bindings are:
-
<C-W>o
or<C-W><C-O>
closes all other windows and makes the current window the only one on the screen. Notice how all of these bindings work with or without keeping the control key down for the second letter? That's nice because it means that you can keep the Control key pressed while you go fromW
toO
. Watch out for this pattern which is quite common at aims at giving you more speed.
You can also create splits with the <C-W>s
(split) and <C-W>v
(vertical split) commands, but you should avoid them. They require 2 steps to open a file: (1) create split, (2) open file. Using :sp {file}
and :vsp {file}
is far more effective since they work in just one step.
The window warlock not only can create windows but can also move them around and resize them at will. You don't need any of these to get through the dip, but it does look quite impressive. Let's take a brief look at how to resize a window:
- Use
<C-W> >
and<C-W> <
to resize a vertical split (as a mnemonic think about a vertical split increasing and decreasing it's width) - Use
<C-W> |
to have a vertical split take its maximum width - Use
<C-W> +
and<C-W> -
to resize a horizontal split - Use
<C-w> _
to have a horizontal split take its maximum height - Use
<C-W> =
to have all splits have equal dimensions
Either of these work with counts, so you can type 5 <C-W> >
or <C-W> 5 >
to make a vertical split that much bigger. Feel like these mappings would be hard to remember? Then try the :resize
and :vertical resize
commands instead.
Check :h window-resize
and h: window-moving
if you're interested into learning more about either resizing or moving. I don't normally resize or move my windows around, but if you do, then I reckon you may want to do some remappings to have these more easy to reachable.
So we've seen windows. What about tabs? I don't use tabs often, I find that splits work great for me but if you are a tab person you'll be happy to hear that vim has great tab support as well.
You can create a new tab using the :tabedit
command (shorthand :tabe
), type it on its own and you'll create an empty tab, use :tabedit {file}
and you'll open a file in a new tab. If you want to move an existing window into its own tab you can do <C-W>T
.
Once you have a bunch of tabs open you can move between tabs using:
-
gt
to move to the next tab -
gT
to move to the previous tab -
{count}gt
to move to the tab numbercount
You can also close all tabs except the active one using the :tabonly
command.
Since typing a full command to open a tab can be quite a feat. If you like to use tabs intensively you may want to create some convenient mappings. For instance:
" Create new tab with no name
map <Leader>tt :tabedit<CR>
" Create new tab with a file for editing
" Since there's no <CR> it allows you to specify a filename.
" The name of a new file to create or an existing one.
map <Leader>te :tabedit
" Close all tabs but the active one
map <Leader>to :tabonly<CR>
The One Thing You Should Learn About Visual Mode
Thus far we've focused mainly in the normal and insert modes but there are many more. The visual mode can come very handy when you need to select some text because it gives you visual feedback as you do it. There's three ways in which you can start visual mode:
-
v
for visual mode character-wise. When you move around you go selecting character by character -
V
for visual mode line-wise. When you move around you go selecting line by line -
<C-V>
for visual mode block-wise. When you move around yo go selecting rectangular blocks of text
The visual mode can be very helpful for copying and pasting stuff and when operating on blocks of text or code. For instance, imagine that you have a list line this one:
<h1>Inventory</h1>
<ul>
<li>Rusty Sword</li>
<li>Sword</li>
<li>Obsidian Dagger</li>
</ul>
And you want to add the same class to all the li
elements. A way to do that would be to go inside visual mode blockwise <C-V>
select the li element and then append the class using A
which in visual mode means appending at the end of the selected block:
2jww<C-V>lAclass&eq;"inventory-item"<ESC>
Making the appropriate selection may be tricky some times. Vim will only let you move one extreme of the selection at a time (which makes sense), so if you need to manipulate either one you can use o
(O
in visual block mode) to change which end you're moving at a given time. This is easier seen than read:
A Very Useful Ex Command
The command-line mode is a universe unto itself and it would require a nice and long article to go through. In this article though, we're going to focus on a very helpful command that can come in very handy: :substitute
(shorthand :s
).
With the :s
command you can substitute arbitrary pieces of text anywhere within a document so it is mighty useful for renaming things. Let's say that you have the following text:
<h3>Spell book:</h3>
You can run :s/Spell/Incantation/
to replace Spell
for Incantation
. This command will look for the first occurrence of a pattern (Spell
) in a line and replace it (in this case for Incantation
). Ok. Now you may be thinking... alright, I can do this with a normal search and caw
. What's the big deal?
One cool thing about the :s
command is that it allows you to operate on big ranges of text at once. Let's say that we expand on the previous example to represent a spell book:
<h3>Spell book:</h3>
<dl>
<dt>Fireball Spell</dt>
<dd>A bright streak flashes from your pointing finger to a point you choose within range and then blossoms with a low roar into an explosion of flame. Each creature in a 20-foot-radius sphere centered on that point must make a Dexterity saving throw. A target takes 8d6 fire damage on a failed save, or half as much damage on a successful one. The fire spreads around corners. It ignites flammable objects in the area that aren't being worn or carried.</dd>
<dt>Cone of Cold Spell</dt>
<dd>
A blast of cold air erupts from your hands. Each creature in a 60-foot cone must make a Constitution saving throw. A creature takes 8d8 cold damage on a failed save, or half as much damage on a successful one. A creature killed by this spell becomes a frozen statue until it thaws.
</dd>
<dt>Raise Dead Spell</dt>
<dd>
You return a dead creature you touch to life, provided that it has been dead no longer than 10 days. If the creature's soul is both willing and at liberty to rejoin the body, the creature returns to life with 1 hit point.
</dd>
</dl>
// Credit for descriptions goes to: https://roll20.net/compendium/dnd5e
You can run :%s/Spell/Incantation/g
to replace all occurrences of Spell
in a file at once. What do the %
and g
mean though? The general form of the :s
command (as with many ex commands which are designed to operate on lines of text) is like this:
:{range}s/{pattern}/{replace}/{flags}
So %
is a special range that tells vim to apply the substitute command in all the lines of a file. Using ranges you can limit the area of application of the :s
command to specific lines (and any other ex command). For example, the command 0,2s/Spell/Incantation/g
would limit the substitution to the first three lines in a document.
Ranges work also great with visual mode as you can visually select a bit of text and then run :s
only on that selection. Try it out. When you select some text in visual mode and type :
you'll be surprised to find the following text in the command area: :'<,'>
. That text is a special range to denote the visual mode selection. You can go ahead and type the substitution command, run it and it will only be applied inside that area. You can find more info about using ranges in the vim user manual :h 10.3
.
The g
is the global flag which tells vim to substitute all the occurrences of a pattern within a single line. Together %
and g
let you replace patterns within a whole file. There's a bunch of useful flags that modify the way a substitution works: for instance, c
let's you confirm every substitution one by one. If you're interested about learning of other flags, take a look at :h :s_flags
(substitute flags).
A nice trick to doing substitutions is to separate them in a search and a substitution. For instance, the previous command could be decomposed in:
- A search for
/Spell
- A substitution
:%s//Incantation/g
That is, by leaving the {pattern}
empty, the substitution command will use the last search. This is very helpful because the search commands gives you visual feedback.
The :s
command is not only for renaming things, you can also do more complex tasks if you are creative. The search pattern doesn't look for exact matches, it actually uses regular expressions, so you could grab a long one liner like this one:
Between the time when the oceans drank Atlantis, and the rise of the sons of Aryas, there was an age undreamed of. And unto this, Conan, destined to wear the jeweled crown of Aquilonia upon a troubled brow. It is I, his chronicler, who alone can tell thee of his saga. Let me tell you of the days of high adventure!
And separate it into several sentences. Running :%s/\. /\.\r/g
will result in a new text broken down in separated sentences:
Between the time when the oceans drank Atlantis, and the rise of the sons of Aryas, there was an age undreamed of.
And unto this, Conan, destined to wear the jeweled crown of Aquilonia upon a troubled brow.
It is I, his chronicler, who alone can tell thee of his saga. Let me tell you of the days of high adventure!
The true power of the :s
is that you can match any pattern using regular expressions, create submatches of that pattern and transform those into other bits of text using expressions or even arbitrary vim scripts. Again, this is out of scope for this article and you don't need it when you're starting with vim.
As a bonus tip consider the following mapping:
" map ; to :
nnoremap ; :
" Remember that ; and , where used to repeat character searches
" fix command that you shadowed with the prevoius one
nnoremap <Leader>; ;
" for symmetry add the following command
nnoremap <Leader>, ,
You'll discover that you will reach out for :
very often to type ex commands. Using ;
instead of :
and saving that pinky finger from having to hold the left shift key is veeeery nice.
Remember shorthand notation!
Wop! Remember shorthand notation when using your Ex commands. It can save you lots of keystrokes in a lifetime.
Ex commands excel at operating with entire lines and saving you a lot of work with repetitive tasks. If you want to learn how you can save lots of time then take a sneak peek at :h :global
.
Jumping From File To File
Earlier we saw how you can open files with :edit
, :split
and :vsplit
, but one thing that you REALLY want in a modern text editor or IDE is a Go To File functionality. You want to be able to type <C-P>
(or another key combination), type in the name of the file and be transported to it as if by art of magic.
The best experience I've found of this type of experience in vim is using the fzf plugin. It consists on:
- The fzf fuzzy search command line utility
- The fzf-vim plugin which is a vim wrapper around this tool
Install them using your favorite plugin manager (See the previous article in this series for more information about plugin managers) and enjoy lightning fast file opening.
Once installed:
- Use
<C-P>
to open fuzzy file search - Type the name or something similar to the file you want
- As you type the name you'll be offered different alternatives
- Select the file you want and open it in the current window with
<Enter>
, in a vertical split with<C-V>
, in a horizontal one with<C-X>
and in a new tab with<C-T>
.
Navigating around with fzf-vim
Get Yourself A Nice Colorscheme
We humans really appreciate beauty and beauty is important to us. So much so that we perceive beautiful thing as working better and being easier to use. So something that can be considered banal at first, like a color scheme is actually pretty important in providing a good user experience. So go get yourself a nice color scheme for your vim and install it using your favorite plugin manager. You'll appreciate it. I'm using this one.
How to Learn Vim
Boom! And that is it! That's all you need to know to get over the dip and into your path to uber productivity. This article was quite long and we went through a lot of small and different things you can do within vim. Clap yourself in the back, now you know how to:
- Open, create and save files in vim
- Move around files swift like the wind with diverse motions
- Edit text like a cheetah using operators, counts and motions
- Insert code like you've never before
- Undo and redo at the speed of thought
- Use abbreviations to fix your spelling mistakes, save your precious keystrokes and avoid stress
- Enhance your workflow by making Windows and Tabs appear out of thin air
- Select stuff and change multiple lines at once in visual mode
- Search and replace stuff all over a document with substitute
- Jump from file to file like an archmage using fzf
- Get yourself a beautiful color scheme
Even though we covered a lot of ground, I struggled a little bit to decide which things to include and left out a lot of cool stuff that I'm saving for future articles. Regardless, if you're new to vim, please don't feel overwhelmed. The idea is not that you become proficient in vim right away, right this very moment after you've read this article. Nope. The idea is that this article and the teachings within serve as a reference, inspiration and foundation upon which to begin your vim journey. Here are some tips to help you along this path if you're willing to follow:
- Practice, Practice, Practice
- Be in the Habit of Improving Your Vim. Feel when there's pain in your workflow and fix it
- Learn to use and rely on vim's help
- If you haven't try vimtutor at least once
Deliberate Practice
Most of the reward with vim comes when the commands become part of your muscle memory. In order for that to happen, you are going to need to practice a lot. The best way to practice is to isolate the stuff you're actively practicing and focus on improving that one tiny bit at a time. So, pick one thing and focus on practicing that until you feel comfortable with it. For instance, focus on using the search command /{pattern}
to move your cursor to a position in source code instead of using the mouse or less efficient methods like hjkl
.
Creating a Habit of Improving Vim
Whenever you start feeling pain when doing something within vim (or even outside of vim), think whether there's a better way. Can you do what you're doing more efficiently? Can you create some commands or mappings to make it faster?
An important part of cultivating this habit is making accessing your vimrc
and updating it as friction free as possible. Create the following bindings:
" Make easy editing and sourcing vimrc
command! RefreshConfig source $MYVIMRC <bar> echo "Refreshed vimrc!"
" <Leader> ev for edit vimrc
:nnoremap <leader>ev :vsplit $MYVIMRC<cr>
" <Leader> sv for sourcing vimrc
:nnoremap <leader>sv :RefreshConfig<cr>
" Thanks to Steve Losh for inspiring me to create these bindings
" Go read 'Learn Vimscript the Hard Way'! :D
Now, whenever you encounter something you can improve you're just a few keystrokes away from your vimrc:
-
<leader>ev
will open your vimrc in a vertical split - Add your new magic
-
<leader>sv
will source it, refreshing your vim configuration - You're ready to start using your new improvements within vim. Wiho!
Learning To Use Vim's Help
Vim's help is truly amazing. Type :h {keyword}
and vim will do its best to fulfill your wishes and find the help you need. The {keyword}
itself can be a command, a key combination or just an action that you want to learn more about:
- What to know how the
:global
command works? Then try:h :global
. - What to know what the
daw
key combo does? Test:h daw
. - What to know about
motions
in vim? Then try:h motions
. - What to learn how to quit vim? Yes. You guessed it. Go
:h quit
Can't exactly find what you want?
Sometimes vim will have more than one match for something you are searching. If you can't seem to find what you want, try typing
:h {keyword}
and then instead of pressing ENTER useCTRL-D
. That will show you all the occurrences of the keyword within vim's help and may reveal what you're truly looking for.
Vim's help is great for precision lightning attacks of curiosity and/or need, like the ones above, but it is also great to peruse and read like a book. Type :h
or :help
and you'll be taken to the helps index which starts with help... about :help
:
How shall I help you, oh master?
A couple of highlights here to help you navigate Vim's help:
-
<C-]>
to follow a link (they're highlighted) -
<C-T>
or<C-O>
to go back - Use
/{pattern}
to search within a document as usual
After the help's help you have the user and reference manuals. The user manual is essentially a book on how to use vim, from novice to expert with topics ranging from how to move around in vim to how to create your own syntax highlighters. The reference manual is an in-depth reference of everything vim.
One thing that is really cool is that vim third party plugins also appear in the help. Just installed a popular plugin and don't quite know how it works? Then try :h {nameOfPlugin}
or check at the bottom of :help
:
Vimtutor At Least Once
If you haven't checked vimtutor yet then take a look. It is the perfect tutorial to start getting your hands dirty with vim. If you're using vim type vimtutor
in your terminal. Neovim offers a couple of nice improvements when it comes to the vimtutor: First, you can open it from within vim using the :Tutor
command; second, it is a nicer version of vimtutor that gives you feedback as you make the exercises.
Go Kick Ass!!
The next time you catch yourself being average when you feel like quitting, realize that you have only two good choices: Quit or be exceptional.
Seth Godin. The Dip
-
This thing could be something you want to learn, a new skill you want to develop, a side project, etc, etc, etc. ↩
-
A word in vim consists of a sequence of letters, numbers and underscores separated by whitespace. You can use
w
,b
,e
andge
to move words back and forth. Vim also has the concept of a WORD (in uppercase). A WORD consists of a sequence of non-blank characters separated with whitespace. You can use the uppercase version on the previous commands to move over WORDs (W
,B
,E
,gE
). For instance, you need to typewww
to move the cursor toJaime
inI'm Jaime
, whereas you need to typeW
only once to perform the same task. ↩ -
There's faster ways to do this in vim. But again it is a nice, illustrative and simple example. ↩
Top comments (12)
Thank you. This was very informative, especially the abbreviations part.
The snippets were one of the last pieces that was missing in my workflow with Vim. I refused to install a snippet plugin because I don't need that many. Now that I know about abbreviations I've created a couple for
if
statements and one for function definitions.One thing I'm still missing is the "Go to definition" feature. I know that I can use
ctags
to make that happen but I'll have to find a way to keep them updated.Thank you! Glad that you enjoyed it! :D
There's different ways in which to get that Go To Definition working:
Thanks. Now my workflow is complete.
I will go with the file watch approach to update the tag file. It will give me a good excuse to use this utility. It will be enough 90% of the time, for the other 10% I'll jump back to Sublime text.
:O
I guess my dip is dvorak (note that only used vim to a point where learn the four keys to move around and that was in a game). I love dvorak so much that I don't want to switch to anything else (tried recently colemak).
I feel like this will make things harder for me.
Do you have any recommendations on that?
Hi Anton! _^
TBH I don't know :)
If you take a look at the vim keybindings it does look like some of them were placed where they are with QWERTY in mind, particularly the basic motion keys under the right hand on the home row. There's also keys that are somewhat associated with each other and are colocated within QWERTY. F.i.
;
and,
orf
andt
ord
andc
,w
ande
. Other than that there's motions and operators spread all over the keyboard.I think that you should be able to get accustomed to using vim regardless of where they are located within a keyboard as long as your hands rest in the home row where they can reach all the keys. The most important thing is to spend some time practicing so that moving around, using operators, etc becomes natural and you no longer need to think consciously about it. Try starting with a small set of motions and commands and see if you can get comfy with them and then decide :D
This is just an opinion though, I think we need to find a vim dvorak user to enlighten both of us :D
I've used vim for years and it was great to learn some new things I wish I knew earlier. Thanks!
Informative article, I've been using Neovim for about a year now and have just learned a lot again.
Awesome! Stoked that you found it useful! 😀
@vintharas ? More like @vimtharas
🤭