" nrrwrgn.vim - Narrow Region plugin for Vim " ------------------------------------------------------------- " Version: 0.33 " Maintainer: Christian Brabandt " 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! 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! 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=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 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! 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! 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 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! CleanRegions() abort "{{{1 let s:nrrw_rgn_line={} unlet! s:nrrw_rgn_buf endfun fun! CompareNumbers(a1,a2) abort "{{{1 return (a:a1+0) == (a:a2+0) ? 0 : (a:a1+0) > (a:a2+0) ? 1 : -1 endfun fun! 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' : 'CompareNumbers')) let result = {} let start = 0 let temp = 0 let item = 0 for item in sort(list[buf], (s:numeric_sort ? 'n' : "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! 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! 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) && \ !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 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 NrrwRgnAuCmd(nrrw_instn) endif endfun fun! 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! 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) && \ !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! SetupBufWriteCmd(instn) "{{{1 if !exists("#NrrwRgn".a:instn."#BufWriteCmd#") if s:debug echo "Setting up BufWriteCmd!" endif au BufWriteCmd nested :call s:WriteNrrwRgn(1) endif endfu fun! SetupBufWinLeave(instn) "{{{1 if !exists("#NrrwRgn".a:instn."#BufWinLeave#") && \ exists("b:orig_buf") && bufloaded(b:orig_buf) au BufWinLeave :call s:NRBufWinLeave() endif endfu fun! SetupWinLeave(instn) "{{{1 if !exists("#NrrwRgn".a:instn."#WinLeave#") exe "au WinLeave :call s:NRWinLeave(".a:instn.")" endif endfu fun! NRWinLeave(instn) "{{{1 let orig_buf = s:nrrw_rgn_lines[a:instn].orig_buf let orig_tab = tabpagenr() call JumpToBufinTab(BufInTab(b:orig_buf), orig_buf, a:instn, s:window_type["source"]) :sil doautocmd WinEnter endfu fun! NRBufWinLeave() "{{{1 let instn = getbufvar(expand(""), 'nrrw_instn') let nrw_buf = bufnr('') let orig_buf = getbufvar(expand(""), 'orig_buf') let orig_tab = tabpagenr() call JumpToBufinTab(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 JumpToBufinTab(orig_tab, nrw_buf, instn, s:window_type["target"]) endfu fun! 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 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 nested \ :call s:WriteNrrwRgn() au CursorMoved :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 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 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 GoToWindow(buf, a:instn, s:window_type["source"]) call DeleteMatches(a:instn) unlet! w:nrrw_rgn_id w:nrrw_rgn_id_type call CleanUpInstn(a:instn) endif endif endfun fun! 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! 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 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! RetVisRegionPos() abort "{{{1 let a = getpos("'<") let b = getpos("'>") let a[2] = virtcol("'<") let b[2] = virtcol("'>") return [a, b] endfun fun! 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! 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! 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! 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! 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! 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! 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! HideNrrwRgnLines() abort "{{{1 let char1 = 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! ReturnCommentFT() abort "{{{1 if !empty(&l:commentstring) return substitute(&l:commentstring, '%s', ' ', '') else return "# " endif endfun fun! 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), '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] = 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' : "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 AddMatches(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! 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! 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! 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 GoToWindow(a:buf, a:instn, a:type) endfun fun! 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 DeleteMatches(instn) call AddMatches(GeneratePattern( \s:nrrw_rgn_lines[instn].start[1:2], \s:nrrw_rgn_lines[instn].end[1:2], \'V'), instn) endif endfor endfun fun! 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! SetupBufLocalCommands() abort "{{{1 com! -buffer -bang WidenRegion :call nrrwrgn#WidenRegion(0) com! -buffer -bang WR :WidenRegion com! -buffer NRSyncOnWrite :call nrrwrgn#ToggleSyncWrite(1) com! -buffer NRNoSyncOnWrite :call nrrwrgn#ToggleSyncWrite(0) endfun fun! SetupBufLocalMaps(bang) abort "{{{1 if !hasmapto('NrrwrgnWinIncr', 'n') nmap NrrwrgnWinIncr endif if !hasmapto('ToggleWindowSize') nnoremap