vim: The Editor
An introduction to vim's many powerful features.
March 3, 2004
by: dcantrell, clumens, and dshea

Introduction

About vim

Vim is a modal text editor. Its name stands for Vi IMproved, or something like that. Vim is not vi, but is easy for vi users to start using. As a text editor, it's designed to be powerful, not easy to use. But that doesn't mean it's hard to use either, commands are just not obvious all the time. Vim comes with great online documentation, so you can quickly find answers to questions.

Vim is written by many people, but the main guy is Bram Moolenaar. Vim is GPL-compatible, but not GPL software. It's charityware. Bram asks that if you find vim useful, please make a donation to help children in Uganda through the ICCF. More information can be found on the vim home page at http://www.vim.org/.

Dot Files

Vim reads and executes several files when it starts, which allow an environment to be created every time the editor starts. These vim scripts use the same commands that you can type after the colon character while in command mode, but without the colon. Generally these files contain a lot of "set" commands. "set" is used to set the value of a variable, which can either be a boolean (set variable or set novariable) or a string (set stringvar="asdf").

Here's some examples of settings you might use in your ~/.vimrc. The double quotation mark is the comment character.

" turn off some unpleasant vi-compatible behavior
set nocompatible
" make backspace erase over anything
set backspace=2
" don't create those annoying ~ files
set nobackup
" make searching not jump around or highlight stuff
set nohlsearch noincsearch
" keep a 50-entry command history, no line jump entries
set viminfo='0,\"50

Initialization

On startup, vim processes command line arguments, then reads in the system vimrc file, then reads in the optional .vimrc file in your home directory. There are some other details here, but those relate to starting up vim in another mode.

You may have found that certain distributions (like the Red Hat installation on the CoC machines) have an undesirable system vimrc. If you start vim with the -u switch and pass it your .vimrc file, it will skip all other initialization steps and just use the file you specify.

Modes

Vim, like its predecessor, vi, is a modal text editor. When in "insert" mode, typing will add text to the current file, whereas while in "command" mode (also known as normal mode), typing will do something else entirely. Command mode is used to execute movement commands, delete, copy, and paste text, undo your stupid mistakes, and other assorted cool things.

Vim starts in command mode. Hitting i will enter insert mode. Hitting a (append) will enter insert mode and move the cursor forward one space, useful for adding text after the end of a line and things like that. Other nice ways to enter insert mode are o, which starts a new line after the current one, and O, which starts a new line before the current one. Certain text-replacement commands, such as c and s will enter insert mode after deleting some amount of text. s (substitute) will remove a single letter, while c (change), when followed by a movement command, will remove the amount of text you moved over. cw will replace a word, cG will replace to the end of the file, and so on.

While in insert mode, typing does mostly just that. Hit Esc to return to command mode. Insert also has a special sub-mode useful for pasting text. You can either run :set paste from command mode or set pastetoggle to some key (:set pastetoggle=<F4>, for example) and hit that key, and all automatic indentation is disabled. After you're done pasting text, either :set nopaste or hit the pastetoggle key again.

Many of vim's commands apply to a group of line numbers or a movement command, but editing in this abstract fashion can be confusing. Visual mode solves this problem by allowing you to select a block of text, showing you the selection as you go, and apply a command to it. v will enter visual mode, V will enter visual line mode, selecting entire lines at a time, and Ctrl-V will enter visual block mode, selecting an arbitrary rectangle of text.

Movement Keys

If you've only got an old busted terminal type, hjkl moves you left, down, up, and right, respectively. Otherwise, the arrow keys, page up, and page down do what they say they do.

You can move to the beginning of a line with ^ and the end of a line with $.

You can move to the next word in a line with w, or to the previous word in a line with b. vim defines a word as a sequence of letters, numbers, and underscores. That means hyphenated words are really two words, plus an extra one for the punctuation. W and B do the same motion, but have a different definition of a word - a sequence of non-space characters.

You can also move in larger quantities. ( and ) move you to the beginning of the previous and next sentence. A sentence is defined as a block of text terminating with a punctuation mark, followed by whitespace. You can also move a paragraph at a time with { and }. Paragraphs end with a blank line.

You can also move to a specific line, with :n. There's a special shortcut for going to the first line - gg - and the last line - G.

