From e171ba5a3beba00bd63724116357c1635a8860c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Yngve=20Lerv=C3=A5g?= Date: Sun, 20 Jul 2014 14:47:41 +0200 Subject: [PATCH] Improved TOC (fixes #31) * Syntax works for unnumbered sections * No numbers on frontmatter --- autoload/latex/toc.vim | 98 ++++++++++++++++++++++++++++++++---------- ftplugin/latextoc.vim | 1 + syntax/latextoc.vim | 18 ++++---- 3 files changed, 85 insertions(+), 32 deletions(-) diff --git a/autoload/latex/toc.vim b/autoload/latex/toc.vim index f715ea5..0688373 100644 --- a/autoload/latex/toc.vim +++ b/autoload/latex/toc.vim @@ -25,6 +25,9 @@ function! latex#toc#open() " {{{1 let calling_file = expand('%:p') let calling_line = line('.') + " Parse tex files for max level + let s:max_level = s:set_max_level(g:latex#data[b:latex.id].tex) + " Parse tex files for TOC data let toc = s:parse_file(g:latex#data[b:latex.id].tex, 1) @@ -43,7 +46,11 @@ function! latex#toc#open() " {{{1 let index = 0 let closest_index = 0 for entry in toc - call append('$', entry.number . "\t" . entry.title) + call append('$', + \ printf('%-10s%-140s%s', + \ entry.number, + \ entry.title, + \ s:max_level - entry.level)) let index += 1 if entry.file == calling_file && entry.line <= calling_line @@ -82,6 +89,9 @@ function! latex#toc#toggle() " {{{1 endfunction " }}}1 +" {{{1 TOC number variables +let s:max_level = 0 + " Define dictionary to keep track of TOC numbers let s:number = { \ 'part' : 0, @@ -89,6 +99,8 @@ let s:number = { \ 'section' : 0, \ 'subsection' : 0, \ 'subsubsection' : 0, + \ 'subsubsubsection' : 0, + \ 'current_level' : 0, \ 'preamble' : 0, \ 'frontmatter' : 0, \ 'mainmatter' : 0, @@ -96,11 +108,23 @@ let s:number = { \ 'backmatter' : 0, \ } +" Map for section hierarchy +let s:sec_to_value = { + \ '_' : 0, + \ 'subsubsubsection' : 1, + \ 'subsubsection' : 2, + \ 'subsection' : 3, + \ 'section' : 4, + \ 'chapter' : 5, + \ 'part' : 6, + \ } + " Define regular expressions to match document parts let s:re_input = '\v^\s*\\%(input|include)\s*\{' let s:re_input_file = s:re_input . '\zs[^\}]+\ze}' let s:re_sec = '\v^\s*\\%(part|chapter|%(sub)*section)\*?\s*\{' -let s:re_sec_level = '\v^\s*\\\zs%(part|chapter|%(sub)*section)\*?' +let s:re_sec_starred = '\v^\s*\\%(part|chapter|%(sub)*section)\*' +let s:re_sec_level = '\v^\s*\\\zs%(part|chapter|%(sub)*section)' let s:re_sec_title = s:re_sec . '\zs.{-}\ze\}?$' let s:re_structure = '\v^\s*\\((front|main|back)matter|appendix)>' let s:re_structure_match = '\v((front|main|back)matter|appendix)' @@ -122,6 +146,8 @@ let s:re_other = { \ }, \ } +" }}}1 + function! s:parse_file(file, ...) " {{{1 " Parses tex file for TOC entries " @@ -132,10 +158,10 @@ function! s:parse_file(file, ...) " {{{1 " number : "3.1.2", " file : /path/to/file.tex, " line : 142, + " level : 2, " } - " Test if file is readable - if ! filereadable(a:file) + if !filereadable(a:file) echoerr "Error in latex#toc s:parse_file:" echoerr "File not readable: " . a:file return [] @@ -166,6 +192,7 @@ function! s:parse_file(file, ...) " {{{1 \ 'number' : '', \ 'file' : a:file, \ 'line' : lnum, + \ 'level' : s:max_level, \ }) continue endif @@ -197,6 +224,7 @@ function! s:parse_file(file, ...) " {{{1 \ 'number' : '', \ 'file' : a:file, \ 'line' : lnum, + \ 'level' : s:max_level, \ }) continue endif @@ -216,26 +244,38 @@ endfunction function! s:parse_line_sec(file, lnum, line) " {{{1 let title = matchstr(a:line, s:re_sec_title) - let number = s:number_increment(matchstr(a:line, s:re_sec_level)) + let level = matchstr(a:line, s:re_sec_level) + let starred = a:line =~# s:re_sec_starred ? 1 : 0 + let number = s:number_increment(level, starred) return { \ 'title' : title, \ 'number' : number, \ 'file' : a:file, \ 'line' : a:lnum, + \ 'level' : s:number.current_level, \ } endfunction +" }}}1 + function! s:number_reset(part) " {{{1 for key in keys(s:number) let s:number[key] = 0 endfor let s:number[a:part] = 1 + + " Initialize for preamble + if a:part == 'preamble' + endif endfunction -function! s:number_increment(level) " {{{1 +function! s:number_increment(level, starred) " {{{1 + " Store current level + let s:number.current_level = s:sec_to_value[a:level] + " Check if level should be incremented - if a:level !~# '\v%(part|chapter|(sub)*section)$' + if a:starred return '' endif @@ -246,20 +286,27 @@ function! s:number_increment(level) " {{{1 let s:number.section = 0 let s:number.subsection = 0 let s:number.subsubsection = 0 + let s:number.subsubsubsection = 0 elseif a:level == 'chapter' let s:number.chapter += 1 let s:number.section = 0 let s:number.subsection = 0 let s:number.subsubsection = 0 + let s:number.subsubsubsection = 0 elseif a:level == 'section' let s:number.section += 1 let s:number.subsection = 0 let s:number.subsubsection = 0 + let s:number.subsubsubsection = 0 elseif a:level == 'subsection' let s:number.subsection += 1 let s:number.subsubsection = 0 + let s:number.subsubsubsection = 0 elseif a:level == 'subsubsection' let s:number.subsubsection += 1 + let s:number.subsubsubsection = 0 + elseif a:level == 'subsubsubsection' + let s:number.subsubsubsection += 1 endif return s:number_print() @@ -272,6 +319,7 @@ function! s:number_print() " {{{1 \ s:number.section, \ s:number.subsection, \ s:number.subsubsection, + \ s:number.subsubsubsection, \ ] " Remove unused parts @@ -283,12 +331,10 @@ function! s:number_print() " {{{1 endwhile " Change numbering in frontmatter, appendix, and backmatter - if s:number.frontmatter - call map(number, 's:roman_numeral(v:val)') + if s:number.frontmatter || s:number.backmatter + return "" elseif s:number.appendix let number[0] = nr2char(number[0] + 64) - elseif s:number.backmatter - return "" endif return join(number, '.') @@ -296,19 +342,25 @@ endfunction " }}}1 -function! s:roman_numeral(number) " {{{1 - let n = a:number - let result = "" - for [limit, glyph] in s:digits - while n >= limit - let result .= glyph - let n -= limit - endwhile - endfor - return result -endfunction +function! s:set_max_level(file) " {{{1 + if !filereadable(a:file) + echoerr "Error in latex#toc s:get_depth:" + echoerr "File not readable: " . a:file + return '' + endif -let s:digits = [[10, "x"], [9, "ix"], [5, "v"], [4, "iv"], [1, "i"]] + let n = 0 + + for line in readfile(a:file) + if line =~# s:re_input + let n = max([n, s:set_max_level(s:parse_line_input(line))]) + elseif line =~# s:re_sec + let n = max([n, s:sec_to_value[matchstr(line, s:re_sec_level)]]) + endif + endfor + + return n +endfunction " }}}1 diff --git a/ftplugin/latextoc.vim b/ftplugin/latextoc.vim index 0f5669b..5e445a0 100644 --- a/ftplugin/latextoc.vim +++ b/ftplugin/latextoc.vim @@ -12,6 +12,7 @@ let b:did_ftplugin = 1 " Set local buffer settings setlocal buftype=nofile setlocal bufhidden=wipe +setlocal listchars= setlocal nobuflisted setlocal noswapfile setlocal nowrap diff --git a/syntax/latextoc.vim b/syntax/latextoc.vim index f2b2de6..ce395cb 100644 --- a/syntax/latextoc.vim +++ b/syntax/latextoc.vim @@ -1,15 +1,15 @@ syntax match TocHelpText /^.*: .*/ -syntax match TocNum /^\S\+\(\.\S\+\)\?\s*/ contained conceal -syntax match TocSec /^\t.\+/ -syntax match TocSec1 /^[^\.]\+\t.*/ contains=secNum -syntax match TocSec2 /^\([^\.]\+\.\)\{1}[^\.]\+\t.*/ contains=secNum -syntax match TocSec3 /^\([^\.]\+\.\)\{2}[^\.]\+\t.*/ contains=secNum -syntax match TocSec4 /^\([^\.]\+\.\)\{3}[^\.]\+\t.*/ contains=secNum +syntax match TocNum /^\(\S\+\(\.\S\+\)*\)\?\s*/ contained conceal +syntax match TocSec0 /^.*0$/ contains=TocNum,@Tex +syntax match TocSec1 /^.*1$/ contains=TocNum,@Tex +syntax match TocSec2 /^.*2$/ contains=TocNum,@Tex +syntax match TocSec3 /^.*3$/ contains=TocNum,@Tex +syntax match TocSec4 /^.*4$/ contains=TocNum,@Tex highlight link TocHelpText helpVim highlight link TocNum Number -highlight link TocSec Title -highlight link TocSec1 TocSec -highlight link TocSec2 Normal +highlight link TocSec0 Title +highlight link TocSec1 Normal +highlight link TocSec2 helpVim highlight link TocSec3 NonText highlight link TocSec4 Comment