Tutorial: getting started with vim


Posted: 25 May 2012

Tagged: tutorial vim

Synergy tutorials, vim

This is the first in a series of tutorials I’ve put together to present to the synergy group, my research group at Virginia Tech. They were meant to be delivered as presentations, so the format may not be entirely natural when read, but I hope some will find this useful.

Starting materials:

A tar archive with a portable configuration as well as some extra features and test files is available here, I would recommend setting up the configuration, but it is not necessary.

Overview:

First off, vim is not an IDE, it is not a programming environment (i.e. lisp/emacs, java/eclipse) it is an editor with a surprisingly rich feature set and extension API. Chances are, if you want it to do something, it can, as a result of this even with an hour I can’t come close to covering the features I use in an average day let alone the full feature set. That said, I will cover some that I find most useful for general editing situations. Some things I may not cover but are built in or easily available (in no particular order) are.

  • Spell checking (with word suggestions and automatic check-as-you-type features)
  • Folding (code, text, anything you may wish to condense)
  • Multiple windows in splits
  • Tabbed editing
  • Completion of functions, filenames, variables
  • Remote editing over FTP,SFTP,etc.
  • Code formatting and text reflowing
  • Tag file or CScope support (find function/variable definition or instantiation from call/l/reference even across files)
  • Contextual diffs with highlighting
  • Source control managment
  • Syntax coloring up to 256 colors in terminals
  • Mouse support, in terminals, over ssh, anywhere
  • Infinite undo stack
  • Saved session support

First things first, the most basic possible workflow.

vim test.txt
i
[edit as usual]
<ESC>
:wq<ENTER>

You have now edited a file in vim. Not so hard, or daunting right? This is where you learn the most important key command of all for a novice vim user, undo. While the original vi had almost no functionality for undoing edits, vim’s undo stack is infinite. If you did something you want undone, just hit u in normal mode, and it will be undone. To redo, <C-r>, either of these can be repeated ad-nauseum to back out of or retrieve any number of edits, never fear accidentally destroying your file, even if you accidentally save it to disk, so long as vim is running you can always back out.

Now we’ll get into some of the more interesting things about each part of that first example. First, you actually have choices when opening VIM, you can run vi, vim, view, or vimdiff and all will open vim, but they all have different properties.

  • vi: open vim in vi compatible mode, do not do this unless you want to pull your hair out, or are using a configuration file that tells it to behave normally
  • vim: the editor, standard mode
  • view: open read only
  • vimdiff: diff two files, open them in vertical split mode with color highlights showing all differences and hiding large regions of similarity (insanely useful even if you don’t like vim as an editor)

Of these one is best explained by example, that’s vimdiff. Try ‘diff difftest1.txt difftest2.txt’ and see what you get. I do not find this output useful, while the lines do differ, the amount to which they differ is completely unclear, let us try the same with vimdiff like this ‘vimdiff difftest1.txt difftest2.txt’. Notice that while many of the lines are different, they are different in small ways, something a regular text diff cannot show easily. Also, the two panes are tied, if you scroll one down, the other follows to make viewing any part of the diff simple. Now, use :qa to quit out of vim.

MODES:

Unlike most editors, vim does not operate in insertion mode at all times. It actually has several different modes each of which use almost completely different keymaps and have different outcomes for any given single key, this is the most difficult part of learning vim for most people, in a way it’s also the most powerful thing about vim.

The editing modes we will be dealing with today are:

  • Insert
  • Normal
  • Command
  • Visual
  • Visual block
  • Paste

The vast majority of editors have one of these, insert mode, it is the mode they start in and stay in at all times. Emacs has insert mode and arguably command mode, but starts in insert mode. Vim confuses most by starting in normal mode, and it is the mode in which most major edits are performed. In general the modes are used for different tasks. Insert mode is used for inserting new text into the file by the keyboard. Normal mode is for moving around a file, controlling the environment, searching, deleting, copying, cutting, and pretty much all the special functions of the editor that are performed with relation to the cursor. This is usually the mode which scares people the most, because in it two keystrokes could delete all the text in your file, thankfully it is also the mode in which the u key would immediately restore all that text, so no need to worry. Command mode is very similar to editing with ed or ex (vim’s ancestors), it is a command line within the editor which is used for saving, quitting, performing operations which edit the file without respect to the cursor, and allows one to set variables and call functions to control the vim environment. The next two are highly related, visual mode is the same as when you select text in a regular editor, it just shows visually what part of the text has been selected. In general the keymaps for visual and visual block are the same as for normal mode, they just act on a different region and have a different argument precedence order (more on this shortly). Visual block differs from visual only in that block selects by columns and rows (a rectangular set of text) rather than logically along lines like normal selection. This is usually considered an advanced feature, I consider it essential, so we will be seeing it again later. Lastly is a mode that won’t often get used, but is necessary for a terminal vim user. Some very useful features, such as automatic indenting and text formatting, become frustrating when pasting already formatted text into vim through a terminal. Since vim thinks you’re typing it, it can get messed up very quickly, paste mode is a special version of insert mode that turns off all automatic formatting to prevent that problem. If you need to use it simply type :set paste while in normal mode, hit enter, paste your text, then :set nopaste to turn it off, that’s all you need to know about paste mode.