If you're editing code with lots of parens, you might also like to quickly jump around and find out where the paren you're closing was opened. Put your cursor on a paren and hit %. The cursor will jump to the matching open or close. This also works for brackets, curly braces, C comments, and c preprocessor defines.

Finally, the really powerful thing about movement keys is that they can be combined with operators to do text manipulations. See :help operators

Online Help

The included man pages are really there to document the command line options for vim and not explain the program in detail. The main documentation is available through the :help system in vim. If you type that you will get a list of all of the online help files available.

The online help system is hyperlinked. The movement keys are the same as those in the tags system (see below). Links are wrapped in pipeline characters. For example, |tips.txt| is a link to the tips.txt help file. To jump to that, position the cursor somewhere between the pipeline characters and press Ctrl+]. To go back to the previous page, press Ctrl+t.

Navigating the help system is nice, but sometimes you know exactly where you want to go. Say you want to read the help file for the GUI version of vim. You can type :help gui and it will jump right to it. Of course, there's no way of knowing these names until you become familiar with the help system. If I wanted to get to the GUI help page by navigating, I would position the cursor over |gui.txt| and press Ctrl+].

Lastly, to exit the online help, just type :q


Developer Stuff

Syntax Highlighting

One of vim's more popular features is syntax highlighting (or technically lexical highlighting). Syntax highlighting provides a mechanism to display text in different colors or fonts, based on pattern matching. Chances are, you are using syntax highlighting without knowing it. Random bit of trivia: open your dns.vim file in vim and see who the maintainer is.

To enable syntax highlighting, use the :syntax enable command (NOTE: the :syntax on command does the same thing, but instructs vim to override any color settings you already have). The main syntax highlighting file is sourced in, which then determines your file type and loads the right pattern matching rules. On my vim 6.2.200 installation, there are 384 syntax files included. Most languages and configuration file formats have a syntax file, but you may fine an instance where a file is incomplete or lacking entirely.

You can create your own syntax files and place them in your ~/.vim/syntax directory. Vim searches the existing library, then yours for syntax files. Type :set syntax=YOURFILE to start using your syntax file.

If you want to add to an existing syntax file, you can place additions in to a file by the same name in to the ~/.vim/after/syntax directory. The main syntax file will be loaded, then your additions.

Detailed documentation on the syntax file format can be found by typing :help syntax within vim.

Tags

Often, when wandering through a program, it would be nice to just jump to a function. ctags, available at http://ctags.sourceforget.net, solves this problem by creating an index of the functions in each file in a format readable by vim. Just run ctags on your source files, which will create a file 'tags' in the current directory, and, when you want to jump to the function under the cursor, hit Ctrl-]. To return to the spot where you were before jumping to the tag, hit Ctrl-T.

If you know the name of the function and just want to go there, the tag command can be used. :tag function_name Sometimes multiple matches occur, and you can choose a particular one using :tagstack.

split/vsplit

vim lets you have several files open at a time by having multiple windows open at once. There's two important things to remember: first, any commands you do apply to the window that the cursor is currently in; and second, just about all the window manipulation commands start with Ctrl-W.

Typing :split filename makes a new window with filename open in it. The two windows are put one on top of the other. Having the same file open twice isn't very exciting which is why split can optionally take an argument with the file to put in the other window.

You can also split the screen vertically so the two files are open side-by-side. That command is :vsplit and works in the same way to regular split. Yes, you can keep splitting horizontally and vertically until you have a giant pile of unreadable windows.

Now that you've got the two windows open, you'll want to move between them. The movement keys make heavy use of the control key, unfortunately. You can move left, down, up, and right by pressing Ctrl-W followed by h, j, k, or l, respectively. You can also use Ctrl-W and an arrow key, if that's more your style.

Once you've got a window open, closing it is simply a matter of putting the cursor in the window you want closed and doing :q or a similar command.

Windows can also be resized. Ctrl-W = makes all the windows the same height and width. Ctrl-W _ makes the current window as wide as possible, while Ctrl-W | makes it as wide as possible. Those make sense if you squint really hard. You can also change the window size one line at a time though I don't find that to be very useful. If you're using gvim or you have the mouse enabled for the terminal, you can use it to just drag the resize bars.

There's about a billion other window manipulation commands. You can do all sorts of resizing, jumping between windows, applying commands to all windows, hiding and unhiding, and moving windows around on the screen. :help windows will tell you more than you ever wanted to know.

vimdiff

