Handy Keymaps in Vim

May 27, 2019

In my first two posts in this Vim series, I talked about finding files in Vim and having a minimal Vim setup. In this post I’m going to go over some useful keymaps and functions you can use in Vim to boost your text editing abilities and to master the Vim wizardry. I will only cover keymaps that don’t include external plugins except for section #2 which will be about generating tags (I couldn’t leave this part without covering it).

Essentials

First and foremost, the leader key is a special key in Vim that with other combinations of keys can be mapped to perform certain functions. By default, Vim maps the leader to the backslash key. I see many Vimmers (yes, this is a word now) set it to the comma key. I, however, like to set it to the space bar; it’s a big key in the middle of the keyboard so it’s really easy to find it and use it with other key combinations:

"The Leader
let mapleader="\<Space>"

Now that we’ve mapped the leader key, we can start mapping other keys to functions.

The first function in our list will be the save or the write buffer function. Instead of using the shift and the semi-colon keys to generate a colon, typing w, and then hitting Enter to save the current buffer, I found out that hitting the space bar with the letter w is faster and easier to use specially for a function that is used many times in the course of writing. This is just two key presses instead of four:

"save current buffer
nnoremap <leader>w :w<cr>

The second function is for replacing the current-under-cursor word with another pattern/word. Simply, it copies the word under cursor and inserts it into a substitution command call. You only need to type the replacement pattern and press the Enter key to actually replace the text:

"replace the word under cursor
nnoremap <leader>* :%s/\<<c-r><c-w>\>//g<left><left>

Next is a function that is found in many modern text editors, that is, auto closing tags. Although sometimes it can get annoying when you don’t need it, it’s handy most of the time when writing function definitions, if statements, and other control structures in most popular languages. Each of the following keymaps simply inserts a closing tag and puts the cursor in between the opening and the closing tags:

"autoclose tags
inoremap ( ()<Left>
inoremap { {}<Left>
inoremap [ []<Left>
inoremap " ""<Left>

I feel like this section got really long so here’s one last function. To move a line up or down in Vim, normally you’d delete it and paste it into the desired target line. These keymaps make it possible to move lines up or down using the leader key + k or j (for up and down):

"move lines around
nnoremap <leader>k :m-2<cr>==
nnoremap <leader>j :m+<cr>==
xnoremap <leader>k :m-2<cr>gv=gv
xnoremap <leader>j :m'>+<cr>gv=gv

Generating Tags

As I mentioned before, this is the only section that includes an external dependency. Universal Ctags is a tool that analyzes the codebase and generates an index file of tags. This index of tags can be used to jump between the definitions of functions, classes, and other identifiers while navigating the code. You can jump to a tag definition using the :tag IDENTIFIER command in Vim.

Since I’m trying not to switch context and leave the text editor as much as possible, I made a keymap that generates the list of tags for me without leaving Vim. The next block of code tells Vim where to look for tag definitions by setting the set tags entry and maps leader + ct to generate the tag list:

set tags+=.git/tags
nnoremap <leader>ct :!ctags -Rf .git/tags --tag-relative --extra=+f --exclude=.git,pkg --languages=-sql<cr><cr>

You can also simplify the command above by moving the flags to a ~/.ctags file (each flag alone on a single line) and only having this in your .vimrc:

nnoremap <leader>ct :!ctags -Rf .git/tags<cr><cr>

Manipulating Buffers

Vim has this notion of buffers. Simply put, a buffer is an open file. A window in Vim is a way to view an open buffer. A tab, on the other hand, is a collection of windows. To save you (and myself) the pain, use buffers and treat them the way you treat tabs in other text editors. You can read more about buffers versus tabs and the best way to use them here.

Anyway, I have a few keymaps that make it easier to manipulate and deal with buffers. For example, to open and close buffers, I have in my .vimrc this block of code:

"create a new buffer (save it with :w ./path/to/FILENAME)
nnoremap <leader>B :enew<cr>
"close current buffer
nnoremap <leader>bq :bp <bar> bd! #<cr>
"close all open buffers
nnoremap <leader>ba :bufdo bd!<cr>

The following is for switching between open buffers:

"Tab to switch to next open buffer
nnoremap <Tab> :bnext<cr>
"Shift + Tab to switch to previous open buffer
nnoremap <S-Tab> :bprevious<cr>
"leader key twice to cycle between last two open buffers
nnoremap <leader><leader> <c-^>

You can install vim-buftabline to visualize your open buffers and see how they are being switched by the keymaps above.

Splits, Splits, Splits!

Window splits are such an important element of my text editing since sometimes I need to keep track on multiple files at the same time. Vim provides some shortcuts for creating and moving around splits, however; they can be a little unintuitive for quick navigation between splits.

To fix this, I have had a small function in my Vim configuration for a long time that makes my life a lot easier. The function is mapped to a set of intuitive combination of keys, namely, the control key + any of the navigation keys (h, j, k, l).

What the function does is that it checks first if a split already exists in the direction you want to move to. If it does, the function simply moves the focus to that split. If there isn’t a split already, the function creates a new split and moves the focus to that split. This function I took from someone some long time ago. I can’t recall where I got it from, but all the credit is due to the original author.

"move to the split in the direction shown, or create a new split
nnoremap <silent> <C-h> :call WinMove('h')<cr>
nnoremap <silent> <C-j> :call WinMove('j')<cr>
nnoremap <silent> <C-k> :call WinMove('k')<cr>
nnoremap <silent> <C-l> :call WinMove('l')<cr>

function! WinMove(key)
  let t:curwin = winnr()
  exec "wincmd ".a:key
  if (t:curwin == winnr())
    if (match(a:key,'[jk]'))
      wincmd v
    else
      wincmd s
    endif
    exec "wincmd ".a:key
  endif
endfunction

Vim is a powerful text editor with great capabilities. You can map multiple keys to perform different functionalities in Vim that makes your text editing easier.

All the code in this post is taken from my .vimrc file in my dotfiles repository on GitHub. You can check it out here.