200 lines
5.1 KiB
VimL
200 lines
5.1 KiB
VimL
" {{{1 latex#toc#init
|
|
function! latex#toc#init(initialized)
|
|
if g:latex_mappings_enabled && g:latex_toc_enabled
|
|
nnoremap <silent><buffer> <LocalLeader>lt :call latex#toc#open()<cr>
|
|
nnoremap <silent><buffer> <LocalLeader>lT :call latex#toc#toggle()<cr>
|
|
endif
|
|
endfunction
|
|
|
|
" {{{1 latex#toc#open
|
|
function! latex#toc#open()
|
|
" Check if buffer exists
|
|
let winnr = bufwinnr(bufnr('LaTeX TOC'))
|
|
if winnr >= 0
|
|
silent execute winnr . 'wincmd w'
|
|
return
|
|
endif
|
|
|
|
" Get file names
|
|
let auxfile = g:latex#data[b:latex.id].aux()
|
|
let texfile = g:latex#data[b:latex.id].tex
|
|
|
|
" Create TOC window
|
|
let calling_buf = bufnr('%')
|
|
let calling_file = expand('%:p')
|
|
if g:latex_toc_resize
|
|
silent exe "set columns+=" . g:latex_toc_width
|
|
endif
|
|
|
|
" Parse TOC data
|
|
if auxfile == ""
|
|
silent exe g:latex_toc_split_side g:latex_toc_width . 'vnew LaTeX\ TOC'
|
|
call append('$', "TeX file not compiled")
|
|
else
|
|
let toc = s:read_toc(auxfile, texfile)
|
|
let closest_index = s:find_closest_section(toc, calling_file)
|
|
let b:toc = toc.data
|
|
let b:toc_numbers = 1
|
|
let b:calling_win = bufwinnr(calling_buf)
|
|
silent exe g:latex_toc_split_side g:latex_toc_width . 'vnew LaTeX\ TOC'
|
|
|
|
" Add TOC entries
|
|
for entry in toc.data
|
|
call append('$', entry['number'] . "\t" . entry['text'])
|
|
endfor
|
|
|
|
" Jump to the closest section
|
|
execute 'normal! ' . (closest_index + 1) . 'G'
|
|
endif
|
|
|
|
" Add help info
|
|
if !g:latex_toc_hide_help
|
|
call append('$', "")
|
|
call append('$', "<Esc>/q: close")
|
|
call append('$', "<Space>: jump")
|
|
call append('$', "<Enter>: jump and close")
|
|
call append('$', "s: hide numbering")
|
|
endif
|
|
0delete _
|
|
|
|
" Set filetype and lock buffer
|
|
setlocal filetype=latextoc
|
|
setlocal nomodifiable
|
|
endfunction
|
|
|
|
" {{{1 latex#toc#toggle
|
|
function! latex#toc#toggle()
|
|
if bufwinnr(bufnr('LaTeX TOC')) >= 0
|
|
if g:latex_toc_resize
|
|
silent exe "set columns-=" . g:latex_toc_width
|
|
endif
|
|
silent execute 'bwipeout' . bufnr('LaTeX TOC')
|
|
else
|
|
call latex#toc#open()
|
|
silent execute 'wincmd w'
|
|
endif
|
|
endfunction
|
|
" }}}1
|
|
|
|
" {{{1 s:read_toc
|
|
function! s:read_toc(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)
|
|
" Check for included files, include if found
|
|
let included = matchstr(line, '^\\@input{\zs[^}]*\ze}')
|
|
if included != ''
|
|
let newaux = prefix . '/' . included
|
|
let newtex = fnamemodify(newaux, ':r') . '.tex'
|
|
call s:read_toc(newaux, newtex, toc, fileindices)
|
|
continue
|
|
endif
|
|
|
|
" Parse TOC statements from aux files
|
|
let line = matchstr(line,
|
|
\ '\\@writefile{toc}{\\contentsline\s*\zs.*\ze}\s*$')
|
|
if empty(line)
|
|
continue
|
|
endif
|
|
|
|
let tree = latex#util#tex2tree(latex#util#convert_back(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 number
|
|
if len(tree[1]) > 3 && empty(tree[1][1])
|
|
call remove(tree[1], 1)
|
|
endif
|
|
if len(tree[1]) > 1
|
|
if !empty(tree[1][1])
|
|
let secnum = latex#util#tree2tex(tree[1][1])
|
|
let secnum = substitute(secnum, '\\\S\+\s', '', 'g')
|
|
let secnum = substitute(secnum, '\\\S\+{\(.\{-}\)}', '\1', 'g')
|
|
let secnum = substitute(secnum, '^{\+\|}\+$', '', 'g')
|
|
endif
|
|
let tree = tree[1][2:]
|
|
else
|
|
let secnum = ''
|
|
let tree = tree[1]
|
|
endif
|
|
|
|
" Parse title
|
|
let text = latex#util#tree2tex(tree)
|
|
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 {'data': toc, 'fileindices': fileindices}
|
|
endfunction
|
|
|
|
" {{{1 s:find_closest_section
|
|
"
|
|
" 1. Binary search for the closest section
|
|
" 2. Return the index of the TOC entry
|
|
"
|
|
function! s:find_closest_section(toc, file)
|
|
if !has_key(a:toc.fileindices, a:file)
|
|
return
|
|
endif
|
|
|
|
let imax = len(a:toc.fileindices[a:file])
|
|
if imax > 0
|
|
let imin = 0
|
|
while imin < imax - 1
|
|
let i = (imax + imin) / 2
|
|
let tocindex = a:toc.fileindices[a:file][i]
|
|
let entry = a:toc.data[tocindex]
|
|
let titlestr = substitute(entry['text'],
|
|
\ '\\\w*\>\s*\%({[^}]*}\)\?', '.*', 'g')
|
|
let titlestr = escape(titlestr, '\')
|
|
let titlestr = substitute(titlestr, ' ', '\\_\\s\\+', 'g')
|
|
let [lnum, cnum]
|
|
\ = searchpos('\\'.entry['level'].'\_\s*{'.titlestr.'}', 'cnW')
|
|
if lnum
|
|
let imax = i
|
|
else
|
|
let imin = i
|
|
endif
|
|
endwhile
|
|
return a:toc.fileindices[a:file][imin]
|
|
else
|
|
return 0
|
|
endif
|
|
endfunction
|
|
|
|
" }}}1
|
|
|
|
" vim:fdm=marker:ff=unix
|