This repository has been archived on 2023-10-17. You can view files and clone it, but cannot push or open issues or pull requests.
dotfiles/.vim/ftplugin/latex-suite/folding.vim

547 lines
18 KiB
VimL

"=============================================================================
" File: folding.vim
" Author: Srinath Avadhanula
" modifications/additions by Zhang Linbo, Gerd Wachsmuth
" Created: Tue Apr 23 05:00 PM 2002 PST
"
" Description: functions to interact with Syntaxfolds.vim
"=============================================================================
nnoremap <Plug>Tex_RefreshFolds :call MakeTexFolds(1, 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
call MakeTexFolds(0, 0)
endif
let s:ml = '<Leader>'
call Tex_MakeMap(s:ml."rf", "<Plug>Tex_RefreshFolds", 'n', '<silent> <buffer>')
" Setup a local autocommand, if FileChangedShellPost is available
if exists('##FileChangedShellPost')
augroup LatexSuite
autocmd FileChangedShellPost <buffer> call MakeTexFolds(1, 0)
augroup END
endif
endfunction " }}}
" Tex_FoldSections: creates section folds {{{
" 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 . '\\' . label . '\|' . '%%fake' . label
let prefix = '\|'
endfor
" The line before the pattern could contain a mixture of "% =_" (within a
" comment).
" The pattern itself is ended by a non-word character "\W" or a newline.
let s = '^\%(%[% =-]*\n\)\?\s*' . '\%(' . pattern . '\)' . '\%(\W\|\n\)'
endif
let endpat = s . '\|' . a:endpat
if i > 0
call Tex_FoldSections(strpart(a:lst,i+1), endpat)
endif
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, manual)
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 \textbf{text} and
" will _not_ start a fold.
" In other words, the pattern is safe, but not exact.
call AddSyntaxFoldItem('^\s*\\'.s.'{[^{}]*$','^[^}]*}',0,0)
else
if s =~ 'itemize\|enumerate\|description'
" These environments can nest.
call AddSyntaxFoldItem('^\s*\\begin{'.s,'\(^\|\s\)\s*\\end{'.s,0,0,'^\s*\\begin{'.s,'\(^\|\s\)\s*\\end{'.s)
else
call AddSyntaxFoldItem('^\s*\\begin{'.s,'\(^\|\s\)\s*\\end{'.s,0,0,'','')
endif
endif
endif
endwhile
let pass = pass + 1
endwhile
" }}}
" Sections {{{
if g:Tex_FoldedSections != ''
call Tex_FoldSections(g:Tex_FoldedSections,
\ '^\s*\\\%(frontmatter\|mainmatter\|backmatter\)\|'
\. '^\s*\\begin{thebibliography\|^\s*\\endinput\|'
\. '^\s*\\begin{slide\|^\s*\\\%(begin\|end\){document\|'
\. '^\s*\\\%(\%(begin\|end\){appendix}\|appendix\)')
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)
" Open all folds if this function was triggered automatically
" and g:Tex_AutoFolding is disabled
if !a:manual && !g:Tex_AutoFolding
normal! zR
endif
endfunction
" }}}
" TexFoldTextFunction: create fold text for folds {{{
function! TexFoldTextFunction()
" The dashes indicating the foldlevel together with
" the number of lines are aligned to width '7'.
let lines = v:foldend - v:foldstart + 1
let myfoldtext = repeat('-', v:foldlevel-1) . '+'
\. repeat(' ', 7-(v:foldlevel-1)-len(lines))
\. lines . ' lines: '
" Add some indent per foldlevel
let myfoldtext .= repeat('> ', v:foldlevel-1)
if getline(v:foldstart) =~ '^\s*\\begin{'
let header = matchstr(getline(v:foldstart),
\ '^\s*\\begin{\zs\([:alpha:]*\)[^}]*\ze}')
let title = ''
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', '')
elseif header =~ 'frame' && getline(i) =~ '\\begin{frame}.*{[^{}]*}\|\\frametitle\|%'
if getline(i) =~ '\\begin{frame}'
" The first argument inside {} is the frame title (the
" second one is a subtitle)
let title = matchstr(getline(i), '\\begin{frame}.\{-}{\zs[^{}]*\ze}')
elseif getline(i) =~ '\\frametitle'
let title = matchstr(getline(i), '\\frametitle{\zs[^}]*\ze}')
elseif getline(i) =~ '%' && title == ''
let title = substitute(getline(i), '^\(\s\|%\)*', '', '')
endif
end
let i = i + 1
endwhile
if header =~ 'frame'
if title == ''
let title = getline(v:foldstart + 1)
end
" Count frames
let frnum = 0
for line in getline(1,v:foldstart)
if line =~ '\\begin{frame}'
let frnum=frnum+1
endif
endfor
" Pad with spaces to length 2
let frnum = repeat(' ', 2-len(frnum)) . frnum
return myfoldtext . ': Frame ' . frnum . ': ' . title
end
" if no caption found, then use the second line.
if caption == ''
let caption = getline(v:foldstart + 1)
end
return myfoldtext . header. ' ('.label.'): '.caption
elseif getline(v:foldstart) =~ '^\s*%\+[% =-]*$'
" Useless comment. Use the next line.
return myfoldtext . getline(v:foldstart+1)
elseif getline(v:foldstart) =~ '^\s*%%fake'
" Just strip one '%' from the fakesection.
return myfoldtext . substitute(getline(v:foldstart), '^\s*%%fake', '%', '')
elseif getline(v:foldstart) =~ '^\s*%'
" It's any other comment. Use it.
return myfoldtext . getline(v:foldstart)
elseif getline(v:foldstart) =~ '^\s*\\document\(class\|style\).*{'
" This is the preamble.
return myfoldtext . 'Preamble: ' . getline(v:foldstart)
end
let section_pattern = substitute(g:Tex_FoldedSections, ',\||', '\\|', 'g')
let section_pattern = '\\\%(' . section_pattern .'\)\>'
if getline(v:foldstart) =~ '^\s*' . section_pattern
" This is a section. Search for the content of the mandatory argument {...}
let type = matchstr(getline(v:foldstart), '^\s*\zs' . section_pattern)
return myfoldtext . type . s:ParseSectionTitle(v:foldstart, section_pattern)
else
" This is something.
return myfoldtext . getline(v:foldstart)
end
endfunction
" }}}
" s:ParseSectionTitle: create fold text for sections {{{
" Search for the mandatory argument of the \section command and ignore the
" optional argument.
function! s:ParseSectionTitle(foldstart, section_pattern)
let currlinenr = a:foldstart
let currline = s:StripLine(getline(currlinenr))
let currlinelen = strlen(currline)
" Look for the section title after the section macro
let index = match(currline, '^\s*' . a:section_pattern . '\zs')
let maxlines = 10
" Current depth of nested [] and {}:
let currdepth = 0
" Do we have found the mandatory argument?
" (We are looking for '{' at depth 0)
let found_mandatory = 0
let string = ''
while (currdepth > 0) || !found_mandatory
if index >= currlinelen
" Read a new line.
let maxlines = maxlines - 1
if maxlines < 0
return string . ' Scanned too many lines'
endif
let currlinenr = currlinenr + 1
let currline = s:StripLine(getline(currlinenr))
let currlinelen = strlen(currline)
let index = 0
if found_mandatory
let string .= ' '
endif
continue
endif
" Look for [] and {} at current position
if currline[index] =~ '[[{]'
if(currdepth == 0) && (currline[index] =~ '{')
let found_mandatory = 1
end
let currdepth += 1
elseif currline[index] =~ '[]}]'
let currdepth -= 1
endif
" Look for the next interesting character
let next_index = match( currline, '[{}[\]]', index + 1 )
if next_index == -1
let next_index = currlinelen + 1
endif
" Update the string
if found_mandatory
let string .= currline[index:next_index-1]
endif
let index = next_index
endwhile
return string
endfunction
" }}}
" s:StripLine: strips whitespace and comments {{{
function! s:StripLine( string )
let string = matchstr( a:string, '^\s*\zs.*$')
let comment = match( string, '\\\@<!\%(\\\\\)*\zs%')
if comment > 0
let string = string[0:comment-1]
elseif comment == 0
let string = ''
endif
return string
endfunction
" }}}
" vim:fdm=marker:ff=unix:noet:ts=4:sw=4