Igor Irianto
Posted on March 26, 2020
Follow @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 5x
, 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, recommends 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
- Operator-Pending Mappings
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: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 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 does5x
. - When I type
x
in file2, it doesdd
. - When I type
x
in new file,file3
, it does neither5x
nordd
.
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
- split buffer horizontally
- split buffer vertically
- 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:
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}
.
Posted on March 26, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.