pax_global_header00006660000000000000000000000064130571016410014510gustar00rootroot0000000000000052 comment=423600d0ab98254bae6fa2ca60d06057ecfb748a VOoM-5.3/000077500000000000000000000000001305710164100121775ustar00rootroot00000000000000VOoM-5.3/.gitignore000066400000000000000000000000521305710164100141640ustar00rootroot00000000000000__pycache__ *.pyc *.bat *.vbs *.lnk *.sh VOoM-5.3/README.txt000066400000000000000000000001111305710164100136660ustar00rootroot00000000000000This is a mirror of http://www.vim.org/scripts/script.php?script_id=2657 VOoM-5.3/autoload/000077500000000000000000000000001305710164100140075ustar00rootroot00000000000000VOoM-5.3/autoload/voom.vim000066400000000000000000003121511305710164100155070ustar00rootroot00000000000000" File: voom.vim " Last Modified: 2017-02-18 " Version: 5.3 " Description: VOoM -- two-pane outliner plugin for Python-enabled Vim " Website: http://www.vim.org/scripts/script.php?script_id=2657 " Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) " License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ "---Conventions-------------------------------{{{1 " Tree --Tree buffer " Body --Body buffer " tree --Tree buffer number " body --Body buffer number " headline --Body line with a matching fold marker, also a Tree line " node --Body region between two headlines, usually also a fold. " A node is identified by Tree lnum (nodes) or Body lnum (bnodes). " nodes --list of Tree lnums " bnodes --list of Body lnums, line numbers of Body headlines " bnr --buffer number " wnr, tnr --window number, tab number " lnum, ln, lnr --line number, usually Tree " blnum, bln, blnr --Body line number " tline(s) --Tree line(s) " bline(s) --Body line(s) " snLn --selected node line number, a Tree line number " var_ --previous value of var " l:var --this var is set or may be changed by Python code (l:blnShow) " z, Z --list siZe, usually len(bnodes) "---Initialize--------------------------------{{{1 if !exists('s:voom_did_init') if exists('g:voom_python_versions') if type(g:voom_python_versions) != type([]) echom '**VOoM**: cannot initialize, g:voom_python_versions is not a list' finish endif let s:PYCMD = 'pyNOpy' for s:it in g:voom_python_versions if type(s:it) != type(0) | continue | endif let s:PYCMD = s:it==2 ? 'python' : 'python'.s:it if has(s:PYCMD) break else let s:PYCMD = 'pyNOpy' endif endfor unlet! s:it if s:PYCMD ==# 'pyNOpy' unlet s:PYCMD echom '**VOoM**: cannot initialize, none of the requested Python versions is available, g:voom_python_versions=' . string(g:voom_python_versions) finish endif else if has('python') let s:PYCMD = 'python' elseif has('python3') let s:PYCMD = 'python3' else echom '**VOoM**: cannot initialize, neither Python 2 nor Python 3 is available' finish endif endif lockvar s:PYCMD let s:script_path = expand(":p") let s:script_dir = expand(":p:h") let s:voom_dir = fnamemodify(s:script_dir, ':p') . 'voom' let s:voom_logbnr = 0 " {tree : associated body, ...} let s:voom_trees = {} " {body : { " 'tree' : associated tree, " 'snLn' : selected node Tree lnum, " 'MTYPE' : integer indicating the type of markup mode, " 0 -- an fmr mode, all operations are supported " 1 -- special node marks are not supported " 2 -- as 1, in addition Move Right/Left, Add New Headline As Child are not supported " 'mmode' : markup mode, " 'tick' : b:changedtick of Body on Body BufLeave, " 'tick_' : b:changedtick of Body on last Tree update " }, {...}, ... } let s:voom_bodies = {} " force one-time outline verification let s:verify = 0 " setup Python environment exe s:PYCMD "import sys, vim" exe s:PYCMD "if not vim.eval('s:voom_dir') in sys.path: sys.path.append(vim.eval('s:voom_dir'))" exe s:PYCMD "import voom_vimplugin2657.voom_vim as _VOoM2657" exe s:PYCMD "sys.modules['voom_vimplugin2657.voom_vim'].VOOMS = {}" let s:voom_did_init = 'v5.3' lockvar s:voom_did_init endif "---User Options------------------------------{{{1 " These can be defined in .vimrc . " Where Tree window is created: 'left', 'right', 'top', 'bottom' " This is relative to the current window. if !exists('g:voom_tree_placement') let g:voom_tree_placement = 'left' endif " Initial Tree window width. if !exists('g:voom_tree_width') let g:voom_tree_width = 30 endif " Initial Tree window height. if !exists('g:voom_tree_height') let g:voom_tree_height = 12 endif " Where Log window is created: 'left', 'right', 'top', 'bottom' " This is far left/right/top/bottom. if !exists('g:voom_log_placement') let g:voom_log_placement = 'bottom' endif " Initial Log window width. if !exists('g:voom_log_width') let g:voom_log_width = 30 endif " Initial Log window height. if !exists('g:voom_log_height') let g:voom_log_height = 12 endif " Verify outline after outline operations. if !exists('g:voom_verify_oop') let g:voom_verify_oop = 1 endif " Which key to map to Select-Node-and-Shuttle-between-Body/Tree if !exists('g:voom_return_key') let g:voom_return_key = '' endif " Which key to map to Shuttle-between-Body/Tree if !exists('g:voom_tab_key') let g:voom_tab_key = '' endif " g:voom_rstrip_chars_{filetype} -- string with chars to strip from right side " of Tree headlines for Body 'filetype' {filetype}. " If defined, these will be used instead of 'commentstring' chars. if !exists('g:voom_rstrip_chars_vim') let g:voom_rstrip_chars_vim = "\"# \t" endif if !exists('g:voom_rstrip_chars_text') let g:voom_rstrip_chars_text = " \t" endif if !exists('g:voom_rstrip_chars_help') let g:voom_rstrip_chars_help = " \t" endif "---Commands----------------------------------{{{1 " Main commands are defined in ../plugin/voom.vim. " Naming convention: Voomdoit will not modify Body, VoomDoit can modify Body. com! Voomunl call voom#EchoUNL() com! -nargs=? Voomgrep call voom#Grep() com! -range -nargs=? VoomSort call voom#OopSort(,, ) com! -range VoomFoldingSave call voom#OopFolding(,, 'save') com! -range VoomFoldingRestore call voom#OopFolding(,, 'restore') com! -range VoomFoldingCleanup call voom#OopFolding(,, 'cleanup') com! Voomtoggle call voom#ToggleTreeWindow() com! Voomquit call voom#DeleteOutline() com! VoomQuitAll call voom#DeleteOutlines() com! -nargs=? Voominfo call voom#Voominfo() """ development helpers if exists('g:voom_create_devel_commands') " reload autoload/voom.vim (outlines are preserved) com! VoomReloadVim exe 'so '.s:script_path " wipe out Trees, PyLog, delete Python modules; reload autoload/voom.vim, voom_vim.py " Note: simply reloading Python modules is pointless since v4.2 com! VoomReloadAll call voom#ReloadAllPre() | exe 'so '.s:script_path endif "---voom#Init(), various commands, helpers----{{{1 func! voom#Init(qargs, ...) "{{{2 " Commands :Voom, :VoomToggle. Optional boolean args: toggleOutline, keepCursor. let toggleOutline = (a:0 > 0 && a:1) ? 1 : 0 let keepCursor = (a:0 > 1 && a:2) ? 1 : 0 let bnr = bufnr('') " Current buffer is Tree. if has_key(s:voom_trees, bnr) let body = s:voom_trees[bnr] if toggleOutline call voom#UnVoom(body, bnr) return endif if !hasmapto('voom#ToTreeOrBodyWin','n') call voom#ErrorMsg("VOoM: Tree lost mappings. Reconfiguring...") call voom#TreeConfig() call voom#TreeConfigFT(body) endif if !keepCursor call voom#ToBody(body) endif return " Current buffer is Body. elseif has_key(s:voom_bodies, bnr) let tree = s:voom_bodies[bnr].tree if toggleOutline call voom#UnVoom(bnr, tree) return endif if !hasmapto('voom#ToTreeOrBodyWin','n') call voom#ErrorMsg("VOoM: Body lost mappings. Reconfiguring...") call voom#BodyConfig() endif if !keepCursor call voom#ToTree(tree) endif return endif " Current buffer is not a VOoM buffer. Create Tree for it. Current buffer " becomes a Body buffer. let body = bnr let s:voom_bodies[body] = {} let blnr = line('.') let [b_name, b_dir] = [expand('%:p:t'), expand('%:p:h')] if b_name=='' | let b_name='No Name' | endif let l:firstLine = ' '.b_name.' ['.b_dir.'], b'.body let [l:MTYPE, l:qargs] = [-1, a:qargs] exe s:PYCMD "_VOoM2657.voom_Init(int(vim.eval('l:body')))" if l:MTYPE < 0 | unlet s:voom_bodies[body] | return | endif let s:voom_bodies[body].MTYPE = l:MTYPE let s:voom_bodies[body].mmode = l:mmode call voom#BodyConfig() call voom#ToTreeWin() call voom#TreeCreate(body, blnr) if keepCursor call voom#ToBody(body) endif endfunc func! voom#TreeSessionLoad() "{{{2 " Create outline when loading session created with :mksession. if !exists('g:SessionLoad') || &modified || line('$')>1 || getline(1)!='' return endif call setline(1,[' PLEASE',' KILL',' ME (:bw)']) setl nomod noma bh=wipe " don't -- horrible errors if two tabs with a Tree in each "exe 'au SessionLoadPost bw '.bufnr('') "au SessionLoadPost call voom#TreeSessionLoadPost() let [tree, tname] = [bufnr(''), bufname('')] if has_key(s:voom_trees,tree) | return | endif """ try to find Body matching this Tree buffer name let treeName = fnamemodify(tname,':t') if treeName !~# '^.\+_VOOM\d\+$' | return | endif let bodyName = substitute(treeName, '\C_VOOM\d\+$', '', '') let bodyNameM = substitute(bodyName, '[', '[[]', 'g') . '$' let [body, bodyWnr] = [bufnr(bodyNameM), bufwinnr(bodyNameM)] "echo 'DEBUG' treeName tree '|' bodyName body bodyWnr " Body must exist and be in a window in the current tabpage if body < 0 || bodyName !=# fnamemodify(bufname(body),':t') return elseif bodyWnr < 0 || bodyWnr == winnr() || bodyWnr != bufwinnr(body) return " there is already an outline for this Body elseif has_key(s:voom_bodies, body) exe 'b'.s:voom_bodies[body].tree call voom#TreeConfigWin() call voom#TreeConfigFT(body) return endif " rename Tree (current buffer), if needed, to correct Body bufnr let tname_new = substitute(tname, '\C_VOOM\d\+$', '_VOOM'.body, '') if tname !=# tname_new if bufexists(tname_new) | return | endif let bnrMax_ = bufnr('$') exe 'silent file '.fnameescape(tname_new) " An unlisted buffer is created to hold the old name. Kill it. let bnrMax = bufnr('$') if bnrMax > bnrMax_ && bnrMax==bufnr(tname.'$') exe 'bwipeout '.bnrMax endif endif """ go to Body, create outline, go back, configure Tree let wnr_ = winnr() let wnr_p = winnr('#') try exe 'noautocmd '.bodyWnr.'wincmd w' let s:voom_bodies[body] = {} let blnr = line('.') let b_dir = expand('%:p:h') let l:firstLine = ' '.bodyName.' ['.b_dir.'], b'.body let [l:MTYPE, l:qargs] = [-1, ''] exe s:PYCMD "_VOoM2657.voom_Init(int(vim.eval('l:body')))" if l:MTYPE < 0 | unlet s:voom_bodies[body] | return | endif let s:voom_bodies[body].MTYPE = l:MTYPE let s:voom_bodies[body].mmode = l:mmode call voom#BodyConfig() finally if wnr_p | exe 'noautocmd '.wnr_p.'wincmd w' | endif exe 'noautocmd '.wnr_.'wincmd w' endtry if bufnr('')==tree call voom#TreeCreate(body, blnr) endif endfunc func! voom#Complete(A,L,P) "{{{2 " Argument completion for command :Voom. Return string "wiki\nvimwiki\nviki..." " constructed from file names ../plugin/voom/voom_vimplugin2657/voom_mode_{whatever}.py . let thefiles = split(glob(s:voom_dir.'/voom_vimplugin2657/voom_mode_?*.py'), "\n") let themodes = [] for the in thefiles let themode = substitute(fnamemodify(the,':t'), '\c^voom_mode_\(.*\)\.py$', '\1', '') call add(themodes, themode) endfor return join(themodes, "\n") endfunc func! voom#Help() "{{{2 " Open voom.txt as outline in a new tabpage. let help_path = fnamemodify(s:script_dir.'/../doc/voom.txt', ":p") if !filereadable(help_path) call voom#ErrorMsg("VOoM: can't read help file:" help_path) return endif """ voom.txt exists and is shown in some window in some tab -- go there let help_bufnr = bufnr('^'.help_path.'$') if help_bufnr > 0 let alltabs = range(tabpagenr(),tabpagenr('$')) + range(1,tabpagenr()-1) for tnr in alltabs if index(tabpagebuflist(tnr), help_bufnr) > -1 exe 'tabnext '.tnr exe bufwinnr(help_bufnr).'wincmd w' " make sure critical settings are correct if &ft!=#'help' set ft=help endif if &fmr!=#'[[[,]]]' || &fdm!=#'marker' setl fmr=[[[,]]] fdm=marker endif " make sure outline is present call voom#Init('') return endif endfor endif """ try 'tab help' command let help_installed = 1 let [tnr_, tnrM_] = [tabpagenr(), tabpagenr('$')] try silent tab help voom.txt catch /^Vim\%((\a\+)\)\=:E149/ " no help for voom.txt let help_installed = 0 catch /^Vim\%((\a\+)\)\=:E429/ " help file not found--removed after installing let help_installed = 0 endtry if help_installed==1 if fnamemodify(bufname(""), ":t")!=#'voom.txt' echoerr "VOoM: INTERNAL ERROR" return endif if &fmr!=#'[[[,]]]' || &fdm!=#'marker' setl fmr=[[[,]]] fdm=marker endif call voom#Init('') return " 'tab help' failed, we are on new empty tabpage -- kill it elseif tabpagenr()!=tnr_ && tabpagenr('$')==tnrM_+1 && bufname('')=='' && winnr('$')==1 bwipeout exe 'tabnext '.tnr_ endif """ open voom.txt as regular file exe 'tabnew '.fnameescape(help_path) if fnamemodify(bufname(""), ":t")!=#'voom.txt' echoerr "VOoM: INTERNAL ERROR" return endif if &ft!=#'help' setl ft=help endif if &fmr!=#'[[[,]]]' || &fdm!=#'marker' setl fmr=[[[,]]] fdm=marker endif call voom#Init('') endfunc func! voom#DeleteOutline(...) "{{{2 " Delete current outline, execute Ex command if in Body or non-VOoM buffer. let bnr = bufnr('') " current buffer is Tree if has_key(s:voom_trees, bnr) call voom#UnVoom(s:voom_trees[bnr], bnr) return " current buffer is Body elseif has_key(s:voom_bodies, bnr) call voom#UnVoom(bnr, s:voom_bodies[bnr].tree) endif " current buffer is Body or non-VOoM buffer if a:0 execute a:1 endif endfunc func! voom#DeleteOutlines() "{{{2 " Delete all VOoM outlines. for bnr in keys(s:voom_trees) let tree = str2nr(bnr) call voom#UnVoom(s:voom_trees[tree], tree) endfor endfunc func! voom#UnVoom(body,tree) "{{{2 " Remove VOoM data for Body body and its Tree tree. " Wipeout Tree, delete Body au, etc. " Can be called from any buffer. " Note: when called from Tree BufUnload au, tree doesn't exist. if has_key(s:voom_bodies, a:body) && has_key(s:voom_trees, a:tree) unlet s:voom_bodies[a:body] unlet s:voom_trees[a:tree] else echoerr 'VOoM: INTERNAL ERROR' return endif exe s:PYCMD "_VOoM2657.voom_UnVoom(int(vim.eval('a:body')))" exe 'au! VoomBody * ' if bufexists(a:tree) "exe 'noautocmd bwipeout '.a:tree exe 'au! VoomTree * ' exe 'bwipeout '.a:tree endif if bufnr('')==a:body call voom#BodyUnMap() endif endfunc func! voom#FoldStatus(lnum) "{{{2 " there is no fold if foldlevel(a:lnum)==0 return 'nofold' endif let fc = foldclosed(a:lnum) " line is hidden in fold, cannot determine it's status if fc < a:lnum && fc > 0 return 'hidden' " line is first line of a closed fold elseif fc==a:lnum return 'folded' " line is in an opened fold else return 'notfolded' endif " Helper for dealing with folds. Determine if line lnum is: " not in a fold; " hidden in a closed fold; " not hidden and is a closed fold; " not hidden and is in an open fold. endfunc func! voom#WarningMsg(...) "{{{2 echohl WarningMsg for line in a:000 echo line endfor echohl None endfunc func! voom#ErrorMsg(...) "{{{2 echohl ErrorMsg for line in a:000 echom line endfor echohl None endfunc func! voom#BufNotLoaded(body) "{{{2 if bufloaded(a:body) return 0 endif if bufexists(a:body) let bname = fnamemodify(bufname(a:body),":t") call voom#ErrorMsg('VOoM: Body buffer '.a:body.' ('.bname.') is not loaded') else call voom#ErrorMsg('VOoM: Body buffer '.a:body.' does not exist') endif return 1 endfunc func! voom#BufNotEditable(body) "{{{2 if getbufvar(a:body, "&ma")==1 && getbufvar(a:body, "&ro")==0 return 0 endif let bname = fnamemodify(bufname(a:body),":t") call voom#ErrorMsg("VOoM: Body buffer ".a:body." (".bname.") is 'nomodifiable' or 'readonly'") return 1 " If buffer doesn't exist, getbufvar() returns '' . endfunc func! voom#BufNotTree(tree) "{{{2 if has_key(s:voom_trees,a:tree) && !getbufvar(a:tree,'&ma') return 0 endif if !has_key(s:voom_trees,a:tree) call voom#ErrorMsg('VOoM: current buffer is not Tree') elseif getbufvar(a:tree,'&ma') echoerr "VOoM: Tree buffer is 'modifiable'" endif return 1 endfunc func! voom#SetSnLn(body, snLn) "{{{2 " Set snLn. Used by Python code. let s:voom_bodies[a:body].snLn= a:snLn endfunc func! voom#ToggleTreeWindow() "{{{2 " Mimimize/restore Tree window. let bnr = bufnr('') if has_key(s:voom_bodies, bnr) let [body, tree, inBody] = [bnr, s:voom_bodies[bnr].tree, 1] elseif has_key(s:voom_trees, bnr) let [body, tree, inBody] = [s:voom_trees[bnr], bnr, 0] else call voom#ErrorMsg("VOoM: current buffer is not a VOoM buffer") return endif if inBody if voom#ToTree(tree)!=0 | return | endif endif " current window width (w) and height (h) let [winw, winh] = [winwidth(0), winheight(0)] " maximum possible w and h (-2 for statusline and tabline) let [maxw, maxh] = [&columns, &lines-&cmdheight-2] " minimize w, h, or both if winw > 1 && winh > 1 let w:voom_winsave = winsaveview() if winw < maxw let w:voom_w = winw vertical resize 1 endif if winh < maxh let w:voom_h = winh resize 1 endif " restore w, h, or both else if winw <= 1 let w = exists('w:voom_w') ? w:voom_w : g:voom_tree_width exe 'vertical resize '.w endif if winh <= 1 let h = exists('w:voom_h') ? w:voom_h : g:voom_tree_height exe 'resize '.h endif if exists('w:voom_winsave') call winrestview(w:voom_winsave) endif endif if inBody | call voom#ToBody(body) | endif endfunc func! voom#Voominfo(qargs) "{{{2 let bnr = bufnr('') if has_key(s:voom_trees, bnr) let [body, tree] = [s:voom_trees[bnr], bnr] elseif has_key(s:voom_bodies, bnr) let [body, tree] = [bnr, s:voom_bodies[bnr].tree] else let [body, tree] = [bnr, 0] endif let l:vimvars = '' if a:qargs==#'all' for var in ['s:script_path', 's:script_dir', 's:voom_dir', 'g:voom_did_load_plugin', 's:voom_did_init', 's:voom_logbnr', 's:verify', 'g:voom_verify_oop', 's:voom_trees', 's:voom_bodies'] let l:vimvars = l:vimvars . printf("%-13s = %s\n", var, string({var})) endfor endif exe s:PYCMD "_VOoM2657.voom_Voominfo()" endfunc func! voom#ReloadAllPre() "{{{2 " Helper for reloading the entire plugin and all modes. " Wipe out all Tree buffers and PyLog buffer. Delete Python voom modules. call voom#DeleteOutlines() if s:voom_logbnr && bufexists(s:voom_logbnr) exe 'bwipeout '.s:voom_logbnr endif exe s:PYCMD "_VOoM2657.voom_ReloadAllPre()" unlet s:voom_did_init unlet s:PYCMD endfunc "--- for external scripts --- {{{2 func! voom#GetVar(var) "{{{2 return {a:var} endfunc func! voom#GetBodiesTrees() "{{{2 return [s:voom_bodies, s:voom_trees] endfunc func! voom#GetTypeBodyTree(...) "{{{2 let bnr = bufnr('') if has_key(s:voom_trees, bnr) let [bufType, body, tree] = ['Tree', s:voom_trees[bnr], bnr] if voom#BufNotLoaded(body) | return ['Tree',-1,-1] | endif elseif has_key(s:voom_bodies, bnr) let [bufType, body, tree] = ['Body', bnr, s:voom_bodies[bnr].tree] if voom#BodyUpdateTree() < 0 | return ['Body',-1,-1] | endif else if !(a:0 && a:1) call voom#ErrorMsg("VOoM: current buffer is not a VOoM buffer") endif return ['None',0,0] endif return [bufType, body, tree] " Return ['Body'/'Tree', body, tree] for the current buffer. " Return ['None',0,0] if current buffer is neither Body nor Tree and print " error message. To supress the error message: voom#GetTypeBodyTree(1) " Return ['Body'/'Tree',-1,-1] if outline is not available. " Update outline if needed if the current buffer is Body. endfunc func! voom#GetModeBodyTree(bnr) "{{{2 if has_key(s:voom_trees, a:bnr) let [body, tree] = [s:voom_trees[a:bnr], a:bnr] elseif has_key(s:voom_bodies, a:bnr) let [body, tree] = [a:bnr, s:voom_bodies[a:bnr].tree] else return ['',-1,0,0] endif return [s:voom_bodies[body].mmode, s:voom_bodies[body].MTYPE, body, tree] " Return [markup mode, MTYPE, body, tree] for buffer number bnr. " Return ['',-1,0,0] if the buffer is not a VOoM buffer. endfunc "---Windows Navigation and Creation-----------{{{1 " These deal only with the current tab page. func! voom#ToTreeOrBodyWin() "{{{2 " If in Tree window, move to Body window. " If in Body window, move to Tree window. " If possible, use previous window. let bnr = bufnr('') " current buffer is Tree if has_key(s:voom_trees, bnr) let target = s:voom_trees[bnr] " current buffer is Body else " This happens after Tree is wiped out. if !has_key(s:voom_bodies, bnr) call voom#BodyUnMap() return endif let target = s:voom_bodies[bnr].tree endif " Try previous window. It's the most common case. let wnr = winnr('#') if winbufnr(wnr)==target exe wnr.'wincmd w' return endif " Use any other window. if bufwinnr(target) > 0 exe bufwinnr(target).'wincmd w' return endif endfunc func! voom#ToTreeWin() "{{{2 " Move to window or create a new one where a Tree will be loaded. " Already in a Tree buffer. if has_key(s:voom_trees, bufnr('')) | return | endif " Use previous window if it shows Tree. let wnr = winnr('#') if has_key(s:voom_trees, winbufnr(wnr)) exe wnr.'wincmd w' call voom#SplitIfUnique() return endif " Use any window with a Tree buffer. for bnr in tabpagebuflist() if has_key(s:voom_trees, bnr) exe bufwinnr(bnr).'wincmd w' call voom#SplitIfUnique() return endif endfor " Create new window. if g:voom_tree_placement==#'top' exe 'leftabove '.g:voom_tree_height.'split' elseif g:voom_tree_placement==#'bottom' exe 'rightbelow '.g:voom_tree_height.'split' elseif g:voom_tree_placement==#'left' exe 'leftabove '.g:voom_tree_width.'vsplit' elseif g:voom_tree_placement==#'right' exe 'rightbelow '.g:voom_tree_width.'vsplit' endif endfunc func! voom#SplitIfUnique() "{{{2 " Split current window if current buffer is not displayed in any other window " in current tabpage. let bnr = bufnr('') let wnr = winnr() for i in range(1,winnr('$')) if winbufnr(i)==bnr && i!=wnr return endif endfor if winheight(0) * 2 >= winwidth(0) leftabove split else leftabove vsplit endif endfunc func! voom#ToTree(tree) abort "{{{2 " Move cursor to window with Tree buffer tree. " If there is no such window, load buffer in a new window. " Already there. if bufnr('')==a:tree | return | endif " Try previous window. let wnr = winnr('#') if winbufnr(wnr)==a:tree exe wnr.'wincmd w' return endif " There is window with buffer a:tree. if bufwinnr(a:tree) > 0 exe bufwinnr(a:tree).'wincmd w' return endif " Bail out if Tree is unloaded or doesn't exist. " Because of au, this should never happen. if !bufloaded(a:tree) let body = s:voom_trees[a:tree] call voom#UnVoom(body,a:tree) echoerr "VOoM: Tree buffer" a:tree "is not loaded or does not exist. Cleanup has been performed." return -1 endif " Load Tree in appropriate window. call voom#ToTreeWin() silent exe 'b '.a:tree " window-local options will be set on BufEnter return 1 endfunc func! voom#ToBodyWin() "{{{2 " Split current Tree window to create window where Body will be loaded if g:voom_tree_placement==#'top' exe 'leftabove '.g:voom_tree_height.'split' wincmd p elseif g:voom_tree_placement==#'bottom' exe 'rightbelow '.g:voom_tree_height.'split' wincmd p elseif g:voom_tree_placement==#'left' exe 'leftabove '.g:voom_tree_width.'vsplit' wincmd p elseif g:voom_tree_placement==#'right' exe 'rightbelow '.g:voom_tree_width.'vsplit' wincmd p endif endfunc func! voom#ToBody(body) abort "{{{2 " Move to window with Body a:body or load it in a new window. " Already there. if bufnr('')==a:body | return | endif " Try previous window. let wnr = winnr('#') if winbufnr(wnr)==a:body exe wnr.'wincmd w' return endif " There is a window with buffer a:body . if bufwinnr(a:body) > 0 exe bufwinnr(a:body).'wincmd w' return endif if !bufloaded(a:body) " Body is unloaded. Load it and force outline update. if bufexists(a:body) call voom#ToBodyWin() exe 'b '.a:body call voom#BodyUpdateTree() call voom#WarningMsg('VOoM: loaded Body buffer and updated outline') " Body doesn't exist. Bail out. else let tree = s:voom_bodies[a:body].tree if !has_key(s:voom_trees, tree) || s:voom_trees[tree]!=a:body echoerr "VOoM: INTERNAL ERROR" return -1 endif call voom#UnVoom(a:body,tree) call voom#ErrorMsg("VOoM: Body ".a:body." does not exist. Cleanup has been performed.") endif return -1 endif " Create new window and load there. call voom#ToBodyWin() exe 'b '.a:body return 1 endfunc func! voom#ToLogWin() "{{{2 " Create new window where PyLog will be loaded. if g:voom_log_placement==#'top' exe 'topleft '.g:voom_log_height.'split' elseif g:voom_log_placement==#'bottom' exe 'botright '.g:voom_log_height.'split' elseif g:voom_log_placement==#'left' exe 'topleft '.g:voom_log_width.'vsplit' elseif g:voom_log_placement==#'right' exe 'botright '.g:voom_log_width.'vsplit' endif endfunc "---TREE BUFFERS------------------------------{{{1 func! voom#TreeCreate(body, blnr) "{{{2 " Create new Tree buffer in the current window for Body body, Body line blnr. let b_name = fnamemodify(bufname(a:body),":t") if b_name=='' | let b_name='NoName' | endif silent exe 'edit '.fnameescape(b_name).'_VOOM'.a:body let tree = bufnr('') """ Finish initializing VOoM data for this Body. let s:voom_bodies[a:body].tree = tree let s:voom_trees[tree] = a:body let s:voom_bodies[a:body].tick_ = 0 exe s:PYCMD "_VOoM2657.VOOMS[int(vim.eval('a:body'))].tree = int(vim.eval('l:tree'))" exe s:PYCMD "_VOoM2657.VOOMS[int(vim.eval('a:body'))].Tree = vim.current.buffer" " set folding options here: voom_TreeCreate() needs folding call voom#TreeConfig() let l:blnShow = -1 """ Create outline and draw Tree lines. let lz_ = &lz | set lz setl ma let ul_ = &l:ul | setl ul=-1 try let l:ok = 0 exe "keepj" s:PYCMD "_VOoM2657.updateTree(int(vim.eval('a:body')), int(vim.eval('l:tree')))" " Draw = mark. Create folding from o marks. Must be done afer creating outline and folding. " this assigns s:voom_bodies[body].snLn " If there is Python error in updateTree(), execution does not stop here if Voomlog is on. if l:ok exe s:PYCMD "_VOoM2657.voom_TreeCreate()" let snLn = s:voom_bodies[a:body].snLn " Initial draw puts = on first line. if snLn > 1 keepj call setline(snLn, '='.getline(snLn)[1 : ]) keepj call setline(1, ' '.getline(1)[1 : ]) endif let s:voom_bodies[a:body].tick_ = s:voom_bodies[a:body].tick endif finally let &l:ul = ul_ setl noma let &lz=lz_ " Python code failed. Abort. (Enable :Voomlog to see Python traceback.) if !l:ok call voom#UnVoom(a:body,tree) call voom#ErrorMsg('VOoM: voom#TreeCreate(): Cannot create outline. Python function updateTree() failed. Enable :Voomlog to see Python traceback.') return endif endtry " apply user's window-local options here: voom_TreeCreate() sets fdl call voom#TreeConfigFT(a:body) """ Position cursor on snLn line. VOoM**voom_notes.txt#id_20110125210844 keepj normal! gg if snLn > 1 exe "normal! ".snLn."G0f|m'" call voom#TreeZV() if line('w0')!=1 && line('w$')!=line('$') normal! zz endif endif "--- the end if markup mode other than fmr mode --- " blnShow is set by voom_TreeCreate() when there is Body headline marked with = if l:blnShow > 0 " go to Body let wnr_ = winnr() if voom#ToBody(a:body) < 0 | return | endif " show fold at l:blnShow exe 'keepj normal! '.l:blnShow.'G' if &fdm==#'marker' normal! zMzvzt else normal! zvzt endif " go back to Tree let wnr_ = winnr('#') if winbufnr(wnr_)==tree exe wnr_.'wincmd w' else exe bufwinnr(tree).'wincmd w' endif endif endfunc func! voom#TreeConfig() "{{{2 " Configure the current buffer as a Tree buffer. augroup VoomTree au! * au BufEnter call voom#TreeBufEnter() "au BufUnload call voom#TreeBufUnload() au BufUnload nested call voom#TreeBufUnload() augroup END call voom#TreeMap() call voom#TreeConfigWin() " local to buffer, may be changed by the user setl bufhidden=wipe " Options local to buffer. DO NOT CHANGE. setl nobuflisted buftype=nofile noswapfile setl noro ma ff=unix noma endfunc func! voom#TreeConfigWin() "{{{2 " Tree window-local options. setl foldenable setl foldtext=getline(v:foldstart).'\ \ \ /'.(v:foldend-v:foldstart) setl foldmethod=expr setl foldexpr=voom#TreeFoldexpr(v:lnum) setl cul nocuc nowrap nolist "setl winfixheight setl winfixwidth let w:voom_tree = 'VOoM' endfunc func! voom#TreeConfigFT(body) "{{{2 " Allow customization via ftplugin/voomtree.vim, syntax/voomtree.vim, etc. setl ft=voomtree " Tree buffer default syntax highlighting. Must be done after'setl ft=voomtree'. if exists('b:current_syntax') | return | endif syn match Title /\%1l.*/ "syn keyword Todo contained TODO XXX FIXME syn keyword Todo TODO XXX FIXME syn match WarningMsg /^[^|]\+|\zs!\+/ let FT = getbufvar(a:body, "&ft") if FT==#'text' " organizer nodes: /headline, #headline syn match Comment '^[^|]\+|\zs[/#].*' contains=Todo elseif FT==#'python' syn match Statement /^[^|]\+|\zs\%(def\s\|class\s\)/ syn match Define /^[^|]\+|\zs@/ syn match Comment /#.*/ contains=Todo elseif FT==#'vim' syn match Statement /^[^|]\+|\zs\%(fu\%[nction]\>\|def\s\|class\s\)/ syn match Comment /".*/ contains=Todo " treat # as comment: can be embedded Python, Perl, etc syn match Comment /^[^|]\+|\zs#.*/ contains=Todo elseif FT==#'tex' syn match Comment /%.*/ contains=Todo elseif FT==#'html' || FT==#'xml' syn match Comment /\|$\)/ contains=Todo else " Organizer nodes: /headline, #headline. Takes adequate care of 'cms' /*%s*/ and #%s. syn match Comment '^[^|]\+|\zs[/#].*' contains=Todo " hi as comment after first part of 'cms' unless it's /* " /*%s*/ is default 'cms' and thus often means nothing let CMS = substitute(getbufvar(a:body, '&cms'), '%s.*', '', '') if CMS !~ '^\s*\%(/\*\|\)\s*$' let CMS = escape(CMS, '*.^$[]/\') exec 'syn match Comment /^[^|]\+|.\{-}\zs' . CMS . '.*/ contains=Todo' endif endif let b:current_syntax = 'voomtree' endfunc func! voom#TreeBufEnter() "{{{2 " Tree BufEnter au. " Update outline if Body changed since last update. Redraw Tree if needed. let tree = bufnr('') let body = s:voom_trees[tree] if !exists('w:voom_tree') | call voom#TreeConfigWin() | call voom#TreeConfigFT(body) | endif if s:voom_bodies[body].tick_==s:voom_bodies[body].tick || &ma || voom#BufNotLoaded(body) return endif let snLn_ = s:voom_bodies[body].snLn setl ma let ul_ = &l:ul | setl ul=-1 try let l:ok = 0 exe "keepj" s:PYCMD "_VOoM2657.updateTree(int(vim.eval('l:body')), int(vim.eval('l:tree')))" if l:ok let s:voom_bodies[body].tick_ = s:voom_bodies[body].tick endif finally let &l:ul = ul_ setl noma endtry " The = mark is placed by updateTree() " When nodes are deleted by editing Body, snLn can get > last Tree lnum, " updateTree() will set snLn to the last line lnum. if snLn_ != s:voom_bodies[body].snLn keepj normal! Gzv endif endfunc func! voom#TreeBufUnload() "{{{2 " Tree BufUnload au. Wipe out Tree and cleanup. let tree = expand("") if !exists("s:voom_trees") || !has_key(s:voom_trees, tree) echoerr "VOoM: INTERNAL ERROR" return endif let body = s:voom_trees[tree] "echom bufexists(tree) --always 0 "exe 'noautocmd bwipeout '.tree exe 'au! VoomTree * ' try exe 'bwipeout '.tree catch /^Vim\%((\a\+)\)\=:E937/ " E937 occurs in Vim 8.0 (Patch 7.4.2324), wipeout still happens endtry call voom#UnVoom(body,tree) endfunc func! voom#TreeFoldexpr(lnum) "{{{2 let ind = stridx(getline(a:lnum),'|') / 2 let indn = stridx(getline(a:lnum+1),'|') / 2 return indn>ind ? '>'.ind : ind-1 "return indn>ind ? '>'.ind : indnind ? '>'.ind : '<'.indn endfunc func! voom#TreeMap() "{{{2= " Tree buffer local mappings and commands. let cpo_ = &cpo | set cpo&vim """ disable keys that change text {{{ " disable common text change commands nnoremap o noremap O noremap i noremap I noremap a noremap A noremap s noremap S noremap r noremap R noremap x noremap X noremap D noremap J noremap c noremap C noremap P noremap . noremap = noremap ~ noremap noremap noremap noremap p noremap d noremap < noremap > noremap ^ noremap _ " disable undo (also case conversion) noremap u noremap U noremap " disable creation/deletion of folds noremap zf noremap zF noremap zd noremap zD noremap zE """ }}} """ node navigation and selection {{{ "--- the following select node ----------- exe "nnoremap ".g:voom_return_key." :call voom#TreeSelect(0)" exe "vnoremap ".g:voom_return_key." :call voom#TreeSelect(0)" "exe "vnoremap ".g:voom_return_key." " exe "nnoremap ".g:voom_tab_key." :call voom#ToTreeOrBodyWin()" exe "vnoremap ".g:voom_tab_key." :call voom#ToTreeOrBodyWin()" "exe "vnoremap ".g:voom_tab_key." " " MOUSE: Left mouse release. Triggered when resizing window with the mouse. nnoremap :call voom#TreeMouseClick() inoremap " disable Left mouse double click to avoid entering Visual mode nnoremap <2-LeftMouse> nnoremap :call voom#TreeSelect(1) nnoremap :call voom#TreeSelect(1) nnoremap :call voom#TreeLeft() nnoremap :call voom#TreeRight() nnoremap x :call voom#TreeToMark(0) nnoremap X :call voom#TreeToMark(1) "--- the following don't select node ----------- nnoremap :call voom#TreeToggleFold() vnoremap "vnoremap :call voom#TreeToggleFold() " put cursor on the selected node nnoremap = :call voom#TreeToSelected() " put cursor on the node marked with '=', if any nnoremap + :call voom#TreeToStartupNode() " go up to the parent node nnoremap P :call voom#Tree_Pco('P','n') " go up to the parent node and contract it nnoremap c :call voom#Tree_Pco('c','n') " go down to direct child node nnoremap o :call voom#Tree_Pco('o','n') " contract all siblings of current node nnoremap C :call voom#Tree_CO('zC','n') " contract all nodes in Visual selection vnoremap C :call voom#Tree_CO('zC','v') " expand all siblings of current node nnoremap O :call voom#Tree_CO('zO','n') " expand all nodes in Visual selection vnoremap O :call voom#Tree_CO('zO','v') " go up to the previous sibling nnoremap K :call voom#Tree_KJUD('K','n') vnoremap K :call voom#Tree_KJUD('K','v') " go down to the next sibling nnoremap J :call voom#Tree_KJUD('J','n') vnoremap J :call voom#Tree_KJUD('J','v') " go up to the uppermost sibling nnoremap U :call voom#Tree_KJUD('U','n') vnoremap U :call voom#Tree_KJUD('U','v') " go down to the downmost sibling nnoremap D :call voom#Tree_KJUD('D','n') vnoremap D :call voom#Tree_KJUD('D','v') """ }}} """ outline operations {{{ " edit Body text nnoremap i :call voom#OopEdit('i') nnoremap I :call voom#OopEdit('I') " insert new node nnoremap a :call voom#OopInsert('') nnoremap aa :call voom#OopInsert('') nnoremap A :call voom#OopInsert('as_child') nnoremap AA :call voom#OopInsert('as_child') " move nnoremap u :call voom#Oop('up', 'n') nnoremap :call voom#Oop('up', 'n') nnoremap ^^ :call voom#Oop('up', 'n') vnoremap u :call voom#Oop('up', 'v') vnoremap :call voom#Oop('up', 'v') vnoremap ^^ :call voom#Oop('up', 'v') nnoremap d :call voom#Oop('down', 'n') nnoremap :call voom#Oop('down', 'n') nnoremap __ :call voom#Oop('down', 'n') vnoremap d :call voom#Oop('down', 'v') vnoremap :call voom#Oop('down', 'v') vnoremap __ :call voom#Oop('down', 'v') nnoremap l :call voom#Oop('left', 'n') nnoremap :call voom#Oop('left', 'n') nnoremap << :call voom#Oop('left', 'n') vnoremap l :call voom#Oop('left', 'v') vnoremap :call voom#Oop('left', 'v') vnoremap << :call voom#Oop('left', 'v') nnoremap r :call voom#Oop('right', 'n') nnoremap :call voom#Oop('right', 'n') nnoremap >> :call voom#Oop('right', 'n') vnoremap r :call voom#Oop('right', 'v') vnoremap :call voom#Oop('right', 'v') vnoremap >> :call voom#Oop('right', 'v') " cut/copy/paste nnoremap dd :call voom#Oop('cut', 'n') vnoremap dd :call voom#Oop('cut', 'v') nnoremap yy :call voom#Oop('copy', 'n') vnoremap yy :call voom#Oop('copy', 'v') nnoremap pp :call voom#OopPaste() " mark/unmark nnoremap m :call voom#OopMark('mark', 'n') vnoremap m :call voom#OopMark('mark', 'v') nnoremap M :call voom#OopMark('unmark', 'n') vnoremap M :call voom#OopMark('unmark', 'v') " mark node as selected node nnoremap = :call voom#OopMarkStartup() " select Body region nnoremap R :call voom#OopSelectBodyRange('n') vnoremap R :call voom#OopSelectBodyRange('v') """ }}} """ save/Restore Tree folding {{{ nnoremap fs :call voom#OopFolding(line('.'),line('.'), 'save') nnoremap fr :call voom#OopFolding(line('.'),line('.'), 'restore') nnoremap fas :call voom#OopFolding(1,line('$'), 'save') nnoremap far :call voom#OopFolding(1,line('$'), 'restore') """ }}} """ various commands {{{ " echo Tree headline nnoremap s :echo getline('.')[(stridx(getline('.'),'')+1) : ] " echo UNL nnoremap S :call voom#EchoUNL() "nnoremap :call voom#Help() nnoremap e :call voom#Exec('') " delete outline nnoremap q :call voom#DeleteOutline() """ }}} let &cpo = cpo_ return " Use noremap to disable keys. This must be done first. " Use nnoremap and vnoremap in VOoM mappings, don't use noremap. " It's better to disable keys by mapping to instead of : " VOoM**voom_notes.txt#id_20110121201243 " " Do not map . Not triggered on first click in the buffer. " Triggered on first click in another buffer. Vim probably doesn't know " what buffer it is until after the click. " " Can't use Ctrl: is Tab; , are page up/down. " Use instead of Ctrl. " " Still up for grabs: [ ] { } ~ - ! endfunc "---Outline Navigation---{{{2 " To select node from Tree, call voom#TreeSelect(). ALWAYS return immediately " after calling voom#TreeSelect() in case Body checks fail. " " To position cursor on | in Tree (not needed if voom#TreeSelect() is called): " call cursor(0,stridx(getline('.'),'|')+1) " or " normal! 0f| " Notes: VOoM**voom_notes.txt#id_20110116213809 " zt is affected by 'scrolloff' (voom#TreeSelect) func! voom#TreeSelect(stayInTree) "{{{3 " Select node corresponding to the current Tree line. " Show correspoding Body's node. " Leave cursor in Body if the current line was in the selected node and !stayInTree. let tree = bufnr('') let body = s:voom_trees[tree] if voom#BufNotLoaded(body) | return | endif let lnum = line('.') let snLn = s:voom_bodies[body].snLn let lz_ = &lz | set lz call voom#TreeZV() call cursor(0,stridx(getline('.'),'|')+1) " compute l:blnum1, l:blnum2 -- start and end of the selected Body node " set VO.snLn before going to Body in case outline update is forced exe s:PYCMD "_VOoM2657.voom_TreeSelect()" """ Mark new line with =. Remove old = mark. if lnum != snLn setl ma | let ul_ = &l:ul | setl ul=-1 keepj call setline(lnum, '='.getline(lnum)[1 : ]) keepj call setline(snLn, ' '.getline(snLn)[1 : ]) setl noma | let &l:ul = ul_ let s:voom_bodies[body].snLn = lnum endif """ Go to Body, show selected node, come back or stay in Body. if voom#ToBody(body) < 0 | let &lz=lz_ | return | endif if voom#BodyCheckTicks(body) < 0 | let &lz=lz_ | return | endif let blnum = line('.') let gotNewNode = (blnum < l:blnum1) || (blnum > l:blnum2) if gotNewNode exe 'keepj normal! '.l:blnum1.'G' if &fdm ==# 'marker' normal! zMzvzt else normal! zvzt endif endif """ Go back to Tree after showing new node in Body. """ Stay in Body if Body's current line was in the selected node. if gotNewNode || a:stayInTree let wnr_ = winnr('#') if winbufnr(wnr_)==tree exe wnr_.'wincmd w' else exe bufwinnr(tree).'wincmd w' endif endif let &lz=lz_ endfunc func! voom#TreeZV() "{{{3 " Make current line visible. Return -1 if it was hidden. Like zv, but when " current line starts a fold, do not open that fold. let lnum = line('.') let fc = foldclosed(lnum) if fc < lnum && fc > 0 normal! zo let fc = foldclosed(lnum) while fc < lnum && fc > 0 normal! zo let fc = foldclosed(lnum) endwhile return -1 endif endfunc func! voom#TreeToLine(lnum) "{{{3 " Put cursor on line lnum, e.g., snLn. if (line('w0') < a:lnum) && (a:lnum > 'w$') let offscreen = 0 else let offscreen = 1 endif exe 'keepj normal! '.a:lnum.'G' call voom#TreeZV() call cursor(0,stridx(getline('.'),'|')+1) if offscreen==1 normal! zz endif endfunc func! voom#TreeToggleFold() "{{{3 " Toggle fold at cursor: expand/contract node. let lnum=line('.') let ln_status = voom#FoldStatus(lnum) if ln_status==#'folded' normal! zo elseif ln_status==#'notfolded' if stridx(getline(lnum),'|') < stridx(getline(lnum+1),'|') normal! zc endif elseif ln_status==#'hidden' call voom#TreeZV() endif endfunc func! voom#TreeMouseClick() "{{{3 " Select node. Toggle fold if click is outside of headline text. if !has_key(s:voom_trees, bufnr('')) call voom#ErrorMsg('VOoM: in wrong buffer') return endif if virtcol('.')+1 >= virtcol('$') || col('.')-1 < stridx(getline('.'),'|') call voom#TreeToggleFold() endif call voom#TreeSelect(1) endfunc func! voom#TreeLeft() "{{{3 " Go to parent node, but first contract current node if it's expanded. if voom#TreeZV() < 0 call voom#TreeSelect(1) return endif let lnum = line('.') if lnum==1 | return | endif let ind = stridx(getline(lnum),'|') " next line has bigger indent and line is an opened fold -- close fold if stridx(getline(lnum+1),'|') > ind && foldclosed(lnum) < 0 normal! zc " top level -- do not go anywhere elseif ind < 3 " go to parent else call search('\m^[^|]\{0,'.(ind-2).'}|', 'bWe') endif call voom#TreeSelect(1) endfunc func! voom#TreeRight() "{{{3 " Go to first child of current node. if voom#TreeZV() < 0 call voom#TreeSelect(1) return endif let lnum = line('.') if lnum==1 | return | endif " line is first line of a closed fold, does not necessarily have children if foldclosed(lnum)==lnum normal! zv " next line has bigger indent elseif stridx(getline(lnum),'|') < stridx(getline(lnum+1),'|') normal! j endif call voom#TreeSelect(1) endfunc func! voom#Tree_KJUD(action, mode) "{{{3 " Move cursor to a sibling node as specified by action: U D K J. if voom#TreeZV() < 0 call cursor(0,stridx(getline('.'),'|')+1) return endif let lnum = line('.') if lnum==1 | return | endif if a:mode==#'v' let [ln1,ln2] = [line("'<"), line("'>")] else let [ln1,ln2] = [lnum, lnum] endif let vcount1 = v:count1 if ln2 > ln1 " put the cursor on the last _visible_ line of selection if a:action==#'D' || a:action==#'J' exe 'keepj normal! '.ln2.'Gkj' " put the cursor on the first line of selection, should be always visible elseif a:action==#'U' || a:action==#'K' exe 'keepj normal! '.ln1.'G' endif endif " node's level is indent of first | keepj normal! 0f| let ind = virtcol('.')-1 let lnum = line('.') " go to the downmost sibling: down to next elder, up to sibling if a:action==#'D' call search('\m^[^|]\{0,'.(ind-2).'}|', 'We') if line('.') > lnum call search('\m^[^|]\{'.(ind).'}|', 'bWe') else keepj normal! G0f| call search('\m^[^|]\{'.(ind).'}|', 'bcWe') endif " go to the uppermost sibling: up to parent, down to sibling elseif a:action==#'U' call search('\m^[^|]\{0,'.(ind-2).'}|', 'bWe') if line('.') < lnum call search('\m^[^|]\{'.(ind).'}|', 'We') else keepj normal! gg call search('\m^[^|]\{'.(ind).'}|', 'We') endif " go down to the next sibling, stopline is next elder node elseif a:action==#'J' let stopline = search('\m^[^|]\{0,'.(ind-2).'}|', 'Wn') for i in range(vcount1) call search('\m^[^|]\{'.(ind).'}|', 'We', stopline) endfor " go up to the previous sibling, stopline is parent elseif a:action==#'K' let stopline = search('\m^[^|]\{0,'.(ind-2).'}|', 'bWn') for i in range(vcount1) call search('\m^[^|]\{'.(ind).'}|', 'bWe', stopline) endfor endif call voom#TreeZV() " restore and extend Visual selection if a:mode==#'v' let lnum = line(".") exe 'keepj normal! gv'.lnum.'G0f|' endif endfunc func! voom#Tree_Pco(action, mode) "{{{3 " action: P c o if voom#TreeZV() < 0 call cursor(0,stridx(getline('.'),'|')+1) return endif let lnum = line('.') if lnum==1 | return | endif """ action 'P' or 'c': go up to parent, contract if 'c' if a:action==#'c' || a:action==#'P' keepj normal! 0f| let ind = virtcol('.')-1 call search('\m^[^|]\{0,'.(ind-2).'}|', 'bWe') if a:action==#'c' && line('.') < lnum normal! zc endif return " action 'o': go to first child node, same as voom#TreeRight() elseif a:action==#'o' " line is first line of a closed fold, does not necessarily have children if foldclosed(lnum)==lnum normal! zv endif if stridx(getline(lnum),'|') < stridx(getline(lnum+1),'|') normal! j endif normal! 0f| endif endfunc func! voom#Tree_CO(action, mode) "{{{3 " action: zC zO if voom#TreeZV() < 0 call cursor(0,stridx(getline('.'),'|')+1) return endif let lnum = line('.') if lnum==1 | return | endif """ do 'zC' or 'zO' for all siblings of current node let winsave_dict = winsaveview() if a:mode==#'n' keepj normal! 0f| let ind = virtcol('.')-1 " go the uppermost sibling: up to parent, down to sibling call search('\m^[^|]\{0,'.(ind-2).'}|', 'bWe') if line('.') < lnum let lnUp = search('\m^[^|]\{'.(ind).'}|', 'We') else keepj normal! gg let lnUp = search('\m^[^|]\{'.(ind).'}|', 'We') endif exe 'keepj normal! '.lnum.'G0f|' " go to the last subnode of the downmost sibling: down to elder node, up call search('\m^[^|]\{0,'.(ind-2).'}|', 'We') if line('.') > lnum exe 'keepj normal! '.(line('.')-1).'G0f|' else keepj normal! G0f| endif try "exe 'keepj normal! V'.lnUp.'GzC' exe 'keepj normal! V'.lnUp.'G'.a:action catch /^Vim\%((\a\+)\)\=:E490/ endtry """ do 'zC' or 'zO' for all nodes in Visual selection elseif a:mode==#'v' try "normal! gvzC exe 'normal! gv'.a:action catch /^Vim\%((\a\+)\)\=:E490/ endtry endif exe 'keepj normal! '.lnum.'G0f|' call voom#TreeZV() call winrestview(winsave_dict) endfunc func! voom#TreeToSelected() "{{{3 " Put cursor on selected node, that is on SnLn line. let lnum = s:voom_bodies[s:voom_trees[bufnr('')]].snLn call voom#TreeToLine(lnum) endfunc func! voom#TreeToStartupNode() "{{{3 " Put cursor on startup node, if any: node marked with '=' in Body headline. " Warn if there are several such nodes. let body = s:voom_trees[bufnr('')] if s:voom_bodies[body].MTYPE > 0 call voom#ErrorMsg('VOoM: startup nodes are not available in this markup mode') return endif " this creates l:lnums exe s:PYCMD "_VOoM2657.voom_TreeToStartupNode()" if len(l:lnums)==0 call voom#WarningMsg("VOoM: no nodes marked with '='") return endif call voom#TreeToLine(l:lnums[-1]) if len(l:lnums)>1 call voom#WarningMsg("VOoM: multiple nodes marked with '=': ".join(l:lnums, ', ')) endif endfunc func! voom#TreeToMark(back) "{{{3 " Go to next or previous marked node. if a:back==1 normal! 0 let found = search('\C\v^.x', 'bw') else let found = search('\C\v^.x', 'w') endif if found==0 call voom#WarningMsg("VOoM: there are no marked nodes") else call voom#TreeSelect(1) endif endfunc "---Outline Operations---{{{2 " NOTES: " getbufvar(body,'changedtick') returns '' if Vim version is < 7.3.105 " " Operations other than Sort rely on verification and must call " voom#OopFromBody() while Tree is &ma to suppress outline update on Tree " BufEnter. " " Note that voom#OopFromBody() is often called from Python code. func! voom#OopSelectBodyRange(mode) "{{{3 " Move to Body and select region corresponding to node(s) in the Tree. let tree = bufnr('') if voom#BufNotTree(tree) | return | endif let body = s:voom_trees[tree] if voom#BufNotLoaded(body) | return | endif let ln = line('.') if voom#FoldStatus(ln)==#'hidden' call voom#ErrorMsg("VOoM: current line is hidden in fold") return endif " normal mode: use current line if a:mode==#'n' let [ln1, ln2] = [ln, ln] " visual mode: use range elseif a:mode==#'v' let [ln1, ln2] = [line("'<"), line("'>")] endif if voom#ToBody(body) < 0 | return | endif if voom#BodyCheckTicks(body) < 0 | return | endif " compute bln1 and bln2 exe s:PYCMD "_VOoM2657.voom_OopSelectBodyRange()" " this happens when ln2==1 and the first headline is top of buffer if l:bln2==0 | return | endif exe 'normal! '.bln1.'Gzv'.bln2.'GzvV'.bln1.'G' if line('w$') < bln2 normal! zt endif endfunc func! voom#OopEdit(op) "{{{3 " Edit Body. Move cursor to Body on the node's first (i) or last (I) line. let tree = bufnr('') if voom#BufNotTree(tree) | return | endif let body = s:voom_trees[tree] if voom#BufNotLoaded(body) | return | endif let lnum = line('.') "if lnum==1 | return | endif if voom#FoldStatus(lnum)==#'hidden' call voom#ErrorMsg("VOoM: current line is hidden in fold") return endif let head = getline(lnum)[1+stridx(getline(lnum),'|') : ] " compute l:bLnr -- Body lnum to which to jump exe s:PYCMD "_VOoM2657.voom_OopEdit()" let lz_ = &lz | set lz if voom#ToBody(body) < 0 | let &lz=lz_ | return | endif if voom#BodyCheckTicks(body) < 0 | let &lz=lz_ | return | endif " do zz only when target line is not in the window if l:bLnr < line('w0') || l:bLnr > line('w$') let do_zz = 1 else let do_zz = 0 endif exe 'keepj normal! '.l:bLnr.'Gzv^' if do_zz normal! zz endif if a:op==#'i' " put cursor on the headline text, then on the first word char call search('\V'.substitute(head,'\','\\\\','g'), 'c', line('.')) call search('\m\<', 'c', line('.')) endif let &lz=lz_ endfunc func! voom#OopInsert(as_child) "{{{3 " Insert new node, headline text should be NewHeadline. let tree = bufnr('') if voom#BufNotTree(tree) | return | endif let body = s:voom_trees[tree] if voom#BufNotLoaded(body) | return | endif if voom#BufNotEditable(body) | return | endif let ln = line('.') let ln_status = voom#FoldStatus(ln) if ln_status==#'hidden' call voom#ErrorMsg("VOoM: current line is hidden in fold") return endif if a:as_child==#'as_child' && s:voom_bodies[body].MTYPE > 1 call voom#ErrorMsg('VOoM: operation ''Add New Headline As Child'' is not available in this markup mode') return endif let lz_ = &lz | set lz " check ticks, getbufvar(body,'changedtick') is '' if Vim < 7.3.105 if s:voom_bodies[body].tick_ != getbufvar(body,'changedtick') if voom#ToBody(body) < 0 | let &lz=lz_ | return | endif if voom#BodyCheckTicks(body) < 0 | let &lz=lz_ | return | endif call voom#OopFromBody(body,tree,-1) endif setl ma if a:as_child==#'as_child' exe "keepj" s:PYCMD "_VOoM2657.voom_OopInsert(as_child=True)" else exe "keepj" s:PYCMD "_VOoM2657.voom_OopInsert(as_child=False)" endif setl noma let snLn = s:voom_bodies[body].snLn exe "keepj normal! ".snLn."G0f|" call voom#TreeZV() if voom#ToBody(body) < 0 | let &lz=lz_ | return | endif exe "keepj normal! ".l:bLnum."Gzvz\" call search('\CNewHeadline', 'c', line('.')) let &lz=lz_ endfunc func! voom#OopPaste() "{{{3 " Paste the content of the "+ register as an outline. let tree = bufnr('') if voom#BufNotTree(tree) | return | endif let body = s:voom_trees[tree] if voom#BufNotLoaded(body) | return | endif if voom#BufNotEditable(body) | return | endif let ln = line('.') let ln_status = voom#FoldStatus(ln) if ln_status==#'hidden' call voom#ErrorMsg("VOoM: current line is hidden in fold") return endif let lz_ = &lz | set lz if voom#ToBody(body) < 0 | let &lz=lz_ | return | endif if voom#BodyCheckTicks(body) < 0 | let &lz=lz_ | return | endif " default bnlShow -1 means pasting not possible let l:blnShow = -1 let l:pyOK = 0 let bbTick = b:changedtick call setbufvar(tree, '&ma', 1) exe "keepj" s:PYCMD "_VOoM2657.voom_OopPaste()" call setbufvar(tree, '&ma', 0) if l:blnShow > 0 let s:voom_bodies[body].snLn = l:ln1 if l:ln1==l:ln2 call voom#OopShowTree(l:ln1, l:ln2, 'n') else call voom#OopShowTree(l:ln1, l:ln2, 'v') endif endif let &lz=lz_ call voom#OopVerify(body, tree, 'paste') if l:pyOK != 1 call voom#OopPyNotOK(body, bbTick, 'paste') endif endfunc func! voom#OopMark(op, mode) "{{{3 " Mark or unmark current node or all nodes in selection " Checks and init vars. {{{ let tree = bufnr('') if voom#BufNotTree(tree) | return | endif let body = s:voom_trees[tree] if s:voom_bodies[body].MTYPE > 0 call voom#ErrorMsg('VOoM: marked nodes are not available in this markup mode') return endif if voom#BufNotLoaded(body) | return | endif if voom#BufNotEditable(body) | return | endif let ln = line('.') if voom#FoldStatus(ln)==#'hidden' call voom#ErrorMsg("VOoM: current line is hidden in fold") return endif " normal mode: use current line if a:mode==#'n' let ln1 = ln let ln2 = ln " visual mode: use range elseif a:mode==#'v' let ln1 = line("'<") let ln2 = line("'>") endif " don't touch first line if ln1==1 && ln2==ln1 return elseif ln1==1 && ln2>1 let ln1=2 endif " }}} let lz_ = &lz | set lz let t_fdm = &fdm if voom#ToBody(body) < 0 | let &lz=lz_ | return | endif if voom#BodyCheckTicks(body) < 0 | let &lz=lz_ | return | endif let l:pyOK = 0 let bbTick = b:changedtick let b_fdm=&fdm | setl fdm=manual call setbufvar(tree, '&fdm', 'manual') call setbufvar(tree, '&ma', 1) if a:op==#'mark' exe "keepj" s:PYCMD "_VOoM2657.voom_OopMark()" elseif a:op==#'unmark' exe "keepj" s:PYCMD "_VOoM2657.voom_OopUnmark()" endif let &fdm=b_fdm call voom#OopFromBody(body,tree,-1) call setbufvar(tree, '&ma', 0) let &fdm=t_fdm let &lz=lz_ call voom#OopVerify(body, tree, a:op) if l:pyOK != 1 call voom#OopPyNotOK(body, bbTick, a:op) endif endfunc func! voom#OopMarkStartup() "{{{3 " Mark current node as startup node. let tree = bufnr('') if voom#BufNotTree(tree) | return | endif let body = s:voom_trees[tree] if s:voom_bodies[body].MTYPE > 0 call voom#ErrorMsg('VOoM: startup nodes are not available in this markup mode') return endif if voom#BufNotLoaded(body) | return | endif if voom#BufNotEditable(body) | return | endif let ln = line('.') if voom#FoldStatus(ln)==#'hidden' call voom#ErrorMsg("VOoM: current line is hidden in fold") return endif let lz_ = &lz | set lz if voom#ToBody(body) < 0 | let &lz=lz_ | return | endif if voom#BodyCheckTicks(body) < 0 | let &lz=lz_ | return | endif let l:pyOK = 0 let bbTick = b:changedtick call setbufvar(tree, '&ma', 1) exe "keepj" s:PYCMD "_VOoM2657.voom_OopMarkStartup()" call voom#OopFromBody(body,tree,-1) call setbufvar(tree, '&ma', 0) let &lz=lz_ call voom#OopVerify(body, tree, 'markStartup') if l:pyOK != 1 call voom#OopPyNotOK(body, bbTick, 'markStartup') endif endfunc func! voom#Oop(op, mode) "{{{3 " Outline operations that can be perfomed on the current node or on nodes in " Visual selection. All apply to branches, not to single nodes. " Checks and init vars. {{{ let tree = bufnr('') if voom#BufNotTree(tree) | return | endif let body = s:voom_trees[tree] if voom#BufNotLoaded(body) | return | endif if a:op!=#'copy' && voom#BufNotEditable(body) | return | endif let ln = line('.') if voom#FoldStatus(ln)==#'hidden' call voom#ErrorMsg("VOoM: current line is hidden in fold") return endif " normal mode: use current line if a:mode==#'n' let [ln1,ln2] = [ln,ln] " visual mode: use range elseif a:mode==#'v' let [ln1,ln2] = [line("'<"),line("'>")] " before op: move cursor to ln1 or ln2 endif if ln1==1 call voom#ErrorMsg("VOoM (".a:op."): first Tree line cannot be operated on") return endif " set ln2 to last node in the last sibling branch in selection " check validity of selection exe s:PYCMD "vim.command('let ln2=%s' %_VOoM2657.voom_OopSelEnd())" if ln2==0 call voom#ErrorMsg("VOoM: invalid Tree selection") return endif " }}} let lz_ = &lz | set lz let l:doverif = 1 " bnlShow=-1 means no changes were made, pyOK=0 means Python code failed let l:blnShow = -1 let l:pyOK = 0 if a:op==#'up' " {{{ if ln1<3 | let &lz=lz_ | return | endif if a:mode==#'v' " must be on first line of selection exe "keepj normal! ".ln1."G" endif " ln before which to insert, also, new snLn normal! k let lnUp1 = line('.') " top node of a tree after which to insert normal! k let lnUp2 = line('.') if voom#ToBody(body) < 0 | let &lz=lz_ | return | endif if voom#BodyCheckTicks(body) < 0 | let &lz=lz_ | return | endif let bbTick = b:changedtick call setbufvar(tree, '&ma', 1) exe "keepj" s:PYCMD "_VOoM2657.voom_OopUp()" call setbufvar(tree, '&ma', 0) if l:blnShow > 0 let s:voom_bodies[body].snLn = lnUp1 let lnEnd = lnUp1+ln2-ln1 call voom#OopShowTree(lnUp1, lnEnd, a:mode) endif " }}} elseif a:op==#'down' " {{{ if ln2==line('$') | let &lz=lz_ | return | endif " must be on the last node of current tree or last tree in selection exe "keepj normal! ".ln2."G" " line after which to insert normal! j let lnDn1 = line('.') " should be ln2+1 let lnDn1_status = voom#FoldStatus(lnDn1) if voom#ToBody(body) < 0 | let &lz=lz_ | return | endif if voom#BodyCheckTicks(body) < 0 | let &lz=lz_ | return | endif let bbTick = b:changedtick call setbufvar(tree, '&ma', 1) exe "keepj" s:PYCMD "_VOoM2657.voom_OopDown()" call setbufvar(tree, '&ma', 0) if l:blnShow > 0 let s:voom_bodies[body].snLn = l:snLn let lnEnd = snLn+ln2-ln1 call voom#OopShowTree(snLn, lnEnd, a:mode) endif " }}} elseif a:op==#'right' " {{{ if ln1==2 | let &lz=lz_ | return | endif if voom#ToBody(body) < 0 | let &lz=lz_ | return | endif if voom#BodyCheckTicks(body) < 0 | let &lz=lz_ | return | endif let bbTick = b:changedtick let b_fdm=&fdm | setl fdm=manual call setbufvar(tree, '&ma', 1) exe "keepj" s:PYCMD "_VOoM2657.voom_OopRight()" call setbufvar(tree, '&ma', 0) if l:blnShow > 0 let s:voom_bodies[body].snLn = ln1 call voom#OopShowTree(ln1, ln2, a:mode) endif " }}} elseif a:op==#'left' " {{{ "if ln1==2 | let &lz=lz_ | return | endif if voom#ToBody(body) < 0 | let &lz=lz_ | return | endif if voom#BodyCheckTicks(body) < 0 | let &lz=lz_ | return | endif let bbTick = b:changedtick let b_fdm=&fdm | setl fdm=manual call setbufvar(tree, '&ma', 1) exe "keepj" s:PYCMD "_VOoM2657.voom_OopLeft()" call setbufvar(tree, '&ma', 0) if l:blnShow > 0 let s:voom_bodies[body].snLn = ln1 call voom#OopShowTree(ln1, ln2, a:mode) endif " }}} elseif a:op==#'cut' " {{{ if a:mode==#'v' " must be on first line of selection exe "keepj normal! ".ln1."G" endif " new snLn normal! k let lnUp1 = line('.') if voom#ToBody(body) < 0 | let &lz=lz_ | return | endif if voom#BodyCheckTicks(body) < 0 | let &lz=lz_ | return | endif let bbTick = b:changedtick call setbufvar(tree, '&ma', 1) exe "keepj" s:PYCMD "_VOoM2657.voom_OopCut()" call setbufvar(tree, '&ma', 0) if l:blnShow > 0 let s:voom_bodies[body].snLn = lnUp1 call cursor(0,stridx(getline('.'),'|')+1) elseif bufnr('')==tree normal! j endif " }}} elseif a:op==#'copy' " {{{ let bbTick = getbufvar(body,'changedtick') " check ticks, getbufvar(body,'changedtick') is '' if Vim < 7.3.105 if s:voom_bodies[body].tick_ != bbTick if voom#ToBody(body) < 0 | let &lz=lz_ | return | endif if voom#BodyCheckTicks(body) < 0 | let &lz=lz_ | return | endif let bbTick = b:changedtick call voom#OopFromBody(body,tree,-1) endif exe s:PYCMD "_VOoM2657.voom_OopCopy()" let l:doverif = 0 "}}} endif let &lz=lz_ if l:doverif call voom#OopVerify(body, tree, a:op) endif if l:pyOK != 1 if a:op==#'right' || a:op==#'left' call setbufvar(body, '&fdm', b_fdm) endif call voom#OopPyNotOK(body, bbTick, a:op) endif endfunc func! voom#OopFolding(ln1, ln2, action) "{{{3 " Deal with Tree folding in range ln1-ln2 according to action: " save, restore, cleanup. Range is ignored if 'cleanup'. " Since potentially large lists are involved, folds are manipulated in Python. let tree = bufnr('') if voom#BufNotTree(tree) | return | endif let body = s:voom_trees[tree] if s:voom_bodies[body].MTYPE > 0 call voom#ErrorMsg('VOoM: Tree folding operations are not available in this markup mode') return endif if voom#BufNotLoaded(body) | return | endif if a:action!=#'restore' && voom#BufNotEditable(body) return endif if a:action!=#'cleanup' && voom#FoldStatus(a:ln1)==#'hidden' call voom#ErrorMsg("VOoM: current line is hidden in fold") return endif let lz_ = &lz | set lz let l:pyOK = 0 let bbTick = getbufvar(body,'changedtick') " check ticks, getbufvar(body,'changedtick') is '' if Vim < 7.3.105 if s:voom_bodies[body].tick_ != bbTick if voom#ToBody(body) < 0 | let &lz=lz_ | return | endif if voom#BodyCheckTicks(body) < 0 | let &lz=lz_ | return | endif let bbTick = b:changedtick call voom#OopFromBody(body,tree,-1) endif """ diddle with folds let winsave_dict = winsaveview() exe s:PYCMD "_VOoM2657.voom_OopFolding(vim.eval('a:action'))" call winrestview(winsave_dict) if a:action==#'restore' | let &lz=lz_ | return | endif " go to Body, set ticks, go back if voom#ToBody(body) < 0 | let &lz=lz_ | return | endif call setbufvar(tree, '&ma', 1) call voom#OopFromBody(body,tree,-1) call setbufvar(tree, '&ma', 0) let &lz=lz_ call voom#OopVerify(body, tree, a:action.' folding marks') if l:pyOK != 1 call voom#OopPyNotOK(body, bbTick, a:action.' folding marks') endif endfunc func! voom#OopSort(ln1,ln2,qargs) "{{{3 " Sort siblings in Tree range ln1:ln2 according to options qargs. " Sort siblings of the current node if range is one line (ln1==ln2). " If one of the options is 'deep' -- also sort siblings in all subnodes. " Options are dealt with in the Python code. let tree = bufnr('') if voom#BufNotTree(tree) | return | endif let body = s:voom_trees[tree] if voom#BufNotLoaded(body) | return | endif if voom#BufNotEditable(body) | return | endif if a:ln1 <= a:ln2 let [l:ln1, l:ln2] = [a:ln1, a:ln2] else let [l:ln1, l:ln2] = [a:ln2, a:ln1] endif if l:ln1 < 2 call voom#ErrorMsg("VOoM (sort): first Tree line cannot be operated on") return elseif (line('.') < l:ln1) || (line('.') > l:ln2) call voom#ErrorMsg("VOoM (sort): current line is outside the range") return elseif voom#FoldStatus(line('.'))==#'hidden' call voom#ErrorMsg("VOoM (sort): current line is hidden in fold") return endif let lz_ = &lz | set lz let Z = line('$') if voom#ToBody(body) < 0 | let &lz=lz_ | return | endif if voom#BodyCheckTicks(body) < 0 | let &lz=lz_ | return | endif " default l:bnlShow -1 means no changes were made let l:blnShow = -1 let l:pyOK = 0 let bbTick = b:changedtick " Modify Body buffer. NOTE: Tree buffer and outline data are not adjusted. exe "keepj" s:PYCMD "_VOoM2657.voom_OopSort()" " IMPORTANT: we rely on Tree BufEnter au to update outline call voom#OopFromBody(body,tree,l:blnShow) if l:blnShow > 0 call voom#OopShowTree(l:lnum1, l:lnum2, a:ln1==a:ln2 ? 'n' : 'v') endif let &lz=lz_ " Sorting must not change the number of headlines! " This is problem with markups: rest, asciidoc, pandoc, python. if Z != line('$') && bufnr('') == tree let d = line('$') - Z call voom#ErrorMsg("VOoM (sort): ERROR OCCURRED DURING SORTING! YOU **MUST UNDO** THIS SORT!!!") call voom#ErrorMsg(" Total number of nodes has changed by " .d. " !") if d < 0 call voom#ErrorMsg(" This is usually caused by missing blank lines (reST, AsciiDoc, Pandoc, paragraphBlank).") call voom#ErrorMsg(" Make sure there is a blank line before each headline and at the end of file.") endif endif if l:pyOK != 1 call voom#OopPyNotOK(body, bbTick, 'sort') endif endfunc func! voom#OopFromBody(body,tree,blnShow) "{{{3 " Move from Body to Tree, usually during an outline operation when Tree is &ma. " Show line at Body lnum blnShow if blnShow > 0. " Set tick_ if Tree is &ma to suppress subsequent updates on Tree BufEnter. " NOTE: outline update on Tree BufEnter is always blocked when Tree is &ma. if bufnr('')!=a:body | echoerr 'VOoM: INTERNAL ERROR 1' | return | endif " set .tick_ to suppress Tree updates; always set .tick in case BufLeave au fails let b_tick = b:changedtick let s:voom_bodies[a:body].tick = b:changedtick if getbufvar(a:tree,'&ma') let s:voom_bodies[a:body].tick_ = b:changedtick endif " show line at blnShow if a:blnShow > 0 exe 'keepj normal! '.a:blnShow.'G' if &fdm==#'marker' normal! zMzvzt else normal! zvzt endif endif " go back to Tree window, which should be previous window let wnr_ = winnr('#') if winbufnr(wnr_)==a:tree exe wnr_.'wincmd w' else exe bufwinnr(a:tree).'wincmd w' endif if bufnr('')!=a:tree | echoerr 'VOoM: INTERNAL ERROR 2' | return | endif if &ma if s:voom_bodies[a:body].tick != b_tick let s:voom_bodies[a:body].tick_ = s:voom_bodies[a:body].tick let s:verify = 1 endif elseif s:voom_bodies[a:body].tick_ != s:voom_bodies[a:body].tick call voom#ErrorMsg('VOoM: wrong ticks. Forcing outline update...') call voom#TreeBufEnter() endif endfunc func! voom#OopShowTree(ln1, ln2, mode) " {{{3 " select range ln2-ln1 and close all folds " first zv ensures node ln1 is expanded when extending selection to it exe 'keepj normal! '.a:ln1.'Gzv'.a:ln2.'G0f|V'.a:ln1.'G0f|' try normal! zC catch /^Vim\%((\a\+)\)\=:E490/ endtry call voom#TreeZV() call cursor(0,stridx(getline('.'),'|')+1) " close subnodes below ln2 after Move Left with g:voom_always_allow_move_left if stridx(getline(a:ln2+1),'|') > stridx(getline(a:ln1),'|') let ind = virtcol('.')-1 exe 'keepj normal! '.(a:ln2+1).'Gzv' call search('\m^[^|]\{0,'.ind.'}|', 'We') if line('.') > a:ln2+1 exe 'keepj normal! '.(line('.')-1).'GV'.(a:ln2+1).'G' else exe 'keepj normal! GV'.(a:ln2+1).'G' endif try normal! zC catch /^Vim\%((\a\+)\)\=:E490/ endtry call voom#TreeZV() exe 'keepj normal! '.a:ln2.'G0f|V'.a:ln1.'G0f|' " end in visual mode if outline operation was started in visual mode elseif a:mode ==# 'v' normal! gv endif return " alternatives to gv: "exe 'keepj normal! '.a:ln2.'G0f|V'.a:ln1.'G0f|' "exe 'keepj normal! '.a:ln2.'GV'.a:ln1.'G' " Adjust Tree view after an outline operation. " ln1 and ln2 are first and last line of the modified range. " After an outline operation Tree folds in the affected range are usually " sprung open. To make it look nice, close all folds in the range: select the " range, zC (watch out for E490: No fold found), show the first node. " To fix: cursor is not positioned on | in visual mode when ln1 or ln2 is folded. endfunc func! voom#OopVerify(body, tree, op) "{{{3 " Verify outline after outline operation. Current buffer must be Tree. if s:verify let s:verify = 0 elseif !g:voom_verify_oop return endif let l:ok = 0 exe s:PYCMD "_VOoM2657.voom_OopVerify()" if l:ok | return | endif call voom#ErrorMsg('VOoM: outline verification failed after "'.a:op.'". Forcing outline update...') let s:voom_bodies[a:body].tick_ = -1 if bufnr('')!=a:tree || voom#BufNotTree(a:tree) echoerr 'VOoM: INTERNAL ERROR. Outline update aborted.' return endif call voom#TreeBufEnter() endfunc func! voom#OopPyNotOK(body, bbTick, op) "{{{3 " This is called after outline operation a:op when Pythons code fails to set pyOK. " This means outline operation has failed because of Python error, possibly in " the middle of modifying Body buffer. "echoerr 'OOPSY' if bufnr('') != a:body call voom#ToBody(a:body) if bufnr('') != a:body echoerr 'VOoM: INTERNAL ERROR. Cannot switch to Body in voom#OopPyNotOK().' return endif endif call voom#ErrorMsg(' ') if b:changedtick != a:bbTick call voom#ErrorMsg('VOoM: Python error occured during outline operaton "'.a:op.'"!') call voom#ErrorMsg('VOoM: Body buffer WAS CHANGED during failed outline operation! You **MUST UNDO** this change!!!') else call voom#ErrorMsg('VOoM: Python error occured during outline operaton "'.a:op.'". Body buffer was not changed.') endif endfunc "---BODY BUFFERS------------------------------{{{1 func! voom#BodyConfig() "{{{2 " Configure current buffer as a Body buffer. augroup VoomBody au! * au BufLeave call voom#BodyBufLeave() au BufEnter call voom#BodyBufEnter() augroup END " will be also set on BufLeave let s:voom_bodies[bufnr('')].tick = b:changedtick call voom#BodyMap() unlet! w:voom_tree endfunc func! voom#BodyBufLeave() "{{{2 " Body BufLeave au needed because getbufvar() doesn't work with b:changedtick if Vim <7.3.105. let s:voom_bodies[bufnr('')].tick = b:changedtick endfunc func! voom#BodyBufEnter() "{{{2 " Body BufEnter au. Restore buffer-local mappings lost after :bd. if !hasmapto('voom#ToTreeOrBodyWin','n') call voom#BodyMap() endif endfunc func! voom#BodyMap() "{{{2 " Body buffer local mappings. let cpo_ = &cpo | set cpo&vim exe "nnoremap ".g:voom_return_key." :call voom#BodySelect()" exe "nnoremap ".g:voom_tab_key. " :call voom#ToTreeOrBodyWin()" let &cpo = cpo_ endfunc func! voom#BodyUnMap() "{{{2 " Remove Body local mappings. Must be called from Body. let cpo_ = &cpo | set cpo&vim exe "nunmap ".g:voom_return_key exe "nunmap ".g:voom_tab_key let &cpo = cpo_ endfunc func! voom#BodySelect() "{{{2 " Select current Body node. Show corresponding line in the Tree. " Stay in the Tree if the node is already selected. let body = bufnr('') " Tree has been wiped out. if !has_key(s:voom_bodies, body) call voom#BodyUnMap() return endif let wnr_ = winnr() let tree = s:voom_bodies[body].tree let blnr = line('.') " Go to Tree. Outline will be updated on BufEnter. if voom#ToTree(tree) < 0 | return | endif if s:voom_bodies[body].tick_!=s:voom_bodies[body].tick exe bufwinnr(body).'wincmd w' call voom#BodyCheckTicks(body) return endif " updateTree() sets = mark and may change snLn to a wrong value if outline was modified from Body. let snLn_ = s:voom_bodies[body].snLn " Compute new and correct snLn with updated outline. exe s:PYCMD "_VOoM2657.computeSnLn(int(vim.eval('l:body')), int(vim.eval('l:blnr')))" let snLn = s:voom_bodies[body].snLn call voom#TreeToLine(snLn) " Node has not changed. Stay in Tree. if snLn==snLn_ | return | endif " Node has changed. Draw marks. Go back to Body setl ma | let ul_ = &l:ul | setl ul=-1 keepj call setline(snLn_, ' '.getline(snLn_)[1 : ]) keepj call setline(snLn, '='.getline(snLn)[1 : ]) setl noma | let &l:ul = ul_ let wnr_ = winnr('#') if winbufnr(wnr_)==body exe wnr_.'wincmd w' else exe bufwinnr(body).'wincmd w' endif endfunc func! voom#BodyCheckTicks(body) "{{{2 " Current buffer is Body body. Check ticks assuming that outline is up to date, " as after going to Body from Tree. " note: 'abort' argument is not needed and would be counterproductive if bufnr('')!=a:body echoerr 'VOoM: wrong buffer' return -1 endif " Wrong ticks, probably after :bun or :bd. Force outline update. if s:voom_bodies[a:body].tick_!=b:changedtick let tree = s:voom_bodies[a:body].tree if !exists("s:voom_trees") || !has_key(s:voom_trees, tree) echoerr "VOoM: INTERNAL ERROR" return -1 endif call voom#BodyUpdateTree() call voom#ErrorMsg('VOoM: wrong ticks for Body buffer '.a:body.'. Outline has been updated.') return -1 endif endfunc func! voom#BodyUpdateTree() "{{{2 " Current buffer is Body. Update outline and Tree. let body = bufnr('') if !has_key(s:voom_bodies, body) call voom#ErrorMsg('VOoM: current buffer is not Body') return -1 endif let tree = s:voom_bodies[body].tree " paranoia if !bufloaded(tree) call voom#UnVoom(body,tree) echoerr "VOoM: Tree buffer" tree "is not loaded or does not exist. Cleanup has been performed." return -1 endif " update is not needed if s:voom_bodies[body].tick_==b:changedtick | return | endif " do update call setbufvar(tree, '&ma', 1) let ul_ = &l:ul call setbufvar(tree, '&ul', -1) try let l:ok = 0 exe "keepj" s:PYCMD "_VOoM2657.updateTree(int(vim.eval('l:body')), int(vim.eval('l:tree')))" if l:ok let s:voom_bodies[body].tick_ = b:changedtick let s:voom_bodies[body].tick = b:changedtick endif finally " &ul is global, but 'let &ul=ul_' causes 'undo list corrupt' error. WHY? call setbufvar(tree, '&ul', ul_) call setbufvar(tree, '&ma', 0) endtry endfunc "---Tree or Body------------------------------{{{1 func! voom#EchoUNL() "{{{2 " Display UNL (Uniformed Node Locator) of current node. " Copy UNL to register 'n'. " Can be called from any buffer. let bnr = bufnr('') let lnum = line('.') if has_key(s:voom_trees, bnr) let [bufType, body, tree] = ['Tree', s:voom_trees[bnr], bnr] if voom#BufNotLoaded(body) | return | endif elseif has_key(s:voom_bodies, bnr) let [bufType, body, tree] = ['Body', bnr, s:voom_bodies[bnr].tree] if voom#BodyUpdateTree() < 0 | return | endif else call voom#ErrorMsg("VOoM: current buffer is not a VOoM buffer") return endif exe s:PYCMD "_VOoM2657.voom_EchoUNL()" endfunc func! voom#Grep(input) "{{{2 " Seach Body for pattern(s). Show list of UNLs of nodes with matches. " Input can have several patterns separated by boolean 'AND' and 'NOT'. " Stop if >500000 matches found for a pattern. " Set "/ register to AND patterns. """ Process input first in case we are in Tree and want word under cursor. if a:input=='' let input = expand('') let input = substitute(input, '\s\+$', '', '') if input=='' | return | endif let [pattsAND, pattsNOT] = [['\<'.input.'\>'], []] call histdel('cmd', -1) call histadd('cmd', 'Voomgrep '.pattsAND[0]) else let input = substitute(a:input, '\s\+$', '', '') if input=='' | return | endif let [pattsAND, pattsNOT] = voom#GrepParseInput(input) endif """ Search must be done in Body buffer. Move to Body if in Tree. let bnr = bufnr('') if has_key(s:voom_trees, bnr) let body = s:voom_trees[bnr] let tree = bnr if voom#BufNotLoaded(body) | return | endif if voom#ToBody(body) < 0 | return | endif if voom#BodyCheckTicks(body) < 0 | return | endif elseif has_key(s:voom_bodies, bnr) let body = bnr let tree = s:voom_bodies[bnr].tree " update outline if voom#BodyUpdateTree() < 0 | return | endif else call voom#ErrorMsg("VOoM: current buffer is not a VOoM buffer") return endif """ Search for each pattern with search(). let [lnum_,cnum_] = [line('.'), col('.')] let lz_ = &lz | set lz let winsave_dict = winsaveview() " search results: list of lists with blnums for each pattern let [matchesAND, matchesNOT] = [[], []] " inheritance flags (hierarchical search): 0 or 1 let [inhAND, inhNOT] = [[], []] let pattsAND1 = [] for patt in pattsAND if patt =~ '\m^\*.' let patt = patt[1 : ] call add(inhAND, 1) else call add(inhAND, 0) endif call add(pattsAND1, patt) let [matches, notOK] = voom#GrepSearch(patt) if notOK if notOK == 1 call voom#ErrorMsg('VOoM (Voomgrep): pattern not found: '. patt) endif call winrestview(winsave_dict) call winline() let &lz=lz_ return endif call add(matchesAND, matches) endfor for patt in pattsNOT if patt =~ '\m^\*.' let patt = patt[1 : ] call add(inhNOT, 1) else call add(inhNOT, 0) endif let [matches, notOK] = voom#GrepSearch(patt) if notOK > 1 call winrestview(winsave_dict) call winline() let &lz=lz_ return endif call add(matchesNOT, matches) endfor call winrestview(winsave_dict) call winline() let &lz=lz_ let [lenAND, lenNOT] = [len(pattsAND), len(pattsNOT)] """ Highlight all AND pattern. " Problem: there is no search highlight after :noh " Problem: \c \C get combined if lenAND if lenAND==1 let @/ = pattsAND1[0] else " add \m or \M to to negate any preceding \v \V \m \M let mm = &magic ? '\m' : '\M' let @/ = mm.'\%('. join(pattsAND1, mm.'\)\|\%(') .mm.'\)' endif call histadd('search', @/) endif """ Set and display quickfix list. let [line1] = getbufline(tree,1) " 2nd line shows patterns and numbers of matches let line2 = ':Voomgrep' for i in range(lenAND) let L = matchesAND[i] if i == 0 let line2 = line2 . ' '. pattsAND[i] .' {'. len(L) .' matches}' else let line2 = line2 .' AND '. pattsAND[i] .' {'. len(L) .' matches}' endif endfor for i in range(lenNOT) let L = matchesNOT[i] let line2 = line2 .' NOT '. pattsNOT[i] .' {'. len(L) .' matches}' endfor " initiate quickfix list with two lines call setqflist([{'text':line1, 'bufnr':body, 'lnum':lnum_, 'col':cnum_}, {'text':line2}]) exe s:PYCMD "_VOoM2657.voom_Grep()" botright copen " Configure quickfix buffer--strip file names, adjust syntax hi. if &buftype!=#'quickfix' || &ma || &mod | return | endif setl ma let ul_ = &l:ul | setl ul=-1 silent 1,2s/\m^.\{-}|.\{-}|// call histdel('search', -1) if line('$')>2 silent 3,$s/\m^.\{-}\ze|// call histdel('search', -1) endif keepj normal! 1G0 let &l:ul = ul_ setl nomod noma syn clear syn match Title /\%1l.*/ syn match Statement /\%2l.*/ syn match LineNr /^|.\{-}|.\{-}|/ syn match Title / -> / endfunc func! voom#GrepParseInput(input) "{{{2 " Input string is patterns separated by AND or NOT. " There can be a leading NOT, but not leading AND. " Segregate patterns into AND and NOT lists. let [pattsAND, pattsNOT] = [[], []] let S = a:input " bop -- preceding boolean operator: 1 if AND, 0 if NOT " i -- start of pattern " j,k -- start,end+1 of the next operator string let k = matchend(S, '\v\c^\s*not\s+') let [i,bop] = k==-1 ? [0,1] : [k,0] let OP = '\v\c\s+(and|not)\s+' let j = match(S,OP,i) while j > -1 let patt = S[i : j-1] call add(bop ? pattsAND : pattsNOT, patt) let k = matchend(S,OP,i) let bop = S[j : k] =~? 'and' ? 1 : 0 let i = k let j = match(S,OP,i) endwhile call add(bop ? pattsAND : pattsNOT, S[i : ]) return [pattsAND, pattsNOT] endfunc func! voom#GrepSearch(pattern) "{{{2 " Seach buffer for pattern. Return [[lnums-of-matches], notOK] . " notOK is 0 (success), 1 (no matches), 2 (search stopped after >500000 matches found). let [matches, notOK, n] = [[], 0, 0] " always search from start keepj normal! gg0 " special effort needed to detect match at cursor if searchpos(a:pattern, 'nc', 1) == [1,1] call add(matches,1) let n += 1 endif " do search try let found = search(a:pattern, 'W') while found > 0 call add(matches, found) let n += 1 if n > 500000 call voom#ErrorMsg('VOoM (Voomgrep): too many matches (>500000) for pattern: '. a:pattern) return [[], 2] endif let found = search(a:pattern, 'W') endwhile catch /^Vim:Interrupt$/ " FIXME this message is not visible, it is overwritten by Vim's CTRL-C message call voom#ErrorMsg("VOoM (Voomgrep): search interrupted after ". n ." matches found for pattern: " .a:pattern) return [[], 4] endtry " no matches found if matches == [] let notOK = 1 endif return [matches, notOK] endfunc "---LOG BUFFER (Voomlog)----------------------{{{1 " " Do "normal! G" to position cursor and scroll Log window. " "call cursor('$',1)" does not scroll Log window. func! voom#LogInit() "{{{2 " Create and configure PyLog buffer or show existing one. let bnr_ = bufnr('') """ Log buffer exists, show it. if s:voom_logbnr if !bufloaded(s:voom_logbnr) exe s:PYCMD "sys.stdout = _voom2657_py_sys_stdout" exe s:PYCMD "sys.stderr = _voom2657_py_sys_stderr" exe s:PYCMD "if 'pydoc' in sys.modules: del sys.modules['pydoc']" if bufexists(s:voom_logbnr) exe 'au! VoomLog * ' exe 'bwipeout '.s:voom_logbnr endif let bnr = s:voom_logbnr let s:voom_logbnr = 0 echoerr "VOoM: PyLog buffer" bnr "was not shut down properly. Cleanup has been performed. Execute the command :Voomlog again." return endif if bufwinnr(s:voom_logbnr) < 0 call voom#ToLogWin() silent exe 'b '.s:voom_logbnr keepj normal! G exe bufwinnr(bnr_).'wincmd w' endif return endif """ Create and configure PyLog buffer. if bufexists('__PyLog__') > 0 call voom#ErrorMsg('VOoM: there is already a buffer named __PyLog__') return endif call voom#ToLogWin() silent edit __PyLog__ call voom#LogConfig() """ Go back. exe bufwinnr(bnr_).'wincmd w' endfunc func! voom#LogConfig() "{{{2 " Configure current buffer as PyLog. Redirect Python stdout and stderr to it. " NOTE: the caller must check if PyLog already exists. let s:voom_logbnr = bufnr('') augroup VoomLog au! * au BufUnload nested call voom#LogBufUnload() augroup END setl cul nocuc list wrap setl bufhidden=wipe call voom#LogConfigFT() setl noro ma ff=unix setl nobuflisted buftype=nofile noswapfile exe s:PYCMD "_voom2657_py_sys_stdout = sys.stdout" exe s:PYCMD "_voom2657_py_sys_stderr = sys.stderr" exe s:PYCMD "sys.stdout = sys.stderr = _VOoM2657.LogBufferClass()" exe s:PYCMD "if 'pydoc' in sys.modules: del sys.modules['pydoc']" endfunc func! voom#LogConfigFT() "{{{2 " Allow customization via ftplugin/voomlog.vim, syntax/voomlog.vim, etc. setl ft=voomlog " Log buffer default syntax highlighting. Must be done after 'setl ft=voomlog'. if exists('b:current_syntax') | return | endif " Python tracebacks syn match Error /^Traceback (most recent call last):/ syn match Error /^\u\h*Error/ syn match Error /^vim\.error/ syn region WarningMsg start="^Traceback (most recent call last):" end="\%(^\u\h*Error.*\)\|\%(^\s*$\)\|\%(^vim\.error\)" contains=Error keepend "Vim exceptions syn match Error /^Vim.*:E\d\+:.*/ " VOoM messages syn match Error /^ERROR: .*/ syn match Error /^EXCEPTION: .*/ syn match PreProc /^---end of \w\+ script.*---$/ " -> UNL separator syn match Title / -> / let b:current_syntax = 'voomlog' endfunc func! voom#LogBufUnload() "{{{2 if !s:voom_logbnr || expand("")!=s:voom_logbnr echoerr 'VOoM: INTERNAL ERROR' return endif exe s:PYCMD "sys.stdout = _voom2657_py_sys_stdout" exe s:PYCMD "sys.stderr = _voom2657_py_sys_stderr" exe s:PYCMD "if 'pydoc' in sys.modules: del sys.modules['pydoc']" exe 'au! VoomLog * ' try exe 'bwipeout '.s:voom_logbnr catch /^Vim\%((\a\+)\)\=:E937/ " E937 occurs in Vim 8.0 (Patch 7.4.2324), wipeout still happens endtry let s:voom_logbnr = 0 endfunc func! voom#LogScroll() "{{{2 " Scroll windows with the __PyLog__ buffer. " All tabs are searched. Only the first found Log window in each tab is scrolled. " Uses noautocmd when jumping between tabs and windows. " Note: don't use Python here: an error will result in recursive loop. " can't go to other windows when in Ex mode (after 'Q' or 'gQ') if mode()==#'c' | return | endif " This should never happen. if !s:voom_logbnr || !bufloaded(s:voom_logbnr) echoerr "VOoM: INTERNAL ERROR" return endif let lz_=&lz | set lz let log_found = 0 let [tnr_, wnr_, bnr_] = [tabpagenr(), winnr(), bufnr('')] " search among visible buffers in all tabs for tnr in range(1, tabpagenr('$')) if index(tabpagebuflist(tnr), s:voom_logbnr) > -1 let log_found = 1 if tabpagenr() != tnr exe 'noautocmd tabnext '.tnr endif let [wnr__, wnr__p] = [winnr(), winnr('#')] exe 'noautocmd '. bufwinnr(s:voom_logbnr).'wincmd w' keepj normal! G " restore tab's current and previous window numbers if wnr__p exe 'noautocmd '.wnr__p.'wincmd w' endif exe 'noautocmd '.wnr__.'wincmd w' endif endfor " At least one Log window was found and scrolled. Return to original tab and window. if log_found==1 if tabpagenr() != tnr_ exe 'noautocmd tabnext '.tnr_ exe 'noautocmd '.wnr_.'wincmd w' endif " Log window was not found. Create it. else call voom#ToLogWin() exe 'b '.s:voom_logbnr keepj normal! G exe 'tabnext '.tnr_ exe bufwinnr(bnr_).'wincmd w' endif let &lz=lz_ endfunc func! voom#LogSessionLoad() "{{{2 " Activate PyLog when loading Vim session created with :mksession. if !exists('g:SessionLoad') || &modified || line('$')>1 || getline(1)!='' || (exists('s:voom_logbnr') && s:voom_logbnr) return endif call voom#LogConfig() endfunc "---EXECUTE SCRIPT (Voomexec)-----------------{{{1 func! voom#GetVoomRange(lnum, withSubnodes) "{{{2 let bnr = bufnr('') if has_key(s:voom_trees, bnr) let [bufType, body, tree] = ['Tree', s:voom_trees[bnr], bnr] if voom#BufNotLoaded(body) | return ['Tree',-1,-1,-1] | endif elseif has_key(s:voom_bodies, bnr) let [bufType, body, tree] = ['Body', bnr, s:voom_bodies[bnr].tree] if voom#BodyUpdateTree() < 0 | return ['Body',-1,-1,-1] | endif else return ['None',0,0,0] endif if a:withSubnodes exe s:PYCMD "_VOoM2657.voom_GetVoomRange(withSubnodes=1)" else exe s:PYCMD "_VOoM2657.voom_GetVoomRange()" return [bufType, body, l:bln1, l:bln2] " Return [bufType, body, bln1, bln2] for node at line lnum of the current " VOoM buffer (Tree or Body). " bln1, bln2: VOoM node's first and last Body lnums. Current node only if " a:withSubnodes==0. Include all subnodes if a:withSubnodes==1. " Return [bufType,-1,-1,-1] in case of an error (unloaded Body, etc.) " Return ['None',0,0,0] for a non-VOoM buffer. " This is for use by external scripts: " let [bufType, body, bln1, bln2] = voom#GetVoomRange(line('.'),0) " let bodyLines = getbufline(body,bln1,bln2) endfunc func! voom#GetBufRange(ln1, ln2) "{{{2 let bnr = bufnr('') if has_key(s:voom_trees, bnr) let [bufType, body, tree] = ['Tree', s:voom_trees[bnr], bnr] if voom#BufNotLoaded(body) | return ['Tree',-1,-1,-1] | endif exe s:PYCMD "_VOoM2657.voom_GetBufRange()" return [bufType, body, l:bln1, l:bln2] elseif has_key(s:voom_bodies, bnr) return ['Body',bnr,a:ln1,a:ln2] else return ['None',bnr,a:ln1,a:ln2] endif " Return [bufType, body, bln1, bln2] for line range lnum1,lnum2. " If current buffer is a Tree: bln1, bln2 are start and end lnums of the " corresponding Body line range; 'body' is Body's buffer number. " Return ['Tree',-1,-1,-1] in case of an error (unloaded Body.) " If current buffer is not a Tree: bln1, bln2 are lnum1, lnum2; 'body' is the " current buffer number. " NOTE: Outline is not updated if the current buffer is Body. endfunc func! voom#GetExecRange(lnum) "{{{2 " Return line range info for Voomexec: [bufType, bufnr, start lnum, end lnum] let bnr = bufnr('') let status = voom#FoldStatus(a:lnum) if status==#'hidden' call voom#ErrorMsg('VOoM: current line is hidden in fold') return ['',-1,-1,-1] endif " Tree buffer: get start/end of Body node and subnodes. if has_key(s:voom_trees, bnr) let [bufType, body, tree] = ['Tree', s:voom_trees[bnr], bnr] if voom#BufNotLoaded(body) | return ['',-1,-1,-1] | endif exe s:PYCMD "_VOoM2657.voom_GetVoomRange(withSubnodes=1)" return [bufType, body, l:bln1, l:bln2] endif " Any other buffer: get start/end of the current fold and subfolds. if &fdm !=# 'marker' call voom#ErrorMsg('VOoM: ''foldmethod'' must be "marker"') return ['',-1,-1,-1] endif if status==#'nofold' call voom#ErrorMsg('VOoM: no fold at cursor') return ['',-1,-1,-1] elseif status==#'folded' return ['', bnr, foldclosed(a:lnum), foldclosedend(a:lnum)] elseif status==#'notfolded' let lz_ = &lz | set lz let winsave_dict = winsaveview() normal! zc let foldStart = foldclosed(a:lnum) let foldEnd = foldclosedend(a:lnum) normal! zo call winrestview(winsave_dict) let &lz=lz_ return ['', bnr, foldStart, foldEnd] endif endfunc func! voom#Exec(qargs) "{{{2 " Execute text from the current node (Tree or Body, include subnodes) or fold " (non-VOoM buffer, include subfolds) as a script. " If argument is 'vim' or 'py'/'python': execute as Vim or Python script. " Otherwise execute according to filetype. " If current buffer is a Tree: use Body filetype, encodings, etc. let bnr = bufnr('') if has_key(s:voom_trees, bnr) let bnr = s:voom_trees[bnr] endif let FT = getbufvar(bnr, '&ft') if a:qargs==#'vim' let scriptType = 'vim' elseif a:qargs==#'py' || a:qargs==#'python' let scriptType = 'python' elseif a:qargs!='' call voom#ErrorMsg('VOoM: unsupported script type: "'.a:qargs.'"') return elseif FT==#'vim' let scriptType = 'vim' elseif FT==#'python' let scriptType = 'python' else call voom#ErrorMsg('VOoM: unsupported script type: "'.FT.'"') return endif " Get script lines. let [bufType, body, bln1, bln2] = voom#GetExecRange(line('.')) if body<1 | return | endif " Execute Vim script: Copy list of lines to register and execute it. " Problem: Python errors do not terminate script and Python tracebacks are " not printed. They are printed to the PyLog if it's enabled. Probably " caused by 'catch', but without it foldtext is temporarily messed up in " all windows after any error. if scriptType==#'vim' let lines = getbufline(body, bln1, bln2) if lines==[] | return | endif let reg_z = getreg('z') let reg_z_mode = getregtype('z') let script = join(lines, "\n") . "\n" call setreg('z', script, "l") try call s:ExecVim() catch call voom#ErrorMsg(v:exception) finally call setreg('z', reg_z, reg_z_mode) echo '---end of Vim script ('.bln1.'-'.bln2.')---' endtry " Execute Python script. elseif scriptType==#'python' " do not change, see ./voom/voom_vimplugin2657/voom_vim.py#id_20101214100357 if s:voom_logbnr try exe s:PYCMD "_VOoM2657.voom_Exec()" catch exe s:PYCMD "print(vim.eval('v:exception'))" endtry else exe s:PYCMD "_VOoM2657.voom_Exec()" endif endif endfunc func! s:ExecVim() "{{{2 @z endfunc "---execute user command----------------------{{{1 if exists('g:voom_user_command') execute g:voom_user_command endif " modelines {{{1 " vim:fdm=marker:fdl=0: " vim:foldtext=getline(v\:foldstart).'...'.(v\:foldend-v\:foldstart): VOoM-5.3/autoload/voom/000077500000000000000000000000001305710164100147675ustar00rootroot00000000000000VOoM-5.3/autoload/voom/voom_vimplugin2657/000077500000000000000000000000001305710164100203655ustar00rootroot00000000000000VOoM-5.3/autoload/voom/voom_vimplugin2657/__init__.py000066400000000000000000000000671305710164100225010ustar00rootroot00000000000000# Dummy file to make this directory a Python package. VOoM-5.3/autoload/voom/voom_vimplugin2657/voom_mode_asciidoc.py000066400000000000000000000411271305710164100245660ustar00rootroot00000000000000# File: voom_mode_asciidoc.py # Last Modified: 2017-01-07 # Description: VOoM -- two-pane outliner plugin for Python-enabled Vim # Website: http://www.vim.org/scripts/script.php?script_id=2657 # Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) # License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ """ VOoM markup mode for AsciiDoc document and section titles. See |voom-mode-asciidoc|, ../../../doc/voom.txt#*voom-mode-asciidoc* """ ### NOTES # # When outline operation changes level, it has to deal with two ambiguities: # a) Level 1-5 headline can use 2-style (underline) or 1-style (=). # b) 1-style can have or not have closing ='s. # To determine current preferences: check first headline at level <6 and check # first headline with =. This must be done in hook_makeOutline(). # (Save in VO, similar to reST mode.) Cannot be done during outline operation, # that is in hook_doBodyAfterOop(). # Defaults: use underline, use closing ='s. try: import vim if vim.eval('exists("g:voom_asciidoc_do_blanks")')=='1' and vim.eval("g:voom_asciidoc_do_blanks")=='0': DO_BLANKS = False else: DO_BLANKS = True except ImportError: DO_BLANKS = True import sys if sys.version_info[0] > 2: xrange = range def len_u(s, enc): return len(s) else: def len_u(s, enc): return len(unicode(s, enc, 'replace')) import re # regex for 1-style headline, assumes there is no trailing whitespace HEAD_MATCH = re.compile(r'^(=+)(\s+\S.*?)(\s+\1)?$').match #--------------------------------------------------------------------- # Characters used as underlines in two-line headlines. ADS_LEVELS = {'=' : 1, '-' : 2, '~' : 3, '^' : 4, '+' : 5} # Characters for Delimited Blocks. Headines are ignored inside such blocks. BLOCK_CHARS = {'/' : 0, '+' : 0, '-' : 0, '.' : 0, '*' : 0, '_' : 0, '=' : 0} #LEVELS_ADS = {1:'=', 2:'-', 3:'~', 4:'^', 5:'+'} LEVELS_ADS = {} for k in ADS_LEVELS: LEVELS_ADS[ADS_LEVELS[k]] = k # Combine all signficant chars. Need one of these at start of line for a headline or DelimitedBlock to occur. CHARS = {} for k in ADS_LEVELS: CHARS[k] = 0 for k in BLOCK_CHARS: CHARS[k] = 0 #--------------------------------------------------------------------- def hook_makeOutline(VO, blines): """Return (tlines, bnodes, levels) for Body lines blines. blines is either Vim buffer object (Body) or list of buffer lines. """ ENC = VO.enc Z = len(blines) tlines, bnodes, levels = [], [], [] tlines_add, bnodes_add, levels_add = tlines.append, bnodes.append, levels.append # trailing whitespace is always removed with rstrip() # if headline is precedeed by [AAA] and/or [[AAA]], bnode is set to their lnum # # 1-style, overrides 2-style # [[AAA]] L3, blines[i-2] # [yyy] L2, blines[i-1] # == head == L1, blines[i] -- current line, closing = are optional # # 2-style (underline) # [[AAA]] L4, blines[i-3] # [yyy] L3, blines[i-2] # head L2, blines[i-1] -- title line, many restrictions on the format # ---- L1, blines[i] -- current line # Set this the first time a headline with level 1-5 is encountered. # 0 or 1 -- False, use 2-style (default); 2 -- True, use 1-style useOne = 0 # Set this the first time headline in 1-style is encountered. # 0 or 1 -- True, use closing ='s (default); 2 -- False, do not use closing ='s useOneClose = 0 isHead = False isFenced = False # True if inside DelimitedBlock, the value is the char headI = -2 # idx of the last line that is part of a headline blockI = -2 # idx of the last line where a DelimitedBlock ended m = None # match object for 1-style regex for i in xrange(Z): L1 = blines[i].rstrip() if not L1 or not L1[0] in CHARS: continue ch = L1[0] if isFenced: if isFenced==ch and len(L1)>3 and L1.lstrip(ch)=='': isFenced = False blockI = i continue # 1-style headline if ch == '=' and L1.strip('='): m = HEAD_MATCH(L1) if m: isHead = True headI_ = headI headI = i lev = len(m.group(1)) head = m.group(2).strip() bnode = i+1 # current line is an underline # the previous, underlined line (L2) is not a headline if it: # is not exactly the length of underline +/- 2 # is already part of in the previous headline # looks like an underline or a delimited block line # is [[AAA]] or [AAA] (BlockID or Attribute List) # starts with . (Block Title, they have no level) # starts with // (comment line) # starts with tab (don't know why, spaces are ok) # is only 1 chars (avoids confusion with --, as in Vim syntax, not as in AsciiDoc) if not isHead and ch in ADS_LEVELS and L1.lstrip(ch)=='' and i > 0: L2 = blines[i-1].rstrip() z2 = len_u(L2, ENC) z1 = len(L1) if (L2 and (-3 < z2 - z1 < 3) and z1 > 1 and z2 > 1 and headI != i-1 and not ((L2[0] in CHARS) and L2.lstrip(L2[0])=='') and not (L2.startswith('[') and L2.endswith(']')) and not L2.startswith('.') and not L2.startswith('\t') and not (L2.startswith('//') and not L2.startswith('///')) ): isHead = True headI_ = headI headI = i lev = ADS_LEVELS[ch] head = L2.strip() bnode = i # lnum of previous line (L2) if isHead and bnode > 1: # decrement bnode if preceding lines are [[AAA]] or [AAA] lines # that is set bnode to the topmost [[AAA]] or [AAA] line number j_ = bnode-2 # idx of line before the title line L3 = blines[bnode-2].rstrip() while L3.startswith('[') and L3.endswith(']'): bnode -= 1 if bnode > 1: L3 = blines[bnode-2].rstrip() else: break # headline must be preceded by a blank line unless: # it's line 1 (j == -1) # headline is preceded by [AAA] or [[AAA]] lines (j != j_) # previous line is a headline (headI_ == j) # previous line is the end of a DelimitedBlock (blockI == j) j = bnode-2 if DO_BLANKS and j==j_ and j > -1: L3 = blines[j].rstrip() if L3 and headI_ != j and blockI != j: # skip over any adjacent comment lines while L3.startswith('//') and not L3.startswith('///'): j -= 1 if j > -1: L3 = blines[j].rstrip() else: L3 = '' if L3 and headI_ != j and blockI != j: isHead = False headI = headI_ # start of DelimitedBlock if not isHead and ch in BLOCK_CHARS and len(L1)>3 and L1.lstrip(ch)=='': isFenced = ch continue if isHead: isHead = False # save style info for first headline and first 1-style headline if not useOne and lev < 6: if m: useOne = 2 else: useOne = 1 if not useOneClose and m: if m.group(3): useOneClose = 1 else: useOneClose = 2 # make outline tline = ' %s|%s' %('. '*(lev-1), head) tlines_add(tline) bnodes_add(bnode) levels_add(lev) # don't clobber these when parsing clipboard during Paste # which is the only time blines is not Body if blines is VO.Body: VO.useOne = useOne == 2 VO.useOneClose = useOneClose < 2 return (tlines, bnodes, levels) def hook_newHeadline(VO, level, blnum, tlnum): """Return (tree_head, bodyLines). tree_head is new headline string in Tree buffer (text after |). bodyLines is list of lines to insert in Body buffer. """ tree_head = 'NewHeadline' if level < 6 and not VO.useOne: bodyLines = [tree_head, LEVELS_ADS[level]*11, ''] else: lev = '='*level if VO.useOneClose: bodyLines = ['%s %s %s' %(lev, tree_head, lev), ''] else: bodyLines = ['%s %s' %(lev, tree_head), ''] # Add blank line when inserting after non-blank Body line. if VO.Body[blnum-1].strip(): bodyLines[0:0] = [''] return (tree_head, bodyLines) #def hook_changeLevBodyHead(VO, h, levDelta): # DO NOT CREATE THIS HOOK def hook_doBodyAfterOop(VO, oop, levDelta, blnum1, tlnum1, blnum2, tlnum2, blnumCut, tlnumCut): # this is instead of hook_changeLevBodyHead() # Based on Markdown mode function. # Inserts blank separator lines if missing. #print('oop=%s levDelta=%s blnum1=%s tlnum1=%s blnum2=%s tlnum2=%s tlnumCut=%s blnumCut=%s' % (oop, levDelta, blnum1, tlnum1, blnum2, tlnum2, tlnumCut, blnumCut)) Body = VO.Body Z = len(Body) bnodes, levels = VO.bnodes, VO.levels ENC = VO.enc # blnum1 blnum2 is first and last lnums of Body region pasted, inserted # during up/down, or promoted/demoted. if blnum1: assert blnum1 == bnodes[tlnum1-1] if tlnum2 < len(bnodes): assert blnum2 == bnodes[tlnum2]-1 else: assert blnum2 == Z # blnumCut is Body lnum after which a region was removed during 'cut', # 'up', 'down'. Need this to check if there is blank line between nodes # used to be separated by the cut/moved region. if blnumCut: if tlnumCut < len(bnodes): assert blnumCut == bnodes[tlnumCut]-1 else: assert blnumCut == Z # Total number of added lines minus number of deleted lines. b_delta = 0 ### After 'cut' or 'up': insert blank line if there is none # between the nodes used to be separated by the cut/moved region. if DO_BLANKS and (oop=='cut' or oop=='up') and (0 < blnumCut < Z) and Body[blnumCut-1].strip(): Body[blnumCut:blnumCut] = [''] update_bnodes(VO, tlnumCut+1 ,1) b_delta+=1 if oop=='cut': return ### Make sure there is blank line after the last node in the region: # insert blank line after blnum2 if blnum2 is not blank, that is insert # blank line before bnode at tlnum2+1. if DO_BLANKS and blnum2 < Z and Body[blnum2-1].strip(): Body[blnum2:blnum2] = [''] update_bnodes(VO, tlnum2+1 ,1) b_delta+=1 ### Change levels and/or formats of headlines in the affected region. # Always do this after Paste, even if level is unchanged -- format can # be different when pasting from other outlines. # Examine each headline, from bottom to top, and change level and/or format. # To change from 1-style to 2-style: # strip ='s, strip whitespace; # insert underline. # To change from 2-style to 1-style: # delete underline; # insert ='s. # Update bnodes after inserting or deleting a line. # # NOTE: bnode can be [[AAA]] or [AAA] line, we check for that and adjust it # to point to the headline text line # # 1-style 2-style # # L0 L0 Body[bln-2] # == head L1 head L1 <--bnode Body[bln-1] (not always the actual bnode) # L2 ---- L2 Body[bln] # L3 L3 Body[bln+1] if levDelta or oop=='paste': for i in xrange(tlnum2, tlnum1-1, -1): # required level (VO.levels has been updated) lev = levels[i-1] # current level from which to change to lev lev_ = lev - levDelta # Body headline (bnode) and the next line bln = bnodes[i-1] L1 = Body[bln-1].rstrip() # bnode can point to the tompost [AAA] or [[AAA]] line # increment bln until the actual headline (title line) is found while L1.startswith('[') and L1.endswith(']'): bln += 1 L1 = Body[bln-1].rstrip() # the underline line if bln < len(Body): L2 = Body[bln].rstrip() else: L2 = '' # get current headline format hasOne, hasOneClose = False, VO.useOneClose theHead = L1 if L1.startswith('='): m = HEAD_MATCH(L1) if m: hasOne = True # headline without ='s but with whitespace around it preserved theHead = m.group(2) theclose = m.group(3) if theclose: hasOneClose = True theHead += theclose.rstrip('=') else: hasOneClose = False # get desired headline format if oop=='paste': if lev > 5: useOne = True else: useOne = VO.useOne useOneClose = VO.useOneClose elif lev < 6 and lev_ < 6: useOne = hasOne useOneClose = hasOneClose elif lev > 5 and lev_ > 5: useOne = True useOneClose = hasOneClose elif lev < 6 and lev_ > 5: useOne = VO.useOne useOneClose = VO.useOneClose elif lev > 5 and lev_ < 6: useOne = True useOneClose = hasOneClose else: assert False #print('useOne=%s hasOne=%s useOneClose=%s hasOneClose=%s' %(useOne, hasOne, useOneClose, hasOneClose)) ### change headline level and/or format # 2-style unchanged, only adjust level of underline if not useOne and not hasOne: if not levDelta: continue Body[bln] = LEVELS_ADS[lev]*len(L2) # 1-style unchanged, adjust level of ='s and add/remove closing ='s elif useOne and hasOne: # no format change, there are closing ='s if useOneClose and hasOneClose: if not levDelta: continue Body[bln-1] = '%s%s%s' %('='*lev, theHead, '='*lev) # no format change, there are no closing ='s elif not useOneClose and not hasOneClose: if not levDelta: continue Body[bln-1] = '%s%s' %('='*lev, theHead) # add closing ='s elif useOneClose and not hasOneClose: Body[bln-1] = '%s%s %s' %('='*lev, theHead.rstrip(), '='*lev) # remove closing ='s elif not useOneClose and hasOneClose: Body[bln-1] = '%s%s' %('='*lev, theHead.rstrip()) # insert underline, remove ='s elif not useOne and hasOne: L1 = theHead.strip() Body[bln-1] = L1 # insert underline Body[bln:bln] = [LEVELS_ADS[lev] * len_u(L1, ENC)] update_bnodes(VO, i+1, 1) b_delta+=1 # remove underline, insert ='s elif useOne and not hasOne: if useOneClose: Body[bln-1] = '%s %s %s' %('='*lev, theHead.strip(), '='*lev) else: Body[bln-1] = '%s %s' %('='*lev, theHead.strip()) # delete underline Body[bln:bln+1] = [] update_bnodes(VO, i+1, -1) b_delta-=1 ### Make sure first headline is preceded by a blank line. blnum1 = bnodes[tlnum1-1] if DO_BLANKS and blnum1 > 1 and Body[blnum1-2].strip(): Body[blnum1-1:blnum1-1] = [''] update_bnodes(VO, tlnum1 ,1) b_delta+=1 ### After 'down' : insert blank line if there is none # between the nodes used to be separated by the moved region. if DO_BLANKS and oop=='down' and (0 < blnumCut < Z) and Body[blnumCut-1].strip(): Body[blnumCut:blnumCut] = [''] update_bnodes(VO, tlnumCut+1 ,1) b_delta+=1 assert len(Body) == Z + b_delta def update_bnodes(VO, tlnum, delta): """Update VO.bnodes by adding/substracting delta to each bnode starting with bnode at tlnum and to the end. """ bnodes = VO.bnodes for i in xrange(tlnum, len(bnodes)+1): bnodes[i-1] += delta VOoM-5.3/autoload/voom/voom_vimplugin2657/voom_mode_cwiki.py000066400000000000000000000041631305710164100241150ustar00rootroot00000000000000# File: voom_mode_cwiki.py # Last Modified: 2017-01-07 # Description: VOoM -- two-pane outliner plugin for Python-enabled Vim # Website: http://www.vim.org/scripts/script.php?script_id=2657 # Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) # License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ """ VOoM markup mode for cwiki Vim plugin. Contributed by Craig B. Allen. http://www.vim.org/scripts/script.php?script_id=2176 See |voom-mode-various|, ../../../doc/voom.txt#*voom-mode-various* +++ headline level 1 some text ++++ headline level 2 more text +++++ headline level 3 ++++++ headline level 4 etc. First + must be at start of line. Whitespace after the last + is optional. """ import sys if sys.version_info[0] > 2: xrange = range import re headline_match = re.compile(r'^\+\+(\++)').match def hook_makeOutline(VO, blines): """Return (tlines, bnodes, levels) for Body lines blines. blines is either Vim buffer object (Body) or list of buffer lines. """ Z = len(blines) tlines, bnodes, levels = [], [], [] tlines_add, bnodes_add, levels_add = tlines.append, bnodes.append, levels.append for i in xrange(Z): if not blines[i].startswith('+'): continue bline = blines[i] m = headline_match(bline) if not m: continue lev = len(m.group(1)) head = bline[2+lev:].strip() tline = ' %s|%s' %('. '*(lev-1), head) tlines_add(tline) bnodes_add(i+1) levels_add(lev) return (tlines, bnodes, levels) def hook_newHeadline(VO, level, blnum, tlnum): """Return (tree_head, bodyLines). tree_head is new headline string in Tree buffer (text after |). bodyLines is list of lines to insert in Body buffer. """ tree_head = 'NewHeadline' bodyLines = ['++%s %s' %('+'*level, tree_head), ''] return (tree_head, bodyLines) def hook_changeLevBodyHead(VO, h, levDelta): """Increase of decrease level number of Body headline by levDelta.""" if levDelta==0: return h m = headline_match(h) level = len(m.group(1)) return '++%s%s' %('+'*(level+levDelta), h[m.end(1):]) VOoM-5.3/autoload/voom/voom_vimplugin2657/voom_mode_dokuwiki.py000066400000000000000000000110501305710164100246260ustar00rootroot00000000000000# File: voom_mode_dokuwiki.py # Last Modified: 2017-01-07 # Description: VOoM -- two-pane outliner plugin for Python-enabled Vim # Website: http://www.vim.org/scripts/script.php?script_id=2657 # Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) # License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ """ VOoM markup mode for DokuWiki sections. See |voom-mode-dokuwiki|, ../../../doc/voom.txt#*voom-mode-dokuwiki* """ # based on voom_mode_inverseAtx.py try: import vim except ImportError: pass import sys if sys.version_info[0] > 2: xrange = range import re headline_match = re.compile(r'^( ?| \t[ \t]*)(={2,})(.+?)(={2,})[ \t]*$').match # Marker character that denotes a headline in the regexp above. CHAR = '=' # The maximum possible level. # The number of leading marker characters for level 1 headline is MAX+1 or more. MAX = 5 def hook_makeOutline(VO, blines): """Return (tlines, bnodes, levels) for Body lines blines. blines is either Vim buffer object (Body) or list of buffer lines. """ Z = len(blines) tlines, bnodes, levels = [], [], [] tlines_add, bnodes_add, levels_add = tlines.append, bnodes.append, levels.append for i in xrange(Z): if not blines[i].lstrip().startswith(CHAR): continue bline = blines[i] m = headline_match(bline) if not m: continue n = len(m.group(2)) if n > MAX: lev = 1 else: lev = MAX - n + 2 head = m.group(3).strip() tline = ' %s|%s' %('. '*(lev-1), head) tlines_add(tline) bnodes_add(i+1) levels_add(lev) return (tlines, bnodes, levels) def hook_newHeadline(VO, level, blnum, tlnum): """Return (tree_head, bodyLines). tree_head is new headline string in Tree buffer (text after |). bodyLines is list of lines to insert in Body buffer. """ tree_head = 'NewHeadline' if level >= MAX: C = CHAR else: C = CHAR * (MAX - level + 1) bodyLines = ['=%s %s =%s' %(C, tree_head, C), ''] return (tree_head, bodyLines) #def hook_changeLevBodyHead(VO, h, levDelta): def hook_doBodyAfterOop(VO, oop, levDelta, blnum1, tlnum1, blnum2, tlnum2, blnumCut, tlnumCut): # this is instead of hook_changeLevBodyHead() #print('oop=%s levDelta=%s blnum1=%s tlnum1=%s blnum2=%s tlnum2=%s tlnumCut=%s blnumCut=%s' % (oop, levDelta, blnum1, tlnum1, blnum2, tlnum2, tlnumCut, blnumCut)) Body = VO.Body Z = len(Body) bnodes, levels = VO.bnodes, VO.levels # blnum1 blnum2 is first and last lnums of Body region pasted, inserted # during up/down, or promoted/demoted. if blnum1: assert blnum1 == bnodes[tlnum1-1] if tlnum2 < len(bnodes): assert blnum2 == bnodes[tlnum2]-1 else: assert blnum2 == Z # blnumCut is Body lnum after which a region was removed during 'cut' if blnumCut: if tlnumCut < len(bnodes): assert blnumCut == bnodes[tlnumCut]-1 else: assert blnumCut == Z ### Change levels and/or sections of headlines in the affected region. if not levDelta: return # Examine each headline in the affected region from top to bottom. # Change levels. # Correct levels that exceed the MAX: set them to MAX. invalid_levs = [] # tree lnums of nodes with level > MAX for i in xrange(tlnum1, tlnum2+1): # required level based on new VO.levels, can be disallowed lev_ = levels[i-1] # Body line bln = bnodes[i-1] L = Body[bln-1] # original Body headline line if lev_ <= MAX: n = MAX - lev_ + 1 # MAX level exceeded else: n = 1 invalid_levs.append(i) levels[i-1] = MAX # correct VO.levels # don't change Body line if level is already at MAX if lev_ - levDelta == MAX: continue m = headline_match(L) # set Body line # don't bother changing closing CHARs if there are too many of them if len(m.group(4)) <= MAX+1: Body[bln-1] = '%s=%s%s=%s' %(m.group(1), CHAR * n, m.group(3), CHAR * n) else: Body[bln-1] = '%s=%s%s' %(m.group(1), CHAR * n, L[m.end(2):]) ### --- the end --- if invalid_levs: vim.command("call voom#ErrorMsg('VOoM (dokuwiki): Disallowed levels have been corrected after ''%s''')" %oop) invalid_levs = ', '.join(['%s' %i for i in invalid_levs]) vim.command("call voom#ErrorMsg(' level set to maximum (%s) for nodes: %s')" %(MAX, invalid_levs)) VOoM-5.3/autoload/voom/voom_vimplugin2657/voom_mode_fmr.py000066400000000000000000000010571305710164100235720ustar00rootroot00000000000000# File: voom_mode_fmr.py # Last Modified: 2017-01-07 # Description: VOoM -- two-pane outliner plugin for Python-enabled Vim # Website: http://www.vim.org/scripts/script.php?script_id=2657 # Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) # License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ """ VOoM markup mode for start fold markers with levels. See |voom-mode-fmr|, ../../../doc/voom.txt#*voom-mode-fmr* This is the default or "fmr" mode. This module changes absolutely nothing. """ # Define this mode as an 'fmr' mode. MTYPE = 0 VOoM-5.3/autoload/voom/voom_vimplugin2657/voom_mode_fmr1.py000066400000000000000000000040671305710164100236570ustar00rootroot00000000000000# File: voom_mode_fmr1.py # Last Modified: 2017-01-07 # Description: VOoM -- two-pane outliner plugin for Python-enabled Vim # Website: http://www.vim.org/scripts/script.php?script_id=2657 # Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) # License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ """ VOoM markup mode for start fold markers with levels. See |voom-mode-fmr1|, ../../../doc/voom.txt#*voom-mode-fmr1* Headline text is before the start fold marker with level. Very similar to "fmr" mode. headline level 1 {{{1 some text headline level 2 {{{2 more text """ import sys if sys.version_info[0] > 2: xrange = range # Define this mode as an 'fmr' mode. MTYPE = 0 # voom_vim.makeoutline() without char stripping def hook_makeOutline(VO, blines): """Return (tlines, bnodes, levels) for Body lines blines. blines is either Vim buffer object (Body) or list of buffer lines. """ marker = VO.marker marker_re_search = VO.marker_re.search Z = len(blines) tlines, bnodes, levels = [], [], [] tlines_add, bnodes_add, levels_add = tlines.append, bnodes.append, levels.append #c = VO.rstrip_chars for i in xrange(Z): if not marker in blines[i]: continue bline = blines[i] m = marker_re_search(bline) if not m: continue lev = int(m.group(1)) #head = bline[:m.start()].lstrip().rstrip(c).strip('-=~').strip() head = bline[:m.start()].strip() tline = ' %s%s|%s' %(m.group(2) or ' ', '. '*(lev-1), head) tlines_add(tline) bnodes_add(i+1) levels_add(lev) return (tlines, bnodes, levels) # same as voom_vim.newHeadline() but without --- def hook_newHeadline(VO, level, blnum, ln): """Return (tree_head, bodyLines). tree_head is new headline string in Tree buffer (text after |). bodyLines is list of lines to insert in Body buffer. """ tree_head = 'NewHeadline' #bodyLines = ['---%s--- %s%s' %(tree_head, VO.marker, level), ''] bodyLines = ['%s %s%s' %(tree_head, VO.marker, level), ''] return (tree_head, bodyLines) VOoM-5.3/autoload/voom/voom_vimplugin2657/voom_mode_fmr2.py000066400000000000000000000041461305710164100236560ustar00rootroot00000000000000# File: voom_mode_fmr2.py # Last Modified: 2017-01-07 # Description: VOoM -- two-pane outliner plugin for Python-enabled Vim # Website: http://www.vim.org/scripts/script.php?script_id=2657 # Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) # License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ """ VOoM markup mode for start fold markers with levels. See |voom-mode-fmr2|, ../../../doc/voom.txt#*voom-mode-fmr2* Headline text is after the start fold marker with level. {{{1 headline level 1 some text {{{2 headline level 2 more text """ import sys if sys.version_info[0] > 2: xrange = range # Define this mode as an 'fmr' mode. MTYPE = 0 def hook_makeOutline(VO, blines): """Return (tlines, bnodes, levels) for Body lines blines. blines is either Vim buffer object (Body) or list of buffer lines. """ marker = VO.marker marker_re_search = VO.marker_re.search Z = len(blines) tlines, bnodes, levels = [], [], [] tlines_add, bnodes_add, levels_add = tlines.append, bnodes.append, levels.append #c = VO.rstrip_chars for i in xrange(Z): if not marker in blines[i]: continue bline = blines[i] m = marker_re_search(bline) if not m: continue lev = int(m.group(1)) head = bline[m.end():] # part after the fold marker # strip optional special marks from left side: "o", "=", "o=" #if head and head[0]=='o': head = head[1:] #if head and head[0]=='=': head = head[1:] # lstrip all xo= to avoid conflicts with commands that add or remove them head = head.lstrip('xo=') tline = ' %s%s|%s' %(m.group(2) or ' ', '. '*(lev-1), head.strip()) tlines_add(tline) bnodes_add(i+1) levels_add(lev) return (tlines, bnodes, levels) def hook_newHeadline(VO, level, blnum, ln): """Return (tree_head, bodyLines). tree_head is new headline string in Tree buffer (text after |). bodyLines is list of lines to insert in Body buffer. """ tree_head = 'NewHeadline' bodyLines = ['%s%s %s' %(VO.marker, level, tree_head), ''] return (tree_head, bodyLines) VOoM-5.3/autoload/voom/voom_vimplugin2657/voom_mode_fmr3.py000066400000000000000000000044301305710164100236530ustar00rootroot00000000000000# File: voom_mode_fmr3.py # Last Modified: 2017-01-07 # Description: VOoM -- two-pane outliner plugin for Python-enabled Vim # Website: http://www.vim.org/scripts/script.php?script_id=2657 # Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) # License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ """ VOoM markup mode for start fold markers with levels. See |voom-mode-fmr3|, ../../../doc/voom.txt#*voom-mode-fmr3* Headline text can be before or after the start fold marker with level. {{{1 headline level 1 headline level 2 {{{2 """ import sys if sys.version_info[0] > 2: xrange = range # Define this mode as an 'fmr' mode. MTYPE = 0 def hook_makeOutline(VO, blines): """Return (tlines, bnodes, levels) for Body lines blines. blines is either Vim buffer object (Body) or list of buffer lines. """ marker = VO.marker marker_re_search = VO.marker_re.search Z = len(blines) tlines, bnodes, levels = [], [], [] tlines_add, bnodes_add, levels_add = tlines.append, bnodes.append, levels.append #c = VO.rstrip_chars for i in xrange(Z): if not marker in blines[i]: continue bline = blines[i] m = marker_re_search(bline) if not m: continue lev = int(m.group(1)) head = bline[m.end():] # part after the fold marker # strip optional special marks from left side: "o", "=", "o=" #if head and head[0]=='o': head = head[1:] #if head and head[0]=='=': head = head[1:] # lstrip all xo= to avoid conflicts with commands that add or remove them head = head.lstrip('xo=') # add part before the fold marker if head: head = '%s %s' % (bline[:m.start()].rstrip(), head.lstrip()) else: head = bline[:m.start()] tline = ' %s%s|%s' %(m.group(2) or ' ', '. '*(lev-1), head.strip()) tlines_add(tline) bnodes_add(i+1) levels_add(lev) return (tlines, bnodes, levels) def hook_newHeadline(VO, level, blnum, ln): """Return (tree_head, bodyLines). tree_head is new headline string in Tree buffer (text after |). bodyLines is list of lines to insert in Body buffer. """ tree_head = 'NewHeadline' bodyLines = ['%s %s%s' %(tree_head, VO.marker, level), ''] return (tree_head, bodyLines) VOoM-5.3/autoload/voom/voom_vimplugin2657/voom_mode_hashes.py000066400000000000000000000046641305710164100242700ustar00rootroot00000000000000# File: voom_mode_hashes.py # Last Modified: 2017-01-07 # Description: VOoM -- two-pane outliner plugin for Python-enabled Vim # Website: http://www.vim.org/scripts/script.php?script_id=2657 # Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) # License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ """ VOoM markup mode for headlines marked with #'s (atx-headers, a subset of Markdown format). See |voom-mode-hashes|, ../../../doc/voom.txt#*voom-mode-hashes* # heading level 1 ##heading level 2 ### heading level 3 """ import sys if sys.version_info[0] > 2: xrange = range import re # Marker character can be changed to any ASCII character. CHAR = '#' # Use this if whitespace after marker chars is optional. headline_match = re.compile(r'^(%s+)' %re.escape(CHAR)).match # Use this if a whitespace is required after marker chars (as in org-mode). #headline_match = re.compile(r'^(%s+)\s' %re.escape(CHAR)).match def hook_makeOutline(VO, blines): """Return (tlines, bnodes, levels) for Body lines blines. blines is either Vim buffer object (Body) or list of buffer lines. """ Z = len(blines) tlines, bnodes, levels = [], [], [] tlines_add, bnodes_add, levels_add = tlines.append, bnodes.append, levels.append for i in xrange(Z): if not blines[i].startswith(CHAR): continue bline = blines[i] m = headline_match(bline) # Uncomment the next line if whitespace is required after marker chars. #if not m: continue lev = len(m.group(1)) head = bline[lev:].strip() # Do this instead if optional closing markers need to be stripped. #head = bline[lev:].strip().rstrip(CHAR).rstrip() tline = ' %s|%s' %('. '*(lev-1), head) tlines_add(tline) bnodes_add(i+1) levels_add(lev) return (tlines, bnodes, levels) def hook_newHeadline(VO, level, blnum, tlnum): """Return (tree_head, bodyLines). tree_head is new headline string in Tree buffer (text after |). bodyLines is list of lines to insert in Body buffer. """ tree_head = 'NewHeadline' bodyLines = ['%s %s' %(CHAR * level, tree_head), ''] return (tree_head, bodyLines) def hook_changeLevBodyHead(VO, h, levDelta): """Increase of decrease level number of Body headline by levDelta.""" if levDelta==0: return h m = headline_match(h) level = len(m.group(1)) return '%s%s' %(CHAR * (level+levDelta), h[m.end(1):]) VOoM-5.3/autoload/voom/voom_vimplugin2657/voom_mode_html.py000066400000000000000000000044511305710164100237530ustar00rootroot00000000000000# File: voom_mode_html.py # Last Modified: 2017-01-07 # Description: VOoM -- two-pane outliner plugin for Python-enabled Vim # Website: http://www.vim.org/scripts/script.php?script_id=2657 # Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) # License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ """ VOoM markup mode for HTML headings. See |voom-mode-html|, ../../../doc/voom.txt#*voom-mode-html*

