A Guide to Getting Started with ViM (Part 2)
In my previous article, I introduced ViM and some very basic commands to help you navigate text in NORMAL
mode. Today, I'll be discussing copy/paste and undo/redo commands as well as find/replace (and spellchecking, as a bonus). However, before we get to these useful commands, there are still faster ways to move around in NORMAL
mode, and we really should learn these in conjunction with searching.
Jumping Between Words
First, let's learn the w
, e
, and b
command set. The first of these, w
, moves to the start of the next word. Next, e
moves to the end of the next word. Finally, b
moves back to the start of the previous word. Try these now with the following text:
This is a test, and tests are very, very important!
Notice the behavior when you get to punctuation! All of these commands treat the commas like they are their own word. You will find that it is often the case that the capitalized versions of a command will slightly modify how it works (There are some exceptions; j
and J
do completely different things). In this case, the capitalized versions, W
, E
, and B
will ignore punctuation. Practice using these commands, they are typically much faster than l
and ;
for moving around.
Another useful command is the f
command (think find). This command, followed by a single character, moves the cursor to the next occurrence of that character. F
does the same thing, but moves to the previous occurrence.
Next, four more positional commands: 0
, ^
, $
, and %
can be used for bigger jumps. 0
moves the cursor to the start of the line (think of it as the "zeroeth" character on the line). ^
moves to the first non-blank character of the line. If you've ever written a RegEx before, you'll see the similarity here, otherwise this is just one of those commands you have to take at face value. $
moves to the end of the line. Finally, you can use %
to move between matching sets of brackets, braces, or parentheses. This can be extremely useful when proofreading code that is complaining about a missing parenthesis.
Finally, the largest jump commands involve {
, }
, and g
. The braces jump back and forth between paragraphs, or, when editing code, they can be used to jump between functions or code blocks. This will vary depending on the coding language, but it's usually quite useful.
There are quite a few commands that start with the g
key. They are often related to the command performed by the key that follows them. The biggest jumps you can possibly make in a file are jumping to the beginning or end, and to do this we use gg
and G
respectively. Also, we can prefix these commands with a number to jump to that line in the document. Remember in the previous article when I recommended using set number
in your .vimrc
? This is why. It's easy to get lost in a long document, and knowing that 23gg
will take you to the 23rd line every time can be useful for getting your bearings. The g
key can also be combined with j
and k
to move up and down inside wrapped text. Remember how we remapped the arrow keys to do nothing last time? If you want ViM to move up and down more like a conventional text editor (rather than by line), you can remap your j
and k
keys to gj
and gk
by adding the following to your .vimrc
file:
nnoremap j gj
nnoremap k gk
Note that you can also use numbers before j
and k
to jump that many lines relative to the current line, which is why I chose to set relativenumber
in my .vimrc
. However, if you chose to remap these two keys, that setting won't be very useful, since while 10j
would originally move the cursor down 10 lines, the remapping would cause 10j
to become 10gj
which would move the cursor down 10 lines, including wrapped lines, which don't get numbered differently, so the usefulness of set relativenumber
is moot. I prefer the gj
and gk
mappings because most of my work is with text rather than code, so I turn the relative line numbers off and just use <number>gg
to skip around lines.
Copy/Paste (Yank/Paste)
In ViM, we call copying "yanking" after the letter associated with the command (y
). The c
command has a much different interpretation (change) which we'll get to later. The typical syntax of "yanking" is the y
key followed by a "motion". Motions include most of the movement commands I have mentioned above, as well as a few others. Let's go through the basics of yanking text, starting with yanking entire lines. To do this, position the cursor on a line of text and type yy
. This copies the entire line, including any newline characters at the end. You can then paste that line using p
. If you don't want to copy the potential newline character, you can use y$
. I have remapped Y
to y$
in my .vimrc
using
nnoremap Y y$
since the $
key is farther away than SHIFT
. By default, Y
is mapped to yy
, so this remapping won't really be a huge difference. I'll now list a few other motions to accompany y
:
yw
yanks to the beginning of the next word. There are similar corollaries for the other motions we went over above. For example,yG
yanks from the cursor to the end of the file.yaw
(read "yank a word") yanks the current word on which the cursor is placed, including leading/trailing whitespace characters.yiw
(read "yank inside word") does the same action as the previous command, but doesn't include whitespace, so it's typically more useful.yt<character>
(read "yank to") yanks up to and before the specified character. yf<character>
(read "yank find") yanks up to and including the specified character.
We should also go over the various pasting commands. Besides just p
, you can also use P
to paste the text in front of the cursor. gp
and gP
move the cursor to the end of the pasted text (some users also prefer overwriting p
to gp
since it acts more like a traditional editor).
Cutting Text
In traditional editors, there is also a "cut" command which copies text but also deletes the selected instance. There is a similar command in ViM which uses the d
key followed by a motion, exactly like the motions for pasting. dd
deletes the current line but also copies it. D
deletes to the end of the line without deleting (and yanking) the newline character. It acts like y$
above, but doesn't need to be remapped. In fact, D
and d$
do the same thing.
The x
key can also be used in NORMAL
mode to delete (cut) a single character under the cursor.
Registers
One of the places ViM outperforms other editors is in it's copy/paste registers. On most systems, when you copy to the clipboard, you overwrite what was previously copied. This is only slightly true in ViM. While the default yank/delete/paste commands appear to overwrite the clipboard (henceforth refered to as a register), the overwritten text actually isn't lost. ViM can store text in ten automatically populated registers (called the numbered registers) and up to 26 alphabetical registers. How does this work? We can use all of the commands we just learned, but prefix them with "<character>
. No, the double-quote symbol is not a typo. In place of <character>
, we can use any lowercase letter a
to z
. When pasting, we can additionally use the numbers 0
through 9
to access previously yanked text, where "0p
will paste the most recently yanked/deleted text, "1p
will paste the next most recent text, and so on. These registers automatically populate each time you yank or delete text, so they kind of act like a clipboard history.
There are some additional special registers:
+
and*
access the system clipboard. Note that this is different from ViM's clipboard. If you copy something in a web browser and pressp
in ViM, you won't get your copied text, but instead the last ViM yank. Using"+p
will produce the desired result..
(period/full stop) is a register which contains the last text that was typed in insert mode.%
contains the current filename of the document you are editing./
contains the most recent search result (more on searching later).
You can also paste from registers while in INSERT
mode using <C-R><register>
(Control + r). The default register is also called "
, (so ""p
is equivalent to p
). For instance, in INSERT
mode, <C-R>%
will paste the current filename. To see a preview of all of the registers, use the :reg
command.
All of this useful information about registers comes from Brian Storti's blog post on the subject.
Finally, a note on communicating between the system clipboard. As mentioned, the +
and *
registers are used to access the system clipboard, so they should be shared with the usual system copy/paste clipboard. However, this gets a bit tricky, especially when using things like X11 (for example, when you're SSH'ed into a server or when using ViM in a command-line window rather than one of the standalone interfaces like gvim). Play around a bit with copying and pasting, checking the registers with :reg
to see which one is being used as the system clipboard. Then, if you would prefer to use that as the default clipboard, add
set clipboard=unnamed
or
set clipboard=unnamedplus
to your .vimrc
file (use plus
if the +
register is the system clipboard). I believe there are also some operating-system-dependent ways to do this, such as using SHIFT
when selecting text or SHIFT+CTRL+V
in some Linux distros.
Search/Replace
Quickly, we can get the simpler "find without replacing" command out of the way. In NORMAL
mode, simply type /
. You'll notice a /
appear at the command line at the bottom of the screen. If you start typing, ViM will search for the text you type. Pressing RETURN
will then put you back in NORMAL
mode and allow you to cycle through the search results using n
(next result) and N
(previous result). The search result will remain active until a new search is performed, but if you want to at least visually clear the search, you can use the :noh
command (no highlighting). Note that the results will only be visually highlighted if you use the setting I provide below. Alternatively, you can map this to a key, but I've just gotten used to typing it quickly. Below are some of my default settings which I include in my .vimrc
for searching:
set hlsearch
highlights search results.set ignorecase
ignores case in searches.set incsearch
searches as you type.set smartcase
is often used in tandem withignorecase
. It causes the search to be case-sensitive
Additionally *
and #
will search for the current word under the cursor (backward and forward respectively).
To search and replace, we use the :substitute
command (:s
for short). The syntax is :<range>s/<pattern>/<replacement>/<flags>
. The allowed values for <range>
are:
- A number, in which case the command will substitute on that line only,
.
, which substitutes on the current line,%
, which substitutes over the whole file,- and leaving it blank, which performs the same action as
.
.
as well as some not-very-useful options.
Next, <pattern>
is the text you want to search for and <replacement>
is what you want to replace it with. These accept RegEx formatting, which is beyond the scope of this article, but can come in very handy when you need to search for very specific patterns and replace parts of them in creative ways.
Finally, the <flags>
can be any of the following:
g
replaces all occurrences in each line (otherwise just the first occurrence).c
asks for confirmation on each substitution.i/I
ignores/doesn't ignore case (these settings overridesmartcase
andignorecase
).n
reports the number of matches but doesn't perform the substitution.
and a few more that are more complicated and not necessary right now. Below are a few use cases:
:s/foo/bar
replaces the first occurrence offoo
withbar
in the current line.:%s/foo/bar/g
replaces allfoo
's withbar
's in the entire document.:%s/foo/bar/gc
replaces allfoo
's withbar
's in the entire document but asks for confirmation on each one.
When we discuss VISUAL
mode, I will demonstrate how to find/replace in a selection of text, but that's a discussion for another time.
Undo/Redo
This is actually a pretty simple part of ViM. The undo key is u
in NORMAL
mode, and to redo the last undone change, you can use <C-R>
(Control + r) in NORMAL
mode (note that doing this in INSERT
mode has the effect of pasting from a register as discussed above).
It is important to distinguish the command U
, since you might accidentally press it. This command reverses all changes in the last modified line. Technically, its action can also be undone with the u
key, so it's not a "true" undo since it doesn't actually navigate the undo history.
Spellchecking
The final topic I want to include is how to simplify spellchecking in ViM. In the last article, I covered two settings, set spell
, which enables spellcheck, and set spelllang=en
, which sets the default spellcheck language. In addition to these, I have created my own spelling file at $HOME/.vim/spell/en.utf-8.add
and I set that as the default file to add new words to with the setting set spellfile=$HOME/.vim/spell/en.utf-8.add
. Note that this file must actually exist, so you have to create the parent directories yourself and create a blank file to store the new words. To add a word to your dictionary, move your cursor onto the word and enter the command zg
. The z
command, like g
, has many unrelated meanings, so it's just another one you're going to have to get used to. To get spelling suggestions, navigate to the misspelled word and enter z=
. A menu will appear with all the options, and you can use numbers to select the proper replacement. If you trust ViM, you can use 1z=
to automatically use whatever the first option is without entering the menu. However, I prefer Gilles Castel's way of correcting spelling mistakes with a command mapping:
inoremap <C-l> <C-g>u<Esc>[s1z=`]a<C-g>u
I had some trouble getting his version to work with his use of lowercase C
's, but this mapping works for me. I'll walk you through it, although he also explains the command in his article. We are mapping <C-l>
(Control + l) in INSERT
mode only to that big string of commands. First <C-g>u
(Control + g) creates an "undo block" that allows the spell correction to be easily undone with u
. Next, <Esc>
takes us into NORMAL
mode, [s
moves us to the previously misspelled word, 1z=
accepts the first spelling option, `]
moves us back to where the cursor was when we started this operation, a
puts us back in insert mode, and <C-g>u
closes the undo block. The effect is that pressing <C-l>
in INSERT
mode corrects the most recent spelling mistake. If you have multiple mistakes, you can keep pressing it to go backwards through them and correct them.
Finally, I don't like how ViM highlights bad spelling. I'd rather have it underlined. In my .vimrc
file, I include the following code:
hi clear SpellBad
hi SpellBad cterm=underline
Note that this code must be added after you set a colorscheme.
Conclusion
We've gone through a few more movement commands, as well as yank/paste, undo/redo, find/replace, and spellchecking. In the next article, I'll be discussing the REPLACE
and VISUAL
modes, as well as discussing the s
(substitute) and c
(change) commands. After that, there really isn't that much more required to be able to use ViM as well as any other text editor; Most improvements will just come from learning and practicing the commands. However, there seems to be an endless number of commands or ways to perform simple tasks. I won't even be covering macros, for example, since I don't really use them at all. In the future, I also want to cover some of the plugins I use alongside ViM. Gilles Castel wrote a very informative series of posts on how he types his mathematics notes in LaTeX live during lectures. I've since worked through his setup and made many modifications of my own, which I hope to discuss in the future, but his article is a great demonstration of how ViM can be used much more effectively than other editors. It only took me about a month to become proficient enough to type my own lecture notes in LaTeX using a modification of his method (I use a faster but less versatile completion library), and I am not an exceptionally fast typist.
One of the things you'll notice when you start using ViM is that you'll want to use it for everything. I hardly ever open up Apple Pages on my laptop anymore, since most documents I care about are in LaTeX anyway, but even when I do, I find myself typing things like :w
to save and pressing <Esc>
when it doesn't actually do anything. Once you make the connections between the ViM commands and what you want to do in your head, it just becomes natural.
Comments !