" LaTeX Box motion functions " Motion options {{{ " Opening and closing patterns if !exists('g:LatexBox_open_pats') let g:LatexBox_open_pats = [ '\\{','{','\\(','(','\\\[','\[', \ '\\begin\s*{.\{-}}', '\\left\s*\%([^\\]\|\\.\|\\\a*\)'] let g:LatexBox_close_pats = [ '\\}','}','\\)',')','\\\]','\]', \ '\\end\s*{.\{-}}', '\\right\s*\%([^\\]\|\\.\|\\\a*\)'] endif " }}} " HasSyntax {{{ " s:HasSyntax(syntaxName, [line], [col]) function! s:HasSyntax(syntaxName, ...) let line = a:0 >= 1 ? a:1 : line('.') let col = a:0 >= 2 ? a:2 : col('.') return index(map(synstack(line, col), \ 'synIDattr(v:val, "name") == "' . a:syntaxName . '"'), \ 1) >= 0 endfunction " }}} " Search and Skip Comments {{{ " s:SearchAndSkipComments(pattern, [flags], [stopline]) function! s:SearchAndSkipComments(pat, ...) let flags = a:0 >= 1 ? a:1 : '' let stopline = a:0 >= 2 ? a:2 : 0 let saved_pos = getpos('.') " search once let ret = search(a:pat, flags, stopline) if ret " do not match at current position if inside comment let flags = substitute(flags, 'c', '', 'g') " keep searching while in comment while LatexBox_InComment() let ret = search(a:pat, flags, stopline) if !ret break endif endwhile endif if !ret " if no match found, restore position call setpos('.', saved_pos) endif return ret endfunction " }}} " Finding Matching Pair {{{ function! s:FindMatchingPair(mode) if a:mode =~ 'h\|i' 2match none elseif a:mode == 'v' normal! gv endif if LatexBox_InComment() | return | endif " open/close pairs (dollars signs are treated apart) let dollar_pat = '\$' let notbslash = '\%(\\\@1 && a:mode =~ 'o' call cursor(lnum2, matchend(getline('.'), '\C' \ . close_pat, col('.')-1)) endif endif break elseif delim =~# '^' . close_pat " if on closing pattern, search for opening pattern let [lnum2, cnum2] = searchpairpos('\C' . open_pat, '', \ '\C\%(\%'. lnum . 'l\%' . cnum . 'c\)\@!' \ . close_pat, 'bnW', 'LatexBox_InComment()', \ line('w0')*(a:mode =~ 'h\|i') , 200) if a:mode =~ 'h\|i' execute '2match MatchParen /\%(\%' . lnum2 . 'l\%' . cnum2 \ . 'c' . g:LatexBox_open_pats[i] . '\|\%' \ . lnum . 'l\%' . cnum . 'c' \ . g:LatexBox_close_pats[i] . '\)/' elseif a:mode =~ 'n\|v\|o' call cursor(lnum2,cnum2) endif break endif endfor endif endfunction " Allow to disable functionality if desired if !exists('g:LatexBox_loaded_matchparen') " Disable matchparen autocommands augroup LatexBox_HighlightPairs autocmd BufEnter * if !exists("g:loaded_matchparen") || !g:loaded_matchparen | runtime plugin/matchparen.vim | endif autocmd BufEnter *.tex 3match none | unlet! g:loaded_matchparen | au! matchparen autocmd! CursorMoved *.tex call s:FindMatchingPair('h') autocmd! CursorMovedI *.tex call s:FindMatchingPair('i') augroup END endif " Use LatexBox'es FindMatchingPair as '%' (enable jump between e.g. $'s) nnoremap LatexBox_JumpToMatch :call FindMatchingPair('n') vnoremap LatexBox_JumpToMatch :call FindMatchingPair('v') onoremap LatexBox_JumpToMatch v:call FindMatchingPair('o') " }}} " select inline math {{{ " s:SelectInlineMath(seltype) " where seltype is either 'inner' or 'outer' function! s:SelectInlineMath(seltype) let dollar_pat = '\\\@ LatexBox_SelectInlineMathInner \ :call SelectInlineMath('inner') vnoremap LatexBox_SelectInlineMathOuter \ :call SelectInlineMath('outer') " }}} " select current environment {{{ function! s:SelectCurrentEnv(seltype) let [env, lnum, cnum, lnum2, cnum2] = LatexBox_GetCurrentEnvironment(1) call cursor(lnum, cnum) if a:seltype == 'inner' if env =~ '^\' call search('\\.\_\s*\S', 'eW') else call search('}\(\_\s*\[\_[^]]*\]\)\?\_\s*\S', 'eW') endif endif if visualmode() ==# 'V' normal! V else normal! v endif call cursor(lnum2, cnum2) if a:seltype == 'inner' call search('\S\_\s*', 'bW') else if env =~ '^\' normal! l else call search('}', 'eW') endif endif endfunction vnoremap LatexBox_SelectCurrentEnvInner :call SelectCurrentEnv('inner') vnoremap LatexBox_SelectCurrentEnvOuter :call SelectCurrentEnv('outer') " }}} " Jump to the next braces {{{ " function! LatexBox_JumpToNextBraces(backward) let flags = '' if a:backward normal h let flags .= 'b' else let flags .= 'c' endif if search('[][}{]', flags) > 0 normal l endif let prev = strpart(getline('.'), col('.') - 2, 1) let next = strpart(getline('.'), col('.') - 1, 1) if next =~ '[]}]' && prev !~ '[][{}]' return "\" else return '' endif endfunction " }}} " Table of Contents {{{ " Special UTF-8 conversion function! s:ConvertBack(line) let line = a:line if exists('g:LatexBox_plaintext_toc') " " Substitute stuff like '\IeC{\"u}' to plain 'u' " let line = substitute(line, '\\IeC\s*{\\.\(.\)}', '\1', 'g') else " " Substitute stuff like '\IeC{\"u}' to corresponding unicode symbols " for [pat, symbol] in s:ConvBackPats let line = substitute(line, pat, symbol, 'g') endfor endif return line endfunction function! s:ReadTOC(auxfile, texfile, ...) let texfile = a:texfile let prefix = fnamemodify(a:auxfile, ':p:h') if a:0 != 2 let toc = [] let fileindices = { texfile : [] } else let toc = a:1 let fileindices = a:2 let fileindices[ texfile ] = [] endif for line in readfile(a:auxfile) let included = matchstr(line, '^\\@input{\zs[^}]*\ze}') if included != '' " append the input TOX to `toc` and `fileindices` let newaux = prefix . '/' . included let newtex = fnamemodify(newaux, ':r') . '.tex' call s:ReadTOC(newaux, newtex, toc, fileindices) continue endif " Parse statements like: " \@writefile{toc}{\contentsline {section}{\numberline {secnum}Section Title}{pagenumber}} " \@writefile{toc}{\contentsline {section}{\tocsection {}{1}{Section Title}}{pagenumber}} " \@writefile{toc}{\contentsline {section}{\numberline {secnum}Section Title}{pagenumber}{otherstuff}} let line = matchstr(line, \ '\\@writefile{toc}{\\contentsline\s*\zs.*\ze}\s*$') if empty(line) continue endif let tree = LatexBox_TexToTree(s:ConvertBack(line)) if len(tree) < 3 " unknown entry type: just skip it continue endif " parse level let level = tree[0][0] " parse page if !empty(tree[2]) let page = tree[2][0] else let page = '' endif " parse section number let secnum = '' let tree = tree[1] if len(tree) > 3 && empty(tree[1]) call remove(tree, 1) endif if len(tree) > 1 && type(tree[0]) == type("") && tree[0] =~ '^\\\(\(chapter\)\?numberline\|tocsection\)' let secnum = LatexBox_TreeToTex(tree[1]) let secnum = substitute(secnum, '\\\S\+\s', '', 'g') let secnum = substitute(secnum, '\\\S\+{\(.\{-}\)}', '\1', 'g') let secnum = substitute(secnum, '^{\+\|}\+$', '', 'g') call remove(tree, 1) endif " parse section title let text = LatexBox_TreeToTex(tree) let text = substitute(text, '^{\+\|}\+$', '', 'g') let text = substitute(text, '\m^\\\(no\)\?\(chapter\)\?numberline\s*', '', '') let text = substitute(text, '\*', '', 'g') " add TOC entry call add(fileindices[texfile], len(toc)) call add(toc, {'file': texfile, \ 'level': level, \ 'number': secnum, \ 'text': text, \ 'page': page}) endfor return [toc, fileindices] endfunction function! LatexBox_TOC(...) " Check if window already exists let winnr = bufwinnr(bufnr('LaTeX TOC')) " Two types of splits, horizontal and vertical let l:hori = "new" let l:vert = "vnew" " Set General Vars and initialize size let l:type = g:LatexBox_split_type let l:size = 10 " Size detection if l:type == l:hori let l:size = g:LatexBox_split_length elseif l:type == l:vert let l:size = g:LatexBox_split_width endif if winnr >= 0 if a:0 == 0 silent execute winnr . 'wincmd w' else " Supplying an argument to this function causes toggling instead " of jumping to the TOC window if g:LatexBox_split_resize silent exe "set columns-=" . l:size endif silent execute 'bwipeout' . bufnr('LaTeX TOC') endif return endif " Read TOC let [toc, fileindices] = s:ReadTOC(LatexBox_GetAuxFile(), \ LatexBox_GetMainTexFile()) let calling_buf = bufnr('%') " Find closest section in current buffer let closest_index = s:FindClosestSection(toc,fileindices) " Create TOC window and set local settings if g:LatexBox_split_resize silent exe "set columns+=" . l:size endif silent exe g:LatexBox_split_side l:size . l:type . ' LaTeX\ TOC' let b:toc = toc let b:toc_numbers = 1 let b:calling_win = bufwinnr(calling_buf) setlocal filetype=latextoc " Add TOC entries and jump to the closest section for entry in toc call append('$', entry['number'] . "\t" . entry['text']) endfor if !g:LatexBox_toc_hidehelp call append('$', "") call append('$', "/q: close") call append('$', ": jump") call append('$', ": jump and close") call append('$', "s: hide numbering") endif 0delete _ execute 'normal! ' . (closest_index + 1) . 'G' " Lock buffer setlocal nomodifiable endfunction " Binary search for the closest section " return the index of the TOC entry function! s:FindClosestSection(toc, fileindices) let file = expand('%:p') if !has_key(a:fileindices, file) return 0 endif let imax = len(a:fileindices[file]) if imax > 0 let imin = 0 while imin < imax - 1 let i = (imax + imin) / 2 let tocindex = a:fileindices[file][i] let entry = a:toc[tocindex] let titlestr = entry['text'] let titlestr = escape(titlestr, '\') let titlestr = substitute(titlestr, ' ', '\\_\\s\\+', 'g') let [lnum, cnum] = searchpos('\\' . entry['level'] . '\_\s*{' . titlestr . '}', 'nW') if lnum let imax = i else let imin = i endif endwhile return a:fileindices[file][imin] else return 0 endif endfunction let s:ConvBackPats = map([ \ ['\\''A}' , 'Á'], \ ['\\`A}' , 'À'], \ ['\\^A}' , 'À'], \ ['\\¨A}' , 'Ä'], \ ['\\"A}' , 'Ä'], \ ['\\''a}' , 'á'], \ ['\\`a}' , 'à'], \ ['\\^a}' , 'à'], \ ['\\¨a}' , 'ä'], \ ['\\"a}' , 'ä'], \ ['\\''E}' , 'É'], \ ['\\`E}' , 'È'], \ ['\\^E}' , 'Ê'], \ ['\\¨E}' , 'Ë'], \ ['\\"E}' , 'Ë'], \ ['\\''e}' , 'é'], \ ['\\`e}' , 'è'], \ ['\\^e}' , 'ê'], \ ['\\¨e}' , 'ë'], \ ['\\"e}' , 'ë'], \ ['\\''I}' , 'Í'], \ ['\\`I}' , 'Î'], \ ['\\^I}' , 'Ì'], \ ['\\¨I}' , 'Ï'], \ ['\\"I}' , 'Ï'], \ ['\\''i}' , 'í'], \ ['\\`i}' , 'î'], \ ['\\^i}' , 'ì'], \ ['\\¨i}' , 'ï'], \ ['\\"i}' , 'ï'], \ ['\\''{\?\\i }' , 'í'], \ ['\\''O}' , 'Ó'], \ ['\\`O}' , 'Ò'], \ ['\\^O}' , 'Ô'], \ ['\\¨O}' , 'Ö'], \ ['\\"O}' , 'Ö'], \ ['\\''o}' , 'ó'], \ ['\\`o}' , 'ò'], \ ['\\^o}' , 'ô'], \ ['\\¨o}' , 'ö'], \ ['\\"o}' , 'ö'], \ ['\\''U}' , 'Ú'], \ ['\\`U}' , 'Ù'], \ ['\\^U}' , 'Û'], \ ['\\¨U}' , 'Ü'], \ ['\\"U}' , 'Ü'], \ ['\\''u}' , 'ú'], \ ['\\`u}' , 'ù'], \ ['\\^u}' , 'û'], \ ['\\¨u}' , 'ü'], \ ['\\"u}' , 'ü'], \ ['\\`N}' , 'Ǹ'], \ ['\\\~N}' , 'Ñ'], \ ['\\''n}' , 'ń'], \ ['\\`n}' , 'ǹ'], \ ['\\\~n}' , 'ñ'], \], '[''\C\(\\IeC\s*{\)\?'' . v:val[0], v:val[1]]') " }}} " TOC Command {{{ command! LatexTOC call LatexBox_TOC() command! LatexTOCToggle call LatexBox_TOC(1) " }}} " vim:fdm=marker:ff=unix:noet:ts=4:sw=4