dotfiles/vim/vim-latex/ftplugin/latex-suite/folding.vim

401 lines
13 KiB
VimL
Executable File

"=============================================================================
" 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 <unique> <Plug>Tex_RefreshFolds :call MakeTexFolds(1)<cr>
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 = '<Leader>'
call Tex_MakeMap(s:ml."rf", "<Plug>Tex_RefreshFolds", 'n', '<silent> <buffer>')
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 =~ '\<comments\>'
call AddSyntaxFoldItem (
\ '^%\([^%]\|[^f]\|[^a]\|[^k]\|[^e]\)',
\ '^[^%]',
\ 0,
\ -1
\ )
endif
" }}}
" {{{ items
if g:Tex_FoldedMisc =~ '\<item\>'
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 =~ '\<title\>'
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 =~ '\<slide\>'
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 =~ '\<preamble\>'
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