headline level 1

some text

headline level 2

more text

headline level 3

< h4 > headline level 4 some text

headline 5

etc. """ import sys if sys.version_info[0] > 2: xrange = range import re headline_search = re.compile(r'<\s*h(\d+).*?>(.*?)', re.IGNORECASE).search html_tag_sub = re.compile('<.*?>').sub def hook_makeOutline(VO, blines): """Return (tlines, bnodes, levels) for Body lines blines. blines is either Vim buffer object (Body) or list of buffer lines. """ Z = len(blines) tlines, bnodes, levels = [], [], [] tlines_add, bnodes_add, levels_add = tlines.append, bnodes.append, levels.append for i in xrange(Z): bline = blines[i] if not ('%s' %(level, tree_head, level), ''] return (tree_head, bodyLines) def hook_changeLevBodyHead(VO, h, levDelta): """Increase of decrease level number of Body headline by levDelta.""" if levDelta==0: return h m = headline_search(h) level = int(m.group(1)) lev = level+levDelta return '%s%s%s%s%s' %(h[:m.start(1)], lev, h[m.end(1):m.start(3)], lev, h[m.end(3):]) VOoM-5.3/autoload/voom/voom_vimplugin2657/voom_mode_inverseAtx.py000066400000000000000000000134071305710164100251400ustar00rootroot00000000000000# File: voom_mode_inverseAtx.py # Last Modified: 2017-01-07 # Description: VOoM -- two-pane outliner plugin for Python-enabled Vim # Website: http://www.vim.org/scripts/script.php?script_id=2657 # Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) # License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ """ VOoM markup mode for inverse Atx-style headers. See |voom-mode-various|, ../../../doc/voom.txt#*voom-mode-various* Headlines start with '@'. There is a maximum of 3 levels: @@@ Headline level 1 @@ Headline level 2 @ Headline level 3 To change the character that denotes headlines and the maximum level, change module-level constants CHAR and MAX below. You can also change them by adding options to .vimrc: let g:voom_inverseAtx_char = '^' let g:voom_inverseAtx_max = 5 """ # Marker character that denotes a headline. It can be any ASCII character. CHAR = '@' # The number of marker characters for level 1 headline. This is also the maximum possible level. MAX = 3 try: import vim if vim.eval('exists("g:voom_inverseAtx_char")')=='1': CHAR = vim.eval("g:voom_inverseAtx_char") if vim.eval('exists("g:voom_inverseAtx_max")')=='1': MAX = int(vim.eval("g:voom_inverseAtx_max")) except ImportError: pass import sys if sys.version_info[0] > 2: xrange = range import re # Use this if whitespace after marker chars is optional. headline_match = re.compile(r'^(%s+)' %re.escape(CHAR)).match # Use this if a whitespace is required after marker chars. #headline_match = re.compile(r'^(%s+)\s' %re.escape(CHAR)).match # based on voom_mode_hashes.py def hook_makeOutline(VO, blines): """Return (tlines, bnodes, levels) for Body lines blines. blines is either Vim buffer object (Body) or list of buffer lines. """ Z = len(blines) tlines, bnodes, levels = [], [], [] tlines_add, bnodes_add, levels_add = tlines.append, bnodes.append, levels.append for i in xrange(Z): if not blines[i].startswith(CHAR): continue bline = blines[i] m = headline_match(bline) # Uncomment the next line if whitespace is required after marker chars. #if not m: continue n = len(m.group(1)) if n >= MAX: lev = 1 else: lev = MAX - n + 1 head = bline.lstrip(CHAR).strip() # Do this instead if optional closing markers need to be stripped. #head = bline.rstrip().strip(CHAR).strip() tline = ' %s|%s' %('. '*(lev-1), head) tlines_add(tline) bnodes_add(i+1) levels_add(lev) return (tlines, bnodes, levels) def hook_newHeadline(VO, level, blnum, tlnum): """Return (tree_head, bodyLines). tree_head is new headline string in Tree buffer (text after |). bodyLines is list of lines to insert in Body buffer. """ tree_head = 'NewHeadline' if level >= MAX: n = 1 else: n = MAX - level + 1 bodyLines = ['%s %s' %(CHAR * n, tree_head), ''] return (tree_head, bodyLines) ## This is not good enough: Body is always modified when move right fails ## because MAX level was exceeded, even if no changes to headlines were made. #def hook_changeLevBodyHead(VO, h, levDelta): # """Increase of decrease level number of Body headline by levDelta.""" # if levDelta==0: return h # m = headline_match(h) # n = len(m.group(1)) # if n >= MAX: # lev = 1 # else: # lev = MAX - n + 1 # level = lev + levDelta # if level >= MAX: # n = 1 # else: # n = MAX - level + 1 # return '%s%s' %(CHAR * n, h[m.end(1):]) # based on voom_mode_latex.py def hook_doBodyAfterOop(VO, oop, levDelta, blnum1, tlnum1, blnum2, tlnum2, blnumCut, tlnumCut): # this is instead of hook_changeLevBodyHead() #print('oop=%s levDelta=%s blnum1=%s tlnum1=%s blnum2=%s tlnum2=%s tlnumCut=%s blnumCut=%s' % (oop, levDelta, blnum1, tlnum1, blnum2, tlnum2, tlnumCut, blnumCut)) Body = VO.Body Z = len(Body) bnodes, levels = VO.bnodes, VO.levels # blnum1 blnum2 is first and last lnums of Body region pasted, inserted # during up/down, or promoted/demoted. if blnum1: assert blnum1 == bnodes[tlnum1-1] if tlnum2 < len(bnodes): assert blnum2 == bnodes[tlnum2]-1 else: assert blnum2 == Z # blnumCut is Body lnum after which a region was removed during 'cut' if blnumCut: if tlnumCut < len(bnodes): assert blnumCut == bnodes[tlnumCut]-1 else: assert blnumCut == Z ### Change levels and/or sections of headlines in the affected region. if not levDelta: return # Examine each headline in the affected region from top to bottom. # Change levels. # Correct levels that exceed the MAX: set them to MAX. invalid_levs = [] # tree lnums of nodes with level > MAX for i in xrange(tlnum1, tlnum2+1): # required level based on new VO.levels, can be disallowed lev_ = levels[i-1] # Body line bln = bnodes[i-1] L = Body[bln-1] # original Body headline line if lev_ <= MAX: n = MAX - lev_ + 1 # MAX level exceeded else: n = 1 invalid_levs.append(i) levels[i-1] = MAX # correct VO.levels # don't change Body line if level is already at MAX if lev_ - levDelta == MAX: continue m = headline_match(L) Body[bln-1] ='%s%s' %(CHAR * n, L[m.end(1):]) ### --- the end --- if invalid_levs: vim.command("call voom#ErrorMsg('VOoM (inverseAtx): Disallowed levels have been corrected after ''%s''')" %oop) invalid_levs = ', '.join(['%s' %i for i in invalid_levs]) vim.command("call voom#ErrorMsg(' level set to maximum (%s) for nodes: %s')" %(MAX, invalid_levs)) VOoM-5.3/autoload/voom/voom_vimplugin2657/voom_mode_latex.py000066400000000000000000000253001305710164100241200ustar00rootroot00000000000000# File: voom_mode_latex.py # Last Modified: 2017-01-15 # Description: VOoM -- two-pane outliner plugin for Python-enabled Vim # Website: http://www.vim.org/scripts/script.php?script_id=2657 # Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) # License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ """ VOoM markup mode for LaTeX. See |voom-mode-latex|, ../../../doc/voom.txt#*voom-mode-latex* """ # SECTIONS, ELEMENTS, VERBATIMS can be defined here or in Vim variables: # g:voom_latex_sections # g:voom_latex_elements # g:voom_latex_verbatims # # SECTIONS defines sectioning commands, in order of increasing level: # \part{A Heading} # \chapter{A Heading} # \section{A Heading} # \subsection{A Heading} # \subsubsection{A Heading} # \paragraph{A Heading} # \subparagraph{A Heading} # # ELEMENTS defines fixed elements -- always at level 1: # \begin{document} # \begin{abstract} # \begin{thebibliography} # \end{document} # \bibliography{... # # VERBATIMS defines regions where headlines are ignored: # \begin{verbatim} ... \end{verbatim} # \begin{comment} ... \end{comment} # # The actual levels are determined by sections that are present in the buffer. # Levels are always incremented by 1. That is, if there are only # \section and \paragraph then \section is level 1 and \paragraph is level 2. # sectioning commands, in order of increasing level SECTIONS = ['part', 'chapter', 'section', 'subsection', 'subsubsection', 'paragraph', 'subparagraph'] # fixed elements -- always at level 1 ELEMENTS = r'^\s*\\(begin\s*\{(document|abstract|thebibliography)\}|end\s*\{document\}|bibliography\s*\{)' # verbatim regions, headlines are ignored inside \begin{verbatim} ... \end{verbatim} VERBATIMS = ['verbatim', 'comment'] #--------------------------------------------------------------------- try: import vim if vim.eval('exists("g:voom_latex_sections")')=='1': SECTIONS = vim.eval("g:voom_latex_sections") if vim.eval('exists("g:voom_latex_elements")')=='1': ELEMENTS = vim.eval("g:voom_latex_elements") if vim.eval('exists("g:voom_latex_verbatims")')=='1': VERBATIMS = vim.eval("g:voom_latex_verbatims") except ImportError: pass import sys if sys.version_info[0] > 2: xrange = range import re # \section{head} or \section*{head} or \section[optionaltitle]{head} # NOTE: match leading whitespace to preserve it during outline operations # m.group() 1 2 3 SECTS_RE = re.compile(r'^\s*\\(%s)\s*(\*|\[[^]{]*\])?\s*\{(.*)' %('|'.join(SECTIONS))).match if ELEMENTS: ELEMS_RE = re.compile(ELEMENTS).match else: ELEMS_RE = 0 if VERBATIMS: # NOTE: leading whitespace must be lstripped before matching VERBS_RE = re.compile(r'^\\begin\s*\{(%s)\}' %('|'.join(VERBATIMS))).match else: VERBS_RE = 0 SECTIONS = ['\\'+s for s in SECTIONS] SECTS_LEVS = {} # {section: its default level, ...} LEVS_SECTS = {} # {level: its default section, ...} i = 1 for s in SECTIONS: SECTS_LEVS[s] = i LEVS_SECTS[i] = s i+=1 def hook_makeOutline(VO, blines): """Return (tlines, bnodes, levels) for Body lines blines. blines is either Vim buffer object (Body) or list of buffer lines. """ Z = len(blines) tlines, bnodes, levels = [], [], [] tlines_add, bnodes_add, levels_add = tlines.append, bnodes.append, levels.append marks, heads = [], [] marks_add, heads_add = marks.append, heads.append sects_levs = {} # {section: its default level} for all section found in the buffer inVerbatim = False isHead = False mark = ' ' # * or - for i in xrange(Z): L = blines[i].lstrip() if not L.startswith('\\'): continue # regions to ignore: \begin{verbatim} ... \end{verbatim} if VERBS_RE: if inVerbatim: if re.match(inVerbatim, L): inVerbatim = False continue else: m = VERBS_RE(L) if m: inVerbatim = r'\\end\s*\{%s\}' %m.group(1) continue # check for sections m = SECTS_RE(L) if m: isHead = True s = '\\' + m.group(1) lev = SECTS_LEVS[s] sects_levs[s] = lev if m.group(2) and m.group(2)=='*': mark = '*' head = m.group(3) # truncate head before the matching '}' j = 0; k = 1 for ch in head: if ch=='{': k+=1 elif ch=='}': k-=1 if not k: break j+=1 head = head[:j].strip() # check for fixed level 1 elements elif ELEMS_RE: m = ELEMS_RE(L) if m: isHead = True lev = 1 head = L.rstrip() mark = '-' # add node to outline if isHead: isHead = False bnodes_add(i+1) levels_add(lev) # tlines must be constructed from marks and heads and after levels are adjusted marks_add(mark) mark = ' ' heads_add(head) # adjust default level numbers to reflect only sections present in the buffer # that is make all level numbers continuous, top level is 1 d = {} # {default level: actual level, ...} levs_sects = {} # {actual level: section, ...} sects = [(sects_levs[s], s) for s in sects_levs.keys()] sects.sort() sects = [i[1] for i in sects] i = 1 for s in sects: d[sects_levs[s]] = i levs_sects[i] = s i+=1 levels = [d.get(i,i) for i in levels] # construct tlines for i in xrange(len(levels)): tlines_add(' %s%s|%s' %(marks[i], '. '*(levels[i]-1), heads[i])) # save levs_sects for outline operations # don't clobber VO.levs_sects when parsing clipboard during Paste # which is the only time blines is not Body if blines is VO.Body: VO._levs_sects = levs_sects return (tlines, bnodes, levels) def hook_newHeadline(VO, level, blnum, tlnum): """Return (tree_head, bodyLines). tree_head is new headline string in Tree buffer (text after |). bodyLines is list of lines to insert in Body buffer. """ tree_head = 'NewHeadline' (sect, lev) = get_sect_for_lev(VO._levs_sects, level) assert lev <= level if not lev==level: vim.command("call voom#ErrorMsg('VOoM (latex): MAXIMUM LEVEL EXCEEDED')") bodyLines = ['%s{%s}' %(sect, tree_head), ''] return (tree_head, bodyLines) #def hook_changeLevBodyHead(VO, h, levDelta): # DO NOT CREATE THIS HOOK def hook_doBodyAfterOop(VO, oop, levDelta, blnum1, tlnum1, blnum2, tlnum2, blnumCut, tlnumCut): # this is instead of hook_changeLevBodyHead() #print('oop=%s levDelta=%s blnum1=%s tlnum1=%s blnum2=%s tlnum2=%s tlnumCut=%s blnumCut=%s' % (oop, levDelta, blnum1, tlnum1, blnum2, tlnum2, tlnumCut, blnumCut)) Body = VO.Body Z = len(Body) bnodes, levels = VO.bnodes, VO.levels # blnum1 blnum2 is first and last lnums of Body region pasted, inserted # during up/down, or promoted/demoted. if blnum1: assert blnum1 == bnodes[tlnum1-1] if tlnum2 < len(bnodes): assert blnum2 == bnodes[tlnum2]-1 else: assert blnum2 == Z # blnumCut is Body lnum after which a region was removed during 'cut' if blnumCut: if tlnumCut < len(bnodes): assert blnumCut == bnodes[tlnumCut]-1 else: assert blnumCut == Z ### Change levels and/or sections of headlines in the affected region. # Sections must always be adjusted after Paste, even if level is unchanged, # in case pasting was done from another outline with different style. if not (levDelta or oop=='paste'): return # Examine each headline in the affected region from top to bottom. # For sections: change them to the current level and style. # Correct invalid levels: VOoM**voom_notes.txt#ID_20120520092604 # use max level if max possible level is exeeded # use 1 for fixed elements at level >1 invalid_sects, invalid_elems = [], [] # tree lnums of nodes with disallowed levels levs_sects = VO._levs_sects #for i in xrange(tlnum2, tlnum1-1, -1): for i in xrange(tlnum1, tlnum2+1): # required level based on new VO.levels, can be disallowed lev_ = levels[i-1] # Body line bln = bnodes[i-1] L = Body[bln-1] # NOTE: original line, not lstripped m = SECTS_RE(L) if not m: assert ELEMS_RE(L) # fixed level 1 element at level >1 if lev_ > 1: invalid_elems.append(i) levels[i-1] = 1 # correct VO.levels continue # current section sect_ = '\\' + m.group(1) # required section and its actual level (sect, lev) = get_sect_for_lev(levs_sects, lev_) # change section (NOTE: SECTS_RE matches after \, thus -1) if not sect == sect_: Body[bln-1] = '%s%s%s' %(L[:m.start(1)-1], sect, L[m.end(1):]) # check if max level was exceeded if not lev == lev_: invalid_sects.append(i) levels[i-1] = lev # correct VO.levels # changes VO._levs_sects if not lev in levs_sects: levs_sects[lev] = sect ### --- the end --- if invalid_elems or invalid_sects: vim.command("call voom#ErrorMsg('VOoM (latex): Disallowed levels have been corrected after ''%s''')" %oop) if invalid_elems: invalid_elems = ', '.join(['%s' %i for i in invalid_elems]) vim.command("call voom#ErrorMsg(' level set to 1 for nodes: %s')" %invalid_elems) if invalid_sects: invalid_sects = ', '.join(['%s' %i for i in invalid_sects]) vim.command("call voom#ErrorMsg(' level set to maximum for nodes: %s')" %invalid_sects) def get_sect_for_lev(levs_sects, level): """Return (section, actual level) corresponding to the desired level. levs_sects contains all sections currently in use. If level exceeds the maximum, return section for maximum possible level and max level. """ if level in levs_sects: return (levs_sects[level], level) z = len(SECTIONS) # outline is empty if not levs_sects: if level <= z: return (SECTIONS[level-1], level) else: return (SECTIONS[-1], z) # pick new sect from SECTIONS levmax = max(levs_sects.keys()) # currently used max level sectmax = levs_sects[levmax] idx = SECTS_LEVS[sectmax] + (level - levmax) if idx <= z: return (SECTIONS[idx-1], level) else: return (SECTIONS[-1], level-(idx-z)) VOoM-5.3/autoload/voom/voom_vimplugin2657/voom_mode_latexDtx.py000066400000000000000000000271271305710164100246110ustar00rootroot00000000000000# File: voom_mode_latexDtx.py # Last Modified: 2017-01-15 # Description: VOoM -- two-pane outliner plugin for Python-enabled Vim # Website: http://www.vim.org/scripts/script.php?script_id=2657 # Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) # License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ """ VOoM markup mode for .dtx files (Documented LaTeX sources). It is almost identical to the LaTeX mode. The main difference is that only lines that begin with the comment character "%" can be headlines. See |voom-mode-latexDtx|, ../../../doc/voom.txt#*voom-mode-latexDtx* """ # THIS MODULE IS ALMOST IDENTICAL TO voom_mode_latex.py -- KEEP IN SYNC. # # Only commented lines are considered. Commented lines start with: optional # leading whitespace, at least one % character, optionally followed by any # combination of % and whitespace. # The following are all valid sectioning commands: # %\section{Introduction} # % \section{Introduction} # %% \section{Introduction} # %%% % % \section{Introduction} # The leading string of % and whitespace is preserved during outline operations. # SECTIONS, ELEMENTS, VERBATIMS can be defined here or in Vim variables: # g:voom_latexdtx_sections # g:voom_latexdtx_elements # g:voom_latexdtx_verbatims # # SECTIONS defines sectioning commands, in order of increasing level: # \part{A Heading} # \chapter{A Heading} # \section{A Heading} # \subsection{A Heading} # \subsubsection{A Heading} # \paragraph{A Heading} # \subparagraph{A Heading} # # ELEMENTS defines fixed elements -- always at level 1: # \begin{document} # \begin{abstract} # \begin{thebibliography} # \end{document} # \bibliography{... # # VERBATIMS defines regions where headlines are ignored: # \begin{verbatim} ... \end{verbatim} # \begin{comment} ... \end{comment} # # The actual levels are determined by sections that are present in the buffer. # Levels are always incremented by 1. That is, if there are only # \section and \paragraph then \section is level 1 and \paragraph is level 2. # sectioning commands, in order of increasing level SECTIONS = ['part', 'chapter', 'section', 'subsection', 'subsubsection', 'paragraph', 'subparagraph'] # fixed elements -- always at level 1 ELEMENTS = r'^[\s%]*\\(begin\s*\{(document|abstract|thebibliography)\}|end\s*\{document\}|bibliography\s*\{)' # verbatim regions, headlines are ignored inside \begin{verbatim} ... \end{verbatim} VERBATIMS = ['verbatim', 'comment', 'macrocode'] #--------------------------------------------------------------------- try: import vim if vim.eval('exists("g:voom_latexdtx_sections")')=='1': SECTIONS = vim.eval("g:voom_latexdtx_sections") if vim.eval('exists("g:voom_latexdtx_elements")')=='1': ELEMENTS = vim.eval("g:voom_latexdtx_elements") if vim.eval('exists("g:voom_latexdtx_verbatims")')=='1': VERBATIMS = vim.eval("g:voom_latexdtx_verbatims") except ImportError: pass import sys if sys.version_info[0] > 2: xrange = range import re # \section{head} or \section*{head} or \section[optionaltitle]{head} # NOTE: match leading whitespace to preserve it during outline operations # m.group() 1 2 3 SECTS_RE = re.compile(r'^[\s%%]*\\(%s)\s*(\*|\[[^]{]*\])?\s*\{(.*)' %('|'.join(SECTIONS))).match if ELEMENTS: ELEMS_RE = re.compile(ELEMENTS).match else: ELEMS_RE = 0 if VERBATIMS: # NOTE: leading whitespace and % must be lstripped before matching VERBS_RE = re.compile(r'^\\begin\s*\{(%s)\}' %('|'.join(VERBATIMS))).match else: VERBS_RE = 0 SECTIONS = ['\\'+s for s in SECTIONS] SECTS_LEVS = {} # {section: its default level, ...} LEVS_SECTS = {} # {level: its default section, ...} i = 1 for s in SECTIONS: SECTS_LEVS[s] = i LEVS_SECTS[i] = s i+=1 def hook_makeOutline(VO, blines): """Return (tlines, bnodes, levels) for Body lines blines. blines is either Vim buffer object (Body) or list of buffer lines. """ Z = len(blines) tlines, bnodes, levels = [], [], [] tlines_add, bnodes_add, levels_add = tlines.append, bnodes.append, levels.append marks, heads = [], [] marks_add, heads_add = marks.append, heads.append sects_levs = {} # {section: its default level} for all section found in the buffer inVerbatim = False isHead = False mark = ' ' # * or - for i in xrange(Z): L = blines[i].lstrip() if not L.startswith('%'): continue # dtx-specific L = L.lstrip('% \t') # dtx-specifc if not L.startswith('\\'): continue # regions to ignore: \begin{verbatim} ... \end{verbatim} if VERBS_RE: if inVerbatim: if re.match(inVerbatim, L): inVerbatim = False continue else: m = VERBS_RE(L) if m: inVerbatim = r'\\end\s*\{%s\}' %m.group(1) continue # check for sections m = SECTS_RE(L) if m: isHead = True s = '\\' + m.group(1) lev = SECTS_LEVS[s] sects_levs[s] = lev if m.group(2) and m.group(2)=='*': mark = '*' head = m.group(3) # truncate head before the matching '}' j = 0; k = 1 for ch in head: if ch=='{': k+=1 elif ch=='}': k-=1 if not k: break j+=1 head = head[:j].strip() # check for fixed level 1 elements elif ELEMS_RE: m = ELEMS_RE(L) if m: isHead = True lev = 1 head = L.rstrip() mark = '-' # add node to outline if isHead: isHead = False bnodes_add(i+1) levels_add(lev) # tlines must be constructed from marks and heads and after levels are adjusted marks_add(mark) mark = ' ' heads_add(head) # adjust default level numbers to reflect only sections present in the buffer # that is make all level numbers continuous, top level is 1 d = {} # {default level: actual level, ...} levs_sects = {} # {actual level: section, ...} sects = [(sects_levs[s], s) for s in sects_levs.keys()] sects.sort() sects = [i[1] for i in sects] i = 1 for s in sects: d[sects_levs[s]] = i levs_sects[i] = s i+=1 levels = [d.get(i,i) for i in levels] # construct tlines for i in xrange(len(levels)): tlines_add(' %s%s|%s' %(marks[i], '. '*(levels[i]-1), heads[i])) # save levs_sects for outline operations # don't clobber VO.levs_sects when parsing clipboard during Paste # which is the only time blines is not Body if blines is VO.Body: VO._levs_sects = levs_sects return (tlines, bnodes, levels) def hook_newHeadline(VO, level, blnum, tlnum): """Return (tree_head, bodyLines). tree_head is new headline string in Tree buffer (text after |). bodyLines is list of lines to insert in Body buffer. """ tree_head = 'NewHeadline' (sect, lev) = get_sect_for_lev(VO._levs_sects, level) assert lev <= level if not lev==level: vim.command("call voom#ErrorMsg('VOoM (latexDtx): MAXIMUM LEVEL EXCEEDED')") bodyLines = ['%% %s{%s}' %(sect, tree_head), '%'] # dtx-specific (insert %) return (tree_head, bodyLines) #def hook_changeLevBodyHead(VO, h, levDelta): # DO NOT CREATE THIS HOOK def hook_doBodyAfterOop(VO, oop, levDelta, blnum1, tlnum1, blnum2, tlnum2, blnumCut, tlnumCut): # this is instead of hook_changeLevBodyHead() #print('oop=%s levDelta=%s blnum1=%s tlnum1=%s blnum2=%s tlnum2=%s tlnumCut=%s blnumCut=%s' % (oop, levDelta, blnum1, tlnum1, blnum2, tlnum2, tlnumCut, blnumCut)) Body = VO.Body Z = len(Body) bnodes, levels = VO.bnodes, VO.levels # blnum1 blnum2 is first and last lnums of Body region pasted, inserted # during up/down, or promoted/demoted. if blnum1: assert blnum1 == bnodes[tlnum1-1] if tlnum2 < len(bnodes): assert blnum2 == bnodes[tlnum2]-1 else: assert blnum2 == Z # blnumCut is Body lnum after which a region was removed during 'cut' if blnumCut: if tlnumCut < len(bnodes): assert blnumCut == bnodes[tlnumCut]-1 else: assert blnumCut == Z ### Change levels and/or sections of headlines in the affected region. # Sections must always be adjusted after Paste, even if level is unchanged, # in case pasting was done from another outline with different style. if not (levDelta or oop=='paste'): return # Examine each headline in the affected region from top to bottom. # For sections: change them to the current level and style. # Correct invalid levels: VOoM**voom_notes.txt#ID_20120520092604 # use max level if max possible level is exeeded # use 1 for fixed elements at level >1 invalid_sects, invalid_elems = [], [] # tree lnums of nodes with disallowed levels levs_sects = VO._levs_sects #for i in xrange(tlnum2, tlnum1-1, -1): for i in xrange(tlnum1, tlnum2+1): # required level based on new VO.levels, can be disallowed lev_ = levels[i-1] # Body line bln = bnodes[i-1] L = Body[bln-1] # NOTE: original line, not lstripped m = SECTS_RE(L) if not m: assert ELEMS_RE(L) # fixed level 1 element at level >1 if lev_ > 1: invalid_elems.append(i) levels[i-1] = 1 # correct VO.levels continue # current section sect_ = '\\' + m.group(1) # required section and its actual level (sect, lev) = get_sect_for_lev(levs_sects, lev_) # change section (NOTE: SECTS_RE matches after \, thus -1) if not sect == sect_: Body[bln-1] = '%s%s%s' %(L[:m.start(1)-1], sect, L[m.end(1):]) # check if max level was exceeded if not lev == lev_: invalid_sects.append(i) levels[i-1] = lev # correct VO.levels # changes VO._levs_sects if not lev in levs_sects: levs_sects[lev] = sect ### --- the end --- if invalid_elems or invalid_sects: vim.command("call voom#ErrorMsg('VOoM (latexDtx): Disallowed levels have been corrected after ''%s''')" %oop) if invalid_elems: invalid_elems = ', '.join(['%s' %i for i in invalid_elems]) vim.command("call voom#ErrorMsg(' level set to 1 for nodes: %s')" %invalid_elems) if invalid_sects: invalid_sects = ', '.join(['%s' %i for i in invalid_sects]) vim.command("call voom#ErrorMsg(' level set to maximum for nodes: %s')" %invalid_sects) def get_sect_for_lev(levs_sects, level): """Return (section, actual level) corresponding to the desired level. levs_sects contains all sections currently in use. If level exceeds the maximum, return section for maximum possible level and max level. """ if level in levs_sects: return (levs_sects[level], level) z = len(SECTIONS) # outline is empty if not levs_sects: if level <= z: return (SECTIONS[level-1], level) else: return (SECTIONS[-1], z) # pick new sect from SECTIONS levmax = max(levs_sects.keys()) # currently used max level sectmax = levs_sects[levmax] idx = SECTS_LEVS[sectmax] + (level - levmax) if idx <= z: return (SECTIONS[idx-1], level) else: return (SECTIONS[-1], level-(idx-z)) VOoM-5.3/autoload/voom/voom_vimplugin2657/voom_mode_markdown.py000066400000000000000000000301131305710164100246230ustar00rootroot00000000000000# File: voom_mode_markdown.py # Last Modified: 2017-01-07 # Description: VOoM -- two-pane outliner plugin for Python-enabled Vim # Website: http://www.vim.org/scripts/script.php?script_id=2657 # Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) # License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ """ VOoM markup mode for Markdown headers. See |voom-mode-markdown|, ../../../doc/voom.txt#*voom-mode-markdown* """ import sys if sys.version_info[0] > 2: xrange = range def len_u(s, enc): return len(s) else: def len_u(s, enc): return len(unicode(s, enc, 'replace')) ### NOTES # When an outline operation changes level, it has to deal with two ambiguities: # a) Level 1 and 2 headline can use underline-style or hashes-style. # b) Hashes-style can have or not have closing hashes. # To determine current preferences: check first headline at level <3 and check # first headline with hashes. This must be done in hook_makeOutline(). # (Save in VO, similar to reST mode.) Cannot be done during outline operation, # that is in hook_doBodyAfterOop(). # Defaults: use underline, use closing hashes. LEVELS_ADS = {1:'=', 2:'-'} ADS_LEVELS = {'=':1, '-':2} def hook_makeOutline(VO, blines): """Return (tlines, bnodes, levels) for Body lines blines. blines is either Vim buffer object (Body) or list of buffer lines. """ Z = len(blines) tlines, bnodes, levels = [], [], [] tlines_add, bnodes_add, levels_add = tlines.append, bnodes.append, levels.append # trailing whitespace is always removed with rstrip() # # underline-style, overrides hashes-style: # head L1, blines[i] -- current line, title line, not blank # ------ L2, blines[i+1] -- any number of = or - only # # hashes-style: # ## head L1, blines[i] -- current line # abcde L2, blines[i+1] # # Set this once when headline with level 1 or 2 is encountered. # 0 or 1 -- False, use underline-style (default); 2 -- True, use hashes-style useHash = 0 # Set this once when headline with hashes is encountered. # 0 or 1 -- True, use closing hashes (default); 2 -- False, do not use closing hashes useCloseHash = 0 L2 = blines[0].rstrip() # first Body line isHead = False for i in xrange(Z): L1 = L2 j = i+1 if j < Z: L2 = blines[j].rstrip() else: L2 = '' if not L1: continue if L2 and (L2[0] in ADS_LEVELS) and not L2.lstrip(L2[0]): isHead = True lev = ADS_LEVELS[L2[0]] head = L1.strip() L2 = '' if not useHash: useHash = 1 elif L1.startswith('#'): isHead = True lev = len(L1) - len(L1.lstrip('#')) head = L1.strip('#').strip() if not useHash and lev < 3: useHash = 2 if not useCloseHash: if L1.endswith('#'): useCloseHash = 1 else: useCloseHash = 2 else: continue if isHead: isHead = False tline = ' %s|%s' %('. '*(lev-1), head) tlines_add(tline) bnodes_add(j) levels_add(lev) # don't clobber these when parsing clipboard during Paste # which is the only time blines is not Body if blines is VO.Body: VO.useHash = useHash == 2 VO.useCloseHash = useCloseHash < 2 return (tlines, bnodes, levels) #------ the rest is identical to voom_mode_pandoc.py ------ def hook_newHeadline(VO, level, blnum, tlnum): """Return (tree_head, bodyLines). tree_head is new headline string in Tree buffer (text after |). bodyLines is list of lines to insert in Body buffer. """ tree_head = 'NewHeadline' if level < 3 and not VO.useHash: bodyLines = [tree_head, LEVELS_ADS[level]*11, ''] else: lev = '#'*level if VO.useCloseHash: bodyLines = ['%s %s %s' %(lev, tree_head, lev), ''] else: bodyLines = ['%s %s' %(lev, tree_head), ''] # Add blank line when inserting after non-blank Body line. if VO.Body[blnum-1].strip(): bodyLines[0:0] = [''] return (tree_head, bodyLines) #def hook_changeLevBodyHead(VO, h, levDelta): # DO NOT CREATE THIS HOOK def hook_doBodyAfterOop(VO, oop, levDelta, blnum1, tlnum1, blnum2, tlnum2, blnumCut, tlnumCut): # this is instead of hook_changeLevBodyHead() # Based on reST mode function. Insert blank separator lines if missing, # even though they are not important for Markdown headlines. #print('oop=%s levDelta=%s blnum1=%s tlnum1=%s blnum2=%s tlnum2=%s tlnumCut=%s blnumCut=%s' % (oop, levDelta, blnum1, tlnum1, blnum2, tlnum2, tlnumCut, blnumCut)) Body = VO.Body Z = len(Body) bnodes, levels = VO.bnodes, VO.levels ENC = VO.enc # blnum1 blnum2 is first and last lnums of Body region pasted, inserted # during up/down, or promoted/demoted. if blnum1: assert blnum1 == bnodes[tlnum1-1] if tlnum2 < len(bnodes): assert blnum2 == bnodes[tlnum2]-1 else: assert blnum2 == Z # blnumCut is Body lnum after which a region was removed during 'cut', # 'up', 'down'. Need this to check if there is blank line between nodes # used to be separated by the cut/moved region. if blnumCut: if tlnumCut < len(bnodes): assert blnumCut == bnodes[tlnumCut]-1 else: assert blnumCut == Z # Total number of added lines minus number of deleted lines. b_delta = 0 ### After 'cut' or 'up': insert blank line if there is none # between the nodes used to be separated by the cut/moved region. if (oop=='cut' or oop=='up') and (0 < blnumCut < Z) and Body[blnumCut-1].strip(): Body[blnumCut:blnumCut] = [''] update_bnodes(VO, tlnumCut+1 ,1) b_delta+=1 if oop=='cut': return ### Make sure there is blank line after the last node in the region: # insert blank line after blnum2 if blnum2 is not blank, that is insert # blank line before bnode at tlnum2+1. if blnum2 < Z and Body[blnum2-1].strip(): Body[blnum2:blnum2] = [''] update_bnodes(VO, tlnum2+1 ,1) b_delta+=1 ### Change levels and/or formats of headlines in the affected region. # Always do this after Paste, even if level is unchanged -- format can # be different when pasting from other outlines. # Examine each headline, from bottom to top, and change level and/or format. # To change from hashes to underline-style: # strip hashes, strip whitespace; # insert underline. # To change from underline to hashes-style: # delete underline or change it to blank if it is followed by another underline # insert hashes. # Update bnodes after inserting or deleting a line. # hash-style underline-style (overrides hash-style) # # ## head L1 head L1 <--bnode Body[bln-1] # L2 ---- L2 Body[bln] # L3 L3 Body[bln+1] if levDelta or oop=='paste': for i in xrange(tlnum2, tlnum1-1, -1): # required level (VO.levels has been updated) lev = levels[i-1] # current level from which to change to lev lev_ = lev - levDelta # Body headline (bnode) and next line bln = bnodes[i-1] L1 = Body[bln-1].rstrip() if bln < len(Body): L2 = Body[bln].rstrip() else: L2 = '' # get the current headline format hasHash, hasCloseHash = True, VO.useCloseHash if L2 and (L2.lstrip('=')=='' or L2.lstrip('-')==''): hasHash = False else: if L1.endswith('#'): hasCloseHash = True else: hasCloseHash = False # get the desired headline format if oop=='paste': if lev > 2: useHash = True else: useHash = VO.useHash useCloseHash = VO.useCloseHash elif lev < 3 and lev_ < 3: useHash = hasHash useCloseHash = hasCloseHash elif lev > 2 and lev_ > 2: useHash = True useCloseHash = hasCloseHash elif lev < 3 and lev_ > 2: useHash = VO.useHash useCloseHash = VO.useCloseHash elif lev > 2 and lev_ < 3: useHash = True useCloseHash = hasCloseHash else: assert False #print('useHash=%s hasHash=%s useCloseHash=%s hasCloseHash=%s' %(useHash, hasHash, useCloseHash, hasCloseHash)) #print('%s %s' %(L1, L2)) # change headline level and/or format # underline-style unchanged, only adjust level of underline if not useHash and not hasHash: if not levDelta: continue Body[bln] = LEVELS_ADS[lev]*len(L2) # hashes-style unchanged, adjust level of hashes and add/remove closing hashes elif useHash and hasHash: # no format change, there are closing hashes if useCloseHash and hasCloseHash: if not levDelta: continue Body[bln-1] = '%s%s%s' %('#'*lev, L1.strip('#'), '#'*lev) # no format change, there are no closing hashes elif not useCloseHash and not hasCloseHash: if not levDelta: continue Body[bln-1] = '%s%s' %('#'*lev, L1.lstrip('#')) # add closing hashes elif useCloseHash and not hasCloseHash: Body[bln-1] = '%s%s %s' %('#'*lev, L1.strip('#').rstrip(), '#'*lev) # remove closing hashes elif not useCloseHash and hasCloseHash: Body[bln-1] = '%s%s' %('#'*lev, L1.strip('#').rstrip()) # insert underline, remove hashes elif not useHash and hasHash: L = L1.strip('#').strip() Body[bln-1] = L # insert underline Body[bln:bln] = [LEVELS_ADS[lev] * len_u(L, ENC)] update_bnodes(VO, i+1, 1) b_delta+=1 # remove underline, insert hashes elif useHash and not hasHash: if L1[0].isspace(): sp = '' else: sp = ' ' if useCloseHash: Body[bln-1] = '%s%s%s %s' %('#'*lev, sp, L1, '#'*lev) else: Body[bln-1] = '%s%s%s' %('#'*lev, sp, L1) # check if the next line after underline is another underline if bln+1 < len(Body): L3 = Body[bln+1].rstrip() else: L3 = '' #print('%s %s %s' %(L1, L2, L3)) # yes: do not delete underline, change it to a blank line if L3 and (L3.lstrip('=')=='' or L3.lstrip('-')==''): Body[bln] = '' # no: delete underline else: Body[bln:bln+1] = [] update_bnodes(VO, i+1, -1) b_delta-=1 ### Make sure first headline is preceded by a blank line. blnum1 = bnodes[tlnum1-1] if blnum1 > 1 and Body[blnum1-2].strip(): Body[blnum1-1:blnum1-1] = [''] update_bnodes(VO, tlnum1 ,1) b_delta+=1 ### After 'down' : insert blank line if there is none # between the nodes used to be separated by the moved region. if oop=='down' and (0 < blnumCut < Z) and Body[blnumCut-1].strip(): Body[blnumCut:blnumCut] = [''] update_bnodes(VO, tlnumCut+1 ,1) b_delta+=1 assert len(Body) == Z + b_delta def update_bnodes(VO, tlnum, delta): """Update VO.bnodes by adding/substracting delta to each bnode starting with bnode at tlnum and to the end. """ bnodes = VO.bnodes for i in xrange(tlnum, len(bnodes)+1): bnodes[i-1] += delta VOoM-5.3/autoload/voom/voom_vimplugin2657/voom_mode_org.py000066400000000000000000000035331305710164100235760ustar00rootroot00000000000000# File: voom_mode_org.py # Last Modified: 2017-01-07 # Description: VOoM -- two-pane outliner plugin for Python-enabled Vim # Website: http://www.vim.org/scripts/script.php?script_id=2657 # Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) # License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ """ VOoM markup mode for Emacs Org-mode headline format. See |voom-mode-org|, ../../../doc/voom.txt#*voom-mode-org* """ import sys if sys.version_info[0] > 2: xrange = range import re headline_match = re.compile(r'^(\*+)\s').match def hook_makeOutline(VO, blines): """Return (tlines, bnodes, levels) for Body lines blines. blines is either Vim buffer object (Body) or list of buffer lines. """ Z = len(blines) tlines, bnodes, levels = [], [], [] tlines_add, bnodes_add, levels_add = tlines.append, bnodes.append, levels.append for i in xrange(Z): if not blines[i].startswith('*'): continue bline = blines[i] m = headline_match(bline) if not m: continue lev = len(m.group(1)) head = bline[lev:].strip() tline = ' %s|%s' %('. '*(lev-1), head) tlines_add(tline) bnodes_add(i+1) levels_add(lev) return (tlines, bnodes, levels) def hook_newHeadline(VO, level, blnum, tlnum): """Return (tree_head, bodyLines). tree_head is new headline string in Tree buffer (text after |). bodyLines is list of lines to insert in Body buffer. """ tree_head = 'NewHeadline' bodyLines = ['%s %s' %('*'*level, tree_head), ''] return (tree_head, bodyLines) def hook_changeLevBodyHead(VO, h, levDelta): """Increase of decrease level number of Body headline by levDelta.""" if levDelta==0: return h m = headline_match(h) level = len(m.group(1)) return '%s%s' %('*'*(level+levDelta), h[m.end(1):]) VOoM-5.3/autoload/voom/voom_vimplugin2657/voom_mode_pandoc.py000066400000000000000000000313531305710164100242540ustar00rootroot00000000000000# File: voom_mode_pandoc.py # Last Modified: 2017-01-07 # Description: VOoM -- two-pane outliner plugin for Python-enabled Vim # Website: http://www.vim.org/scripts/script.php?script_id=2657 # Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) # License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ """ VOoM markup mode for Pandoc Markdown headers. See |voom-mode-pandoc|, ../../../doc/voom.txt#*voom-mode-pandoc* """ import sys if sys.version_info[0] > 2: xrange = range def len_u(s, enc): return len(s) else: def len_u(s, enc): return len(unicode(s, enc, 'replace')) ### NOTES # The code is identical to voom_mode_markdown.py except that the parser ignores # headlines that: # - are not preceded by a blank line, or another headline, or an end of fenced block # - are inside fenced code blocks. LEVELS_ADS = {1:'=', 2:'-'} ADS_LEVELS = {'=':1, '-':2} def hook_makeOutline(VO, blines): """Return (tlines, bnodes, levels) for Body lines blines. blines is either Vim buffer object (Body) or list of buffer lines. """ Z = len(blines) tlines, bnodes, levels = [], [], [] tlines_add, bnodes_add, levels_add = tlines.append, bnodes.append, levels.append # trailing whitespace is always removed with rstrip() # # underline-style, overrides hashes-style: # head L1, blines[i] -- current line, title line, not blank # ------ L2, blines[i+1] -- any number of = or - only # # hashes-style: # ## head L1, blines[i] -- current line # abcde L2, blines[i+1] # # Set this once when headline with level 1 or 2 is encountered. # 0 or 1 -- False, use underline-style (default); 2 -- True, use hashes-style useHash = 0 # Set this once when headline with hashes is encountered. # 0 or 1 -- True, use closing hashes (default); 2 -- False, do not use closing hashes useCloseHash = 0 # Keep track of fenced code blocks where headlines are ignored. isFenced = '' # Set True on lines after which a new headline is allowed: blank line, # headline, end-of-fenced-block. Also applies to start-of-fenced-block. ok = 1 L2 = blines[0].rstrip() # first Body line isHead = False for i in xrange(Z): L1 = L2 j = i+1 if j < Z: L2 = blines[j].rstrip() else: L2 = '' if not L1: ok = 1 continue # ignore headlines inside fenced code block if isFenced: if L1.startswith(isFenced) and L1.lstrip(isFenced[0])=='': isFenced = '' ok = 1 continue # Headline is allowed only after a blank line, another headline, # end-of-fenced block. Same for start-of-fenced-block. if not ok: continue # new fenced code block if L1.startswith('~~~') or L1.startswith('```'): ch = L1[0] isFenced = ch*(len(L1)-len(L1.lstrip(ch))) continue if L2 and (L2[0] in ADS_LEVELS) and not L2.lstrip(L2[0]): isHead = True lev = ADS_LEVELS[L2[0]] head = L1.strip() L2 = '' # this will set ok=1 on the next line (underline) if not useHash: useHash = 1 elif L1.startswith('#') and not L1.startswith('#. '): ok = 1 isHead = True lev = len(L1) - len(L1.lstrip('#')) head = L1.strip('#').strip() if not useHash and lev < 3: useHash = 2 if not useCloseHash: if L1.endswith('#'): useCloseHash = 1 else: useCloseHash = 2 else: ok = 0 continue if isHead: isHead = False tline = ' %s|%s' %('. '*(lev-1), head) tlines_add(tline) bnodes_add(j) levels_add(lev) # don't clobber these when parsing clipboard during Paste # which is the only time blines is not Body if blines is VO.Body: VO.useHash = useHash == 2 VO.useCloseHash = useCloseHash < 2 return (tlines, bnodes, levels) #------ the rest is identical to voom_mode_markdown.py ------ def hook_newHeadline(VO, level, blnum, tlnum): """Return (tree_head, bodyLines). tree_head is new headline string in Tree buffer (text after |). bodyLines is list of lines to insert in Body buffer. """ tree_head = 'NewHeadline' if level < 3 and not VO.useHash: bodyLines = [tree_head, LEVELS_ADS[level]*11, ''] else: lev = '#'*level if VO.useCloseHash: bodyLines = ['%s %s %s' %(lev, tree_head, lev), ''] else: bodyLines = ['%s %s' %(lev, tree_head), ''] # Add blank line when inserting after non-blank Body line. if VO.Body[blnum-1].strip(): bodyLines[0:0] = [''] return (tree_head, bodyLines) #def hook_changeLevBodyHead(VO, h, levDelta): # DO NOT CREATE THIS HOOK def hook_doBodyAfterOop(VO, oop, levDelta, blnum1, tlnum1, blnum2, tlnum2, blnumCut, tlnumCut): # this is instead of hook_changeLevBodyHead() # Based on reST mode function. Insert blank separator lines if missing, # even though they are not important for Markdown headlines. #print('oop=%s levDelta=%s blnum1=%s tlnum1=%s blnum2=%s tlnum2=%s tlnumCut=%s blnumCut=%s' % (oop, levDelta, blnum1, tlnum1, blnum2, tlnum2, tlnumCut, blnumCut)) Body = VO.Body Z = len(Body) bnodes, levels = VO.bnodes, VO.levels ENC = VO.enc # blnum1 blnum2 is first and last lnums of Body region pasted, inserted # during up/down, or promoted/demoted. if blnum1: assert blnum1 == bnodes[tlnum1-1] if tlnum2 < len(bnodes): assert blnum2 == bnodes[tlnum2]-1 else: assert blnum2 == Z # blnumCut is Body lnum after which a region was removed during 'cut', # 'up', 'down'. Need this to check if there is blank line between nodes # used to be separated by the cut/moved region. if blnumCut: if tlnumCut < len(bnodes): assert blnumCut == bnodes[tlnumCut]-1 else: assert blnumCut == Z # Total number of added lines minus number of deleted lines. b_delta = 0 ### After 'cut' or 'up': insert blank line if there is none # between the nodes used to be separated by the cut/moved region. if (oop=='cut' or oop=='up') and (0 < blnumCut < Z) and Body[blnumCut-1].strip(): Body[blnumCut:blnumCut] = [''] update_bnodes(VO, tlnumCut+1 ,1) b_delta+=1 if oop=='cut': return ### Make sure there is blank line after the last node in the region: # insert blank line after blnum2 if blnum2 is not blank, that is insert # blank line before bnode at tlnum2+1. if blnum2 < Z and Body[blnum2-1].strip(): Body[blnum2:blnum2] = [''] update_bnodes(VO, tlnum2+1 ,1) b_delta+=1 ### Change levels and/or formats of headlines in the affected region. # Always do this after Paste, even if level is unchanged -- format can # be different when pasting from other outlines. # Examine each headline, from bottom to top, and change level and/or format. # To change from hashes to underline-style: # strip hashes, strip whitespace; # insert underline. # To change from underline to hashes-style: # delete underline or change it to blank if it is followed by another underline # insert hashes. # Update bnodes after inserting or deleting a line. # hash-style underline-style (overrides hash-style) # # ## head L1 head L1 <--bnode Body[bln-1] # L2 ---- L2 Body[bln] # L3 L3 Body[bln+1] if levDelta or oop=='paste': for i in xrange(tlnum2, tlnum1-1, -1): # required level (VO.levels has been updated) lev = levels[i-1] # current level from which to change to lev lev_ = lev - levDelta # Body headline (bnode) and next line bln = bnodes[i-1] L1 = Body[bln-1].rstrip() if bln < len(Body): L2 = Body[bln].rstrip() else: L2 = '' # get the current headline format hasHash, hasCloseHash = True, VO.useCloseHash if L2 and (L2.lstrip('=')=='' or L2.lstrip('-')==''): hasHash = False else: if L1.endswith('#'): hasCloseHash = True else: hasCloseHash = False # get the desired headline format if oop=='paste': if lev > 2: useHash = True else: useHash = VO.useHash useCloseHash = VO.useCloseHash elif lev < 3 and lev_ < 3: useHash = hasHash useCloseHash = hasCloseHash elif lev > 2 and lev_ > 2: useHash = True useCloseHash = hasCloseHash elif lev < 3 and lev_ > 2: useHash = VO.useHash useCloseHash = VO.useCloseHash elif lev > 2 and lev_ < 3: useHash = True useCloseHash = hasCloseHash else: assert False #print('useHash=%s hasHash=%s useCloseHash=%s hasCloseHash=%s' %(useHash, hasHash, useCloseHash, hasCloseHash)) #print('%s %s' %(L1, L2)) # change headline level and/or format # underline-style unchanged, only adjust level of underline if not useHash and not hasHash: if not levDelta: continue Body[bln] = LEVELS_ADS[lev]*len(L2) # hashes-style unchanged, adjust level of hashes and add/remove closing hashes elif useHash and hasHash: # no format change, there are closing hashes if useCloseHash and hasCloseHash: if not levDelta: continue Body[bln-1] = '%s%s%s' %('#'*lev, L1.strip('#'), '#'*lev) # no format change, there are no closing hashes elif not useCloseHash and not hasCloseHash: if not levDelta: continue Body[bln-1] = '%s%s' %('#'*lev, L1.lstrip('#')) # add closing hashes elif useCloseHash and not hasCloseHash: Body[bln-1] = '%s%s %s' %('#'*lev, L1.strip('#').rstrip(), '#'*lev) # remove closing hashes elif not useCloseHash and hasCloseHash: Body[bln-1] = '%s%s' %('#'*lev, L1.strip('#').rstrip()) # insert underline, remove hashes elif not useHash and hasHash: L = L1.strip('#').strip() Body[bln-1] = L # insert underline Body[bln:bln] = [LEVELS_ADS[lev] * len_u(L, ENC)] update_bnodes(VO, i+1, 1) b_delta+=1 # remove underline, insert hashes elif useHash and not hasHash: if L1[0].isspace(): sp = '' else: sp = ' ' if useCloseHash: Body[bln-1] = '%s%s%s %s' %('#'*lev, sp, L1, '#'*lev) else: Body[bln-1] = '%s%s%s' %('#'*lev, sp, L1) # check if the next line after underline is another underline if bln+1 < len(Body): L3 = Body[bln+1].rstrip() else: L3 = '' #print('%s %s %s' %(L1, L2, L3)) # yes: do not delete underline, change it to a blank line if L3 and (L3.lstrip('=')=='' or L3.lstrip('-')==''): Body[bln] = '' # no: delete underline else: Body[bln:bln+1] = [] update_bnodes(VO, i+1, -1) b_delta-=1 ### Make sure first headline is preceded by a blank line. blnum1 = bnodes[tlnum1-1] if blnum1 > 1 and Body[blnum1-2].strip(): Body[blnum1-1:blnum1-1] = [''] update_bnodes(VO, tlnum1 ,1) b_delta+=1 ### After 'down' : insert blank line if there is none # between the nodes used to be separated by the moved region. if oop=='down' and (0 < blnumCut < Z) and Body[blnumCut-1].strip(): Body[blnumCut:blnumCut] = [''] update_bnodes(VO, tlnumCut+1 ,1) b_delta+=1 assert len(Body) == Z + b_delta def update_bnodes(VO, tlnum, delta): """Update VO.bnodes by adding/substracting delta to each bnode starting with bnode at tlnum and to the end. """ bnodes = VO.bnodes for i in xrange(tlnum, len(bnodes)+1): bnodes[i-1] += delta VOoM-5.3/autoload/voom/voom_vimplugin2657/voom_mode_paragraphBlank.py000066400000000000000000000120141305710164100257160ustar00rootroot00000000000000# File: voom_mode_paragraphBlank.py # Last Modified: 2017-01-07 # Description: VOoM -- two-pane outliner plugin for Python-enabled Vim # Website: http://www.vim.org/scripts/script.php?script_id=2657 # Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) # License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ """ VOoM markup mode for paragraphs separated by blank lines. The first line of each paragraph is level 1 headline. That is the first non-blank line and any non-blank line preceded by a blank line is a headline. See |voom-mode-paragraphBlank|, ../../../doc/voom.txt#*voom-mode-paragraphBlank* Everything is at level 1. Levels >1 are not possible. There are must be a blank line after the last paragraph, that is end-of-file. Otherwise there are will be errors when the last paragraph is moved. """ import sys if sys.version_info[0] > 2: xrange = range # Disable unsupported outline operations: special node marks, insert new headline as child, move right. MTYPE = 2 def hook_makeOutline(VO, blines): """Return (tlines, bnodes, levels) for Body lines blines. blines is either Vim buffer object (Body) or list of buffer lines. """ # A line is headline level 1 if it is: preceded by a blank line (or is # first buffer line) and is non-blank. Z = len(blines) tlines, bnodes, levels = [], [], [] tlines_add, bnodes_add, levels_add = tlines.append, bnodes.append, levels.append bline_ = '' for i in xrange(Z): bline = blines[i].strip() if bline_ or not bline: bline_ = bline continue bline_ = bline tlines_add(' |%s' %bline) bnodes_add(i+1) levels_add(1) return (tlines, bnodes, levels) def hook_newHeadline(VO, level, blnum, tlnum): """Return (tree_head, bodyLines). tree_head is new headline string in Tree buffer (text after |). bodyLines is list of lines to insert in Body buffer. """ # Add blank line when inserting after non-blank Body line. if VO.Body[blnum-1].strip(): return ('NewHeadline', ['', 'NewHeadline', '']) else: return ('NewHeadline', ['NewHeadline', '']) ### DO NOT DEFINE THIS HOOK -- level never changes, it is always 1 #def hook_changeLevBodyHead(VO, h, levDelta): # """Increase of decrease level number of Body headline by levDelta.""" # return h # This is needed to insert blank line missing from end-of-file. Code is from rest mode. def hook_doBodyAfterOop(VO, oop, levDelta, blnum1, tlnum1, blnum2, tlnum2, blnumCut, tlnumCut): # this is instead of hook_changeLevBodyHead() #print('oop=%s levDelta=%s blnum1=%s tlnum1=%s blnum2=%s tlnum2=%s tlnumCut=%s blnumCut=%s' % (oop, levDelta, blnum1, tlnum1, blnum2, tlnum2, tlnumCut, blnumCut)) Body = VO.Body Z = len(Body) bnodes = VO.bnodes # blnum1 blnum2 is first and last lnums of Body region pasted, inserted # during up/down, or promoted/demoted. if blnum1: assert blnum1 == bnodes[tlnum1-1] if tlnum2 < len(bnodes): assert blnum2 == bnodes[tlnum2]-1 else: assert blnum2 == Z # blnumCut is Body lnum after which a region was removed during 'cut', # 'up', 'down'. We need to check if there is blank line between nodes # used to be separated by the cut/moved region to prevent headline loss. if blnumCut: if tlnumCut < len(bnodes): assert blnumCut == bnodes[tlnumCut]-1 else: assert blnumCut == Z # Total number of added lines minus number of deleted lines. b_delta = 0 # ### After 'cut' or 'up': insert blank line if there is none # # between the nodes used to be separated by the cut/moved region. # if (oop=='cut' or oop=='up') and (0 < blnumCut < Z) and Body[blnumCut-1].strip(): # Body[blnumCut:blnumCut] = [''] # update_bnodes(VO, tlnumCut+1 ,1) # b_delta+=1 if oop=='cut': return ### Prevent loss of headline after last node in the region: # insert blank line after blnum2 if blnum2 is not blank, that is insert # blank line before bnode at tlnum2+1. if blnum2 < Z and Body[blnum2-1].strip(): Body[blnum2:blnum2] = [''] update_bnodes(VO, tlnum2+1 ,1) b_delta+=1 ### Prevent loss of first headline: make sure it is preceded by a blank line blnum1 = bnodes[tlnum1-1] if blnum1 > 1 and Body[blnum1-2].strip(): Body[blnum1-1:blnum1-1] = [''] update_bnodes(VO, tlnum1 ,1) b_delta+=1 # ### After 'down' : insert blank line if there is none # # between the nodes used to be separated by the moved region. # if oop=='down' and (0 < blnumCut < Z) and Body[blnumCut-1].strip(): # Body[blnumCut:blnumCut] = [''] # update_bnodes(VO, tlnumCut+1 ,1) # b_delta+=1 assert len(Body) == Z + b_delta def update_bnodes(VO, tlnum, delta): """Update VO.bnodes by adding/substracting delta to each bnode starting with bnode at tlnum and to the end. """ bnodes = VO.bnodes for i in xrange(tlnum, len(bnodes)+1): bnodes[i-1] += delta VOoM-5.3/autoload/voom/voom_vimplugin2657/voom_mode_paragraphIndent.py000066400000000000000000000051011305710164100261070ustar00rootroot00000000000000# File: voom_mode_paragraphIndent.py # Last Modified: 2017-01-07 # Description: VOoM -- two-pane outliner plugin for Python-enabled Vim # Website: http://www.vim.org/scripts/script.php?script_id=2657 # Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) # License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ """ VOoM markup mode for paragraphs identified by indented lines. Any non-blank line that starts with a space or tab is a headline. Everything is at level 1. Levels >1 are not possible. See |voom-mode-paragraphIndent|, ../../../doc/voom.txt#*voom-mode-paragraphIndent* """ import sys if sys.version_info[0] > 2: xrange = range # Disable unsupported outline operations: special node marks, insert new headline as child, move right. MTYPE = 2 whitespace = ('\t', ' ') def hook_makeOutline(VO, blines): """Return (tlines, bnodes, levels) for Body lines blines. blines is either Vim buffer object (Body) or list of buffer lines. """ # every line that doesn't start with a space or tab is level 1 headline Z = len(blines) tlines, bnodes, levels = [], [], [] tlines_add, bnodes_add, levels_add = tlines.append, bnodes.append, levels.append for i in xrange(Z): bline = blines[i] if not bline or not (bline[0] in whitespace): # THE ONLY DIFFERENCE FROM voom_mode_paragraphNoIndent.py continue bline = bline.strip() if not bline: continue tlines_add(' |%s' %bline) bnodes_add(i+1) levels_add(1) return (tlines, bnodes, levels) def hook_newHeadline(VO, level, blnum, tlnum): """Return (tree_head, bodyLines). tree_head is new headline string in Tree buffer (text after |). bodyLines is list of lines to insert in Body buffer. """ # inserting after another headline: use indent of previous body headline if tlnum > 1: bheadline = VO.Body[VO.bnodes[tlnum-1]-1] # previous Body headline idx = len(bheadline) - len(bheadline.lstrip()) indent = bheadline[: idx] # inserting as first headline and there are other headlines: use indent of next headline elif len(VO.bnodes) > 1: bheadline = VO.Body[VO.bnodes[tlnum]-1] # next Body headline idx = len(bheadline) - len(bheadline.lstrip()) indent = bheadline[: idx] else: indent = ' ' return ('NewHeadline', ['%sNewHeadline' %indent]) ### DO NOT DEFINE THIS HOOK -- level never changes, it is always 1 #def hook_changeLevBodyHead(VO, h, levDelta): # """Increase of decrease level number of Body headline by levDelta.""" # return h VOoM-5.3/autoload/voom/voom_vimplugin2657/voom_mode_paragraphNoIndent.py000066400000000000000000000040121305710164100264040ustar00rootroot00000000000000# File: voom_mode_paragraphNoIndent.py # Last Modified: 2017-01-07 # Description: VOoM -- two-pane outliner plugin for Python-enabled Vim # Website: http://www.vim.org/scripts/script.php?script_id=2657 # Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) # License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ """ VOoM markup mode for paragraphs identified by non-indented lines. Any line that starts with a character other than space or tab is a headline. Everything is at level 1. Levels >1 are not possible. See |voom-mode-paragraphNoIndent|, ../../../doc/voom.txt#*voom-mode-paragraphNoIndent* """ import sys if sys.version_info[0] > 2: xrange = range # Disable unsupported outline operations: special node marks, insert new headline as child, move right. MTYPE = 2 whitespace = ('\t', ' ') def hook_makeOutline(VO, blines): """Return (tlines, bnodes, levels) for Body lines blines. blines is either Vim buffer object (Body) or list of buffer lines. """ # every line that doesn't start with a space or tab is level 1 headline Z = len(blines) tlines, bnodes, levels = [], [], [] tlines_add, bnodes_add, levels_add = tlines.append, bnodes.append, levels.append for i in xrange(Z): bline = blines[i] if not bline or bline[0] in whitespace: # THE ONLY DIFFERENCE FROM voom_mode_paragraphIndent.py continue bline = bline.strip() if not bline: continue tlines_add(' |%s' %bline) bnodes_add(i+1) levels_add(1) return (tlines, bnodes, levels) def hook_newHeadline(VO, level, blnum, tlnum): """Return (tree_head, bodyLines). tree_head is new headline string in Tree buffer (text after |). bodyLines is list of lines to insert in Body buffer. """ return ('NewHeadline', ['NewHeadline']) ### DO NOT DEFINE THIS HOOK -- level never changes, it is always 1 #def hook_changeLevBodyHead(VO, h, levDelta): # """Increase of decrease level number of Body headline by levDelta.""" # return h VOoM-5.3/autoload/voom/voom_vimplugin2657/voom_mode_python.py000066400000000000000000000217521305710164100243330ustar00rootroot00000000000000# File: voom_mode_python.py # Last Modified: 2017-01-07 # Description: VOoM -- two-pane outliner plugin for Python-enabled Vim # Website: http://www.vim.org/scripts/script.php?script_id=2657 # Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) # License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ """ VOoM markup mode for Python code. See |voom-mode-python|, ../../../doc/voom.txt#*voom-mode-python* """ import sys if sys.version_info[0] > 2: xrange = range import token, tokenize import traceback import vim def hook_makeOutline(VO, blines): """Return (tlines, bnodes, levels) for Body lines blines. blines is either Vim buffer object (Body) or list of buffer lines. """ Z = len(blines) tlines, bnodes, levels = [], [], [] tlines_add, bnodes_add, levels_add = tlines.append, bnodes.append, levels.append #ignore_lnums, func_lnums = get_lnums_from_tokenize(blines) try: ignore_lnums, func_lnums = get_lnums_from_tokenize(blines) except (IndentationError, tokenize.TokenError): vim.command("call voom#ErrorMsg('VOoM: EXCEPTION WHILE PARSING PYTHON OUTLINE')") # DO NOT print to sys.stderr -- triggers Vim error when default stderr (no PyLog) #traceback.print_exc() --this goes to sys.stderr #print traceback.format_exc() --ok but no highlighting lines = traceback.format_exc().replace("'","''").split('\n') for ln in lines: vim.command("call voom#ErrorMsg('%s')" %ln) return (['= |!!!ERROR: OUTLINE IS INVALID'], [1], [1]) isHead = False # True if current line is a headline indents = [0,] # indents of previous levels funcLevels = [] # levels of previous def or class indentError = '' # inconsistent indent isDecor = 0 # keeps track of decorators, set to lnum of the first decorator X = ' ' # char in Tree's column 2 (marks) for i in xrange(Z): bnode = i + 1 if bnode in ignore_lnums: continue bline = blines[i] bline_s = bline.strip() if not bline_s: continue if bline_s.startswith('#'): # ignore comment lines consisting only of #, -, =, spaces, tabs (separators, pretty headers) if not bline_s.lstrip('# \t-='): continue isComment = True else: isComment = False bline_ls = bline.lstrip() # compute indent and level indent = len(bline) - len(bline_ls) if indent > indents[-1]: indents.append(indent) elif indent < indents[-1]: while indents and (indents[-1] > indent): indents.pop() if indents[-1]==indent: indentError = '' else: indentError = '!!! ' lev = len(indents) # First line after the end of a class or def block. if funcLevels and lev <= funcLevels[-1]: isHead = True while funcLevels and funcLevels[-1] >= lev: funcLevels.pop() # First line of a class or def block. if bnode in func_lnums: isHead = True if isDecor: bnode = isDecor isDecor = 0 X = 'd' if not funcLevels or (lev > funcLevels[-1]): funcLevels.append(lev) # Line after a decorator. Not a def or class. elif isDecor: # ingore valid lines between the first decorator and function/class if bline_s.startswith('@') or isComment or not bline_s: isHead = False continue # Invalid line after a decorator (should be syntax error): anything # other than another decorator, comment, blank line, def/class. # If it looks like a headline, let it be a headline. else: isDecor = 0 # Decorator line (the first one if a group of several). elif bline_s.startswith('@'): isDecor = bnode isHead = False continue # Special comment line (unconditional headline). Not a separator or pretty header line. elif isComment: if bline_s.startswith('###') or bline_s.startswith('#--') or bline_s.startswith('#=='): isHead = True if isHead: ########################################## # Take care of pretty headers like this. # ########################################## if isComment: # add preceding lines to the current node if they consist only of #, =, -, whitespace while bnode > 1: bline_p = blines[bnode-2].lstrip() if not bline_p.startswith('#') or bline_p.lstrip('# \t-='): break else: bnode -= 1 # the end isHead = False tline = ' %s%s|%s%s' %(X, '. '*(lev-1), indentError, bline_s) X = ' ' tlines_add(tline) bnodes_add(bnode) levels_add(lev) return (tlines, bnodes, levels) class BLines: """Wrapper around Vim buffer object or list of Body lines to provide readline() method for use with tokenize.generate_tokens(). """ def __init__(self, blines): self.blines = blines self.size = len(blines) self.idx = -1 def readline(self): self.idx += 1 if self.idx == self.size: return '' return "%s\n" %self.blines[self.idx] ### toktypes of tokens STRING = token.STRING NAME = token.NAME NEWLINE = token.NEWLINE def get_lnums_from_tokenize(blines): """Return dicts. Keys are Body lnums. The main purpose is to get list of lnums to ignore: multi-line strings and expressions. """ # lnums to ignore: multi-line strings and expressions other than the first line ignore_lnums = {} # lnums of 'class' and 'def' tokens func_lnums = {} inName = False for tok in tokenize.generate_tokens(BLines(blines).readline): toktype, toktext, (srow, scol), (erow, ecol), line = tok #print('token.tok_name[toktype]=%s tok=%s' %(token.tok_name[toktype], tok)) if toktype == NAME: if not inName: inName = True srow_name = srow if toktext in ('def','class'): func_lnums[srow] = toktext elif toktype == NEWLINE and inName: inName = False if srow_name != erow: for i in xrange(srow_name+1, erow+1): ignore_lnums[i] = 0 elif toktype == STRING: if srow != erow: for i in xrange(srow+1, erow+1): ignore_lnums[i] = 0 return (ignore_lnums, func_lnums) def get_body_indent(body): """Return string used for indenting Body lines.""" et = int(vim.eval("getbufvar(%s,'&et')" %body)) if et: ts = int(vim.eval("getbufvar(%s,'&ts')" %body)) return ' '*ts else: return '\t' def hook_newHeadline(VO, level, blnum, tlnum): """Return (tree_head, bodyLines). tree_head is new headline string in Tree buffer (text after |). bodyLines is list of lines to insert in Body buffer. """ tree_head = '### NewHeadline' indent = get_body_indent(VO.body) body_head = '%s%s' %(indent*(level-1), tree_head) return (tree_head, [body_head]) #def hook_changeLevBodyHead(VO, h, levDelta): #"""Increase of decrease level number of Body headline by levDelta.""" #if levDelta==0: return h def hook_doBodyAfterOop(VO, oop, levDelta, blnum1, tlnum1, blnum2, tlnum2, blnumCut, tlnumCut): # this is instead of hook_changeLevBodyHead() #print('oop=%s levDelta=%s blnum1=%s tlnum1=%s blnum2=%s tlnum2=%s tlnumCut=%s blnumCut=%s' % (oop, levDelta, blnum1, tlnum1, blnum2, tlnum2, tlnumCut, blnumCut)) Body = VO.Body Z = len(Body) ind = get_body_indent(VO.body) # levDelta is wrong when pasting because hook_makeOutline() looks at relative indent # determine level of pasted region from indent of its first line if oop=='paste': bline1 = Body[blnum1-1] lev = int((len(bline1) - len(bline1.lstrip())) / len(ind)) + 1 levDelta = VO.levels[tlnum1-1] - lev if not levDelta: return indent = abs(levDelta) * ind #--- copied from voom_mode_thevimoutliner.py ----------------------------- if blnum1: assert blnum1 == VO.bnodes[tlnum1-1] if tlnum2 < len(VO.bnodes): assert blnum2 == VO.bnodes[tlnum2]-1 else: assert blnum2 == Z # dedent (if possible) or indent every non-blank line in Body region blnum1,blnum2 blines = [] for i in xrange(blnum1-1,blnum2): line = Body[i] if not line.strip(): blines.append(line) continue if levDelta > 0: line = '%s%s' %(indent,line) elif levDelta < 0 and line.startswith(indent): line = line[len(indent):] blines.append(line) # replace Body region Body[blnum1-1:blnum2] = blines assert len(Body)==Z VOoM-5.3/autoload/voom/voom_vimplugin2657/voom_mode_rest.py000066400000000000000000000325501305710164100237650ustar00rootroot00000000000000# File: voom_mode_rest.py # Last Modified: 2016-08-20 # Description: VOoM -- two-pane outliner plugin for Python-enabled Vim # Website: http://www.vim.org/scripts/script.php?script_id=2657 # Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) # License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ """ VOoM markup mode for reStructuredText. See |voom-mode-rest|, ../../../doc/voom.txt#*voom-mode-rest* http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#sections The following are all valid section title adornment characters: ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~ Some characters are more suitable than others. The following are recommended: = - ` : . ' " ~ ^ _ * + # http://docs.python.org/documenting/rest.html#sections Python recommended styles: ## ** = - ^ " """ import sys if sys.version_info[0] > 2: xrange = range def len_u(s, enc): return len(s) else: def len_u(s, enc): return len(unicode(s, enc, 'replace')) # All valid section title adornment characters. AD_CHARS = """ ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~ """ AD_CHARS = AD_CHARS.split() # List of adornment styles, in order of preference. # Adornment style (ad) is a char or double char: '=', '==', '-', '--', '*', etc. # Char is adornment char, double if there is overline. AD_STYLES = """ == -- = - * " ' ` ~ : ^ + # . _ """ AD_STYLES = AD_STYLES.split() # add all other possible styles to AD_STYLES d = {}.fromkeys(AD_STYLES) for c in AD_CHARS: if not c*2 in d: AD_STYLES.append(c*2) if not c in d: AD_STYLES.append(c) assert len(AD_STYLES)==64 # convert AD_CHARS to dict for faster lookups AD_CHARS = {}.fromkeys(AD_CHARS) def hook_makeOutline(VO, blines): """Return (tlines, bnodes, levels) for Body lines blines. blines is either Vim buffer object (Body) or list of buffer lines. """ Z = len(blines) tlines, bnodes, levels = [], [], [] tlines_add, bnodes_add, levels_add = tlines.append, bnodes.append, levels.append ENC = VO.enc # {adornment style: level, ...} # Level indicates when the first instance of this style was found. ads_levels = {} # diagram of Body lines when a headline is detected # trailing whitespace always removed with rstrip() # a b c # ------ L3, blines[i-2] -- an overline or a blank line # head L2, blines[i-1] -- title line, not blank, <= than underline, can be inset only if overline # ------ L1, blines[i] -- current line, always an underline # x y z L1, L2, L3 = '','','' # An underline can be only the 2nd or 3rd line of a block after a blank # line or previous underline. Thus, index of the next underline must be ok or ok+1. ok = 1 isHead = False for i in xrange(Z): L2, L3 = L1, L2 L1 = blines[i].rstrip() if not L1: ok = i+2 continue if i < ok or not L2: continue # At this point both the current line (underline) and previous line (title) are not blank. # current line must be an underline if not ((L1[0] in AD_CHARS) and L1.lstrip(L1[0])==''): if i > ok: ok = Z continue # underline must be as long as headline text if len(L1) < len_u(L2, ENC): if i > ok: ok = Z continue head = L2.lstrip() # headline text cannot look like an underline unless it's shorter than underline if (head[0] in AD_CHARS) and head.lstrip(head[0])=='' and len(head)==len(L1): if i > ok: ok = Z continue # there is no overline; L3 must be blank line; L2 must be not inset if not L3 and len(L2)==len(head): #if len(L1) < len_u(L2, ENC): continue isHead = True ad = L1[0] bnode = i # there is overline -- bnode is lnum of overline! elif L3==L1: #if len(L1) < len_u(L2, ENC): continue isHead = True ad = L1[0]*2 bnode = i-1 else: if i > ok: ok = Z continue if isHead: if not ad in ads_levels: ads_levels[ad] = len(ads_levels)+1 lev = ads_levels[ad] isHead = False L1, L2, L3 = '','','' ok = i+2 tline = ' %s|%s' %('. '*(lev-1), head) tlines_add(tline) bnodes_add(bnode) levels_add(lev) # save ads_levels for outline operations # don't clobber VO.ads_levels when parsing clipboard during Paste # which is the only time blines is not Body if blines is VO.Body: VO.ads_levels = ads_levels return (tlines, bnodes, levels) def hook_newHeadline(VO, level, blnum, tlnum): """Return (tree_head, bodyLines). tree_head is new headline string in Tree buffer (text after |). bodyLines is list of lines to insert in Body buffer. """ tree_head = 'NewHeadline' ads_levels = VO.ads_levels levels_ads = dict([[v,k] for k,v in ads_levels.items()]) if level in levels_ads: ad = levels_ads[level] else: ad = get_new_ad(levels_ads, ads_levels, level) if len(ad)==1: bodyLines = [tree_head, ad*11, ''] elif len(ad)==2: ad = ad[0] bodyLines = [ad*11, tree_head, ad*11, ''] # Add blank line when inserting after non-blank Body line. if VO.Body[blnum-1].strip(): bodyLines[0:0] = [''] return (tree_head, bodyLines) #def hook_changeLevBodyHead(VO, h, levDelta): # DO NOT CREATE THIS HOOK def hook_doBodyAfterOop(VO, oop, levDelta, blnum1, tlnum1, blnum2, tlnum2, blnumCut, tlnumCut): # this is instead of hook_changeLevBodyHead() #print('oop=%s levDelta=%s blnum1=%s tlnum1=%s blnum2=%s tlnum2=%s tlnumCut=%s blnumCut=%s' % (oop, levDelta, blnum1, tlnum1, blnum2, tlnum2, tlnumCut, blnumCut)) Body = VO.Body Z = len(Body) bnodes, levels = VO.bnodes, VO.levels ENC = VO.enc # blnum1 blnum2 is first and last lnums of Body region pasted, inserted # during up/down, or promoted/demoted. if blnum1: assert blnum1 == bnodes[tlnum1-1] if tlnum2 < len(bnodes): assert blnum2 == bnodes[tlnum2]-1 else: assert blnum2 == Z # blnumCut is Body lnum after which a region was removed during 'cut', # 'up', 'down'. We need to check if there is blank line between nodes # used to be separated by the cut/moved region to prevent headline loss. if blnumCut: if tlnumCut < len(bnodes): assert blnumCut == bnodes[tlnumCut]-1 else: assert blnumCut == Z # Total number of added lines minus number of deleted lines. b_delta = 0 ### After 'cut' or 'up': insert blank line if there is none # between the nodes used to be separated by the cut/moved region. if (oop=='cut' or oop=='up') and (0 < blnumCut < Z) and Body[blnumCut-1].strip(): Body[blnumCut:blnumCut] = [''] update_bnodes(VO, tlnumCut+1 ,1) b_delta+=1 if oop=='cut': return ### Prevent loss of headline after last node in the region: # insert blank line after blnum2 if blnum2 is not blank, that is insert # blank line before bnode at tlnum2+1. if blnum2 < Z and Body[blnum2-1].strip(): Body[blnum2:blnum2] = [''] update_bnodes(VO, tlnum2+1 ,1) b_delta+=1 ### Change levels and/or styles of headlines in the affected region. # Always do this after Paste, even if level is unchanged -- adornments can # be different when pasting from other outlines. # Examine each headline, from bottom to top, and change adornment style. # To change from underline to overline style: # insert overline. # To change from overline to underline style: # delete overline if there is blank before it; # otherwise change overline to blank line; # remove inset from headline text. # Update bnodes after inserting or deleting a line. if levDelta or oop=='paste': ads_levels = VO.ads_levels levels_ads = dict([[v,k] for k,v in ads_levels.items()]) # Add adornment styles for new levels. Can't do this in the main loop # because it goes backwards and thus will add styles in reverse order. for i in xrange(tlnum1, tlnum2+1): lev = levels[i-1] if not lev in levels_ads: ad = get_new_ad(levels_ads, ads_levels, lev) levels_ads[lev] = ad ads_levels[ad] = lev for i in xrange(tlnum2, tlnum1-1, -1): # required level (VO.levels has been updated) lev = levels[i-1] # required adornment style ad = levels_ads[lev] # deduce current adornment style bln = bnodes[i-1] L1 = Body[bln-1].rstrip() L2 = Body[bln].rstrip() if bln+1 < len(Body): L3 = Body[bln+1].rstrip() else: L3 = '' ad_ = deduce_ad_style(L1,L2,L3,ENC) # change adornment style # see deduce_ad_style() for diagram if ad_==ad: continue elif len(ad_)==1 and len(ad)==1: Body[bln] = ad*len(L2) elif len(ad_)==2 and len(ad)==2: Body[bln-1] = ad[0]*len(L1) Body[bln+1] = ad[0]*len(L3) elif len(ad_)==1 and len(ad)==2: # change underline if different if not ad_ == ad[0]: Body[bln] = ad[0]*len(L2) # insert overline; current bnode doesn't change Body[bln-1:bln-1] = [ad[0]*len(L2)] update_bnodes(VO, i+1, 1) b_delta+=1 elif len(ad_)==2 and len(ad)==1: # change underline if different if not ad_[0] == ad: Body[bln+1] = ad*len(L3) # remove headline inset if any if not len(L2) == len(L2.lstrip()): Body[bln] = L2.lstrip() # check if line before overline is blank if bln >1: L0 = Body[bln-2].rstrip() else: L0 = '' # there is blank before overline # delete overline; current bnode doesn't change if not L0: Body[bln-1:bln] = [] update_bnodes(VO, i+1, -1) b_delta-=1 # there is no blank before overline # change overline to blank; only current bnode needs updating else: Body[bln-1] = '' bnodes[i-1]+=1 ### Prevent loss of first headline: make sure it is preceded by a blank line blnum1 = bnodes[tlnum1-1] if blnum1 > 1 and Body[blnum1-2].strip(): Body[blnum1-1:blnum1-1] = [''] update_bnodes(VO, tlnum1 ,1) b_delta+=1 ### After 'down' : insert blank line if there is none # between the nodes used to be separated by the moved region. if oop=='down' and (0 < blnumCut < Z) and Body[blnumCut-1].strip(): Body[blnumCut:blnumCut] = [''] update_bnodes(VO, tlnumCut+1 ,1) b_delta+=1 assert len(Body) == Z + b_delta def update_bnodes(VO, tlnum, delta): """Update VO.bnodes by adding/substracting delta to each bnode starting with bnode at tlnum and to the end. """ bnodes = VO.bnodes for i in xrange(tlnum, len(bnodes)+1): bnodes[i-1] += delta def get_new_ad(levels_ads, ads_levels, level): """Return adornment style for new level, that is level missing from levels_ads and ads_levels. """ for ad in AD_STYLES: if not ad in ads_levels: return ad # all 64 adornment styles are in use, return style for level 64 assert len(levels_ads)==64 return levels_ads[64] def deduce_ad_style(L1,L2,L3,ENC): """Deduce adornment style given first 3 lines of Body node. 1st line is bnode line. Lines must be rstripped. L1 and L2 are not blank. """ # '--' style '-' style # # L0 L0 Body[bln-2] # ---- L1 head L1 <--bnode Body[bln-1] # head L2 ---- L2 Body[bln] # ---- L3 text L3 Body[bln+1] # bnode is headline text, L2 is underline if (L2[0] in AD_CHARS) and L2.lstrip(L2[0])=='' and (len(L2) >= len_u(L1, ENC)): ad = L2[0] # bnode is overline elif L1==L3 and (L1[0] in AD_CHARS) and L1.lstrip(L1[0])=='' and (len(L1) >= len_u(L2, ENC)): ad = 2*L1[0] else: print(L1) print(L2) print(L3) print(ENC) assert None return ad def test_deduce_ad_style(VO): """ A test to verify deduce_ad_style(). Execute from Vim :py _VOoM2657.VOOMS[1].mModule.test_deduce_ad_style(_VOoM2657.VOOMS[1]) """ bnodes, levels, Body = VO.bnodes, VO.levels, VO.Body ads_levels = VO.ads_levels levels_ads = dict([[v,k] for k,v in ads_levels.items()]) ENC = VO.enc for i in xrange(2, len(bnodes)+1): bln = bnodes[i-1] L1 = Body[bln-1].rstrip() L2 = Body[bln].rstrip() if bln+1 < len(Body): L3 = Body[bln+1].rstrip() else: L3 = '' ad = deduce_ad_style(L1,L2,L3,ENC) lev = levels[i-1] print('%s %s %s' %(i, ad, levels_ads[lev])) assert ad == levels_ads[lev] VOoM-5.3/autoload/voom/voom_vimplugin2657/voom_mode_taskpaper.py000066400000000000000000000057561305710164100250120ustar00rootroot00000000000000# File: voom_mode_taskpaper.py # Last Modified: 2017-01-07 # Description: VOoM -- two-pane outliner plugin for Python-enabled Vim # Website: http://www.vim.org/scripts/script.php?script_id=2657 # Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) # License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ """ VOoM markup mode for TaskPaper format. See |voom-mode-taskpaper|, ../../../doc/voom.txt#*voom-mode-taskpaper* """ import sys if sys.version_info[0] > 2: xrange = range import re # match for Project line, as in syntax/taskpaper.vim project_match = re.compile(r'^.+:(\s+@[^ \t(]+(\([^)]*\))?)*$').match def hook_makeOutline(VO, blines): """Return (tlines, bnodes, levels) for Body lines blines. blines is either Vim buffer object (Body) or list of buffer lines. """ Z = len(blines) tlines, bnodes, levels = [], [], [] tlines_add, bnodes_add, levels_add = tlines.append, bnodes.append, levels.append for i in xrange(Z): bline = blines[i] h = bline.lstrip('\t') # line is a Task if h.startswith('- '): head = h[2:] mark = ' ' # line is a Project # the "in" test is for efficiency sake in case there is lots of Notes elif h.endswith(':') or (':' in h and project_match(h)): head = h mark = 'x' else: continue lev = len(bline) - len(h) + 1 tline = ' %s%s|%s' %(mark, '. '*(lev-1), head) tlines_add(tline) bnodes_add(i+1) levels_add(lev) return (tlines, bnodes, levels) def hook_newHeadline(VO, level, blnum, tlnum): """Return (tree_head, bodyLines). tree_head is new headline string in Tree buffer (text after |). bodyLines is list of lines to insert in Body buffer. """ tree_head = 'NewHeadline' bodyLines = ['%s- %s' %('\t'*(level-1), tree_head),] return (tree_head, bodyLines) # ---- The rest is identical to vimoutliner/thevimoutliner modes. ----------- def hook_doBodyAfterOop(VO, oop, levDelta, blnum1, tlnum1, blnum2, tlnum2, blnumCut, tlnumCut): # this is instead of hook_changeLevBodyHead() if not levDelta: return indent = abs(levDelta) * '\t' Body = VO.Body Z = len(Body) # ---- identical to voom_mode_python.py code ---------------------------- if blnum1: assert blnum1 == VO.bnodes[tlnum1-1] if tlnum2 < len(VO.bnodes): assert blnum2 == VO.bnodes[tlnum2]-1 else: assert blnum2 == Z # dedent (if possible) or indent every non-blank line in Body region blnum1,blnum2 blines = [] for i in xrange(blnum1-1,blnum2): line = Body[i] if not line.strip(): blines.append(line) continue if levDelta > 0: line = '%s%s' %(indent,line) elif levDelta < 0 and line.startswith(indent): line = line[len(indent):] blines.append(line) # replace Body region Body[blnum1-1:blnum2] = blines assert len(Body)==Z VOoM-5.3/autoload/voom/voom_vimplugin2657/voom_mode_thevimoutliner.py000066400000000000000000000060501305710164100260620ustar00rootroot00000000000000# File: voom_mode_thevimoutliner.py # Last Modified: 2017-01-07 # Description: VOoM -- two-pane outliner plugin for Python-enabled Vim # Website: http://www.vim.org/scripts/script.php?script_id=2657 # Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) # License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ """ VOoM markup mode for The Vim Outliner format. See |voom-mode-thevimoutliner|, ../../../doc/voom.txt#*voom-mode-thevimoutliner* Headlines and body lines are indented with Tabs. Number of tabs indicates level. 0 Tabs means level 1. Headlines are lines with >=0 Tabs followed by any character except '|'. Blank lines are not headlines. """ import sys if sys.version_info[0] > 2: xrange = range # Body lines start with these chars BODY_CHARS = {'|':0,} # ------ the rest is identical to voom_mode_vimoutliner.py ------------------- def hook_makeOutline(VO, blines): """Return (tlines, bnodes, levels) for Body lines blines. blines is either Vim buffer object (Body) or list of buffer lines. """ Z = len(blines) tlines, bnodes, levels = [], [], [] tlines_add, bnodes_add, levels_add = tlines.append, bnodes.append, levels.append for i in xrange(Z): bline = blines[i].rstrip() if not bline: continue head = bline.lstrip('\t') if head[0] in BODY_CHARS: continue lev = len(bline) - len(head) + 1 tline = ' %s|%s' %('. '*(lev-1), head) tlines_add(tline) bnodes_add(i+1) levels_add(lev) return (tlines, bnodes, levels) def hook_newHeadline(VO, level, blnum, tlnum): """Return (tree_head, bodyLines). tree_head is new headline string in Tree buffer (text after |). bodyLines is list of lines to insert in Body buffer. """ tree_head = 'NewHeadline' bodyLines = ['%s%s' %('\t'*(level-1), tree_head),] return (tree_head, bodyLines) #def hook_changeLevBodyHead(VO, h, levDelta): #"""Increase of decrease level number of Body headline by levDelta.""" #if levDelta==0: return h def hook_doBodyAfterOop(VO, oop, levDelta, blnum1, tlnum1, blnum2, tlnum2, blnumCut, tlnumCut): # this is instead of hook_changeLevBodyHead() if not levDelta: return indent = abs(levDelta) * '\t' Body = VO.Body Z = len(Body) # ---- identical to voom_mode_python.py code ---------------------------- if blnum1: assert blnum1 == VO.bnodes[tlnum1-1] if tlnum2 < len(VO.bnodes): assert blnum2 == VO.bnodes[tlnum2]-1 else: assert blnum2 == Z # dedent (if possible) or indent every non-blank line in Body region blnum1,blnum2 blines = [] for i in xrange(blnum1-1,blnum2): line = Body[i] if not line.strip(): blines.append(line) continue if levDelta > 0: line = '%s%s' %(indent,line) elif levDelta < 0 and line.startswith(indent): line = line[len(indent):] blines.append(line) # replace Body region Body[blnum1-1:blnum2] = blines assert len(Body)==Z VOoM-5.3/autoload/voom/voom_vimplugin2657/voom_mode_txt2tags.py000066400000000000000000000071241305710164100245670ustar00rootroot00000000000000# File: voom_mode_txt2tags.py # Last Modified: 2017-01-07 # Description: VOoM -- two-pane outliner plugin for Python-enabled Vim # Website: http://www.vim.org/scripts/script.php?script_id=2657 # Author: Vlad Irnov (vlad DOT irnov AT gmail DOT com) # License: CC0, see http://creativecommons.org/publicdomain/zero/1.0/ """ VOoM markup mode for txt2tags titles. See |voom-mode-txt2tags|, ../../../doc/voom.txt#*voom-mode-txt2tags* """ import sys if sys.version_info[0] > 2: xrange = range import re # headline regexps from txt2tags.py: # titskel = r'^ *(?P%s)(?P%s)\1(\[(?P