Search This Blog

Learn Vim Fast: Moving In and Getting Around

If you started learning Vim with my last post, and you've been practicing the handful of commands we covered, then you're probably pretty tired of how you have to move around and edit things with only those rudimentary commands. It's time to expand our command set and crank up our efficiency in getting things done with Vim, but before we do that, let's take a look at how to make Vim a bit more comfortable to look at.

Moving In

Normally I use gvim, the variant of Vim with a GUI window. Out of the box, gvim looks like this:

New gvim window

It looks somewhat uninviting to my eyes. Personally, I prefer editing code on a dark background, so I'd like to change the color scheme. Also, the bar of icons at the top of the window only encourages you to use the mouse for those common tasks, but we don't need them. The extra space would be better, so we'll get rid of them. To change these settings and more, we need to create a Vim configuration file. Putting this file in your home directory will cause Vim to load the configuration whenever it launches. With Vim open, type :e ~/.vimrc to create this file for editing, and enter the following lines:

Listing of .vimrc

Don't be overwhelmed. We'll go through each one of these settings, but I wanted to lay them all out as one listing first.

Starting at the top, set nocompatible disables compatibility mode so that some new features of Vim work correctly. This setting is likely already set this way, but we'll be extra sure.

Next, set history=100 allows you to use the up and down arrows at the command line (by typing ':') to search back and forth through your history of commands, and you can execute any previous command by going back to it, editing it if needed, and hitting <Enter>. The history is set to some number I don't remember by default, but 100 is a good large number. You can set it to whatever you want.

The next two settings, incsearch and hlsearch, cause the cursor to advance to the first matching search term and highlight all matching search terms when you're searching, respectively. These will come into play later when we cover searching, but just know that they are nice to have on and feel quite natural with the search command.

The set backspace=indent,eol,start setting makes it so the <Backspace> key will delete indents, end-of-line characters, and characters not added in the current Insert Mode session when you're in Insert Mode. It basically makes the <Backspace> key work as you'd expect, and in recent experience, it seems that backspace is set this way by default. It doesn't hurt to be explicit, though.

The set go-=T setting is short for guioption-=T, and this gets rid of the toolbar because you aren't gonna need it. Besides, it just wastes vertical space, which is at a premium with today's wide screen monitors.

The next set of options set up how Vim handles tabs. The tab stop is set to 2 spaces, tabs are expanded into spaces, and shifting tabs back and forth will shift them by 2 spaces. This is somewhat of a personal preference. Some people prefer other tab sizes, but this setup has generally worked for me to make tabs behave in a reasonable way. If you want a different tab size, just change the 2s to something else.

The line and column settings force the GUI window to open with that number of lines and columns. You can still resize the window, but these values are a good fit for most of the monitors I use. I might tweak them for larger monitors. I also turn on line numbers with set number, and make Vim automatically update a buffer when the file in the buffer was changed outside of Vim with set autoread.

The section with the set guifont settings changes the font depending on which operating system Vim is running on. Each of the fonts is one that is available by default on the corresponding system and a nice font to look at for coding.

The set wildignore option forces Vim to ignore certain file extensions that I really don't want it to ever open.

The next command is pretty cool. The autocmd BufWritePre command attaches a task to a hook that executes just prior to writing a buffer to a file. This particular one trims all whitespace from the end of every line. It's a nice little add-on, and there are a number of other hooks that you can attach commands to. I haven't found anything else that I want to execute automatically on other actions, but the option is there and the sky's the limit.

