" Vimball Archiver by Charles E. Campbell, Jr., Ph.D. UseVimball finish ftplugin/tex_LatexBox.vim [[[1 21 " LaTeX Box plugin for Vim " Maintainer: David Munger " Email: mungerd@gmail.com " Version: 0.5 if !exists('s:loaded') let prefix = expand(':p:h') . '/latex-box/' execute 'source ' . fnameescape(prefix . 'common.vim') execute 'source ' . fnameescape(prefix . 'complete.vim') execute 'source ' . fnameescape(prefix . 'motion.vim') execute 'source ' . fnameescape(prefix . 'latexmk.vim') let s:loaded = 1 endif execute 'source ' . fnameescape(prefix . 'mappings.vim') " vim:fdm=marker:ff=unix:noet:ts=4:sw=4 ftplugin/latex-box/common.vim [[[1 185 " LaTeX Box common functions " Settings {{{ " Compilation {{{ " g:vim_program {{{ if !exists('g:vim_program') " attempt autodetection of vim executable let g:vim_program = '' let tmpfile = tempname() silent execute '!ps -o command= -p $PPID > ' . tmpfile for line in readfile(tmpfile) let line = matchstr(line, '^\S\+\>') if !empty(line) && executable(line) let g:vim_program = line . ' -g' break endif endfor call delete(tmpfile) if empty(g:vim_program) if has('gui_macvim') let g:vim_program = '/Applications/MacVim.app/Contents/MacOS/Vim -g' else let g:vim_program = v:progname endif endif endif " }}} if !exists('g:LatexBox_latexmk_options') let g:LatexBox_latexmk_options = '' endif if !exists('g:LatexBox_output_type') let g:LatexBox_output_type = 'pdf' endif if !exists('g:LatexBox_viewer') let g:LatexBox_viewer = 'xdg-open' endif " }}} " Completion {{{ if !exists('g:LatexBox_completion_close_braces') let g:LatexBox_completion_close_braces = 1 endif if !exists('g:LatexBox_bibtex_wild_spaces') let g:LatexBox_bibtex_wild_spaces = 1 endif if !exists('g:LatexBox_cite_pattern') let g:LatexBox_cite_pattern = '\\cite\(p\|t\)\?\*\?\_\s*{' endif if !exists('g:LatexBox_ref_pattern') let g:LatexBox_ref_pattern = '\\v\?\(eq\|page\)\?ref\*\?\_\s*{' endif if !exists('g:LatexBox_completion_environments') let g:LatexBox_completion_environments = [ \ {'word': 'itemize', 'menu': 'bullet list' }, \ {'word': 'enumerate', 'menu': 'numbered list' }, \ {'word': 'description', 'menu': 'description' }, \ {'word': 'center', 'menu': 'centered text' }, \ {'word': 'figure', 'menu': 'floating figure' }, \ {'word': 'table', 'menu': 'floating table' }, \ {'word': 'equation', 'menu': 'equation (numbered)' }, \ {'word': 'align', 'menu': 'aligned equations (numbered)' }, \ {'word': 'align*', 'menu': 'aligned equations' }, \ {'word': 'document' }, \ {'word': 'abstract' }, \ ] endif if !exists('g:LatexBox_completion_commands') let g:LatexBox_completion_commands = [ \ {'word': '\begin{' }, \ {'word': '\end{' }, \ {'word': '\item' }, \ {'word': '\label{' }, \ {'word': '\ref{' }, \ {'word': '\eqref{eq:' }, \ {'word': '\cite{' }, \ {'word': '\nonumber' }, \ {'word': '\bibliography' }, \ {'word': '\bibliographystyle' }, \ ] endif " }}} " Templates {{{ " DEPRECATED "!if !exists('g:LatexBox_templates') "! let g:LatexBox_templates = { "! \ 'document': {}, "! \ 'abstract': {}, "! \ 'itemize': {'template': "\\\item "}, "! \ 'enumerate': {'template': "\\\item "}, "! \ 'figure': {'label': 'fig:', 'options': '[htb]'}, "! \ 'table': {'label': 'tab:', 'options': '[htb]'}, "! \ 'tabular': {'options': '[cc]'}, "! \ 'center': {}, "! \ 'equation': {'label': 'eq:'}, "! \ 'align': {'label': 'eq:'}, "! \ 'gather': {'label': 'eq:'}, "! \ } "!endif " }}} " }}} " Filename utilities {{{ " function! LatexBox_GetMainTexFile() " 1. check for the b:main_tex_file variable if exists('b:main_tex_file') && glob(b:main_tex_file, 1) != '' return b:main_tex_file endif " 2. scan current file for "\begin{document}" if &filetype == 'tex' && search('\\begin\_\s*{document}', 'nw') != 0 return expand('%:p') endif " 3. prompt for file with completion let b:main_tex_file = s:PromptForMainFile() return b:main_tex_file endfunction function! s:PromptForMainFile() let saved_dir = getcwd() execute 'cd ' . expand('%:p:h') let l:file = '' while glob(l:file, 1) == '' let l:file = input('main LaTeX file: ', '', 'file') if l:file !~ '\.tex$' let l:file .= '.tex' endif endwhile execute 'cd ' . saved_dir return l:file endfunction " Return the directory of the main tex file function! LatexBox_GetTexRoot() return fnamemodify(LatexBox_GetMainTexFile(), ':h') endfunction function! LatexBox_GetTexBasename(with_dir) if a:with_dir return fnamemodify(LatexBox_GetMainTexFile(), ':r') else return fnamemodify(LatexBox_GetMainTexFile(), ':t:r') endif endfunction function! LatexBox_GetAuxFile() return LatexBox_GetTexBasename(1) . '.aux' endfunction function! LatexBox_GetLogFile() return LatexBox_GetTexBasename(1) . '.log' endfunction function! LatexBox_GetOutputFile() return LatexBox_GetTexBasename(1) . '.' . g:LatexBox_output_type endfunction " }}} " View {{{ function! LatexBox_View() let outfile = LatexBox_GetOutputFile() if !filereadable(outfile) echomsg fnamemodify(outfile, ':.') . ' is not readable' return endif silent execute '!' . g:LatexBox_viewer ' ' . shellescape(LatexBox_GetOutputFile()) . ' &' endfunction command! LatexView call LatexBox_View() " }}} " vim:fdm=marker:ff=unix:noet:ts=4:sw=4 ftplugin/latex-box/complete.vim [[[1 426 " LaTeX Box completion " Wrap {{{ function! s:GetSID() return matchstr(expand(''), '\zs\d\+_\ze.*$') endfunction let s:SID = s:GetSID() function! s:SIDWrap(func) return s:SID . a:func endfunction " }}} " Omni Completion {{{ let s:completion_type = '' function! LatexBox_Complete(findstart, base) if a:findstart " return the starting position of the word let line = getline('.') let pos = col('.') - 1 while pos > 0 && line[pos - 1] !~ '\\\|{' let pos -= 1 endwhile if line[0:pos-1] =~ '\\begin\_\s*{$' let s:completion_type = 'begin' elseif line[0:pos-1] =~ '\\end\_\s*{$' let s:completion_type = 'end' elseif line[0:pos-1] =~ g:LatexBox_ref_pattern . '$' let s:completion_type = 'ref' elseif line[0:pos-1] =~ g:LatexBox_cite_pattern . '$' let s:completion_type = 'bib' " check for multiple citations let pos = col('.') - 1 while pos > 0 && line[pos - 1] !~ '{\|,' let pos -= 1 endwhile else let s:completion_type = 'command' if line[pos-1] == '\' let pos -= 1 endif endif return pos else " return suggestions in an array let suggestions = [] if s:completion_type == 'begin' " suggest known environments for entry in g:LatexBox_completion_environments if entry.word =~ '^' . escape(a:base, '\') if g:LatexBox_completion_close_braces " add trailing '}' let entry = copy(entry) let entry.abbr = entry.word let entry.word = entry.word . '}' endif call add(suggestions, entry) endif endfor elseif s:completion_type == 'end' " suggest known environments let env = s:GetLastUnclosedEnv() if env != '' if g:LatexBox_completion_close_braces call add(suggestions, {'word': env . '}', 'abbr': env}) else call add(suggestions, env) endif endif elseif s:completion_type == 'command' " suggest known commands for entry in g:LatexBox_completion_commands if entry.word =~ '^' . escape(a:base, '\') " do not display trailing '{' if entry.word =~ '{' let entry.abbr = entry.word[0:-2] endif call add(suggestions, entry) endif endfor elseif s:completion_type == 'ref' let suggestions = s:CompleteLabels(a:base) elseif s:completion_type == 'bib' " suggest BibTeX entries let suggestions = LatexBox_BibComplete(a:base) endif if !has('gui_running') redraw! endif return suggestions endif endfunction " }}} " BibTeX search {{{ " find the \bibliography{...} commands " the optional argument is the file name to be searched function! s:FindBibData(...) if a:0 == 0 let file = LatexBox_GetMainTexFile() else let file = a:1 endif let prefix = fnamemodify(file, ':p:h') let ext = fnamemodify(file, ':e') let bibdata_list = [] for line in readfile(file) " match \bibliography{...} let cur_bibdata = matchstr(line, '\\bibliography\_\s*{\zs[^}]*\ze}') if !empty(cur_bibdata) call add(bibdata_list, cur_bibdata) endif " match \include{...} or \input ... let included_file = matchstr(line, '\\\(input\|include\)\_\s*{\zs[^}]*\ze}') if empty(included_file) let included_file = matchstr(line, '\\@\?\(input\|include\)\_\s*\zs\S\+\ze') endif if !empty(included_file) if !filereadable(included_file) let included_file .= '.' . ext if !filereadable(included_file) continue endif endif call add(bibdata_list, s:FindBibData(included_file)) endif endfor let bibdata = join(bibdata_list, ',') return bibdata endfunction let s:bstfile = expand(':p:h') . '/vimcomplete' function! LatexBox_BibSearch(regexp) " find bib data let bibdata = s:FindBibData() if bibdata == '' echomsg 'error: no \bibliography{...} command found' return endif " write temporary aux file let tmpbase = LatexBox_GetTexRoot() . '/_LatexBox_BibComplete' let auxfile = tmpbase . '.aux' let bblfile = tmpbase . '.bbl' let blgfile = tmpbase . '.blg' call writefile(['\citation{*}', '\bibstyle{' . s:bstfile . '}', '\bibdata{' . bibdata . '}'], auxfile) silent execute '! cd ' shellescape(LatexBox_GetTexRoot()) . \ ' ; bibtex -terse ' . fnamemodify(auxfile, ':t') . ' >/dev/null' let res = [] let curentry = '' for l:line in readfile(bblfile) if l:line =~ '^\s*$' " process current entry if empty(curentry) || curentry !~ a:regexp " skip entry if void or doesn't match let curentry = '' continue endif let matches = matchlist(curentry, '^{\(.*\)}{\(.*\)}{\(.*\)}{\(.*\)}{\(.*\)}.*') if !empty(matches) && !empty(matches[1]) call add(res, {'key': matches[1], 'type': matches[2], \ 'author': matches[3], 'year': matches[4], 'title': matches[5]}) endif let curentry = '' else let curentry .= l:line endif endfor call delete(auxfile) call delete(bblfile) call delete(blgfile) return res endfunction " }}} " BibTeX completion {{{ function! LatexBox_BibComplete(regexp) " treat spaces as '.*' if needed if g:LatexBox_bibtex_wild_spaces "let regexp = substitute(a:regexp, '\s\+', '.*', 'g') let regexp = '.*' . substitute(a:regexp, '\s\+', '\\\&.*', 'g') else let regexp = a:regexp endif let res = [] for m in LatexBox_BibSearch(regexp) let w = {'word': m['key'], \ 'abbr': '[' . m['type'] . '] ' . m['author'] . ' (' . m['year'] . ')', \ 'menu': m['title']} " close braces if needed if g:LatexBox_completion_close_braces let rest_of_line = strpart(getline("."), getpos(".")[2] - 1) if rest_of_line !~ '^\s*[,}]' let w.word = w.word . '}' endif endif call add(res, w) endfor return res endfunction " }}} " Complete Labels {{{ " the optional argument is the file name to be searched function! s:CompleteLabels(regex, ...) let suggestions = [] if a:0 == 0 let auxfile = LatexBox_GetAuxFile() else let auxfile = a:1 endif let prefix = fnamemodify(auxfile, ':p:h') " search for the target equation number for line in readfile(auxfile) " search for matching label let matches = matchlist(line, '^\\newlabel{\(' . a:regex . '[^}]*\)}{{\([^}]*\)}{\([^}]*\)}.*}') if empty(matches) " also try to match label and number let regex_split = split(a:regex) let base = regex_split[0] let number = escape(join(regex_split[1:], ' '), '.') let matches = matchlist(line, '^\\newlabel{\(' . base . '[^}]*\)}{{\(' . number . '\)}{\([^}]*\)}.*}') endif if empty(matches) " also try to match number let matches = matchlist(line, '^\\newlabel{\([^}]*\)}{{\(' . escape(a:regex, '.') . '\)}{\([^}]*\)}.*}') endif if !empty(matches) let entry = {'word': matches[1], 'menu': '(' . matches[2] . ') [p.' . matches[3] . ']'} if g:LatexBox_completion_close_braces " add trailing '}' let entry = copy(entry) let entry.abbr = entry.word let entry.word = entry.word . '}' endif call add(suggestions, entry) endif " search for included files let included_auxfile = matchstr(line, '^\\@input{\zs[^}]*\ze}') if included_auxfile != '' let included_auxfile = prefix . '/' . included_auxfile call extend(suggestions, s:CompleteLabels(a:regex, included_auxfile)) endif endfor return suggestions endfunction " }}} " DEPRECATED "!" Find TeX label by number {{{ "!function! s:LabelByNumber(regex, number, ...) "! "! if a:0 == 0 "! let auxfile = LatexBox_GetAuxFile() "! else "! let auxfile = a:1 "! endif "! "! echomsg 'label by number for ' . auxfile "! "! let prefix = fnamemodify(auxfile, ':p:h') "! "! " search for the target equation number "! for line in readfile(auxfile) "! "! " search for matching label "! let label = matchstr(line, '^\\newlabel{\zs' . a:regex . '[^}]*\ze}{{' . a:number . '}') "! if label != '' "! return label "! endif "! "! " search for included files "! let included_auxfile = matchstr(line, '^\\@input{\zs[^}]*\ze}') "! if included_auxfile != '' "! let included_auxfile = prefix . '/' . included_auxfile "! let ret = s:LabelByNumber(a:regex, a:number, included_auxfile) "! if !empty(ret) "! return ret "! endif "! endif "! "! endfor "! "! " no match found; return the empty string "! return '' "! "!endfunction "!" }}} " DEPRECATED "!" Find TeX label by number with prompt {{{ "!function! s:LabelByNumberPrompt() "! let regex = input('label prefix: ', '', 'customlist,' . s:SIDWrap('GetLabelTypes')) "! let number = input('label number: ') "! return s:LabelByNumber(regex, number) "!endfunction "! "!function! s:GetLabelTypes(lead, cmdline, pos) "! let l:label_types = ['eq:', 'fig:', 'tab:'] "! let suggestions = [] "! for l:w in l:label_types "! if l:w =~ '^' . a:lead "! call add(suggestions, l:w) "! endif "! endfor "! return suggestions "!endfunction "!" }}} " DEPRECATED "!" Templates {{{ "!function! s:GetTemplateList(lead, cmdline, pos) "! let suggestions = [] "! for env in keys(g:LatexBox_templates) "! if env =~ '^' . a:lead "! call add(suggestions, env) "! endif "! endfor "! return suggestions "!endfunction "!function! LatexBox_Template(env, close) "! let envdata = get(g:LatexBox_templates, a:env, {}) "! "! let text = '\begin{' . a:env . '}' "! "! if has_key(envdata, 'options') "! let text .= envdata.options "! endif "! if a:close "! let text .= "\\n" . '\end{' . a:env . '}' . "\\" "! endif "! if has_key(envdata, 'template') "! let text .= "\n" . envdata.template "! endif "! if has_key(envdata, 'label') "! let text .= "\n" . '\label{' . envdata.label . '}' . "\" "! endif "! "! return text "!endfunction "!function! LatexBox_TemplatePrompt(close) "! let env = input('Environment: ', '', 'customlist,' . s:SIDWrap('GetTemplateList')) "! return LatexBox_Template(env, a:close) "!endfunction " }}} " Close Last Environment {{{ function! s:CloseLastEnv() let env = s:GetLastUnclosedEnv() if env != '' return '\end{' . env . '}' else return '' endif endfunction function! s:GetLastUnclosedEnv() let begin_line = searchpair('\\begin\_\s*{[^}]*}', '', '\\end\_\s*{[^}]*}', 'bnW') if begin_line let env = matchstr(getline(begin_line), '\\begin\_\s*{\zs[^}]*\ze}') return env else return '' endif endfunction " }}} " Wrap Selection {{{ function! s:WrapSelection(wrapper) normal `>a} exec 'normal `LatexCloseLastEnv =CloseLastEnv() vmap LatexWrapSelection :call WrapSelection('')i " }}} " vim:fdm=marker:ff=unix:noet:ts=4:sw=4 ftplugin/latex-box/latexmk.vim [[[1 185 " LaTeX Box latexmk functions " Wrap {{{ function! s:GetSID() return matchstr(expand(''), '\zs\d\+_\ze.*$') endfunction let s:SID = s:GetSID() function! s:SIDWrap(func) return s:SID . a:func endfunction " }}} " dictionary of latexmk PID's (basename: pid) let s:latexmk_running_pids = {} " Set PID {{{ function! s:LatexmkSetPID(basename, pid) let s:latexmk_running_pids[a:basename] = a:pid endfunction " }}} " Callback {{{ function! s:LatexmkCallback(basename, status) "let pos = getpos('.') if a:status echomsg "latexmk exited with status " . a:status else echomsg "latexmk finished" endif call remove(s:latexmk_running_pids, a:basename) call LatexBox_LatexmkErrors(0) "call setpos('.', pos) endfunction " }}} " Latexmk {{{ function! LatexBox_Latexmk(force) if empty(v:servername) echoerr "cannot run latexmk in background without a VIM server" return endif let basename = LatexBox_GetTexBasename(1) if has_key(s:latexmk_running_pids, basename) echomsg "latexmk is already running for `" . fnamemodify(basename, ':t') . "'" return endif let callsetpid = s:SIDWrap('LatexmkSetPID') let callback = s:SIDWrap('LatexmkCallback') let l:options = '-' . g:LatexBox_output_type . ' -quiet ' . g:LatexBox_latexmk_options if a:force let l:options .= ' -g' endif let l:options .= " -e '$pdflatex =~ s/ / -file-line-error /'" let l:options .= " -e '$latex =~ s/ / -file-line-error /'" " callback to set the pid let vimsetpid = g:vim_program . ' --servername ' . v:servername . ' --remote-expr ' . \ shellescape(callsetpid) . '\(\"' . basename . '\",$$\)' " latexmk command let cmd = 'cd ' . LatexBox_GetTexRoot() . ' ; latexmk ' . l:options . ' ' . LatexBox_GetMainTexFile() " callback after latexmk is finished let vimcmd = g:vim_program . ' --servername ' . v:servername . ' --remote-expr ' . \ shellescape(callback) . '\(\"' . basename . '\",$?\)' silent execute '! ( ' . vimsetpid . ' ; ( ' . cmd . ' ) ; ' . vimcmd . ' ) &' endfunction " }}} " LatexmkStop {{{ function! LatexBox_LatexmkStop() let basename = LatexBox_GetTexBasename(1) if !has_key(s:latexmk_running_pids, basename) echomsg "latexmk is not running for `" . fnamemodify(basename, ':t') . "'" return endif let gpid = s:latexmk_running_pids[basename] " This version doesn't work on systems on which pkill is not installed: "!silent execute '! pkill -g ' . pid " This version is more portable, but still doesn't work on Mac OS X: "!silent execute '! kill `ps -o pid= -g ' . pid . '`' " Since 'ps' behaves differently on different platforms, we must use brute force: " - list all processes in a temporary file " - match by process group ID " - kill matches let pids = [] let tmpfile = tempname() silent execute '!ps x -o pgid,pid > ' . tmpfile for line in readfile(tmpfile) let pid = matchstr(line, '^\s*' . gpid . '\s\+\zs\d\+\ze') if !empty(pid) call add(pids, pid) endif endfor call delete(tmpfile) if !empty(pids) silent execute '! kill ' . join(pids) endif call remove(s:latexmk_running_pids, basename) echomsg "latexmk stopped for `" . fnamemodify(basename, ':t') . "'" endfunction " }}} " LatexmkClean {{{ function! LatexBox_LatexmkClean(cleanall) if a:cleanall let l:options = '-C' else let l:options = '-c' endif let l:cmd = 'cd ' . LatexBox_GetTexRoot() . ' ; latexmk ' . l:options . ' ' . LatexBox_GetMainTexFile() silent execute '! ' . l:cmd echomsg "latexmk clean finished" endfunction " }}} " LatexmkStatus {{{ function! LatexBox_LatexmkStatus(detailed) if a:detailed if empty(s:latexmk_running_pids) echo "latexmk is not running" else let plist = "" for [basename, pid] in items(s:latexmk_running_pids) if !empty(plist) plist .= '; ' endif let plist .= fnamemodify(basename, ':t') . ':' . pid endfor echo "latexmk is running (" . plist . ")" endif else let basename = LatexBox_GetTexBasename(1) if has_key(s:latexmk_running_pids, basename) echo "latexmk is running" else echo "latexmk is not running" endif endif endfunction " }}} " LatexErrors {{{ function! LatexBox_LatexErrors(jump) let log = LatexBox_GetLogFile() if (a:jump) execute 'cfile ' . log else execute 'cgetfile ' . log endif endfunction " }}} " Commands {{{ command! Latexmk call LatexBox_Latexmk(0) command! LatexmkForce call LatexBox_Latexmk(1) command! LatexmkClean call LatexBox_LatexmkClean(0) command! LatexmkCleanAll call LatexBox_LatexmkClean(1) command! LatexmkStatus call LatexBox_LatexmkStatus(0) command! LatexmkStatusDetailed call LatexBox_LatexmkStatus(1) command! LatexmkStop call LatexBox_LatexmkStop() command! LatexErrors call LatexBox_LatexErrors(1) " }}} " vim:fdm=marker:ff=unix:noet:ts=4:sw=4 ftplugin/latex-box/mappings.vim [[[1 52 " LaTeX Box mappings " latexmk {{{ map ll :Latexmk map lL :LatexmkForce map lc :LatexmkClean map lC :LatexmkCleanAll map lg :LatexmkStatus map lG :LatexmkStatusDetailed map lk :LatexmkStop map le :LatexErrors " }}} " View {{{ map lv :LatexView " }}} " Error Format {{{ " This assumes we're using the -file-line-error with [pdf]latex. setlocal efm=%E%f:%l:%m,%-Cl.%l\ %m,%-G " }}} " TOC {{{ command! LatexTOC call LatexBox_TOC() map lt :LatexTOC " }}} setlocal omnifunc=LatexBox_Complete finish " Suggested mappings: " Motion {{{ map ¶ :call LatexBox_JumpToNextBraces(0) map § :call LatexBox_JumpToNextBraces(1) imap =LatexBox_JumpToNextBraces(0) imap § =LatexBox_JumpToNextBraces(1) " }}} " begin/end {{{ imap =LatexBox_TemplatePrompt(1) imap [[ \begin{ imap ]] =LatexBox_CloseLastEnv() vmap :call LatexBox_WrapSelection('')i " }}} " Other commands {{{ imap =LatexBox_FindLabelByNumberPrompt() " }}} " vim:fdm=marker:ff=unix:noet:ts=4:sw=4 ftplugin/latex-box/motion.vim [[[1 146 " LaTeX Box motion functions " 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 {{{ function! s:ReadTOC(auxfile) let toc = [] let prefix = fnamemodify(a:auxfile, ':p:h') for line in readfile(a:auxfile) let included = matchstr(line, '^\\@input{\zs[^}]*\ze}') if included != '' call extend(toc, s:ReadTOC(prefix . '/' . included)) continue endif let m = matchlist(line, \ '^\\@writefile{toc}{\\contentsline\s*' . \ '{\([^}]*\)}{\\numberline {\([^}]*\)}\(.*\)') if !empty(m) let str = m[3] let nbraces = 0 let istr = 0 while nbraces >= 0 && istr < len(str) if str[istr] == '{' let nbraces += 1 elseif str[istr] == '}' let nbraces -= 1 endif let istr += 1 endwhile let text = str[:(istr-2)] let page = matchstr(str[(istr):], '{\([^}]*\)}') call add(toc, {'file': fnamemodify(a:auxfile, ':r') . '.tex', \ 'level': m[1], 'number': m[2], 'text': text, 'page': page}) endif endfor return toc endfunction function! LatexBox_TOC() let toc = s:ReadTOC(LatexBox_GetAuxFile()) let calling_buf = bufnr('%') 30vnew +setlocal\ buftype=nofile LaTeX\ TOC for entry in toc call append('$', entry['number'] . "\t" . entry['text']) endfor call append('$', ["", "/q: close", ": jump", ": jump and close"]) 0delete syntax match Comment /^<.*/ map q :bdelete map :bdelete map :call TOCActivate(0) map :call TOCActivate(1) setlocal cursorline nomodifiable tabstop=8 nowrap let b:toc = toc let b:calling_win = bufwinnr(calling_buf) endfunction " TODO "!function! s:FindClosestSection(toc, pos) "! let saved_pos = getpos('.') "! for entry in toc "! endfor "! "! call setpos(saved_pos) "!endfunction function! s:TOCActivate(close) let n = getpos('.')[1] - 1 if n >= len(b:toc) return endif let entry = b:toc[n] let toc_bnr = bufnr('%') let toc_wnr = winnr() execute b:calling_win . 'wincmd w' let bnr = bufnr(entry['file']) if bnr >= 0 execute 'buffer ' . bnr else execute 'edit ' . entry['file'] endif let titlestr = entry['text'] " Credit goes to Marcin Szamotulski for the following fix. It allows to match through " commands added by TeX. let titlestr = substitute(titlestr, '\\\w*\>\s*\%({[^}]*}\)\?', '.*', 'g') let titlestr = escape(titlestr, '\') let titlestr = substitute(titlestr, ' ', '\\_\\s\\+', 'g') call search('\\' . entry['level'] . '\_\s*{' . titlestr . '}', 'w') normal zt if a:close execute 'bdelete ' . toc_bnr else execute toc_wnr . 'wincmd w' endif endfunction " }}} " vim:fdm=marker:ff=unix:noet:ts=4:sw=4 ftplugin/latex-box/vimcomplete.bst [[[1 303 ENTRY { address author booktitle chapter doi edition editor eid howpublished institution isbn issn journal key month note number organization pages publisher school series title type volume year } {} { label } STRINGS { s t} FUNCTION {output} { 's := %purify$ "}{" * write$ s } FUNCTION {fin.entry} { "}" * write$ newline$ } FUNCTION {not} { { #0 } { #1 } if$ } FUNCTION {and} { 'skip$ { pop$ #0 } if$ } FUNCTION {or} { { pop$ #1 } 'skip$ if$ } FUNCTION {field.or.null} { duplicate$ empty$ { pop$ "" } 'skip$ if$ } FUNCTION {capitalize} { "u" change.case$ "t" change.case$ } FUNCTION {space.word} { " " swap$ * " " * } FUNCTION {bbl.and} { "&"} FUNCTION {bbl.etal} { "et al." } INTEGERS { nameptr namesleft numnames } STRINGS { bibinfo} FUNCTION {format.names} { duplicate$ empty$ 'skip$ { 's := "" 't := #1 'nameptr := s num.names$ 'numnames := numnames 'namesleft := { namesleft #0 > } { s nameptr %"{vv~}{ll}{, f.}{, jj}" "{vv }{ll}{}{}" format.name$ 't := nameptr #1 > { namesleft #1 > { ", " * t * } { s nameptr "{ll}" format.name$ duplicate$ "others" = { 't := } { pop$ } if$ t "others" = { " " * bbl.etal * } { bbl.and space.word * t * } if$ } if$ } 't if$ nameptr #1 + 'nameptr := namesleft #1 - 'namesleft := } while$ } if$ } FUNCTION {format.authors} { author empty$ {editor format.names} {author format.names} if$ } FUNCTION {format.title} { title duplicate$ empty$ 'skip$ { "t" change.case$ } if$ } FUNCTION {output.label} { newline$ "{" cite$ * write$ "" } FUNCTION {format.date} { "" duplicate$ empty$ year duplicate$ empty$ { swap$ 'skip$ { "there's a month but no year in " cite$ * warning$ } if$ * } { swap$ 'skip$ { swap$ " " * swap$ } if$ * } if$ } FUNCTION {output.entry} { 's := output.label s output format.authors output format.date output format.title output fin.entry } FUNCTION {default.type} {"?" output.entry} FUNCTION {article} {"a" output.entry} FUNCTION {book} {"B" output.entry} FUNCTION {booklet} {"k" output.entry} FUNCTION {conference} {"f" output.entry} FUNCTION {inbook} {"b" output.entry} FUNCTION {incollection} {"c" output.entry} FUNCTION {inproceedings} {"p" output.entry} FUNCTION {manual} {"m" output.entry} FUNCTION {mastersthesis} {"Master" output.entry} FUNCTION {misc} {"-" output.entry} FUNCTION {phdthesis} {"PhD" output.entry} FUNCTION {proceedings} {"P" output.entry} FUNCTION {techreport} {"r" output.entry} FUNCTION {unpublished} {"u" output.entry} READ FUNCTION {sortify} { purify$ "l" change.case$ } INTEGERS { len } FUNCTION {chop.word} { 's := 'len := s #1 len substring$ = { s len #1 + global.max$ substring$ } 's if$ } FUNCTION {sort.format.names} { 's := #1 'nameptr := "" s num.names$ 'numnames := numnames 'namesleft := { namesleft #0 > } { s nameptr "{vv{ } }{ll{ }}{ f{ }}{ jj{ }}" format.name$ 't := nameptr #1 > { " " * namesleft #1 = t "others" = and { "zzzzz" * } { t sortify * } if$ } { t sortify * } if$ nameptr #1 + 'nameptr := namesleft #1 - 'namesleft := } while$ } FUNCTION {sort.format.title} { 't := "A " #2 "An " #3 "The " #4 t chop.word chop.word chop.word sortify #1 global.max$ substring$ } FUNCTION {author.sort} { author empty$ { key empty$ { "to sort, need author or key in " cite$ * warning$ "" } { key sortify } if$ } { author sort.format.names } if$ } FUNCTION {author.editor.sort} { author empty$ { editor empty$ { key empty$ { "to sort, need author, editor, or key in " cite$ * warning$ "" } { key sortify } if$ } { editor sort.format.names } if$ } { author sort.format.names } if$ } FUNCTION {author.organization.sort} { author empty$ { organization empty$ { key empty$ { "to sort, need author, organization, or key in " cite$ * warning$ "" } { key sortify } if$ } { "The " #4 organization chop.word sortify } if$ } { author sort.format.names } if$ } FUNCTION {editor.organization.sort} { editor empty$ { organization empty$ { key empty$ { "to sort, need editor, organization, or key in " cite$ * warning$ "" } { key sortify } if$ } { "The " #4 organization chop.word sortify } if$ } { editor sort.format.names } if$ } FUNCTION {presort} { type$ "book" = type$ "inbook" = or 'author.editor.sort { type$ "proceedings" = 'editor.organization.sort { type$ "manual" = 'author.organization.sort 'author.sort if$ } if$ } if$ " " * year field.or.null sortify * " " * title field.or.null sort.format.title * #1 entry.max$ substring$ 'sort.key$ := } ITERATE {presort} SORT ITERATE {call.type$} doc/latex-box.txt [[[1 357 *latex-box.txt* LaTeX Tool Box *latex-box* This plugin provides: - Background compilation using latexmk; - Completion for commands, environments, labels, and bibtex entries; - A simple table of contents; - Motion through brackets/braces. ============================================================================== |latex-box-completion| COMPLETION |latex-box-completion-commands| Commands |latex-box-completion-environments| Environments |latex-box-completion-labels| Labels |latex-box-completion-bibtex| Bibtex |latex-box-commands| COMMANDS |latex-box-commands-compilation| Compilation |latex-box-commands-viewing| Viewing |latex-box-commands-motion| Motion |latex-box-motion| MOTION |latex-box-mappings| MAPPINGS |latex-box-mappings-compilation| Compilation |latex-box-mappings-insertion| Insertion |latex-box-mappings-viewing| Viewing |latex-box-mappings-motion| Motion |latex-box-settings| SETTINGS |latex-box-settings-compilation| Compilation |latex-box-settings-completion| Completion ============================================================================== COMPLETION *latex-box-completion* Completion is achieved through omni completion |compl-omni|, with default bindings . There are four types of completion: ------------------------------------------------------------------------------ *latex-box-completion-commands* Commands ~ Command completion is triggered by the '\' character. For example, > \beg completes to > \begin{ Associated settings: |g:LatexBox_completion_commands| |g:LatexBox_completion_close_braces| ------------------------------------------------------------------------------ *latex-box-completion-environments* Environments ~ Environment completion is triggered by '\begin{'. For example, > \begin{it completes to > \begin{itemize} Completion of '\end{' automatically closes the last open environment. Associated settings: |g:LatexBox_completion_environments| |g:LatexBox_completion_close_braces| ------------------------------------------------------------------------------ *latex-box-completion-labels* Labels ~ Label completion is triggered by '\ref{' or '\eqref{'. For example, > \ref{sec: offers a list of all matching labels, with their associated value and page number. Labels are read from the aux file, so label completion works only after complilation. It matches: 1. labels: > \ref{sec: < 2. numbers: > \eqref{2 < 3. labels and numbers together (separated by whitespace): > \eqref{eq 2 Associated settings: |g:LatexBox_ref_pattern| |g:LatexBox_completion_close_braces| ------------------------------------------------------------------------------ *latex-box-completion-bibtex* BibTeX entries ~ BibTeX completion is triggered by '\cite{', '\citep{' or '\citet{'. For example, assume you have in your .bib files an entry looking like: > @book { knuth1981, author = "Donald E. Knuth", title = "Seminumerical Algorithms", publisher = "Addison-Wesley", year = "1981" } Then, try: > \cite{Knuth 1981 \cite{algo You can also use regular expressions (or vim patterns) after '\cite{'. Associated settings: |g:LatexBox_cite_pattern| |g:LatexBox_bibtex_wild_spaces| |g:LatexBox_completion_close_braces| ============================================================================== COMMANDS *latex-box-commands* ------------------------------------------------------------------------------ *latex-box-commands-compilation* Compilation ~ *:Latexmk* Compile with latexmk in background. See |g:LatexBox_latexmk_options|. *:LatexmkForce* Force compilation with latexmk in background. *:LatexmkClean* Clean temporary output from LaTeX. *:LatexmkCleanAll* Clean all output from LaTeX. *:LatexmkStop* Stop latexmk if it is running. *:LatexmkStatus* Show the running status of latexmk for the current buffer. *:LatexmkStatusDetailed* Show the running status of latexmk for all buffers with process group ID's. *:LatexErrors* Load the log file for the current document and jump to the first error. When latexmk terminates, it reports its success or failure (with status number). To navigate through the errors, you can use the |:cc|, |:cn| and |:cp| commands, as well as the |:clist| command to list the errors. ------------------------------------------------------------------------------ *latex-box-commands-viewing* Viewing ~ *:LatexView* Launch viewer on output file. See |g:LatexBox_output_type| and |g:LatexBox_viewer|. ------------------------------------------------------------------------------ *latex-box-commands-motion* Motion ~ *:LatexTOC* Open a table of contents. Use Enter to navigate to selected entry. ============================================================================== MOTION *latex-box-motion* The function LatexBox_JumpToNextBraces({backward}) allows to jump outside of the current brace/bracket pair, or inside of the next opening braces/brackets. ============================================================================== MAPPINGS *latex-box-mappings* ------------------------------------------------------------------------------ *latex-box-mappings-compilation* Compilation ~ ll |:Latexmk| Compile with latexmk in background. lL |:LatexmkForce| Force compilation with latexmk in background. lc |:LatexmkClean| Clean temporary output from LaTeX. lC |:LatexmkCleanAll| Clean all output from LaTeX. lk |:LatexmkStop| Stop latexmk if it is running. lg |:LatexmkStatus| Show the running status of latexmk for the current buffer. lG |:LatexmkStatusDetailed| Show the running status of latexmk for all buffers with process group ID's. le |:LatexErrors| Load the log file for the current document and jump to the first error. ------------------------------------------------------------------------------ *latex-box-mappings-viewing* Viewing ~ lv |:LatexView| View output file. ------------------------------------------------------------------------------ *latex-box-mappings-insertion* Insertion ~ LatexCloseLastEnv Close the last matching open environment. Use with imap, e.g.: > imap ]] LatexCloseLastEnv < LatexWrapSelection Wrap the current selection in a LaTeX command. Use with vmap, e.g.: > vmap LatexWrapSelection < Suggested bindings: > imap [[ \begin{ imap ]] LatexCloseLastEnv vmap LatexWrapSelection imap (( \eqref{ < ------------------------------------------------------------------------------ *latex-box-mappings-motion* Motion ~ lt |:LatexTOC| Open a table of contents. Use Enter to navigate to selected entry. Suggested bindings: > map ¶ :call LatexBox_JumpToNextBraces(0) map § :call LatexBox_JumpToNextBraces(1) imap =LatexBox_JumpToNextBraces(0) imap § =LatexBox_JumpToNextBraces(1) < ============================================================================== SETTINGS *latex-box-settings* ------------------------------------------------------------------------------ *latex-box-settings-completion* Completion ~ *g:LatexBox_completion_close_braces* Default: 1 If nonzero, omni completion will add closing brackets where relevant. For example, if nonzero, > \begin{itemize < completes to > \begin{itemize} *g:LatexBox_bibtex_wild_spaces* Default: 1 If nonzero, spaces act as wildcards ('.*') in completion. For example, if nonzero, > \cite{Knuth 1981 < is equivalent to > \cite{Knuth.*1981 *g:LatexBox_completion_environments* *g:LatexBox_completion_commands* Static completion lists for environments |latex-box-completion-environments| and commands |latex-box-completion-commands|. See |complete-items|. *g:LatexBox_cite_pattern* Default: '\\cite\(p\|t\)\?\*\?\_\s*{' *g:LatexBox_ref_pattern* Default: '\\v\?\(eq\|page\)\?ref\*\?\_\s*{' Patterns to match \cite and \ref commands for BibTeX and label completion. Must include the trailing '{'. To match all commands that contain 'cite' (case insensitive), use: > let g:LatexBox_cite_pattern = '\c\\\a*cite\a*\*\?\_\s*{' < To match all commands that end with 'ref' (case insensitive): > let g:LatexBox_ref_pattern = '\c\\\a*ref\*\?\_\s*{' < Both examples match commands with a trailing star too. ------------------------------------------------------------------------------ Templates (DEPRECATED) ~ *g:LatexBox_templates* Dictionary of environment templates |latex-box-templates|. DEPRECATED! I think it is better to leave this task to plug-ins oriented to do this well, like snipMate: https://www.vim8.org/scripts/script.php?script_id=2540 ------------------------------------------------------------------------------ *latex-box-settings-compilation* Compilation ~ *g:vim_program* Default: autodetected Vim program to use on command line for callbacks. If autodetect fails, defaults to > '/Applications/MacVim.app/Contents/MacOS/Vim -g' < on MacVim, or to |v:progname| on other systems. *g:LatexBox_latexmk_options* Default: "" Additional options to pass to latexmk during compilation, e.g, "-d". *g:LatexBox_output_type* Default: "pdf" Extension of the output file. One of "pdf", "dvi" or "ps". *g:LatexBox_viewer* Default: "xdg-open" Viewer application for the output file, e.g., "xpdf". ============================================================================== TODO *latex-box-todo* - Proper indentation. ============================================================================== vim:tw=78:ts=8:sw=8:ft=help:norl:noet: