Initial revision

This commit is contained in:
Karl Yngve Lervåg 2013-10-05 13:53:42 +02:00
commit 7808e59239
17 changed files with 3342 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
doc/tags

47
README.md Normal file
View File

@ -0,0 +1,47 @@
# vim-latex
## Introduction
There exists several LaTeX plugins for vim, for instance:
- LaTeX-Suite: vimscript#475
- AutomaticTexPlugin: vimscript#2945
- LaTeX-Box: vimscript#3109
I have been using both LaTeX-Suite and LaTeX-Box myself, but I found both of
these to be relatively bulky and difficult to manage and extend. LaTeX-Box
was supposed to be simple and lightweight, and I think it was close to being
just that. However, after having worked on it for some time, I felt that much
of the simplicity could be improved by a complete restructuring.
Enter vim-latex, which is a lightweight and simple plugin that provides LaTeX
support for vim. It has most of the functionality of LaTeX-Box, but the idea
is to combine vim-latex with the strength of other plugins. I personally
recommend [UltiSnips](https://github.com/SirVer/ultisnips) for snippets and
[neocomplete](https://github.com/Shougo/neocomplete.vim) for completion.
Read the documentation for a more thorough introduction.
## Installation
### With gmarik vundle
_https://github.com/gmarik/vundle_
Add `Bundle 'lervag/vim-latex'` to your ~/.vimrc and run
`:BundleInstall` in a vim buffer. Add `!` to the command to update.
### With neobundle
_https://github.com/Shougo/neobundle.vim_
Add `NeoBundle 'lervag/vim-latex'` to your ~/.vimrc and run
`:NeoBundleInstall` in a vim buffer. Add `!` to the command to update.
### With pathogen
_https://github.com/tpope/vim-pathogen_
Add the vim-latex bundle to your bundle directory, for instance with `git
clone`. This will typically be enough:
cd ~/.vim/bundle
git clone git://github.com/lervag/vim-latex
### Without a plugin manager
Copy the directories to your `.vim/` folder.

5
after/syntax/tex.vim Normal file
View File

@ -0,0 +1,5 @@
" Add support for cleverref package (`\cref` and `\Cref`)
syn region texRefZone matchgroup=texStatement
\ start="\\\(c\|C\)ref{"
\ end="}\|%stopzone\>"
\ contains=@texRefGroup

263
autoload/latex.vim Normal file
View File

@ -0,0 +1,263 @@
" {{{1 latex#init
let s:initialized = 0
function! latex#init()
call s:init_environment()
call s:init_errorformat()
call latex#toc#init(s:initialized)
call latex#fold#init(s:initialized)
call latex#motion#init(s:initialized)
call latex#change#init(s:initialized)
call latex#latexmk#init(s:initialized)
call latex#complete#init(s:initialized)
"
" This variable is used to allow a distinction between global and buffer
" initialization
"
let s:initialized = 1
endfunction
" {{{1 latex#info
function! latex#info()
echo "Buffer data"
echo printf(' id: %-s', b:latex.id)
echo printf('fold sections: %-s', string(b:latex.fold_sections))
echo "\n"
echo "Latex blobs"
let n = -1
for data in g:latex#data
let n += 1
if n > 0
echo "\n"
endif
let d = copy(data)
let d.aux = d.aux()
let d.out = d.out()
let d.log = d.log()
echo printf('%6s: %-s', 'id', n)
for [key, val] in sort(items(d), "s:info_sort_func")
if key =~ '\vaux|out|root|log|tex'
let val = s:truncate(val)
endif
echo printf('%6s: %-s', key, val)
endfor
endfor
endfunction
" {{{1 latex#help
function! latex#help()
if g:latex_default_mappings
echo "Latex mappings"
nmap <buffer>
vmap <buffer>
omap <buffer>
endif
endfunction
" {{{1 latex#reinit
function! latex#reinit()
"
" Stop latexmk processes (if running)
"
call latex#latexmk#stop_all()
"
" Reset variables
"
let s:initialized = 0
unlet g:latex#data
bufdo unlet b:notbslash
bufdo unlet b:notcomment
bufdo unlet b:latex
"
" Reinitialize
"
bufdo call latex#init()
endfunction
" {{{1 latex#view
function! latex#view()
let outfile = g:latex#data[b:latex.id].out()
if !filereadable(outfile)
echomsg "Can't view: Output file is not readable!"
return
endif
silent execute '!' . g:latex_viewer . ' ' . outfile . ' &>/dev/null &'
if !has("gui_running")
redraw!
endif
endfunction
" }}}1
" {{{1 s:init_environment
function! s:init_environment()
"
" Initialize global and local data blobs
"
call latex#util#set_default('g:latex#data', [])
call latex#util#set_default('b:latex', {})
"
" Initialize some common patterns
"
call latex#util#set_default('b:notbslash', '\%(\\\@<!\%(\\\\\)*\)\@<=')
call latex#util#set_default('b:notcomment',
\ '\%(\%(\\\@<!\%(\\\\\)*\)\@<=%.*\)\@<!')
"
" Create new or link to old blob
"
let main = s:get_main_tex()
let id = s:get_id(main)
if id >= 0
let b:latex.id = id
else
let data = {}
let data.tex = main
let data.root = fnamemodify(data.tex, ':h')
let data.base = fnamemodify(data.tex, ':t')
let data.name = fnamemodify(data.tex, ':t:r')
function data.aux() dict
return s:get_main_ext(self, 'aux')
endfunction
function data.log() dict
return s:get_main_ext(self, 'log')
endfunction
function data.out() dict
return s:get_main_ext(self, g:latex_latexmk_output)
endfunction
call add(g:latex#data, data)
let b:latex.id = len(g:latex#data) - 1
endif
if g:latex_default_mappings
nnoremap <silent><buffer> <localleader>li :call latex#info()<cr>
nnoremap <silent><buffer> <localleader>lh :call latex#help()<cr>
nnoremap <silent><buffer> <localleader>lv :call latex#view()<cr>
nnoremap <silent><buffer> <LocalLeader>lR :call latex#reinit()<cr>
endif
endfunction
" {{{1 s:init_errorformat
function! s:init_errorformat()
"
" Note: The error formats assume we're using the -file-line-error with
" [pdf]latex. For more info, see |errorformat-LaTeX|.
"
" Push file to file stack
setlocal efm+=%+P**%f
" Match errors
setlocal efm=%E!\ LaTeX\ %trror:\ %m
setlocal efm+=%E%f:%l:\ %m
setlocal efm+=%E!\ %m
" More info for undefined control sequences
setlocal efm+=%Z<argument>\ %m
" Show warnings
if g:latex_errorformat_show_warnings
" Ignore some warnings
for w in g:latex_errorformat_ignore_warnings
let warning = escape(substitute(w, '[\,]', '%\\\\&', 'g'), ' ')
exe 'setlocal efm+=%-G%.%#'. warning .'%.%#'
endfor
setlocal efm+=%+WLaTeX\ %.%#Warning:\ %.%#line\ %l%.%#
setlocal efm+=%+W%.%#\ at\ lines\ %l--%*\\d
setlocal efm+=%+WLaTeX\ %.%#Warning:\ %m
setlocal efm+=%+W%.%#%.%#Warning:\ %m
endif
" Ignore unmatched lines
setlocal efm+=%-G%.%#
endfunction
" }}}1
" {{{1 s:get_id
function! s:get_id(main)
if exists('g:latex#data') && !empty(g:latex#data)
let id = 0
while id < len(g:latex#data)
if g:latex#data[id].tex == a:main
return id
endif
let id += 1
endwhile
endif
return -1
endfunction
" {{{1 s:get_main_tex
function! s:get_main_tex()
if !search('\C\\begin\_\s*{document}', 'nw')
let tex_files = glob('*.tex', 0, 1) + glob('../*.tex', 0, 1)
call filter(tex_files,
\ "count(g:latex_main_tex_candidates, fnamemodify(v:val,':t:r'))")
if !empty(tex_files)
return fnamemodify(tex_files[0], ':p')
endif
endif
return expand('%:p')
endfunction
" {{{1 s:get_main_ext
function! s:get_main_ext(texdata, ext)
" Create set of candidates
let candidates = [
\ a:texdata.name,
\ g:latex_build_dir . '/' . a:texdata.name,
\ ]
" Search through the candidates
for f in map(candidates,
\ 'a:texdata.root . ''/'' . v:val . ''.'' . a:ext')
if filereadable(f)
return fnamemodify(f, ':p')
endif
endfor
" Return empty string if no entry is found
return ''
endfunction
" {{{1 s:info_sort_func
function! s:info_sort_func(a, b)
if a:a[1][0] == "!"
" Put cmd's way behind
return 1
elseif a:b[1][0] == "!"
" Put cmd's way behind
return -1
elseif a:a[1][0] == "/" && a:b[1][0] != "/"
" Put full paths behind
return 1
elseif a:a[1][0] != "/" && a:b[1][0] == "/"
" Put full paths behind
return -1
elseif a:a[1][0] == "/" && a:b[1][0] == "/"
" Put full paths behind
return -1
else
return a:a[1] > a:b[1] ? 1 : -1
endif
endfunction
" {{{1 s:truncate
function! s:truncate(string)
if len(a:string) >= winwidth('.') - 9
return a:string[0:10] . "..." . a:string[-winwidth('.')+23:]
else
return a:string
endif
endfunction
" }}}1
" vim:fdm=marker:ff=unix

153
autoload/latex/change.vim Normal file
View File

@ -0,0 +1,153 @@
" {{{1 latex#change#init
function! latex#change#init(initialized)
if g:latex_default_mappings
nnoremap <silent><buffer> <f5>
\ :call latex#change#environment_prompt()<cr>
nnoremap <silent><buffer> <f6>
\ :call latex#change#environment_toggle_star()<cr>
endif
endfunction
" {{{1 latex#change#environment
function! latex#change#environment(new_env)
let [env, l1, c1, l2, c2] = latex#util#get_env(1)
if a:new_env == '\[' || a:new_env == '['
let beg = '\['
let end = '\]'
let n1 = 1
let n2 = 1
elseif a:new_env == '\(' || a:new_env == '('
let beg = '\('
let end = '\)'
let n1 = 1
let n2 = 1
else
let beg = '\begin{' . a:new_env . '}'
let end = '\end{' . a:new_env . '}'
let n1 = len(env) + 7
let n2 = len(env) + 5
endif
let line = getline(l1)
let line = strpart(line, 0, c1 - 1) . l:beg . strpart(line, c1 + n1)
call setline(l1, line)
let line = getline(l2)
let line = strpart(line, 0, c2 - 1) . l:end . strpart(line, c2 + n2)
call setline(l2, line)
endfunction
" {{{1 latex#change#environment_prompt
function! latex#change#environment_prompt()
let new_env = input('Change ' . latex#util#get_env() . ' for: ', '',
\ 'customlist,' . s:sidwrap('input_complete'))
if empty(new_env)
return
else
call latex#change#environment(new_env)
endif
endfunction
" {{{1 latex#change#environment_toggle_star
function! latex#change#environment_toggle_star()
let env = latex#util#get_env()
if env == '\('
return
elseif env == '\['
let new_env = equation
elseif env[-1:] == '*'
let new_env = env[:-2]
else
let new_env = env . '*'
endif
call latex#change#environment(new_env)
endfunction
" {{{1 latex#change#wrap_selection
function! latex#change#wrap_selection(wrapper)
keepjumps normal! `>a}
execute 'keepjumps normal! `<i\' . a:wrapper . '{'
endfunction
" {{{1 latex#change#wrap_selection_prompt
function! latex#change#wrap_selection_prompt(...)
let env = input('Environment: ', '',
\ 'customlist,' . s:sidwrap('input_complete'))
if empty(env)
return
endif
" Make sure custom indentation does not interfere
let ieOld = &indentexpr
setlocal indentexpr=""
if visualmode() ==# 'V'
execute 'keepjumps normal! `>o\end{' . env . '}'
execute 'keepjumps normal! `<O\begin{' . env . '}'
" indent and format, if requested.
if a:0 && a:1
normal! gv>
normal! gvgq
endif
else
execute 'keepjumps normal! `>a\end{' . env . '}'
execute 'keepjumps normal! `<i\begin{' . env . '}'
endif
exe "setlocal indentexpr=" . ieOld
endfunction
" }}}1
" {{{1 s:sidwrap
let s:SID = matchstr(expand('<sfile>'), '\zs<SNR>\d\+_\ze.*$')
function! s:sidwrap(func)
return s:SID . a:func
endfunction
" {{{1 s:input_complete
function! s:input_complete(lead, cmdline, pos)
let suggestions = []
for entry in g:latex_complete_environments
let env = entry.word
if env =~ '^' . a:lead
call add(suggestions, env)
endif
endfor
return suggestions
endfunction
" {{{1 s:search_and_skip_comments
function! s:search_and_skip_comments(pat, ...)
" Usage: s:search_and_skip_comments(pat, [flags, stopline])
let flags = a:0 >= 1 ? a:1 : ''
let stopline = a:0 >= 2 ? a:2 : 0
let saved_pos = getpos('.')
" search once
let ret = search(a:pat, flags, stopline)
if ret
" do not match at current position if inside comment
let flags = substitute(flags, 'c', '', 'g')
" keep searching while in comment
while latex#util#in_comment()
let ret = search(a:pat, flags, stopline)
if !ret
break
endif
endwhile
endif
if !ret
" if no match found, restore position
call setpos('.', saved_pos)
endif
return ret
endfunction
" }}}1 Modeline
" vim:fdm=marker:ff=unix

312
autoload/latex/complete.vim Normal file
View File

@ -0,0 +1,312 @@
" {{{1 latex#complete#init
function! latex#complete#init(initialized)
if g:latex_complete_enabled
setlocal omnifunc=latex#complete#omnifunc
endif
endfunction
" {{{1 latex#complete#omnifunc
let s:completion_type = ''
function! latex#complete#omnifunc(findstart, base)
if a:findstart
"
" First call: Find start of text to be completed
"
" Note: g:latex_complete_patterns is a dictionary where the keys are the
" types of completion and the values are the patterns that must match for
" the given type. Currently, it completes labels (e.g. \ref{...), bibtex
" entries (e.g. \cite{...) and commands (e.g. \...).
"
let line = getline('.')
let pos = col('.') - 1
for [type, pattern] in items(g:latex_complete_patterns)
if line =~ pattern . '$'
let s:completion_type = type
while pos > 0 && line[pos - 1] !~ '{\|,'
let pos -= 1
endwhile
return pos > 0 ? pos : -2
endif
endfor
else
"
" Second call: Find list of matches
"
if s:completion_type == 'ref'
return latex#complete#labels(a:base)
elseif s:completion_type == 'bib'
return latex#complete#bibtex(a:base)
endif
endif
endfunction
" {{{1 latex#complete#labels
function! latex#complete#labels(regex)
let labels = s:labels_get(g:latex#data[b:latex.id].aux())
let matches = filter(copy(labels), 'v:val[0] =~ ''' . a:regex . '''')
" Try to match label and number
if empty(matches)
let regex_split = split(a:regex)
if len(regex_split) > 1
let base = regex_split[0]
let number = escape(join(regex_split[1:], ' '), '.')
let matches = filter(copy(labels),
\ 'v:val[0] =~ ''' . base . ''' &&' .
\ 'v:val[1] =~ ''' . number . '''')
endif
endif
" Try to match number
if empty(matches)
let matches = filter(copy(labels), 'v:val[1] =~ ''' . a:regex . '''')
endif
let suggestions = []
for m in matches
let entry = {
\ 'word': m[0],
\ 'menu': printf("%7s [p. %s]", '('.m[1].')', m[2])
\ }
if g:latex_complete_close_braces && !s:next_chars_match('^\s*[,}]')
let entry = copy(entry)
let entry.abbr = entry.word
let entry.word = entry.word . '}'
endif
call add(suggestions, entry)
endfor
return suggestions
endfunction
" {{{1 latex#complete#bibtex
function! latex#complete#bibtex(regexp)
let res = []
for m in s:bibtex_search(a:regexp)
let type = m['type'] == '' ? '[-]' : '[' . m['type'] . '] '
let auth = m['author'] == '' ? '' : m['author'][:20] . ' '
let year = m['year'] == '' ? '' : '(' . m['year'] . ')'
let w = {
\ 'word': m['key'],
\ 'abbr': type . auth . year,
\ 'menu': m['title']
\ }
" Close braces if desired
if g:latex_complete_close_braces && !s:next_chars_match('^\s*[,}]')
let w.word = w.word . '}'
endif
call add(res, w)
endfor
return res
endfunction
" }}}1
" {{{1 s:bibtex_search
let s:bstfile = expand('<sfile>:p:h') . '/vimcomplete'
function! s:bibtex_search(regexp)
let res = []
" Find data from external bib files
let bibdata = join(s:bibtex_find_bibs(), ',')
if bibdata != ''
let tmp = {
\ 'aux' : 'tmpfile.aux',
\ 'bbl' : 'tmpfile.bbl',
\ 'blg' : 'tmpfile.blg',
\ }
" Write temporary aux file
call writefile([
\ '\citation{*}',
\ '\bibstyle{' . s:bstfile . '}',
\ '\bibdata{' . bibdata . '}',
\ ], tmp.aux)
" Create temporary bbl file
silent execute '!bibtex -terse ' . tmp.aux . ' >/dev/null'
if !has('gui_running')
redraw!
endif
" Parse temporary bbl file
let lines = split(substitute(join(readfile(tmp.bbl), "\n"),
\ '\n\n\@!\(\s\=\)\s*\|{\|}', '\1', 'g'), "\n")
for line in filter(lines, 'v:val =~ a:regexp')
let matches = matchlist(line,
\ '^\(.*\)||\(.*\)||\(.*\)||\(.*\)||\(.*\)')
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
endfor
call delete(tmp.aux)
call delete(tmp.bbl)
call delete(tmp.blg)
endif
" Find data from 'thebibliography' environments
let lines = readfile(g:latex#data[b:latex.id].tex)
if match(lines, '\C\\begin{thebibliography}')
for line in filter(filter(lines, 'v:val =~ ''\C\\bibitem'''),
\ 'v:val =~ a:regexp')
let match = matchlist(line, '\\bibitem{\([^}]*\)')[1]
call add(res, {
\ 'key': match,
\ 'type': '',
\ 'author': '',
\ 'year': '',
\ 'title': match,
\ })
endfor
endif
return res
endfunction
" {{{1 s:bibtex_find_bibs
function! s:bibtex_find_bibs(...)
if a:0
let file = a:1
else
let file = g:latex#data[b:latex.id].tex
endif
if !filereadable(file)
return ''
endif
let lines = readfile(file)
let bibdata_list = []
"
" Search for added bibliographies
"
let bibliography_cmds = [
\ '\\bibliography',
\ '\\addbibresource',
\ '\\addglobalbib',
\ '\\addsectionbib',
\ ]
for cmd in bibliography_cmds
let filter = 'v:val =~ ''\C' . cmd . '\s*{[^}]\+}'''
let map = 'matchstr(v:val, ''\C' . cmd . '\s*{\zs[^}]\+\ze}'')'
let bibdata_list += map(filter(copy(lines), filter), map)
endfor
"
" Also search included files
"
for input in filter(lines, 'v:val =~ ''\C\\\%(input\|include\)\s*{[^}]\+}''')
let bibdata_list += s:bibtex_find_bibs(latex#util#kpsewhich(
\ matchstr(input, '\C\\\%(input\|include\)\s*{\zs[^}]\+\ze}')))
endfor
"
" Make all entries full paths
"
return bibdata_list
endfunction
" {{{1 s:labels_cache
"
" s:label_cache is a dictionary that maps filenames to tuples of the form
"
" [ time, labels, inputs ]
"
" where time is modification time of the cache entry, labels is a list like
" returned by extract_labels, and inputs is a list like returned by
" s:extract_inputs.
"
let s:label_cache = {}
" {{{1 s:labels_get
function! s:labels_get(file)
"
" s:labels_get compares modification time of each entry in the label cache
" and updates it if necessary. During traversal of the label cache, all
" current labels are collected and returned.
"
if !filereadable(a:file)
return []
endif
" Open file in temporary split window for label extraction.
if !has_key(s:label_cache , a:file)
\ || s:label_cache[a:file][0] != getftime(a:file)
let s:label_cache[a:file] = [
\ getftime(a:file),
\ s:labels_extract(a:file),
\ s:labels_extract_inputs(a:file),
\ ]
endif
" We need to create a copy of s:label_cache[fid][1], otherwise all inputs'
" labels would be added to the current file's label cache upon each
" completion call, leading to duplicates/triplicates/etc. and decreased
" performance. Also, because we don't anything with the list besides
" matching copies, we can get away with a shallow copy for now.
let labels = copy(s:label_cache[a:file][1])
for input in s:label_cache[a:file][2]
let labels += s:labels_get(input)
endfor
return labels
endfunction
" {{{1 s:labels_extract
function! s:labels_extract(file)
"
" Searches file for commands of the form
"
" \newlabel{name}{{number}{page}.*}.*
"
" and returns a list of [name, number, page] tuples.
"
let matches = []
let lines = readfile(a:file)
let lines = filter(lines, 'v:val =~ ''\\newlabel{''')
let lines = filter(lines, 'v:val !~ ''@cref''')
let lines = map(lines, 'latex#util#convert_back(v:val)')
for line in lines
let tree = latex#util#tex2tree(line)
call add(matches, [
\ latex#util#tree2tex(tree[1][0]),
\ latex#util#tree2tex(tree[2][0][0]),
\ latex#util#tree2tex(tree[2][1][0]),
\ ])
endfor
return matches
endfunction
" {{{1 s:labels_extract_inputs
function! s:labels_extract_inputs(file)
"
" Searches file for \@input{file} entries and returns list of all files.
"
let matches = []
for line in filter(readfile(a:file), 'v:val =~ ''\\@input{''')
call add(matches, matchstr(line, '{\zs.*\ze}'))
endfor
return matches
endfunction
" }}}1
" {{{1 s:next_chars_match
function! s:next_chars_match(regex)
return strpart(getline('.'), col('.') - 1) =~ a:regex
endfunction
" }}}1
" vim:fdm=marker:ff=unix

291
autoload/latex/fold.vim Normal file
View File

@ -0,0 +1,291 @@
" {{{1 latex#fold#init
function! latex#fold#init(initialized)
if g:latex_fold_enabled
setl foldmethod=expr
setl foldexpr=latex#fold#level(v:lnum)
setl foldtext=latex#fold#text()
call latex#fold#refresh()
if g:latex_default_mappings
nnoremap <silent><buffer> zx :call latex#fold#refresh()<cr>zx
endif
"
" The foldexpr function returns "=" for most lines, which means it can
" become slow for large files. The following is a hack that is based on
" this reply to a discussion on the Vim Developer list:
" http://permalink.gmane.org/gmane.editors.vim.devel/14100
"
if !a:initialized
augroup latex_fold
autocmd!
autocmd InsertEnter *.tex setlocal foldmethod=manual
autocmd InsertLeave *.tex setlocal foldmethod=expr
augroup END
endif
endif
endfunction
" {{{1 latex#fold#refresh
function! latex#fold#refresh()
" Parse tex file to dynamically set the sectioning fold levels
let b:latex.fold_sections = s:find_fold_sections()
endfunction
" {{{1 latex#fold#level
function! latex#fold#level(lnum)
" Check for normal lines first (optimization)
let line = getline(a:lnum)
if line !~ '\(% Fake\|\\\(document\|begin\|end\|'
\ . 'front\|main\|back\|app\|sub\|section\|chapter\|part\)\)'
return "="
endif
" Fold preamble
if g:latex_fold_preamble
if line =~# '\s*\\documentclass'
return ">1"
elseif line =~# '^\s*\\begin\s*{\s*document\s*}'
return "0"
endif
endif
" Fold parts (\frontmatter, \mainmatter, \backmatter, and \appendix)
if line =~# '^\s*\\\%(' . join(g:latex_fold_parts, '\|') . '\)'
return ">1"
endif
" Fold chapters and sections
for [part, level] in b:latex.fold_sections
if line =~# part
return ">" . level
endif
endfor
" Never fold \end{document}
if line =~# '^\s*\\end{document}'
return 0
endif
" Fold environments
if g:latex_fold_envs
if line =~# b:notcomment . b:notbslash . '\\begin\s*{.\{-}}'
return "a1"
elseif line =~# b:notcomment . b:notbslash . '\\end\s*{.\{-}}'
return "s1"
endif
endif
" Return foldlevel of previous line
return "="
endfunction
" {{{1 latex#fold#text
function! latex#fold#text()
" Initialize
let line = getline(v:foldstart)
let nlines = v:foldend - v:foldstart + 1
let level = ''
let title = 'Not defined'
" Fold level
let level = strpart(repeat('-', v:foldlevel-1) . '*',0,3)
if v:foldlevel > 3
let level = strpart(level, 1) . v:foldlevel
endif
let level = printf('%-3s', level)
" Preamble
if line =~ '\s*\\documentclass'
let title = "Preamble"
endif
" Parts, sections and fakesections
let sections = '\(\(sub\)*section\|part\|chapter\)'
let secpat1 = '^\s*\\' . sections . '\*\?\s*{'
let secpat2 = '^\s*\\' . sections . '\*\?\s*\['
if line =~ '\\frontmatter'
let title = "Frontmatter"
elseif line =~ '\\mainmatter'
let title = "Mainmatter"
elseif line =~ '\\backmatter'
let title = "Backmatter"
elseif line =~ '\\appendix'
let title = "Appendix"
elseif line =~ secpat1 . '.*}'
let title = matchstr(line, secpat1 . '\zs.*\ze}')
elseif line =~ secpat1
let title = matchstr(line, secpat1 . '\zs.*')
elseif line =~ secpat2 . '.*\]'
let title = matchstr(line, secpat2 . '\zs.*\ze\]')
elseif line =~ secpat2
let title = matchstr(line, secpat2 . '\zs.*')
elseif line =~ 'Fake' . sections . ':'
let title = matchstr(line,'Fake' . sections . ':\s*\zs.*')
elseif line =~ 'Fake' . sections
let title = matchstr(line, 'Fake' . sections)
endif
" Environments
if line =~ '\\begin'
" Capture environment name
let env = matchstr(line,'\\begin\*\?{\zs\w*\*\?\ze}')
" Set caption/label based on type of environment
if env == 'frame'
let label = ''
let caption = s:parse_caption_frame(line)
elseif env == 'table'
let label = s:parse_label()
let caption = s:parse_caption_table(line)
else
let label = s:parse_label()
let caption = s:parse_caption(line)
endif
" Add paranthesis to label
if label != ''
let label = substitute(strpart(label,0,54), '\(.*\)', '(\1)','')
endif
" Set size of label and caption part of string
let nl = len(label) > 56 ? 56 : len(label)
let nc = 56 - (nl + 1)
let caption = strpart(caption, 0, nc)
" Create title based on env, caption and label
let title = printf('%-12s%-' . nc . 's %' . nl . 's',
\ env, caption, label)
endif
let title = strpart(title, 0, 68)
return printf('%-3s %-68S #%5d', level, title, nlines)
endfunction
" }}}1
" {{{1 s:find_fold_sections
function! s:find_fold_sections()
"
" This function parses the tex file to find the sections that are to be
" folded and their levels, and then predefines the patterns for optimized
" folding.
"
" Initialize
let level = 1
let foldsections = []
" If we use two or more of the *matter commands, we need one more foldlevel
let nparts = 0
for part in g:latex_fold_parts
let i = 1
while i < line("$")
if getline(i) =~ '^\s*\\' . part . '\>'
let nparts += 1
break
endif
let i += 1
endwhile
if nparts > 1
let level = 2
break
endif
endfor
" Combine sections and levels, but ignore unused section commands: If we
" don't use the part command, then chapter should have the highest
" level. If we don't use the chapter command, then section should be the
" highest level. And so on.
let ignore = 1
for part in g:latex_fold_sections
" For each part, check if it is used in the file. We start adding the
" part patterns to the fold sections array whenever we find one.
let partpattern = '^\s*\(\\\|% Fake\)' . part . '\>'
if ignore
let i = 1
while i < line("$")
if getline(i) =~# partpattern
call insert(foldsections, [partpattern, level])
let level += 1
let ignore = 0
break
endif
let i += 1
endwhile
else
call insert(foldsections, [partpattern, level])
let level += 1
endif
endfor
return foldsections
endfunction
" {{{1 s:parse_label
function! s:parse_label()
let i = v:foldend
while i >= v:foldstart
if getline(i) =~ '^\s*\\label'
return matchstr(getline(i), '^\s*\\label{\zs.*\ze}')
end
let i -= 1
endwhile
return ""
endfunction
" {{{1 s:parse_caption
function! s:parse_caption(line)
let i = v:foldend
while i >= v:foldstart
if getline(i) =~ '^\s*\\caption'
return matchstr(getline(i),
\ '^\s*\\caption\(\[.*\]\)\?{\zs.\{-1,}\ze\(}\s*\)\?$')
end
let i -= 1
endwhile
" If no caption found, check for a caption comment
return matchstr(a:line,'\\begin\*\?{.*}\s*%\s*\zs.*')
endfunction
" {{{1 s:parse_caption_table
function! s:parse_caption_table(line)
let i = v:foldstart
while i <= v:foldend
if getline(i) =~ '^\s*\\caption'
return matchstr(getline(i),
\ '^\s*\\caption\(\[.*\]\)\?{\zs.\{-1,}\ze\(}\s*\)\?$')
end
let i += 1
endwhile
" If no caption found, check for a caption comment
return matchstr(a:line,'\\begin\*\?{.*}\s*%\s*\zs.*')
endfunction
" {{{1 s:parse_caption_frame
function! s:parse_caption_frame(line)
" Test simple variants first
let caption1 = matchstr(a:line,'\\begin\*\?{.*}{\zs.\+\ze}')
let caption2 = matchstr(a:line,'\\begin\*\?{.*}{\zs.\+')
if len(caption1) > 0
return caption1
elseif len(caption2) > 0
return caption2
else
let i = v:foldstart
while i <= v:foldend
if getline(i) =~ '^\s*\\frametitle'
return matchstr(getline(i),
\ '^\s*\\frametitle\(\[.*\]\)\?{\zs.\{-1,}\ze\(}\s*\)\?$')
end
let i += 1
endwhile
" If no caption found, check for a caption comment
return matchstr(a:line,'\\begin\*\?{.*}\s*%\s*\zs.*')
endif
endfunction
" }}}1
" vim:fdm=marker:ff=unix

226
autoload/latex/latexmk.vim Normal file
View File

@ -0,0 +1,226 @@
" {{{1 latex#latexmk#init
function! latex#latexmk#init(initialized)
if !g:latex_latexmk_enabled | return | endif
"
" Initialize pid for current tex file
"
if !has_key(g:latex#data[b:latex.id], 'pid')
let g:latex#data[b:latex.id].pid = 0
endif
"
" Set default mappings
"
if g:latex_default_mappings
nnoremap <silent><buffer> <localleader>ll :call latex#latexmk#compile()<cr>
nnoremap <silent><buffer> <localleader>lc :call latex#latexmk#clean()<cr>
nnoremap <silent><buffer> <localleader>lC :call latex#latexmk#clean(1)<cr>
nnoremap <silent><buffer> <localleader>lg :call latex#latexmk#status()<cr>
nnoremap <silent><buffer> <localleader>lG :call latex#latexmk#status(1)<cr>
nnoremap <silent><buffer> <localleader>lk :call latex#latexmk#stop(1)<cr>
nnoremap <silent><buffer> <localleader>lK :call latex#latexmk#stop_all()<cr>
nnoremap <silent><buffer> <localleader>le :call latex#latexmk#errors()<cr>
endif
"
" Ensure that all latexmk processes are stopped when vim exits
" Note: Only need to define this once, globally.
"
if !a:initialized
augroup latex_latexmk
autocmd!
autocmd VimLeave *.tex call latex#latexmk#stop_all()
augroup END
endif
"
" If all buffers for a given latex project are closed, kill latexmk
" Note: This must come after the above so that the autocmd group is properly
" refreshed if necessary
"
augroup latex_latexmk
autocmd BufUnload <buffer> call s:stop_buffer()
augroup END
endfunction
" {{{1 latex#latexmk#clean
function! latex#latexmk#clean(...)
let full = a:0 > 0
let data = g:latex#data[b:latex.id]
if data.pid
echomsg "latexmk is already running"
return
endif
"
" Run latexmk clean process
"
let cmd = '!cd ' . data.root . ';'
if full
let cmd .= 'latexmk -C '
else
let cmd .= 'latexmk -c '
endif
let cmd .= data.base . ' &>/dev/null'
let g:latex#data[b:latex.id].clean_cmd = cmd
call s:execute(cmd)
if full
echomsg "latexmk full clean finished"
else
echomsg "latexmk clean finished"
endif
endfunction
" {{{1 latex#latexmk#compile
function! latex#latexmk#compile()
let data = g:latex#data[b:latex.id]
if data.pid
echomsg "latexmk is already running for `" . data.base . "'"
return
endif
"
" Set latexmk command with options
"
let cmd = '!cd ' . data.root . ' && '
let cmd .= 'max_print_line=2000 latexmk'
let cmd .= ' -' . g:latex_latexmk_output
let cmd .= ' -quiet '
let cmd .= ' -pvc'
let cmd .= g:latex_latexmk_options
let cmd .= ' -e ' . shellescape('$pdflatex =~ s/ / -file-line-error /')
let cmd .= ' -e ' . shellescape('$latex =~ s/ / -file-line-error /')
let cmd .= ' ' . data.base
let cmd .= ' &>/dev/null &'
let g:latex#data[b:latex.id].cmd = cmd
"
" Start latexmk and save PID
"
call s:execute(cmd)
let g:latex#data[b:latex.id].pid = system('pgrep -nf latexmk')[:-2]
echomsg 'latexmk started successfully'
endfunction
" {{{1 latex#latexmk#errors
function! latex#latexmk#errors()
let log = g:latex#data[b:latex.id].log()
cclose
if g:latex_latexmk_autojump
execute 'cfile ' . log
else
execute 'cgetfile ' . log
endif
botright copen
endfunction
" {{{1 latex#latexmk#status
function! latex#latexmk#status(...)
let detailed = a:0 > 0
if detailed
let running = 0
for data in g:latex#data
if data.pid
if !running
echo "latexmk is running"
let running = 1
endif
let name = data.tex
if len(name) >= winwidth('.') - 20
let name = "..." . name[-winwidth('.')+23:]
endif
echom printf('pid: %6s, file: %-s', data.pid, name)
endif
endfor
if !running
echo "latexmk is not running"
endif
else
if g:latex#data[b:latex.id].pid
echo "latexmk is running"
else
echo "latexmk is not running"
endif
endif
endfunction
" {{{1 latex#latexmk#stop
function! latex#latexmk#stop(...)
let l:verbose = a:0 > 0
let pid = g:latex#data[b:latex.id].pid
let base = g:latex#data[b:latex.id].base
if pid
call s:execute('!kill ' . pid)
let g:latex#data[b:latex.id].pid = 0
if l:verbose
echo "latexmk stopped for `" . base . "'"
endif
elseif l:verbose
echo "latexmk is not running for `" . base . "'"
endif
endfunction
" {{{1 latex#latexmk#stop_all
function! latex#latexmk#stop_all()
for data in g:latex#data
if data.pid
call s:execute('!kill ' . data.pid)
let data.pid = 0
endif
endfor
endfunction
" }}}1
" {{{1 s:stop_buffer
function! s:stop_buffer()
"
" Only run if latex variables are set
"
if !exists('b:latex') | return | endif
let id = b:latex.id
let pid = g:latex#data[id].pid
"
" Only stop if latexmk is running
"
if pid
"
" Count the number of buffers that point to current latex blob
"
let n = 0
for b in filter(range(1, bufnr("$")), 'buflisted(v:val)')
if id == getbufvar(b, 'latex', {'id' : -1}).id
let n += 1
endif
endfor
"
" Only stop if current buffer is the last for current latex blob
"
if n == 1
call latex#latexmk#stop(0)
endif
endif
endfunction
" {{{1 s:execute
function! s:execute(cmd)
silent execute a:cmd
if !has('gui_running')
redraw!
endif
endfunction
" }}}1
" vim:fdm=marker:ff=unix

275
autoload/latex/motion.vim Normal file
View File

@ -0,0 +1,275 @@
" {{{1 latex#motion#init
function! latex#motion#init(initialized)
if !g:latex_motion_enabled | return | endif
if g:latex_default_mappings
nnoremap <silent><buffer> % :call latex#motion#find_matching_pair('n')<cr>
vnoremap <silent><buffer> %
\ :<c-u>call latex#motion#find_matching_pair('v')<cr>
onoremap <silent><buffer> % :call latex#motion#find_matching_pair('o')<cr>
nnoremap <silent><buffer> ]] :call latex#motion#next_sec(0,0,0)<cr>
nnoremap <silent><buffer> ][ :call latex#motion#next_sec(1,0,0)<cr>
nnoremap <silent><buffer> [] :call latex#motion#next_sec(1,1,0)<cr>
nnoremap <silent><buffer> [[ :call latex#motion#next_sec(0,1,0)<cr>
vnoremap <silent><buffer> ]] :<c-u>call latex#motion#next_sec(0,0,1)<cr>
vnoremap <silent><buffer> ][ :<c-u>call latex#motion#next_sec(1,0,1)<cr>
vnoremap <silent><buffer> [] :<c-u>call latex#motion#next_sec(1,1,1)<cr>
vnoremap <silent><buffer> [[ :<c-u>call latex#motion#next_sec(0,1,1)<cr>
onoremap <silent><buffer> ]] :normal v]]<cr>
onoremap <silent><buffer> ][ :normal v][<cr>
onoremap <silent><buffer> [] :normal v[]<cr>
onoremap <silent><buffer> [[ :normal v[[<cr>
vnoremap <silent><buffer> ie :latex#motion#select_current_env('inner')<cr>
vnoremap <silent><buffer> ae :latex#motion#select_current_env('outer')<cr>
onoremap <silent><buffer> ie :normal vie<cr>
onoremap <silent><buffer> ae :normal vae<cr>
vnoremap <silent><buffer> i$ :latex#motion#select_inline_math('inner')<cr>
vnoremap <silent><buffer> a$ :latex#motion#select_inline_math('outer')<cr>
onoremap <silent><buffer> i$ :normal vi$<cr>
onoremap <silent><buffer> a$ :normal va$<cr>
endif
"
" Highlight matching parens ($, (), ...)
"
if !a:initialized && g:latex_motion_matchparen
augroup latex_motion
autocmd!
" Disable matchparen autocommands
autocmd BufEnter *.tex
\ if !exists("g:loaded_matchparen") || !g:loaded_matchparen
\ | runtime plugin/matchparen.vim
\ | endif
autocmd BufEnter *.tex
\ 3match none | unlet! g:loaded_matchparen | au! matchparen
" Enable latex matchparen functionality
autocmd! CursorMoved *.tex call latex#motion#find_matching_pair('h')
autocmd! CursorMovedI *.tex call latex#motion#find_matching_pair('i')
augroup END
endif
endfunction
" {{{1 latex#motion#find_matching_pair
function! latex#motion#find_matching_pair(mode)
"
" Note: This code is ugly, but it seems to work.
"
if a:mode =~ 'h\|i'
2match none
elseif a:mode == 'v'
normal! gv
endif
if latex#util#in_comment() | return | endif
let lnum = line('.')
let cnum = searchpos('\A', 'cbnW', lnum)[1]
" Check if previous char is a backslash
if strpart(getline(lnum), cnum-2, 1) == '\'
let cnum = cnum-1
endif
" Make pattern to combine all open/close pats
let all_pats = join(g:latex_motion_open_pats+g:latex_motion_close_pats, '\|')
let all_pats = '\(' . all_pats . '\|\$\)'
let delim = matchstr(getline(lnum), '\C^'. all_pats, cnum-1)
if empty(delim) || strlen(delim)+cnum-1 < col('.')
if a:mode =~ 'n\|v\|o'
" if not found, search forward
let cnum = match(getline(lnum), '\C'. all_pats, col('.') - 1) + 1
if cnum == 0 | return | endif
call cursor(lnum, cnum)
let delim = matchstr(getline(lnum), '\C^'. all_pats, cnum - 1)
elseif a:mode =~ 'i'
" if not found, move one char bacward and search
let cnum = searchpos('\A', 'bnW', lnum)[1]
" if the previous char is a backslash
if strpart(getline(lnum), cnum-2, 1) == '\'
let cnum = cnum-1
endif
let delim = matchstr(getline(lnum), '\C^'. all_pats, cnum - 1)
if empty(delim) || strlen(delim)+cnum< col('.')
return
endif
elseif a:mode =~ 'h'
return
endif
endif
if delim =~ '^\$'
" match $-pairs
" check if next character is in inline math
let [lnum0, cnum0] = searchpos('.', 'nW')
if lnum0 && latex#util#has_syntax('texMathZoneX', lnum0, cnum0)
let [lnum2, cnum2] = searchpos(b:notcomment . b:notbslash . '\$',
\ 'nW', line('w$')*(a:mode =~ 'h\|i'), 200)
else
let [lnum2, cnum2] = searchpos('\%(\%'. lnum . 'l\%'
\ . cnum . 'c\)\@!'. b:notcomment . b:notbslash . '\$',
\ 'bnW', line('w0')*(a:mode =~ 'h\|i'), 200)
endif
if a:mode =~ 'h\|i'
execute '2match MatchParen /\%(\%' . lnum . 'l\%'
\ . cnum . 'c\$' . '\|\%' . lnum2 . 'l\%' . cnum2 . 'c\$\)/'
elseif a:mode =~ 'n\|v\|o'
call cursor(lnum2,cnum2)
endif
else
" match other pairs
for i in range(len(g:latex_motion_open_pats))
let open_pat = b:notbslash . g:latex_motion_open_pats[i]
let close_pat = b:notbslash . g:latex_motion_close_pats[i]
if delim =~# '^' . open_pat
" if on opening pattern, search for closing pattern
let [lnum2, cnum2] = searchpairpos('\C' . open_pat, '', '\C'
\ . close_pat, 'nW', 'latex#util#in_comment()',
\ line('w$')*(a:mode =~ 'h\|i'), 200)
if a:mode =~ 'h\|i'
execute '2match MatchParen /\%(\%' . lnum . 'l\%' . cnum
\ . 'c' . g:latex_motion_open_pats[i] . '\|\%'
\ . lnum2 . 'l\%' . cnum2 . 'c'
\ . g:latex_motion_close_pats[i] . '\)/'
elseif a:mode =~ 'n\|v\|o'
call cursor(lnum2,cnum2)
if strlen(close_pat)>1 && a:mode =~ 'o'
call cursor(lnum2, matchend(getline('.'), '\C'
\ . close_pat, col('.')-1))
endif
endif
break
elseif delim =~# '^' . close_pat
" if on closing pattern, search for opening pattern
let [lnum2, cnum2] = searchpairpos('\C' . open_pat, '',
\ '\C\%(\%'. lnum . 'l\%' . cnum . 'c\)\@!'
\ . close_pat, 'bnW', 'latex#util#in_comment()',
\ line('w0')*(a:mode =~ 'h\|i'), 200)
if a:mode =~ 'h\|i'
execute '2match MatchParen /\%(\%' . lnum2 . 'l\%' . cnum2
\ . 'c' . g:latex_motion_open_pats[i] . '\|\%'
\ . lnum . 'l\%' . cnum . 'c'
\ . g:latex_motion_close_pats[i] . '\)/'
elseif a:mode =~ 'n\|v\|o'
call cursor(lnum2,cnum2)
endif
break
endif
endfor
endif
endfunction
" {{{1 latex#motion#next_sec
function! latex#motion#next_sec(type, backwards, visual)
" Restore visual mode if desired
if a:visual
normal! gv
endif
" For the [] and ][ commands we move up or down before the search
if a:type == 1
if a:backwards
normal! k
else
normal! j
endif
endif
" Define search pattern and do the search while preserving "/
let save_search = @/
let flags = 'W'
if a:backwards
let flags = 'b' . flags
endif
" Define section pattern
let sec_pat = join([
\ '(sub)*section',
\ 'chapter',
\ 'part',
\ 'appendix',
\ '(front|back|main)matter',
\ ], '|')
let sec_pat = b:notcomment . '\v\s*\\(' . sec_pat . ')>'
" Perform the search
call search(sec_pat, flags)
let @/ = save_search
" For the [] and ][ commands we move down or up after the search
if a:type == 1
if a:backwards
normal! j
else
normal! k
endif
endif
endfunction
" {{{1 latex#motion#select_current_env
function! latex#motion#select_current_env(seltype)
let [env, lnum, cnum, lnum2, cnum2] = latex#util#get_env(1)
call cursor(lnum, cnum)
if a:seltype == 'inner'
if env =~ '^\'
call search('\\.\_\s*\S', 'eW')
else
call search('}\(\_\s*\[\_[^]]*\]\)\?\_\s*\S', 'eW')
endif
endif
if visualmode() ==# 'V'
normal! V
else
normal! v
endif
call cursor(lnum2, cnum2)
if a:seltype == 'inner'
call search('\S\_\s*', 'bW')
else
if env =~ '^\'
normal! l
else
call search('}', 'eW')
endif
endif
endfunction
" {{{1 latex#motion#select_inline_math
function! latex#motion#select_inline_math(seltype)
" seltype is either 'inner' or 'outer'
let dollar_pat = '\\\@<!\$'
if latex#util#has_syntax('texMathZoneX')
call s:search_and_skip_comments(dollar_pat, 'cbW')
elseif getline('.')[col('.') - 1] == '$'
call s:search_and_skip_comments(dollar_pat, 'bW')
else
return
endif
if a:seltype == 'inner'
normal! l
endif
if visualmode() ==# 'V'
normal! V
else
normal! v
endif
call s:search_and_skip_comments(dollar_pat, 'W')
if a:seltype == 'inner'
normal! h
endif
endfunction
" }}}1
" vim:fdm=marker:ff=unix

197
autoload/latex/toc.vim Normal file
View File

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

231
autoload/latex/util.vim Normal file
View File

@ -0,0 +1,231 @@
"
" Utility functions sorted by name
"
" {{{1 latex#util#convert_back
function! latex#util#convert_back(line)
"
" Substitute stuff like '\IeC{\"u}' to corresponding unicode symbols
"
let line = a:line
for [pat, symbol] in s:convert_back_list
let line = substitute(line, pat, symbol, 'g')
endfor
"
" There might be some missing conversions, which might be fixed by the last
" substitution
"
return substitute(line, '\C\(\\IeC\s*{\)\?\\.\(.\)}', '\1', 'g')
endfunction
let s:convert_back_list = map([
\ ['\\''A}' , 'Á'],
\ ['\\`A}' , 'À'],
\ ['\\^A}' , 'À'],
\ ['\\¨A}' , 'Ä'],
\ ['\\"A}' , 'Ä'],
\ ['\\''a}' , 'á'],
\ ['\\`a}' , 'à'],
\ ['\\^a}' , 'à'],
\ ['\\¨a}' , 'ä'],
\ ['\\"a}' , 'ä'],
\ ['\\''E}' , 'É'],
\ ['\\`E}' , 'È'],
\ ['\\^E}' , 'Ê'],
\ ['\\¨E}' , 'Ë'],
\ ['\\"E}' , 'Ë'],
\ ['\\''e}' , 'é'],
\ ['\\`e}' , 'è'],
\ ['\\^e}' , 'ê'],
\ ['\\¨e}' , 'ë'],
\ ['\\"e}' , 'ë'],
\ ['\\''I}' , 'Í'],
\ ['\\`I}' , 'Î'],
\ ['\\^I}' , 'Ì'],
\ ['\\¨I}' , 'Ï'],
\ ['\\"I}' , 'Ï'],
\ ['\\''i}' , 'í'],
\ ['\\`i}' , 'î'],
\ ['\\^i}' , 'ì'],
\ ['\\¨i}' , 'ï'],
\ ['\\"i}' , 'ï'],
\ ['\\''{\?\\i }' , 'í'],
\ ['\\''O}' , 'Ó'],
\ ['\\`O}' , 'Ò'],
\ ['\\^O}' , 'Ô'],
\ ['\\¨O}' , 'Ö'],
\ ['\\"O}' , 'Ö'],
\ ['\\''o}' , 'ó'],
\ ['\\`o}' , 'ò'],
\ ['\\^o}' , 'ô'],
\ ['\\¨o}' , 'ö'],
\ ['\\"o}' , 'ö'],
\ ['\\o }' , 'ø'],
\ ['\\''U}' , 'Ú'],
\ ['\\`U}' , 'Ù'],
\ ['\\^U}' , 'Û'],
\ ['\\¨U}' , 'Ü'],
\ ['\\"U}' , 'Ü'],
\ ['\\''u}' , 'ú'],
\ ['\\`u}' , 'ù'],
\ ['\\^u}' , 'û'],
\ ['\\¨u}' , 'ü'],
\ ['\\"u}' , 'ü'],
\ ['\\`N}' , 'Ǹ'],
\ ['\\\~N}' , 'Ñ'],
\ ['\\''n}' , 'ń'],
\ ['\\`n}' , 'ǹ'],
\ ['\\\~n}' , 'ñ'],
\], '[''\C\(\\IeC\s*{\)\?'' . v:val[0], v:val[1]]')
" {{{1 latex#util#get_env
function! latex#util#get_env(...)
" latex#util#get_env([with_pos])
" Returns:
" - environment
" if with_pos is not given
" - [environment, lnum_begin, cnum_begin, lnum_end, cnum_end]
" if with_pos is nonzero
if a:0 > 0
let with_pos = a:1
else
let with_pos = 0
endif
let begin_pat = '\C\\begin\_\s*{[^}]*}\|\\\@<!\\\[\|\\\@<!\\('
let end_pat = '\C\\end\_\s*{[^}]*}\|\\\@<!\\\]\|\\\@<!\\)'
let saved_pos = getpos('.')
" move to the left until on a backslash
let [bufnum, lnum, cnum, off] = getpos('.')
let line = getline(lnum)
while cnum > 1 && line[cnum - 1] != '\'
let cnum -= 1
endwhile
call cursor(lnum, cnum)
" match begin/end pairs but skip comments
let flags = 'bnW'
if strpart(getline('.'), col('.') - 1) =~ '^\%(' . begin_pat . '\)'
let flags .= 'c'
endif
let [lnum1, cnum1] = searchpairpos(begin_pat, '', end_pat, flags,
\ 'latex#util#in_comment()')
let env = ''
if lnum1
let line = strpart(getline(lnum1), cnum1 - 1)
if empty(env)
let env = matchstr(line, '^\C\\begin\_\s*{\zs[^}]*\ze}')
endif
if empty(env)
let env = matchstr(line, '^\\\[')
endif
if empty(env)
let env = matchstr(line, '^\\(')
endif
endif
if with_pos == 1
let flags = 'nW'
if !(lnum1 == lnum && cnum1 == cnum)
let flags .= 'c'
endif
let [lnum2, cnum2] = searchpairpos(begin_pat, '', end_pat, flags,
\ 'latex#util#in_comment()')
call setpos('.', saved_pos)
return [env, lnum1, cnum1, lnum2, cnum2]
else
call setpos('.', saved_pos)
return env
endif
endfunction
" {{{1 latex#util#has_syntax
function! latex#util#has_syntax(name, ...)
" Usage: latex#util#has_syntax(name, [line], [col])
let line = a:0 >= 1 ? a:1 : line('.')
let col = a:0 >= 2 ? a:2 : col('.')
return 0 <= index(map(synstack(line, col),
\ 'synIDattr(v:val, "name") == "' . a:name . '"'), 1)
endfunction
" {{{1 latex#util#in_comment
function! latex#util#in_comment(...)
let line = a:0 >= 1 ? a:1 : line('.')
let col = a:0 >= 2 ? a:2 : col('.')
return synIDattr(synID(line, col, 0), "name") =~# '^texComment'
endfunction
" {{{1 latex#util#kpsewhich
function! latex#util#kpsewhich(file, ...)
let cmd = 'kpsewhich '
let cmd .= a:0 > 0 ? a:1 : ''
let cmd .= ' "' . a:file . '"'
let out = system(cmd)
" If kpsewhich has found something, it returns a non-empty string with a
" newline at the end; otherwise the string is empty
if len(out)
" Remove the trailing newline
let out = fnamemodify(out[:-2], ':p')
endif
return out
endfunction
" {{{1 latex#util#set_default
function! latex#util#set_default(variable, default)
if !exists(a:variable)
let {a:variable} = a:default
endif
endfunction
" {{{1 latex#util#tex2tree
function! latex#util#tex2tree(str)
let tree = []
let i1 = 0
let i2 = -1
let depth = 0
while i2 < len(a:str)
let i2 = match(a:str, '[{}]', i2 + 1)
if i2 < 0
let i2 = len(a:str)
endif
if i2 >= len(a:str) || a:str[i2] == '{'
if depth == 0
let item = substitute(strpart(a:str, i1, i2 - i1),
\ '^\s*\|\s*$', '', 'g')
if !empty(item)
call add(tree, item)
endif
let i1 = i2 + 1
endif
let depth += 1
else
let depth -= 1
if depth == 0
call add(tree, latex#util#tex2tree(strpart(a:str, i1, i2 - i1)))
let i1 = i2 + 1
endif
endif
endwhile
return tree
endfunction
" {{{1 latex#util#tree2tex
function! latex#util#tree2tex(tree)
if type(a:tree) == type('')
return a:tree
else
return '{' . join(map(a:tree, 'latex#util#tree2tex(v:val)'), '') . '}'
endif
endfunction
" }}}1
" vim:fdm=marker:ff=unix

View File

@ -0,0 +1,306 @@
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$
"||" * write$
s
}
FUNCTION {fin.entry}
%{ "}" * write$
{ 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$
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$}

41
autoload/toc.vim Normal file
View File

@ -0,0 +1,41 @@
" {{{1 latextoc#fold_level
function! latextoc#fold_level(lnum)
let line = getline(a:lnum)
let match_s1 = line =~# '^\w\+\s'
let match_s2 = line =~# '^\w\+\.\w\+\s'
let match_s3 = line =~# '^\w\+\.\w\+\.\w\+\s'
if g:latex_toc_fold_levels >= 3
if match_s3
return ">3"
endif
endif
if g:latex_toc_fold_levels >= 2
if match_s2
return ">2"
endif
endif
if match_s1
return ">1"
endif
" Don't fold options
if line =~# '^\s*$'
return 0
endif
" Return previous fold level
return "="
endfunction
" {{{1 latextoc#fold_text
function! latextoc#fold_text()
let parts = matchlist(getline(v:foldstart), '^\(.*\)\t\(.*\)$')
return printf('%-8s%-72s', parts[1], parts[2])
endfunction
" }}}1
" vim:fdm=marker:ff=unix

745
doc/latex.txt Normal file
View File

@ -0,0 +1,745 @@
*latex.txt* LaTeX plugin for Vim version 7.3 (and above)
*vim-latex*
Author: Karl Yngve Lervåg <karl.yngve@gmail.com>
License: MIT license {{{
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
}}}
==============================================================================
CONTENTS *vim-latex-contents*
1. Intro ................................ |vim-latex-intro|
2. Main interface ....................... |vim-latex-main|
3. Default mappings ..................... |vim-latex-mappings|
4. Options .............................. |vim-latex-options|
5. Omni completion ...................... |vim-latex-completion|
6. Folding .............................. |vim-latex-folding|
7. Latexmk .............................. |vim-latex-latexmk|
8. Motion ............................... |vim-latex-motion|
9. Table of contents .................... |vim-latex-toc|
10. Function reference ................... |vim-latex-functions|
11. Limitations .......................... |vim-latex-limitations|
==============================================================================
INTRO *vim-latex-intro*
This vim plugin provides some convenience functionality for editing LaTeX
documents. The goal has been to create a minimalistic and functional plugin
that is easy to customize and evolve. Most of the functionality provided is
turned on by default, but the user may turn off features that are not desired.
The plugin will hereafter be referred to as |vim-latex|.
==============================================================================
MAIN INTERFACE *vim-latex-main*
The |vim-latex| interface is based on the |autoload| feature of vim. For each
new latex buffer, the function *latex#init* initializes the variables and
functionalities based on the desired options |vim-latex-options|. The first
run performs some global initialization, which is mainly to define
autocommands. Other functionality is provided by additional autoloaded
scripts, such as |vim-latex-latexmk|. Every additional script should have an
initialization script that sets default mappings, creates autocommands and
performs other necessary initialization. This initialization script is then
called from |latex#init|.
The main interface provides some basic functionality. |latex#view|, by
default mapped to '<localleader>lv', opens the current output file in
a viewer. |latex#help| lists all mappings that are defined specifically for
the current buffer, by default mapped to '<localleader>lh'. If the default
mappings are used, |latex#help| will display them. |latex#info| echoes the
contents of |g:latex#data| and |b:latex|. This is useful mainly for
debugging. Finally, |latex#reinit| clears the current data in |g:latex#data|
and |b:latex|, stops running latexmk processes |latex#latexmk#stop_all|, and
then performs a new initialization with |latex#init|.
For each latex project that is opened, a |Dictionary| is created and added to
the list |g:latex#data|. The dictionary is initialized with information tied
to the current project, mainly the different associated file names. In
addition, a dictonary is created for every buffer |b:latex|. This contains
data that is specific to the current buffer, most importantly it contains the
ID of the main latex project. This combination of local and global data
enables |vim-latex| to work properly for multi-file latex projects. It also
allows the editing of different latex projects simultaneously in different
buffers.
*g:latex#data*
A |List| of |Dictionaries|, each containing data specific to a given latex
project. The ID of a latex project is the index of its dictonary in the list.
An example of a dictionary is given here: >
{
'pid': 0,
'name': 'main',
'base': 'main.tex',
'root': '/some/path',
'tex': '/some/path/main.tex',
'aux': function('202'),
'log': function('203'),
'out': function('204'),
}
Which entries are present in a given dictionary depends on the current
settings. For example, the entry `pid` is only available if
|vim-latex-latexmk| is enabled |g:latex_latexmk_enabled|. Note that some of
the file entries are functions. The functions are used to find the files when
necessary, in case they do not exist when the latex file is opened. All
defined dictionaries can be printed with the function |latex#info|, by default
mapped to '<localleader>li'.
*b:latex*
For each buffer, |vim-latex| defines a |Dictionary| that contains buffer local
information. An example of such a dictonary is: >
{
'id': 0,
'fold_sections': [],
}
The most important entry is `id`, which is the index of the corresponding
entry in the list of latex projects |g:latex#data|. Other entries may also be
exist, such as `fold_sections`. The dictionary can be printed with the
function |latex#info|, by default mapped to '<localleader>li'.
Functions:
|latex#info|
|latex#help|
|latex#reinit|
|latex#view|
==============================================================================
DEFAULT MAPPINGS *vim-latex-mappings*
The default mappings for |vim-latex| are given below. See 'map-listing' for
an explanation of the format. The function |latex#help| is provided for
convenience to list all the defined mappings, and it is by default mapped to
'<localleader>lh'. The default mappings may be disabled with the option
|g:latex_default_mappings|, if the user wishes to create his own mappings.
n % *@:call latex#motion#find_matching_pair('n')<cr>
v % *@:<C-U>call latex#motion#find_matching_pair('v')<cr>
o % *@:call latex#motion#find_matching_pair('o')<cr>
v a$ *@:latex#motion#select_inline_math('outer')<cr>
v i$ *@:latex#motion#select_inline_math('inner')<cr>
o a$ *@:normal va$<cr>
o i$ *@:normal vi$<cr>
v ae *@:latex#motion#select_current_env('outer')<cr>
v ie *@:latex#motion#select_current_env('inner')<cr>
o ae *@:normal vae<cr>
o ie *@:normal vie<cr>
n [[ *@:call latex#motion#next_sec(0,1,0)<cr>
n [] *@:call latex#motion#next_sec(1,1,0)<cr>
n ][ *@:call latex#motion#next_sec(1,0,0)<cr>
n ]] *@:call latex#motion#next_sec(0,0,0)<cr>
v [[ *@:<C-U>call latex#motion#next_sec(0,1,1)<cr>
v [] *@:<C-U>call latex#motion#next_sec(1,1,1)<cr>
v ][ *@:<C-U>call latex#motion#next_sec(1,0,1)<cr>
v ]] *@:<C-U>call latex#motion#next_sec(0,0,1)<cr>
o [[ *@:normal v[[<cr>
o [] *@:normal v[]<cr>
o ][ *@:normal v][<cr>
o ]] *@:normal v]]<cr>
n <localleader>li *@:call latex#info()<cr>
n <localleader>lh *@:call latex#help()<cr>
n <localleader>lv *@:call latex#view()<cr>
n <localleader>lR *@:call latex#reinit()<cr>
n <localleader>lt *@:call latex#toc#open()<cr>
n <localleader>lT *@:call latex#toc#toggle()<cr>
n <localleader>ll *@:call latex#latexmk#compile()<cr>
n <localleader>lk *@:call latex#latexmk#stop(1)<cr>
n <localleader>lK *@:call latex#latexmk#stop_all()<cr>
n <localleader>le *@:call latex#latexmk#errors()<cr>
n <localleader>lg *@:call latex#latexmk#status()<cr>
n <localleader>lG *@:call latex#latexmk#status(1)<cr>
n <localleader>lc *@:call latex#latexmk#clean()<cr>
n <localleader>lC *@:call latex#latexmk#clean(1)<cr>
n zx *@:call latex#fold#refresh()<cr>zx
n <F6> *@:call latex#change#environment_toggle_star()<cr>
n <F5> *@:call latex#change#environment_prompt()<cr>
==============================================================================
OPTIONS *vim-latex-options*
This section describes the options for |vim-latex|. The options are first
listed in alphabetical order, before they are described in more detail. The
descriptions also list the default values.
Overview:~
|g:latex_build_dir|
|g:latex_complete_close_braces|
|g:latex_complete_enabled|
|g:latex_complete_patterns|
|g:latex_default_mappings|
|g:latex_errorformat_ignore_warnings|
|g:latex_errorformat_show_warnings|
|g:latex_fold_enabled|
|g:latex_fold_envs|
|g:latex_fold_parts|
|g:latex_fold_preamble|
|g:latex_fold_sections|
|g:latex_latexmk_autojump|
|g:latex_latexmk_enabled|
|g:latex_latexmk_options|
|g:latex_latexmk_output|
|g:latex_main_tex_candidates|
|g:latex_motion_close_pats|
|g:latex_motion_enabled|
|g:latex_motion_matchparen|
|g:latex_motion_open_pats|
|g:latex_toc_enabled|
|g:latex_toc_fold_levels|
|g:latex_toc_fold|
|g:latex_toc_hide_help|
|g:latex_toc_resize|
|g:latex_toc_split_side|
|g:latex_toc_width|
|g:latex_viewer|
------------------------------------------------------------------------------
Detailed descriptions and default values:~
*g:latex_build_dir*
Set this variable in case a dedicated build dir is used with latexmk/latex
compilations. >
let g:latex_build_dir = '.'
<
*g:latex_complete_close_braces*
When a label or a cite has been completed, this option controls whether it
will be followed by a closing brace. >
let g:latex_complete_close_braces = 0
<
*g:latex_complete_enabled*
Use this option to prevent the plugin from setting the 'omnifunc': >
let g:latex_complete_enabled = 1
<
*g:latex_complete_patterns*
Define patterns that control when the label and citation completion is
triggered. >
let g:latex_complete_patterns = {
\ 'ref' : '\C\\v\?\(eq\|page\|[cC]\)\?ref\*\?\_\s*{[^{}]*',
\ 'bib' : '\C\\\a*cite\a*\*\?\(\[[^\]]*\]\)*\_\s*{[^{}]*',
\ })
<
*g:latex_default_mappings*
Whether to load the default mappings. If this is set to 0, then no mappings
will be defined. Since all of the functionality is available as functions,
this allows the user to define his or her own mappings. >
let g:latex_default_mappings = 1
<
*g:latex_errorformat_ignore_warnings*
List of warning messages that should be ignored. >
let g:latex_errorformat_ignore_warnings = [
\ 'Underfull',
\ 'Overfull',
\ 'specifier changed to',
\ ]
<
*g:latex_errorformat_show_warnings*
Show warnings in quickfix window. >
let g:latex_errorformat_show_warnings = 1
<
*g:latex_fold_enabled*
Use this option to disable/enable folding. >
let g:latex_fold_enabled = 1
<
*g:latex_fold_envs*
Decide whether environments should be folded or not. >
let g:latex_fold_envs = 1
<
*g:latex_fold_parts*
List of parts that should be folded. >
let g:latex_fold_parts = [
\ "appendix",
\ "frontmatter",
\ "mainmatter",
\ "backmatter",
\ ]
<
*g:latex_fold_preamble*
Decide whether preamble should be folded or not. >
let g:latex_fold_preamble = 1
<
*g:latex_fold_sections*
List of section constructs that should be folded. >
let g:latex_fold_sections = [
\ "part",
\ "chapter",
\ "section",
\ "subsection",
\ "subsubsection",
\ ]
<
*g:latex_latexmk_autojump*
Whether to automatically jump to the first error when the error window is
opened with the default mapping or |latex#latexmk#errors|. >
let g:latex_latexmk_autojump = '0'
<
*g:latex_latexmk_enabled*
Whether to enable the latexmk interface or not. Note that even if it is not
enabled, the autoload functions will be available. However, the
necessary variables and autocommands will not be defined, and the mappings
will not be created. >
let g:latex_latexmk_enabled = 1
<
*g:latex_latexmk_options*
Set extra options for latexmk compilation. >
let g:latex_latexmk_options = ''
<
*g:latex_latexmk_output*
Set desired output for latexmk compilation. >
let g:latex_latexmk_output = 'pdf'
<
*g:latex_main_tex_candidates*
A list of common names for main tex-file candidates. This is used to find the
main tex file in multi-file projects. >
let g:latex_main_tex_candidates = [
\ 'main',
\ 'memo',
\ 'note',
\ 'report',
\ 'thesis',
\]
<
*g:latex_motion_close_pats*
Define a list of patterns that match closing braces and environments. >
let g:latex_motion_close_pats = [
\ '}',
\ ')',
\ '\]',
\ '\\}',
\ '\\)',
\ '\\\]',
\ '\\end\s*{.\{-}}',
\ '\\right\s*\%([^\\]\|\\.\|\\\a*\)',
\ ]
<
*g:latex_motion_enabled*
Whether to enable the motion interface. If it is disabled, then neither the
default mappings nor the autocommands that enable highlighting of matching
parens will be defined. >
let g:latex_motion_enabled = 1
<
*g:latex_motion_matchparen*
Enable highlighting of matching parens. This gives better support for LaTeX,
but disables the builtin |matchparen|. >
let g:latex_motion_matchparen = 1
<
*g:latex_motion_open_pats*
Define a list of patterns that match opening braces and environments. >
let g:latex_motion_open_pats = [
\ '{',
\ '(',
\ '\[',
\ '\\{',
\ '\\(',
\ '\\\[',
\ '\\begin\s*{.\{-}}',
\ '\\left\s*\%([^\\]\|\\.\|\\\a*\)',
\ ]
<
*g:latex_toc_enabled*
Enable interface for TOC. If it is disabled, then mappings for the TOC will
not be created. >
let g:latex_toc_enabled = 0
<
*g:latex_toc_fold_levels*
If TOC entries are folded, this option controls the number of fold levels that
will be used. >
let g:latex_toc_fold_levels = 0
<
*g:latex_toc_fold*
Turn on folding of TOC entries. >
let g:latex_toc_fold = 0
<
*g:latex_toc_hide_help*
Allow the TOC help text to be hidden. >
let g:latex_toc_hide_help = 0
<
*g:latex_toc_resize*
Automatically resize vim when the TOC window is opened. >
let g:latex_toc_resize = 1
<
*g:latex_toc_split_side*
Define where the TOC window is opened. >
let g:latex_toc_split_side = 'leftabove'
<
*g:latex_toc_width*
Set width of TOC window. >
let g:latex_toc_width = 30
<
*g:latex_viewer*
Set default viewer application. >
let g:latex_viewer = 'xdg-open'
<
==============================================================================
OMNI COMPLETION *vim-latex-completion*
|vim-latex| provides an 'omnifunc' for omni completion, see |compl-omni| and
|latex#complete#omnifunc|. The function is enabled by default, but may be
disabled with |g:latex_complete_enabled|. Omni completion is accessible with
'i_<CTRL-X><CTRL-O>'.
The omni function completes labels and citations. The completion candidates
are gathered with the functions |latex#complete#labels| and
|latex#complete#bibtex|. If |g:latex_complete_close_braces| is set to 1, then
the completion includes closing braces.
Associated settings:
|g:latex_complete_enabled|
|g:latex_complete_patterns.ref|
|g:latex_complete_patterns.bib|
|g:latex_complete_close_braces|
Functions:
|latex#complete#omnifunc|
|latex#complete#labels|
|latex#complete#bibtex|
------------------------------------------------------------------------------
Complete labels~
Label completion is triggered by '\ref{' commands as defined with
|g:latex_complete_patterns.ref|. The completion parses every relevant aux
file to gather the completion candidates. This is important to note, because
it means that the completion only works when the latex document has been
compiled.
As an example: >
\ref{sec:<CTRL-X><CTRL-O>
offers a list of all matching labels, with their associated value and page
number. The label completion matches:
1. labels: >
\ref{sec:<CTRL-X><CTRL-O>
< 2. numbers: >
\eqref{2<CTRL-X><CTRL-O>
< 3. labels and numbers together (separated by whitespace): >
\eqref{eq 2<CTRL-X><CTRL-O>
------------------------------------------------------------------------------
Complete citations~
Citation completion is triggered by '\cite{' commands as defined with
|g:latex_complete_patterns.bib|. The completion parses included bibliography
files (`*.bib`) and `thebibliography` environments to gather the completion
candidates.
As an example, assume that a bibliography file is included with the following
entry: >
@book { knuth1981,
author = "Donald E. Knuth",
title = "Seminumerical Algorithms",
publisher = "Addison-Wesley",
year = "1981" }
Then the bibliography key `knuth1981` will be completed with e.g.: >
\cite{Knuth 1981<CTRL-X><CTRL-O>
\cite{algo<CTRL-X><CTRL-O>
\cite{Don.*Knuth<CTRL-X><CTRL-O>
In particular, note that regular expressions (or vim patterns) can be used
after '\cite{' to search for candidates.
==============================================================================
FOLDING *vim-latex-folding*
LatexBox can fold texts according to LaTeX structure (part, chapter, section
and subsection). Folding is turned on by default, but it can be disabled if
desired |g:latex_fold_enabled|.
When folding is turned on and a latex document is opened, the document is
parsed once in order to define the highest fold level based on which parts
(such as frontmatter, backmatter, and appendix) and section types (chapter,
section, etc.) are present. If the document has been edited and a new fold
level is required (or has become redundant), then |latex#fold#refresh| can be
used to refresh the fold level settings. This function is mapped by default
to `zx`.
Associated settings:
|g:latex_fold_enabled|
|g:latex_fold_preamble|
|g:latex_fold_parts|
|g:latex_fold_sections|
|g:latex_fold_envs|
Functions:
|latex#fold#level|
|latex#fold#text|
|latex#fold#refresh|
==============================================================================
LATEXMK *vim-latex-latexmk*
|vim-latex| provides a basic interface to `latexmk` for background
compilation. The interface may be disabled with |g:latex_latexmk_enabled|.
The default mappings are: >
nnoremap <localleader>ll :call latex#latexmk#compile()<cr>
nnoremap <localleader>lk :call latex#latexmk#stop(1)<cr>
nnoremap <localleader>lK :call latex#latexmk#stop_all()<cr>
nnoremap <localleader>le :call latex#latexmk#errors()<cr>
nnoremap <localleader>lg :call latex#latexmk#status(0)<cr>
nnoremap <localleader>lG :call latex#latexmk#status(1)<cr>
nnoremap <localleader>lc :call latex#latexmk#clean(0)<cr>
nnoremap <localleader>lC :call latex#latexmk#clean(1)<cr>
The background compilation is started with |latex#latexmk#compile|, and relies
on the preview continuous mode of `latexmk`. Compilation errors are not
parsed automatically, since there is no way of knowing when the document has
been compiled. To view errors, use |latex#latexmk#errors|. To check if
compilation is running in the background, use |latex#latexmk#status|.
Associated settings:
|g:latex_latexmk_enabled|
|g:latex_latexmk_autojump|
|g:latex_latexmk_options|
|g:latex_latexmk_output|
Functions:
|latex#latexmk#clean|
|latex#latexmk#compile|
|latex#latexmk#errors|
|latex#latexmk#status|
|latex#latexmk#stop|
|latex#latexmk#stop_all|
==============================================================================
MOTION *vim-latex-motion*
|vim-latex| provides some functions that can be used to give improved motions
and text objects. |latex#motion#find_matching_pair| is also used to enable
highlighting of matching parens or tags (such as begin/end structures). The
functionality is enabled by default, but may be disabled if desired.
Associated settings:
|g:latex_motion_enabled|
|g:latex_motion_matchparen|
|g:latex_motion_open_pats|
|g:latex_motion_close_pats|
Functions:
|latex#motion#find_matching_pair|
|latex#motion#next_sec|
|latex#motion#select_current_env|
|latex#motion#select_inline_math|
==============================================================================
TABLE OF CONTENTS *vim-latex-toc*
|vim-latex| provides a table of contents (TOC) window that can be opened
|latex#toc#open| or toggled |latex#toc#toggle|. In the TOC, one can use
'<CR>' on a selected entry to navigate.
Associated settings:
|g:latex_toc_enabled|
|g:latex_toc_fold_levels|
|g:latex_toc_fold|
|g:latex_toc_hide_help|
|g:latex_toc_resize|
|g:latex_toc_split_side|
|g:latex_toc_width|
Functions:
|latex#toc#open|
|latex#toc#toggle|
==============================================================================
FUNCTION REFERENCE *vim-latex-functions*
The following is a reference of the available functions, sorted
alphabetically. First a short overview is given, then more detailed
descriptions follow.
Overview:~
|latex#complete#omnifunc|
|latex#complete#labels|
|latex#complete#bibtex|
|latex#fold#level|
|latex#fold#text|
|latex#fold#refresh|
|latex#help|
|latex#info|
|latex#latexmk#clean|
|latex#latexmk#compile|
|latex#latexmk#errors|
|latex#latexmk#status|
|latex#latexmk#stop|
|latex#latexmk#stop_all|
|latex#motion#find_matching_pair|
|latex#motion#next_sec|
|latex#motion#select_current_env|
|latex#motion#select_inline_math|
|latex#reinit|
|latex#toc#open|
|latex#toc#toggle|
|latex#view|
------------------------------------------------------------------------------
Detailed descriptions:~
*latex#complete#omnifunc*
An 'omnifunc' for label and citation completion, see |vim-latex-completion|.
*latex#complete#labels*
Parses aux files to gather label candidates for completion.
*latex#complete#bibtex*
Parses included bibliography files and `thebibliography` environments to
gather candidates for completion.
*latex#fold#level*
Sets fold level for each line. 'foldexpr' |fold-expr|
*latex#fold#text*
Sets fold title text. 'foldtext'
*latex#fold#refresh*
Refreshes fold levels based on which parts and sections used in the current
file buffer.
*latex#help*
Lists all mappings that are defined specifically for the current buffer. If
the default mappings are used, then |latex#help| will display them.
*latex#info*
Echoes the contents of |g:latex#data| and |b:latex|. This is useful mainly
for debugging.
*latex#latexmk#clean*
Clean up temporary files with `latexmk -c`. An optional argument may be
supplied to indicate that the `-C` flag should be used, which also cleans
output files. This will only be run if `latexmk` is not already running.
*latex#latexmk#compile*
Starts `latexmk -pvc ...` for the given buffer, if it is not already running.
*latex#latexmk#errors*
Displays the log file in the quickfix window. The output may be controlled
slightly with the options |g:latex_errorformat_show_warnings| and
|g:latex_errorformat_ignore_warnings|.
*latex#latexmk#status*
Show if the `latexmk` has been started for the current buffer. An optional
argument may be supplied, in which case the status for all buffers is shown.
*latex#latexmk#stop*
Stop the `latexmk` process running for the current buffer. An optional
argument may be given, in which case the function becomes verbose.
*latex#latexmk#stop_all*
Stops all running `latexmk` processes.
*latex#motion#find_matching_pair*
Finds a matching pair of parenthesis or begin-end-tags. The functions is used
*latex#motion#next_sec*
A motion command function that moves to the next section. Used to redefine
the mappings for ']]', '[[', and similar.
*latex#motion#select_current_env*
A function that is used to create text objects for environments.
*latex#motion#select_inline_math*
A function that is used to create text objects for inline math structures.
*latex#reinit*
Clears the current global and local data in |g:latex#data| and |b:latex|,
stops running latexmk processes |latex#latexmk#stop_all|, and then performs
a new initialization.
*latex#toc#open*
Open the TOC window. If it is already open, then simply move the cursor to
the TOC window.
*latex#toc#toggle*
Toggle TOC window: If TOC window is open, then close it. If it is closed,
then open it (but do not move the cursor to the window).
*latex#view*
Open the output file (specified with |g:latex_latexmk_output|) with the
default viewer |g:latex_viewer|.
==============================================================================
LIMITATIONS *vim-latex-limitations*
This plugin is written for Linux/Unix environments, and so it does NOT support
Windows. I do not plan to add support.
==============================================================================
CREDITS *vim-latex-credits*
|vim-latex| is developed by Karl Yngve Lervåg <karl.yngve@gmail.com>, and is
distributed under the MIT license. The project is available as a Git
repository: https://github.com/lervag/vim-latex.
|vim-latex| was developed from scratch, but much of the code has been based on
LaTeX-Box: https://github.com/LaTeX-Box-Team/LaTeX-Box. LaTeX-suite was also
an inspiration: http://vim-latex.sourceforge.net/.
The documentation of |vim-latex| is structured with inspiration from CtrlP
(https://github.com/kien/ctrlp.vim), simply because CtrlP has a very good
documentation.
==============================================================================
CHANGELOG *vim-latex-changelog*
First public release: 2013/10/05~
==============================================================================
vim:tw=78:ts=8:ft=help:norl:

134
ftplugin/latextoc.vim Normal file
View File

@ -0,0 +1,134 @@
" LaTeX plugin for Vim
"
" Maintainer: Karl Yngve Lervåg
" Email: karl.yngve@gmail.com
"
if exists('b:did_ftplugin')
finish
endif
let b:did_ftplugin = 1
" Set local buffer settings
setlocal buftype=nofile
setlocal bufhidden=wipe
setlocal nobuflisted
setlocal noswapfile
setlocal nowrap
setlocal nonumber
setlocal nolist
setlocal nospell
setlocal cursorline
setlocal tabstop=8
setlocal cole=0
setlocal cocu=nvic
if g:latex_toc_fold
setlocal foldmethod=expr
setlocal foldexpr=toc#fold(v:lnum)
setlocal foldtext=toc#fold_tex()
endif
" Define mappings
nnoremap <buffer> <silent> G G4k
nnoremap <buffer> <silent> <Esc>OA k
nnoremap <buffer> <silent> <Esc>OB j
nnoremap <buffer> <silent> <Esc>OC l
nnoremap <buffer> <silent> <Esc>OD h
nnoremap <buffer> <silent> s :call <SID>toc_toggle_numbers()<cr>
nnoremap <buffer> <silent> q :call <SID>toc_close()<cr>
nnoremap <buffer> <silent> <Esc> :call <SID>toc_close()<cr>
nnoremap <buffer> <silent> <Space> :call <SID>toc_activate(0)<cr>
nnoremap <buffer> <silent> <leftrelease> :call <SID>toc_activate(0)<cr>
nnoremap <buffer> <silent> <CR> :call <SID>toc_activate(1)<cr>
nnoremap <buffer> <silent> <2-leftmouse> :call <SID>toc_activate(1)<cr>
" {{{1 s:toc_activate
function! s:toc_activate(close)
let n = getpos('.')[1] - 1
if n >= len(b:toc)
return
endif
let entry = b:toc[n]
let titlestr = s:toc_escape_title(entry['text'])
" Search for duplicates
"
let i=0
let entry_hash = entry['level'].titlestr
let duplicates = 0
while i<n
let i_entry = b:toc[n]
let i_hash = b:toc[i]['level'].s:toc_escape_title(b:toc[i]['text'])
if i_hash == entry_hash
let duplicates += 1
endif
let i += 1
endwhile
let toc_bnr = bufnr('%')
let toc_wnr = winnr()
execute b:calling_win . 'wincmd w'
let bnr = bufnr(entry['file'])
if bnr == -1
execute 'badd ' . entry['file']
let bnr = bufnr(entry['file'])
endif
execute 'buffer! ' . bnr
" skip duplicates
while duplicates > 0
if search('\\' . entry['level'] . '\_\s*{' . titlestr . '}', 'ws')
let duplicates -= 1
endif
endwhile
if search('\\' . entry['level'] . '\_\s*{' . titlestr . '}', 'ws')
normal zv
endif
if a:close
if g:latex_toc_resize
silent exe "set columns-=" . g:latex_toc_width
endif
execute 'bwipeout ' . toc_bnr
else
execute toc_wnr . 'wincmd w'
endif
endfunction
" {{{1 s:toc_close
function! s:toc_close()
if g:latex_toc_resize
silent exe "set columns-=" . g:latex_toc_width
endif
bwipeout
endfunction
" {{{1 s:toc_escape_title
function! s:toc_escape_title(titlestr)
" Credit goes to Marcin Szamotulski for the following fix. It allows to
" match through commands added by TeX.
let titlestr = substitute(a:titlestr, '\\\w*\>\s*\%({[^}]*}\)\?', '.*', 'g')
let titlestr = escape(titlestr, '\')
return substitute(titlestr, ' ', '\\_\\s\\+', 'g')
endfunction
" {{{1 s:toc_toggle_numbers
function! s:toc_toggle_numbers()
if b:toc_numbers
setlocal conceallevel=3
let b:toc_numbers = 0
else
setlocal conceallevel=0
let b:toc_numbers = 1
endif
endfunction
" }}}1
" vim:fdm=marker:ff=unix

105
ftplugin/tex.vim Normal file
View File

@ -0,0 +1,105 @@
" LaTeX plugin for Vim
"
" Maintainer: Karl Yngve Lervåg
" Email: karl.yngve@gmail.com
"
if exists('b:did_ftplugin')
finish
endif
let b:did_ftplugin = 1
" Set default options
" {{{1 Completion
call latex#util#set_default('g:latex_complete_enabled', 1)
call latex#util#set_default('g:latex_complete_close_braces', 0)
call latex#util#set_default('g:latex_complete_patterns', {
\ 'ref' : '\C\\v\?\(eq\|page\|[cC]\)\?ref\*\?\_\s*{[^{}]*',
\ 'bib' : '\C\\\a*cite\a*\*\?\(\[[^\]]*\]\)*\_\s*{[^{}]*',
\ })
" {{{1 Folding
call latex#util#set_default('g:latex_fold_enabled', 1)
call latex#util#set_default('g:latex_fold_preamble', 1)
call latex#util#set_default('g:latex_fold_envs', 1)
call latex#util#set_default('g:latex_fold_parts',
\ [
\ "appendix",
\ "frontmatter",
\ "mainmatter",
\ "backmatter",
\ ])
call latex#util#set_default('g:latex_fold_sections',
\ [
\ "part",
\ "chapter",
\ "section",
\ "subsection",
\ "subsubsection",
\ ])
" {{{1 Latexmk
call latex#util#set_default('g:latex_latexmk_enabled', 1)
call latex#util#set_default('g:latex_latexmk_options', '')
call latex#util#set_default('g:latex_latexmk_output', 'pdf')
call latex#util#set_default('g:latex_latexmk_autojump', '0')
" {{{1 Miscelleneous
call latex#util#set_default('g:latex_default_mappings', 1)
call latex#util#set_default('g:latex_viewer', 'xdg-open')
call latex#util#set_default('g:latex_build_dir', '.')
call latex#util#set_default('g:latex_main_tex_candidates',
\ [
\ 'main',
\ 'memo',
\ 'note',
\ 'report',
\ 'thesis',
\])
call latex#util#set_default('g:latex_errorformat_show_warnings', 1)
call latex#util#set_default('g:latex_errorformat_ignore_warnings',
\ [
\ 'Underfull',
\ 'Overfull',
\ 'specifier changed to',
\ ])
" {{{1 Motion
call latex#util#set_default('g:latex_motion_enabled', 1)
call latex#util#set_default('g:latex_motion_matchparen', 1)
call latex#util#set_default('g:latex_motion_open_pats',
\ [
\ '{',
\ '(',
\ '\[',
\ '\\{',
\ '\\(',
\ '\\\[',
\ '\\begin\s*{.\{-}}',
\ '\\left\s*\%([^\\]\|\\.\|\\\a*\)',
\ ])
call latex#util#set_default('g:latex_motion_close_pats',
\ [
\ '}',
\ ')',
\ '\]',
\ '\\}',
\ '\\)',
\ '\\\]',
\ '\\end\s*{.\{-}}',
\ '\\right\s*\%([^\\]\|\\.\|\\\a*\)',
\ ])
" {{{1 Toc
call latex#util#set_default('g:latex_toc_enabled', 1)
call latex#util#set_default('g:latex_toc_width', 30)
call latex#util#set_default('g:latex_toc_split_side', 'leftabove')
call latex#util#set_default('g:latex_toc_resize', 1)
call latex#util#set_default('g:latex_toc_hide_help', 0)
call latex#util#set_default('g:latex_toc_fold', 0)
call latex#util#set_default('g:latex_toc_fold_levels', 0)
" }}}1
call latex#init()
" vim:fdm=marker:ff=unix

10
syntax/latextoc.vim Normal file
View File

@ -0,0 +1,10 @@
syntax match helpText /^.*: .*/
syntax match secNum /^\S\+\(\.\S\+\)\?\s*/ contained conceal
syntax match secLine /^\S\+\t.\+/ contains=secNum
syntax match mainSecLine /^[^\.]\+\t.*/ contains=secNum
syntax match ssubSecLine /^[^\.]\+\.[^\.]\+\.[^\.]\+\t.*/ contains=secNum
highlight link helpText PreProc
highlight link secNum Number
highlight link mainSecLine Title
highlight link ssubSecLine Comment