summaryrefslogtreecommitdiffstats
path: root/autoload/vimtex/parser
diff options
context:
space:
mode:
Diffstat (limited to 'autoload/vimtex/parser')
-rw-r--r--autoload/vimtex/parser/auxiliary.vim58
-rw-r--r--autoload/vimtex/parser/bib.vim370
-rw-r--r--autoload/vimtex/parser/fls.vim19
-rw-r--r--autoload/vimtex/parser/tex.vim205
-rw-r--r--autoload/vimtex/parser/toc.vim782
5 files changed, 0 insertions, 1434 deletions
diff --git a/autoload/vimtex/parser/auxiliary.vim b/autoload/vimtex/parser/auxiliary.vim
deleted file mode 100644
index b8805ebd..00000000
--- a/autoload/vimtex/parser/auxiliary.vim
+++ /dev/null
@@ -1,58 +0,0 @@
-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#parser#auxiliary#parse(file) abort " {{{1
- return s:parse_recurse(a:file, [])
-endfunction
-
-" }}}1
-
-function! s:parse_recurse(file, parsed) abort " {{{1
- if !filereadable(a:file) || index(a:parsed, a:file) >= 0
- return []
- endif
- call add(a:parsed, a:file)
-
- let l:lines = []
- for l:line in readfile(a:file)
- call add(l:lines, l:line)
-
- if l:line =~# '\\@input{'
- let l:file = s:input_line_parser(l:line, a:file)
- call extend(l:lines, s:parse_recurse(l:file, a:parsed))
- endif
- endfor
-
- return l:lines
-endfunction
-
-" }}}1
-
-function! s:input_line_parser(line, file) abort " {{{1
- let l:file = matchstr(a:line, '\\@input{\zs[^}]\+\ze}')
-
- " Remove extension to simplify the parsing (e.g. for "my file name".aux)
- let l:file = substitute(l:file, '\.aux', '', '')
-
- " Trim whitespaces and quotes from beginning/end of string, append extension
- let l:file = substitute(l:file, '^\(\s\|"\)*', '', '')
- let l:file = substitute(l:file, '\(\s\|"\)*$', '', '')
- let l:file .= '.aux'
-
- " Use absolute paths
- if l:file !~# '\v^(\/|[A-Z]:)'
- let l:file = fnamemodify(a:file, ':p:h') . '/' . l:file
- endif
-
- " Only return filename if it is readable
- return filereadable(l:file) ? l:file : ''
-endfunction
-
-" }}}1
-
-endif
diff --git a/autoload/vimtex/parser/bib.vim b/autoload/vimtex/parser/bib.vim
deleted file mode 100644
index 7ea2c238..00000000
--- a/autoload/vimtex/parser/bib.vim
+++ /dev/null
@@ -1,370 +0,0 @@
-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#parser#bib#parse(file, opts) abort " {{{1
- if !filereadable(a:file) | return [] | endif
-
- let l:backend = get(a:opts, 'backend', g:vimtex_parser_bib_backend)
-
- if l:backend ==# 'bibtex'
- if !executable('bibtex') | let l:backend = 'vim' | endif
- elseif l:backend ==# 'bibparse'
- if !executable('bibparse') | let l:backend = 'vim' | endif
- else
- let l:backend = 'vim'
- endif
-
- return s:parse_with_{l:backend}(a:file)
-endfunction
-
-" }}}1
-
-
-function! s:parse_with_bibtex(file) abort " {{{1
- call s:parse_with_bibtex_init()
- if s:bibtex_not_executable | return [] | endif
-
- " Define temporary files
- let tmp = {
- \ 'aux' : 'tmpfile.aux',
- \ 'bbl' : 'tmpfile.bbl',
- \ 'blg' : 'tmpfile.blg',
- \ }
-
- " Write temporary aux file
- call writefile([
- \ '\citation{*}',
- \ '\bibstyle{' . s:bibtex_bstfile . '}',
- \ '\bibdata{' . fnamemodify(a:file, ':r') . '}',
- \ ], tmp.aux)
-
- " Create the temporary bbl file
- call vimtex#process#run('bibtex -terse ' . fnameescape(tmp.aux), {
- \ 'background' : 0,
- \ 'silent' : 1,
- \})
-
- " Parse temporary bbl file
- let lines = join(readfile(tmp.bbl), "\n")
- let lines = substitute(lines, '\n\n\@!\(\s\=\)\s*\|{\|}', '\1', 'g')
- let lines = vimtex#util#tex2unicode(lines)
- let lines = split(lines, "\n")
-
- let l:entries = []
- for line in lines
- let matches = split(line, '||')
- if empty(matches) || empty(matches[0]) | continue | endif
-
- let l:entry = {
- \ 'key': matches[0],
- \ 'type': matches[1],
- \}
-
- if !empty(matches[2])
- let l:entry.author = matches[2]
- endif
- if !empty(matches[3])
- let l:entry.year = matches[3]
- endif
- if !empty(get(matches, 4, ''))
- let l:entry.title = get(matches, 4, '')
- endif
-
- call add(l:entries, l:entry)
- endfor
-
- " Clean up
- call delete(tmp.aux)
- call delete(tmp.bbl)
- call delete(tmp.blg)
-
- return l:entries
-endfunction
-
-" }}}1
-function! s:parse_with_bibtex_init() abort " {{{1
- if exists('s:bibtex_init_done') | return | endif
-
- " Check if bibtex is executable
- let s:bibtex_not_executable = !executable('bibtex')
- if s:bibtex_not_executable
- call vimtex#log#warning(
- \ 'bibtex is not executable and may not be used to parse bib files!')
- endif
-
- " Check if bstfile contains whitespace (not handled by vimtex)
- if stridx(s:bibtex_bstfile, ' ') >= 0
- let l:oldbst = s:bibtex_bstfile . '.bst'
- let s:bibtex_bstfile = tempname()
- call writefile(readfile(l:oldbst), s:bibtex_bstfile . '.bst')
- endif
-
- let s:bibtex_init_done = 1
-endfunction
-
-let s:bibtex_bstfile = expand('<sfile>:p:h') . '/vimcomplete'
-
-" }}}1
-
-function! s:parse_with_bibparse(file) abort " {{{1
- call s:parse_with_bibparse_init()
- if s:bibparse_not_executable | return [] | endif
-
- call vimtex#process#run('bibparse ' . fnameescape(a:file)
- \ . ' >_vimtex_bibparsed.log', {'background' : 0, 'silent' : 1})
- let l:lines = readfile('_vimtex_bibparsed.log')
- call delete('_vimtex_bibparsed.log')
-
- let l:current = {}
- let l:entries = []
- for l:line in l:lines
- if l:line[0] ==# '@'
- if !empty(l:current)
- call add(l:entries, l:current)
- let l:current = {}
- endif
-
- let l:index = stridx(l:line, ' ')
- if l:index > 0
- let l:type = l:line[1:l:index-1]
- let l:current.type = l:type
- let l:current.key = l:line[l:index+1:]
- endif
- elseif !empty(l:current)
- let l:index = stridx(l:line, '=')
- if l:index < 0 | continue | endif
-
- let l:key = l:line[:l:index-1]
- let l:value = l:line[l:index+1:]
- let l:current[tolower(l:key)] = l:value
- endif
- endfor
-
- if !empty(l:current)
- call add(l:entries, l:current)
- endif
-
- return l:entries
-endfunction
-
-" }}}1
-function! s:parse_with_bibparse_init() abort " {{{1
- if exists('s:bibparse_init_done') | return | endif
-
- " Check if bibtex is executable
- let s:bibparse_not_executable = !executable('bibparse')
- if s:bibparse_not_executable
- call vimtex#log#warning(
- \ 'bibparse is not executable and may not be used to parse bib files!')
- endif
-
- let s:bibparse_init_done = 1
-endfunction
-
-" }}}1
-
-function! s:parse_with_vim(file) abort " {{{1
- " Adheres to the format description found here:
- " http://www.bibtex.org/Format/
-
- if !filereadable(a:file)
- return []
- endif
-
- let l:current = {}
- let l:strings = {}
- let l:entries = []
- for l:line in filter(readfile(a:file), 'v:val !~# ''^\s*\%(%\|$\)''')
- if empty(l:current)
- if s:parse_type(l:line, l:current, l:strings)
- let l:current = {}
- endif
- continue
- endif
-
- if l:current.type ==# 'string'
- if s:parse_string(l:line, l:current, l:strings)
- let l:current = {}
- endif
- else
- if s:parse_entry(l:line, l:current, l:entries)
- let l:current = {}
- endif
- endif
- endfor
-
- return map(l:entries, 's:parse_entry_body(v:val, l:strings)')
-endfunction
-
-" }}}1
-
-function! s:parse_type(line, current, strings) abort " {{{1
- let l:matches = matchlist(a:line, '\v^\@(\w+)\s*\{\s*(.*)')
- if empty(l:matches) | return 0 | endif
-
- let l:type = tolower(l:matches[1])
- if index(['preamble', 'comment'], l:type) >= 0 | return 0 | endif
-
- let a:current.level = 1
- let a:current.body = ''
-
- if l:type ==# 'string'
- return s:parse_string(l:matches[2], a:current, a:strings)
- else
- let a:current.type = l:type
- let a:current.key = matchstr(l:matches[2], '.*\ze,\s*')
- return 0
- endif
-endfunction
-
-" }}}1
-function! s:parse_string(line, string, strings) abort " {{{1
- let a:string.level += s:count(a:line, '{') - s:count(a:line, '}')
- if a:string.level > 0
- let a:string.body .= a:line
- return 0
- endif
-
- let a:string.body .= matchstr(a:line, '.*\ze}')
-
- let l:matches = matchlist(a:string.body, '\v^\s*(\w+)\s*\=\s*"(.*)"\s*$')
- if !empty(l:matches) && !empty(l:matches[1])
- let a:strings[l:matches[1]] = l:matches[2]
- endif
-
- return 1
-endfunction
-
-" }}}1
-function! s:parse_entry(line, entry, entries) abort " {{{1
- let a:entry.level += s:count(a:line, '{') - s:count(a:line, '}')
- if a:entry.level > 0
- let a:entry.body .= a:line
- return 0
- endif
-
- let a:entry.body .= matchstr(a:line, '.*\ze}')
-
- call add(a:entries, a:entry)
- return 1
-endfunction
-
-" }}}1
-
-function! s:parse_entry_body(entry, strings) abort " {{{1
- unlet a:entry.level
-
- let l:key = ''
- let l:pos = matchend(a:entry.body, '^\s*')
- while l:pos >= 0
- if empty(l:key)
- let [l:key, l:pos] = s:get_key(a:entry.body, l:pos)
- else
- let [l:value, l:pos] = s:get_value(a:entry.body, l:pos, a:strings)
- let a:entry[l:key] = l:value
- let l:key = ''
- endif
- endwhile
-
- unlet a:entry.body
- return a:entry
-endfunction
-
-" }}}1
-function! s:get_key(body, head) abort " {{{1
- " Parse the key part of a bib entry tag.
- " Assumption: a:body is left trimmed and either empty or starts with a key.
- " Returns: The key and the remaining part of the entry body.
-
- let l:matches = matchlist(a:body, '^\v(\w+)\s*\=\s*', a:head)
- return empty(l:matches)
- \ ? ['', -1]
- \ : [tolower(l:matches[1]), a:head + strlen(l:matches[0])]
-endfunction
-
-" }}}1
-function! s:get_value(body, head, strings) abort " {{{1
- " Parse the value part of a bib entry tag, until separating comma or end.
- " Assumption: a:body is left trimmed and either empty or starts with a value.
- " Returns: The value and the remaining part of the entry body.
- "
- " A bib entry value is either
- " 1. A number.
- " 2. A concatenation (with #s) of double quoted strings, curlied strings,
- " and/or bibvariables,
- "
- if a:body[a:head] =~# '\d'
- let l:value = matchstr(a:body, '^\d\+', a:head)
- let l:head = matchend(a:body, '^\s*,\s*', a:head + len(l:value))
- return [l:value, l:head]
- else
- return s:get_value_string(a:body, a:head, a:strings)
- endif
-
- return ['s:get_value failed', -1]
-endfunction
-
-" }}}1
-function! s:get_value_string(body, head, strings) abort " {{{1
- if a:body[a:head] ==# '{'
- let l:sum = 1
- let l:i1 = a:head + 1
- let l:i0 = l:i1
-
- while l:sum > 0
- let [l:match, l:_, l:i1] = matchstrpos(a:body, '[{}]', l:i1)
- if l:i1 < 0 | break | endif
-
- let l:i0 = l:i1
- let l:sum += l:match ==# '{' ? 1 : -1
- endwhile
-
- let l:value = a:body[a:head+1:l:i0-2]
- let l:head = matchend(a:body, '^\s*', l:i0)
- elseif a:body[a:head] ==# '"'
- let l:index = match(a:body, '\\\@<!"', a:head+1)
- if l:index < 0
- return ['s:get_value_string failed', '']
- endif
-
- let l:value = a:body[a:head+1:l:index-1]
- let l:head = matchend(a:body, '^\s*', l:index+1)
- return [l:value, l:head]
- elseif a:body[a:head:] =~# '^\w'
- let l:value = matchstr(a:body, '^\w\+', a:head)
- let l:head = matchend(a:body, '^\s*', a:head + strlen(l:value))
- let l:value = get(a:strings, l:value, '@(' . l:value . ')')
- else
- let l:head = a:head
- endif
-
- if a:body[l:head] ==# '#'
- let l:head = matchend(a:body, '^\s*', l:head + 1)
- let [l:vadd, l:head] = s:get_value_string(a:body, l:head, a:strings)
- let l:value .= l:vadd
- endif
-
- return [l:value, matchend(a:body, '^,\s*', l:head)]
-endfunction
-
-" }}}1
-
-function! s:count(container, item) abort " {{{1
- " Necessary because in old Vim versions, count() does not work for strings
- try
- let l:count = count(a:container, a:item)
- catch /E712/
- let l:count = count(split(a:container, '\zs'), a:item)
- endtry
-
- return l:count
-endfunction
-
-" }}}1
-
-endif
diff --git a/autoload/vimtex/parser/fls.vim b/autoload/vimtex/parser/fls.vim
deleted file mode 100644
index 46b0db2f..00000000
--- a/autoload/vimtex/parser/fls.vim
+++ /dev/null
@@ -1,19 +0,0 @@
-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#parser#fls#parse(file) abort " {{{1
- if !filereadable(a:file)
- return []
- endif
-
- return readfile(a:file)
-endfunction
-
-" }}}1
-
-endif
diff --git a/autoload/vimtex/parser/tex.vim b/autoload/vimtex/parser/tex.vim
deleted file mode 100644
index 6259b5fa..00000000
--- a/autoload/vimtex/parser/tex.vim
+++ /dev/null
@@ -1,205 +0,0 @@
-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#parser#tex#parse(file, opts) abort " {{{1
- let l:opts = extend({
- \ 'detailed': 1,
- \ 'root' : exists('b:vimtex.root') ? b:vimtex.root : '',
- \}, a:opts)
-
- let l:cache = vimtex#cache#open('texparser', {
- \ 'local': 1,
- \ 'persistent': 0,
- \ 'default': {'ftime': -2},
- \})
-
- let l:parsed = s:parse(a:file, l:opts, l:cache)
-
- if !l:opts.detailed
- call map(l:parsed, 'v:val[2]')
- endif
-
- return l:parsed
-endfunction
-
-" }}}1
-function! vimtex#parser#tex#parse_files(file, opts) abort " {{{1
- let l:opts = extend({
- \ 'root' : exists('b:vimtex.root') ? b:vimtex.root : '',
- \}, a:opts)
-
- let l:cache = vimtex#cache#open('texparser', {
- \ 'local': 1,
- \ 'persistent': 0,
- \ 'default': {'ftime': -2},
- \})
-
- return vimtex#util#uniq_unsorted(
- \ s:parse_files(a:file, l:opts, l:cache))
-endfunction
-
-" }}}1
-function! vimtex#parser#tex#parse_preamble(file, opts) abort " {{{1
- let l:opts = extend({
- \ 'inclusive' : 0,
- \ 'root' : exists('b:vimtex.root') ? b:vimtex.root : '',
- \}, a:opts)
-
- return s:parse_preamble(a:file, l:opts, [])
-endfunction
-
-" }}}1
-
-function! s:parse(file, opts, cache) abort " {{{1
- let l:current = a:cache.get(a:file)
- let l:ftime = getftime(a:file)
- if l:ftime > l:current.ftime
- let l:current.ftime = l:ftime
- call s:parse_current(a:file, a:opts, l:current)
- endif
-
- let l:parsed = []
-
- for l:val in l:current.lines
- if type(l:val) == type([])
- call add(l:parsed, l:val)
- else
- call extend(l:parsed, s:parse(l:val, a:opts, a:cache))
- endif
- endfor
-
- return l:parsed
-endfunction
-
-" }}}1
-function! s:parse_files(file, opts, cache) abort " {{{1
- let l:current = a:cache.get(a:file)
- let l:ftime = getftime(a:file)
- if l:ftime > l:current.ftime
- let l:current.ftime = l:ftime
- call s:parse_current(a:file, a:opts, l:current)
- endif
-
- " Only include existing files
- if !filereadable(a:file) | return [] | endif
-
- let l:files = [a:file]
- for l:file in l:current.includes
- let l:files += s:parse_files(l:file, a:opts, a:cache)
- endfor
-
- return l:files
-endfunction
-
-" }}}1
-function! s:parse_current(file, opts, current) abort " {{{1
- let a:current.lines = []
- let a:current.includes = []
-
- " Also load includes from glsentries
- let l:re_input = g:vimtex#re#tex_input . '|^\s*\\loadglsentries'
-
- if filereadable(a:file)
- let l:lnum = 0
- for l:line in readfile(a:file)
- let l:lnum += 1
- call add(a:current.lines, [a:file, l:lnum, l:line])
-
- " Minor optimization: Avoid complex regex on "simple" lines
- if stridx(l:line, '\') < 0 | continue | endif
-
- if l:line =~# l:re_input
- let l:file = s:input_parser(l:line, a:file, a:opts.root)
- call add(a:current.lines, l:file)
- call add(a:current.includes, l:file)
- endif
- endfor
- endif
-endfunction
-
-" }}}1
-function! s:parse_preamble(file, opts, parsed_files) abort " {{{1
- if !filereadable(a:file) || index(a:parsed_files, a:file) >= 0
- return []
- endif
- call add(a:parsed_files, a:file)
-
- let l:lines = []
- for l:line in readfile(a:file)
- if l:line =~# '\\begin\s*{document}'
- if a:opts.inclusive
- call add(l:lines, l:line)
- endif
- break
- endif
-
- call add(l:lines, l:line)
-
- if l:line =~# g:vimtex#re#tex_input
- let l:file = s:input_parser(l:line, a:file, a:opts.root)
- call extend(l:lines, s:parse_preamble(l:file, a:opts, a:parsed_files))
- endif
- endfor
-
- return l:lines
-endfunction
-
-" }}}1
-
-function! s:input_parser(line, current_file, root) abort " {{{1
- " Handle \space commands
- let l:file = substitute(a:line, '\\space\s*', ' ', 'g')
-
- " Handle import package commands
- if l:file =~# g:vimtex#re#tex_input_import
- let l:root = l:file =~# '\\sub'
- \ ? fnamemodify(a:current_file, ':p:h')
- \ : a:root
-
- let l:candidate = s:input_to_filename(
- \ substitute(copy(l:file), '}\s*{', '', 'g'), l:root)
- if !empty(l:candidate)
- return l:candidate
- else
- return s:input_to_filename(
- \ substitute(copy(l:file), '{.{-}}', '', ''), l:root)
- endif
- else
- return s:input_to_filename(l:file, a:root)
- endif
-endfunction
-
-" }}}1
-function! s:input_to_filename(input, root) abort " {{{1
- let l:file = matchstr(a:input, '\zs[^{}]\+\ze}\s*\%(%\|$\)')
-
- " Trim whitespaces and quotes from beginning/end of string
- let l:file = substitute(l:file, '^\(\s\|"\)*', '', '')
- let l:file = substitute(l:file, '\(\s\|"\)*$', '', '')
-
- " Ensure that the file name has extension
- if empty(fnamemodify(l:file, ':e'))
- let l:file .= '.tex'
- endif
-
- if vimtex#paths#is_abs(l:file)
- return l:file
- endif
-
- let l:candidate = a:root . '/' . l:file
- if filereadable(l:candidate)
- return l:candidate
- endif
-
- let l:candidate = vimtex#kpsewhich#find(l:file)
- return filereadable(l:candidate) ? l:candidate : l:file
-endfunction
-
-" }}}1
-
-endif
diff --git a/autoload/vimtex/parser/toc.vim b/autoload/vimtex/parser/toc.vim
deleted file mode 100644
index a518ce53..00000000
--- a/autoload/vimtex/parser/toc.vim
+++ /dev/null
@@ -1,782 +0,0 @@
-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
-"
-"
-" Parses tex project for ToC-like entries. Each entry is a dictionary
-" similar to the following:
-"
-" entry = {
-" title : "Some title",
-" number : "3.1.2",
-" file : /path/to/file.tex,
-" line : 142,
-" rank : cumulative line number,
-" level : 2,
-" type : [content | label | todo | include],
-" link : [0 | 1],
-" }
-"
-
-function! vimtex#parser#toc#parse(file) abort " {{{1
- let l:entries = []
- let l:content = vimtex#parser#tex(a:file)
-
- let l:max_level = 0
- for [l:file, l:lnum, l:line] in l:content
- if l:line =~# s:matcher_sections.re
- let l:max_level = max([
- \ l:max_level,
- \ s:sec_to_value[matchstr(l:line, s:matcher_sections.re_level)]
- \])
- endif
- endfor
-
- call s:level.reset('preamble', l:max_level)
-
- " No more parsing if there is no content
- if empty(l:content) | return l:entries | endif
-
- "
- " Begin parsing LaTeX files
- "
- let l:lnum_total = 0
- let l:matchers = s:matchers_preamble
- for [l:file, l:lnum, l:line] in l:content
- let l:lnum_total += 1
- let l:context = {
- \ 'file' : l:file,
- \ 'line' : l:line,
- \ 'lnum' : l:lnum,
- \ 'lnum_total' : l:lnum_total,
- \ 'level' : s:level,
- \ 'max_level' : l:max_level,
- \ 'entry' : get(l:entries, -1, {}),
- \ 'num_entries' : len(l:entries),
- \}
-
- " Detect end of preamble
- if s:level.preamble && l:line =~# '\v^\s*\\begin\{document\}'
- let s:level.preamble = 0
- let l:matchers = s:matchers_content
- continue
- endif
-
- " Handle multi-line entries
- if exists('s:matcher_continue')
- call s:matcher_continue.continue(l:context)
- continue
- endif
-
- " Apply prefilter - this gives considerable speedup for large documents
- if l:line !~# s:re_prefilter | continue | endif
-
- " Apply the matchers
- for l:matcher in l:matchers
- if l:line =~# l:matcher.re
- let l:entry = l:matcher.get_entry(l:context)
- if type(l:entry) == type([])
- call extend(l:entries, l:entry)
- elseif !empty(l:entry)
- call add(l:entries, l:entry)
- endif
- endif
- endfor
- endfor
-
- for l:matcher in s:matchers
- try
- call l:matcher.filter(l:entries)
- catch /E716/
- endtry
- endfor
-
- return l:entries
-endfunction
-
-" }}}1
-function! vimtex#parser#toc#get_topmatters() abort " {{{1
- let l:topmatters = s:level.frontmatter
- let l:topmatters += s:level.mainmatter
- let l:topmatters += s:level.appendix
- let l:topmatters += s:level.backmatter
-
- for l:level in get(s:level, 'old', [])
- let l:topmatters += l:level.frontmatter
- let l:topmatters += l:level.mainmatter
- let l:topmatters += l:level.appendix
- let l:topmatters += l:level.backmatter
- endfor
-
- return l:topmatters
-endfunction
-
-" }}}1
-function! vimtex#parser#toc#get_entry_general(context) abort dict " {{{1
- return {
- \ 'title' : self.title,
- \ 'number' : '',
- \ 'file' : a:context.file,
- \ 'line' : a:context.lnum,
- \ 'rank' : a:context.lnum_total,
- \ 'level' : 0,
- \ 'type' : 'content',
- \}
-endfunction
-
-" }}}1
-
-" IMPORTANT: The following defines a prefilter for optimizing the toc parser.
-" Any line that should be parsed has to be matched by this regexp!
-" {{{1 let s:re_prefilter = ...
-let s:re_prefilter = '\v%(\\' . join([
- \ '%(front|main|back)matter',
- \ 'add%(global|section)?bib',
- \ 'appendix',
- \ 'begin',
- \ 'bibliography',
- \ 'chapter',
- \ 'documentclass',
- \ 'import',
- \ 'include',
- \ 'includegraphics',
- \ 'input',
- \ 'label',
- \ 'part',
- \ 'printbib',
- \ 'printindex',
- \ 'paragraph',
- \ 'section',
- \ 'subfile',
- \ 'tableofcontents',
- \ 'todo',
- \], '|') . ')'
- \ . '|\%\s*%(' . join(keys(g:vimtex_toc_todo_labels), '|') . ')'
- \ . '|\%\s*vimtex-include'
-for s:m in g:vimtex_toc_custom_matchers
- if has_key(s:m, 'prefilter')
- let s:re_prefilter .= '|' . s:m.prefilter
- endif
-endfor
-
-" }}}1
-
-" Adds entries for included files
-let s:matcher_include = {
- \ 're' : vimtex#re#tex_input . '\zs\f{-}\s*\ze\}',
- \ 'in_preamble' : 1,
- \ 'priority' : 0,
- \}
-function! s:matcher_include.get_entry(context) abort dict " {{{1
- let l:file = matchstr(a:context.line, self.re)
- if !vimtex#paths#is_abs(l:file[0])
- let l:file = b:vimtex.root . '/' . l:file
- endif
- let l:file = fnamemodify(l:file, ':~:.')
- if !filereadable(l:file)
- let l:file .= '.tex'
- endif
- return {
- \ 'title' : 'tex incl: ' . (strlen(l:file) < 70
- \ ? l:file
- \ : l:file[0:30] . '...' . l:file[-36:]),
- \ 'number' : '',
- \ 'file' : l:file,
- \ 'line' : 1,
- \ 'level' : a:context.max_level - a:context.level.current,
- \ 'rank' : a:context.lnum_total,
- \ 'type' : 'include',
- \ }
-endfunction
-
-" }}}1
-
-" Adds entries for included graphics files (filetype tikz, tex)
-let s:matcher_include_graphics = {
- \ 're' : '\v^\s*\\includegraphics\*?%(\s*\[[^]]*\]){0,2}\s*\{\zs[^}]*',
- \ 'priority' : 1,
- \}
-function! s:matcher_include_graphics.get_entry(context) abort dict " {{{1
- let l:file = matchstr(a:context.line, self.re)
- if !vimtex#paths#is_abs(l:file)
- let l:file = vimtex#misc#get_graphicspath(l:file)
- endif
- let l:file = fnamemodify(l:file, ':~:.')
- let l:ext = fnamemodify(l:file, ':e')
-
- return !filereadable(l:file) || index(['asy', 'tikz'], l:ext) < 0
- \ ? {}
- \ : {
- \ 'title' : 'fig incl: ' . (strlen(l:file) < 70
- \ ? l:file
- \ : l:file[0:30] . '...' . l:file[-36:]),
- \ 'number' : '',
- \ 'file' : l:file,
- \ 'line' : 1,
- \ 'level' : a:context.max_level - a:context.level.current,
- \ 'rank' : a:context.lnum_total,
- \ 'type' : 'include',
- \ 'link' : 1,
- \ }
-endfunction
-
-" }}}1
-
-" Adds entries for included files through vimtex specific syntax (this allows
-" to add entries for any filetype or file)
-let s:matcher_include_vimtex = {
- \ 're' : '^\s*%\s*vimtex-include:\?\s\+\zs\f\+',
- \ 'in_preamble' : 1,
- \ 'priority' : 1,
- \}
-function! s:matcher_include_vimtex.get_entry(context) abort dict " {{{1
- let l:file = matchstr(a:context.line, self.re)
- if !vimtex#paths#is_abs(l:file)
- let l:file = b:vimtex.root . '/' . l:file
- endif
- let l:file = fnamemodify(l:file, ':~:.')
- return {
- \ 'title' : 'vtx incl: ' . (strlen(l:file) < 70
- \ ? l:file
- \ : l:file[0:30] . '...' . l:file[-36:]),
- \ 'number' : '',
- \ 'file' : l:file,
- \ 'line' : 1,
- \ 'level' : a:context.max_level - a:context.level.current,
- \ 'rank' : a:context.lnum_total,
- \ 'type' : 'include',
- \ 'link' : 1,
- \ }
-endfunction
-
-" }}}1
-
-let s:matcher_include_bibtex = {
- \ 're' : '\v^\s*\\bibliography\s*\{\zs[^}]+\ze\}',
- \ 'in_preamble' : 1,
- \ 'priority' : 0,
- \}
-function! s:matcher_include_bibtex.get_entry(context) abort dict " {{{1
- let l:entries = []
-
- for l:file in split(matchstr(a:context.line, self.re), ',')
- " Ensure that the file name has extension
- if l:file !~# '\.bib$'
- let l:file .= '.bib'
- endif
-
- call add(l:entries, {
- \ 'title' : printf('bib incl: %-.67s', fnamemodify(l:file, ':t')),
- \ 'number' : '',
- \ 'file' : vimtex#kpsewhich#find(l:file),
- \ 'line' : 1,
- \ 'level' : 0,
- \ 'rank' : a:context.lnum_total,
- \ 'type' : 'include',
- \ 'link' : 1,
- \})
- endfor
-
- return l:entries
-endfunction
-
-" }}}1
-
-let s:matcher_include_biblatex = {
- \ 're' : '\v^\s*\\add(bibresource|globalbib|sectionbib)\s*\{\zs[^}]+\ze\}',
- \ 'in_preamble' : 1,
- \ 'in_content' : 0,
- \ 'priority' : 0,
- \}
-function! s:matcher_include_biblatex.get_entry(context) abort dict " {{{1
- let l:file = matchstr(a:context.line, self.re)
-
- return {
- \ 'title' : printf('bib incl: %-.67s', fnamemodify(l:file, ':t')),
- \ 'number' : '',
- \ 'file' : vimtex#kpsewhich#find(l:file),
- \ 'line' : 1,
- \ 'level' : 0,
- \ 'rank' : a:context.lnum_total,
- \ 'type' : 'include',
- \ 'link' : 1,
- \}
-endfunction
-
-" }}}1
-
-let s:matcher_preamble = {
- \ 're' : '\v^\s*\\documentclass',
- \ 'in_preamble' : 1,
- \ 'in_content' : 0,
- \ 'priority' : 0,
- \}
-function! s:matcher_preamble.get_entry(context) abort " {{{1
- return g:vimtex_toc_show_preamble
- \ ? {
- \ 'title' : 'Preamble',
- \ 'number' : '',
- \ 'file' : a:context.file,
- \ 'line' : a:context.lnum,
- \ 'level' : 0,
- \ 'rank' : a:context.lnum_total,
- \ 'type' : 'content',
- \ }
- \ : {}
-endfunction
-
-" }}}1
-
-let s:matcher_parts = {
- \ 're' : '\v^\s*\\\zs((front|main|back)matter|appendix)>',
- \ 'priority' : 0,
- \}
-function! s:matcher_parts.get_entry(context) abort dict " {{{1
- call a:context.level.reset(
- \ matchstr(a:context.line, self.re),
- \ a:context.max_level)
- return {}
-endfunction
-
-" }}}1
-
-let s:matcher_sections = {
- \ 're' : '\v^\s*\\%(part|chapter|%(sub)*section|%(sub)?paragraph)\*?\s*(\[|\{)',
- \ 're_starred' : '\v^\s*\\%(part|chapter|%(sub)*section)\*',
- \ 're_level' : '\v^\s*\\\zs%(part|chapter|%(sub)*section|%(sub)?paragraph)',
- \ 'priority' : 0,
- \}
-let s:matcher_sections.re_title = s:matcher_sections.re . '\zs.{-}\ze\%?\s*$'
-function! s:matcher_sections.get_entry(context) abort dict " {{{1
- let level = matchstr(a:context.line, self.re_level)
- let type = matchlist(a:context.line, self.re)[1]
- let title = matchstr(a:context.line, self.re_title)
- let number = ''
-
- let [l:end, l:count] = s:find_closing(0, title, 1, type)
- if l:count == 0
- let title = self.parse_title(strpart(title, 0, l:end+1))
- else
- let self.type = type
- let self.count = l:count
- let s:matcher_continue = deepcopy(self)
- endif
-
- if a:context.line !~# self.re_starred
- call a:context.level.increment(level)
- if a:context.line !~# '\v^\s*\\%(sub)?paragraph'
- let number = deepcopy(a:context.level)
- endif
- endif
-
- return {
- \ 'title' : title,
- \ 'number' : number,
- \ 'file' : a:context.file,
- \ 'line' : a:context.lnum,
- \ 'level' : a:context.max_level - a:context.level.current,
- \ 'rank' : a:context.lnum_total,
- \ 'type' : 'content',
- \ }
-endfunction
-
-" }}}1
-function! s:matcher_sections.parse_title(title) abort dict " {{{1
- let l:title = substitute(a:title, '\v%(\]|\})\s*$', '', '')
- return s:clear_texorpdfstring(l:title)
-endfunction
-
-" }}}1
-function! s:matcher_sections.continue(context) abort dict " {{{1
- let [l:end, l:count] = s:find_closing(0, a:context.line, self.count, self.type)
- if l:count == 0
- let a:context.entry.title = self.parse_title(a:context.entry.title . strpart(a:context.line, 0, l:end+1))
- unlet! s:matcher_continue
- else
- let a:context.entry.title .= a:context.line
- let self.count = l:count
- endif
-endfunction
-
-" }}}1
-
-let s:matcher_table_of_contents = {
- \ 'title' : 'Table of contents',
- \ 're' : '\v^\s*\\tableofcontents',
- \ 'priority' : 0,
- \}
-
-let s:matcher_index = {
- \ 'title' : 'Alphabetical index',
- \ 're' : '\v^\s*\\printindex\[?',
- \ 'priority' : 0,
- \}
-
-let s:matcher_titlepage = {
- \ 'title' : 'Titlepage',
- \ 're' : '\v^\s*\\begin\{titlepage\}',
- \ 'priority' : 0,
- \}
-
-let s:matcher_bibliography = {
- \ 'title' : 'Bibliography',
- \ 're' : '\v^\s*\\%('
- \ . 'printbib%(liography|heading)\s*(\{|\[)?'
- \ . '|begin\s*\{\s*thebibliography\s*\}'
- \ . '|bibliography\s*\{)',
- \ 're_biblatex' : '\v^\s*\\printbib%(liography|heading)',
- \ 'priority' : 0,
- \}
-function! s:matcher_bibliography.get_entry(context) abort dict " {{{1
- let l:entry = call('vimtex#parser#toc#get_entry_general', [a:context], self)
-
- if a:context.line !~# self.re_biblatex
- return l:entry
- endif
-
- let self.options = matchstr(a:context.line, self.re_biblatex . '\s*\[\zs.*')
-
- let [l:end, l:count] = s:find_closing(
- \ 0, self.options, !empty(self.options), '[')
- if l:count == 0
- let self.options = strpart(self.options, 0, l:end)
- call self.parse_options(a:context, l:entry)
- else
- let self.count = l:count
- let s:matcher_continue = deepcopy(self)
- endif
-
- return l:entry
-endfunction
-
-" }}}1
-function! s:matcher_bibliography.continue(context) abort dict " {{{1
- let [l:end, l:count] = s:find_closing(0, a:context.line, self.count, '[')
- if l:count == 0
- let self.options .= strpart(a:context.line, 0, l:end)
- unlet! s:matcher_continue
- call self.parse_options(a:context, a:context.entry)
- else
- let self.options .= a:context.line
- let self.count = l:count
- endif
-endfunction
-
-" }}}1
-function! s:matcher_bibliography.parse_options(context, entry) abort dict " {{{1
- " Parse the options
- let l:opt_pairs = map(split(self.options, ','), 'split(v:val, ''='')')
- let l:opts = {}
- for [l:key, l:val] in l:opt_pairs
- let l:key = substitute(l:key, '^\s*\|\s*$', '', 'g')
- let l:val = substitute(l:val, '^\s*\|\s*$', '', 'g')
- let l:val = substitute(l:val, '{\|}', '', 'g')
- let l:opts[l:key] = l:val
- endfor
-
- " Check if entry should appear in the TOC
- let l:heading = get(l:opts, 'heading')
- let a:entry.added_to_toc = l:heading =~# 'intoc\|numbered'
-
- " Check if entry should be numbered
- if l:heading =~# '\v%(sub)?bibnumbered'
- if a:context.level.chapter > 0
- let l:levels = ['chapter', 'section']
- else
- let l:levels = ['section', 'subsection']
- endif
- call a:context.level.increment(l:levels[l:heading =~# '^sub'])
- let a:entry.level = a:context.max_level - a:context.level.current
- let a:entry.number = deepcopy(a:context.level)
- endif
-
- " Parse title
- try
- let a:entry.title = remove(l:opts, 'title')
- catch /E716/
- let a:entry.title = l:heading =~# '^sub' ? 'References' : 'Bibliography'
- endtry
-endfunction
-
-" }}}1
-function! s:matcher_bibliography.filter(entries) abort dict " {{{1
- if !empty(
- \ filter(deepcopy(a:entries), 'get(v:val, "added_to_toc")'))
- call filter(a:entries, 'get(v:val, "added_to_toc", 1)')
- endif
-endfunction
-
-" }}}1
-
-let s:matcher_todos = {
- \ 're' : g:vimtex#re#not_bslash . '\%\s+('
- \ . join(keys(g:vimtex_toc_todo_labels), '|') . ')[ :]+\s*(.*)',
- \ 'in_preamble' : 1,
- \ 'priority' : 2,
- \}
-function! s:matcher_todos.get_entry(context) abort dict " {{{1
- let [l:type, l:text] = matchlist(a:context.line, self.re)[1:2]
- let l:label = g:vimtex_toc_todo_labels[toupper(l:type)]
-
- return {
- \ 'title' : l:label . l:text,
- \ 'number' : '',
- \ 'file' : a:context.file,
- \ 'line' : a:context.lnum,
- \ 'level' : a:context.max_level - a:context.level.current,
- \ 'rank' : a:context.lnum_total,
- \ 'type' : 'todo',
- \ }
-endfunction
-
-" }}}1
-
-let s:matcher_todonotes = {
- \ 're' : g:vimtex#re#not_comment . '\\\w*todo\w*%(\[[^]]*\])?\{\zs.*',
- \ 'priority' : 2,
- \}
-function! s:matcher_todonotes.get_entry(context) abort dict " {{{1
- let title = matchstr(a:context.line, self.re)
-
- let [l:end, l:count] = s:find_closing(0, title, 1, '{')
- if l:count == 0
- let title = strpart(title, 0, l:end)
- else
- let self.count = l:count
- let s:matcher_continue = deepcopy(self)
- endif
-
- let l:label = get(g:vimtex_toc_todo_labels, 'TODO', 'TODO: ')
-
- return {
- \ 'title' : l:label . title,
- \ 'number' : '',
- \ 'file' : a:context.file,
- \ 'line' : a:context.lnum,
- \ 'level' : a:context.max_level - a:context.level.current,
- \ 'rank' : a:context.lnum_total,
- \ 'type' : 'todo',
- \ }
-endfunction
-
-" }}}1
-function! s:matcher_todonotes.continue(context) abort dict " {{{1
- let [l:end, l:count] = s:find_closing(0, a:context.line, self.count, '{')
- if l:count == 0
- let a:context.entry.title .= strpart(a:context.line, 0, l:end)
- unlet! s:matcher_continue
- else
- let a:context.entry.title .= a:context.line
- let self.count = l:count
- endif
-endfunction
-
-" }}}1
-
-let s:matcher_labels = {
- \ 're' : g:vimtex#re#not_comment . '\\label\{\zs.{-}\ze\}',
- \ 'priority' : 1,
- \}
-function! s:matcher_labels.get_entry(context) abort dict " {{{1
- return {
- \ 'title' : matchstr(a:context.line, self.re),
- \ 'number' : '',
- \ 'file' : a:context.file,
- \ 'line' : a:context.lnum,
- \ 'level' : a:context.max_level - a:context.level.current,
- \ 'rank' : a:context.lnum_total,
- \ 'type' : 'label',
- \ }
-endfunction
-" }}}1
-
-let s:matcher_beamer_frame = {
- \ 're' : '^\s*\\begin{frame}',
- \ 'priority' : 0,
- \}
-function! s:matcher_beamer_frame.get_entry(context) abort dict " {{{1
- let l:title = vimtex#util#trim(
- \ matchstr(a:context.line, self.re . '\s*{\zs.*\ze}\s*$'))
-
- return {
- \ 'title' : 'Frame' . (empty(l:title) ? '' : ': ' . l:title),
- \ 'number' : '',
- \ 'file' : a:context.file,
- \ 'line' : a:context.lnum,
- \ 'level' : a:context.max_level - a:context.level.current,
- \ 'rank' : a:context.lnum_total,
- \ 'type' : 'content',
- \ }
-endfunction
-" }}}1
-
-"
-" Utility functions
-"
-function! s:clear_texorpdfstring(title) abort " {{{1
- let l:i1 = match(a:title, '\\texorpdfstring')
- if l:i1 < 0 | return a:title | endif
-
- " Find start of included part
- let [l:i2, l:dummy] = s:find_closing(
- \ match(a:title, '{', l:i1+1), a:title, 1, '{')
- let l:i2 = match(a:title, '{', l:i2+1)
- if l:i2 < 0 | return a:title | endif
-
- " Find end of included part
- let [l:i3, l:dummy] = s:find_closing(l:i2, a:title, 1, '{')
- if l:i3 < 0 | return a:title | endif
-
- return strpart(a:title, 0, l:i1)
- \ . strpart(a:title, l:i2+1, l:i3-l:i2-1)
- \ . s:clear_texorpdfstring(strpart(a:title, l:i3+1))
-endfunction
-
-" }}}1
-function! s:find_closing(start, string, count, type) abort " {{{1
- if a:type ==# '{'
- let l:re = '{\|}'
- let l:open = '{'
- else
- let l:re = '\[\|\]'
- let l:open = '['
- endif
- let l:i2 = a:start-1
- let l:count = a:count
- while l:count > 0
- let l:i2 = match(a:string, l:re, l:i2+1)
- if l:i2 < 0 | break | endif
-
- if a:string[l:i2] ==# l:open
- let l:count += 1
- else
- let l:count -= 1
- endif
- endwhile
-
- return [l:i2, l:count]
-endfunction
-
-" }}}1
-function! s:sort_by_priority(d1, d2) abort " {{{1
- let l:p1 = get(a:d1, 'priority')
- let l:p2 = get(a:d2, 'priority')
- return l:p1 >= l:p2 ? l:p1 > l:p2 : -1
-endfunction
-
-" }}}1
-
-"
-" Section level counter
-"
-let s:level = {}
-function! s:level.reset(part, level) abort dict " {{{1
- if a:part ==# 'preamble'
- let self.old = []
- else
- let self.old += [copy(self)]
- endif
-
- let self.preamble = 0
- let self.frontmatter = 0
- let self.mainmatter = 0
- let self.appendix = 0
- let self.backmatter = 0
- let self.part = 0
- let self.chapter = 0
- let self.section = 0
- let self.subsection = 0
- let self.subsubsection = 0
- let self.subsubsubsection = 0
- let self.paragraph = 0
- let self.subparagraph = 0
- let self.current = a:level
- let self[a:part] = 1
-endfunction
-
-" }}}1
-function! s:level.increment(level) abort dict " {{{1
- let self.current = s:sec_to_value[a:level]
-
- let self.part_toggle = 0
-
- if a:level ==# 'part'
- let self.part += 1
- let self.part_toggle = 1
- elseif a:level ==# 'chapter'
- let self.chapter += 1
- let self.section = 0
- let self.subsection = 0
- let self.subsubsection = 0
- let self.subsubsubsection = 0
- let self.paragraph = 0
- let self.subparagraph = 0
- elseif a:level ==# 'section'
- let self.section += 1
- let self.subsection = 0
- let self.subsubsection = 0
- let self.subsubsubsection = 0
- let self.paragraph = 0
- let self.subparagraph = 0
- elseif a:level ==# 'subsection'
- let self.subsection += 1
- let self.subsubsection = 0
- let self.subsubsubsection = 0
- let self.paragraph = 0
- let self.subparagraph = 0
- elseif a:level ==# 'subsubsection'
- let self.subsubsection += 1
- let self.subsubsubsection = 0
- let self.paragraph = 0
- let self.subparagraph = 0
- elseif a:level ==# 'subsubsubsection'
- let self.subsubsubsection += 1
- let self.paragraph = 0
- let self.subparagraph = 0
- elseif a:level ==# 'paragraph'
- let self.paragraph += 1
- let self.subparagraph = 0
- elseif a:level ==# 'subparagraph'
- let self.subparagraph += 1
- endif
-endfunction
-
-" }}}1
-
-let s:sec_to_value = {
- \ '_' : 0,
- \ 'subparagraph' : 1,
- \ 'paragraph' : 2,
- \ 'subsubsubsection' : 3,
- \ 'subsubsection' : 4,
- \ 'subsection' : 5,
- \ 'section' : 6,
- \ 'chapter' : 7,
- \ 'part' : 8,
- \ }
-
-"
-" Create the lists of matchers
-"
-let s:matchers = map(
- \ filter(items(s:), 'v:val[0] =~# ''^matcher_'''),
- \ 'v:val[1]')
- \ + g:vimtex_toc_custom_matchers
-call sort(s:matchers, function('s:sort_by_priority'))
-
-for s:m in s:matchers
- if !has_key(s:m, 'get_entry')
- let s:m.get_entry = function('vimtex#parser#toc#get_entry_general')
- endif
-endfor
-unlet! s:m
-
-let s:matchers_preamble = filter(
- \ deepcopy(s:matchers), "get(v:val, 'in_preamble')")
-let s:matchers_content = filter(
- \ deepcopy(s:matchers), "get(v:val, 'in_content', 1)")
-
-endif