if exists( "g:__XPREPLACE_VIM__" ) && g:__XPREPLACE_VIM__ >= XPT#ver finish endif let g:__XPREPLACE_VIM__ = XPT#ver let s:oldcpo = &cpo set cpo-=< cpo+=B runtime plugin/debug.vim runtime plugin/xpmark.vim let s:log = CreateLogger( 'warn' ) let s:log = CreateLogger( 'debug' ) fun! s:InitBuffer() if exists( 'b:__xpr_init' ) return endif let b:__xpr_init = { 'settingSwitch' : xpt#settingswitch#New() } call xpt#settingswitch#AddList(b:__xpr_init.settingSwitch, [ '&l:textwidth', '0' ], [ '&l:virtualedit', 'onemore' ], [ '&l:whichwrap' , 'b,s,h,l,<,>,~,[,]' ], [ '&l:selection' , 'exclusive' ], [ '&l:selectmode' , '' ], ) endfunction fun! XPRstartSession() call s:InitBuffer() if exists( 'b:_xpr_session' ) throw "xpreplace session already pushed" return endif let b:_xpr_session = {} call xpt#settingswitch#Switch(b:__xpr_init.settingSwitch) let b:_xpr_session.savedReg = @" let @" = 'XPreplaceInited' endfunction fun! XPRendSession() if !exists( 'b:_xpr_session' ) throw "no setting pushed" return endif let @" = b:_xpr_session.savedReg call xpt#settingswitch#Restore(b:__xpr_init.settingSwitch) unlet b:_xpr_session endfunction fun! XPreplaceByMarkInternal(startMark,endMark,replacement) let [start,end] = [XPMpos(a:startMark),XPMpos(a:endMark)] if start == [0,0] || end == [0,0] throw 'XPM:' . ' ' . a:startMark . ' or ' . a:endMark . 'is invalid' endif let pos = XPreplaceInternal( start, end, a:replacement, { 'doJobs' : 0 } ) call XPMupdateWithMarkRangeChanging(a:startMark,a:endMark,start,pos) return pos endfunction fun! XPreplaceInternal(start,end,replacement,...) let option = { 'doJobs' : 1, 'saveHoriScroll' : 0 } if a:0 == 1 call extend( option, a:1, 'force' ) endif let replacement = a:replacement let repLines = split( a:replacement, '\n', 1 ) if option.doJobs call s:doPreJob(a:start,a:end,replacement) endif if 0 let [curNrLines,finalNrLines] = [a:end[0] - a:start[0] + 1,len(repLines)] let [ s, e ] = [ 1, col( [ a:end[ 0 ], '$' ] ) ] let repLines[0] = XPT#TextInLine(a:start[0],s,a:start[1]) . repLines[0] let repLines[-1] .= XPT#TextInLine(a:end[0],a:end[1],e) let positionAfterReplacement = [a:end[0] + (finalNrLines - curNrLines),a:end[1] - len(getline(a:end[0]))] if curNrLines > finalNrLines call cursor(a:start) if curNrLines > finalNrLines + 1 exe 'silent!' 'normal!' 'zOd' ( finalNrLines - curNrLines - 1 ) 'j' else silent! normal! zOdd endif elseif curNrLines < finalNrLines call append( a:start[ 0 ], repeat( [ '' ], finalNrLines - curNrLines ) ) endif call setline(a:start[0],repLines) let positionAfterReplacement[1] += len(getline(positionAfterReplacement[0])) call cursor(positionAfterReplacement) silent! normal! zO else call cursor(a:start) silent! normal! zO call cursor(a:start) if a:start != a:end silent! normal! v call cursor(a:end) silent! normal! dzO call cursor(a:start) endif if replacement != '' let positionAfterReplacement = s:Replace_standard(a:start,a:end,replacement) else let positionAfterReplacement = [ line("."), col(".") ] endif endif if option.doJobs call s:doPostJob(a:start,positionAfterReplacement,replacement) endif return positionAfterReplacement endfunction fun! s:Replace_standard(start,end,replacement) let replacement = a:replacement let bStart = [a:start[0] - line( '$' ), a:start[1] - len(getline(a:start[0]))] call cursor(a:start) let ifPasteAtEnd = ( col( [ a:start[0], '$' ] ) == a:start[1] && a:start[1] > 1 ) let @" = replacement . ';' if ifPasteAtEnd call cursor(a:start[0],a:start[1] - 1) let char = matchstr( getline( '.' ), '\v.$' ) let @" = char . replacement . ';' silent! normal! ""P else if col( "." ) == len( getline( line( "." ) ) ) + 1 silent! normal! ""p else silent! normal! ""P endif endif let positionAfterReplacement = [ bStart[0] + line( '$' ), 0 ] let positionAfterReplacement[1] = bStart[1] + len(getline(positionAfterReplacement[0])) call cursor(a:start) k' call cursor(positionAfterReplacement) silent! '',.foldopen! if ifPasteAtEnd call cursor(positionAfterReplacement[0],positionAfterReplacement[1] - 1 - len(char)) silent! normal! DzO else call cursor(positionAfterReplacement) if positionAfterReplacement[1] == len(getline(positionAfterReplacement[0])) + 1 && positionAfterReplacement[1] > 1 call cursor(positionAfterReplacement[0],positionAfterReplacement[1] - 1) silent! normal! xzO else silent! normal! XzO endif endif let positionAfterReplacement = [ bStart[0] + line( '$' ), 0 ] let positionAfterReplacement[1] = bStart[1] + len(getline(positionAfterReplacement[0])) return positionAfterReplacement endfunction fun! s:Replace_gp(start,end,replacement) let replacement = a:replacement let bStart = [a:start[0] - line( '$' ), a:start[1] - len(getline(a:start[0]))] call cursor(a:start) let ifPasteAtEnd = ( col( [ a:start[0], '$' ] ) == a:start[1] && a:start[1] > 1 ) let @" = replacement . ';' call cursor(a:start) silent! normal! ""gPzOXzO let positionAfterReplacement = [ line( "." ), col( "." ) ] return positionAfterReplacement endfunction fun! XPreplace(start,end,replacement,...) let option = { 'doJobs' : 1 } if a:0 == 1 call extend(option, a:1, 'force') endif call XPRstartSession() let positionAfterReplacement = a:end try let positionAfterReplacement = XPreplaceInternal(a:start,a:end,a:replacement,option) catch /.*/ call XPT#warn(v:exception) call XPT#warn(v:throwpoint) finally call XPRendSession() endtry return positionAfterReplacement endfunction let s:_xpreplace = { 'post' : {}, 'pre' : {} } fun! XPRaddPreJob(functionName) let s:_xpreplace.pre[a:functionName] = function(a:functionName) endfunction fun! XPRaddPostJob(functionName) let s:_xpreplace.post[a:functionName] = function(a:functionName) endfunction fun! XPRremovePreJob(functionName) let d = s:_xpreplace.pre if has_key(d,a:functionName) unlet d[a:functionName] endif endfunction fun! XPRremovePostJob(functionName) let d = s:_xpreplace.post if has_key(d,a:functionName) unlet d[a:functionName] endif endfunction fun! s:doPreJob(start,end,replacement) let d = { 'f' : '' } for d.f in values(s:_xpreplace.pre) call d.f(a:start,a:end) endfor endfunction fun! s:doPostJob(start,end,replacement) let d = { 'f' : '' } for d.f in values(s:_xpreplace.post) call d.f(a:start,a:end) endfor endfunction let &cpo = s:oldcpo