Basic Vim Mapping
Tags: vim, neovim, map, shortcut
Published: 2020-03-26 19:36:39

---
title: Basic Vim Mapping
published: true
description: How to create vim mapping
tags: vim, neovim, map, shortcut
---

*Follow [@learnvim](https://twitter.com/learnvim) for more Vim tips and tricks!*

One way you can customize vim is by creating your own key mappings to make Vim yours. This article will show you basics of map. This is not 100% comprehensive, but should be enough to get you started.

# Basic Mapping
If you want to map `x` to `dd` (delete line), you can:

```
:map x dd
```
Now whenever you type `x`, it executes `dd` instead. 

## Unmapping

To undo a particular mapping (ie, our `x` earlier), do:

```
:unmap x
```

When you type `x`, it will no longer do `dd`. It is back to its original function.

To remove **all** mapping, you can do 

```
:mapclear
```

This will wipe out all maps (don't worry, just exit and reopen vim to get your vimrc mappings back).

# Avoiding recursion

Suppose instead of mapping `x` to `dd`, you want to map `x` to delete 5 characters at a time (`5x`), so you do:
```
:map x 5x
```
When you type `x`, your screen freezes. What happened?

```
:map x 5x
     ^  ^-- x is recursive
```

What we are really hoping to do is to execute *original* x function (delete character under cursor). But Vim interprets it as if we are calling `x` map, which calls 5`x`, which calls our map, and so on, recursively - causing your display to freeze (`C-c` to free yourself).

To tell vim to use original x functionality, we need to use *NO RE*cursive mapping. In Vim, we add `nore-`:

```
:noremap x 5x
```

This time it should work.

Steve Losh, author of [learn Vimscript the Hard Way](https://learnvimscriptthehardway.stevelosh.com/), [recommends](https://learnvimscriptthehardway.stevelosh.com/chapters/05.html) using nonrecursive *all the time*. 

I agree. 

Even if we don't need it, it is a good habit to start mapping using non-recursive variants.

# Different mode mapping

What if we want to create a mapping that works only on visual mode, or mapping that works only on normal mode, or mapping that works only on insert mode? We can use **modal mapping**.

If you check `:h map.txt`, you'll see many different map options:
```
     COMMANDS                    MODES ~
:map   :noremap  :unmap     Normal, Visual, Select, Operator-pending
:nmap  :nnoremap :nunmap    Normal
:vmap  :vnoremap :vunmap    Visual and Select
:smap  :snoremap :sunmap    Select
:xmap  :xnoremap :xunmap    Visual
:omap  :onoremap :ounmap    Operator-pending
:map!  :noremap! :unmap!    Insert and Command-line
:imap  :inoremap :iunmap    Insert
:lmap  :lnoremap :lunmap    Insert, Command-line, Lang-Arg
:cmap  :cnoremap :cunmap    Command-line
:tmap  :tnoremap :tunmap    Terminal-Job
```

I will not go through all, but the documentation provide excellent resource. To learn more, nothing beats Vim's own documentation. I will go through 3 of them to get you started:

- normal
- insert
- operator pending

Let's go through each.

## Normal
If we use `:map`, it actually applies to 4 modes: normal, visual, select, and operator-pending. If we want to apply our mapping to just normal mode, we need to use normal-mode only map, `nmap`:

```
:nmap x dd
```

This will map `x` to `dd` in normal mode. Using the nonrecursive mapping variant, we have:

```
:nnoremap x dd
```

*I will use the non-recursive variant of all mapping from this point on.*

## Insert
We can also create mapping for when we are in insert mode. One popular insert mode map is to escape to normal mode. This can be very useful if you are typing with keyboard that does not have `<escape>` key equivalent (like some ipad keyboards). I mapped `<esc>` to `"jk"` using:

```
:inoremap jk <esc>
```

Typing `"jk"` will now exits insert mode.

When mapping for insert mode, don't forget that Vim takes your mapping *literally*. Let's say whenever you type `Ctrl-X` in insert mode, you want it to delete 5 characters under cursor (`5x`). 

You might try:
```
:inoremap <C-X> 5x
```

If you tried that, you'd see that it didn't work. Instead it printed "5x". You need to first escape, then perform 5x, then back to insert mode.

```
:inoremap <C-X> <esc>5xa
```

## Operator Pending 

If you are not familiar with "Operator Pending", let me briefly explain. In Vim, whenever you type an operator (ex: `d`, `y`, and `c`), you need to give it a motion or text object. This mapping is for the motion/text object that comes after you type an operator. 

For example, to delete (`d`) inner word (`iw`), you can do `diw`. To create a mapping of `dw` so it does `diw`:

```
:onoremap w iw
```

Whenever we do `dw`, it will instead do `diw`. Not much, but it saves one keystroke!

More resources on operation pending mapping:
-  `:h omap-info`
- [Operator-Pending Mode](https://medium.com/usevim/operator-pending-mode-a4247d8596b7)
- [Operator-Pending Mappings](https://learnvimscriptthehardway.stevelosh.com/chapters/15.html)

# Special arguments
We can give our mapping special arguments (`:h :map-arguments`). There are 7 special arguments:
```
<buffer>
<nowait>
<silent>
<special>
<script>
<expr>
<unique>
```

The basic syntax is:
```
map <special-argument> key-trigger key-sequence
```

I will go over `silent` and `buffer` because they are quite useful. You should be able to look for the rest.

## Silent
Adding `<silent>` prevents stdout in Vim when a command runs. Sometimes when you execute a command call in Vim, it gets echoed. Adding `<silent>` removes the echo. It does not remove error message though.

For example, I use [fzf.vim](https://github.com/junegunn/fzf.vim)`:Buffers` a lot and it echoes "Buffers" every time I run it.

This is the mapping that I initially have:

```
nnoremap <Leader>bb :Buffers<CR>
```

To silence it, I need to add `<silent>` in the map:

```
nnoremap <silent> <Leader>bb :Buffers<CR>
```

Now when I type `<Leader>bb`, I no longer see "Buffer" echoed.

## Buffer
Using `<buffer>` will make the mapping unique only to current buffer (if you're not sure what buffers are, [this](https://sanctum.geek.nz/arabesque/buffers-windows-tabs/) is an excellent article).

For example, if I have 2 files opened: `fileA` and `fileB`. 

In `file1` buffer, I want to map `x` to be `5x`:

```
:noremap <buffer> x 5x
```

In `file2` buffer, I want to map `x` to do `dd`:
```
:noremap <buffer> x dd
```

- When I type `x` in file1, it does `5x`. 
- When I type `x` in file2, it does `dd`.
- When I type `x` in new file, `file3`, it does neither `5x` nor `dd`.


# Leader Mapping

Vim allows us to use `<Leader>` key for further customization. For example, I have several mappings for buffers that use `Leader` key

```
nnoremap <Leader>bs :ls<CR>:sbuffer<Space>           " 1
nnoremap <Leader>bv :ls<CR>:vertical sbuffer<Space>  " 2
nnoremap <Leader>bp :let @+=expand("%:p")<CR>        " 3
```

1. split buffer horizontally
2. split buffer vertically
3. copy current buffer's absolute path.

Vim's default leader is `\` *(to view your current leader, you can do `:echo mapleader`)*.

I remapped my leader key to `<space>` because it is the biggest key in my keyboard. To do that, in my vimrc, I did:

```
let mapleader = "\<space>"
```

# Conclusion
During your Vim journey, you will want to start mapping commonly used actions. I suggest creating your own mapping (and not copy-paste other's vimrc) because other people may have different workflow than you. 

I hope this article helps you understand Vim mapping better. Happy coding!

Happy vimming!

# Resources:
- `:h map.txt`
- [Mapping keys in Vim - Tutorial (Part 2)](https://vim.fandom.com/wiki/Mapping_keys_in_Vim_-_Tutorial_(Part_2))
- [Basic Mapping](https://learnvimscriptthehardway.stevelosh.com/chapters/03.html)
- [On The Genealogy of Modality](https://vimways.org/2018/for-mappings-and-a-tutorial/)


*Btw, when I was reading the docs, `:h map.txt`, I was initially confused by `{lhs}` and `{rhs}`. After researching, they are pretty simple:*

- *`lhs` is the map trigger.*
- *`rhs` is key sequence if mapping is triggered.*

*If we have `:map x dd`, `x` is `{lhs}` and `dd` is `{rhs}`.*