diff options
Diffstat (limited to 'dot_vim/plugin/SyntaxFolds.vim')
-rw-r--r-- | dot_vim/plugin/SyntaxFolds.vim | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/dot_vim/plugin/SyntaxFolds.vim b/dot_vim/plugin/SyntaxFolds.vim new file mode 100644 index 0000000..27c622c --- /dev/null +++ b/dot_vim/plugin/SyntaxFolds.vim @@ -0,0 +1,323 @@ +" ============================================================================== +" File: syntaxFolds.vim +" Author: Srinath Avadhanula +" ( srinath@fastmail.fm ) +" Last Change: Sun Oct 27 01:00 AM 2002 PST +" Description: Emulation of the syntax folding capability of vim using manual +" folding +" +" This script provides an emulation of the syntax folding of vim using manual +" folding. Just as in syntax folding, the folds are defined by regions. Each +" region is specified by a call to FoldRegions() which accepts 4 parameters: +" +" call FoldRegions(startpat, endpat, startoff, endoff) +" +" startpat: a line matching this pattern defines the beginning of a fold. +" endpat : a line matching this pattern defines the end of a fold. +" startoff: this is the offset from the starting line at which folding will +" actually start +" endoff : like startoff, but gives the offset of the actual fold end from +" the line satisfying endpat. +" startoff and endoff are necessary when the folding region does +" not have a specific end pattern corresponding to a start +" pattern. for example in latex, +" \begin{section} +" defines the beginning of a section, but its not necessary to +" have a corresponding +" \end{section} +" the section is assumed to end 1 line _before_ another section +" starts. +" startskip: a pattern which defines the beginning of a "skipped" region. +" +" For example, suppose we define a \itemize fold as follows: +" startpat = '^\s*\\item', +" endpat = '^\s*\\item\|^\s*\\end{\(enumerate\|itemize\|description\)}', +" startoff = 0, +" endoff = -1 +" +" This defines a fold which starts with a line beginning with an +" \item and ending one line before a line beginning with an +" \item or \end{enumerate} etc. +" +" Then, as long as \item's are not nested things are fine. +" However, once items begin to nest, the fold started by one +" \item can end because of an \item in an \itemize +" environment within this \item. i.e, the following can happen: +" +" \begin{itemize} +" \item Some text <------- fold will start here +" This item will contain a nested item +" \begin{itemize} <----- fold will end here because next line contains \item... +" \item Hello +" \end{itemize} <----- ... instead of here. +" \item Next item of the parent itemize +" \end{itemize} +" +" Therefore, in order to completely define a folding item which +" allows nesting, we need to also define a "skip" pattern. +" startskip and end skip do that. +" Leave '' when there is no nesting. +" endskip: the pattern which defines the end of the "skip" pattern for +" nested folds. +" +" Example: +" 1. A syntax fold region for a latex section is +" startpat = "\\section{" +" endpat = "\\section{" +" startoff = 0 +" endoff = -1 +" startskip = '' +" endskip = '' +" Note that the start and end patterns are thus the same and endoff has a +" negative value to capture the effect of a section ending one line before +" the next starts. +" 2. A syntax fold region for the \itemize environment is: +" startpat = '^\s*\\item', +" endpat = '^\s*\\item\|^\s*\\end{\(enumerate\|itemize\|description\)}', +" startoff = 0, +" endoff = -1, +" startskip = '^\s*\\begin{\(enumerate\|itemize\|description\)}', +" endskip = '^\s*\\end{\(enumerate\|itemize\|description\)}' +" Note the use of startskip and endskip to allow nesting. +" +" +" Each time a call is made to FoldRegions(), all the regions (which might be +" disjoint, but not nested) are folded up. +" Nested folds can be created by successive calls to FoldRegions(). The first +" call defines the region which is deepest in the folding. See MakeTexFolds() +" for an idea of how this works for latex files. + +" Function: AddSyntaxFoldItem (start, end, startoff, endoff [, skipStart, skipEnd]) {{{ +function! AddSyntaxFoldItem(start, end, startoff, endoff, ...) + if a:0 > 0 + let skipStart = a:1 + let skipEnd = a:2 + else + let skipStart = '' + let skipEnd = '' + end + if !exists('b:numFoldItems') + let b:numFoldItems = 0 + end + let b:numFoldItems = b:numFoldItems + 1 + + exe 'let b:startPat_'.b:numFoldItems.' = a:start' + exe 'let b:endPat_'.b:numFoldItems.' = a:end' + exe 'let b:startOff_'.b:numFoldItems.' = a:startoff' + exe 'let b:endOff_'.b:numFoldItems.' = a:endoff' + exe 'let b:skipStartPat_'.b:numFoldItems.' = skipStart' + exe 'let b:skipEndPat_'.b:numFoldItems.' = skipEnd' +endfunction + + +" }}} +" Function: MakeSyntaxFolds (force) {{{ +" Description: This function calls FoldRegions() several times with the +" parameters specifying various regions resulting in a nested fold +" structure for the file. +function! MakeSyntaxFolds(force, ...) + if exists('b:doneFolding') && a:force == 0 + return + end + + let skipEndPattern = '' + if a:0 > 0 + let line1 = a:1 + let skipEndPattern = '\|'.a:2 + else + let line1 = 1 + let r = line('.') + let c = virtcol('.') + + setlocal fdm=manual + normal! zE + end + if !exists('b:numFoldItems') + b:numFoldItems = 1000000 + end + + let i = 1 + + let maxline = line('.') + + while exists('b:startPat_'.i) && i <= b:numFoldItems + exe 'let startPat = b:startPat_'.i + exe 'let endPat = b:endPat_'.i + exe 'let startOff = b:startOff_'.i + exe 'let endOff = b:endOff_'.i + + let skipStart = '' + let skipEnd = '' + if exists('b:skipStartPat_'.i) + exe 'let skipStart = b:skipStartPat_'.i + exe 'let skipEnd = b:skipEndPat_'.i + end + exe line1 + let lastLoc = line1 + + if skipStart != '' + call InitStack('BeginSkipArray') + call FoldRegionsWithSkip(startPat, endPat, startOff, endOff, skipStart, skipEnd, 1, line('$')) + " call PrintError('done folding ['.startPat.']') + else + call FoldRegionsWithNoSkip(startPat, endPat, startOff, endOff, 1, line('$'), '') + end + + let i = i + 1 + endwhile + + exe maxline + + if a:0 == 0 + exe r + exe "normal! ".c."|" + if foldlevel(r) > 1 + exe "normal! ".(foldlevel(r) - 1)."zo" + end + let b:doneFolding = 0 + end +endfunction + + +" }}} +" FoldRegionsWithSkip: folding things such as \item's which can be nested. {{{ +function! FoldRegionsWithSkip(startpat, endpat, startoff, endoff, startskip, endskip, line1, line2) + exe a:line1 + " count the regions which have been skipped as we go along. do not want to + " create a fold which with a beginning or end line in one of the skipped + " regions. + let skippedRegions = '' + + " start searching for either the starting pattern or the end pattern. + while search(a:startskip.'\|'.a:endskip, 'W') + + if getline('.') =~ a:endskip + + let lastBegin = Pop('BeginSkipArray') + " call PrintError('popping '.lastBegin.' from stack and folding till '.line('.')) + call FoldRegionsWithNoSkip(a:startpat, a:endpat, a:startoff, a:endoff, lastBegin, line('.'), skippedRegions) + let skippedRegions = skippedRegions.lastBegin.','.line('.').'|' + + + " if this is the beginning of a skip region, then, push this line as + " the beginning of a skipped region. + elseif getline('.') =~ a:startskip + + " call PrintError('pushing '.line('.').' ['.getline('.').'] into stack') + call Push('BeginSkipArray', line('.')) + + end + endwhile + + " call PrintError('with skip starting at '.a:line1.' returning at line# '.line('.')) +endfunction + +" }}} +" FoldRegionsWithNoSkip: folding things such as \sections which do not nest. {{{ +function! FoldRegionsWithNoSkip(startpat, endpat, startoff, endoff, line1, line2, skippedRegions) + exe a:line1 + + " call PrintError('line1 = '.a:line1.', searching from '.line('.').'... for ['.a:startpat.'') + let lineBegin = s:MySearch(a:startpat, 'in') + " call PrintError('... and finding it at '.lineBegin) + + while lineBegin <= a:line2 + if IsInSkippedRegion(lineBegin, a:skippedRegions) + let lineBegin = s:MySearch(a:startpat, 'out') + " call PrintError(lineBegin.' is being skipped') + continue + end + let lineEnd = s:MySearch(a:endpat, 'out') + while IsInSkippedRegion(lineEnd, a:skippedRegions) && lineEnd <= a:line2 + let lineEnd = s:MySearch(a:endpat, 'out') + endwhile + if lineEnd > a:line2 + exe (lineBegin + a:startoff).','.a:line2.' fold' + break + else + " call PrintError ('for ['.a:startpat.'] '.(lineBegin + a:startoff).','.(lineEnd + a:endoff).' fold') + exe (lineBegin + a:startoff).','.(lineEnd + a:endoff).' fold' + end + + " call PrintError('line1 = '.a:line1.', searching from '.line('.').'... for ['.a:startpat.'') + let lineBegin = s:MySearch(a:startpat, 'in') + " call PrintError('... and finding it at '.lineBegin) + endwhile + + exe a:line2 + return +endfunction + +" }}} +" InitStack: initialize a stack {{{ +function! InitStack(name) + exe 'let s:'.a:name.'_numElems = 0' +endfunction +" }}} +" Push: push element into stack {{{ +function! Push(name, elem) + exe 'let numElems = s:'.a:name.'_numElems' + let numElems = numElems + 1 + exe 'let s:'.a:name.'_Element_'.numElems.' = a:elem' + exe 'let s:'.a:name.'_numElems = numElems' +endfunction +" }}} +" Pop: pops element off stack {{{ +function! Pop(name) + exe 'let numElems = s:'.a:name.'_numElems' + if numElems == 0 + return '' + else + exe 'let ret = s:'.a:name.'_Element_'.numElems + let numElems = numElems - 1 + exe 'let s:'.a:name.'_numElems = numElems' + return ret + end +endfunction +" }}} +" MySearch: just like search(), but returns large number on failure {{{ +function! <SID>MySearch(pat, opt) + if a:opt == 'in' + if getline('.') =~ a:pat + let ret = line('.') + else + let ret = search(a:pat, 'W') + end + else + normal! $ + let ret = search(a:pat, 'W') + end + + if ret == 0 + let ret = line('$') + 1 + end + return ret +endfunction +" }}} +" Function: IsInSkippedRegion (lnum, regions) {{{ +" Description: finds whether a given line number is within one of the regions +" skipped. +function! IsInSkippedRegion(lnum, regions) + let i = 1 + let subset = s:Strntok(a:regions, '|', i) + while subset != '' + let n1 = s:Strntok(subset, ',', 1) + let n2 = s:Strntok(subset, ',', 2) + if a:lnum >= n1 && a:lnum <= n2 + return 1 + end + + let subset = s:Strntok(a:regions, '|', i) + let i = i + 1 + endwhile + + return 0 +endfunction " }}} +" Function: Strntok (string, tok, n) {{{ +" extract the n^th token from s seperated by tok. +" example: Strntok('1,23,3', ',', 2) = 23 +fun! <SID>Strntok(s, tok, n) + return matchstr( a:s.a:tok[0], '\v(\zs([^'.a:tok.']*)\ze['.a:tok.']){'.a:n.'}') +endfun " }}} + +" vim600:fdm=marker |