mirror of
https://github.com/chenasraf/vim-matchup.git
synced 2026-05-18 01:38:57 +00:00
Cleanup matchparen, fix transmute, fix bug in da%
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user