Workman layout for Vim

For those of us who REALLY need to type using three layouts.

Reading time: about 4 minutes (797 words).

I’ve recently switched keyboard layouts from Dvorak to Workman. Dvorak has been good to me over the past 5 years or so, but the philosophy behind it wasn’t actualised in it’s final design. Workman has been optimised for English and minimises finger strain etc etc. There’s no point rabbiting on about it as all of my praises or critiques are already well fleshed out on the Workman website.

It’s been two weeks or so since the switch and I’m at the proficiency stage where I’m not yelling at the awkwardness of my inability to find a letter, but if the switch from Qwerty to Dvorak is any indication it’ll be a couple of months until I’m completely up to speed.

I had a fantastic Vim map for Dvorak suggested by Adam Davis, which kept the Qwerty h,j,k,l navigation keys in the same place; remapping sane Dvorak keys with minimal disruption. So obviously something similar for Workman that didn’t disrupt Vim flow is needed.

Taking the laziest approach first; google tells me there are only two current suggestions. First, Matt Weolk has taken the complete remap Qwerty:Workman approach, which is outlined in this gist and takes the idea from colqer; a Colemak solution to the same issue. I really don’t like the blind approach this method uses as I remember Vim keybindings more on their associations (y = yank), than muscle memory of their original Qwerty locations. The second solution is a simple j ↔ t switch discussed in this thread. Closer to what I’m after, and I used it for a while; but ultimately the navigation keys being separated and not entirely on the home row doesn’t sit with me.

So, here’s my attempt at a decent Workman remapping for Vim:

    nnoremap l o
    nnoremap o l
    nnoremap L O
    nnoremap O L
    nnoremap j n
    nnoremap n j
    nnoremap J N
    nnoremap N J
    nnoremap gn gj
    nnoremap gj gn
    nnoremap k e
    nnoremap e k
    nnoremap K E
    nnoremap E <nop>
    nnoremap gk ge
    nnoremap ge gk
    nnoremap h y
    onoremap h y
    nnoremap y h
    nnoremap H Y
    nnoremap Y H

h,j,k,l are replaced by the Workman y,n,e,o home keys, with a few new associations:

  • (Y)ank -> (H)aul
  • Search (N)ext -> (J)ump
  • (E)nd word -> brea(K) of word [yeah, that one’s a push…]
  • (O)pen new line -> (L)ine

Considering I now use three different layouts depending on where I am, I’ve had to set up a layout remap function in my .vimrc. Here it is in it’s present state at the time of writing; check my dotfiles repository for updates though.

    " Keyboard  **************************
    function Keyboard(type)
       if a:type == "dvorak"
           call UnmapWorkman()
           nnoremap d h
           nnoremap h j
           nnoremap t k
           nnoremap n l
           nnoremap s :
           nnoremap S :
           nnoremap j d
           onoremap j d
           nnoremap l n
           nnoremap L N

           nnoremap - $
           nnoremap _ ^
           nnoremap N <C-w><C-w>
           nnoremap H 8<Down>
           nnoremap T 8<Up>
           nnoremap D <C-w><C-r>
       elseif a:type == "workman"
           call UnmapDvorak()
           "(O)pen line -> (L)ine
           nnoremap l o
           nnoremap o l
           nnoremap L O
           nnoremap O L
           "Search (N)ext -> (J)ump
           nnoremap j n
           nnoremap n j
           nnoremap J N
           nnoremap N J
           nnoremap gn gj
           nnoremap gj gn
           "(E)nd of word -> brea(K) of word
           nnoremap k e
           nnoremap e k
           nnoremap K E
           nnoremap E <nop>
           nnoremap gk ge
           nnoremap ge gk
           "(Y)ank -> (H)aul
           nnoremap h y
           onoremap h y
           nnoremap y h
           nnoremap H Y
           nnoremap Y H
       else " qwerty
           call UnmapDvorak()
           call UnmapWorkman()
       endif
    endfunction

    function UnmapDvorak()
        "Unmaps Dvorak keys
        silent! nunmap d
        silent! nunmap h
        silent! nunmap t
        silent! nunmap n
        silent! nunmap s
        silent! nunmap S
        silent! nunmap j
        silent! ounmap j
        silent! nunmap l
        silent! nunmap L

        silent! nunmap -
        silent! nunmap _
        silent! nunmap N
        silent! nunmap H
        silent! nunmap T
        silent! nunmap D
    endfunction

    function UnmapWorkman()
        "Unmaps Workman keys
        silent! nunmap h
        silent! ounmap h
        silent! nunmap j
        silent! nunmap k
        silent! nunmap l
        silent! nunmap y
        silent! nunmap n
        silent! nunmap e
        silent! nunmap o
        silent! nunmap H
        silent! nunmap J
        silent! nunmap K
        silent! nunmap L
        silent! nunmap Y
        silent! nunmap N
        silent! nunmap E
        silent! nunmap O
    endfunction

    function LoadKeyboard()
       let keys = $keyboard
       if (keys == "workman")
           call Keyboard("workman")
       else
           call Keyboard("dvorak")
       endif
    endfunction

    autocmd VimEnter * call LoadKeyboard()

    :noremap <Leader>q :call Keyboard("qwerty")<CR>:echom "Qwerty Keyboard Layout"<CR>
    :noremap <Leader>d :call Keyboard("dvorak")<CR>:echom "Dvorak Keyboard Layout"<CR>
    :noremap <Leader>w :call Keyboard("workman")<CR>:echom "Workman Keyboard Layout"<CR>