Learning the vi Editor/Vim/Useful things for programmers to know
Useful things for programmers to know
[edit | edit source]There are quite a few things programmers ought to know about vim that will make their experience that much easier. Programmers can save hours and weeks of man-hours over the long haul with effective editors. Here are some tricks and tools that vim provides. With the time you save, you might speed up your work and have some extra time for a quick Quake deathmatch or eventually increase your productivity to help justify a larger wage increase.
Word, variable, function, and line completion
[edit | edit source]Sometimes the word you're typing is really long. You shouldn't have to type it all out. If it's in your dictionary, or in the current file, you can save a lot of time with <Ctrl-P> and <Ctrl-N>. Let's take a closer look at how this works:
- Word/variable/function name Completion
Generally, any word in the current file, or any of the other files (buffers) you are editing in the same instance of vim, will match for completion. This means once you've typed it once, you can type the first couple letters next time, and press Ctrl-N (several times if you need to cycle through several options) until you find the word you're looking for.
Technically, this isn't true. You can tell vim where to look for words in the complete
function. In Vim 7, the complete
function will generally be set to figure out a lot about what you're typing — drawing information from function libraries (As of the last update on this book, the author knows C and C++ are supported by default). Keyword completion since Vim 7 will also show a popup menu.
You can also define a dictionary of your own for completion. For more detail, you might want to consult the vim help system ":help complete", ":help complete-functions", and so forth.
Example 1
As an example, you might edit a C program file, "blah.c". You want a function that starts with "str", but you can't remember what it is. You first type "str". It remains regular text until you press <Ctrl-P> or <Ctrl-N>. In vim 7, you will see a menu appear, like this:
You can use <Ctrl-N> and <Ctrl-P> to cycle through the entries shown. In Vim versions 7 and higher, you can actually use the arrow keys to cycle through entries in the menu. There might be too many to show on the screen at once (you will notice the black box on the right represents a scroll position on a gray bar--not all the options are shown on-screen in this example.) The files from which the options were drawn are shown, to help you decide if it's what you're looking for.
(You will also notice in this example that words show up from files the author has recently edited, such as 'strict' from 'cgi-bin/ftplist.pl' -- we certainly don't want that.)
Example 2
Now, suppose you need the sine function, but you know it has an odd name. You type sin
and press <Ctrl-P>, and it doesn't show up:
You're not out of luck, you just haven't included the math library yet. All you have to do is add the line
#include <math.h>
and try again. This time you see the function name you wanted (it wasn't easy to remember since it has an odd name)
- Line Completion
You can complete entire lines if you need to, though this is less likely. <Ctrl-X>, <Ctrl-L> will load the matching lines (white space matters!) into the menu, and from there you can move forward and backward with arrows or <Ctrl-P> and <Ctrl-N> (for Previous and Next)
Indentation
[edit | edit source]Vim can figure out how to indent most common filetypes.
For most of the popular programming languages, vim can detect the file type by the filename's extension, and from there it will decide how to indent your files. If you don't see it automatically creating the proper indentation for you, try
:filetype indent plugin on
In the GUI version, you might be able to turn it on at the same time you turn syntax highlighting on for that file. Choose Syntax -> on/off for this file, or Syntax -> Show Filetypes in menu, then go back into the syntax menu and choose the appropriate file type from the list.
You might want to put the above-mentioned ":filetype ..." line in your vimrc file (discussed earlier) and open your program file again, though this really shouldn't be necessary.
If you still have problems, you might want to check that your runtimepath variable is set properly (:help runtimepath). It's also possible (though unlikely) that your programming language is rare enough that nobody has written an indent plugin for it yet. The official site for vim, vim.org, may have an indent plugin file that meets your needs, even if it didn't come with your default installation of vim.
For those times when you've pasted some text in and the indentation is wrong, (your indent plugin must be loaded), you can use the = command. It's probably easiest to type '10=' to re-indent the next ten lines, or to use visual mode and press <=>.
If you want, you can indent lines with ">>" and unindent them with "<<".
If you are in insert mode, use <Ctrl-D> and <Ctrl-T> to change the indentation of the line (<Ctrl-D> decreases indentation by one level and Ctrl-T increases it by one level)
If you can't manage to get filetype specific indentation working, you might try setting one or more of the following options: smartindent, autoindent, cindent, and copyindent. Chances are these won't work completely right, so <Ctrl-D> and <Ctrl-T> will be more important. To turn autoindent on, type :set autoindent
. To turn autoindent off, type :set noautoindent
Repeating commands, or Performing the Same Command Many Times
[edit | edit source]If you feel comfortable with vim, you might record your keystrokes to an invisible register and repeat them later. It might be easier to write a vim script, or even filter your file with another program (such as a perl script) for complex enough actions.
That said, sometimes it really is easier to record a command and reuse it, or even perform it on any matching line. For more advanced execution patterns (e.g. executing one command on the whole file), see below. You might also consider creating a mapping (discussed below) or running a :global command (also discussed below).
Repeating the last single command
[edit | edit source]Suppose I want to put a semicolon on the end of a few lines, where I forgot:
cout << "Hello world\n" i = j + k cout << "i is " << i << endl
On the first line, I type A;
followed by the ESC
key. I move to the next line and press .
(the period tells vim to repeat the last command -- don't worry, it doesn't duplicate movement commands).
Recording a command macro
[edit | edit source]Vim has a powerful form of command repetition available through the use of macros. A user can record a series of commands into a register and run the register as a macro. Macros can be recorded into any of 26 registers (a through z).
To start recording a macro, press q
followed by a register name (any letter a
through z
-- Registers are defined by only one letter of the alphabet, so only one character may be used as the storage buffer). After performing a series of commands, finish recording the command macro by pressing q
again. For example to start recording into register z, press qz
and press q
again to finish recording.
To run a macro from a register, run it with @x
where x is the register with the desired macro recording. Register q
is the default register for macro recordings, so if you have recorded into register q
you may simply type @@
to run the macro.
(Note: Keep in mind that scripts or mappings may sometimes use an arbitrary register--so if you have a conflict, especially with a third party script or mapping, you should consider recording to a different register. You can view the contents of a register with the :registers command.)
Example 1
[edit | edit source]As a simple example, suppose you have the following lines in the buffer, and you want each line to repeat the last word on the line. Initially, the buffer looks like this:
The quick brown fox jumps over the lazy dog The sly gray fox circles around the unsuspecting rabbit The slow gray fox crawls under the rotting fence
And you want the buffer to look like this: (where additions are highlighted in bold)
The quick brown fox jumps over the lazy dog dog The sly gray fox circles around the unsuspecting rabbit rabbit The slow gray fox crawls under the rotting fence fence
To do this, start recording into the default register with qq
, then append the line with A
, type a space, then Ctrl-P
, then press the ESC
key. To finish recording, press q
again. Now the macro has been recorded into register q. To repeat the command, move down one line, and repeat the command by typing @@
or @q
. You can use @@
to run this macro because q is the default register for macros.
Example 2
[edit | edit source]In another example, suppose you have the following lines in the register:
The quick brown fox jumps over the lazy dog dog The sly gray fox circles around the unsuspecting rabbit rabbit The slow gray fox crawls under the rotting fence fence
and you want to put HTML tags around the animal names (fox, dog and rabbit) to make them bold (eg, fox
needs to become <b>fox </b>
). Suppose you want to use register a for the macro.
To start, move the cursor onto the first animal name--fox. Place the cursor somewhere on the word, such as on the 'o' in fox. Begin recording by typing qa
. Next, delete the word into register b by typing "bdaw
(see :help aw
and :help d
and :help "
for an explanation of this command). Next, enter insert mode by typing i
and then type <b>
followed by Ctrl-O
, then "bP
(see :help i_CTRL-o
for an explanation of this command). Next, type </b>
and press ESC. Finally, stop the recording by typing q
. To repeat the command, move the cursor over the next word you wanted to surround with the HTML tags and run the macro by typing @a
. You can see what the macro looks like by examining the register. To do so, you may run the command :registers a
. In this case, vim will show the following output:
--- Registers --- "a "bdawi<b>^O"bP</b>^[
Note that a recording remembers all your movement commands, so you will need to put the cursor in the correct starting position before you begin recording.
Example 2b: fixing a macro
[edit | edit source]Suppose you made a minor mistake in your macro, but the macro is rather complex and you don't want to repeat all those commands again. We would like to modify the contents of a register. In order to do this, we use the feature that typing "x
in the escape mode uses the contents of register x for the next delete, yank, or put.
Assume that we are using register a,
- create a new line (this line will be eventually deleted) and put the register's contents on the line with
"ap
in the escape mode. This command is pasting (note the p in the command) the contents of register a (via "a) into the line. - Make the modifications as needed, and
- put the modified line back into register a by moving to the start of the line (with
|
) and typing"ad$
in the escape mode. (Do not use"aD
because D will capture the newline character in the buffer as well.) - Test the macro to be sure it is working properly, then use it as needed.
Executing a command macro
[edit | edit source]To execute a macro stored in register q
once, you can just press @q
. But often, you would not write a macro to execute it only once and here the full power of Vim kicks in.
To apply the command to the lines 23 through 42, use :23,42norm! @q
, to apply it to all lines in your document use you can use :%norm! @q
.
The same also works for single commands that you can access with the dot. If you have forgotten semicolons on some lines in your document, you would just execute A;
followed by the ESC
key. Then the command :23,42norm! .
will apply the same action to the lines 23 to 42 and insert a semicolon at the end of each line.
Mapping a command
[edit | edit source]One of the advantages of mapping a new command is that you can put the mapping into your vimrc file for use later. I have the following mapping
map <C-k> :!%:p<C-m>
What this does is maps the normal command Ctrl-K to run the current file as a script. You could also perform the second "Recording a command" exercise from above (encase a word in bold tags) with this mapping:
map <C-x>b "bdawi<b><C-o>"bp</b><ESC>
Note that in this case, I can get away with "<b>" because it doesn't match a special character name. However, if I needed to avoid a conflict (if I wanted to map an insertion of "<ESC>") I would use <lt> and <gt> for the less than and greater-than symbols. (See ":help key-codes")
If you want to map a command for insert mode, use imap instead of map.
If you want to prevent any of the commands in your map definitions from being interpreted in other mappings, use noremap (or inoremap for insert mode inoremap meaning insert mode no re-map)