diff --git a/autoload/delimitMate.vim b/autoload/delimitMate.vim index fc7513e..29d1ceb 100644 --- a/autoload/delimitMate.vim +++ b/autoload/delimitMate.vim @@ -1,57 +1,67 @@ " Script variables {{{1 let s:defaults = {} -let s:defaults.delimitMate_enabled = 1 -let s:defaults.delimitMate_pairs = ['()', '[]', '{}'] -let s:defaults.delimitMate_quotes = ['"', "'", '`'] -let s:defaults.delimitMate_debug = 4 -let s:defaults.delimitMate_autoclose = 1 -let s:defaults.delimitMate_expand_space = 0 -let s:defaults.delimitMate_expand_cr = 0 -let s:defaults.delimitMate_jump_expansion = 0 -let s:defaults.delimitMate_jump_over = 1 -let s:defaults.delimitMate_insert_eol_marker = 0 -let s:defaults.delimitMate_eol_marker = ';' -let s:defaults.delimitMate_expand_inside_quotes = 0 -let s:defaults.delimitMate_smart_pairs = 1 -let s:defaults.delimitMate_smart_pairs_extra = [] -let s:defaults.delimitMate_balance_pairs = 0 -let s:defaults.delimitMate_nesting_quotes = [] -let s:defaults.delimitMate_smart_quotes = 1 -let s:defaults.delimitMate_smart_quotes_extra = [] -let s:defaults.delimitMate_excluded_regions = ['String', 'Comment'] +let s:defaults.enabled = 1 +let s:defaults.pairs = ['()', '[]', '{}'] +let s:defaults.quotes = ['"', "'", '`'] +let s:defaults.debug = 0 +let s:defaults.autoclose = 1 +let s:defaults.expand_space = 0 +let s:defaults.expand_cr = 0 +let s:defaults.jump_expansion = 0 +let s:defaults.jump_over = 1 +let s:defaults.insert_eol_marker = 0 +let s:defaults.eol_marker = ';' +let s:defaults.expand_inside_quotes = 0 +let s:defaults.smart_pairs = 1 +let s:defaults.smart_pairs_extra = [] +let s:defaults.balance_pairs = 0 +let s:defaults.nesting_quotes = [] +let s:defaults.smart_quotes = 1 +let s:defaults.smart_quotes_extra = [] +let s:defaults.excluded_regions = [] " Set smart_pairs expressions: let s:exprs = [] call add(s:exprs, 'next_char =~# "\\w"') call add(s:exprs, 'next_char =~# "[".escape(v:char,"\\^]")."€£$]"') -call add(s:exprs, 'next_char =~# "[".escape(join(s:option("quotes"),""),"\\^]")."]"') +call add(s:exprs, + \'next_char =~# "[".escape(join(s:option("quotes"),""),"\\^]")."]"') call add(s:exprs, 'ahead =~# "^[^[:space:][:punct:]]"') -let s:defaults.delimitMate_smart_pairs_base = s:exprs +let s:defaults.smart_pairs_base = s:exprs " Set smart_quotes expressions: let s:exprs = [] call add(s:exprs, 'prev_char =~# "\\w"') -call add(s:exprs, 'prev_char =~# "[^[:space:][:punct:]".escape(join(options.quotes, ""), "\\^[]")."]"') +call add(s:exprs, 'prev_char =~# "[^[:space:][:punct:]" + \.escape(join(options.quotes, ""), "\\^[]")."]"') call add(s:exprs, 'next_char =~# "\\w"') -call add(s:exprs, 'char == "\"" && &filetype =~? "\\" && line =~ "^\\s*$"') -call add(s:exprs, 'next_char =~# "[^[:space:][:punct:]".escape(join(options.quotes, ""), "\\^[]")."]"') +call add(s:exprs, 'char == "\"" && &filetype =~? "\\" + \&& line =~ "^\\s*$"') +call add(s:exprs, 'next_char =~# "[^[:space:][:punct:]" + \. escape(join(options.quotes, ""), "\\^[]")."]"') " Balance quotes -call add(s:exprs, 'strchars(substitute(substitute(a:info.cur.line, "\\\\.", "", "g"), "[^".escape(char, "\\^[]")."]", "", "g")) % 2') +call add(s:exprs, 'strchars(substitute(substitute(a:info.cur.line, + \"\\\\.", "", "g"), "[^".escape(char, "\\^[]")."]", "", "g")) % 2') -let s:defaults.delimitMate_smart_quotes_base = s:exprs +let s:defaults.smart_quotes_base = s:exprs unlet s:exprs let s:info = {} let s:info.char = '' let s:info.nesting = 0 -let s:info.typeahead = '' +let s:info.skip_icp = 0 +let s:info.is_ignored_syn = 0 let s:info.template = {} function! s:debug(debug_level, ...) "{{{1 - if s:option('debug') >= a:debug_level + if get(b:, 'delimitMate_debug', + \ get(g:, 'delimitMate_debug', + \ get(s:defaults, 'debug', 0))) let trail = expand('') let trail = substitute(trail, '\%(\.\.\d\+_debug\)\+$', '', '') + let trail = substitute(trail, '\d\+_', '', 'g') + let trail = substitute(trail, '\.\.', '.', 'g') let trail = substitute(trail, '^function\s\+\%(delimitMate\)\?', '', '') let message = get(a:, 1, '') echom printf('%s: %s', trail, message) @@ -60,15 +70,42 @@ endfunction command! -nargs=* -count=3 DMDebug call s:debug(, ) function! s:defaults.consolidate() "{{{1 + 3DMDebug 'Consolidate options' let g = filter(copy(g:), 'v:key =~# "^delimitMate_"') let b = filter(copy(b:), 'v:key =~# "^delimitMate_"') call extend(g, b, 'force') - call extend(g, self, 'keep') let short_options = {} - call map(g, 'extend(short_options, {substitute(v:key, "^delimitMate_", "", ""): v:val}, "force")') + call map(g, 'extend(short_options, + \{substitute(v:key, "^delimitMate_", "", ""): v:val}, "force")') + call extend(short_options, self, 'keep') return short_options endfunction +function! s:info.update() "{{{1 + let self.prev = get(self, 'cur', {}) + let d = {} + let d.line = getline('.') + let d.col = col('.') + let d.lnum = line('.') + let d.prev_line = line('.') == 1 ? '' : getline(line('.') - 1) + let d.next_line = line('.') == line('$') ? '' : getline(line('.') + 1) + let d.ahead = len(d.line) >= d.col ? d.line[d.col - 1 : ] : '' + let d.behind = d.col >= 2 ? d.line[: d.col - 2] : '' + let d.prev_char = strcharpart(d.behind, strchars(d.behind) - 1, 1) + let d.next_char = strcharpart(d.ahead, 0, 1) + let d.around = d.prev_char . d.next_char + call extend(d, s:info.template, 'keep') + 1DMDebug printf('lnum: %s, col: %s, prev_char: %s, next_char: %s', + \ d.lnum, d.col, string(d.prev_char), string(d.next_char)) + 1DMDebug printf("behind: %s", d.behind) + 1DMDebug printf("ahead : %s", d.ahead ) + 1DMDebug printf("prev_line: %s", d.prev_line) + 1DMDebug printf('cur_line : %s', d.line) + 1DMDebug printf('next_line: %s', d.next_line) + let self.cur = d + return d +endfunction + function! s:balance_pairs(pair, info, opts) "{{{1 let left = strcharpart(a:pair, 0, 1) let right = strcharpart(a:pair, 1, 1) @@ -102,51 +139,32 @@ function! s:balance_pairs(pair, info, opts) "{{{1 let rights = 0 endif endfor + 3DMDebug balance1 + balance2 return balance1 + balance2 endfunction function! s:info.template.is_escaped(...) "{{{1 + 3DMDebug let str = a:0 ? a1 : self.behind return len(matchstr(str, '\\*$')) % 2 endfunction -function! s:option(name, ...) "{{{1 - if a:0 - let opt = get(a:1, 'delimitMate_' . a:name, '') - else - let opt = get(b:, 'delimitMate_' . a:name, - \ get(g:, 'delimitMate_' . a:name, - \ get(s:defaults, 'delimitMate_' . a:name, ''))) - endif - if type(opt) == v:t_list +function! s:option(name) "{{{1 + 3DMDebug + let opt = get(b:, 'delimitMate_' . a:name, + \ get(g:, 'delimitMate_' . a:name, + \ get(s:defaults, a:name, ''))) + 3DMDebug printf('%s: %s', a:name, string(opt)) + if type(opt) == 3 || type(opt) == 4 return copy(opt) endif return opt endfunction function! s:synstack(lnum, col) "{{{1 - return map(synstack(a:lnum, a:col), 'synIDattr(v:val, "name")') + [synIDattr(synIDtrans(synID(line('.'), col('.'), 1)), 'name')] -endfunction - -function! s:get_info(...) "{{{1 - if a:0 - let d = a:1 - else - let d = {} - let d.line = getline('.') - let d.col = col('.') - let d.lnum = line('.') - let d.prev_line = line('.') == 1 ? '' : getline(line('.') - 1) - let d.next_line = line('.') == line('$') ? '' : getline(line('.') + 1) - endif - let d.ahead = len(d.line) >= d.col ? d.line[d.col - 1 : ] : '' - let d.behind = d.col >= 2 ? d.line[: d.col - 2] : '' - let d.p_char = strcharpart(d.behind, strchars(d.behind) - 1, 1) - let d.n_char = strcharpart(d.ahead, 0, 1) - let d.around = d.p_char . d.n_char - call extend(d, s:info.template, 'keep') - "3DMDebug string(d) - return d + 3DMDebug + return map(synstack(a:lnum, a:col), 'synIDattr(v:val, "name")') + \+ [synIDattr(synIDtrans(synID(line('.'), col('.'), 1)), 'name')] endfunction function! s:any_is_true(expressions, info, options) "{{{1 @@ -158,23 +176,169 @@ function! s:any_is_true(expressions, info, options) "{{{1 let col = info.cur.col let behind = info.cur.behind let ahead = info.cur.ahead - let prev_char = info.cur.p_char - let next_char = info.cur.n_char + let prev_char = info.cur.prev_char + let next_char = info.cur.next_char let exprs = copy(a:expressions) call filter(exprs, 'eval(v:val)') 3DMDebug string(exprs) return !empty(exprs) endfunction +function! s:keys4space(info, opts) "{{{1 + 2DMDebug string(a:opts) + let empty_pair = !empty(filter(copy(a:opts.pairs), + \'v:val ==# a:info.cur.around')) + if a:opts.expand_space && empty_pair + 2DMDebug "expand space inside a pair" + return " \U\" + endif + let empty_quotes = !empty(filter(copy(a:opts.quotes), + \'v:val.v:val ==# a:info.cur.around')) + if a:opts.expand_space && a:opts.expand_inside_quotes && empty_quotes + 2DMDebug "expand space inside quotes" + return " \U\" + endif + 2DMDebug "do nothing" + return '' +endfunction + +function! s:keys4left(char, pair, info, opts) "{{{1 + if !a:opts.autoclose + 2DMDebug "No autoclose" + return '' + endif + let exprs = a:opts.smart_pairs_base + a:opts.smart_pairs_extra + if a:opts.smart_pairs && s:any_is_true(exprs, a:info, a:opts) + 2DMDebug "smart pairs" + return '' + endif + if a:opts.balance_pairs && s:balance_pairs(a:pair, a:info, a:opts) < 0 + 2DMDebug "balance pairs" + return '' + endif + let eol_marker = a:opts.insert_eol_marker == 1 + \&& empty(a:info.cur.ahead) ? a:opts.eol_marker + \ . "\U\" : '' + 2DMDebug "add right delimiter" + return "\" . strcharpart(a:pair, 1, 1) . eol_marker . "\U\" +endfunction + +function! s:keys4right(char, pair, info, opts) "{{{1 + if !a:opts.jump_over + 2DMDebug "don't jump over delimiter" + return '' + endif + if a:opts.balance_pairs && s:balance_pairs(a:pair, a:info, a:opts) > 0 + 2DMDebug "balance pairs" + return '' + endif + if a:opts.jump_expansion + 2DMDebug "maybe jump over expansion" + let around = matchstr(a:info.cur.prev_line, "\\S$") + \. matchstr(a:info.cur.next_line, "^\\s*\zs\\S") + if a:char ==# matchstr(a:info.cur.next_line, "^\\s*\\zs\\S") + \&& empty(a:info.cur.ahead) + let rights = strchars(matchstr(a:info.cur.next_line, '^\s*')) + 2 + 2DMDebug "jump over CR expansion" + return "\s" . repeat("\", rights) + endif + if a:opts.expand_space + \&& a:info.cur.ahead =~# '^ ['.escape(a:char, '\^[]').']' + 2DMDebug "jump over space expansion" + return "\\\U\ \U\" + endif + endif + if !a:opts.autoclose + 2DMDebug "no autoclose" + if s:info.cur.around == a:pair + 2DMDebug "jump over right delimiter" + return "\" + elseif s:info.cur.prev_char == strcharpart(a:pair, 0, 1) + 2DMDebug "jump back" + return "\U\" + endif + 2DMDebug "do nothing" + return "" + endif + if strcharpart(a:info.cur.line[a:info.cur.col - 1 :], 0, 1) ==# a:char + 2DMDebug "jump over delimiter" + return "\" + endif + 2DMDebug "do nothing" + return '' +endfunction + +function! s:keys4quote(char, info, opts) "{{{1 + let quotes_behind = strchars(matchstr(a:info.cur.behind, + \'['.escape(a:char, '\^[]').']*$')) + let quotes_ahead = strchars(matchstr(a:info.cur.ahead, + \'^['.escape(a:char, '\^[]').']*')) + 2DMDebug quotes_behind . ' - ' . quotes_ahead + 2DMDebug string(a:opts.nesting_quotes) + if a:opts.autoclose && index(a:opts.nesting_quotes, a:char) >= 0 + \&& quotes_behind > 1 + let add2right = quotes_ahead > quotes_behind + 1 + \? 0 : quotes_behind - quotes_ahead + 1 + 2DMDebug "nesting quotes" + 2DMDebug add2right + return repeat(a:char, add2right) . repeat("\U\", add2right) + endif + if a:info.cur.next_char ==# a:char + 2DMDebug "jump over quote" + return "\" + endif + if a:info.is_ignored_syn + return '' + endif + let exprs = a:opts.smart_quotes_base + a:opts.smart_quotes_extra + if a:opts.autoclose && a:opts.smart_quotes + \&& s:any_is_true(exprs, a:info, a:opts) + 2DMDebug "smart quotes" + return '' + endif + if !a:opts.autoclose && quotes_behind + 2DMDebug "don't autoclose, jump back" + return "\U\" + endif + if !a:opts.autoclose + 2DMDebug "don't autoclose" + return '' + endif + 2DMDebug "jump back" + return a:char . "\U\" +endfunction + +function! s:keys4cr(info, opts) "{{{1 + if a:opts.expand_cr + \&& !empty(filter(copy(a:opts.pairs), + \ 'v:val ==# a:info.prev.around')) + \|| (a:opts.expand_cr == 2 + \ && !empty(filter(copy(a:opts.pairs), + \ 'strcharpart(v:val, 1, 1) == a:info.cur.next_char'))) + " Empty pair + 2DMDebug "expand CR inside pair" + let eol_marker = a:opts.insert_eol_marker == 2 + \&& strchars(a:info.cur.ahead) == 1 ? a:opts.eol_marker : '' + return "0\\x\U\\\" . a:info.cur.next_char + \. "\" . eol_marker . "\\\" + endif + if a:opts.expand_cr && a:opts.expand_inside_quotes + \&& !empty(filter(copy(a:opts.quotes), + \ 'v:val.v:val ==# a:info.prev.around')) + " Empty pair + 2DMDebug "expand CR inside quotes" + return "\\\" + endif + 2DMDebug "do nothing" + return '' +endfunction +" vim: sw=2 et function! delimitMate#option(name) "{{{1 return s:option(a:name) endfunction -function! delimitMate#call(function, ...) "{{{1 - return call(a:function, get(a:, 1, [])) -endfunction - function! delimitMate#ex_cmd(global, action) "{{{1 + 1DMDebug 'action: ' . a:action . ', scope: ' . (a:global ? 'g:' : 'b:') let scope = a:global ? g: : b: if a:action ==# 'enable' let scope.delimitMate_enabled = 1 @@ -185,34 +349,100 @@ function! delimitMate#ex_cmd(global, action) "{{{1 endif endfunction -function! delimitMate#CursorMovedI(...) "{{{1 - let s:info.prev = s:info.cur - let s:info.cur = call('s:get_info', a:000) +function! delimitMate#InsertEnter(...) "{{{1 + 1DMDebug + call s:info.update() let s:info.skip_icp = 0 - 3DMDebug 'INFO: ' . string(s:info) endfunction -function! delimitMate#InsertEnter(...) "{{{1 - let s:info.cur = call('s:get_info', a:000) - let s:info.prev = {} +function! delimitMate#CursorMovedI(...) "{{{1 + 1DMDebug + call s:info.update() let s:info.skip_icp = 0 - 3DMDebug +endfunction + +function! delimitMate#InsertCharPre(str) "{{{1 + 1DMDebug + 1DMDebug printf('v:char: %s', string(a:str)) + if s:info.skip_icp + " iabbrev fires this event for every char and the trigger + 1DMDebug "iabbrev expansion running" + return 0 + endif + if pumvisible() + 1DMDebug "pumvisible" + return 0 + endif + if s:info.nesting + 1DMDebug "nesting" + let s:info.nesting -= 1 + return 0 + endif + let s:info.skip_icp = 1 + if !s:option('enabled') + 1DMDebug "disabled" + return 0 + endif + let typeahead = '' + let synstack = join(map( + \synstack(line('.'), col('.')), + \'tolower(synIDattr(v:val, "name"))'), ',') + let s:info.is_ignored_syn = !empty(filter( + \s:option('excluded_regions'), + \'stridx(synstack, tolower(v:val)) >= 0')) + " v:char could be more than one character + for char in split(a:str, '\zs') + 1DMDebug 'char: ' . char + let keys = '' + let s:info.char = char + let opts = s:defaults.consolidate() + if s:info.cur.is_escaped() + 1DMDebug "escaped" + return + elseif !empty(filter(copy(opts.quotes), 'v:val ==# char')) + 1DMDebug "quote" + let keys = s:keys4quote(char, s:info, opts) + let s:info.nesting = strchars(matchstr(keys, '^[^[:cntrl:]]*')) + let s:info.nesting = s:info.nesting < 3 ? 0 : s:info.nesting + elseif s:info.is_ignored_syn + 1DMDebug "ignored syn group" + return + elseif char == ' ' + 1DMDebug "space" + let keys = s:keys4space(s:info, opts) + elseif !empty(filter(copy(opts.pairs), + \'strcharpart(v:val, 0, 1) ==# char')) + 1DMDebug "left delimiter" + let pair = get(filter(copy(opts.pairs), + \'strcharpart(v:val, 0, 1) ==# char'), 0, '') + let keys = s:keys4left(char, pair, s:info, opts) + elseif !empty(filter(copy(opts.pairs), + \'strcharpart(v:val, 1, 1) ==# char')) + let pair = get(filter(copy(opts.pairs), + \'strcharpart(v:val, 1, 1) ==# char'), 0, '') + let keys = s:keys4right(char, pair, s:info, opts) + 1DMDebug "right delimiter" + else + 1DMDebug "just ignore it" + return 0 + endif + 1DMDebug 'keys: ' . strtrans(keys) + let typeahead .= keys + endfor + if !empty(typeahead) + 1DMDebug "feed typeahead: " . strtrans(typeahead) + call feedkeys(typeahead, 'tmi') + endif endfunction function! delimitMate#TextChangedI(...) "{{{1 - 3DMDebug s:info.cur.line + 1DMDebug if pumvisible() - 3DMDebug "20" + 1DMDebug "pumvisible" return 0 endif - if !empty(s:info.typeahead) - 3DMDebug "B1" - call feedkeys(s:info.typeahead, 'tmi') - let s:info.typeahead = '' - return - endif if !s:option('enabled') - 3DMDebug "21" + 1DMDebug "disabled" return endif if s:info.cur.lnum == s:info.prev.lnum + 1 @@ -220,248 +450,61 @@ function! delimitMate#TextChangedI(...) "{{{1 \&& s:info.prev.ahead ==# s:info.cur.ahead \&& s:info.cur.behind =~ '^\s*$' " CR - 3DMDebug "22" + 1DMDebug "CR at eol" return feedkeys(s:keys4cr(s:info, s:defaults.consolidate()), 'tni') endif if s:info.cur.lnum == s:info.prev.lnum - 1 \&& s:info.prev.prev_line ==# s:info.cur.line \&& s:info.prev.next_line ==# s:info.cur.next_line - let pair = filter(s:option('pairs'), 's:info.cur.p_char . matchstr(s:info.cur.next_line, "^\\s*\\zs\\S") ==# v:val') - 3DMDebug "23" + let pair = filter(s:option('pairs'), 's:info.cur.prev_char + \. matchstr(s:info.cur.next_line, "^\\s*\\zs\\S") ==# v:val') if s:option('expand_cr') && !empty(pair) - 3DMDebug "23.1" + 1DMDebug "CR expansion inside pair" let spaces = strchars(s:info.cur.next_line, '^\s*') return feedkeys(repeat("\", spaces), 'nti') endif - let quote = filter(s:option('quotes'), 's:info.cur.p_char . matchstr(s:info.cur.next_line, "^\\s*\\zs\\S") ==# v:val.v:val') - if s:option('expand_cr') && s:option('expand_inside_quotes') && !empty(quote) - 3DMDebug "23.2" + let quote = filter(s:option('quotes'), 's:info.cur.prev_char + \. matchstr(s:info.cur.next_line, "^\\s*\\zs\\S") ==# v:val.v:val') + if s:option('expand_cr') && s:option('expand_inside_quotes') + \&& !empty(quote) + 1DMDebug "CR expansion inside quotes" return feedkeys("\") endif + 1DMDebug "BS at bol" return endif if s:info.cur.lnum != s:info.prev.lnum - 3DMDebug "24" + 1DMDebug "Cursor changed line" return endif - if s:info.prev.col - s:info.cur.col != len(s:info.prev.p_char) - 3DMDebug "25" + if s:info.prev.col - s:info.cur.col != len(s:info.prev.prev_char) + 1DMDebug "zero or several characters were deleted" return endif if len(s:info.prev.line) == len(s:info.cur.line) - 3DMDebug "26" + 1DMDebug "Same line length" return endif - 3DMDebug s:info.prev.around - let pair = filter(s:option('pairs'), 'v:val ==# (s:info.cur.p_char . matchstr(s:info.cur.ahead, "^\\s\\zs\\S"))') - let quotes = filter(s:option('quotes'), 'v:val . v:val ==# (s:info.cur.p_char . matchstr(s:info.cur.ahead, "^\\s\\zs\\S"))') - if s:option('expand_space') && (!empty(pair) || (s:option('expand_inside_quotes') && !empty(quotes))) - 3DMDebug "27" + 1DMDebug s:info.prev.around + let pair = filter(s:option('pairs'), 'v:val ==# (s:info.cur.prev_char + \ . matchstr(s:info.cur.ahead, "^\\s\\zs\\S"))') + let quotes = filter(s:option('quotes'), + \ 'v:val . v:val ==# (s:info.cur.prev_char + \ . matchstr(s:info.cur.ahead, "^\\s\\zs\\S"))') + if s:option('expand_space') && (!empty(pair) + \|| (s:option('expand_inside_quotes') && !empty(quotes))) + 1DMDebug "Space expansion inside pair" return feedkeys("\", 'tni') endif let pair = filter(s:option('pairs'), 'v:val ==# s:info.prev.around') - let quote = filter(s:option('quotes'), 'v:val . v:val ==# s:info.prev.around') - if empty(pair) && empty(quote) - 3DMDebug "28" - return + let quote = filter(s:option('quotes'), + \'v:val . v:val ==# s:info.prev.around') + if !empty(pair) || !empty(quote) + 1DMDebug "BS inside empty pair or quotes" + let keys = "\" + return feedkeys(keys, 'tni') endif - 3DMDebug "29" - let keys = "\" - call feedkeys(keys, 'tni') + 1DMDebug "Everything else" + return endfunction -" vim: sw=2 et -function! delimitMate#InsertCharPre(str) "{{{1 - 3DMDebug string(a:str) . ': ' . get(s:info, 'cur', {'line': ''}).line - if s:info.skip_icp - " iabbrev fires this event for every char and the trigger - 3DMDebug "01" - return 0 - endif - if pumvisible() - 3DMDebug "2" - return 0 - endif - if s:info.nesting - 3DMDebug "03" - let s:info.nesting -= 1 - return 0 - endif - let s:info.skip_icp = 1 - if !s:option('enabled') - 3DMDebug "04" - return 0 - endif - let synstack = join(map(synstack(line('.'), col('.')), 'tolower(synIDattr(v:val, "name"))'), ',') - let s:info.is_ignored_syn = !empty(filter(s:option('excluded_regions'), 'stridx(synstack, tolower(v:val)) >= 0')) - 3DMDebug "9" - for char in split(a:str, '\zs') - let keys = '' - let s:info.char = char - let opts = s:defaults.consolidate() - if s:info.cur.is_escaped() - 3DMDebug "12" - return - elseif !empty(filter(copy(opts.quotes), 'v:val ==# char')) - 3DMDebug "15" - let keys = s:keys4quote(char, s:info, opts) - let s:info.nesting = strchars(matchstr(keys, '^[^[:cntrl:]]*')) - let s:info.nesting = s:info.nesting < 3 ? 0 : s:info.nesting - elseif s:info.is_ignored_syn - 3DMDebug "9" - return - elseif char == ' ' - 3DMDebug "13" - let keys = s:keys4space(s:info, opts) - elseif !empty(filter(copy(opts.pairs), 'strcharpart(v:val, 0, 1) ==# char')) - 3DMDebug "16" - let pair = get(filter(copy(opts.pairs), 'strcharpart(v:val, 0, 1) ==# char'), 0, '') - let keys = s:keys4left(char, pair, s:info, opts) - "echom strtrans(keys) - "echom string(pair) - elseif !empty(filter(copy(opts.pairs), 'strcharpart(v:val, 1, 1) ==# char')) - let pair = get(filter(copy(opts.pairs), 'strcharpart(v:val, 1, 1) ==# char'), 0, '') - let keys = s:keys4right(char, pair, s:info, opts) - 3DMDebug "17" - else - 3DMDebug "18" - return 0 - endif - 3DMDebug keys - let s:info.typeahead .= keys - endfor -endfunction - -function! s:keys4space(info, opts) "{{{1 - 3DMDebug string(a:opts) - let empty_pair = !empty(filter(copy(a:opts.pairs), 'v:val ==# a:info.cur.around')) - if a:opts.expand_space && empty_pair - 3DMDebug "61" - return " \U\" - endif - let empty_quotes = !empty(filter(copy(a:opts.quotes), 'v:val.v:val ==# a:info.cur.around')) - if a:opts.expand_space && a:opts.expand_inside_quotes && empty_quotes - 3DMDebug "62" - return " \U\" - endif - 3DMDebug "69" - return '' -endfunction - -function! s:keys4left(char, pair, info, opts) "{{{1 - if !a:opts.autoclose - 3DMDebug "31" - return '' - endif - let exprs = a:opts.smart_pairs_base + a:opts.smart_pairs_extra - if a:opts.smart_pairs && s:any_is_true(exprs, a:info, a:opts) - 3DMDebug "32" - return '' - endif - if a:opts.balance_pairs && s:balance_pairs(a:pair, a:info, a:opts) < 0 - 3DMDebug "33" - return '' - endif - let eol_marker = a:opts.insert_eol_marker == 1 && empty(a:info.cur.ahead) ? a:opts.eol_marker . "\U\" : '' - 3DMDebug "34" - return "\" . strcharpart(a:pair, 1, 1) . eol_marker . "\U\" -endfunction - -function! s:keys4right(char, pair, info, opts) "{{{1 - if !a:opts.jump_over - 3DMDebug "A2" - return '' - endif - if a:opts.balance_pairs && s:balance_pairs(a:pair, a:info, a:opts) > 0 - 3DMDebug "A1" - return '' - endif - if a:opts.jump_expansion - 3DMDebug "40" - let around = matchstr(a:info.cur.prev_line, "\\S$") . matchstr(a:info.cur.next_line, "^\\s*\zs\\S") - if empty(a:info.cur.ahead) && a:char ==# matchstr(a:info.cur.next_line, "^\\s*\\zs\\S") - let rights = strchars(matchstr(a:info.cur.next_line, '^\s*')) + 2 - 3DMDebug "40.1" - return "\s" . repeat("\", rights) - endif - endif - if !a:opts.autoclose - if s:info.cur.around == a:pair - 3DMDebug "41" - return "\" - elseif s:info.cur.p_char == strcharpart(a:pair, 0, 1) - 3DMDebug "42" - return "\U\" - endif - 3DMDebug "43" - return "" - endif - if strcharpart(a:info.cur.line[a:info.cur.col - 1 :], 0, 1) ==# a:char - 3DMDebug "44" - return "\" - endif - if a:opts.expand_space && a:opts.jump_expansion - \ && matchstr(a:info.cur.ahead, '^ ['.escape(a:char, '\^[]').']') ==# ' ' . a:char - 3DMDebug "45" - return "\\\U\ \U\" - endif - 3DMDebug "49" - return '' -endfunction - -function! s:keys4quote(char, info, opts) "{{{1 - let quotes_behind = strchars(matchstr(a:info.cur.behind, '['.escape(a:char, '\^[]').']*$')) - let quotes_ahead = strchars(matchstr(a:info.cur.ahead, '^['.escape(a:char, '\^[]').']*')) - 3DMDebug quotes_behind . ' - ' . quotes_ahead - 3DMDebug string(a:opts.nesting_quotes) - if a:opts.autoclose && index(a:opts.nesting_quotes, a:char) >= 0 - \&& quotes_behind > 1 - let add2right = quotes_ahead > quotes_behind + 1 ? 0 : quotes_behind - quotes_ahead + 1 - 3DMDebug "51" - 3DMDebug add2right - return repeat(a:char, add2right) . repeat("\U\", add2right) - endif - if a:info.cur.n_char ==# a:char - 3DMDebug "53" - return "\" - endif - if a:info.is_ignored_syn - return '' - endif - let exprs = a:opts.smart_quotes_base + a:opts.smart_quotes_extra - if a:opts.autoclose && a:opts.smart_quotes - \&& s:any_is_true(exprs, a:info, a:opts) - 3DMDebug "52" - return '' - endif - if !a:opts.autoclose && quotes_behind - 3DMDebug "54" - return "\" - endif - if !a:opts.autoclose - 3DMDebug "55" - return '' - endif - 3DMDebug "59" - return a:char . "\U\" -endfunction - -function! s:keys4cr(info, opts) "{{{1 - if a:opts.expand_cr - \&& !empty(filter(copy(a:opts.pairs), 'v:val ==# a:info.prev.around')) - \|| (a:opts.expand_cr == 2 && !empty(filter(copy(a:opts.pairs), 'strcharpart(v:val, 1, 1) == a:info.cur.n_char'))) - " Empty pair - 3DMDebug "71" - let eol_marker = a:opts.insert_eol_marker == 2 && strchars(a:info.cur.ahead) == 1 ? a:opts.eol_marker : '' - return "0\\x\U\\\" . a:info.cur.n_char . "\" . eol_marker . "\\\" - endif - if a:opts.expand_cr && a:opts.expand_inside_quotes - \&& !empty(filter(copy(a:opts.quotes), 'v:val.v:val ==# a:info.prev.around')) - " Empty pair - 3DMDebug "72" - return "\\\" - endif - 3DMDebug "79" - return '' -endfunction -" vim: sw=2 et diff --git a/plugin/delimitMate.vim b/plugin/delimitMate.vim index 8f1f45c..d247dde 100644 --- a/plugin/delimitMate.vim +++ b/plugin/delimitMate.vim @@ -1,13 +1,13 @@ -if exists("g:loaded_delimitMate") || &cp || v:version < 800 +if exists("g:loaded_delimitMate") || &cp || !exists('##InsertCharPre') finish endif let g:loaded_delimitMate = 1 let save_cpo = &cpo set cpo&vim -command! -bar -bang DelimitMateSwitch call delimitMate#ex_cmd(0,'switch') -command! -bar -bang DelimitMateOn call delimitMate#ex_cmd(0,'enable') -command! -bar -bang DelimitMateOff call delimitMate#ex_cmd(0,'disable') +command! -bar -bang DelimitMateSwitch call delimitMate#ex_cmd(0, 'switch' ) +command! -bar -bang DelimitMateOn call delimitMate#ex_cmd(0, 'enable' ) +command! -bar -bang DelimitMateOff call delimitMate#ex_cmd(0, 'disable') augroup delimitMate au! diff --git a/test/autoclose_matchpairs.vim b/test/autoclose_matchpairs.vim index bddeab9..554423d 100644 --- a/test/autoclose_matchpairs.vim +++ b/test/autoclose_matchpairs.vim @@ -111,7 +111,9 @@ call DMTest_single('{[(foobar)]}', 'fbi\x', '{[(foobar)]}x', 0, 1) new syntax on set ft=vim +let g:delimitMate_excluded_regions = ['String'] call DMTest_pairs('echo " "', "f\"la(", 'echo " ( "') +let g:delimitMate_excluded_regions = [] filetype indent plugin on set ft=php