summaryrefslogtreecommitdiffstats
path: root/ftplugin/latex-box/folding.vim
diff options
context:
space:
mode:
Diffstat (limited to 'ftplugin/latex-box/folding.vim')
-rw-r--r--ftplugin/latex-box/folding.vim317
1 files changed, 317 insertions, 0 deletions
diff --git a/ftplugin/latex-box/folding.vim b/ftplugin/latex-box/folding.vim
new file mode 100644
index 00000000..36f1577b
--- /dev/null
+++ b/ftplugin/latex-box/folding.vim
@@ -0,0 +1,317 @@
+" Folding support for LaTeX
+"
+" Options
+" g:LatexBox_Folding - Turn on/off folding
+" g:LatexBox_fold_preamble - Turn on/off folding of preamble
+" g:LatexBox_fold_parts - Define parts (eq. appendix, frontmatter) to fold
+" g:LatexBox_fold_sections - Define section levels to fold
+" g:LatexBox_fold_envs - Turn on/off folding of environments
+"
+
+" {{{1 Set options
+if exists('g:LatexBox_Folding') && g:LatexBox_Folding == 1
+ setl foldmethod=expr
+ setl foldexpr=LatexBox_FoldLevel(v:lnum)
+ setl foldtext=LatexBox_FoldText()
+ "
+ " The foldexpr function returns "=" for most lines, which means it can become
+ " slow for large files. The following is a hack that is based on this reply to
+ " a discussion on the Vim Developer list:
+ " http://permalink.gmane.org/gmane.editors.vim.devel/14100
+ "
+ augroup FastFold
+ autocmd!
+ autocmd InsertEnter *.tex setlocal foldmethod=manual
+ autocmd InsertLeave *.tex setlocal foldmethod=expr
+ augroup end
+endif
+if !exists('g:LatexBox_fold_preamble')
+ let g:LatexBox_fold_preamble=1
+endif
+if !exists('g:LatexBox_fold_envs')
+ let g:LatexBox_fold_envs=1
+endif
+if !exists('g:LatexBox_fold_parts')
+ let g:LatexBox_fold_parts=[
+ \ "appendix",
+ \ "frontmatter",
+ \ "mainmatter",
+ \ "backmatter"
+ \ ]
+endif
+if !exists('g:LatexBox_fold_sections')
+ let g:LatexBox_fold_sections=[
+ \ "part",
+ \ "chapter",
+ \ "section",
+ \ "subsection",
+ \ "subsubsection"
+ \ ]
+endif
+if !exists('g:LatexBox_fold_toc')
+ let g:LatexBox_fold_toc=0
+endif
+if !exists('g:LatexBox_fold_toc_levels')
+ let g:LatexBox_fold_toc_levels=1
+endif
+
+
+" {{{1 LatexBox_FoldLevel help functions
+
+" This function parses the tex file to find the sections that are to be folded
+" and their levels, and then predefines the patterns for optimized folding.
+function! s:FoldSectionLevels()
+ " Initialize
+ let level = 1
+ let foldsections = []
+
+ " If we use two or more of the *matter commands, we need one more foldlevel
+ let nparts = 0
+ for part in g:LatexBox_fold_parts
+ let i = 1
+ while i < line("$")
+ if getline(i) =~ '^\s*\\' . part . '\>'
+ let nparts += 1
+ break
+ endif
+ let i += 1
+ endwhile
+ if nparts > 1
+ let level = 2
+ break
+ endif
+ endfor
+
+ " Combine sections and levels, but ignore unused section commands: If we
+ " don't use the part command, then chapter should have the highest
+ " level. If we don't use the chapter command, then section should be the
+ " highest level. And so on.
+ let ignore = 1
+ for part in g:LatexBox_fold_sections
+ " For each part, check if it is used in the file. We start adding the
+ " part patterns to the fold sections array whenever we find one.
+ let partpattern = '^\s*\(\\\|% Fake\)' . part . '\>'
+ if ignore
+ let i = 1
+ while i < line("$")
+ if getline(i) =~# partpattern
+ call insert(foldsections, [partpattern, level])
+ let level += 1
+ let ignore = 0
+ break
+ endif
+ let i += 1
+ endwhile
+ else
+ call insert(foldsections, [partpattern, level])
+ let level += 1
+ endif
+ endfor
+
+ return foldsections
+endfunction
+
+" {{{1 LatexBox_FoldLevel
+
+" Parse file to dynamically set the sectioning fold levels
+let b:LatexBox_FoldSections = s:FoldSectionLevels()
+
+" Optimize by predefine common patterns
+let s:notbslash = '\%(\\\@<!\%(\\\\\)*\)\@<='
+let s:notcomment = '\%(\%(\\\@<!\%(\\\\\)*\)\@<=%.*\)\@<!'
+let s:envbeginpattern = s:notcomment . s:notbslash . '\\begin\s*{.\{-}}'
+let s:envendpattern = s:notcomment . s:notbslash . '\\end\s*{.\{-}}'
+let s:foldparts = '^\s*\\\%(' . join(g:LatexBox_fold_parts, '\|') . '\)'
+let s:folded = '\(% Fake\|\\\(document\|begin\|end\|'
+ \ . 'front\|main\|back\|app\|sub\|section\|chapter\|part\)\)'
+
+function! LatexBox_FoldLevel(lnum)
+ " Check for normal lines first (optimization)
+ let line = getline(a:lnum)
+ if line !~ s:folded
+ return "="
+ endif
+
+ " Fold preamble
+ if g:LatexBox_fold_preamble == 1
+ if line =~# '\s*\\documentclass'
+ return ">1"
+ elseif line =~# '^\s*\\begin\s*{\s*document\s*}'
+ return "0"
+ endif
+ endif
+
+ " Fold parts (\frontmatter, \mainmatter, \backmatter, and \appendix)
+ if line =~# s:foldparts
+ return ">1"
+ endif
+
+ " Fold chapters and sections
+ for [part, level] in b:LatexBox_FoldSections
+ if line =~# part
+ return ">" . level
+ endif
+ endfor
+
+ " Fold environments
+ if g:LatexBox_fold_envs == 1
+ if line =~# s:envbeginpattern
+ return "a1"
+ elseif line =~# '^\s*\\end{document}'
+ " Never fold \end{document}
+ return 0
+ elseif line =~# s:envendpattern
+ return "s1"
+ endif
+ endif
+
+ " Return foldlevel of previous line
+ return "="
+endfunction
+
+" {{{1 LatexBox_FoldText help functions
+function! s:LabelEnv()
+ let i = v:foldend
+ while i >= v:foldstart
+ if getline(i) =~ '^\s*\\label'
+ return matchstr(getline(i), '^\s*\\label{\zs.*\ze}')
+ end
+ let i -= 1
+ endwhile
+ return ""
+endfunction
+
+function! s:CaptionEnv()
+ let i = v:foldend
+ while i >= v:foldstart
+ if getline(i) =~ '^\s*\\caption'
+ return matchstr(getline(i), '^\s*\\caption\(\[.*\]\)\?{\zs.\+')
+ end
+ let i -= 1
+ endwhile
+ return ""
+endfunction
+
+function! s:CaptionTable()
+ let i = v:foldstart
+ while i <= v:foldend
+ if getline(i) =~ '^\s*\\caption'
+ return matchstr(getline(i), '^\s*\\caption\(\[.*\]\)\?{\zs.\+')
+ end
+ let i += 1
+ endwhile
+ return ""
+endfunction
+
+function! s:CaptionFrame(line)
+ " Test simple variants first
+ let caption1 = matchstr(a:line,'\\begin\*\?{.*}{\zs.\+\ze}')
+ let caption2 = matchstr(a:line,'\\begin\*\?{.*}{\zs.\+')
+
+ if len(caption1) > 0
+ return caption1
+ elseif len(caption2) > 0
+ return caption2
+ else
+ let i = v:foldstart
+ while i <= v:foldend
+ if getline(i) =~ '^\s*\\frametitle'
+ return matchstr(getline(i),
+ \ '^\s*\\frametitle\(\[.*\]\)\?{\zs.\+')
+ end
+ let i += 1
+ endwhile
+
+ return ""
+ endif
+endfunction
+
+" {{{1 LatexBox_FoldText
+function! LatexBox_FoldText()
+ " Initialize
+ let line = getline(v:foldstart)
+ let nlines = v:foldend - v:foldstart + 1
+ let level = ''
+ let title = 'Not defined'
+
+ " Fold level
+ let level = strpart(repeat('-', v:foldlevel-1) . '*',0,3)
+ if v:foldlevel > 3
+ let level = strpart(level, 1) . v:foldlevel
+ endif
+ let level = printf('%-3s', level)
+
+ " Preamble
+ if line =~ '\s*\\documentclass'
+ let title = "Preamble"
+ endif
+
+ " Parts, sections and fakesections
+ let sections = '\(\(sub\)*section\|part\|chapter\)'
+ let secpat1 = '^\s*\\' . sections . '\*\?\s*{'
+ let secpat2 = '^\s*\\' . sections . '\*\?\s*\['
+ if line =~ '\\frontmatter'
+ let title = "Frontmatter"
+ elseif line =~ '\\mainmatter'
+ let title = "Mainmatter"
+ elseif line =~ '\\backmatter'
+ let title = "Backmatter"
+ elseif line =~ '\\appendix'
+ let title = "Appendix"
+ elseif line =~ secpat1 . '.*}'
+ let title = matchstr(line, secpat1 . '\zs.*\ze}')
+ elseif line =~ secpat1
+ let title = matchstr(line, secpat1 . '\zs.*')
+ elseif line =~ secpat2 . '.*\]'
+ let title = matchstr(line, secpat2 . '\zs.*\ze\]')
+ elseif line =~ secpat2
+ let title = matchstr(line, secpat2 . '\zs.*')
+ elseif line =~ 'Fake' . sections . ':'
+ let title = matchstr(line,'Fake' . sections . ':\s*\zs.*')
+ elseif line =~ 'Fake' . sections
+ let title = matchstr(line, 'Fake' . sections)
+ endif
+
+ " Environments
+ if line =~ '\\begin'
+ " Capture environment name
+ let env = matchstr(line,'\\begin\*\?{\zs\w*\*\?\ze}')
+
+ " Set caption based on type of environment
+ if env == 'frame'
+ let label = ''
+ let caption = s:CaptionFrame(line)
+ elseif env == 'table'
+ let label = s:LabelEnv()
+ let caption = s:CaptionTable()
+ else
+ let label = s:LabelEnv()
+ let caption = s:CaptionEnv()
+ endif
+
+ " If no caption found, check for a caption comment
+ if caption == ''
+ let caption = matchstr(line,'\\begin\*\?{.*}\s*%\s*\zs.*')
+ endif
+
+ " Create title based on caption and label
+ if caption . label == ''
+ let title = env
+ elseif label == ''
+ let title = printf('%-12s%s', env . ':',
+ \ substitute(caption, '}\s*$', '',''))
+ elseif caption == ''
+ let title = printf('%-12s%56s', env, '(' . label . ')')
+ else
+ let title = printf('%-12s%-30s %21s', env . ':',
+ \ strpart(substitute(caption, '}\s*$', '',''),0,34),
+ \ '(' . label . ')')
+ endif
+ endif
+
+ let title = strpart(title, 0, 68)
+ return printf('%-3s %-68s #%5d', level, title, nlines)
+endfunction
+
+" {{{1 Footer
+" vim:fdm=marker:ff=unix:ts=4:sw=4