why is vim useful?
There is nothing intuitive or easy about learning vim. It's hard. It is every bit as cryptic and undecorated as a text editor could be.
Somehow though, nearly 20 years after its development, and nearly 35 years after its roots, in a world ruled by VisualStudio and Eclipse, vim is still relevant. It is maintained and developed by a thriving online community and it continues to be the work horse of many modern operating systems.
Why is that?
It is the opinion of this author that vim has something to offer that has not yet been matched by the more mouse-oriented text editors and development environments. Vim capitalizes on the fact that you can do more with ten fingers than one mouse pointer. If you're willing to put extra time in up front while learning vim, you will be more productive and effective in the long run. And that is what makes vim powerful.
the building blocks
If you haven't learned the basics about insert mode, command mode, etc., open up a command prompt and enter vimtutor. Come back to this article once you're done with that.
When you first look though this section it will probably seem very dull, but pay attention! These are the building blocks that lead to a productive, effective proficiency in vim.
| Command | Description |
|---|---|
| fx | Move forward to the next occurrence of 'x' on the current line ('x' can be any character) |
| Fx | Move backward to the next occurrence of 'x' on the current line |
| ; | Repeat the last movement command |
| w | Move forward a word (EXTREMELY useful) |
| W | Move forward to the next white-space delimited word |
| e | Move forward to the end of the next word |
| b | Move backward a word |
| B | Move backward a white-space delimited word |
| gg | Jump to the beginning of the file |
| G | Jump to the end of the file |
| ma | Bookmark the current cursor location as 'a' ('a' can be any character) |
| `a | Jump to bookmark 'a' |
| `. | Jump to the last place you entered text |
| `` | Jump to the previous line you were at in the file |
| Command | Description |
|---|---|
| I | Insert text at the beginning of the current line |
| A | Insert text at the end of the current line |
| o | Add a new line below the current one and enter insert mode |
| O | Add a new line above the current one and enter insert mode |
| >> | Indent the current line one level |
| << | Un-indent the current line one level |
| == | Auto-indent the current line. (not always possible, depending on what you're coding... i'm looking at you, python) |
| D | Delete everything until the end of the line |
| C | Delete everything until the end of the line and then enter insert mode (change it) |
| d{motion} | Delete the text from the cursor to the point indicated by {motion} |
| c{motion} | Delete the text from the cursor to the point indicated by {motion} and enter insert mode (I use this most frequently with 'w' to delte a word and change it to something else) |
| ci( | Delete all of the text within the parenthases and enter insert mode (Brackets, braces, or any other character pair could be used instead) |
| ca( | Delete all of the text within the parenthases inlcuding the parenthases themselves and enter insert mode |
| . | Repeat the last insert command |
Those last few can make for some interesting combos. If, for instance you have several places in your code with following conditional:
if (a < b) {
...
And you wanted to substitute it with this:
if (b < c) {
...
Search for the conditional:
/a < bChange it to the new condition:
ci(b < cJump to the next instance of the original:
nAnd repeat your last action:
.This will all be very important when we get to macros...
| Command | Description |
|---|---|
| v | Enter standard visual mode |
| V | Enter linewise visual mode |
| Control-v | Enter blockwise visual mode |
You can easily see how this works by trying it out yourself. Keep in mind that once you're in visual mode, vim sticks with the convention that y copies (yanks) the selection, d deletes the selection, and c deletes the selection and enters insert mode (changes it).
| Command | Description |
|---|---|
| Control-a | Increment the next number in the current line |
| Control-x | Decrement the next number in the current line |
| gUw | Make the rest of the word uppercase |
| guw | Make the rest of the word lowercase |
Notice that the 'w' in the uppercase/lowercase commands is a movement. The 'gU' tells vim that you want to capitalize something, and the 'w' tells vim how far you want to go. You could also use 'gU$' to capitalize until the end of the line, or highlight a block in visual mode, and press 'gU' to capitalize it.
the re-map
Any given developer has strong opinions about how things should work, however no two developers ever quite agree. This absolutely applies to work environments -- we all have our reasons, but at the end of the day, there's a specific way we want to do things. Vim acknowledges this disparity between preferences and reconciles it with the mighty re-map: any keystroke or combination of keystrokes can be re-mapped to anything else. When the user puts all of these mappings in the their ~/.vimrc file, the changes are automatically loaded at startup. Of course excessive re-mapping is ill-advised since they are non-standard configurations, so use them with caution.
Below is a short list of re-mappings I use which will hopefully serve to instruct and inspire.
- noremap U <C-R>
- control-r is the default 'redo' in vim. I find it annoying to be going through undo's, overshoot by one or two, and then have to change to control-r to redo, so I just re-mapped it to shift-u
- nnoremap <silent> <Space> :silent noh<Bar>echo<CR>
- vim will highlight search matches, and this is extremely helpful until you no longer need the search, at which point it becomes extremely annoying. This re-map allows you to clear the search highlighing simply by pressing the space bar.
- cmap w!! w !sudo tee % >/dev/null
- We've all been there... you make a bunch of edits to a file only to realize you need to be root to save them. When you find yourself in this situation, use this re-map by typing :w!! and you won't lose your edits.
- map ,e :!bk edit%<Cr>:e!<Cr>
- If you use BitKeeper or any other source control software with RCS roots you know it's handy to be able to check out a file as you're viewing it. This is the re-map that gets you there.
- map ,e :!bk unedit%<Cr>:!bk get %<Cr>:e!<Cr>
- Same as the above except for un-editing a file.
At this point you should stop reading. Spend a week applying each of these techniques to everything (code, e-mails, online forms, everything), and then come back to this tutorial. It's been dull and dry up to this point, but if you quit now vim will remain difficult and it will never be worth the trouble; it will never be powerful.
a robot in every vim...
Computers are great because they can do all of the little tedious things humans can't stand. Whenever you find yourself doing something over and over you need to stop and figure out how to get the computer to do it for you. Vim does this. Like a robot.
| Command | Description |
|---|---|
| q{register} | Start recording every keystroke into a register. Register names could be any character or number, so 'qa' will start recording to register 'a' |
| q | If you're already recording a macro, pressing 'q' again will stop recording |
| @{register} | Replay the macro recorded in the speicified register |
| @@ | Replay the last macro that was replayed |
If you did what you were supposed to and diligently internalized the previous sections, you're now equipped to do some vim trickery. Let's say you've got a C++ class with ten private member variables that all need getters and setters:
class Class
{
public:
Class();
~Class();
private:
int m1, m2, m3, m4, m5, m6, m7, m8, m9, m10;
};
With a little vim macro magic you can avoid carpal tunnel:
"but VisualStudio has tab completion!"
Vim likewise has tab completion... with a bit of hacking.
| Command | Description |
|---|---|
| Control-p | Complete the current word by searching backwards for the first match |
| Control-n | Complete the current word by searching forward for the first match |
If you're sharp you noticed that pressing tab doesn't complete anything, for that you need a re-map:
- inoremap <tab> <C-P>
This can be limited since it only completes words in the file (and in the #indlucde'd files for C), but if that ends up being a problem, you may want to look into SuperTab.
editing multiple files
Any good editor has a way to edit multiple files, and vim provides numerous ways to do this. My favorite is split-windows, so that's what we'll discuss here.
| Command | Description |
|---|---|
| :sp [filename] | Split the screen in half horizontally and open the specified file in the upper split, if no filename is specified, vim will just replicate the current file (Note that this is run in ex mode) |
| :vs [filename] | Same as above except split the window vertically |
| Control-w j | Move to the next split down |
| Control-w k | Move to the next split up |
| Control-w _ | Fill the screen with the current split, minimizing the others |
- map <C-J> <C-W>j<C-W>_
- Use control-j to move to the next split down and maximize it
- map <C-K> <C-W>k<C-W>_
- Use control-k to move to the next split up and maximize it
If you're using vim to edit a number of source code files, it would be extremely convenient to be able to jump to a function and drill down into heavily-nested code. Vim uses files generated by a program called ctags to accomplish this.
$ ctags my_file.c
Now you've got a file in your directory called 'tags', and when you open my_file.c in vim, you can use the following commands.
| Command | Description |
|---|---|
| Control-[ | Jump to the function implementation or variable definition of the word under your cursor |
| Control-t | Go back to where you were before the last Control-[ |
In the real world you'll be working on projects that span multiple files in multiple directories. For this I would reccomend obtaining a copy of Exuberant Ctags. Say you have a directory structure that looks like this:
- RootDirectory
- LibDirectory
- library_file1.h
- library_file2.h
- library_file3.h
- AppDirectory
- App1
- main.c
- App2
- main.c
- other_file.c
- other_file.h
You would go to the root directory and run ctags -R (for recursive), and open files from there:
$ vim AppDirectory/App1/main.c
This way you still have the benefit of being able to drill down into function calls, but without the hassle of an elaborate tagging system. Also note that ctags works with many more languages than just C.
plugins
Vim has a powerful plugin architecture, and plugins exist for everything under the sun (I've already mentioned SuperTab). I only use a couple of plugins, which are listed below, but there are many smart plugins for specific languages and frameworks that are also worth looking into.
- The NERD Commenter - Comment any code with one easy command. This may also be accomplished with re-map's in your .vimrc (as you can see from mine below), but NERD Commenter is nice because once installed it's like syntax highlighting -- it just works.
- Javascript Indentation - At first javascript looks like any other curly-brace language, but some of the language's flexibilities really throw vim's standard cindent for a loop. This plugin solves those issues.
a few powerful links
There's an incredible amount of information out there about vim, probably too much, but below are several links to get you going.
- Jonathan McPherson's "Efficient Editing with Vim" - another tutorial, far better than this one
- Vim tips on Stackoverflow - There are quite a few of questions like this one on Stackoverflow that are chock-full of good ideas
- My .vimrc file - just for reference
- Ryan Tomayko's "Getters/Setters/Fuxors" - An interesting perspective on why editors like vim and emacs can still compete with the more elaborate IDE's