Cleanup matchparen, fix transmute, fix bug in da%

This commit is contained in:
Andy K. Massimino
2017-11-06 14:42:26 -05:00
parent a61decb022
commit 5a5f411187
4 changed files with 86 additions and 256 deletions

View File

@@ -3,7 +3,7 @@
:warning: warning :warning: this plugin is under heavy
active development. There are probably bugs!
match-up is a replacement for the venerable vim plugin [matchit.vim]
match-up is a replacement for the venerable vim plugin [matchit.vim].
match-up aims to replicate all of matchit's features, fix a number of its
deficiencies and bugs, and add a few totally new features. It also
replaces the standard plugin [matchparen], allowing all of matchit's words
@@ -203,7 +203,9 @@ Changing `pre` to `div` and leaving insert mode will produce:
Note: this currently only works for match words which define a backref
relation like `\1`. A wider set of transmutations are planned.
_Planned_: `g:matchup_auto_transmute`, `CTRL-G %` mapping. A
Parallel transmutation requires the matchparen module to be enabled.
_Planned_: `g:matchup_transmute_auto`, `CTRL-G %` mapping. A
corresponding normal mode command is also planned.
### Inclusive and exclusive motions

View File

@@ -57,22 +57,13 @@ endfunction
let s:matchparen = {}
function! s:matchparen.clear() abort dict " {{{1
silent! call matchdelete(w:matchup_match_id1)
silent! call matchdelete(w:matchup_match_id2)
if exists('w:matchup_match_id_list')
for l:id in w:matchup_match_id_list
silent! call matchdelete(l:id)
endfor
unlet! w:matchup_match_id_list
endif
unlet! w:matchup_match_id1
unlet! w:matchup_match_id2
if exists('w:matchup_oldecho')
echo ''
unlet w:matchup_oldecho
endif
if exists('w:matchup_oldstatus')
let &statusline = w:matchup_oldstatus
unlet w:matchup_oldstatus
@@ -128,26 +119,12 @@ function! s:matchparen.highlight(...) abort dict " {{{1
call matchup#perf#toc('matchparen.highlight', 'get_current')
if empty(l:current) | return | endif
" echo 'curent' l:current.match
let l:corrlist = matchup#delim#get_matching(l:current, 1)
call matchup#perf#toc('matchparen.highlight', 'get_matching')
if empty(l:corrlist) | return | endif
" echo l:corrlist
"echo map(copy(l:corrlist), 'v:val.rematch')
" echo map(copy(l:corrlist), 'v:val.lnum.",".v:val.cnum')
" echo l:corrlist[0].class l:corrlist[1].class
" \ l:corrlist[0].side l:corrlist[1].side
" echo 'vv' map(copy(l:corrlist), 'v:val.match')
" \ map(copy(l:corrlist), 'v:val.lnum')
if !exists('w:matchup_matchparen_context')
let w:matchup_matchparen_context = {
\ 'insert': {
\ 'current': {},
\ 'corrlist': [],
\ },
\ 'normal': {
\ 'current': {},
\ 'corrlist': [],
@@ -156,130 +133,44 @@ function! s:matchparen.highlight(...) abort dict " {{{1
\ 'counter': 0,
\}
endif
let w:matchup_matchparen_context.counter += 1
let w:matchup_matchparen_context.prior
\ = deepcopy(w:matchup_matchparen_context.normal)
let l:mode_name = l:insertmode && !l:entering_insert
\ ? 'insert' : 'normal'
if !l:insertmode
let w:matchup_matchparen_context.prior
\ = deepcopy(w:matchup_matchparen_context.normal)
let w:matchup_matchparen_context[l:mode_name].current = l:current
let w:matchup_matchparen_context[l:mode_name].corrlist = l:corrlist
" echo w:matchup_matchparen_context.normal.current.match
" \ w:matchup_matchparen_context.prior.current.match
" \ b:changedtick
" echo w:matchup_matchparen_context.counter
let w:matchup_matchparen_context.normal.current = l:current
let w:matchup_matchparen_context.normal.corrlist = l:corrlist
endif
" if transmuted, highlight again (will reset timeout)
if matchup#transmute#tick(l:insertmode, l:entering_insert)
return s:matchparen.highlight(l:force_update, l:entering_insert)
" no force_update here because it would screw up prior
return s:matchparen.highlight(0, l:entering_insert)
endif
if len(l:corrlist) <= 1 && !g:matchup_matchparen_singleton
return
endif
" if l:need_update
" endif
" echo l:corrlist
" echo map(deepcopy(l:corrlist), 'v:val.lnum')
" for l:c in l:corrlist
" echom l:c.match
" endfor
" echo map(l:corrlist, 'get(v:val,"match","")')
" PP map(l:corrlist, 'has_key'
" set up links: assume [open, mid.., close]
" let l:open = l:corrlist[0]
" let l:close = l:corrlist[-1]
" let l:toremove = -1
" for l:i in range(len(l:corrlist))
" let l:c = l:corrlist[l:i]
" if empty(l:c)
" let l:corrlist[l:i] = l:current
" let l:toremove = l:i
" else
" endif
" " open prev next close
" endfor
" if l:toremove > -1
" call remove(l:corrlist, l:toremove)
" endif
" let l:current.links = l:links
" let l:corresponding = l:corrlist[-1]
" let [l:open, l:close] = [l:corrlist[0], l:corrlist[-1]]
" let [l:open, l:close] = l:current.is_open
" \ ? [l:current, l:corresponding]
" \ : [l:corresponding, l:current]
" let l:mids = matchup#delim#get_middle(l:open, l:close)
" let w:matchup_match_id1 = matchadd('MatchParen',
" \ '\%' . l:open.lnum . 'l\%' . l:open.cnum
" \ . 'c' . l:open.re.this)
" let w:matchup_match_id2 = matchadd('MatchParen',
" \ '\%' . l:close.lnum . 'l\%' . l:close.cnum
" \ . 'c' . l:close.re.this)
" elseif exists('w:matchup_oldstatus')
" let &statusline = w:matchup_oldstatus
" unlet w:matchup_oldstatus
" endif
" if get(w:, 'matchup_oldecho', [])
" \ . (l:linenr < line('.') ? '%*%=(↑)' : ''
" show off-screen matches
if g:matchup_matchparen_status_offscreen
call matchup#matchparen#offscreen(l:current)
endif
" echo printf('%'.(&numberwidth-1).'s %s',
" \ l:close.lnum, l:close.match)
" echo printf('%'.(l:nw).'s %s', l:open.lnum, l:open.match)
" let l:offset = screencol() - wincol()
" echo printf('%'.(l:offset).'s %d', 'l', l:offscreen.lnum)
" echom screencol()
" else
" echo getline(l:offscreen.lnum)
" " echo l:open.match
" endif
" let w:matchup_oldecho = 1
" add highlighting matches
if !exists('w:matchup_match_id_list')
let w:matchup_match_id_list = []
elseif
endif
" echo map(l:corrlist, 'v:val.lnum." ".v:val.re.this')
" echo '^' l:corrlist
" echo map(l:corrlist, 'v:val')
for l:corr in l:corrlist
" echo l:corr.lnum l:corr.rematch | sleep 1
call add(w:matchup_match_id_list, matchadd('MatchParen',
\ '\%' . l:corr.lnum . 'l'
\ . '\%' . l:corr.cnum . 'c'
\ . '\%(' . l:corr.rematch . '\)'))
" echo \ '\%' . l:corr.lnum . 'l\%' . l:corr.cnum
" \ . 'c' . l:corr.re.this))
" echo '\%' . l:corr.lnum . 'l\%' . l:corr.cnum
" \ . 'c\%(' . l:corr.regex . '\)' | sleep 1
endfor
" echo '\%' . l:open.lnum . 'l\%' . l:open.cnum . 'c' . l:open.re.this
" \ '\%' . l:close.lnum . 'l\%' . l:close.cnum . 'c' . l:close.re.this
call matchup#perf#toc('matchparen.highlight', 'end')
endfunction
@@ -300,9 +191,18 @@ function! matchup#matchparen#offscreen(current) " {{{1
if empty(l:offscreen) | return | endif
let w:matchup_oldstatus = &statusline
let &statusline = s:format_statusline(l:offscreen)
endfunction
" }}}1
function! s:format_statusline(offscreen) " {{{1
let l:line = getline(a:offscreen.lnum)
let l:sl = ''
if &number
let l:nw = max([strlen(line('$')), &numberwidth-1])
let l:linenr = l:offscreen.lnum
let l:linenr = a:offscreen.lnum
if &relativenumber
let l:linenr = l:linenr-line('.')
endif
@@ -313,52 +213,41 @@ function! matchup#matchparen#offscreen(current) " {{{1
else
let l:sl .= ' '
endif
let l:line = getline(l:offscreen.lnum)
let l:lasthi = ''
"for l:idx in range(min([winwidth(0), strchars(l:line)]))
" let l:c = strlen(strcharpart(l:line, 0, l:idx))
" echo l:idx l:c | sleep 1
"endfor
" TODO use character indexing
for l:c in range(min([winwidth(0), strlen(l:line)]))
if l:offscreen.cnum <= l:c+1 && l:c+1 <= l:offscreen.cnum
\ - 1 + strlen(l:offscreen.match)
let l:curhi = 'MatchParen'
else
let l:curhi = synIDattr(
\ synID(l:offscreen.lnum, l:c+1, 1), 'name')
endif
let l:sl .= (l:curhi !=# l:lasthi ? '%#'.l:curhi.'#' : '')
if l:line[l:c] == "\t"
let l:sl .= repeat(' ', strdisplaywidth(strpart(l:line, 0, 1+l:c))
\ - strdisplaywidth(strpart(l:line, 0, l:c)))
else
let l:sl .= l:line[l:c]
endif
let l:lasthi = l:curhi
endfor
" let l:sl .= '%*' . strpart(l:line, 0, l:offscreen.cnum-1)
" \ . '%#MatchParen#'.(l:offscreen.match).'%*'
" \ . strpart(l:line, l:offscreen.cnum - 1
" \ + strlen(l:offscreen.match))
let &statusline = l:sl
else
let &statusline = getline(l:offscreen.lnum)
endif
if !&number && a:offscreen.lnum < line('.')
let l:sl = '%#Search#∆%*'
endif
let l:lasthi = ''
"for l:idx in range(min([winwidth(0), strchars(l:line)]))
" let l:c = strlen(strcharpart(l:line, 0, l:idx))
" echo l:idx l:c | sleep 1
"endfor
" TODO use character indexing
for l:c in range(min([winwidth(0), strlen(l:line)]))
if a:offscreen.cnum <= l:c+1 && l:c+1 <= a:offscreen.cnum
\ - 1 + strlen(a:offscreen.match)
let l:curhi = 'MatchParen'
else
let l:curhi = synIDattr(
\ synID(a:offscreen.lnum, l:c+1, 1), 'name')
endif
let l:sl .= (l:curhi !=# l:lasthi ? '%#'.l:curhi.'#' : '')
if l:line[l:c] == "\t"
let l:sl .= repeat(' ', strdisplaywidth(strpart(l:line, 0, 1+l:c))
\ - strdisplaywidth(strpart(l:line, 0, l:c)))
else
let l:sl .= l:line[l:c]
endif
let l:lasthi = l:curhi
endfor
return l:sl
endfunction
" }}}1
function! s:format_statusline(offscreen) " {{{1
endfunction
function! s:char_virtpos(lnum, cnum)
function! s:gchar_virtpos(lnum, cnum)
return matchstr(getline(a:lnum), '\%'.a:cnum.'v.')
endfunction

View File

@@ -132,8 +132,8 @@ function! matchup#text_obj#delimited(is_inner, visual, type) " {{{1
" special case for delete operator
if v:operator ==# 'd'
\ && strpart(getline(l:l2), l:c2) =~# '\s*$'
\ && strpart(getline(l:l2), 0, l:c1-1) =~# '^\s'
\ && strpart(getline(l:l2), l:c2) =~# '^\s*$'
\ && strpart(getline(l:l2), 0, l:c1-1) =~# '^\s*$'
let l:c1 = 1
let l:c2 = strlen(getline(l:l2))+1
endif

View File

@@ -16,118 +16,58 @@ endfunction
" }}}1
function! matchup#transmute#enable() " {{{1
augroup matchup_transmute
autocmd!
" autocmd InsertEnter * call s:transmute.setup()
" autocmd InsertLeave * call s:transmute.commit()
autocmd TextChanged,TextChangedI * call s:transmute.textchanged()
augroup END
" TODO: add insert mode map
" TODO: add g:matchup_transmute_auto
endfunction
" }}}1
function! matchup#transmute#disable() " {{{1
autocmd! matchup_transmute
endfunction
" }}}1
let s:transmute = {}
function! matchup#transmute#tick(insertmode, entering_insert) " {{{1
if !g:matchup_transmute_enabled | return 0 | endif
function! matchup#transmute#tick(insertmode, entering_insert)
if a:insertmode
return 0
endif
if changenr() > get(w:, 'matchup_transmute_last_changenr', 0)
if changenr() > get(w:, 'matchup_transmute_last_changenr', -1)
\ && !empty('w:matchup_matchparen_context.prior')
let w:matchup_transmute_last_changenr = changenr()
return s:transmute.dochange(
return matchup#transmute#dochange(
\ w:matchup_matchparen_context.prior.corrlist,
\ w:matchup_matchparen_context.prior.current,
\ w:matchup_matchparen_context.normal.current)
endif
" \ changenr()
return 0
endfunction
" let s:cancel_next = 0
function! s:transmute.textchanged() abort dict " {{{1
if !g:matchup_transmute_enabled | return | endif
" if exists('w:matchparen_current')
" echo w:matchparen_current.links.close.match
" endif
" if s:cancel_next
" return
" let s:cancel_next = 0
" endif
" call s:transmute.setup()
" call s:transmute.commit()
if !exists('w:matchup_matchparen_context')
return
endif
" echo w:matchup_matchparen_context.normal.singleton.match
" \ w:matchup_matchparen_context.insert.singleton.match
" echo w:matchup_matchparen_context.counter
" \ w:matchup_matchparen_context.normal.current.match
" \ w:matchup_matchparen_context.prior.current.match
return 0
endfunction
" }}}1
function! s:transmute.setup() abort dict " {{{1
if !g:matchup_transmute_enabled | return | endif
" XXX doesnt work because text changed already
" let l:corrlist = matchup#delim#get_matching(l:prior, 1)
" echo getline('.') | sleep 1
" echo l:prior | redraw! | sleep 1
if exists('w:transmute_state')
unlet w:transmute_state
endif
let l:prior = deepcopy(get(w:, 'matchparen_current', {}))
let l:corrlist = deepcopy(get(w:, 'matchparen_corrlist', []))
if empty(l:prior) || empty(l:corrlist)
return
endif
let w:transmute_state = {
\ 'corrlist': l:corrlist,
\ 'prior': l:prior
\}
endfunction
" }}}1
function! s:transmute.commit() abort dict " {{{1
"echo 'commit' reltime() | sleep 1
endfunction
" }}} 1
function! s:transmute.dochange(list, pri, cur) abort dict " {{{1
" if !g:matchup_transmute_enabled | return | endif
" echo 'doing change' a:pri.class a:cur.class
function! matchup#transmute#dochange(list, pri, cur) " {{{1
if empty(a:list) || empty(a:pri) || empty(a:cur) | return 0 | endif
" so far only same-class changes are supported
if a:pri.class[0] != a:cur.class[0]
let l:cur = a:cur
" check back one
if a:pri.class[0] != l:cur.class[0]
let l:cur = matchup#delim#get_current('all', a:pri.side,
\ {'insertmode': 1})
if empty(l:cur) | return 0 | endif
endif
" right now, only same-class changes are supported
if a:pri.class[0] != l:cur.class[0]
return 0
endif
let l:num_changes = 0
let l:delta = strdisplaywidth(a:cur.match)
let l:delta = strdisplaywidth(l:cur.match)
\ - strdisplaywidth(a:pri.match)
for l:i in range(len(a:list))
@@ -137,7 +77,7 @@ function! s:transmute.dochange(list, pri, cur) abort dict " {{{1
let l:line = getline(l:corr.lnum)
let l:column = l:corr.cnum
if l:corr.lnum == a:cur.lnum && l:i > a:pri.match_index
if l:corr.lnum == l:cur.lnum && l:i > a:pri.match_index
let l:column += l:delta
endif
@@ -150,7 +90,7 @@ function! s:transmute.dochange(list, pri, cur) abort dict " {{{1
\ g:matchup#re#not_bslash.'\\'.l:grp))-1
if l:count == 0 | continue | endif
if a:cur.groups[l:grp] ==# l:groups[l:grp]
if l:cur.groups[l:grp] ==# l:groups[l:grp]
continue
endif
@@ -160,12 +100,12 @@ function! s:transmute.dochange(list, pri, cur) abort dict " {{{1
\ '\=''\zs'.(l:groups[l:grp]).'\ze''', '')
let l:pattern = matchup#delim#fill_backrefs(l:pattern,
\ l:groups, 0)
let l:string = a:cur.groups[l:grp]
let l:string = l:cur.groups[l:grp]
let l:line = substitute(l:line, l:pattern,
\ '\='''.l:string."'", '')
endfor
let l:groups[l:grp] = a:cur.groups[l:grp]
let l:groups[l:grp] = l:cur.groups[l:grp]
endfor
if getline(l:corr.lnum) !=# l:line
@@ -177,7 +117,6 @@ function! s:transmute.dochange(list, pri, cur) abort dict " {{{1
endfor
return l:num_changes
endfunction
" }}}1