Home CPSC 225

More About Vim


 

Building Vim Commands

One of the powerful things about Vim which is unlike other editors is that its commands are able to be combined with each other to form larger commands. For instance, the 'd' command is for deleting things. We have seen using 'dd' for deleting a line, but 'd' is really a Vim "verb" which can be combined with "movements" which allow us to delete other things:

In fact, we can make "verb-movement" commands from any of these verbs:

VerbMeaning
dDelete.
cChange (delete and enter insert mode).
yCopy.
=Re-indent.
>Indent one more level.
<Indent one fewer level.

And these movements:

MovementMeaning
hThe character to the left.
jThis line and the one below it.
kThis line and the one above it.
lThe character to the right.
^From here to the start of the line.
$From here to the end of the line.
ggFrom here to the start of the file.
GFrom here to the end of the file.
{From here to the start of the paragraph.
}From here to the end of the paragraph.
%From here to the matching parenthesis, brace or bracket.
f{char}From here until the next instance of {char} on the current line. For instance fw will move to the next w character on the current line.
t{char}From here until the character right before the next instance of {char} on the current line.
F{char}From here until the previous instance of {char} on the current line.
T{char}From here until the character right after the previous instance of {char} on the current line.

For example, the command =G will re-indent everything from the current cursor location up until the end of the file, and yfP will copy everything from the current location until (and including) the next 'P' character.

As we've seen, we can also use "verb-verb" commands such as "dd" or "yy" which mean to apply whichever verb for just the current line.


 

Text Objects

Vim also allows applying verbs to higher level textual structures it calls text objects. With these we can perform "verb-text object" commands which apply the verb to the text object. Some useful text objects are listed below:

Text ObjectMeaning
i}Text inside curly braces.
a}Text inside curly braces and the braces themselves.
i"Text inside quotations.
a"Text inside quotations and the quotations themselves.
i)Text inside parentheses.
a)Text inside parentheses and the parentheses themselves.
iwThe current word.
awThe current word and the space after it.
isThe current sentence.
asThe current sentence and the space after it.
ipThe current paragraph.
apThe current paragraph and the new line after it.

The first six are most useful for programming, while the last six are more useful for writing regular text.

These allow us to build very succinct shortcuts. For instance, suppose we are editing a program with the line:


print("Hello, how are you?")

And we wish to change the printed message. This can be done using the ci" command which will jump to the quotes, erase everything inside of it, and put us into insert mode. This works even if the cursor is not inside the quotation marks.

Likewise, if we are writing a paper, and wish to move a sentence, we can issue the das command, then move to where we wish to place it and enter the p command.

It takes time to get used to using these bigger commands, and taking advantage of text objects, but it allows you to edit text at a higher level. Instead of dealing with just a string of characters, you can edit text at the sentence, paragraph, or code block level.


 

Counts

Vim commands can also be prefaced by counts which are integers which indicate how many times the command should be performed. For instance, 3dd says to delete three lines.

Movements can contain counts as well. For instance, we can type 3w which moves us three words forwards and is equivalent to typing www. Movements within commands can have counts as well. For instance the command y2fw will copy from here until the second instance of the 'w' character.

Counts can also be used with text objects which can be really helpful. Suppose we have the following code:


if (x == y) {
    // some comment
    while (x < 0) {
        x = x + 1;
        print("Some stuff is happening!");
    }
}

Also suppose that the cursor is within the while loop body, on the print statement line. If we wanted to delete the entire body of the while loop, we could use di} which would give us:


if (x == y) {
    // some comment
    while (x < 0) {
    }
}

The text object i} matches the most nested set of braces we are in. If we wanted to remove everything in the if block, however, we could instead use d2i} which deletes the second most nested brace pair, giving us:


if (x == y) {
}

 

Registers

When we use the d or y verb in a command, it saves the text which is deleted or yanked into a register which is like a Vim variable used to hold text (similar to the "clipboard" used by GUI systems). When we use the p or P commands, the text in a register is put into the file we are editing.

By default, Vim uses the "unnamed register" for these purposes. If you only ever use the unnamed register, then each time you delete or yank something, it will overwrite the previous text of the register.

Vim also allows us to specify a named register which can be any lowercase letter. This is done by prefacing a command with a " character, then the register we wish to use.

For instance, to delete a line into the "j" register, we could use "jdd. Then if we wish to paste from that register, we could use "jp.

Using registers is nice since it lets you save something in a clipboard location and then be able to use the regular copy and cut commands without losing it.


 

Marks

Vim marks are like bookmarks in the file you are editing. They allow you to mark specific points in the file which you can quickly return to later.

You can create a mark with the m command followed by a lowercase letter. This gives you 26 marks to work with. So ma will mark the current location as mark 'a'.

We can then jump back to mark 'a' at any point with either the command 'a or `a. The only difference is the first will take you back to the start of the line containing mark a, while the second will take you to the exact position you marked (the line and column).

Because our mark jumps are Vim motions, they can also be used with verbs to form commands. For instance, d'a says to delete everything from here until the line containing mark a.

Your marks in a file will persist across multiple launches of Vim. So you can assign a mark to an important part of a file, then jump to it each time you open that file.


 

More Ways to Enter Insert Mode

We have seen that the i key can be used to enter insert mode, but there are several other ways to enter insert mode which are convenient in some situations:

KeyMeaning
iEnter insert mode starting here.
IEnter insert mode at the beginning of this line.
aEnter insert mode one character to the right.
AEnter insert mode at the end of this line.
oAdd a line after this line and enter insert mode.
OAdd a line before this line and enter insert mode.
sDelete the current character and enter insert mode.

 

The . Command

The '.' command is, in my opinion, the best feature of Vim, that I miss most sorely when I need to use an inferior editor. The '.' command repeats the last action that you performed. For instance, if we have the text:

Hello this is a sentence.

And the cursor is on the word "this". We can delete the word "this" by typing daw. This will give us:

Hello is a sentence.

Now if we wanted to delete "is", we could again hit daw, or we could just repeat the last one with . which will give us:

Hello a sentence.

Tap . two more times an all we have is:

Hello.

The . command can allow you to save a lot of time. As another example, suppose we have some code like this:


name = input()

while name == "":
    print("Invalid name!")
    name = input()

And suppose we wanted to comment out the while loop. We could do that by manually moving to the beginning of each line and adding a '#' character. Or we could go to the first line to comment and type I to insert at the beginning of the line. Then type the # and then hit escape. Now the action we just did is "insert a # at the beginning of the line", and this whole action can be repeated. To comment the other lines, we can just type j.j. as j moves down a line and . comments it out.

Copyright © 2024 Ian Finlayson | Licensed under a Creative Commons BY-NC-SA 4.0 License.