The last two settings turn syntax highlighting on (even though it's most likely already on) and set the color scheme to my preferred one. You can see the comment before the last line that reminds me where to put the Vim color scheme file. I always forget when setting up a new Vim. That's where you should put it, too. My favorite is vividchalk, gleaned from this list of color schemes.

Now that you have all of these settings entered, you can save the file and then execute :source ~/.vimrc to actually load the Vim configuration for the currently running Vim session. Some of the changes are immediately visible, while the rest will become apparent as you work in Vim.

Listing of .vimrc with new settings sourced

Ahh, that looks much better. Now we can start exploring some ways to get around more easily in Vim than what we've been doing with just the arrow, page up, and page down keys.

Getting Around

For the rest of the commands we are going to cover, we'll use a snippet of code as our canvas to experiment with what these commands do. It's a Ruby module that implements a few basic statistics functions, but what it does isn't very important. We'll simply use it as something to look at in the context of learning new Vim commands. Here's what it looks like:

Ruby code listing in gvim

And here's the code, so you can copy and paste it into a text file.
module Statistics
  def self.sum(data)
    data.inject(0.0) { |s, val| s + val }

  def self.mean(data)
    sum(data) / data.size

  def self.variance(data)
    mu = mean data
    squared_diff = { |val| (mu - val) ** 2 }
    mean squared_diff

  def self.stdev(data)
    Math.sqrt variance(data)

data = [1,2,2,3,3,3,3.5,3.5,3.5,4,4,4,5,5,6]
p Statistics.mean(data)
p Statistics.stdev(data)
Now, let's say we want to go down to the variance method so we can change the name to var. The cursor is currently at the start of the buffer. Up until now, we'd have to use the arrow keys to get there, but it's 10 lines down and 12 characters over. It's so tedious to use the arrow keys, so we want a faster way.

One marginally faster way to move is to use the h, j, k, and l keys. The h and l keys move left and right, respectively, and the j and k keys move down and up, respectively. You can keep these commands straight by remembering that the h key is on the left, the l key is on the right, the j key has a hook down, and the k key has a line going up. If you can get used to using these keys, great. I never have, and I continue to use the arrow keys for small movements. For larger movements like this, we have better options.

Type 10G to move the cursor directly to the beginning of line 10. This is why it's nice to have the line numbers listed. It makes it really easy to jump to exactly the line you want to go to. The G command can be thought of as Goto, and it will make the cursor go to the line number corresponding to whatever number was typed immediately before it. Most Vim commands are like this, where you can specify a number before the command. In this case, it denotes the line number, but in most other cases it will specify how many times to repeat the command.

Another way to get to the tenth line is to type 10gg. It essentially has the same effect, but G and gg have a subtle difference. If you type G without specifying a number, it will move the cursor to the last line of the buffer, while if you do the same with gg, it will take you to the first line of the buffer. It's pretty handy if you don't know how long the buffer is, but you want to get to the end as fast as possible. A 1G would suffice for getting to the beginning of the buffer, but gg is a bit faster to type. Anyway, here's where we are now:

Goto line 10 in gvim

To go the rest of the way, we want to move quickly across this line without having to tap the l key 12 times. We can do better with the w command. This command moves the cursor to the beginning of the next word, which is the first alphanumeric character after a non-alphanumeric character. (An underscore is considered an alphanumeric character.) The lowercase w will also stop at punctuation marks, like the '.', '(', and ')' in the code. A capital W will only stop at characters following a whitespace character. I'm sure I'm missing some subtleties here, but after experimenting with it for a while, you'll get a sense for what characters w and W will stop on.

For this case, we want to type www to get to the 'v'. Finally, we type lll to move over to the 'i', and we're ready to change the name. For now, that means typing i to get into Insert Mode, and hitting the <Delete> key five times to delete 'iance'.

Rename variance in gvim

Most Vim commands have opposite commands, and since w will only move the cursor forward, we need the opposite command for moving backward one word at a time. That command is b, for backward (or maybe backword, so we've got word and backword), and W has the corresponding B as its opposite command. All of these commands accept a repeat number before them, so we could have just as easily gotten to the 'v' by typing 3w instead of www.

Vim also has quick commands for moving to the beginning or end of a line. If you know regular expressions, these will look familiar. A ^ will move the cursor to the beginning of the line the cursor is on, and a $ will move it to the end of the line.

One more way to get where we want to go even faster, is to use the search function. So far we've gotten to the desired position in 8 characters (10gg3w3l), but search does it in less, and we don't have to do any mental counting. Starting back at the beginning of the file, we could type /ia, and we're already there. The / starts the search, and with every character typed after that, the cursor moves to the first matching string of characters that were typed so far. We only need 'ia' to get to 'iance', and we can hit <Enter> to end the search. We're now ready to go into Insert Mode and make the change.

Search for 'ia' in gvim

Notice how two instances of 'ia' have been highlighted. To get to the second one and make the same change, we can type n to move to the next matching instance of the most recent search string. Now we're starting to pick up some speed. If the last change you made was deleting 'iance' from the first 'variance', then you can type . to make the same change to the next 'variance' once the cursor is in the right place.

The search and next match functions also have opposites. To search backwards, use ?, and to move to the previous match, use N. If you combine the two by searching with ? and moving to the previous match with N, then the cursor will actually move forward in the buffer when moving to the previous match. Most of the time, I use / and n, but the variants can come in handy sometimes.

For the last set of movement commands, we'll combine moving and entering Insert Mode. Notice that the last couple lines print out calculations of the mean and standard deviation of some data, but we haven't tried the variance method directly. Let's quickly add a line to do that. First, type 22gg to get to line 22. Then type o to open a line below line 22 with the insertion point at the beginning of the new line.

Open a new line in gvim

Finally, you can type p Statistics.var(data), remember to hit <Esc>, and you're done. The open new line command has an opposite as well. The O command opens a new line above the line with the cursor. At this point you may be asking yourself if i also has a capital I version, and of course, the answer is yes. The I command is not the opposite of i, though. It enters Insert Mode with the insertion point before the first non-whitespace character on the line that the cursor is on instead of immediately before the character that the cursor is on. The opposite command of i is actually a, for append, and a puts the insertion point just after the character that the cursor is on. To round things out, a capital A puts the insertion point at the end of the current line. So there are plenty of ways to enter Insert Mode, with each one coming in handy in certain situations.

It may seem a bit overwhelming at this point, but with a little practice, these keystrokes become second nature. Many of them make sense from the letters that were picked to be associated with commands, and making commands orthogonal allows for some great flexibility. To sum up, in this post we've covered the following new commands:
  • h, j, k, l - Move left, down, up, and right
  • gg, G, <n>gg - Move to first, last, or specified line
  • w, W, b, B - Move forward or backward a word
  • ^, $ - Move to beginning or end of the line
  • /, ? - Search forward or backward
  • n, N - Move to next or previous match
  • . - Repeat last edit
  • o, O - Open a line in Insert Mode after or before the current line
  • a, A - Append to current character or end of the current line
  • I - Insert at beginning of the current line
After practicing these movements, you'll be able to fly around your code files with ease. Keep practicing, and next time we'll cover many of the fast ways we can modify text in Vim.

No comments:

Post a Comment