June 14, 2006

Vim tips: Using Vim mappings and abbreviations

Author: Joe 'Zonker' Brockmeier

Vim ships with a lot of useful functions that make life easier when you're editing text, but Vim is also an extremely extensible editor. If you find yourself typing the same long commands or strings of text over and over again, it's time you learned how to set mappings and abbreviations in Vim, to save valuable keystrokes for your code or prose.

Just as you can set shortcuts in KDE, you can map keystrokes to actions in Vim. A mapping can be as simple as creating an abbreviation that converts your initials to your full name, or something more complicated, like running a function when you press F10. Let's take a look at mappings, and how they can make you much more productive when working in Vim.

Types of mappings

Vim actually recognizes different types of mappings, depending on what mode the editor is in. For example, you might have a mapping for F2 in insert mode that enters an HTML tag or a line of C code, and a different mapping for F2 that toggles the syntax mode on when you're in normal mode.

Vim provides several different types of map commands, including:

  1. cmap handles command-line mappings.
  2. imap handles insert-only mappings.
  3. map maps keys in normal, visual, and operator-pending mode.
  4. map! maps keys in Vim's command and insert modes.
  5. nmap maps keys in normal mode only.
  6. omap maps keys in operator-pending mode only.
  7. vmap maps keys in visual mode only.

So, use imap if you want to set a mapping that works in Vim's insert mode, cmap for mappings to work in command (last line) mode, omap to map keys to function after an operator has been used in normal mode, and so on.

Setting a mapping

Let's start with something simple. To set a mapping while in Vim, enter command mode and use the map command. Here's a quick example:

:map <F10> <Esc>:tabnew<CR>

The syntax is pretty simple. First you tell Vim that you're setting a mapping. Then, tell Vim the key that will be bound to the action -- in this case, F10. Finally, spell out the action that Vim will perform when you use F10. This is pretty easy, because you're basically just listing the same keystrokes that you'd use if you were doing it manually.

In this example, we tell Vim to enter command mode (Esc:) and run the tabnew command, followed by the carriage return to return us to normal mode. (<CR> is the same as <Enter>, just faster to type.) Now, when you type F10 in normal mode, visual mode, or operator-pending mode, Vim will open a new tab.

Every now and again, it might be useful to set a mapping on the fly -- but the odds are, if it's worth doing once, it's worth setting the mapping permanently. To do this, just open your .vimrc and insert the mapping there, like so:

map <F10> <Esc>:tabnew<CR>

Want to see all of the mappings you have set? Type :map with no arguments, and Vim will list the defined mappings, like so:

n  ,S            <Esc>:syn off<CR>
n  ,s            <Esc>:syn on<CR>
   <F11>         <Esc>:setlocal nospell<CR>
   <F10>         <Esc>:setlocal spell spelllang=en_us<CR>

The other mapping commands, :imap and :omap, can also be used without arguments to show what characters are mapped for those modes -- the :map command only shows keys mapped for modes set with :map.

In this example, you can see that I have F10 set to turn on spellchecking, and F11 set to turn it off. This will work in normal and visual mode. In normal mode, using ,S will turn syntax highlighting off, and ,s will turn it on. I use the comma in that mapping for a couple of reasons. First, the comma has no special meaning in normal mode on its own. Second, it's within easy reach of the home keys.

Since I spend a lot of time working with HTML, I've set a few mappings to work in insert mode to insert HTML tags that I use frequently:

imap <F2> <p>
imap <F3> <strong>
imap <F4> <em>
imap <F5> <code>
imap <F6> <a href="
imap <S-F6> ">
imap <F7> <blockquote>
imap <S-F2> &lt;
imap <S-F3> &gt;

You can also set a mapping to call a function. For instance, I like Vim's highlight search, when I've just performed a search. But I like to get rid of the highlighting as soon as I am done with it. I found a useful tip on the Vim.org site with a function to toggle highlight search, so I could turn it off and on with a simple quick keystroke. Here's the function that I put in my .vimrc:

function ToggleHLSearch()
       if &hls
            set nohls
       else
            set hls
       endif
endfunction

Then, I added this to the mapping section:

nmap <silent> <C-n> <Esc>:call ToggleHLSearch()<CR>.

In this example, <silent> isn't a key -- it's to tell Vim not to print a message when it runs the command. Then, the key shortcut that is mapped to the action, and the action that will be called.

Mappings can be really useful once you start writing your own Vim functions -- or using Vim functions that other folks have written already. It's certainly easier to type Ctrl-n than type :call ToggleHLSearch() every time!

Also, I don't know about other Vim users, but I've always found the F1 mapping for Vim's :help command to be a bit annoying. It's not unusual for me to accidentally tap the F1 key when I mean to hit Escape or F2. So I've taken to mapping F1 to Escape in my .vimrc:

map <F1> <Esc>
imap <F1> <Esc>

Unsetting mappings

From time to time, you might want to get rid of a mapping. You can do this in a couple of ways. The first is to change the mapping for a key -- if you want to set F10 to a new mapping, just run :map <F10> command, to replace it for that session. To unmap it completely, use :unmap <F10>.

Each of the map commands has its own unmap command -- so, to unmap an insert map (imap) command, use :iunmap; to unmap a normal mode command (nmap), use :nunmap; and so forth.

Unlike the :map commands, the :unmap commands require an argument -- so, running :unmap won't just unset all of the active mappings, it will simply return an error.

You can also prevent a key from being remapped by using the :noremap command, or :inoremap, :onoremap, etc. This can be useful if you want to set a mapping using map, but want that key to be used for something else in operator-pending mode, or something like that. Despite the name, you can override a noremap command while in Vim.

Mapping notation

We've covered the notation for some of the special keys already, such as Escape (<Esc>), Enter (<CR>), and function key notation (<F1>, <F2>, etc.). For the most part, the notation is pretty intuitive, but not always.

For example, if you want to set a mapping for Ctrl-Esc, you'd use <C-Esc>. If you want to use Shift-F1, you'd use <S-F1>. For Mac users, if you want to set a mapping for the Command key (the weird symbol-thingy that PC users scratch their heads over), you'd use <D>. Note that Alt and Meta are the same, and you can use <M-key> or <A-key>.

You can also combine several keys if you want to emulate the Emacs hand-cramp style of key mappings. For example, if you want to run a command using Shift-Alt-F2, you could use map <S-A-F2> command.

See the Vim online help for a full list of special keys and their notation.

Abbreviations

Abbreviations are much like mappings, but they're used primarily to insert plain strings of text. They're only triggered when you enter a character like a space, Escape, or Enter. If I set a mapping for F10, it takes effect as soon as I type F10. If I set an abbreviation for insert mode to replace "i" with "I," it won't take effect if I type "imagine" or "Delphi," but it will take effect if I type just "i" followed by a space.

Another difference between mappings and abbreviations is that you can't use special keys, such as F10 or Shift-F10, to trigger an abbreviation. That's OK, because abbreviations tend to accumulate, and there are only so many ways you can combine the function, Control, Alt, and Shift keys anyway. (Especially since desktop environments like KDE also claim a number of them.)

Abbreviations are useful for a number of situations. For example, if you are prone to certain typos -- like typing "helllo" instead of "hello" -- just set an abbreviation in your .vimrc like this:

ab helllo hello

If you'd like the abbreviation to work in insert mode only, use iab instead.

Like mappings, abbreviations can be unset during your session. To remove a single abbreviation, use :una abbrv. To clear all abbreviations, use :abc.

If you go at it a little at a time, eventually you'll have a set of mappings and abbreviations tuned for your work that help make Vim even more efficient than it is to begin with.

Click Here!