From c4d51a21b315a023a11f5ee2c54263bdf3b29f1e Mon Sep 17 00:00:00 2001 From: Israel Chauca Fuentes Date: Sat, 1 Apr 2017 12:00:36 -0400 Subject: [PATCH] Refactor pairs handling --- autoload/delimitMate.vim | 126 ++++++++++++++++++++++------------ test/autoclose_matchpairs.vim | 15 +++- 2 files changed, 93 insertions(+), 48 deletions(-) diff --git a/autoload/delimitMate.vim b/autoload/delimitMate.vim index 9d45e1c..ba90e16 100644 --- a/autoload/delimitMate.vim +++ b/autoload/delimitMate.vim @@ -110,10 +110,12 @@ endfunction function! s:balance_pairs(pair, info, opts) "{{{1 let left = strcharpart(a:pair, 0, 1) let right = strcharpart(a:pair, 1, 1) - let behind = matchstr(a:info.cur.behind, '['.escape(left, '\^[]').'].*') - let ahead = matchstr(a:info.cur.ahead, '^.*['.escape(right, '\^[]').']') let pat = '[^' . escape(a:pair, '\^[]') . ']' + let behind = substitute(a:info.cur.behind, '\\.', '', 'g') + let behind = matchstr(behind, '['.escape(left, '\^[]').'].*') let behind = substitute(behind, pat, '', 'g') + let ahead = substitute(a:info.cur.ahead, '\\.', '', 'g') + let ahead = matchstr(ahead, '^.*['.escape(right, '\^[]').']') let ahead = substitute(ahead, pat, '', 'g') let lefts = 0 let rights = 0 @@ -185,14 +187,32 @@ function! s:any_is_true(expressions, info, options) "{{{1 return !empty(exprs) endfunction -function! s:rights2jump(char, pair, info, opts) "{{{1 +function! s:rights2jump_pair(char, pair, info, opts, go_next) "{{{1 + " TODO consider escaped characters + let go_next = a:go_next + \ && empty(a:info.cur.ahead) + \ && a:info.cur.next_line =~# '^\s*['.escape(a:char, '[]^-\').']' let line = a:info.cur.ahead 3DMDebug 'ahead: ' . line let pair_pat = '[' . escape(a:pair, '[]^\-') . ']' let char_pat = '[' . escape(a:char, '[]^\-') . ']' let idx = match(line, pair_pat) let balance = 0 - while idx >= 0 && balance >= 0 && line[idx : ] !~# char_pat + while go_next || idx >= 0 && balance >= 0 && line[idx : ] !~# char_pat + if idx == -1 + let idx = strchars(matchstr(a:info.cur.next_line, '^\s*\S')) + break + endif + if line[idx : ] =~# char_pat + let balance -= 1 + else + let balance += 1 + endif + let idx = match(line, pair_pat, idx + 1) + endwhile + 3DMDebug 'idx: ' . idx + return idx + 1 +endfunction if line[idx : ] =~# char_pat let balance -= 1 else @@ -223,6 +243,14 @@ function! s:keys4space(info, opts) "{{{1 endfunction function! s:keys4left(char, pair, info, opts) "{{{1 + "| cases | criteria | action options | action + "| | balance | auto balance back smart | close back + "|--------|----------|-----------------------------|------------ + "| any | any | 0 0 1 1 | 0 0 + "| any | any | 0 0 1 0 | 0 0 + "| (|)) | -1 | 1 1 1 0 | 0 0 + "| (|) | 0 | 1 1 1 0 | 1 1 + "| ((|) | 1 | 1 1 1 0 | 1 0 if !a:opts.autoclose 2DMDebug "No autoclose" return '' @@ -240,44 +268,53 @@ function! s:keys4left(char, pair, info, opts) "{{{1 \&& empty(a:info.cur.ahead) ? a:opts.eol_marker \ . "\U\" : '' 2DMDebug "add right delimiter" - return "\" . strcharpart(a:pair, 1, 1) . eol_marker . "\U\" + let jump_back = a:opts.jump_back ? "\U\" : '' + return "\" . strcharpart(a:pair, 1, 1) . eol_marker . jump_back endfunction function! s:keys4right(char, pair, info, opts) "{{{1 - " cases | variables | jump options - " | next prev bal space close | next exp long to back - "------------------------------------------------------------ - "1 x(|)x | 1 1 0 0 1 | 1 1 1 1 0 - "2 (|)) | 1 1 -1 0 1 | 1 1 1 1 0 - "3 ((|) | 1 1 1 0 1 | 1 1 1 1 0 - "4 x|) | 1 0 -1 0 1 | 1 1 1 1 0 - "5 (| | 0 1 1 0 0 | 0 0 0 0 1 - "6 |x) | 0 0 -1 0 1 | 0 1 1 1 0 - "7 ( | ) | 0 0 0 1 1 | 0 1 1 1 0 - "8 (x|x) | 0 0 0 0 1 | 0 0 1 1 0 - "9 x| | 0 0 0 0 0 | 0 0 0 0 0 - "10 (x| | 0 0 1 0 0 | 0 0 0 0 0 + "| cases | criteria | action options | action + "| | next prev close bal | next long bal | jump back + "|--------|---------------------|----------------|----------- + "| (|)) | 1 1 1 -1 | 1 1 0 | 1 0 + "| (|) | 1 1 1 0 | 1 1 0 | 1 0 + "| ((|) | 1 1 1 1 | 1 1 0 | 1 0 + "| x|) | 1 0 1 -1 | 1 1 0 | 1 0 + "| (x|) | 1 0 1 0 | 1 1 0 | 1 0 + "| ((x|) | 1 0 1 1 | 1 1 1 | 1 0 + "| (| | 0 1 0 1 | 0 0 1 | 0 1 + "| |x) | 0 0 1 -1 | 0 1 0 | 1 0 + "| (x|x)) | 0 0 1 -1 | 0 1 0 | 1 0 + "| (x|x) | 0 0 1 0 | 0 1 0 | 1 0 + "| ((x|x) | 0 0 1 1 | 0 0 1 | 0 1 + "| x| | 0 0 0 0 | 0 0 0 | 0 0 + "| (x| | 0 0 0 1 | 0 0 0 | 0 0 let previous = strcharpart(a:pair, 0, 1) ==# a:info.cur.prev_char - let next = a:char ==# a:info.cur.next_char + let is_cr_exp = a:opts.expand_cr + \ && empty(a:info.cur.ahead) + \ && matchstr(a:info.cur.next_line, '^\s*\zs\S') ==# a:char + let is_space_exp = a:opts.expand_space + \ && matchstr(a:info.cur.ahead, '^\s\zs\S') ==# a:char + let next = a:char ==# a:info.cur.next_char || is_cr_exp || is_space_exp let balance = s:balance_pairs(a:pair, a:info, a:opts) - let has_space = a:info.cur.next_char == ' ' - let has_closing = s:rights2jump(a:char, a:pair, a:info, a:opts) - let jump_opts = a:opts.jump_next + (a:opts.jump_expansion * 2) - \ + (a:opts.jump_long * 4) - 2DMDebug 'previous: ' . previous + \ - is_cr_exp + let next_line = a:opts.jump_expansion && a:opts.expand_cr + let closing = s:rights2jump_pair(a:char, a:pair, a:info, a:opts, next_line) + let jump_opts = a:opts.jump_next + (a:opts.jump_long * 2) + 2DMDebug 'is_cr_exp: ' . is_cr_exp + 2DMDebug 'is_space_exp: ' . is_space_exp 2DMDebug 'next: ' . next + 2DMDebug 'previous: ' . previous + 2DMDebug 'closing: ' . closing 2DMDebug 'balance: ' . balance - 2DMDebug 'has_space: ' . has_space - 2DMDebug 'has_closing: ' . has_closing + 2DMDebug 'next_line: ' . next_line 2DMDebug 'jump_opts: ' . jump_opts if next 2DMDebug "next" - if previous && !has_space && has_closing && jump_opts - 2DMDebug "cases 1, 2, 3" - return "\" . repeat("\U\", has_closing) - elseif !previous && balance < 0 && !has_space && has_closing && jump_opts - 2DMDebug "case 4" - return "\" . repeat("\U\", has_closing) + if closing && jump_opts && (!a:opts.balance_pairs || balance <= 0) + 2DMDebug "cases: '(|)', '(|))' or '((|)'" + 2DMDebug "cases: 'x|)', '(x|)' or '((x|)'" + return "\" . repeat("\U\", closing) endif 2DMDebug "Nothing to do" return '' @@ -285,26 +322,25 @@ function! s:keys4right(char, pair, info, opts) "{{{1 " !next if previous 2DMDebug "!next && previous" - if balance > 0 && a:opts.jump_back - 2DMDebug "case 5" + if (!a:opts.balance_pairs || balance > 0) && a:opts.jump_back + 2DMDebug "case: '(|'" return "\U\" endif 2DMDebug "Nothing to do" return '' endif " !next && !previous - if balance < 0 && !has_space && has_closing && jump_opts >= 2 - 2DMDebug "case 6" - return "\" . repeat("\U\", has_closing) - elseif balance == 0 - 2DMDebug "!next && !previous && balance == 0" - if has_space && has_closing && jump_opts >= 2 - 2DMDebug "case 7" - return "\" . repeat("\U\", has_closing) - elseif !has_space && has_closing && jump_opts >= 4 - 2DMDebug "case 8" - return "\" . repeat("\U\", has_closing) + if closing + 2DMDebug "!next && !previous && closing" + if (!a:opts.balance_pairs || balance <= 0) && jump_opts >= 2 + 2DMDebug "case: '(x|x))' or '(x|x)'" + return "\" . repeat("\U\", closing) + elseif (!a:opts.balance_pairs || balance > 0) && a:opts.jump_back + 2DMDebug "case: '((x|x)'" + return "\U\" endif + 2DMDebug "Nothing to do" + return '' endif 2DMDebug "Nothing to do" return '' diff --git a/test/autoclose_matchpairs.vim b/test/autoclose_matchpairs.vim index 3fcdc27..0cdeed6 100644 --- a/test/autoclose_matchpairs.vim +++ b/test/autoclose_matchpairs.vim @@ -12,7 +12,7 @@ call vimtest#StartTap() -call vimtap#Plan(217) +call vimtap#Plan(239) let g:delimitMate_matchpairs = '(:),{:},[:],<:>,¿:?,¡:!,,::' @@ -90,10 +90,15 @@ call DMTest_single('()', 'a\x', '()x', 0, 1) call DMTest_single('{()}', 'la\x', '{()}x', 0, 1) +let g:delimitMate_balance_pairs = 0 +call DMTest_pairs('ab cd)', "la(x", 'ab(x) cd)') +" Issue #229 +call DMTest_pairs('((ab cd)', "$i)x", '((ab cd)x') + let g:delimitMate_balance_pairs = 1 call DMTest_pairs('ab cd)', "la(x", 'ab(x cd)') " Issue #229 -call DMTest_pairs('((ab cd)', "A)", '((ab cd))') +call DMTest_pairs('((ab cd)', "$i)x", '((ab cd)x)') unlet g:delimitMate_balance_pairs " Issue #220 @@ -111,9 +116,13 @@ unlet g:delimitMate_jump_long " Issues #207 and #223 let g:delimitMate_jump_all = 1 -call DMTest_single('{[(foobar)]}', 'fbi)x', '{[(foobar)]}x', 0, 1) +call DMTest_single('{[(foobar)]}', 'fbix', '{[(foobar)]}x', 0, 1) unlet g:delimitMate_jump_all +let g:delimitMate_jump_back = 1 +call DMTest_pairs('', 'i()x', '()x') +unlet g:delimitMate_jump_back + " Disable on syntax groups new syntax on