"============================================================================= " File: folding.vim " Author: Srinath Avadhanula " modifications/additions by Zhang Linbo " Created: Tue Apr 23 05:00 PM 2002 PST " " Description: functions to interact with Syntaxfolds.vim "============================================================================= nnoremap Tex_RefreshFolds :call MakeTexFolds(1) augroup LatexSuite au LatexSuite User LatexSuiteFileType \ call Tex_Debug('folding.vim: catching LatexSuiteFileType', 'fold') | \ call Tex_SetFoldOptions() augroup END " Tex_SetFoldOptions: sets maps for every buffer {{{ " Description: function! Tex_SetFoldOptions() if exists('b:doneSetFoldOptions') return endif let b:doneSetFoldOptions = 1 setlocal foldtext=TexFoldTextFunction() if g:Tex_Folding && g:Tex_AutoFolding call MakeTexFolds(0) endif let s:ml = '' call Tex_MakeMap(s:ml."rf", "Tex_RefreshFolds", 'n', ' ') endfunction " }}} " Tex_FoldSections: creates section folds {{{ " Author: Zhang Linbo " Description: " This function takes a comma seperated list of "sections" and creates fold " definitions for them. The first item is supposed to be the "shallowest" field " and the last is the "deepest". See g:Tex_FoldedSections for the default " definition of the lst input argument. " " **works recursively** function! Tex_FoldSections(lst, endpat) let i = match(a:lst, ',') if i > 0 let s = strpart(a:lst, 0, i) else let s = a:lst endif if s =~ '%%fakesection' let s = '^\s*' . s else let pattern = '' let prefix = '' for label in split(s, "|") let pattern .= prefix . '^\s*\\' . label . '\W\|^\s*%%fake' . label let prefix = '\W\|' endfor let s = pattern endif let endpat = s . '\|' . a:endpat if i > 0 call Tex_FoldSections(strpart(a:lst,i+1), endpat) endif let endpat = '^\s*\\appendix\W\|' . endpat call AddSyntaxFoldItem(s, endpat, 0, -1) endfunction " }}} " MakeTexFolds: function to create fold items for latex. {{{ " " used in conjunction with MakeSyntaxFolds(). " see ../plugin/syntaxFolds.vim for documentation function! MakeTexFolds(force) if exists('g:Tex_Folding') && !g:Tex_Folding return endif if &ft != 'tex' return end " Setup folded items lists g:Tex_Foldedxxxx " 1. Use default value if g:Tex_Foldedxxxxxx is not defined " 2. prepend default value to g:Tex_Foldedxxxxxx if it starts with ',' " 3. append default value to g:Tex_Foldedxxxxxx if it ends with ',' " Folding items which are not caught in any of the standard commands, " environments or sections. let s = 'item,slide,preamble,<<<' if !exists('g:Tex_FoldedMisc') let g:Tex_FoldedMisc = s elseif g:Tex_FoldedMisc[0] == ',' let g:Tex_FoldedMisc = s . g:Tex_FoldedMisc elseif g:Tex_FoldedMisc =~ ',$' let g:Tex_FoldedMisc = g:Tex_FoldedMisc . s endif " By default do not fold any commands. It looks like trying to fold " commands is a difficult problem since commands can be arbitrarily nested " and the end patterns are not unique unlike the case of environments. " For this to work well, we need a regexp which will match a line only if " a command begins on that line but does not end on that line. This " requires a regexp which will match unbalanced curly braces and that is " apparently not doable with regexps. let s = '' if !exists('g:Tex_FoldedCommands') let g:Tex_FoldedCommands = s elseif g:Tex_FoldedCommands[0] == ',' let g:Tex_FoldedCommands = s . g:Tex_FoldedCommands elseif g:Tex_FoldedCommands =~ ',$' let g:Tex_FoldedCommands = g:Tex_FoldedCommands . s endif let s = 'verbatim,comment,eq,gather,align,figure,table,thebibliography,' \. 'keywords,abstract,titlepage' if !exists('g:Tex_FoldedEnvironments') let g:Tex_FoldedEnvironments = s elseif g:Tex_FoldedEnvironments[0] == ',' let g:Tex_FoldedEnvironments = s . g:Tex_FoldedEnvironments elseif g:Tex_FoldedEnvironments =~ ',$' let g:Tex_FoldedEnvironments = g:Tex_FoldedEnvironments . s endif if !exists('g:Tex_FoldedSections') let g:Tex_FoldedSections = 'part,chapter,section,' \. 'subsection,subsubsection,paragraph' endif " the order in which these calls are made decides the nestedness. in " latex, a table environment will always be embedded in either an item or " a section etc. not the other way around. so we first fold up all the " tables. and then proceed with the other regions. let b:numFoldItems = 0 " ======================================================================== " How to add new folding items {{{ " ======================================================================== " " Each of the following function calls defines a syntax fold region. Each " definition consists of a call to the AddSyntaxFoldItem() function. " " The order in which the folds are defined is important. Juggling the " order of the function calls will create havoc with folding. The " "deepest" folding item needs to be called first. For example, if " the \begin{table} environment is a subset (or lies within) the \section " environment, then add the definition for the \table first. " " The AddSyntaxFoldItem() function takes either 4 or 6 arguments. When it " is called with 4 arguments, it is equivalent to calling it with 6 " arguments with the last two left blank (i.e as empty strings) " " The explanation for each argument is as follows: " 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. " " " }}} " ======================================================================== " {{{ comment lines if g:Tex_FoldedMisc =~ '\' call AddSyntaxFoldItem ( \ '^%\([^%]\|[^f]\|[^a]\|[^k]\|[^e]\)', \ '^[^%]', \ 0, \ -1 \ ) endif " }}} " {{{ items if g:Tex_FoldedMisc =~ '\' call AddSyntaxFoldItem ( \ '^\s*\\item', \ '^\s*\\item\|^\s*\\end{\(enumerate\|itemize\|description\)}', \ 0, \ -1, \ '^\s*\\begin{\(enumerate\|itemize\|description\)}', \ '^\s*\\end{\(enumerate\|itemize\|description\)}' \ ) endif " }}} " {{{ title if g:Tex_FoldedMisc =~ '\' call AddSyntaxFoldItem ( \ '^\s*\\title\W', \ '^\s*\\maketitle', \ 0, \ 0 \ ) endif " }}} " Commands and Environments {{{ " Fold the commands and environments in 2 passes. let pass = 0 while pass < 2 if pass == 0 let lst = g:Tex_FoldedCommands else let lst = g:Tex_FoldedEnvironments endif while lst != '' let i = match(lst, ',') if i > 0 let s = strpart(lst, 0, i) let lst = strpart(lst, i+1) else let s = lst let lst = '' endif if s != '' if pass == 0 " NOTE: This pattern ensures that a command which is " terminated on the same line will not start a fold. " However, it will also refuse to fold certain commands " which have not terminated. eg: " \commandname{something \bf{text} and " will _not_ start a fold. " In other words, the pattern is safe, but not exact. call AddSyntaxFoldItem('^\s*\\'.s.'{[^{}]*$','^[^}]*}',0,0) else call AddSyntaxFoldItem('^\s*\\begin{'.s,'\(^\|\s\)\s*\\end{'.s,0,0) endif endif endwhile let pass = pass + 1 endwhile " }}} " Sections {{{ if g:Tex_FoldedSections != '' call Tex_FoldSections(g:Tex_FoldedSections, \ '^\s*\\frontmatter\|^\s*\\mainmatter\|^\s*\\backmatter\|' \. '^\s*\\begin{thebibliography\|>>>\|^\s*\\endinput\|' \. '^\s*\\begin{slide\|^\s*\\end{document') endif " }}} " {{{ slide if g:Tex_FoldedMisc =~ '\' call AddSyntaxFoldItem ( \ '^\s*\\begin{slide', \ '^\s*\\appendix\W\|^\s*\\chapter\W\|^\s*\\end{slide\|^\s*\\end{document', \ 0, \ 0 \ ) endif " }}} " {{{ preamble if g:Tex_FoldedMisc =~ '\' call AddSyntaxFoldItem ( \ '^\s*\\document\(class\|style\).*{', \ '^\s*\\begin{document}', \ 0, \ -1 \ ) endif " }}} " Manually folded regions {{{ if g:Tex_FoldedMisc =~ '\(^\|,\)<<<\(,\|$\)' call AddSyntaxFoldItem ( \ '<<<', \ '>>>', \ 0, \ 0 \ ) endif " }}} call MakeSyntaxFolds(a:force) normal! zv endfunction " }}} " TexFoldTextFunction: create fold text for folds {{{ function! TexFoldTextFunction() let leadingSpace = matchstr(' ', ' \{,'.indent(v:foldstart).'}') if getline(v:foldstart) =~ '^\s*\\begin{' let header = matchstr(getline(v:foldstart), \ '^\s*\\begin{\zs\([:alpha:]*\)[^}]*\ze}') let caption = '' let label = '' let i = v:foldstart while i <= v:foldend if getline(i) =~ '\\caption' " distinguish between " \caption{fulldesc} - fulldesc will be displayed " \caption[shortdesc]{fulldesc} - shortdesc will be displayed if getline(i) =~ '\\caption\[' let caption = matchstr(getline(i), '\\caption\[\zs[^\]]*') let caption = substitute(caption, '\zs\]{.*}[^}]*$', '', '') else let caption = matchstr(getline(i), '\\caption{\zs.*') let caption = substitute(caption, '\zs}[^}]*$', '', '') end elseif getline(i) =~ '\\label' let label = matchstr(getline(i), '\\label{\zs.*') " :FIXME: this does not work when \label contains a " newline or a }-character let label = substitute(label, '\([^}]*\)}.*$', '\1', '') end let i = i + 1 endwhile let ftxto = foldtext() " if no caption found, then use the second line. if caption == '' let caption = getline(v:foldstart + 1) end let retText = matchstr(ftxto, '^[^:]*').': '.header. \ ' ('.label.'): '.caption return leadingSpace.retText elseif getline(v:foldstart) =~ '^%' && getline(v:foldstart) !~ '^%%fake' let ftxto = foldtext() return leadingSpace.substitute(ftxto, ':', ': % ', '') elseif getline(v:foldstart) =~ '^\s*\\document\(class\|style\).*{' let ftxto = leadingSpace.foldtext() return substitute(ftxto, ':', ': Preamble: ', '') else return leadingSpace.foldtext() end endfunction " }}} " vim:fdm=marker:ff=unix:noet:ts=4:sw=4