1
Files
flake-nixinator/config/neovim/store/lazy-plugins/NrrwRgn/autoload/nrrwrgn.vim

1638 lines
49 KiB
VimL
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

" nrrwrgn.vim - Narrow Region plugin for Vim
" -------------------------------------------------------------
" Version: 0.33
" Maintainer: Christian Brabandt <cb@256bit.org>
" Last Change: Thu, 15 Jan 2015 20:52:29 +0100
" Script: http://www.vim.org/scripts/script.php?script_id=3075
" Copyright: (c) 2009-2015 by Christian Brabandt
" The VIM LICENSE applies to NrrwRgn.vim
" (see |copyright|) except use "NrrwRgn.vim"
" instead of "Vim".
" No warranty, express or implied.
" *** *** Use At-Your-Own-Risk! *** ***
" GetLatestVimScripts: 3075 33 :AutoInstall: NrrwRgn.vim
"
" Functions:
let s:numeric_sort = v:version > 704 || v:version == 704 && has("patch341")
let s:getcurpos = exists('*getcurpos')
let s:window_type = {"source": 0, "target": 1}
fun! <sid>WarningMsg(msg) abort "{{{1
let msg = "NarrowRegion: ". a:msg
echohl WarningMsg
if exists(":unsilent") == 2
unsilent echomsg msg
else
echomsg msg
endif
sleep 1
echohl Normal
let v:errmsg = msg
endfun
fun! <sid>Init() abort "{{{1
if !exists("s:opts")
" init once
let s:opts = []
endif
if !exists("s:instn")
let s:instn=1
if !exists("g:nrrw_custom_options") || empty(g:nrrw_custom_options)
let s:opts=<sid>Options('local to buffer')
endif
else
" Prevent accidently overwriting windows with instn_id set
" back to an already existing instn_id
let s:instn = (s:instn==0 ? 1 : s:instn)
while (has_key(s:nrrw_rgn_lines, s:instn))
let s:instn+=1
endw
endif
call <sid>SetupHooks()
if !exists("s:nrrw_rgn_lines")
let s:nrrw_rgn_lines = {}
endif
let s:nrrw_rgn_lines[s:instn] = {}
" show some debugging messages
let s:nrrw_winname='NrrwRgn'
" Customization
let s:nrrw_rgn_vert = get(g:, 'nrrw_rgn_vert', 0)
let s:nrrw_rgn_wdth = get(g:, 'nrrw_rgn_wdth', 20)
let s:nrrw_rgn_hl = get(g:, 'nrrw_rgn_hl', 'WildMenu')
let s:nrrw_rgn_nohl = get(g:, 'nrrw_rgn_nohl', 0)
let s:debug = (exists("s:debug") ? s:debug : 0)
let s:float = has('float')
let s:syntax = has('syntax')
if v:version < 704
call s:WarningMsg('NrrwRgn needs Vim > 7.4 or it might not work correctly')
endif
endfun
fun! <sid>SetupHooks() abort "{{{1
if !exists("s:nrrw_aucmd")
let s:nrrw_aucmd = {}
endif
if exists("b:nrrw_aucmd_create")
let s:nrrw_aucmd["create"] = b:nrrw_aucmd_create
endif
if exists("b:nrrw_aucmd_writepost")
let s:nrrw_aucmd["writepost"] = b:nrrw_aucmd_writepost
endif
if exists("b:nrrw_aucmd_close")
let s:nrrw_aucmd["close"] = b:nrrw_aucmd_close
endif
if get(g:, 'nrrw_rgn_write_on_sync', 0)
let b:nrrw_aucmd_written = get(b:, 'nrrw_aucmd_written', ''). '|:w'
endif
endfun
fun! <sid>NrrwRgnWin(bang) abort "{{{1
" Create new scratch window
if has_key(s:nrrw_rgn_lines, s:instn) &&
\ has_key(s:nrrw_rgn_lines[s:instn], 'multi')
let bufname = 'multi'
else
let bufname = matchstr(substitute(expand('%:t:r'), ' ', '_', 'g'), '^.\{0,8}')
endif
let nrrw_winname = s:nrrw_winname. '_'. bufname . '_'. s:instn
let nrrw_win = bufwinnr('^'.nrrw_winname.'$')
if nrrw_win != -1
exe ":noa ". nrrw_win. 'wincmd w'
" just in case, a global nomodifiable was set
" disable this for the narrowed window
setl ma noro
silent %d _
else
if !exists('g:nrrw_topbot_leftright')
let g:nrrw_topbot_leftright = 'topleft'
endif
let nrrw_rgn_direction = (s:nrrw_rgn_vert ? 'vsp' : 'sp')
if get(g:, 'nrrw_rgn_equalalways', &equalalways)
let cmd=printf(':noa %s %s %s', g:nrrw_topbot_leftright,
\ nrrw_rgn_direction,
\ nrrw_winname)
else
let nrrw_rgn_size = (s:nrrw_rgn_vert ? winwidth(0) : winheight(0))/2
let cmd=printf(':noa %s %d%s %s', g:nrrw_topbot_leftright,
\ nrrw_rgn_size,
\ nrrw_rgn_direction,
\ nrrw_winname)
endif
if !a:bang
exe cmd
else
try
enew
if bufexists(s:nrrw_winname. '_'. s:instn)
" avoid E95
exe 'bw' s:nrrw_winname. '_'. s:instn
endif
exe 'f' s:nrrw_winname. '_'. s:instn
catch /^Vim\%((\a\+)\)\=:E37/ " catch error E37
" Fall back and use a new window
exe cmd
endtry
endif
" just in case, a global nomodifiable was set
" disable this for the narrowed window
setl ma noro
" Just in case
silent %d _
" Set up some options like 'bufhidden', 'noswapfile',
" 'buftype', 'bufhidden', when enabling Narrowing.
call <sid>NrrwSettings(1)
let nrrw_win = bufwinnr("")
endif
" focus: target
" set window variables
let w:nrrw_rgn_id = s:instn
let w:nrrw_rgn_id_type = s:window_type["target"]
if !a:bang
noa wincmd p
" focus: source window
let w:nrrw_rgn_id = s:instn
let w:nrrw_rgn_id_type = s:window_type["source"]
noa wincmd p
" focus: target window
endif
" We are in the narrowed buffer now!
return nrrw_win
endfun
fun! <sid>CleanRegions() abort "{{{1
let s:nrrw_rgn_line={}
unlet! s:nrrw_rgn_buf
endfun
fun! <sid>CompareNumbers(a1,a2) abort "{{{1
return (a:a1+0) == (a:a2+0) ? 0 : (a:a1+0) > (a:a2+0) ? 1 : -1
endfun
fun! <sid>ParseList(dict) "{{{1
" for a given list of line numbers, return those line numbers
" in a format start:end for continous items, else [start, next]
" returns a dict of dict: dict[buf][1]=[1,10], dict[buf][2]=[15,20]
let outdict = {}
let i=1
let list = a:dict
for buf in sort(keys(a:dict), (s:numeric_sort ? 'n' : '<sid>CompareNumbers'))
let result = {}
let start = 0
let temp = 0
let item = 0
for item in sort(list[buf], (s:numeric_sort ? 'n' : "<sid>CompareNumbers"))
if start==0
let start=item
elseif temp!=item-1
if has_key(result, i)
let i+=1
endif
let result[i]=[start,temp]
let start=item
endif
let temp=item
endfor
if empty(result)
" add all items from the list to the result
" list consists only of consecutive items
let result[i] = [list[buf][0], list[buf][-1]]
endif
" Make sure the last item is included in the selection
if get(result, i, 0)[0] && result[i][1] != item
let i+=1
let result[i]=[start,item]
endif
let outdict[buf] = result
let i+=1
endfor
return outdict
endfun
fun! <sid>GoToWindow(buffer, instn, type) abort "{{{1
" find correct window and switch to it
" should be called from correct tab page
for win in range(1,winnr('$'))
exe ':noa '. win. 'wincmd w'
if get(w:, 'nrrw_rgn_id', 0) == a:instn && get(w:, 'nrrw_rgn_id_type', -1) == a:type
break
endif
endfor
if bufnr('') == a:buffer
return
else
exe ":noa ". a:buffer. "b"
endif
endfun
fun! <sid>WriteNrrwRgn(...) abort "{{{1
" if argument is given, write narrowed buffer back
" else destroy the narrowed window
let nrrw_instn = exists("b:nrrw_instn") ? b:nrrw_instn : s:instn
if exists("b:orig_buf") && (bufwinnr(b:orig_buf) == -1) &&
\ !<sid>BufInTab(b:orig_buf) &&
\ !bufexists(b:orig_buf)
call s:WarningMsg("Original buffer does no longer exist! Aborting!")
return
endif
if exists("a:1") && a:1
" Write the buffer back to the original buffer
let _wsv = winsaveview()
setl nomod
exe ":WidenRegion"
if bufname('') !~# 'NrrwRgn' && bufwinnr(s:nrrw_winname. '_'. s:instn) > 0
exe ':noa'. bufwinnr(s:nrrw_winname. '_'. s:instn). 'wincmd w'
endif
" prevent E315
call winrestview(_wsv)
" Execute "writepost" autocommands in narrowed buffer
if exists("b:nrrw_aucmd_writepost")
exe b:nrrw_aucmd_writepost
endif
else
call <sid>StoreLastNrrwRgn(nrrw_instn)
" b:orig_buf might not exists (see issue #2)
let winnr = (exists("b:orig_buf") ? bufwinnr(b:orig_buf) : 0)
" Best guess
if bufname('') =~# 'NrrwRgn' && winnr == -1 && exists("b:orig_buf") &&
\ bufexists(b:orig_buf)
exe ':noa '. b:orig_buf. 'b'
elseif bufname('') =~# 'NrrwRgn' && winnr > 0
exe ':noa'. winnr. 'wincmd w'
endif
" close narrowed buffer
call <sid>NrrwRgnAuCmd(nrrw_instn)
endif
endfun
fun! <sid>SaveRestoreRegister(values) abort "{{{1
if empty(a:values)
" Save
let reg = ['a', getreg('a'), getregtype('a') ]
let fold = [ &fen, &l:fdm ]
if &fen
setl nofoldenable
endif
let visual = [getpos("'<"), getpos("'>")]
return [ reg, fold, visual ]
else
" Restore
call call('setreg', a:values[0])
if a:values[1][0]
let [&l:fen, &l:fdm]=a:values[1]
endif
call setpos("'<", a:values[2][0])
call setpos("'>", a:values[2][1])
endif
endfun
fun! <sid>UpdateOrigWin() abort "{{{
" Tries to keep the original windo in the same viewport, that
" is currently being edited in the narrowed window
if !get(g:, 'nrrw_rgn_update_orig_win', 0)
return
endif
if bufname('') !~# 'NrrwRgn'
return
else
let instn = b:nrrw_instn
endif
if !has_key(s:nrrw_rgn_lines[instn], 'multi')
return
endif
if exists("b:orig_buf") && (bufwinnr(b:orig_buf) == -1) &&
\ !<sid>BufInTab(b:orig_buf) &&
\ !bufexists(b:orig_buf)
" Buffer does not exists anymore (shouldn't happen)
return
endif
let cur_win = winnr()
try
if !exists("b:nrrw_rgn_prev_pos")
let b:nrrw_rgn_prev_pos = getpos(".")
endif
if b:nrrw_rgn_prev_pos[0] == line('.')
return
endif
" Try to update the original window
let start = search(' Start NrrwRgn\d\+', 'bcWn')
if start == 0
" not found
return
endif
let region = matchstr(getline(start),
\ ' Start NrrwRgn\zs\d\+\ze')+0
let offset = line('.') - start
exe ":noa" bufwinnr(b:orig_buf). 'wincmd w'
let pos = s:nrrw_rgn_lines[instn].multi[region]
if pos[0] + offset > pos[1]
" safety check
let offset = pos[1] - pos[0]
endif
call cursor(pos[0]+offset, pos[1])
redraw
finally
exe ":noa" cur_win "wincmd w"
let b:nrrw_rgn_prev_pos = getpos(".")
endtry
endfun!
fun! <sid>SetupBufWriteCmd(instn) "{{{1
if !exists("#NrrwRgn".a:instn."#BufWriteCmd#<buffer>")
if s:debug
echo "Setting up BufWriteCmd!"
endif
au BufWriteCmd <buffer> nested :call s:WriteNrrwRgn(1)
endif
endfu
fun! <sid>SetupBufWinLeave(instn) "{{{1
if !exists("#NrrwRgn".a:instn."#BufWinLeave#<buffer>") &&
\ exists("b:orig_buf") && bufloaded(b:orig_buf)
au BufWinLeave <buffer> :call s:NRBufWinLeave()
endif
endfu
fun! <sid>SetupWinLeave(instn) "{{{1
if !exists("#NrrwRgn".a:instn."#WinLeave#<buffer>")
exe "au WinLeave <buffer> :call s:NRWinLeave(".a:instn.")"
endif
endfu
fun! <sid>NRWinLeave(instn) "{{{1
let orig_buf = s:nrrw_rgn_lines[a:instn].orig_buf
let orig_tab = tabpagenr()
call <sid>JumpToBufinTab(<sid>BufInTab(b:orig_buf), orig_buf, a:instn, s:window_type["source"])
:sil doautocmd <nomodeline> WinEnter
endfu
fun! <sid>NRBufWinLeave() "{{{1
let instn = getbufvar(expand("<afile>"), 'nrrw_instn')
let nrw_buf = bufnr('')
let orig_buf = getbufvar(expand("<afile>"), 'orig_buf')
let orig_tab = tabpagenr()
call <sid>JumpToBufinTab(<sid>BufInTab(orig_buf), orig_buf, instn, s:window_type["source"])
if !&modifiable
set modifiable
endif
call s:DeleteMatches(instn)
" don't jump back to target window, it will be closed
"call <sid>JumpToBufinTab(orig_tab, nrw_buf, instn, s:window_type["target"])
endfu
fun! <sid>NrrwRgnAuCmd(instn) abort "{{{1
" If a:instn==0, then enable auto commands
" else disable auto commands for a:instn
if !a:instn
exe "aug NrrwRgn". b:nrrw_instn
au!
"au BufWriteCmd <buffer> nested :call s:WriteNrrwRgn(1)
" don't clean up on BufWinLeave autocommand, that breaks
" :b# and returning back to that buffer later (see issue #44)
au BufWipeout,BufDelete <buffer> nested
\ :call s:WriteNrrwRgn()
au CursorMoved <buffer> :call s:UpdateOrigWin()
" When switching buffer in the original buffer,
" make sure the highlighting of the narrowed buffer will
" be removed"
call s:SetupBufWinLeave(b:nrrw_instn)
call s:SetupWinLeave(b:nrrw_instn)
call s:SetupBufWriteCmd(b:nrrw_instn)
aug end
au BufWinEnter <buffer> call s:SetupBufWriteCmd(b:nrrw_instn)
else
exe "aug NrrwRgn". a:instn
au!
aug end
exe "aug! NrrwRgn". a:instn
if !has_key(s:nrrw_rgn_lines, a:instn)
" narrowed buffer was already cleaned up
call <sid>DeleteMatches(a:instn)
call s:WarningMsg("Window was already cleaned up. Nothing to do.")
return
endif
" make the original buffer modifiable, if possible
let buf = s:nrrw_rgn_lines[a:instn].orig_buf
if !getbufvar(buf, '&l:ma') && !getbufvar(buf, 'orig_buf_ro')
call setbufvar(s:nrrw_rgn_lines[a:instn].orig_buf, '&ma', 1)
endif
if s:debug
echo printf("bufnr: %d a:instn: %d\n", bufnr(''), a:instn)
echo "bwipe " s:nrrw_winname. '_'. a:instn
endif
if (!has_key(s:nrrw_rgn_lines[a:instn], 'disable') ||
\ (has_key(s:nrrw_rgn_lines[a:instn], 'disable') &&
\ !s:nrrw_rgn_lines[a:instn].disable ))
" Skip to original window and remove highlighting
call <sid>GoToWindow(buf, a:instn, s:window_type["source"])
call <sid>DeleteMatches(a:instn)
unlet! w:nrrw_rgn_id w:nrrw_rgn_id_type
call <sid>CleanUpInstn(a:instn)
endif
endif
endfun
fun! <sid>CleanUpInstn(instn) abort "{{{1
if s:instn>=1 && has_key(s:nrrw_rgn_lines, a:instn)
unlet s:nrrw_rgn_lines[a:instn]
let s:instn-=1
endif
endfu
fun! <sid>StoreLastNrrwRgn(instn) abort "{{{1
" Only store the last region, when the narrowed instance is still valid
if !has_key(s:nrrw_rgn_lines, a:instn)
call <sid>WarningMsg("Error storing the last Narrowed Window, it's invalid!")
return
endif
let s:nrrw_rgn_lines['last'] = []
if !exists("b:orig_buf")
let orig_buf = s:nrrw_rgn_lines[a:instn].orig_buf
else
let orig_buf = b:orig_buf
endif
if has_key(s:nrrw_rgn_lines[a:instn], 'multi')
call add(s:nrrw_rgn_lines['last'], [ orig_buf,
\ s:nrrw_rgn_lines[a:instn]['multi']])
else
" Linewise narrowed region, pretend it was done like a visual
" narrowed region
let s:nrrw_rgn_lines['last'] = [ [ orig_buf,
\ s:nrrw_rgn_lines[a:instn].start[1:]],
\ [ orig_buf, s:nrrw_rgn_lines[a:instn].end[1:]]]
call add(s:nrrw_rgn_lines['last'],
\ has_key(s:nrrw_rgn_lines[a:instn], 'vmode') ?
\ s:nrrw_rgn_lines[a:instn].vmode : 'V')
endif
endfu
fun! <sid>RetVisRegionPos() abort "{{{1
let a = getpos("'<")
let b = getpos("'>")
let a[2] = virtcol("'<")
let b[2] = virtcol("'>")
return [a, b]
endfun
fun! <sid>GeneratePattern(startl, endl, mode) abort "{{{1
" This is just a best guess, the highlighted block could still be wrong
" There are basically two ways, highlighting works in block mode:
" 1) only highlight the block
" 2) highlighty from the beginnning until the end of lines (happens,
" intermediate lines are shorter than block width)
if exists("s:curswant") && s:curswant == 2147483647 &&
\ a:startl[0] > 0 && a:startl[1] > 0 && a:mode ==# ''
unlet! s:curswant
return '\%>'. (a:startl[0]-1). 'l\&\%>'. (a:startl[1]-1).
\ 'v\&\%<'. (a:endl[0]+1). 'l'
elseif a:mode ==# '' && a:startl[0] > 0 && a:startl[1] > 0
return '\%>'. (a:startl[0]-1). 'l\&\%>'. (a:startl[1]-1).
\ 'v\&\%<'. (a:endl[0]+1). 'l\&\%<'. (a:endl[1]+1). 'v'
elseif a:mode ==# 'v' && a:startl[0] > 0 && a:startl[1] > 0
" Easy way: match within a line
if a:startl[0] == a:endl[0]
return '\%'.a:startl[0]. 'l\%>'.(a:startl[1]-1).'v.*\%<'.(a:endl[1]+1).'v'
else
" Need to generate concat 3 patterns:
" 1) from startline, startcolumn till end of line
" 2) all lines between startline and end line
" 3) from start of endline until end column
"
" example: Start at line 1 col. 6 until line 3 column 12:
" \%(\%1l\%>6v.*\)\|\(\%>1l\%<3l.*\)\|\(\%3l.*\%<12v\)
return '\%(\%'. (a:startl[0]). 'l\%>'. (a:startl[1]-1). 'v.*\)\|'.
\ '\%(\%>'. (a:startl[0]). 'l\%<'. (a:endl[0]). 'l.*\)\|'.
\ '\%(\%'. (a:endl[0]). 'l.*\%<'. (a:endl[1]+1). 'v\)'
endif
elseif a:startl[0] > 0
return '\%>'. (a:startl[0]-1). 'l\&\%<'. (a:endl[0]+1). 'l'
else
return ''
endif
endfun
fun! <sid>Options(search) abort "{{{1
" return buffer local options (generated from $VIMRUNTIME/doc/options.txt
return
\ ['autoindent', 'autoread', 'balloonexpr', 'binary', 'bomb',
\ 'cindent', 'cinkeys', 'cinoptions', 'cinwords', 'commentstring',
\ 'complete', 'completefunc', 'copyindent', 'cryptmethod', 'define',
\ 'dictionary', 'endofline', 'equalprg', 'errorformat', 'expandtab',
\ 'fileencoding', 'filetype', 'formatoptions', 'formatlistpat',
\ 'formatexpr', 'iminsert', 'imsearch', 'include', 'includeexpr',
\ 'indentexpr', 'indentkeys', 'infercase', 'key', 'keymap', 'lisp',
\ 'makeprg', 'matchpairs', 'nrformats', 'omnifunc', 'osfiletype',
\ 'preserveindent', 'quoteescape', 'shiftwidth', 'shortname', 'smartindent',
\ 'softtabstop', 'spellcapcheck', 'spellfile', 'spelllang', 'suffixesadd',
\ 'synmaxcol', 'syntax', 'tabstop', 'textwidth', 'thesaurus', 'wrapmargin']
" old function, only used to generate above list
let c=[]
let buf=bufnr('')
try
" empty search pattern
if empty(a:search)
return c
endif
silent noa sview $VIMRUNTIME/doc/options.txt
" for whatever reasons $VIMRUNTIME/doc/options.txt
" does not exist, return empty list
if line('$') == 1
return c
endif
keepj 0
let reg_a=[]
call add(reg_a, 'a')
call add(reg_a,getreg('a'))
call add(reg_a, getregtype('a'))
let @a=''
exe "silent :g/". '\v'.escape(a:search, '\\/'). "/-y A"
let b=split(@a, "\n")
call call('setreg', reg_a)
"call setreg('a', reg_a[0], reg_a[1])
call filter(b, 'v:val =~ "^''"')
" the following options should be set
let filter_opt='\%(modifi\%(ed\|able\)\|readonly\|swapfile\|'.
\ 'buftype\|bufhidden\|foldcolumn\|buflisted\|undofile\)'
call filter(b, 'v:val !~ "^''".filter_opt."''"')
for item in b
let item=substitute(item, '''', '', 'g')
call add(c, split(item, '\s\+')[0])
endfor
finally
if fnamemodify(bufname(''),':p') ==
\expand("$VIMRUNTIME/doc/options.txt")
noa bwipe
endif
exe "noa " bufwinnr(buf) "wincmd w"
return c
endtry
endfun
fun! <sid>GetOptions(opt) abort "{{{1
if exists("g:nrrw_custom_options") && !empty(g:nrrw_custom_options)
let result = g:nrrw_custom_options
else
let result={}
for item in a:opt
try
exe "let result[item]=&l:".item
catch
" no-op, just silence the error
endtry
endfor
endif
return result
endfun
fun! <sid>SetOptions(opt) abort "{{{1
if type(a:opt) == type({})
for [option, result] in items(a:opt)
exe "let &l:". option " = " string(result)
endfor
endif
setl nomod noro
endfun
fun! <sid>CheckProtected() abort "{{{1
" Protect the original window, unless the user explicitly defines not to
" protect it
if exists("g:nrrw_rgn_protect") && g:nrrw_rgn_protect =~? 'n'
return
endif
let b:orig_buf_ro=0
if !&l:ma || &l:ro
let b:orig_buf_ro=1
call s:WarningMsg("Buffer is protected, won't be able to write the changes back!")
else
" Protect the original buffer,
" so you won't accidentally modify those lines,
" that might later be overwritten
setl noma
endif
endfun
fun! <sid>HasMatchID(instn) abort "{{{1
if exists("s:nrrw_rgn_lines[a:instn].matchid")
let id = s:nrrw_rgn_lines[a:instn].matchid
for val in getmatches()
if match(id, val.id) > -1
return 1
endif
endfor
endif
return 0
endfun
fun! <sid>DeleteMatches(instn) abort "{{{1
if exists("s:nrrw_rgn_lines[a:instn].matchid")
" if you call :NarrowRegion several times, without widening
" the previous region, b:matchid might already be defined so
" make sure, the previous highlighting is removed.
for item in s:nrrw_rgn_lines[a:instn].matchid
if item > 0
" If the match has been deleted, discard the error
try
call matchdelete(item)
call remove(s:nrrw_rgn_lines[a:instn].matchid, 0)
catch
" id not found ignore
endtry
endif
endfor
endif
endfun
fun! <sid>HideNrrwRgnLines() abort "{{{1
let char1 = <sid>ReturnComments()[0]
let char1 = escape(char1, '"\\')
let cmd='syn match NrrwRgnStart "^'.char1.' Start NrrwRgn\d\+$"'
exe cmd
let cmd='syn match NrrwRgnEnd "^'.char1.' End NrrwRgn\d\+$"'
exe cmd
exe 'syn region NrrwRgn '.
\ ' start="^\ze'. char1.' Start NrrwRgn"'.
\ ' skip="'.char1.' Start NrrwRgn\(\d\+\)\_.\{-}End NrrwRgn\1$"'.
\ ' end="^$" fold transparent'
hi default link NrrwRgnStart Comment
hi default link NrrwRgnEnd Comment
setl fdm=syntax
endfun
fun! <sid>ReturnCommentFT() abort "{{{1
if !empty(&l:commentstring)
return substitute(&l:commentstring, '%s', ' ', '')
else
return "# "
endif
endfun
fun! <sid>WidenRegionMulti(content, instn) abort "{{{1
" for single narrowed windows, the original narrowed buffer will be closed,
" so don't renew the highlighting and clean up (later in
" nrrwrgn#WidenRegion)
if empty(s:nrrw_rgn_lines[a:instn].multi)
return
endif
" we are not yet in the correct buffer, start loading it
let _hid = &hidden
set hidden
let c_win = winnr()
let c_buf = bufnr('')
" let's pretend, splitting windows is always possible .... :(
noa new
let s_win = winnr()
for buf in sort(keys(s:nrrw_rgn_lines[a:instn].multi), '<sid>CompareNumbers')
exe "noa ". (buf+0). "b"
let _list = []
for item in ['ma', 'ro']
call add(_list, printf("let &l:%s=%s", item, get(g:, '&l:'.item)))
endfor
setl ma noro
let output= []
let list = []
let [c_s, c_e] = <sid>ReturnComments()
let lastline = line('$')
" We must put the regions back from top to bottom,
" otherwise, changing lines in between messes up the
" list of lines that still need to put back from the
" narrowed buffer to the original buffer
for key in sort(keys(s:nrrw_rgn_lines[a:instn].multi[buf]),
\ (s:numeric_sort ? 'n' : "<sid>CompareNumbers"))
let adjust = line('$') - lastline
let range = s:nrrw_rgn_lines[a:instn].multi[buf][key]
let last = (len(range)==2) ? range[1] : range[0]
let first = range[0]
let pattern = printf("%s %%s %s %s %s%s", c_s, "NrrwRgn".key,
\ "buffer:", simplify(bufname(buf+0)), c_e)
let indexs = index(a:content, printf(pattern, 'Start')) + 1
let indexe = index(a:content, printf(pattern, 'End')) - 1
if indexs <= 0 || indexe < -1
call s:WarningMsg("Skipping Region ". key)
continue
endif
" Adjust line numbers. Changing the original buffer, might also
" change the regions we have remembered. So we must adjust these
" numbers.
" This only works, if we put the regions from top to bottom!
let first += adjust
let last += adjust
if last == line('$') && first == 1
let delete_last_line=1
else
let delete_last_line=0
endif
exe ':silent :'. first. ','. last. 'd _'
call append((first-1), a:content[indexs : indexe])
" Recalculate the start and end positions of the narrowed window
" so subsequent calls will adjust the region accordingly
let last = first + len(a:content[indexs : indexe]) - 1
if last > line('$')
let last = line('$')
endif
if !has_key(s:nrrw_rgn_lines[a:instn].multi, 'single')
" original narrowed buffer is going to be closed
" so don't renew the matches
call <sid>AddMatches(<sid>GeneratePattern([first, 0 ],
\ [last, 0], 'V'), a:instn)
endif
if delete_last_line
silent! $d _
endif
endfor
for item in _list
exe item
endfor
endfor
if !_hid
set nohidden
endif
" remove scratch window
exe ":noa ".s_win."wincmd c"
endfun
fun! <sid>AddMatches(pattern, instn) abort "{{{1
if !s:nrrw_rgn_nohl || empty(a:pattern)
if !exists("s:nrrw_rgn_lines[a:instn].matchid")
let s:nrrw_rgn_lines[a:instn].matchid=[]
endif
call add(s:nrrw_rgn_lines[a:instn].matchid,
\matchadd(s:nrrw_rgn_hl, a:pattern))
endif
endfun
fun! <sid>BufInTab(bufnr) abort "{{{1
" returns tabpage of buffer a:bufnr
if tabpagenr('$') == 1
" no tabpages present
return 1
endif
" Do not leave tab if buffer exists there
if !empty(filter(tabpagebuflist(), 'v:val == a:bufnr'))
return tabpagenr()
endif
for tab in range(1,tabpagenr('$'))
if !empty(filter(tabpagebuflist(tab), 'v:val == a:bufnr'))
return tab
endif
endfor
return 0
endfun
fun! <sid>JumpToBufinTab(tab,buf,instn,type) abort "{{{1
" Type is s:window_type["source"] or s:window_type["target"] and checks for
" w:nrrw_rgn_source_win or w:nrrw_rgn_target_win variable
if a:tab && a:tab != tabpagenr()
exe "noa tabn" a:tab
endif
call <sid>GoToWindow(a:buf, a:instn, a:type)
endfun
fun! <sid>RecalculateLineNumbers(instn, adjust) abort "{{{1
" This only matters, if the original window isn't protected
if !exists("g:nrrw_rgn_protect") || g:nrrw_rgn_protect !~# 'n'
return
endif
for instn in filter(keys(s:nrrw_rgn_lines), 'v:val != a:instn')
" Skip narrowed instances, when they are before
" the region, we are currently putting back
if s:nrrw_rgn_lines[instn].start[1] <=
\ s:nrrw_rgn_lines[a:instn].start[1]
" Skip this instn
continue
else
let s:nrrw_rgn_lines[instn].start[1] += a:adjust
let s:nrrw_rgn_lines[instn].end[1] += a:adjust
if s:nrrw_rgn_lines[instn].start[1] < 1
let s:nrrw_rgn_lines[instn].start[1] = 1
endif
if s:nrrw_rgn_lines[instn].end[1] < 1
let s:nrrw_rgn_lines[instn].end[1] = 1
endif
call <sid>DeleteMatches(instn)
call <sid>AddMatches(<sid>GeneratePattern(
\s:nrrw_rgn_lines[instn].start[1:2],
\s:nrrw_rgn_lines[instn].end[1:2],
\'V'), instn)
endif
endfor
endfun
fun! <sid>NrrwSettings(on) abort "{{{1
if a:on
setl noswapfile buftype=acwrite foldcolumn=0
setl nobuflisted
let instn = matchstr(bufname(''), '_\zs\d\+$')+0
if has_key(s:nrrw_rgn_lines, s:instn)
if !&hidden && !has_key(s:nrrw_rgn_lines[instn], "single")
setl bufhidden=wipe
endif
endif
else
setl swapfile buftype= bufhidden= buflisted
endif
endfun
fun! <sid>SetupBufLocalCommands() abort "{{{1
com! -buffer -bang WidenRegion :call nrrwrgn#WidenRegion(<bang>0)
com! -buffer -bang WR :WidenRegion<bang>
com! -buffer NRSyncOnWrite :call nrrwrgn#ToggleSyncWrite(1)
com! -buffer NRNoSyncOnWrite :call nrrwrgn#ToggleSyncWrite(0)
endfun
fun! <sid>SetupBufLocalMaps(bang) abort "{{{1
if !hasmapto('<Plug>NrrwrgnWinIncr', 'n')
nmap <buffer> <Leader><Space> <Plug>NrrwrgnWinIncr
endif
if !hasmapto('<sid>ToggleWindowSize')
nnoremap <buffer><unique><script><silent><expr> <Plug>NrrwrgnWinIncr <sid>ToggleWindowSize()
endif
if a:bang && winnr('$') == 1
" Map away :q and :q! in single window mode, so that :q won't
" accidently quit vim.
cabbr <buffer> q <c-r>=(getcmdtype()==':'&&getcmdpos()==1 ? ':bd' : ':q')<cr>
cabbr <buffer> q! <c-r>=(getcmdtype()==':'&&getcmdpos()==1 ? ':bd!' : ':q!')<cr>
endif
endfun
fun! <sid>NrrwDivNear(n, d) abort "{{{1
let m = a:n % a:d
let q = a:n / a:d
let r = m*2 >= a:d ? 1 : 0
return q + r
endfun
fun! <sid>NrrwDivCeil(n, d) abort "{{{1
let q = a:n / a:d
let r = q*a:d == a:n ? 0 : 1
return q + r
endfun
fun! <sid>IsAbsPos(pos) abort "{{{1
if s:syntax
return a:pos =~ '^\%(to\%[pleft]\|bo\%[tright]\)$'
else
return len(a:pos) >= 2 && ('topleft' =~ '^' . a:pos || 'botright' =~ '^' . a:pos)
endif
endfun
fun! <sid>GetTotalSizesFromID(id) abort "{{{1
let sizes = [0,0]
let l:count = 0
for window in range(1, winnr('$'))
let nrrw_rgn_id = getwinvar(window, 'nrrw_rgn_id', 0)
if nrrw_rgn_id == a:id
let sizes[0] += winwidth(window)
let sizes[1] += winheight(window)
let l:count += 1
endif
endfor
if l:count < 1 || l:count > 2
throw "Invalid NrrwRgn window ID count of '" . l:count . "'"
endif
return sizes
endfun
fun! <sid>GetTotalSizes(window) abort "{{{1
let nrrw_rgn_id = getwinvar(a:window, 'nrrw_rgn_id', 0)
if nrrw_rgn_id > 0
return <sid>GetTotalSizesFromID(nrrw_rgn_id)
else
throw "Expected NrrwRgn window ID"
endif
endfun
fun! <sid>GetRelVSizes(window, lines) abort "{{{1
if <sid>IsAbsPos(get(g:, 'nrrw_topbot_leftright', ''))
let lines_parent = &lines
else
let lines_parent = <sid>GetTotalSizes(a:window)[1]
endif
if s:float
let nrrw_rgn_rel_max = get(g:, 'nrrw_rgn_rel_max', 80)/100.0
let nrrw_rgn_rel_min = get(g:, 'nrrw_rgn_rel_min', 10)/100.0
let ratio = 1.0*a:lines/lines_parent
if ratio < nrrw_rgn_rel_min
let ratio = nrrw_rgn_rel_min
elseif ratio > nrrw_rgn_rel_max
let ratio = nrrw_rgn_rel_max
endif
let size_max = min([lines_parent, float2nr(ceil(nrrw_rgn_rel_max*lines_parent))])
let size_min = min([lines_parent, float2nr(ceil(nrrw_rgn_rel_min*lines_parent))])
let size_tgt = min([lines_parent, float2nr(ceil(ratio*lines_parent))])
else
let nrrw_rgn_rel_max = get(g:, 'nrrw_rgn_rel_max', 80)
let nrrw_rgn_rel_min = get(g:, 'nrrw_rgn_rel_min', 10)
let percentage = <sid>NrrwDivNear(a:lines*100, lines_parent)
if percentage < nrrw_rgn_rel_min
let percentage = nrrw_rgn_rel_min
elseif percentage > nrrw_rgn_rel_max
let percentage = nrrw_rgn_rel_max
endif
let size_max = min([lines_parent, <sid>NrrwDivCeil(nrrw_rgn_rel_max*lines_parent, 100)])
let size_min = min([lines_parent, <sid>NrrwDivCeil(nrrw_rgn_rel_min*lines_parent, 100)])
let size_tgt = min([lines_parent, <sid>NrrwDivCeil(percentage*lines_parent, 100)])
endif
let size_alt = (size_tgt >= size_max ? size_min : size_max)
return [size_tgt, size_alt]
endfun
fun! <sid>GetRelHSizes(window) abort "{{{1
if <sid>IsAbsPos(get(g:, 'nrrw_topbot_leftright', ''))
let columns_parent = &columns
else
let columns_parent = <sid>GetTotalSizes(a:window)[0]
endif
let nrrw_rgn_rel_max = get(g:, 'nrrw_rgn_rel_max', 80)
let nrrw_rgn_rel_min = get(g:, 'nrrw_rgn_rel_min', 50)
if s:float
let size_max = min([columns_parent, float2nr(ceil(nrrw_rgn_rel_max/100.0*columns_parent))])
let size_min = min([columns_parent, float2nr(ceil(nrrw_rgn_rel_min/100.0*columns_parent))])
else
let size_max = min([columns_parent, <sid>NrrwDivCeil(nrrw_rgn_rel_max*columns_parent, 100)])
let size_min = min([columns_parent, <sid>NrrwDivCeil(nrrw_rgn_rel_min*columns_parent, 100))])
endif
return [size_min, size_max]
endfun
fun! <sid>GetRelSizes(window, lines) abort "{{{1
return (s:nrrw_rgn_vert ? <sid>GetRelHSizes(a:window) : <sid>GetRelVSizes(a:window, a:lines))
endfun
fun! <sid>GetAbsVSizes(window, lines) abort "{{{1
let nrrw_rgn_incr = get(g:, 'nrrw_rgn_incr', 10)
if s:nrrw_rgn_wdth > 0
let size_min = min([s:nrrw_rgn_wdth, a:lines])
else
let size_min = winheight(a:window)
endif
let size_max = size_min + nrrw_rgn_incr
return [size_min, size_max]
endfun
fun! <sid>GetAbsHSizes(window) abort "{{{1
let nrrw_rgn_incr = get(g:, 'nrrw_rgn_incr', 10)
if s:nrrw_rgn_wdth > 0
let size_min = s:nrrw_rgn_wdth
else
let size_min = winwidth(a:window)
endif
let size_max = size_min + nrrw_rgn_incr
return [size_min, size_max]
endfun
fun! <sid>GetAbsSizes(window, lines) abort "{{{1
return (s:nrrw_rgn_vert ? <sid>GetAbsHSizes(a:window) : <sid>GetAbsVSizes(a:window, a:lines))
endfun
fun! <sid>GetSizes(window, lines) abort "{{{1
let nrrw_rgn_absolute = get(g:, 'nrrw_rgn_resize_window', 'absolute') is? "absolute" ? 1 : 0
return (nrrw_rgn_absolute ? <sid>GetAbsSizes(a:window, a:lines) : <sid>GetRelSizes(a:window, a:lines))
endfun
fun! <sid>ResizeWindow(size) abort "{{{1
let prefix = (s:nrrw_rgn_vert ? ':vert ': ''). ':resize'
let cmd = printf("%s %d", prefix, a:size)
return cmd
endfu
fun! <sid>ToggleWindowSize() abort "{{{1
" Should only be called from the narrowed window!
" assumes a narrowed window is currently focused
if has_key(s:nrrw_rgn_lines[b:nrrw_instn], 'single') && s:nrrw_rgn_lines[b:nrrw_instn].single
call <sid>WarningMsg("Resizing window for single windows not supported!")
return ''
endif
let nrrw_rgn_pad = get(g:, 'nrrw_rgn_pad', 0)
let [size_tgt, size_alt] = <sid>GetSizes(winnr(), line('$') + nrrw_rgn_pad)
let size_cur = (s:nrrw_rgn_vert ? winwidth(0) : winheight(0))
let size_new = (size_cur == size_tgt ? size_alt : size_tgt)
return <sid>ResizeWindow(size_new)."\n"
endfun
fun! <sid>AdjustWindowSize(bang) abort "{{{1
" initial window sizes
" assumes a narrowed window is currently focused
if !a:bang
let nrrw_rgn_pad = get(g:, 'nrrw_rgn_pad', 0)
let size_new = <sid>GetSizes(winnr(), line('$') + nrrw_rgn_pad)[0]
exe <sid>ResizeWindow(size_new)
endif
endfun
fun! <sid>ReturnComments() abort "{{{1
let cmt = <sid>ReturnCommentFT()
let c_s = split(cmt)[0]
let c_e = (len(split(cmt)) == 1 ? "" : " ". split(cmt)[1])
return [c_s, c_e]
endfun
fun! nrrwrgn#NrrwRgnDoMulti(...) abort "{{{1
let bang = (a:0 > 0 && !empty(a:1))
if !exists("s:nrrw_rgn_line")
call <sid>WarningMsg("You need to first select the lines to".
\ " narrow using :NRP!")
return
endif
if empty(s:nrrw_rgn_line) && !exists("s:nrrw_rgn_buf")
call <sid>WarningMsg("No lines selected from :NRP, aborting!")
return
endif
if !exists("s:nrrw_rgn_buf")
let s:nrrw_rgn_buf = <sid>ParseList(s:nrrw_rgn_line)
endif
if empty(s:nrrw_rgn_buf)
call <sid>WarningMsg("An error occured when selecting all lines. Please report as bug")
unlet s:nrrw_rgn_buf
return
endif
let o_lz = &lz
set lz
let orig_buf=bufnr('')
" initialize Variables
call <sid>Init()
call <sid>CheckProtected()
let s:nrrw_rgn_lines[s:instn].start = []
let s:nrrw_rgn_lines[s:instn].end = []
let s:nrrw_rgn_lines[s:instn].multi = s:nrrw_rgn_buf
let s:nrrw_rgn_lines[s:instn].orig_buf = orig_buf
call <sid>DeleteMatches(s:instn)
let nr=0
let lines=[]
let buffer=[]
for buf in sort(keys(s:nrrw_rgn_buf), (s:numeric_sort ? 'n' : "<sid>CompareNumbers"))
if buf !=? bufnr('%')
exe ":noa " . buf. "b"
endif
let keys = keys(s:nrrw_rgn_buf[buf])
call sort(keys, (s:numeric_sort ? 'n' : "<sid>CompareNumbers"))
"for [ nr,lines] in items(s:nrrw_rgn_buf)
let [c_s, c_e] = <sid>ReturnComments()
for nr in keys
let lines = s:nrrw_rgn_buf[buf][nr]
let start = lines[0]
let end = len(lines)==2 ? lines[1] : lines[0]
if !bang
call <sid>AddMatches(<sid>GeneratePattern([start,0],
\ [end,0], 'V'), s:instn)
endif
call add(buffer, c_s.' Start NrrwRgn'.nr.' buffer: '.simplify(bufname("")).c_e)
let buffer = buffer +
\ getline(start,end) +
\ [c_s.' End NrrwRgn'.nr. ' buffer: '.
\ simplify(bufname("")).c_e, '']
endfor
endfor
if bufnr('') !=# orig_buf
" switch back to buffer, where we started
exe ":noa ". orig_buf. "b"
endif
let local_options = <sid>GetOptions(s:opts)
let win=<sid>NrrwRgnWin(bang)
if bang
let s:nrrw_rgn_lines[s:instn].single = 1
endif
let b:orig_buf = orig_buf
call setline(1, buffer)
call <sid>AdjustWindowSize(bang)
setl nomod
let b:nrrw_instn = s:instn
call <sid>SetupBufLocalCommands()
call <sid>SetupBufLocalMaps(bang)
call <sid>NrrwRgnAuCmd(0)
call <sid>SetOptions(local_options)
call <sid>CleanRegions()
call <sid>HideNrrwRgnLines()
" restore settings
let &lz = o_lz
endfun
fun! nrrwrgn#NrrwRgn(mode, ...) range abort "{{{1
let visual = !empty(a:mode)
" a:mode is set when using visual mode
if visual
" This beeps, when called from command mode
" e.g. by using :NRV, so using :sil!
" else exiting visual mode
if s:getcurpos && a:mode ==# ''
" This is an ugly hack, since there does not seem to be a
" possibility to find out, if we are in block-wise '$' mode or
" not (try pressing '$' in block-wise mode)
if !hasmapto('let s:curswant', 'v')
xmap <expr> <Plug>NrrwrgnGetCurswant ":\<c-u>let s:curswant=".getcurpos()[4]."\n"
endif
" Reselect visual mode
exe ":norm gv\<Plug>NrrwrgnGetCurswant"
else
exe "sil! norm! \<ESC>"
endif
endif
let bang = (a:0 > 0 && !empty(a:1))
let o_lz = &lz
set lz
call <sid>Init()
if visual
let s:nrrw_rgn_lines[s:instn].vmode=a:mode
endif
" Protect the original buffer,
" so you won't accidentally modify those lines,
" that will later be overwritten
let orig_buf=bufnr('')
let _opts = <sid>SaveRestoreRegister([])
call <sid>CheckProtected()
if visual
let [ s:nrrw_rgn_lines[s:instn].start,
\ s:nrrw_rgn_lines[s:instn].end ] = <sid>RetVisRegionPos()
norm! gv"ay
if len(split(@a, "\n", 1)) !=
\ (s:nrrw_rgn_lines[s:instn].end[1] -
\ s:nrrw_rgn_lines[s:instn].start[1] + 1)
" remove trailing "\n"
let @a=substitute(@a, '\n$', '', '')
endif
let a = split(@a, "\n")
else
let first = a:firstline
let last = a:lastline
let s:nrrw_rgn_lines[s:instn].start = [ 0, first, 0, 0 ]
let s:nrrw_rgn_lines[s:instn].end = [ 0, last , 0, 0 ]
let a=getline(s:nrrw_rgn_lines[s:instn].start[1],
\ s:nrrw_rgn_lines[s:instn].end[1])
endif
call <sid>DeleteMatches(s:instn)
let local_options = <sid>GetOptions(s:opts)
let win=<sid>NrrwRgnWin(bang)
if bang && winnr('$') == 1
let s:nrrw_rgn_lines[s:instn].single = 1
else
" Set the highlighting
noa wincmd p
" Set highlighting in original window
call <sid>AddMatches(<sid>GeneratePattern(
\s:nrrw_rgn_lines[s:instn].start[1:2],
\s:nrrw_rgn_lines[s:instn].end[1:2],
\(visual ? s:nrrw_rgn_lines[s:instn].vmode : 'V')),
\s:instn)
if _opts[1][0]
" reset folding
setl foldenable
let &l:fdm=_opts[1][1]
endif
" move back to narrowed window
noa wincmd p
endif
let b:orig_buf = orig_buf
let s:nrrw_rgn_lines[s:instn].orig_buf = orig_buf
call setline(1, a)
call <sid>AdjustWindowSize(bang)
let b:nrrw_instn = s:instn
setl nomod
call <sid>SetupBufLocalCommands()
call <sid>SetupBufLocalMaps(bang)
call <sid>NrrwRgnAuCmd(0)
call <sid>SetOptions(local_options)
if has_key(s:nrrw_aucmd, "create")
exe s:nrrw_aucmd["create"]
endif
if has_key(s:nrrw_aucmd, "writepost")
let b:nrrw_aucmd_writepost = s:nrrw_aucmd["writepost"]
endif
if has_key(s:nrrw_aucmd, "close")
let b:nrrw_aucmd_close = s:nrrw_aucmd["close"]
endif
call <sid>SaveRestoreRegister(_opts)
" restore settings
let &lz = o_lz
endfun
fun! nrrwrgn#Prepare(bang) abort "{{{1
if !exists("s:nrrw_rgn_line") || !empty(a:bang)
let s:nrrw_rgn_line={}
if !empty(a:bang)
return
endif
endif
if !has_key(s:nrrw_rgn_line, bufnr('%'))
let s:nrrw_rgn_line[bufnr('%')] = []
endif
call add(s:nrrw_rgn_line[bufnr('%')], line('.'))
endfun
fun! nrrwrgn#Unprepare() abort "{{{1
if !exists("s:nrrw_rgn_line")
let s:nrrw_rgn_line={}
endif
if !has_key(s:nrrw_rgn_line, bufnr('%'))
let s:nrrw_rgn_line[bufnr('%')] = []
endif
let indx = index(s:nrrw_rgn_line[bufnr('%')], line('.'))
if indx > -1
call remove(s:nrrw_rgn_line[bufnr('%')], indx)
endif
endfun
fun! nrrwrgn#WidenRegion(force) abort "{{{1
" a:force: original narrowed window is going to be closed
" so, clean up, don't renew highlighting, etc.
let nrw_buf = bufnr('')
let orig_buf = b:orig_buf
let orig_tab = tabpagenr()
let instn = b:nrrw_instn
" Make sure the narrowed buffer is still valid (happens, when 2 split
" window of the narrowed buffer is opened.
if !has_key(s:nrrw_rgn_lines, instn)
call <sid>WarningMsg("Error writing changes back,".
\ "Narrowed Window invalid!")
return
endif
let winnr = winnr()
let close = has_key(s:nrrw_rgn_lines[instn], 'single')
let vmode = has_key(s:nrrw_rgn_lines[instn], 'vmode')
" Save current state
let nr = changenr()
" Execute autocommands
if has_key(s:nrrw_aucmd, "close")
exe s:nrrw_aucmd["close"]
endif
let cont = getline(1,'$')
if has_key(s:nrrw_aucmd, "close") && nr != changenr()
" Restore buffer contents before the autocommand
" (in case the window isn't closed, the user sees
" the correct input)
exe "undo" nr
endif
if !has_key(s:nrrw_rgn_lines[instn], 'multi')
" <sid>WidenRegionMulti does take care of loading the correct buffer!
call <sid>JumpToBufinTab(<sid>BufInTab(orig_buf), orig_buf, instn, s:window_type["source"])
let orig_win = bufwinnr(orig_buf)
" Should be in the right tab now!
if (orig_win == -1)
if bufexists(orig_buf)
" buffer not in current window, switch to it!
exe "noa" orig_buf "b!"
" Make sure highlighting will be removed
let close = (&g:hid ? 0 : 1)
else
call s:WarningMsg("Original buffer does no longer exist! Aborting!")
return
endif
else
exe ':noa'. orig_win. 'wincmd w'
endif
" Removing matches only works in the right window. So need to check,
" the matchid actually exists, if not, try to remove it later.
if <sid>HasMatchID(instn)
call <sid>DeleteMatches(instn)
endif
if exists("b:orig_buf_ro") && b:orig_buf_ro && !a:force
call s:WarningMsg("Original buffer protected. Can't write changes!")
call <sid>JumpToBufinTab(orig_tab, nrw_buf, instn, s:window_type["target"])
return
endif
if !&l:ma && !(exists("b:orig_buf_ro") && b:orig_buf_ro)
setl ma
endif
endif
let _opts = <sid>SaveRestoreRegister([])
let wsv=winsaveview()
" This is needed to adjust all other narrowed regions
" in case we have several narrowed regions within the same buffer
if exists("g:nrrw_rgn_protect") && g:nrrw_rgn_protect =~? 'n'
let adjust_line_numbers = len(cont) - 1 - (
\s:nrrw_rgn_lines[instn].end[1] -
\s:nrrw_rgn_lines[instn].start[1])
endif
" Now copy the content back into the original buffer
" 1) Check: Multiselection
if has_key(s:nrrw_rgn_lines[instn], 'multi')
call <sid>WidenRegionMulti(cont, instn)
" 2) Visual Selection
elseif vmode
"charwise, linewise or blockwise selection
call setreg('a', join(cont, "\n"). "\n",
\ s:nrrw_rgn_lines[instn].vmode)
if s:nrrw_rgn_lines[instn].vmode == 'v' &&
\ s:nrrw_rgn_lines[instn].end[1] -
\ s:nrrw_rgn_lines[instn].start[1] + 1 == len(cont)
" in characterwise selection, remove trailing \n
call setreg('a', substitute(@a, '\n$', '', ''), 'v')
endif
" settable '< and '> marks
let _v = []
" store actual values
let _v = [getpos("'<"), getpos("'>"), [visualmode(1)]]
" set the mode for the gv command
exe "norm! ". s:nrrw_rgn_lines[instn].vmode."\<ESC>"
call setpos("'<", s:nrrw_rgn_lines[instn].start)
call setpos("'>", s:nrrw_rgn_lines[instn].end)
exe 'norm! gv"aP'
if !empty(_v[2][0]) && (_v[2][0] != visualmode())
exe 'norm!' _v[2][0]. "\<ESC>"
call setpos("'<", _v[0])
call setpos("'>", _v[1])
endif
" Recalculate the start and end positions of the narrowed window
" so subsequent calls will adjust the region accordingly
let [ s:nrrw_rgn_lines[instn].start,
\s:nrrw_rgn_lines[instn].end ] = <sid>RetVisRegionPos()
" make sure the visual selected lines did not add a new linebreak,
" this messes up the characterwise selected regions and removes lines
" on further writings
if s:nrrw_rgn_lines[instn].end[1] - s:nrrw_rgn_lines[instn].start[1]
\ + 1 > len(cont) && s:nrrw_rgn_lines[instn].vmode == 'v'
let s:nrrw_rgn_lines[instn].end[1] =
\ s:nrrw_rgn_lines[instn].end[1] - 1
let s:nrrw_rgn_lines[instn].end[2] = virtcol('$')
endif
" also, renew the highlighted region
" only highlight, if we are in a different window
" then where we started, else we might accidentally
" set a match in the narrowed window (might happen if the
" user typed Ctrl-W o in the narrowed window)
if !(has_key(s:nrrw_rgn_lines[instn], 'single') || bufwinnr(orig_buf) != winnr())
call <sid>AddMatches(<sid>GeneratePattern(
\ s:nrrw_rgn_lines[instn].start[1:2],
\ s:nrrw_rgn_lines[instn].end[1:2],
\ s:nrrw_rgn_lines[instn].vmode),
\ instn)
endif
" 3) :NR started selection
else
" linewise selection because we started the NarrowRegion with the
" command NarrowRegion(0)
"
" if the endposition of the narrowed buffer is also the last line of
" the buffer, the append will add an extra newline that needs to be
" cleared.
if s:nrrw_rgn_lines[instn].end[1]==line('$') &&
\ s:nrrw_rgn_lines[instn].start[1] == 1
let delete_last_line=1
else
let delete_last_line=0
endif
exe ':silent :'.s:nrrw_rgn_lines[instn].start[1].','
\.s:nrrw_rgn_lines[instn].end[1].'d _'
call append((s:nrrw_rgn_lines[instn].start[1]-1),cont)
" Recalculate the start and end positions of the narrowed window
" so subsequent calls will adjust the region accordingly
" so subsequent calls will adjust the region accordingly
let s:nrrw_rgn_lines[instn].end[1] =
\ s:nrrw_rgn_lines[instn].start[1] + len(cont) -1
if s:nrrw_rgn_lines[instn].end[1] > line('$')
let s:nrrw_rgn_lines[instn].end[1] = line('$')
endif
" only highlight, if we are in a different window
" then where we started, else we might accidentally
" set a match in the narrowed window (might happen if the
" user typed Ctrl-W o in the narrowed window)
if !(has_key(s:nrrw_rgn_lines[instn], 'single') || bufwinnr(orig_buf) != winnr())
call <sid>AddMatches(<sid>GeneratePattern(
\s:nrrw_rgn_lines[instn].start[1:2],
\s:nrrw_rgn_lines[instn].end[1:2],
\'V'),
\instn)
endif
if delete_last_line
silent! $d _
endif
endif
" Recalculate start- and endline numbers for all other Narrowed Windows.
" This matters, if you narrow different regions of the same file and
" write your changes back.
if exists("g:nrrw_rgn_protect") && g:nrrw_rgn_protect =~? 'n'
call <sid>RecalculateLineNumbers(instn, adjust_line_numbers)
endif
" if close && !has_key(s:nrrw_rgn_lines[instn], 'single')
" For narrowed windows that have been created using !,
" don't clean up yet, or else we loose all data and can't write
" it back later.
" (e.g. :NR! createas a new single window, do :sp
" and you can only write one of the windows back, the other will
" become invalid, if CleanUp is executed)
" endif
call <sid>SaveRestoreRegister(_opts)
" Execute "written" autocommands in the original buffer
if exists("b:nrrw_aucmd_written")
exe b:nrrw_aucmd_written
endif
call winrestview(wsv)
"if !close && has_key(s:nrrw_rgn_lines[instn], 'single')
if has_key(s:nrrw_rgn_lines[instn], 'single')
if &modified
noa w
endif
" move back to narrowed buffer
noa b #
"elseif close
" call <sid>CleanUpInstn(instn)
endif
let bufnr = bufnr('')
" jump back to narrowed window
call <sid>JumpToBufinTab(orig_tab, nrw_buf, instn, s:window_type["target"])
if bufnr('') != bufnr
" do not set the original buffer unmodified
setl nomod
endif
if a:force
" trigger auto command
bw
endif
endfun
fun! nrrwrgn#UnifiedDiff() abort "{{{1
" if the filetype is not of type diff, assume to create a diff for merge
" conflicts
let merge = &ft=~'diff' ? 0 : 1
let pat = merge ? ['^<\{7\}', '^=\{7\}', '^>\{7\}' ] : ['^@@','^@@']
let save_winposview=winsaveview()
let orig_win = winnr()
" close previous opened Narrowed buffers
silent! windo | if bufname('')=~'^NrrwRgn' &&
\ &diff |diffoff|q!|endif
" move back to original window (windo changes it)
if winnr() != orig_win
exe "noa" orig_win "wincmd w"
endif
" minimize Window
" this is disabled, because this might be useful, to see everything
"exe "vert resize -999999"
"setl winfixwidth
" move to current start of chunk of unified diff
if search(pat[0], 'bcW') > 0
call search(pat[0], 'bc')
else
call search(pat[0], 'c')
endif
let curpos=getpos('.')
for i in range(2)
if merge
if i == 1
" move to start of other change below '=====' line
call search(pat[1], 'W')
endif
exe ".+,/".pat[i+1]."/-NR"
else
if search(pat[0], 'nW') > 0
exe ".+,/".pat[0]."/-NR"
else
" Last chunk in file
.+,$NR
endif
endif
" Split vertically
noa wincmd H
if !merge
if i==0
silent! g/^-/d _
else
silent! g/^+/d _
endif
endif
diffthis
0
noa wincmd p
call setpos('.', curpos)
endfor
call winrestview(save_winposview)
endfun
fun! nrrwrgn#ToggleSyncWrite(enable) abort "{{{1
let s:nrrw_rgn_lines[b:nrrw_instn].disable = !a:enable
" Enable syncing of bufers
if a:enable
" Enable Narrow settings and autocommands
call <sid>NrrwSettings(1)
call <sid>NrrwRgnAuCmd(0)
setl modified
else
" Disable Narrow settings and autocommands
call <sid>NrrwSettings(0)
" b:nrrw_instn should always be available
call <sid>NrrwRgnAuCmd(b:nrrw_instn)
endif
endfun
fun! nrrwrgn#LastNrrwRgn(bang) abort "{{{1
let bang = !empty(a:bang)
if !exists("s:nrrw_rgn_lines") || !has_key(s:nrrw_rgn_lines, 'last')
call <sid>WarningMsg("There is no last region to re-select")
return
endif
let orig_buf = s:nrrw_rgn_lines['last'][0][0] + 0
let tab = <sid>BufInTab(orig_buf)
if tab != tabpagenr() && tab > 0
exe "tabn" tab
endif
let orig_win = bufwinnr(orig_buf)
" Should be in the right tab now!
if (orig_win == -1)
call s:WarningMsg("Original buffer does no longer exist! Aborting!")
return
endif
if orig_win != winnr()
exe "noa" orig_win "wincmd w"
endif
if len(s:nrrw_rgn_lines['last']) == 1
" Multi Narrowed
let s:nrrw_rgn_buf = s:nrrw_rgn_lines['last'][0][1]
call nrrwrgn#NrrwRgnDoMulti('')
else
exe "keepj" s:nrrw_rgn_lines['last'][0][1][0]
exe "keepj norm!" s:nrrw_rgn_lines['last'][0][1][1]. '|'
" Start visual mode
exe "keepj norm!" s:nrrw_rgn_lines['last'][2]
exe "keepj" s:nrrw_rgn_lines['last'][1][1][0]
if col(s:nrrw_rgn_lines['last'][1][1][1]) == col('$') &&
\ s:nrrw_rgn_lines['last'][2] == ''
" Best guess
exe "keepj $"
else
exe "keepj norm!" s:nrrw_rgn_lines['last'][1][1][1]. '|'
endif
" Call VisualNrrwRgn()
call nrrwrgn#NrrwRgn(visualmode(), bang)
endif
endfu
fun! nrrwrgn#NrrwRgnStatus() abort "{{{1
if !exists("b:nrrw_instn")
return {}
else
let dict={}
try
let cur = deepcopy(s:nrrw_rgn_lines[b:nrrw_instn])
if has_key(cur, 'multi')
let multi = cur.multi
else
let multi = []
endif
let dict.shortname = bufname('')
let bufname=bufname(cur.orig_buf)
if !empty(bufname)
let dict.fullname = fnamemodify(expand(bufname(cur.orig_buf)),':p')
else
let dict.fullname = '[No Name]' " vim default
endif
let dict.multi = has_key(cur, 'multi')
if has_key(cur, 'multi')
let end = keys(multi[1])[-1]
let dict.startl= map(copy(multi), 'v:val[1][0]')
let dict.endl = map(copy(multi), 'v:val[end][1]')
else
let dict.start = cur.start
let dict.end = cur.end
endif
let dict.matchid = cur.matchid
let dict.visual = has_key(cur, 'vmode') ? cur.vmode : ''
let dict.enabled = has_key(cur, 'disable') ? (cur.disable ? 0 : 1) : 1
let dict.instn = b:nrrw_instn
unlet cur
catch
" oh oh, something is wrong...
let dict={}
endtry
lockvar dict
return dict
endif
endfu
" Debugging options "{{{1
fun! nrrwrgn#Debug(enable) abort "{{{2
if (a:enable)
let s:debug=1
fun! <sid>NrrwRgnDebug() abort "{{{2
"sil! unlet s:instn
com! NI :call <sid>WarningMsg("Instance: ".s:instn)
com! NJ :call <sid>WarningMsg("Data: ".string(s:nrrw_rgn_lines))
com! -nargs=1 NOutput :if exists("s:".<q-args>)|redraw!|
\ :exe 'echo s:'.<q-args>|else|
\ echo "s:".<q-args>. " does not exist!"|endif
endfun
call <sid>NrrwRgnDebug()
else
let s:debug=0
delf <sid>NrrwRgnDebug
delc NI
delc NJ
delc NOutput
endif
endfun
" Modeline {{{1
" vim: noet ts=4 sts=4 fdm=marker com+=l\:\" fdl=0