chapters/04.markdown @ a16e1fecfe07 default tip

Be clear
author Steve Losh <steve@stevelosh.com>
date Mon, 27 Mar 2017 13:10:55 +0000
parents b0ca11bfb7a8
children (none)
Modal Mapping
=============

In the last chapter we talked about how to map keys in Vim.  We used the `map`
command which made the keys work in normal mode.  If you played around a bit
before moving on to this chapter, you may have noticed that the mappings also
took effect in visual mode.

You can be more specific about when you want mappings to apply by using `nmap`,
`vmap`, and `imap`.  These tell Vim to only use the mapping in normal, visual,
or insert mode respectively.

Run this command:

    :::vim
    :nmap \ dd

Now put your cursor in your text file, make sure you're in normal mode, and
press `\`.  Vim will delete the current line.

Now enter visual mode and try pressing `\`.  Nothing will happen, because we
told Vim to only use that mapping in normal mode (and `\` doesn't do anything by
default).

Run this command:

    :::vim
    :vmap \ U

Enter visual mode and select some text, then press `\`.  Vim will convert the
text to uppercase!

Try the `\` key a few times in normal and visual modes and notice that it now
does something completely different depending on which mode you're in.

Muscle Memory
-------------

At first the idea of mapping the same key to do different things depending on
which mode you're in may sound like a terrible idea.  Why would you want to
have to stop and think which mode you're in before pressing the key?  Wouldn't
that negate any time you save from the mapping itself?

In practice it turns out that this isn't really a problem.  Once you start using
Vim often you won't be thinking about the individual keys you're typing any
more.  You'll think: "delete a line" and not "press `dd`".  Your fingers and
brain will learn your mappings and the keys themselves will become subconscious.

Insert Mode
-----------

Now that we've covered how to map keys in normal and visual mode, let's move on
to insert mode.  Run this command:

    :::vim
    :imap <c-d> dd

You might think that this would let you press `Ctrl+d` whenever you're in insert
mode to delete the current line.  This would be handy because you wouldn't need
to go back into normal mode to cut out lines.

Go ahead and try it.  It won't work -- instead it will just put two `d`s in your
file!  That's pretty useless.

The problem is that Vim is doing exactly what we told it to.  We said: "when
I press `<c-d>` I want you to do what pressing `d` and `d` would normally do".
Well, normally when you're in insert mode and press the `d` key twice, you get
two `d`s in a row!

To make this mapping do what we intended we need to be very explicit.  Run this
command to change the mapping:

    :::vim
    :imap <c-d> <esc>dd

The `<esc>` is our way of telling Vim to press the Escape key, which will take
us out of insert mode.

Now try the mapping.  It works, but notice how you're now back in normal mode.
This makes sense because we told Vim that `<c-d>` should exit insert mode and
delete a line, but we never told it to go back into insert mode.

Run one more command to fix the mapping once and for all:

    :::vim
    :imap <c-d> <esc>ddi

The `i` at the end enters insert mode, and our mapping is finally complete.

Exercises
---------

Set up a mapping so that you can press `<c-u>` to convert the current word to
uppercase when you're in insert mode.  Remember that `U` in visual mode will
uppercase the selection.  I find this mapping extremely useful when I'm writing
out the name of a long constant like `MAX_CONNECTIONS_ALLOWED`.  I type out the
constant in lower case and then uppercase it with the mapping instead of holding
shift the entire time.

Add that mapping to your `~/.vimrc` file.

Set up a mapping so that you can uppercase the current word with `<c-u>` when in
*normal* mode.  This will be slightly different than the previous mapping
because you don't need to enter normal mode.  You should end up back in normal
mode at the end instead of in insert mode as well.

Add that mapping to your `~/.vimrc` file.