summaryrefslogtreecommitdiffstats
path: root/autoload/vimtex/fold.vim
diff options
context:
space:
mode:
Diffstat (limited to 'autoload/vimtex/fold.vim')
-rw-r--r--autoload/vimtex/fold.vim143
1 files changed, 143 insertions, 0 deletions
diff --git a/autoload/vimtex/fold.vim b/autoload/vimtex/fold.vim
new file mode 100644
index 00000000..fc897b69
--- /dev/null
+++ b/autoload/vimtex/fold.vim
@@ -0,0 +1,143 @@
+if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
+
+" vimtex - LaTeX plugin for Vim
+"
+" Maintainer: Karl Yngve LervÄg
+" Email: karl.yngve@gmail.com
+"
+
+function! vimtex#fold#init_buffer() abort " {{{1
+ if !g:vimtex_fold_enabled
+ \ || s:foldmethod_in_modeline() | return | endif
+
+ " Set fold options
+ setlocal foldmethod=expr
+ setlocal foldexpr=vimtex#fold#level(v:lnum)
+ setlocal foldtext=vimtex#fold#text()
+
+ if g:vimtex_fold_manual
+ " Remap zx to refresh fold levels
+ nnoremap <silent><nowait><buffer> zx :call vimtex#fold#refresh('zx')<cr>
+ nnoremap <silent><nowait><buffer> zX :call vimtex#fold#refresh('zX')<cr>
+
+ " Define commands
+ command! -buffer VimtexRefreshFolds call vimtex#fold#refresh('zx')
+
+ " Ensure that folds are refreshed on startup
+ augroup vimtex_temporary
+ autocmd! * <buffer>
+ autocmd CursorMoved <buffer>
+ \ call vimtex#fold#refresh('zx')
+ \ | autocmd! vimtex_temporary CursorMoved <buffer>
+ augroup END
+ endif
+endfunction
+
+" }}}1
+function! vimtex#fold#init_state(state) abort " {{{1
+ "
+ " Initialize the enabled fold types
+ "
+ let a:state.fold_types_dict = {}
+ for [l:key, l:val] in items(g:vimtex_fold_types_defaults)
+ let l:config = extend(deepcopy(l:val), get(g:vimtex_fold_types, l:key, {}))
+ if get(l:config, 'enabled', 1)
+ let a:state.fold_types_dict[l:key] = vimtex#fold#{l:key}#new(l:config)
+ endif
+ endfor
+
+ "
+ " Define ordered list and the global fold regex
+ "
+ let a:state.fold_types_ordered = []
+ let a:state.fold_re = '\v'
+ \ . '\\%(begin|end)>'
+ \ . '|^\s*\%'
+ \ . '|^\s*\]\s*%(\{|$)'
+ \ . '|^\s*}'
+ for l:name in [
+ \ 'preamble',
+ \ 'cmd_single',
+ \ 'cmd_single_opt',
+ \ 'cmd_multi',
+ \ 'cmd_addplot',
+ \ 'sections',
+ \ 'markers',
+ \ 'comments',
+ \ 'envs',
+ \ 'env_options',
+ \]
+ let l:type = get(a:state.fold_types_dict, l:name, {})
+ if !empty(l:type)
+ call add(a:state.fold_types_ordered, l:type)
+ if exists('l:type.re.fold_re')
+ let a:state.fold_re .= '|' . l:type.re.fold_re
+ endif
+ endif
+ endfor
+endfunction
+
+" }}}1
+
+function! vimtex#fold#refresh(map) abort " {{{1
+ setlocal foldmethod=expr
+ execute 'normal!' a:map
+ setlocal foldmethod=manual
+endfunction
+
+" }}}1
+function! vimtex#fold#level(lnum) abort " {{{1
+ let l:line = getline(a:lnum)
+
+ " Filter out lines that do not start any folds (optimization)
+ if l:line !~# b:vimtex.fold_re | return '=' | endif
+
+ " Never fold \begin|end{document}
+ if l:line =~# '^\s*\\\%(begin\|end\){document}'
+ return 0
+ endif
+
+ for l:type in b:vimtex.fold_types_ordered
+ let l:value = l:type.level(l:line, a:lnum)
+ if !empty(l:value) | return l:value | endif
+ endfor
+
+ " Return foldlevel of previous line
+ return '='
+endfunction
+
+" }}}1
+function! vimtex#fold#text() abort " {{{1
+ let l:line = getline(v:foldstart)
+ let l:level = v:foldlevel > 1
+ \ ? repeat('-', v:foldlevel-2) . g:vimtex_fold_levelmarker
+ \ : ''
+
+ for l:type in b:vimtex.fold_types_ordered
+ if l:line =~# l:type.re.start
+ let l:text = l:type.text(l:line, l:level)
+ if !empty(l:text) | return l:text | endif
+ endif
+ endfor
+endfunction
+
+" }}}1
+
+
+function! s:foldmethod_in_modeline() abort " {{{1
+ let l:cursor_pos = vimtex#pos#get_cursor()
+ let l:fdm_modeline = 'vim:.*\%(foldmethod\|fdm\)'
+
+ call vimtex#pos#set_cursor(1, 1)
+ let l:check_top = search(l:fdm_modeline, 'cn', &modelines)
+
+ normal! G$
+ let l:check_btm = search(l:fdm_modeline, 'b', line('$') + 1 - &modelines)
+
+ call vimtex#pos#set_cursor(l:cursor_pos)
+ return l:check_top || l:check_btm
+endfunction
+
+" }}}1
+
+endif