And I mean custom mappings, not built-in stuff. I mean, you could easily fill a blog post with the built-in bindings you use regularly, since, in vim, there's a dozen ways to do the same thing. Some people prefer
D and others prefer
d$. But no, this post will include some of the custom bindings defined in my vimrc that I use pretty much every day.
If you're a big vim user already, feel free to grab these and throw them in your vimrc (if you're not a big vim user, that's usually
~/.vimrc). If you just want to experiment, you can type ":" and then any of the commands below to see how they work.
First, it's worth noting that I have my leader key set to space (which feels way more comfortable than the default backslash). You can configure your leader to use space like this:
let mapleader = "\<Space>"
The following commands use the
noremap base commands (and their modal equivalents).
noremap is a non-recursive mapping, meaning any non-default mappings that occur in another mapping will not be expanded, whereas
map is recursive. For example, given these bindings
:map j gg :map Q j :noremap W j
j will invoke the default
gg binding (jump to top of file). Pressing
Q will also jump to the top of the file because
map is recursive, so the
j is recursively mapped to the
gg mapping above it. However, the third binding will simply move your cursor down a line (the default binding for
j) since it is a non-recursive map and the
j is not expanded.
In addition to these commands, there are modal equivalents for creating bindings that only work in particular modes, such as
vnoremap for normal, insert, and visual mode recursive and non-recursive mappings respectively. If you are new to vim and that sentence was gibberish to you, 1) don't worry about it and just copy the mappings below. They work. I promise. 2) Don't worry about it. Vim takes time. I've been using it exclusively for over two years now and I still learn new things. There's probably still more that I don't know than I do.
Vim can highlight matches when you search if you set the
hls flag (i.e.
:set hls). This is a nice feature when you're in a text heavy piece of code, like HTML or markdown, or if you're just looking for a quick overview of where a variable is used, but I find it distracting to have on all the time. Here's a couple bindings you can add to quickly toggle between highlight and no higlight.
" Toggle on highlighting nnoremap <silent> <leader><CR> :set hls<CR> " Toggle off highlighting nnoremap <silent> <leader><Esc> :set nohlsearch<Bar>:echo<CR>
The first binding let's you turn on search highlighting by pressing "space enter" (depending on what you're leader key is). The second let's you turn it back off with "space esc."
It only makes sense that your tab key should switch between tabs. They have the same name after all. The tab key is popular in many Vim plugins, such as YouCompleteMe and Snipmate, but most plugins don't use the normal mode mapping, so add the following to make Tab and Shift-Tab cycle tabs forward and backward.
" Go to next tab nnoremap <Tab> gt " Go to previous tab nnoremap <S-Tab> gT
First, backspacing is not smart in vim to being with, so you should definitely add
to your vimrc to make it work more like you'd expect. An additional mapping I like to add is one that deletes the previous character while putting you into insert mode.
nnoremap <BS> i<BS>
It's important to map it this way, as opposed to some of the other possible ways, like
hs. That achieves the same thing, but also writes the character you delete to your default register, blowing away anything there, which I find annoying.
Remap annoying things
I use to hit F1 frequently when trying to exit insert mode, so I finally added these first two bindings to eliminate this problem. The third is just for consistency, since
D deletes to the end of the line and
C changes to the end of the line, but
Y by default yanks the whole line (which
yy also does).
map <F1> <Esc> imap <F1> <Esc> nnoremap Y y$
I guess I don't technically know that I use this binding every day. The whole point of it is that I don't know when I'm using it. But I definitely did hit F1 somewhat frequently before I added it.
Just like highlighting, text wrapping can be helpful sometimes (again, often in html) but is also annoying to leave on all the time. These bindings quickly toggle between wrapped and unwrapped text.
" Turn on wrapping nnoremap <leader>wr :set wrap<CR> " Turn off wrapping nnoremap <leader>nw :set nowrap<CR>
Note the mnemonic
wr for wrap and
nw for no wrap. On a side note, I also have this configuration in my vimrc
set showbreak=>>\ \ \ \
which makes it easier to see which lines are wrapped lines.
Always navigate linewise
By default, vim treats a line as a line, even if it wraps across multiple lines, but you can override that with the following bindings so that
k function more as you'd expect when wrapping is turned on.
nnoremap j gj nnoremap k gk vnoremap j gj vnoremap k gk
Toggle test exclusivity
These bindings are extremely specific and therefore might not help you, but I spend a lot of time writing jasmine (with jasmine-only) and mocha tests for node, so I frequently add
.only to a
context to run a test exclusively. This is tedious, so I wrote these little helpers to do it for me.
" Top-only: Add .only to top-most describe nnoremap <silent> <leader>to moG/describe<CR>ea.only<Esc>`o:delmarks o<CR> " Describe-only: Add .only to nearest describe nnoremap <silent> <leader>do mo/describe<CR><S-N>ea.only<Esc>`o:delmarks o<CR> " Context-only: Add .only to nearest context nnoremap <silent> <leader>co mo/context<CR><S-N>ea.only<Esc>`o:delmarks o<CR> " It-only: Add .only to nearest it nnoremap <silent> <leader>io mo/it '<CR><S-N>ea.only<Esc>`o:delmarks o<CR> " Remove-only: Remove all occurrences of .only nnoremap <silent> <leader>ro mo:%s/\.only//g<CR>`o:delmarks o<CR>
The mnemonics here are as follows:
- to = top only
- do = describe only
- co = context only
- io = it only
- ro = remove only
A sort of tl;dr explanation of what's happening is that we mark the current position, find the function (describe, context, etc.) to annotate, annotate it, then jump back to the mark we set.
Copy and paste
Copying and pasting from the system register is much easier on Linux than on Mac, but nonetheless, it feels more intuitive using these mapping.
vnoremap <leader>y "+y nnoremap <leader>p "+p
On Mac, it's similar:
vnoremap <leader>y "*y nnoremap <leader>p "*p
And on the topic of different commands for Linux vs. Mac, here's a little variable you can set to determine where you're running.
let g:osName = substitute(system('uname'), "\n", "", "")
You can then use this variable like this
if g:osName == 'Darwin' " Add some Mac specific bindings else " Add Linux specific bindings endif
I believe this is the part of the show where I am supposed to tell you how vim will change your life and how all other editors are inferior. But I'm not going to do that. I do believe it improves my productivity immensely, and it probably would for most people if they take the time to learn it, but many don't want to take that time and that's fine. Vim is not for everyone. But hopefully, if you're in the process of learning or you just have an interest in doing so, these bindings will help you become more productive quicker. Happy typing!