An Introduction to Vi (Part Two): Registers

28 July 2012 - Vi

In the previous part of this series I introduced some very basic concepts of Vi, including some very simple navigation commands. These do not even scratch the surface of what Vi can do. There's no doubt that learning Vi is a huge time commitment before you can begin to use Vi effortlessly. There really is so much to learn. The important thing is to take it one step at a time. Learn the basics and drill those, then slowly add more commands to your commandset over time. If you program for a living, then you're writing code all day long anyway, so you have a lot of typing time to enforce Vi commands into your subconcious muscle memory.

In part one I discussed using the HJKL keys instead of the cursor keys and also introduced a very small number of basic navigation commands. In this post I will introduce the Vi registers.

What is a register?

A register is basically just a storage location. It can store text or commands (actually commands are just text as you'll see later). Registers are referenced by keys on the keyboard. There are actually 9 types of register, but we're just going to deal with named registers, which are the a-z keys.

Hopefully you're all comfortable with the concept of cutting and pasting into a clipboard. Vi takes this to the next level by not only allowing you to store multiple clipboard entries (in registers), but also combine the cut/copy action with other Vi commands to give greater flexibility over what it is you're cutting/copying in each atomic command.

If you don't explicitly specify a register, then Vi will use what's called the default register. This is actually assigned to the " (quote) key, but you don't need to explicitly specify this. If you want to use any other registers, then you need to prefix the command with "<reg>, where <reg> is the register key. So *"a<command> will run <command> on the a register. This will make a bit more sense after seeing a few examples below.

Copy, Cut, Paste

In Vi terminology copying text is called a "yank". Below are some examples to give you an idea of how this works.

yy   Yank the current line
yw   Yank up to the next word
ye   Yank to the end of the word

So those are some basic examples of a yank. These examples will "copy" the text into the default register. If you want to "cut" rather than copy, then replace y with d. So to delete the current word, use dw. In the case of yanking a line, replace both d's (ie. dd instead of yy). Note that deleting still stores the text in the register - so it's like "cut".

dd   Cut the current line
dw   Cut up to the next word
de   Cut to the end of the word

So now that you've got your data in the default register, how about pasting it back into your code? To do this, you can either press 'p' which pastes after the current cursor location, or press 'shift-p' to paste before. The way the paste works is slightly different depending on whether you yanked a character/word or a full line / code block. These slight differences will all become second nature after a very short period of time.

As mentioned above, if you want to use another register, you can prefix the command with "<reg>. As an example, to copy the current line into the a register, you'd press "ayy. Then to paste from that register, you'd do "ap.

Combining yank and navigation commands

I mentioned in part one that you can use the f<character> command to move the cursor upto the next instance of the specified character. This is useful when yanking and deleting as it means that you can yank 'up to' a specific character. For example, yf; will yank everything on the current line from the cursor position up until (and including) the first semi-colon. Or similarly, you can delete up to (and including) the semi-colon with df;. If you want to yank/delete up to, but NOT including the specified character, then use t instead of f. One command I use very often is dt), which deletes everything up to but not including the next ) character. Which is great when editing function parameters. In the same sense, I use dt, a lot to for deleting to the next comma (again great when editing function parameters).

You can also specify blocks of code - eg. everything inside the current curly brackets, everything inside the current quote marks, etc.

Here are some examples:

yi{		Yank everything "inside" the current set of curly brackets
yi(		Yank everything "inside" the current set of brackets
yi"		Yank everything "inside" the current set of quote marks
ya{		Yank everything "around" the current set of curly brackets
ya(		Yank everything "around" the current set of brackets
ya"		Yank everything "around" the current set of quote marks

In the same way as mentioned earlier, you can replace the y with a d to delete. You can also use c instead of d, which will delete then leave you in insert mode.

Vi Grammar

You've probably noticed by now that there are a lot of common patterns with these various command combinations. For example, you can use the y (yank) command with various other keypresses to achieve different things. You can use d (delete) with those exact same other keypresses to delete rather than copy the same selection criteria. You can use c (change) rather than d with the same selection criteria.

Once you start understanding the various nouns and verbs, you can start combining them in different ways to create very powerful combinations.

Macros

Clipboard style operations aren't the only thing that Vi registers are used for. A very powerful concept in Vi is the ease of which you can quickly record and playback combinations of keypresses and commands.

Before talking about recording macros, I should mention the repeat command. By pressing the . key, the last command you performed will be repeated. The granularity of this is either the last command made, or if the last thing you did was to exit insert mode, then it'll repeat everything that you did in insert mode. This is a very important and powerful shortcut to use, and will save you a lot of typing time.

If you want a bit more control over the granularity of what you're repeating, then you can record a macro. This is done with the q key. In the same way as yanks can be stored in different registers, so too can recorded macros. Infact, it actually just stores the commands as text in the register, as you can see if you try and paste from a register where you've recorded a macro. To record a macro, press the q key, followed by a macro key. For this example, we'll also use the q register. So to start recording your macro, type qq. Once you've finished the series of actions that you want to record, press the q key again to stop recording. Then to replay the macro press the @ key followed by the macro key. It really is as simple as that. This is a feature I use all the time, as it's so easy to record and replay thowaway macros.

Tip: In the Vi configuration file (_viemu) you can remap keys. I've remapped my space bar key to qq for quick macro recording, and shift-space to end a macro. I've also mapped my ' key to @q' to quickly replay. This is done with the following text in your _vimrc file:

noremap  qq
noremap  q
noremap ' @q

I'll go into more detail on the _vimrc file and Vi configuration in the next post in this series.

Summary

In this section of the series we've covered how Vi handles clipboard-like operations, how registers are used, and how to record macros. Each of these topics are only touched upon here, but hopefully it has given you an idea of how it works.

One extra tip before I sign off is that you can use the upper-case version of the register names to append rather than replace the current contents of the register.

In the next post in this series I'll discuss how to configure Vi. This is one of the many great things about Vi - it's so customisable, and you can change almost anything about it via configuration files.