vimdiff lets you compare two files side-by-side and operate on the differences between then. You can start diff mode from the command line with vimdiff disk.c.orig disk.c or from within vim if you've already got one of the files open, line so: :vert diffsplit disk.c.

Any lines in one windows that aren't in the other are highlighted in blue, with a filler line in the other window. This keeps the two files in sync as you scroll. Lines with differences are in purple, with the differences themselves highlighted in red. These colors are customizable.

You can easily copy differences from one window to the other. Put the cursor on a difference or right after it. Then use dp (diffput) to take the difference from the active window and put it in the second window. You can also use do (diffobtain) to take the difference from the second window and put it in the active one. As you make changes and bring the files in sync, vim will fold the differences up.

Folding

Sometimes it's useful to treat multiple lines as a single entity. vimdiff will do this automatically, some project, such as PHP, define folds through comments, and folds can be defined as you go using commands that no one can ever remember (zf<movement> creates a fold, <n>zF creates a n-line fold).

There are several methods of defining folds, configurable through the 'foldmethod' variable. vimdiff uses the 'diff' method, php uses the 'marker' method and makes comments using the text in the 'foldmarker' variable, and some languages work well with the 'indent' method, where increased indentation creates a new fold.

A fold, for the most part, can be treated as a single line. To open a fold, use zo or zO to open the fold and all nested folds. Use zc or zC to close a fold.

Indents

Nobody likes to hit tab all of the time, so vim has some rules to figure out when to hit tab for you. The simplest form of automatic indentation is done when the autoindent option is set. If the previous line has some initial indentation, the next one will, too. This prevents you from hitting tab for every line in a C file, but vim can do a lot more.

The generic autoindent rules are defined through the indentexpr variable, which usually points to a big complicated function that, hopefully, someone else has already written. If the indentation rules are bothersome, you can set indentexpr to the empty string to disable it. The number of spaces to add for each new indentation is configurable through the shiftwidth variable. This variable alos effects the < and > commands.

Vim two special indentation cases. Setting 'cindent' will activate indentation rules suitable for C programs which will keep you from needing to hit Tab or Backspace ever again, and the 'lisp' mode does the same sort of thing for LISP. cindent can be configured for different indentation styles through the 'cinoptions' variables. The 'smartindent' option activates rules similar to cindent, but less so.


Advanced Commands

Auto Commands

Often, there are several settings that you want to apply only to certain types of files. For example, Makefiles should never have expandtab set, and different indentation levels work better for different languages. Vim solves this problem with autocommands, which allow commands in your .vimrc to be executed only if a certain condition is met. There are approximately 50 million events that can trigger an autocommand; see :help autocmd-events for all of them.

Autocommands take the form of:

:au[tocmd] <event> <pattern> <command...>

Among the most useful of the events are BufEnter, which executes any time a filename matches a given glob pattern, and FileType, which uses vim's filetype heuristics instead of the filename. Some examples:

" disable all current autocommands in case vimrc gets sourced twice
au!

" holy crap we need tabs
au FileType make setlocal noexpandtab
" set 3-space autoindents and tabstops for a big pile of languages
au FileType c,cpp,python,java,sh setlocal shiftwidth=3 softtabstop=3 expandtab

" wrap at 76 characters when editing the motd, READMEs, or any random text file
au BufEnter motd,README,*.txt setlocal textwidth=76

The "setlocal" command works just like "set", but only applies the settings to the current buffer. This prevents the file-specific settings running the settings for other files.

Vim has several built-in autocommands for certain filetypes, which can be run by adding the following to your .vimrc:

" load any plugin commands and indentation rules
filetype plugin indent on

Editing over the network

You don't even have to have the file on the same computer as you're editing. vim will let you edit files over rcp, scp, ftp, http, dav, and rsync. All you need to do is have the netrw script installed, which comes with any recent version of vim. Then you just use :e and :w as usual. It's the parameter that's different. Since most people prefer scp, here's how you'd use it:

:e scp://chris@monolith//etc/rc.d/rc.local

If you've got your SSH keys set up, it won't even prompt for a password. The file will be transferred to the local computer. When you go to write the file out, it will be transferred back to where it came from. Note that the netrw syntax for scp is a little different from the scp command syntax.

