" Insert or delete brackets, parens, quotes in pairs. " Maintainer: JiangMiao " Contributor: camthompson " Last Change: 2012-05-14 " Version: 1.2.0 " Homepage: http://www.vim.org/scripts/script.php?script_id=3599 " Repository: https://github.com/jiangmiao/auto-pairs if exists('g:AutoPairsLoaded') || &cp finish end let g:AutoPairsLoaded = 1 if !exists('g:AutoPairs') let g:AutoPairs = {'(':')', '[':']', '{':'}',"'":"'",'"':'"', '`':'`'} end if !exists('g:AutoPairsParens') let g:AutoPairsParens = {'(':')', '[':']', '{':'}'} end let g:AutoExtraPairs = copy(g:AutoPairs) let g:AutoExtraPairs['<'] = '>' if !exists('g:AutoPairsMapBS') let g:AutoPairsMapBS = 1 end if !exists('g:AutoPairsMapCR') let g:AutoPairsMapCR = 1 end if !exists('g:AutoPairsMapSpace') let g:AutoPairsMapSpace = 1 end if !exists('g:AutoPairsCenterLine') let g:AutoPairsCenterLine = 1 end if !exists('g:AutoPairsShortcutToggle') let g:AutoPairsShortcutToggle = '' end if !exists('g:AutoPairsShortcutFastWrap') let g:AutoPairsShortcutFastWrap = '' end if !exists('g:AutoPairsShortcutJump') let g:AutoPairsShortcutJump = '' endif " Fly mode will for closed pair to jump to closed pair instead of insert. " also support AutoPairsBackInsert to insert pairs where jumped. if !exists('g:AutoPairsFlyMode') let g:AutoPairsFlyMode = 1 endif " Work with Fly Mode, insert pair where jumped if !exists('g:AutoPairsShortcutBackInsert') let g:AutoPairsShortcutBackInsert = '' endif " Will auto generated {']' => '[', ..., '}' => '{'}in initialize. let g:AutoPairsClosedPairs = {} function! AutoPairsInsert(key) if !b:autopairs_enabled return a:key end let line = getline('.') let prev_char = line[col('.')-2] let current_char = line[col('.')-1] let next_char = line[col('.')] let eol = 0 if col('$') - col('.') <= 1 let eol = 1 end " Ignore auto close if prev character is \ if prev_char == '\' return a:key end " The key is difference open-pair, then it means only for ) ] } by default if !has_key(g:AutoPairs, a:key) " Skip the character if next character is space if current_char == ' ' && next_char == a:key return "\\" end " Skip the character if closed pair is next character if current_char == '' let next_lineno = line('.')+1 let next_line = getline(nextnonblank(next_lineno)) let next_char = matchstr(next_line, '\s*\zs.') if next_char == a:key return "\e^a" endif endif " Skip the character if current character is the same as input if current_char == a:key return "\" end " Fly Mode, and the key is closed-pairs, search closed-pair and jump if g:AutoPairsFlyMode && has_key(g:AutoPairsClosedPairs, a:key) if search(a:key, 'W') return "\" endif endif " Input directly if the key is not an open key return a:key end let open = a:key let close = g:AutoPairs[open] if current_char == close && open == close return "\" end " Ignore auto close ' if follows a word " MUST after closed check. 'hello|' if a:key == "'" && prev_char =~ '\v\w' return a:key end " support for ''' ``` and """ if open == close " The key must be ' " ` let pprev_char = line[col('.')-3] if pprev_char == open && prev_char == open " Double pair found return a:key end end return open.close."\" endfunction function! AutoPairsDelete() let line = getline('.') let current_char = line[col('.')-1] let prev_char = line[col('.')-2] let pprev_char = line[col('.')-3] if pprev_char == '\' return "\" end " Delete last two spaces in parens, work with MapSpace if has_key(g:AutoPairs, pprev_char) && prev_char == ' ' && current_char == ' ' return "\\" endif if has_key(g:AutoPairs, prev_char) let close = g:AutoPairs[prev_char] if match(line,'^\s*'.close, col('.')-1) != -1 let space = matchstr(line, '^\s*', col('.')-1) return "\". repeat("\", len(space)+1) else let nline = getline(line('.')+1) if nline =~ '^\s*'.close let space = matchstr(nline, '^\s*') return "\\". repeat("\", len(space)+1) end end end return "\" endfunction function! AutoPairsJump() call search('["\]'')}]','W') endfunction " Fast wrap the word in brackets function! AutoPairsFastWrap() let line = getline('.') let current_char = line[col('.')-1] let next_char = line[col('.')] " Ignore EOL if col('.') == col('$') return '' end normal! x if next_char =~ '\s' call search('\S', 'W') let next_char = getline('.')[col('.')-1] end if has_key(g:AutoExtraPairs, next_char) let close = g:AutoExtraPairs[next_char] call search(close, 'W') return "\".current_char."\" else if next_char =~ '\w' execute "normal! he" end execute "normal! a".current_char return "" end endfunction function! AutoPairsMap(key) let escaped_key = substitute(a:key, "'", "''", 'g') execute 'inoremap '.a:key." AutoPairsInsert('".escaped_key."')" endfunction function! AutoPairsToggle() if b:autopairs_enabled let b:autopairs_enabled = 0 echo 'AutoPairs Disabled.' else let b:autopairs_enabled = 1 echo 'AutoPairs Enabled.' end return '' endfunction function! AutoPairsReturn() let line = getline('.') let pline = getline(line('.')-1) let prev_char = pline[strlen(pline)-1] let cmd = '' let cur_char = line[col('.')-1] if has_key(g:AutoPairs, prev_char) && g:AutoPairs[prev_char] == cur_char if g:AutoPairsCenterLine && winline() * 1.5 >= winheight(0) let cmd = " \zz\cl" end " conflict with javascript and coffee " javascript need indent new line " coffeescript forbid indent new line if &filetype == 'coffeescript' || &filetype == 'coffee' return "\k==o".cmd else return "\=ko".cmd endif end return '' endfunction function! AutoPairsSpace() let line = getline('.') let prev_char = line[col('.')-2] let cmd = '' let cur_char =line[col('.')-1] if has_key(g:AutoPairsParens, prev_char) && g:AutoPairsParens[prev_char] == cur_char let cmd = "\\" endif return "\".cmd endfunction function! AutoPairsBackInsert() if exists('b:autopairs_saved_pair') let pair = b:autopairs_saved_pair[0] let pos = b:autopairs_saved_pair[1] call setpos('.', pos) return pair endif return '' endfunction function! AutoPairsInit() let b:autopairs_loaded = 1 let b:autopairs_enabled = 1 " buffer level map pairs keys for [open, close] in items(g:AutoPairs) call AutoPairsMap(open) if open != close call AutoPairsMap(close) end let g:AutoPairsClosedPairs[close] = open endfor " Still use level mapping for if g:AutoPairsMapBS execute 'inoremap AutoPairsDelete()' end if g:AutoPairsMapSpace execute 'inoremap AutoPairsSpace()' end if g:AutoPairsShortcutFastWrap != '' execute 'inoremap '.g:AutoPairsShortcutFastWrap.' =AutoPairsFastWrap()' end if g:AutoPairsShortcutBackInsert != '' execute 'inoremap '.g:AutoPairsShortcutBackInsert.' =AutoPairsBackInsert()' end if g:AutoPairsShortcutToggle != '' " use to ensure showing the status when toggle execute 'inoremap '.g:AutoPairsShortcutToggle.' AutoPairsToggle()' execute 'noremap '.g:AutoPairsShortcutToggle.' :call AutoPairsToggle()' end if g:AutoPairsShortcutJump != '' execute 'inoremap ' . g:AutoPairsShortcutJump. ' :call AutoPairsJump()a' execute 'noremap ' . g:AutoPairsShortcutJump. ' :call AutoPairsJump()' end endfunction function! s:ExpandMap(map) let map = a:map if map =~ '' let map = substitute(map, '\(\w\+\)', '\=maparg(submatch(1), "i")', 'g') endif return map endfunction function! AutoPairsForceInit() if exists('b:autopairs_loaded') return end " for auto-pairs starts with 'a', so the priority is higher than supertab and vim-endwise " " vim-endwise doesn't support AutoPairsReturn " when use AutoPairsReturn will cause isn't expanded " " supertab doesn't support AutoPairsReturn " when use AutoPairsReturn will cause Duplicated " " and when load after vim-endwise will cause unexpected endwise inserted. " so always load AutoPairs at last " Buffer level keys mapping " comptible with other plugin if g:AutoPairsMapCR let old_cr = maparg('', 'i') if old_cr == '' let old_cr = '' else let old_cr = s:ExpandMap(old_cr) endif if old_cr !~ 'AutoPairsReturn' execute 'imap '.old_cr.'AutoPairsReturn' end endif call AutoPairsInit() endfunction " Always silent the command inoremap AutoPairsReturn =AutoPairsReturn() imap