NORMAL MODE COMMANDS AND THEIR STRUCTURE:

Now, having covered the modes, the next thing to know is why normal mode is awesome, and how commands in normal mode are structured. In general they are structured as follows.

<# of times to repeat>["<optional register argument>]<command key(s)><motion/range>

That’s kinda complicated, but it’s worth knowing this because once you start to learn what each of these things can be, it allows you to compose commands, movements or ranges into unexpectedly useful editing commands. Lets get to some basic examples of normal mode essentials, motions and commands.

ESSENTIALS:

Enter insert mode:

    before the cursor                               : i
    after the cursor                                : a
    beginning of line                               : I
    end of line                                     : A
    in a new line below the cursor                  : o
    in a new line above the cursor                  : O
    replacing the character under the cursor        : s
    replacing the line under the cursor             : S
    replacing a range from the cursor               : c
    replacing the part of the line after the cursor : c

Enter command mode: : Return to normal mode from any other: <Esc>

NORMAL MODE MOTIONS:

It’s always good to know how to move around in a file, these are some of the most useful ways (note not all). Also, remember these are normal mode commands, so they do take a repetition argument, i.e. 15k will move up 15 lines.

Move cursor:

up                                             : <Up   arrow>  OR k
down                                           : <Down arrow>  OR j
left                                           : <Left arrow>  OR h
right                                          : <Right arrow> OR l
beginning of line                              : 0 OR ^
end of line                                    : $
to beginning of file                           : gg
to end of file                                 : G
beginning of next word                         : w
end of next word                               : e
beginning of previous word                     : b
end of previous word                           : ge
beginning of next WORD                         : W
end of next WORD                               : E
beginning of previous WORD                     : B
end of previous WORD                           : GE
beginning of sentence                          : (
end of sentence                                : )
beginning of paragraph                         : {
end of paragraph                               : }
beginning of code block                        : [{
end of code block                              : ]}
to matching [ ( { or <                         : %
to before next occurence of <char> on line     : t
to after previous occurence of <char> on line  : T
to after next occurence of <char> on line      : f
to before previous occurence of <char> on line : F
previous occurrence of word under cursor       : #
next occurrence of word under cursor           : *
search for and move to <pattern>               : /<pattern>
next misspelled word                           : ]s
previous misspelled word                       : [s

Move screen:

                       up   down
             half page ^u : ^d
             full page ^b : ^f
              one line ^y : ^e

NORMAL MODE COMMANDS:

delete:

character under cursor : x
range                  : d
line                   : dd
rest of current line   : D

change:

character under cursor : r
range                  : c
line                   : cc
rest of line           : C

(any patterns emerging?)

copy:

range: ["optional buffer]y
line: ["optional buffer]Y

paste:

after cursor                  : ["optional buffer]p
before cursor                 : ["optional buffer]P
after cursor and move to end  : ["optional buffer]gp
before cursor and move to end : ["optional buffer]gP

general:

repeat last command                    : .
change case of letter under cursor     : ~
undo                                   : u
increment next number on the line by 1 : ^a
decriment next number on the line by 1 : ^a
indent range by one level              : >
unindent range by one level            : >
format range of code                   : =
format range of text                   : gq
run range text through external command: !

spelling:

suggest alternate spellings for word under cursor : z=
add word to good list                             : zg

folding:

unfold all levels of all folds: zR
fold all levels of all folds: zM
toggle folding by one level on current line: za
toggle folding by all levels on current line: zA
close fold by one level: zc
open fold by one level: zo

there are many more, but this is a good start.

Now, so you can give some of this a try, open up implementation.tex. First, lets try moving around in normal mode. Especially try moving by word w/b, moving by sentence (/), and moving by paragraph {/}. Also, notice that the text may have been ‘folded’ collapsed by sections for easier navigation, to open it all up all the way, type zR, zM will reverse this.

Also, try some edits, delete a few characters, maybe add some text.

RANGES AND WHY WE LOVE THEM:

Now that you’ve tried just editing in a relatively straightforward way, it’s time to take a look at the commands, motions, and ranges together. First, a range can be specified by visual selection, motion command, or region command. We’ve gone over all of these but the last, and these are the doozies. When specifying by a region you specify two things as below.

<command><in or around><region type>

This allows you to execute a command on a region of text your cursor is inside of without explicitly selecting it first, these are some of the more useful region types.

region types:

blocks: ) ] } or >
strings: " or '
word: w
sentence: s
paragraph: p

For example, in the latex file we’re working on, lets try formatting the first paragraph so we don’t have so many lines sticking out of it. Try putting your cursor on any character in that paragraph and typing gqip or < format text ><in><paragraph> and see what happens. Magic right? Or try deleting a paragraph, or a sentence. One of the more useful things, is using this to change a word. Typing ciw removes the word and enters insert mode to replace it. Just want the word gone as if it were never there? Then daw will remove the word and the space on one side. Let’s exit out and open calculate_potential.c instead. This is where things get fun. Try putting your cursor inside any {} block, and typing di}, notice it deletes the entire contents of the nearest enclosing curly braces. This works for all block types and strings, makes it very easy to clear something out and replace it. The around modifier works here too, but instead of removing the space on one side it removes the block delimiters.

These are some of the most useful features of vim, the composability. Now that you know how to do any of these things to a paragraph, what about the entire file? Need to select all? Not even. Type gg, then the command you want, then G, and the command is applied across the whole file. Usually this is best used with either = to format code, or with gq if you set your formatoption to something like astyle.

COMMAND MODE COMMANDS:

We will touch briefly here, this space is so vast that it is not useful to even try and cover it all, but we will cover the various ways to save and exit vim, as well as do some basic actions. A : command has a structure much like that of normal mode, but a bit different, see below.

<range><command><arguments>

Note that the range comes first, and many commands have arguments. These are some of the most common.

save/quit: (add ! at the end of any to force)

save file in current pane : w
save all files            : wa
quit current pane         : q
quit all panes            : qa
save and quit all panes   : wqa
save as                   : sav

search/replace:

replace occurences of <pattern> with <text>                            : s/<pattern>/<text>/[g]
run <command> on all lines which match <pattern> (grep command)        : g/<pattern>/<command>
run <command> on all lines which do not match <pattern> (grep command) : v/<pattern>/<command>

Some examples, replace all occurrences of foo with bar on all lines in a file (% is the range for whole file).

:%s/foo/bar/g

Delete all lines that contain ‘DEBUG’.

:g/DEBUG/d

Copy all lines that do not contain the word debug and paste them at the top of the file.

:v/DEBUG/t0

Also useful for running external commands, this is why I almost never use ^z.

external commands/files:

read external file: r <fn>
run external command in current terminal and display output: !<command>
read output from external command and insert into file: r!<command>

Beyond the use for saving files and find/replace, the command mode is where files and splits and tabs are controlled.

opening new files:

in current pane       : e <fn>
in new split          : sp <fn>
in new vertical split : vsp <fn>
in new tab            : tabedit <fn>

SPLITS AND TABS:

To view any number of files effectively, it helps to be able to open more than one at once, in vim the easiest way to do this is through splits and tabs. Personally I almost exclusively use splits, but that’s just my style.

To try this out, try opening one of the files as usual, then type :vsp. You will get a second pane splitting the window vertically, but viewing the same file and buffer. This can occasionally be useful if you want to look at two different parts of the same file at once. From there, you can type :e to open a different file in one of the panes.

Managing panes is much like working with a terminal multiplexor, assume any command is prefixed with ^w.

split commands: (remember, ^w then whatever is below)

move to split at right    : <Right> OR l
...
expand split vertically   : <lines>+
shrink split vertically   : <lines>-
expand split horizontally : <lines>>
shrink split horizontally : <lines><

Note that :q will close one of these. For tabs, you use :tabnew or :tabedit to open a new one, then switch with :tabnext or :tabp. In the provided configuration Alt+t will also open a tab, and Alt+} will switch tabs right. This is all especially useful because vim’s yank and paste mechanisms work between all of these panes, keeping everything together rather than having to jump window to window.

COOL STUFF:

Ok, a few quick more advanced moves that will make things easier for everyone. First, something that works with no configuration magic. Block selection, insertion, and replacement. In normal mode v enters visual mode to select text. By the same token ^v enters block selection mode, which initially does not seem terribly useful, but let’s do some examples. First, to comment out the following code, try moving to the first column of the first row and press ^v. Move to the first column of the last row, press S-I (shift I), then //, then Esc. Then watch as not just the last line, but all lines are commented.

int a[50];
int b[50; 
int c[50];

Now, say that instead of commenting that out, we want to replace the sizes, 50, with 100 in all three lines. Use ^v to select the block of text with all of the 50s in it, press c then type the new number (100) followed by Esc. See all of them replaced in one go. Some ask me why I always align key parts of function calls and variable definitions, this is why. If things are reasonably aligned, edits can be fast and effortless.

try these:

^vI
^vA
^vc

I hope you found this useful, if you have any comments or suggestions, feel free to contact me or use the comment area below.

blog comments powered by Disqus