vim uses wget for http transfers and only supports read-only mode. vim will also read your .netrc file for ftp configuration, if it exists. With the right setup, network editing is basically transparent. As with everything, there are bunches of options to play with. See :help netrw for the details.

Tab Completion

You can get bash-style tab completion from within vim by adding the following to your .vimrc:

set wildmode=longest,list

Completion will run to the longest common string, then list the multiple matches if there are any. More information is available from :help wildmode.

Abbreviations

Abbreviations allow you to define a short piece of text that stands for something much longer. As you type, vim looks for the shortened forms and automatically replaces them with the longer forms. Luckily, it only does the substitution when the short form is followed by whitespace or punctuation, when you hit escape, or when you explicitly tell it to expand. Abbreviations can be defined for insert mode, replace mode, and command line mode.

:iab mainf int main (int argc, char **argv)

This creates an abbreviation so that any time you type mainf, the prototype for the C main function will get pasted in place. You can list all your defined abbreviations with :ab and remove that mainf abbreviation with :unab mainf.

The other use for abbreviations is for correcting bad typing. :iab teh the will cause vim to correct that common typo.

map

Map allows you to set custom key mappings within vim. For example, you can set the F7 key to be a syntax highlighting toggle key:

:map <F7> :if exists("syntax_on") <Bar>
     \   syntax off <Bar>
     \ else <Bar>
     \   syntax enable <Bar>
     \ endif <CR>

With this map, you can press F7 to enable and disable syntax highlighting on the fly.

Programming with vim

Vim can be used as a programming language. It has variables, and functions, and control-flow statements and all that, but you probably shouldn't try to write a compiler as a vim command. Vim's programming features are mostly useful for (surprise!) doing more crazy things with text. Indentation expressions are usually defined as a function, and functions can also be used to create new commands, which can in turn be mapped to new keybindings.

Variables are defined with the 'let' command. The let command recognizes several different scopes: l:varname is local to a function, b:varname is local to a buffer, and g:varname is global. l: is the default scope, and the other scope prefixes must be used whenever a variable is defined or used. let can also be used to modifier configuration settings by prepending an ampersand to the setting name. let &showmatch=1 is equivalent to set showmatch.

Functions are defined with the 'function' command, and end with 'endfunction'. They work about how one would expect. Here's a factorial example to demonstrate.

function Factorial(n)
   if a:n == 0
      return 1
   else
      return a:n*Factorial(a:n-1)
   endif
endfunction

User functions must begin with an uppercase letter, which prevents them from running over vim's functions. Arguments are passed in through the 'a:' scope, and everything else works pretty much as you would expect.

Commands are defined in much the same way as functions, except they happen all on one logical line and can't have arguments. Commands are also usually more concerned with editing things than returning things, so they tend to make more use of things like the 's' command, or the 'normal' command, which executes a string of text in normal mode. For example, to append the value of Factorial(12) after the current cursor position:

" uses execute so that one bigass string, with <Esc> and the like
" translated into their corresponding characters, are all passed to one
" normal command
command Fact12 execute "normal a" . Factorial(12) . "\<Esc>"

Vim has a big pile of builtin functions to do whatever you could want with file I/O and string mangling. :help is your friend. For the sake of an example, here's how you could tell vim to treat *.sig files as SML if there's any *.sml files in the same directory:

au BufEnter *.sig if
   \globname(substitute(bufname("%"), "[^/]*$", "", "") . "*.sml") != "" |
   \setlocal filetype=sml endif

The substitute function takes the name of the current file (bufname("%")), replaces the filename component (arg 2) with the empty string (arg 3, arg 4 is flags) which leaves the directory name, appends *.sml to this, and then tests whether that works as a shell-style glob. If so, it's sml.

Vim also has a while command for looping, but no one ever uses that.

Random Stuff

There are two ways of using CVS within vim. The cvscommand method allows for CVS interaction from the : prompt. CVS diffs are performed using vimdiff. The cvsmenu method adds a CVS menu to gvim, with some more options. You can find these two addins here:

http://vim.sourceforge.net/scripts/script.php?script_id=90
http://vim.sourceforge.net/scripts/script.php?script_id=58

You can drive your Makefile from within vim using the :make command. Type :help make for more information.

Filter lines of text through external programs with the ! command.

You can get keyword completion in insert mode using the Ctrl+N and Ctrl+P commands. If you have multiple source files, you'll need to be using ctags for this to work.


Valid XHTML 1.1!