diff options
Diffstat (limited to 'autoload/vimtex/parser/bib.vim')
-rw-r--r-- | autoload/vimtex/parser/bib.vim | 370 |
1 files changed, 0 insertions, 370 deletions
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 |