I am surprised to see the amount of people who don't know all the cool features of vim, quite frequently even its aficianados! Hence I will go over some of its useful advanced features today; this assumes you can use it on a basic level.
The single worst criticism of vi is that it is very lacking in useful features, and this is especially heard from emacs users. Well, this is no longer 1976, Bill Joy is a washed-up scientist, and his early brainchild has been cultivated by numerous others. Most will agree, the best vi variant to date is vim, which has an active developer community and a ton of functionality not found in the first vi. It can be used for editing of system and formatted text, numerous programming languages and typesetters, and even file management...and, yes, it even plays Snake.
Before I start with anything else, it is important to discuss the basic elements of vim's extension facilities and such. These are:
Buffers
A buffer is a sequence of text that usually comes from a file. Buffers have a number of Options to change their behavior.
Windows
Granted, this (as well as buffer) got ripped off of emacs. But it was a good idea from none other than rms, and can be considered a parallel or related development to the very earliest GUI milestones. This is not a window as such (in a windowing system), but is instead a region of the screen that conveys a certain buffer. In this way, vim running on a terminal can divide the display into a sections, each displaying a buffer.
Options
A sort of variable dictating various behaviors to vim. They are not the same as vim script variables, and are treated differently. Options can be global, as well as local to a given buffer or window. The behavior can be quite complex and I am only covering the most basic parts of it. Naturally, the local options are preferred over global.
Scripts
In this presentation, a script will be considered a series of ex commands that can be put into a file and executed as a script. There are a number of ways that this is done, both arbitrarily and in instances done automatically by the editor. $HOME/.vimrc is one such example, the file containing various commands that represents each user's settings. To see all of the vim scripts that have been sourced, in ascending order of time, use the ex command :scriptnames. Normal mode commands can be placed in a script via the ex command :normal. Vim can also run scripts from the command line on files.
Plugins
Plugins are scripts which are automatically loaded to extend vim's functionality or provide extra facilities for a certain filetype. Filetype plugins include things like syntax highlighting and indenting.
Visual Mode is awesome for a number of reasons. What it does is selects text within a given buffer, to which commands can be applied (in fact most commands will be made to apply strictly to the selected area). There are several ways to do this: by character, by line, and by block, which means vim can select a rectangular area of text within a buffer. This is the only Unix editor I know that can do this.
Here, on an example file, I will use some sample Visual Mode commands on an example text:
18. Eusa had thay Nos. of thay Master Chaynjis. He run them thru the
Power Ring he mayd the 1 Big 1. Eusa put the 1 Big 1 in barms then him &
Mr Clevver droppit so much barms thay kilt as menne uv thear oan as thay
kilt enemes. Thay wun the Warr but the land wuz poyzen frum it the ayr &
water as wel. Peapl din jus dy in the Warr thay kep dyin after it wuz
over. Mr Clevver din cayr it wuz aul the saym tu him poyzen wuz meat &
drink tu him he wuz that hard. Eusa with his wyf & 2 littl suns gon
lukin for a nuther plays tu liv.
Moving the cursor to the beginning of the text, I can select individual characters with v in normal mode. I'll get rid of some chars like so:
v5l, then x
sa had thay Nos. of thay Master Chaynjis. He run them thru the
Power Ring he mayd the 1 Big 1. Eusa put the 1 Big 1 in barms then him &
Mr Clevver droppit so much barms thay kilt as menne uv thear oan as thay
kilt enemes. Thay wun the Warr but the land wuz poyzen frum it the ayr &
water as wel. Peapl din jus dy in the Warr thay kep dyin after it wuz
over. Mr Clevver din cayr it wuz aul the saym tu him poyzen wuz meat &
drink tu him he wuz that hard. Eusa with his wyf & 2 littl suns gon
lukin for a nuther plays tu liv.
Trivial example, but now let's say I want to make the first three lines all lowercase like an IRC chat:
V2ju
sa had thay nos. of thay master chaynjis. he run them thru the
power ring he mayd the 1 big 1. eusa put the 1 big 1 in barms then him &
mr clevver droppit so much barms thay kilt as menne uv thear oan as thay
kilt enemes. Thay wun the Warr but the land wuz poyzen frum it the ayr &
water as wel. Peapl din jus dy in the Warr thay kep dyin after it wuz
over. Mr Clevver din cayr it wuz aul the saym tu him poyzen wuz meat &
drink tu him he wuz that hard. Eusa with his wyf & 2 littl suns gon
lukin for a nuther plays tu liv.
Even better. Now we move onto the block visual mode. What I can do with this is select rectangular regions of text, and what's more, special commands apply to such a selection. One such is the normal mode command I. I'll select the beginnings of the text, then I serves as an insert equivalency that inserts the string entered at front of all rows of the block:
CTRL-V7jI<Spc><Spc><Spc><ESC>
sa had thay nos. of thay master chaynjis. he run them thru the
power ring he mayd the 1 big 1. eusa put the 1 big 1 in barms then him &
mr clevver droppit so much barms thay kilt as menne uv thear oan as thay
kilt enemes. Thay wun the Warr but the land wuz poyzen frum it the ayr &
water as wel. Peapl din jus dy in the Warr thay kep dyin after it wuz
over. Mr Clevver din cayr it wuz aul the saym tu him poyzen wuz meat &
drink tu him he wuz that hard. Eusa with his wyf & 2 littl suns gon
lukin for a nuther plays tu liv.
That'll leave space for notes on a printout. Cool!
It is no exaggeration to say that vim has a shiatload of options. Just tons of easily configurable behavior right at the fingertips! For those of you who don't have time or don't want to write some kind of script or macro, options, nearly all being simple Boolean values, options are awesome. This section details their use and a few of the more useful ones.
Options in vim are set mainly via the ex command :set. Actually, there are variants of :set that specifically alter the global and/or local (to buffer or window depending on the particular option) value of an option. All the behaviors are not covered here. :set will set both a global and local value. :setglobal will do global without affecting local. :setlocal follows as being fairly obvious. As some may know, Boolean values are set by typing either :set option or :set nooption for true and false, respectively. Naturally, these ex commands can go into your .vimrc which gets sourced automatically each time the editor runs. Let's examine a few of these cool options, starting with my own .vimrc:
:set textwidth=72
:set nowrap
:set runtimepath+=~/.vim/macros
:filetype plugin indent on
:syntax on
The first three lines obviously set options. The first sets textwidth's global value to be 72, which means that as I'm typing, text will be automatically fit within 72 columns. The negative of the option wrap will supress lines that exceed the boundaries of the display from wrapping around, something I find really annoying. The next one is a little more peculiar in that it does not operate on a Boolean level, instead, it adds a dircetory to option runtimepath, the list of directories that serves as a sort of $PATH for scripts.
The last two lines don't exactly set options, but since they are closely related, I'll cover them here. The ex command :filetype plugin indent on, which turns on filetype detection and allows for plugins and indentation behavior files related to various filetypes to be used. :syntax on does the same thing for syntax highlighting.
But there is plenty to add to that. By typing the ex command :options, the whole gamut of options is visible in a new window. By typing Return over a 'set' line, the option can be changed globally (save for a few options strictly local). There is just tons of stuff. One such that stands out is dict. By settting this to the path of a dictionary file, I can do completion of words in Insert mode, by typing C-X C-K . Enlightened, I made a dictionary file off of web sources and put it in ~/.vim, then put :set dict=/home/fingolfin/.vim/dict in my .vimrc to make it permanent.
Ever see a file with a a line like this at the top? /* vim:ts=4 */ That's called a modeline. By putting this at the beginning or end of a file, one can set options local to the buffer each time the file is loaded. Modelines can be enclosed within some form of comment to avoid interference with parsing. In fact this html file has vim:ts=4 enclosed in an html comment. The option ts is used to modify the width of tabstops, set to four spaces in this instance.
Lastly, with all these options set, you may wonder how to view the value of an option. Ganz einfach...:set option? This displays it at the bottom, and tries to use a local value before global.
This section will not cover how to write vim scripts. Instead, it will talk about them from the perspective of a user. Imagine vim's scripting as being like a miniature version of the shell. There is an equivalent of $PATH, some scripts are run automatically by vim as a part of the overhead, and still others must be sourced explicity. Vim scripts end with the extension of .vim. By querying the option runtimepaths, I can find out where they are. For example in /usr/share/vim/vim62:
total 256
-rw-r--r-- 1 root root 1906 Sep 18 2003 bugreport.vim
drwxr-xr-x 2 root root 4096 Sep 18 2003 colors
drwxr-xr-x 2 root root 4096 Sep 18 2003 compiler
-rw-r--r-- 1 root root 645 Sep 18 2003 delmenu.vim
drwxr-xr-x 2 root root 4096 Sep 18 2003 doc
-rw-r--r-- 1 root root 1812 Sep 18 2003 evim.vim
-rw-r--r-- 1 root root 37365 Sep 18 2003 filetype.vim
-rw-r--r-- 1 root root 280 Sep 18 2003 ftoff.vim
drwxr-xr-x 2 root root 4096 Sep 18 2003 ftplugin
-rw-r--r-- 1 root root 766 Sep 18 2003 ftplugin.vim
-rw-r--r-- 1 root root 285 Sep 18 2003 ftplugof.vim
-rw-r--r-- 1 root root 1698 Sep 18 2003 gvimrc_example.vim
drwxr-xr-x 2 root root 4096 Sep 18 2003 indent
-rw-r--r-- 1 root root 382 Sep 18 2003 indent.vim
-rw-r--r-- 1 root root 282 Sep 18 2003 indoff.vim
drwxr-xr-x 2 root root 4096 Sep 18 2003 keymap
drwxr-xr-x 19 root root 4096 Sep 18 2003 lang
drwxr-xr-x 6 root root 4096 Sep 18 2003 macros
-rw-r--r-- 1 root root 32837 Sep 18 2003 menu.vim
-rw-r--r-- 1 root root 2609 Sep 18 2003 mswin.vim
-rw-r--r-- 1 root root 48084 Sep 18 2003 optwin.vim
drwxr-xr-x 2 root root 4096 Sep 18 2003 plugin
drwxr-xr-x 2 root root 4096 Sep 18 2003 print
-rw-r--r-- 1 root root 7503 Sep 18 2003 scripts.vim
-rw-r--r-- 1 root root 24208 Sep 18 2003 synmenu.vim
drwxr-xr-x 2 root root 8192 Sep 18 2003 syntax
drwxr-xr-x 2 root root 4096 Sep 18 2003 tools
drwxr-xr-x 2 root root 4096 Sep 18 2003 tutor
-rw-r--r-- 1 root root 2411 Sep 18 2003 vimrc_example.vim
There are a whole bunch of subdirectories here, containing a number of scripts for vim's extension. indent coveres indentation files, keymap covers the scripts that enable non-English, non-ASCII input, ftplugin covers filetype plugins, etc. This structure can be mirrored in your home directory, under .vim. For example, scripts under the directory plugins in any directory in runtimepath will be automatically sourced during startup, such as those in /usr/share/vim/vim62/plugins, as well as those you can put in $HOME/.vim/plugins and good as they offer much useful functionality:
total 96
-rw-r--r-- 1 root root 286 Sep 18 2003 README.txt
-rw-r--r-- 1 root root 34959 Sep 18 2003 explorer.vim
-rw-r--r-- 1 root root 4783 Sep 18 2003 gzip.vim
-rw-r--r-- 1 root root 37620 Sep 18 2003 netrw.vim
-rw-r--r-- 1 root root 1171 Sep 18 2003 rrhelper.vim
-rw-r--r-- 1 root root 705 Sep 18 2003 tohtml.vim
Stuff like editing of gzip compressed files and transparent editing over network protocols like scp and ftp is made available by these standard plugins. Let's examine the tohtml.vim plugin:
" Vim plugin for converting a syntax highlighted file to HTML.
" Maintainer: Bram Moolenaar
" Last Change: 2003 Apr 06
" Don't do this when:
" - when 'compatible' is set
" - this plugin was already loaded
" - user commands are not available.
if !&cp & !exists(":TOhtml") & has("user_commands")
command -range=% TOhtml :call Convert2HTML(
func Convert2HTML(line1, line2)
if a:line2 >= a:line1
let g:html_start_line = a:line1
let g:html_end_line = a:line2
else
let g:html_start_line = a:line2
let g:html_end_line = a:line1
endif
runtime syntax/2html.vim
unlet g:html_start_line
unlet g:html_end_line
endfunc
endif
This script defines a function to convert a buffer to HTML via the 2html.vim script, and defines an ex command to call the same function.
But it is possible to source 2html.vim directly, the example I will use for explicit execution of a vim script. Let's say for example, I want a highlighted HTML of the buffer I am editing. I type :runtime syntax/2html.vim This executes a script in the path, with the directory and name of the script supplied.Of course, there are plenty of scripts available for vim on the web, and the chief repository for the same is at Vim's Sourceforge Page; simply browse to the Scripts section. The gamut is now become so sophisticated that there are some scripts that have dependencies on others. One useful script I found is vimcommander.vim, a two-pane file browser that does what Dired does for emacs (save of course that it has the advantage of a two-pane commander layout). I downloaded the script via lynx, then put it into my directory $HOME/.vim/macros/. When I want to source it, I need only type :runtime vimcommander.vim. This is because I added $HOME/.vim/macros to my runtimepath. But say I wanted it loaded automatically every time I start up? By moving the script into the subdirectory plugin of any directory in runtimepath, the script will be automatically sourced upon startup, and thus I can move it into $HOME/.vim/plugin.
Most scripts have some kind of instruction on using them. Their primary function for usage is bound to a sequence of keys (called a mapping), and that's what I'll cover shortly. In the instance of vimcommander.vim the ex command suggested is: :noremap <silent> <F11> :call VimCommanderToggle()<CR>, which binds F11 to do :call VimCommanderToggle() and then hit enter, as though it were being typed.
Filetype plugins are those plugins which are related to...filetypes. For the filetypes available, see /usr/share/vim/vim62/filetype.vim. To use them, simply drop them in any directory in runtimepath plus ftplugin/filetype optional_suffix_beginning_with_underscore.vim. So for example, I have html.vim and html_macros.vim.
It seems a lot of people don't know vim can do this quite well! This had come up during a particularly rowdy conversation in one of our monthly LUG meetings, while I was still walking the misguided path of emacs, when I compared using vi to taking a dump in a garbage can. But I knew this even then!
Remember what buffers and windows are; they are the basis of editing multiple files in any circumstance. For instance, we can try the first method vi used to edit multiple files, which is by supplying multiple files on the command line.
vim *
This will of course edit all files in pwd. When I am done with one file, I write the buffer that I made changes to and go onto the next with the ex command :next. Of course, I can also go back with :previous. When all is done I can :q.
And another example: typing :options will create a new window in which global options can be edited, as said before. Typing :quit will nuke this window off.
But what is it that lies beneath all this? Typing :buffers while editing multiple files in the method above, I find that vim is simply using buffers to keep track of the multiple files. Note that :quit does not necessarily quit the editor; it only does this when there is one window (which is the case when you are just editing one file, using one window, the usual circumstances). Now, I will discuss how to use windows and buffers in a more versatile manner.
To begin with, I'll start by opening a blank instance of vim, the one with the guilt-trip inducing charity message (but I don't have so much as a job right now). I'll make a buffer by loading a file with the command :edit file. This ex command, given a file as argument, edits a file in the current window and discards changes to the buffer that was in it before; it frees the memory for the buffer, although the buffer remains in the list; this is called unloading the buffer. Note that when I speak of hiding a buffer, there is a different scenario; the buffer is not visible, but it is still remembered. If you do the command :buffers after starting a blank instance of vim, you will notice there is one, called "No File". If I made changes to this, remember that :edit file would nuke any changes made to it. This may sound useless now, but the applied knowledge can be quite useful...
:edit example_bar
Ok, now I want to create a new window by typing :split. This splits the display into two horizontal windows; :vsplit does a vertical split. There are now two windows looking at the same buffer. Hoopy, I can make changes in stereo! But I want to edit another file by :edit example_foo Here is the exception to how :edit will kill changes to the current buffer; since the buffer is open in another window, it is still active. The vim manual covers the three primary states of a buffer nicely:
A buffer can be in one of three states:
*active-buffer*
active: The buffer is displayed in a window. If there is a file for this
buffer, it has been read into the buffer. The buffer may have been
modified since then and thus be different from the file.
*hidden-buffer*
hidden: The buffer is not displayed. If there is a file for this buffer, it
has been read into the buffer. Otherwise it's the same as an active
buffer, you just can't see it.
*inactive-buffer*
inactive: The buffer is not displayed and does not contain anything. Options
for the buffer are remembered if the file was once loaded. It can
contain marks from the |viminfo| file. But the buffer doesn't
contain text.
If I wanted to nuke the window containing some file, and make the buffer hidden, I could simply type the ex command :hide while in that window. But it is necessary to know how to switch windows, and how to switch buffers within them to return to a hidden buffer.
Window switching commands in vim have the advantage of allowing spatial motion. What I mean is that it doesn't go in a cyclic fashion; I can tell the editor to switch to the window above, below, or to the right or left. So if I have two windows, split horizontally, and I'm on the top one, I can do in normal mode: CTRL-W j (or the down arrow, of course), to move to the one below. Recall that the command to show current listed buffers is :buffers. Say I have three files open, but my 80x24 terminal is best suited for two windows. I will switch over to the window I want to switch the buffer in and type :buffers to see what's there. Then I can do :buffer number of buffer to switch.
There's more to it than that, of course. Let's say I start editing some file, and during the middle of the session, I want to start work on a completely new file that never existed before. By doing :new or :vnew, for horizontal and vertical windows respectively, I get the "No File" buffer like I would when starting a blank vim with no file. When I'm done with the new buffer, I can write it to a new filename with :w foobar. Additionally, it is possible to resize windows as needed. There are two ways to do this, through the ex commands, and through the keybindings. The keybindings are a lot more convenient, especially for horizontally arranged windows. They are number CTRL-W + and number CTRL-W - for enlargement and reduction respectively. The number that may be prepended is the number of columns. A really great command that works on all windows vertical and horizontal alike is CTRL-W =. This attempts to make them roughly the same size. A final element I will deal with, regarding buffers, is the unlisted variety. They do not show up in the output of :buffers unless you append an exclamation mark to the command (like with :q!), the 'dammit' operator in ex. This can be set by doing :set buflisted or :set nobuflisted.
Vim keymapping is the translation of one series of key strokes to another. That's it. Actually that's not all of it; there is more than that, but overall it is a fairly simple mechanism.
We'll investigate a few basic mappings now:
:nmap ,l :'<,'>s/</\</g<CR>
:nmap ,g :'<,'>s/>/\>/g<CR>
:nmap ,br :'<,'>s/$/<br>/g<CR>
First things needs to be known to understand these mappings is what they do and what they are for. The first, for example, maps the keys ,l in normal mode to type :nmap ,l :'<,'>s/</\</g<CR>, which executes the ex command that will substitute an instance of a < with an <, within the area selected by visual mode; ,g does the same with its counterpart and ,br replaces the end of the line with a <br> This is obviously for html formatting. Note also the characters enclosed in angle brackets. They are usually used to represent non-printable characters. From the vim manual:
Examples are often given in the <> notation. Sometimes this is just to make
clear what you need to type, but often it can be typed literally, e.g., with
the ":map" command. The rules are:
1. Any printable characters are typed directly, except backslash and '<'
2. A backslash is represented with "\\", double backslash, or "<Bslash>".
3. A real '<' is represented with "\<" or "<lt>". When there is no
confusion possible, a '<' can be used directly.
4. "<key>" means the special key typed. This is the notation explained in
the table above. A few examples:
<Esc> Escape key
<C-G> CTRL-G
<Up> cursor up key
<C-LeftMouse> Control- left mouse click
<S-F11> Shifted function key 11
<M-a> Meta- a ('a' with bit 8 set)
<M-A> Meta- A ('A' with bit 8 set)
<t_kd> "kd" termcap entry (cursor down key)
So if I wanted to bind the function key F4, I would use <F4> or, if I'm feeling obscure, the termcap entry, which is <t_k4>
Now, for further understanding, let's examine another mapping from the vim documentation:
:imap <F2> <CR>Date: <Esc>:read !date<CR>kJ
Notice a difference in the command given. This mapping applies to insert mode as opposed to normal mode, done by :imap. Intuitive, eh? Now, we examine the content of the mapping. First, it enters <CR>, which of course starts a new line, enters the text 'Date: ', then enters <Esc> to go to normal mode. So remember again, that mappings follow just as though you had typed them. The ex command :read !date is executed, remember that the <CR> is needed to call the command, as one would have to hit the same key when interactively typing it. Lastly, the cursor is moved up, and the new line made is joined.
Mappings can also be defined locally to a buffer, such as with a mapping like this one: :imap <buffer> <F2> <CR>Date: <Esc>:read !date<CR>kJ. Additionally, mappings that have outlived their usefulness can be nuked off with commands such as :nunmap key to destroy a normal mode mapping. This details most of the basic features of mappings; more can be found on your time.
As you might have guessed, this section deals with internationalization of vim. In my experience, the internationalization of vim is way, wayyy less a pain in the ass than in emacs.
First thing I will cover is using different encodings. Sometimes, it is good enough to set the option encoding, to define what charset vim uses internally for the text. It is usually either set to latin1, which is for Latin-1 obviously and evidently other eight-bit charsets like VISCII, or utf-8 for Unicode text. However, termencoding may also have to be set as well. As with any other editor supporting internationalization, use what works; experimentation may be neccesary. When editing a Unicode file on a non-Unicode terminal (i.e., no chance of setting console font or anything), you can set encoding to be utf-8, but set termencoding to be latin1 or whatever else is relevant. Unprintable characters will show often as an upside-down question mark, and you can examine them by the normal mode command ga. Also, the the ex commands :edit and :write can take the option ++enc to explicitly cause conversion. For example, :write ++enc=utf-8 can be used to convert an ISO-8859-1 file to UTF-8, as we see with my wonderful examples from Kraftwerk lyrics: Kraftwerk in ISO-8859-1 and Kraftwerk in Unicode. Doing the same for :edit will force detection of an arbitrary character set in a file.
Language of messages can also be changed, either by setting the proper POSIX environment variables, or by the ex command :language. For German messages, I may use either: export LC_ALL=de_DE or :language de_DE. Using the C locale will yield our familiar E------.
Now, the really cool part: entering foreign language text! This is extremely simple in vim. For those who do not use many special characters, digraphs can be used; you would type CTRL-K plus a short combination of letters (usually mnemonic) in insert mode. The default digraphs are generally made for European languages and very mnemonic; for example CTRL-K ss in insert mode will give us an s set: Wir mußen jedes Wort verstehen! You can also define your own digraphs, by typing the ex command :digraph mnemonic representation character in decimal. For example, a digraph for VISCII might be: :digraph dd 240. To see all available digraphs, just do :digraphs.
Keymaps are even better for editing lots of foreign language text. They can be found in any directory in runtimepath plus keymap, such as in /usr/share/vim/vim62/keymap. What they do is translate sequences of characters in insert mode as they are being typed. They are applied by changing the value of the option keymap. On a Unicode terminal, I can set encoding to be utf-8 and keymap to hebrew_utf-8, which is /usr/share/vim/vim62/keymap/hebrew_utf-8.vim minus the extension. I don't actually know Hebrew, but I can type some cool text now, and it'll come in handy should I ever decide to learn Hebrew (which could very well happen). These options, of course, can be set via a modeline, which is a good choice for long-term editing of foreign language text.
Vim is effin' A!