My .vimrc (Colemak Edition)

A vimrc for Colemak users, explained.

Warning: Boring story stuff. You can skip it for the .vimrc.

Here's the deal. Vim is my favorite editor. It was the first code editor that I learned in college. I have no idea why the University of Missouri introduces their freshman Computer Science students to one of the most confusing code editors, but I am really glad they do.

In the Summer after freshman year, I took an internship with a company in Saint Louis (Asynchrony) where I met an amazing developer, and my best friend to this day. He introduced me to the Colemak keyboard layout. I became so intrigued that I decided to learn it during the following Winter Break.

During the learning process, it became almost impossible to write code or do anything typing-heavy on a computer. I was dedicated, so I didn't allow myself to type in Qwerty. After typing almost daily in typeracer (highly recommend it) for about a month, I was up to like 30-40 WPM. It's not great (for a developer), but I finally felt competent enough to start writing code again.

Uh oh.

Vim didn't work the same as before. See, I had previously remapped the arrow keys to do nothing in Insert mode, so that I would be forced to use h, j, k, and l for navigation. With Colemak, this wasn't going to work anymore.

At first I panicked, but I eventually found a reasonable looking key remapping for Colemak deep in some forum post on the second page Google (it was probably on the first page, but let's pretend). I implemented those key bindings, struggled for a couple days, and eventually all was back to normal.

Now, I have kept those remappings for about four years and made modifications along the way. The front page of "vim colemak" on Google is quite a bit more vibrant now than it was in 2013, but I would like to share regardless.

So let's get started. I will first paste the entire .vimrc at once, and then go into details line-by-line.

The .vimrc

" Vundle
set nocompatible
filetype off
set rtp+=~/.vim/bundle/Vundle.vim
call vundle#begin()

Plugin 'VundleVim/Vundle.vim'
Plugin 'mattn/emmet-vim'
Plugin 'godlygeek/tabular'
Plugin 'Chiel92/vim-autoformat'
Plugin 'altercation/vim-colors-solarized'
Plugin 'pangloss/vim-javascript'
Plugin 'mxw/vim-jsx'
Plugin 'kchmck/vim-coffee-script'
Plugin 'tpope/vim-sleuth'

call vundle#end()
filetype plugin indent on
" End Vundle

" Remap movement for Colemak
noremap n j
noremap e k
noremap i l
noremap k n
noremap s i
noremap j e

" Remap splits for Colemak / Ease of Use
noremap <C-H> <C-W><C-H>
noremap <C-N> <C-W><C-J>
noremap <C-E> <C-W><C-K>
noremap <C-I> <C-W><C-L>

" Remap l as end of 'line' key
nnoremap l $
nnoremap <C-l> J

" Destroy arrow keys in insert mode
inoremap <Up> <Nop>
inoremap <Down> <Nop>
inoremap <Left> <Nop>
inoremap <Right> <Nop>

" Make arrow keys useful
noremap <Up> ddkP
noremap <Down> ddp
noremap <Left> <<
noremap <Right> >>
vmap <Left> <gv
vmap <Right> >gv

" Brace completion
inoremap {<CR> {<CR>}<Esc>ko

" Paren + Brace completion
inoremap ({<CR> ({<CR>});<Esc>ko

" Make backspace work
set backspace=2

" Indent if already indented
set autoindent

" auto indent on these words
set smartindent cinwords=if,elif,else,for,while,try,except,finally,def,class

" Wrapping and tabs.
set tw=160 ts=4 sw=4 sta et sts=4

" Highlight end of line whitespace.
highlight WhitespaceEOL ctermbg=240 guibg=red
match WhitespaceEOL /\s\+$/

" Line numbers
set number

set visualbell
set t_vb=

" Keep 5 line padding on cursor
set scrolloff=5

" keyword highlighting
syntax on

" Color column at 81
set colorcolumn=81

" set color scheme to solarized
let g:solarized_termcolors=256
set t_Co=256
set background=dark
colorscheme solarized

" to keep whitespace highlighting on recognized file types
au FileType * highlight WhitespaceEOL ctermbg=240 guibg=red

" md means markdown
autocmd BufNewFile,BufReadPost *.md set filetype=markdown

" JSX highlighting
let g:jsx_ext_required=0

" Panes should split to the right, or to the bottom
set splitbelow
set splitright

Colemak-Specific Remaps

Let's skip over the plug-in configuration (more on that later) and start with the lines that deal with Colemak.

21 " Remap movement for Colemak
22 noremap n j
23 noremap e k
24 noremap i l
25 noremap k n
26 noremap s i
27 noremap j e

Lines 22-25 are mapping the standard Qwerty movement keys (jkl) to the appropriate Colemak keys (nei). Notice that 'h' is missing because it is the same location on the keyboard for both layouts. The problem after this remapping is that they key for insert mode (i), repeat search (n), and movement to end-of-word (e) have all been remapped.

Insert mode was placed on the s key (which is originally the "subsitute" command, that I never used). Repeat search was placed on k, which is conveniently the exact same location as n on Qwerty and was now unused, because it used to be a movement key. Lastly, end-of-word was placed on j, which was also a movement key.

The Rest

Now, onto my own personal choices for vim.

29 " Remap splits for Colemak / Ease of Use
30 noremap <C-H> <C-W><C-H>
31 noremap <C-N> <C-W><C-J>
32 noremap <C-E> <C-W><C-K>
33 noremap <C-I> <C-W><C-L> 

I only recently added this section to my .vimrc. I don't use Tmux, instead choosing to split the vim window. I almost always have multiple panes open in vim. These bindings help move around using a single keystroke, and in the direction you want to move (I used to cycle through 3+ panes by hitting Ctrl+W over and over. Painful!).

If you didn't already know, pressing Ctrl+W, and then Ctrl+<Direction-Key> allowed you to jump panes, smartly, in the direction you want to go. These remaps make it happen in one keystroke, and are specific to Colemak (except with h, of course).

35 " Remap l as end of 'line' key
36 nnoremap l $
37 nnoremap <C-l> J  

Since l has been freed up, why not use it? This makes l jump to the end of line, and Ctrl+L collapse the following line onto the current line.

39 " Destroy arrow keys in insert mode
40 inoremap <Up> <Nop>
41 inoremap <Down> <Nop>
42 inoremap <Left> <Nop>
43 inoremap <Right> <Nop>
45 " Make arrow keys useful
46 noremap <Up> ddkP
47 noremap <Down> ddp
48 noremap <Left> <<
49 noremap <Right> >>
50 vmap <Left> <gv
51 vmap <Right> >gv  

This is the same configuration I first used when deciding to learn to use the home row for navigation. Lines 40-43 simply make the arrow keys completely unusable while in Insert mode.

Line 46 means that the Up key takes your current line, and moves it up one line (swapping places with the line above it). Line 47 does the opposite, for the Down key.

Line 48 maps the Left key to un-indent your current line, while line 49 serves to make the Right key add one level of indentation. Lines 50 and 51 do the same thing, except for Visual mode.

 53 " Brace completion
 54 inoremap {<CR> {<CR>}<Esc>ko
 56 " Paren + Brace completion
 57 inoremap ({<CR> ({<CR>});<Esc>ko 

These are pretty amazing if you frequently edit JavaScript. Line 54 makes it so that ending a line with a brace will put an ending brace on the next line, move up a line and then create a new line afterwards — meaning that you start indented, inside your new block, in Insert mode.

Line 57 is the same, except that it checks for a new line after a left parenthesis and a brace.


59 " Make backspace work
60 set backspace=2 

This overrides vim default behavior of not backspacing over auto-indent, new lines, or the location where insert mode started.

62 " Indent if already indented
63 set autoindent
65 " auto indent on these words
66 set smartindent cinwords=if,elif,else,for,while,try,except,finally,def,class     
68 " Wrapping and tabs.
69 set tw=160 ts=4 sw=4 sta et sts=4

Line 63 tells vim to turn on autoindent and line 66 adds some extra keywords for languages that don't use braces (like Python, Ruby).

Onto line 69. tw stands for text-width. This limits my typing to 160 characters per line. ts is tabstop, sw is shiftwidth, sta is smarttab, et is expandtab, and sts is softtabstop. All of this configuration is so that when I hit tab it insert four spaces (by default). To be honest, with the Vim Sleuth plugin, I am not sure how much this line matters anymore.

71 " Highlight end of line whitespace.
72 highlight WhitespaceEOL ctermbg=240 guibg=red
73 match WhitespaceEOL /\s\+$/   

Here, line 72 highlights trailing whitespaces (so that I can delete them) and line 73 indicates that a trailing whitespace is any amount of whitespaces immediately before End-of-Line.

(Note: I am surprised these lines work in this order, but it is how they have always been).

75 " Line numbers
76 set number

Well, I like seeing line numbers.

79 set visualbell
80 set t_vb= 

Vim outputs a bell sound basically whenever you try an action that isn't allowed. It gets annoying pretty quick.

82 " Keep 5 line padding on cursor
83 set scrolloff=5

This is one of my favorite lines in my vim file and one of the first I ever added. This sets a five-line boundary between your cursor and the edge of the screen at all time, so you never have to work with your cursor at the edge.

85 " keyword highlighting
86 syntax on

Enables syntax highlighting.

88 " Color column at 81
89 set colorcolumn=81 

Another one of my favorite lines. This adds a highlighted column to vim where the 81st character in a line would fall. This lets me see when my lines are getting too long.

91 " set color scheme to solarized
92 let g:solarized_termcolors=256
93 set t_Co=256
94 set background=dark
95 colorscheme solarized  

This allows me to use the dark Solarized theme. The theme itself is a plugin.

 97 " to keep whitespace highlighting on recognized file types
 98 au FileType * highlight WhitespaceEOL ctermbg=240 guibg=red 

Yes vim, I still want you to highlight trailing whitespaces, even on recognized file types.

100 " md means markdown
101 autocmd BufNewFile,BufReadPost *.md set filetype=markdown     

Vim does not recognize .md as a markdown file by default. This sets the correct syntax highlighting for .md files (Markdown).

103 " JSX highlighting
104 let g:jsx_ext_required=0

This allows JSX highlighting inside of regular .js files (useful for React).

106 " Panes should split to the right, or to the bottom
107 set splitbelow
108 set splitright         

The last lines of my .vimrc. Also, the most recently added. Whenever you create a new split pane in Vim (:vsp or :sp), it will create horizontal panes on the left, and vertical panes on the top. With these settings, new panes go on the right and on the bottom, which feels much more natural for me.

Plugin Manager

I choose to use Vundle as my plugin manager, because it is much easier than the only other one I have used: Pathogen. With Vundle, I just add a line to the .vimrc and then run :PluginInstall. Here's my configuration:

  1 " Vundle
  2 set nocompatible
  3 filetype off
  4 set rtp+=~/.vim/bundle/Vundle.vim
  5 call vundle#begin()
  7 Plugin 'VundleVim/Vundle.vim'
  8 Plugin 'mattn/emmet-vim'
  9 Plugin 'godlygeek/tabular'
 10 Plugin 'Chiel92/vim-autoformat'
 11 Plugin 'altercation/vim-colors-solarized'
 12 Plugin 'pangloss/vim-javascript'
 13 Plugin 'mxw/vim-jsx'
 14 Plugin 'kchmck/vim-coffee-script'
 15 Plugin 'tpope/vim-sleuth'
 17 call vundle#end()
 18 filetype plugin indent on
 19 " End Vundle           

If you aren't familiar with one of these plugins, I encourage you to look it up. I'll touch on two of them: Tabular and Sleuth.

Tabular allows you to align multiple lines of code visually, like assignment statements, using a regular expression. I don't use this much anymore, but I used it heavily when I was writing a lot of Haskell.


Sleuth is auto-tab-width for Vim. It reads the file and determines the correct tab width. This means that if you are normally a two-space kind of person, but your team uses four, you won't have to reconfigure vim every time you switch between projects. You just open the file and hitting tab will be insert the right character or characters.


I used to have a lot of difficulties during ssh sessions while I was setting up a remote web server. I would inevitably have to edit a configuration file, and all my muscle memory was completely useless.

I just kind of dealt with this for awhile because pulling my dotfiles was always too much of a hassle... until I learned about vcsh.

Vcsh is git-managed dotfiles. There are dozens of similar apps that do this, but vcsh is so simple and it comes as a package in many modern UNIX systems. This is how I install my vim configuration now:

sudo apt-get install vcsh
vcsh clone vim
vcsh vim submodule update --init

Done. My vimrc is setup and Vundle is installed. If I open vim and run :PluginInstall, I'm ready to go.