Create a gist now

Instantly share code, notes, and snippets.

" Main novelty here (if it is one): this does NOT try to be helpful by
" inserting the closing delimiter for you when you type an opening one.
" Instead it only tries to be smart about what to do when you type a closing
" delimiter yourself.
" If you just typed an empty delimiter pair, it'll move the cursor back
" inside. If you type a closing delimiter the cursor is already on (or to
" the left of, if the cursor is on a space), it'll skip the cursor past that
" delimiter without inserting it.
" That way you never end with superfluous delimiters to delete, which deletion
" itself can be tricky to perform, since the editor might be trying to be
" helpful about deletions as well. Instead, you only ever get delimiters you
" explicitly typed yourself.
" I had trained myself into the good habit of typing pairs together anyway.
" The only annoying part of that habit is the manual cursor placement work;
" but that work is quite predictable almost all of the time. That's exactly
" the sort of work that computers are for.
function! IsEmptyPair(str)
for pair in split( &matchpairs, ',' ) + [ "''", '""', '``' ]
if a:str == join( split( pair, ':' ),'' )
return 1
return 0
function! WithinEmptyPair()
let cur = strpart( getline('.'), col('.')-2, 2 )
return IsEmptyPair( cur )
function! SkipDelim(char)
let cur = strpart( getline('.'), col('.')-2, 3 )
if cur[0] == "\\"
return a:char
elseif cur[1] == a:char
return "\<Right>"
elseif cur[1] == ' ' && cur[2] == a:char
return "\<Right>\<Right>"
elseif IsEmptyPair( cur[0] . a:char )
return a:char . "\<Left>"
return a:char
inoremap <expr> ) SkipDelim(')')
inoremap <expr> ] SkipDelim(']')
inoremap <expr> } SkipDelim('}')
inoremap <expr> ' SkipDelim("'")
inoremap <expr> " SkipDelim('"')
inoremap <expr> ` SkipDelim('`')
inoremap <expr> <BS> WithinEmptyPair() ? "\<Right>\<BS>\<BS>" : "\<BS>"
inoremap <expr> <CR> WithinEmptyPair() ? "\<CR>\<CR>\<Up>" : "\<CR>"
inoremap <expr> <Space> WithinEmptyPair() ? "\<Space>\<Space>\<Left>" : "\<Space>"
vmap q( s()<C-R>"<Esc>
vmap q) s()<C-R>"<Esc>
vmap q[ s[]<C-R>"<Esc>
vmap q] s[]<C-R>"<Esc>
vmap q{ s{}<C-R>"<Esc>
vmap q} s{}<C-R>"<Esc>
vmap q' s''<C-R>"<Esc>
vmap q" s""<C-R>"<Esc>
vmap q` s``<C-R>"<Esc>
aghast commented Jan 8, 2014

In my particular version of Vim (VIM - Vi IMproved 7.3 (2010 Aug 15, compiled Aug 24 2013 18:58:47)
the vmap commands do not work as I think you intend them to work. I get ()foo instead of (foo). Changing the mapping to s(") works fine, though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment