chapters/05.markdown @ ad477bf7ad4e

Introduce nunmap and prevent surprising behavior.

Thanks to @sedm0784 on GitHub for pointing it out.
author Steve Losh <steve@stevelosh.com>
date Fri, 12 Oct 2012 19:42:20 -0400
parents 383d371f3f1c
children 41e61b3dce7a
Strict Mapping
==============

Hold on, things are about to get a little wild.

So far we've used `map`, `nmap`, `vmap`, and `imap` to create key mappings that
will save time.  These work, but they have a downside.

Run the following commands:

    :::vim
    :nmap - dd
    :nmap \ -

Now try pressing `\` (in normal mode).  What happens?

When you press `\` Vim sees the mapping and says "I should run `-` instead".
But we've already mapped `-` to do something else!  Vim sees that and says "oh,
now I need to run `dd`", and so it deletes the current line.

When you map keys with these commands Vim will take *other* mappings into
account.  This may sound like a good thing at first but in reality it's pure,
unadulterated evil.  Let's talk about why, but first remove those mappings by
running the following commands:

    :::vim
    :nunmap -
    :nunmap \

Recursion
---------

Run this command:

    :::vim
    :nmap dd O<esc>jddk

You might think that this would change `dd` to:

* Open a new line above this one.
* Exit insert mode.
* Move back down.
* Delete the current line.
* Move up to the blank line just created.

In effect, this should "clear the current line".  Try it.

Vim will seem to freeze when you press `dd`.  If you press `<c-c>` you'll get
Vim back, but there will be a ton of empty lines in your file!  What happened?

This mapping is actually *recursive*!  When you press `dd`, Vim says:

* `dd` is mapped, so perform the mapping.
    * Open a line.
    * Exit insert mode.
    * Move down a line.
    * `dd` is mapped, so perform the mapping.
        * Open a line.
        * Exit insert mode.
        * Move down a line.
        * `dd` is mapped, so perform the mapping.
            * ...

This mapping can never finish running!  Go ahead and remove it with the
following command:

    :::vim
    :nunmap dd

Side Effects
------------

Not only do the `*map` commands we've learned so far run the danger of
recursing, but because they take other mappings into account they can change
when we install various plugins.

When you install a new Vim plugin there's a good chance that you won't use and
memorize every mapping it uses.  Even if you *do*, you'd have to go back and
look through your `~/.vimrc` file to make sure none of your custom mappings use
something that the plugin has mapped, and vice versa.

This would make installing plugins tedious and error-prone.  There must be
a better way.

Nonrecursive Mapping
--------------------

Vim offers another set of mapping commands that will *not* take mappings into
account when they perform their actions.  Run these commands:

    :::vim
    :nmap x dd
    :nnoremap \ x

Now press `\` and see what happens.

When you press `\` Vim ignores the `x` mapping and does whatever it would do for
`x` by default.  Instead of deleting the current line, it deletes the current
character.

Each of the `*map` commands has a `*noremap` counterpart that ignores other
mappings: `noremap`, `nnoremap`, `vnoremap`, and `inoremap`.

When to Use
-----------

When should you use these nonrecursive variants instead of their normal
counterparts?  The answer is: always.

**Always.**

**No, seriously, ALWAYS.**

Using a bare `*map` is just *asking* for pain down the road when you install
a plugin or add a new custom mapping.  Save yourself the trouble and type the
extra characters to make sure it never happens.

Exercises
---------

Convert all the mappings you added to your `~/.vimrc` file in the previous
chapters to their nonrecursive counterparts.

Read `:help unmap`.