Vim Tips Wiki
Advertisement
Tip 630 Printable Monobook Previous Next

created January 2, 2004 · complexity basic · author Andrzej Cuber · version 6.0


A simple solution

When you type an open brace, this will automatically insert a closing brace on the same line, after the cursor. If you quickly hit Enter after the open brace, (to begin a code block), the closing brace will be inserted on the line below the cursor. If you quickly press the open brace key again after the open brace, Vim won't insert anything extra, you'll just get a single open brace. Finally, if you quickly type an open and close brace, Vim will not do anything special.

inoremap {      {}<Left>
inoremap {<CR>  {<CR>}<Esc>O
inoremap {{     {
inoremap {}     {}

Similar mappings for other "paired" characters can be made from the above with trivial modifications, but characters like brackets and parentheses which often require text after them might instead benefit from something like the following, which automatically closes all groups, and "overwrites" existing closing characters if another one is typed immediately before:

inoremap (     ()<Left>
inoremap )     )<Esc>
               \y2l
               \:if '))'=="<C-R>=escape(@0,'"\')<CR>"<BAR>
               \  exec 'normal x'<BAR>
               \endif<CR>
               \a

This solution is fairly straightforward, and is keep simple for clarity. As-is, it will unfortunately clobber some of your registers. See Improved Bracket-Matching for a solution.

For adding multi-byte pairs such as C-style comments, you may want to find another way to prevent the mapping from taking effect, such as typing the mapleader (usually '\' – see :help mapleader) character first as below:

inoremap /*          /**/<Left><Left>
inoremap /*<Space>   /*<Space><Space>*/<Left><Left><Left>
inoremap /*<CR>      /*<CR>*/<Esc>O
inoremap <Leader>/*  /*

Similar mappings might be useful for quotes, but they might get in your way depending on the type of file you're editing. Some languages use duplicate single-quotes a lot, and some pair the backtick with the quote. For these situations, you might want to put similar commands into language-specific files. For example, this quote-completer for GNU M4 might live in ~/.vim/after/ftplugin/m4.vim. :help after-directory

inoremap `      `')<Left><Left>
inoremap `<CR>  `<CR>'<Esc>O
inoremap ``     `
inoremap `'     `'

More advanced solutions

If you want something more complex and configurable, there are a number of different scripts that accomplish this task.

Library plugins

Luc Hermitte has some very advanced and smart ftplugins for editing C & C++ files . Those scripts give advanced brace-handling features like markers support (placeholders in another terminology), several things can be easily tweaked (whether we want newlines or not before the curly-brackets, ...), the abbreviations are buffer-relative (which is necessary to have "for" expand into different things according to the filetype of the buffer edited), context-sensitive (the abbreviations are not expanded within comments or string contexts) and more.

See also the core bracketing system and the C&C++ ftplugin suite built on top of it.

Srinath Avadhanula's imaps.vim is used by Latex-Suite to provide a similar bracketing system.

ReplaceCurly script

This script operates only on braces, but is smarter about detecting when it should act. It will not take effect when editing comments, strings and lines containing the the word "new." (This is useful for array initialization, e.g. string[] myArray = new string[] {"a", "b"}.)

imap { <Esc>:call ReplaceCurly()<CR>"_cl
function! ReplaceCurly()
  imap { {
  " only replace outside of comments or strings (which map to constant)
  let elesyn = synIDtrans(synID(line("."), col(".") - 1, 0))
  if elesyn != hlID('Comment') && elesyn != hlID('Constant') && match(getline("."), "\\<new\\>") < 0
    exe "normal a{"
    " need to add a spare character (x) to position the cursor afterwards
    exe "normal ox"
    exe "normal o}"
    exe "normal kw"
  else
    " need to add a spare character (x) to position the cursor afterwards
    exe "normal a{x"
  endif
  imap { <Esc>:let word= ReplaceCurly()<CR>"_cl
endfunction

"Surround code with braces
nmap <Leader>{} O{<Esc>ddj>>ddkP
vmap <Leader>{} <Esc>o{<Esc>ddgv>gvdp

Improved Bracket-Matching

The code for matching all brackets and allowing a typed closing bracket to overwrite an existing bracket has the problem of overwriting your unnamed and yank registers (@" and @0). It also echos a substantial about of code to the command line. The code is kept as-is in A simple solution for clarity, but these problems can be solved by storing these registers in temporary variables, use of the "black hole" register, and adding a <silent> as follows:

inoremap          (   ()<LEFT>
inoremap <silent> )   )<Esc>
                      \:let tmp0=&clipboard <BAR>
                      \let &clipboard=''<BAR>
                      \let tmp1=@"<BAR>
                      \let tmp2=@0<CR>
                      \y2l
                      \:if '))'=="<C-R>=escape(@0,'"\')<CR>"<BAR>
                      \  exec 'normal "_x'<BAR>
                      \endif<BAR>
                      \let @"=tmp1<BAR>
                      \let @0=tmp2<BAR>
                      \let &clipboard=tmp0<BAR>
                      \unlet tmp0<BAR>
                      \unlet tmp1<BAR>
                      \unlet tmp2<CR>
                      \a

The "clipboard" option is also manipulated just in case the user has "unnamed" in their clipboard option.

References:

Comments

Advertisement