diff options
Diffstat (limited to 'ftplugin/latex-box/complete.vim')
-rw-r--r-- | ftplugin/latex-box/complete.vim | 805 |
1 files changed, 805 insertions, 0 deletions
diff --git a/ftplugin/latex-box/complete.vim b/ftplugin/latex-box/complete.vim new file mode 100644 index 00000000..76f909b9 --- /dev/null +++ b/ftplugin/latex-box/complete.vim @@ -0,0 +1,805 @@ +" LaTeX Box completion + +setlocal omnifunc=LatexBox_Complete + +" <SID> Wrap {{{ +function! s:GetSID() + return matchstr(expand('<sfile>'), '\zs<SNR>\d\+_\ze.*$') +endfunction +let s:SID = s:GetSID() +function! s:SIDWrap(func) + return s:SID . a:func +endfunction +" }}} + +" 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 = '\C\\\a*cite\a*\*\?\(\[[^\]]*\]\)*\_\s*{' +endif +if !exists('g:LatexBox_ref_pattern') + let g:LatexBox_ref_pattern = '\C\\v\?\(eq\|page\|[cC]\)\?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': '\chapter{' }, + \ {'word': '\section{' }, + \ {'word': '\subsection{' }, + \ {'word': '\subsubsection{' }, + \ {'word': '\paragraph{' }, + \ {'word': '\nonumber' }, + \ {'word': '\bibliography' }, + \ {'word': '\bibliographystyle' }, + \ ] +endif + +if !exists('g:LatexBox_complete_inlineMath') + let g:LatexBox_complete_inlineMath = 0 +endif + +if !exists('g:LatexBox_eq_env_patterns') + let g:LatexBox_eq_env_patterns = 'equation\|gather\|multiline\|align\|flalign\|alignat\|eqnarray' +endif + +" }}} + +"LatexBox_kpsewhich {{{ +function! LatexBox_kpsewhich(file) + let old_dir = getcwd() + execute 'lcd ' . fnameescape(LatexBox_GetTexRoot()) + let out = system('kpsewhich "' . a:file . '"') + + " 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 + + execute 'lcd ' . fnameescape(old_dir) + + return out +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 + + let line_start = line[:pos-1] + if line_start =~ '\C\\begin\_\s*{$' + let s:completion_type = 'begin' + elseif line_start =~ '\C\\end\_\s*{$' + let s:completion_type = 'end' + elseif line_start =~ g:LatexBox_ref_pattern . '$' + let s:completion_type = 'ref' + elseif line_start =~ 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 + elseif s:LatexBox_complete_inlineMath_or_not() + let s:completion_type = 'inlineMath' + let pos = s:eq_pos + 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 && !s:NextCharsMatch('^}') + " 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 = LatexBox_GetCurrentEnvironment() + if env != '' + if g:LatexBox_completion_close_braces && !s:NextCharsMatch('^\s*[,}]') + 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) + elseif s:completion_type == 'inlineMath' + let suggestions = s:LatexBox_inlineMath_completion(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 + + if !filereadable(file) + return '' + endif + + let bibliography_cmds = [ + \ '\\bibliography', + \ '\\addbibresource', + \ '\\addglobalbib', + \ '\\addsectionbib', + \ ] + + let lines = readfile(file) + + let bibdata_list = [] + + for cmd in bibliography_cmds + let bibdata_list += map(filter(copy(lines), + \ 'v:val =~ ''\C' . cmd . '\s*{[^}]\+}'''), + \ 'matchstr(v:val, ''\C' . cmd . '\s*{\zs[^}]\+\ze}'')') + endfor + + let bibdata_list += map(filter(copy(lines), + \ 'v:val =~ ''\C\\\%(input\|include\)\s*{[^}]\+}'''), + \ 's:FindBibData(LatexBox_kpsewhich(matchstr(v:val,' + \ . '''\C\\\%(input\|include\)\s*{\zs[^}]\+\ze}'')))') + + let bibdata_list += map(filter(copy(lines), + \ 'v:val =~ ''\C\\\%(input\|include\)\s\+\S\+'''), + \ 's:FindBibData(LatexBox_kpsewhich(matchstr(v:val,' + \ . '''\C\\\%(input\|include\)\s\+\zs\S\+\ze'')))') + + return join(bibdata_list, ',') +endfunction + +let s:bstfile = expand('<sfile>:p:h') . '/vimcomplete' + +function! LatexBox_BibSearch(regexp) + let res = [] + + " Find data from bib files + let bibdata = s:FindBibData() + if bibdata != '' + + " 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 lines = split(substitute(join(readfile(bblfile), "\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(auxfile) + call delete(bblfile) + call delete(blgfile) + endif + + " Find data from 'thebibliography' environments + let lines = readfile(LatexBox_GetMainTexFile()) + 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 +" }}} + +" 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 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 needed + if g:LatexBox_completion_close_braces && !s:NextCharsMatch('^\s*[,}]') + let w.word = w.word . '}' + endif + + call add(res, w) + endfor + return res +endfunction +" }}} + +" ExtractLabels {{{ +" Generate list of \newlabel commands in current buffer. +" +" Searches the current buffer for commands of the form +" \newlabel{name}{{number}{page}.* +" and returns list of [ name, number, page ] tuples. +function! s:ExtractLabels() + call cursor(1,1) + + let matches = [] + let [lblline, lblbegin] = searchpos( '\\newlabel{', 'ecW' ) + + while [lblline, lblbegin] != [0,0] + let [nln, nameend] = searchpairpos( '{', '', '}', 'W' ) + if nln != lblline + let [lblline, lblbegin] = searchpos( '\\newlabel{', 'ecW' ) + continue + endif + let curname = strpart( getline( lblline ), lblbegin, nameend - lblbegin - 1 ) + + " Ignore cref entries (because they are duplicates) + if curname =~ "\@cref" + continue + endif + + if 0 == search( '{\w*{', 'ce', lblline ) + let [lblline, lblbegin] = searchpos( '\\newlabel{', 'ecW' ) + continue + endif + + let numberbegin = getpos('.')[2] + let [nln, numberend] = searchpairpos( '{', '', '}', 'W' ) + if nln != lblline + let [lblline, lblbegin] = searchpos( '\\newlabel{', 'ecW' ) + continue + endif + let curnumber = strpart( getline( lblline ), numberbegin, numberend - numberbegin - 1 ) + + if 0 == search( '\w*{', 'ce', lblline ) + let [lblline, lblbegin] = searchpos( '\\newlabel{', 'ecW' ) + continue + endif + + let pagebegin = getpos('.')[2] + let [nln, pageend] = searchpairpos( '{', '', '}', 'W' ) + if nln != lblline + let [lblline, lblbegin] = searchpos( '\\newlabel{', 'ecW' ) + continue + endif + let curpage = strpart( getline( lblline ), pagebegin, pageend - pagebegin - 1 ) + + let matches += [ [ curname, curnumber, curpage ] ] + + let [lblline, lblbegin] = searchpos( '\\newlabel{', 'ecW' ) + endwhile + + return matches +endfunction +"}}} + +" ExtractInputs {{{ +" Generate list of \@input commands in current buffer. +" +" Searches the current buffer for \@input{file} entries and +" returns list of all files. +function! s:ExtractInputs() + call cursor(1,1) + + let matches = [] + let [inline, inbegin] = searchpos( '\\@input{', 'ecW' ) + + while [inline, inbegin] != [0,0] + let [nln, inend] = searchpairpos( '{', '', '}', 'W' ) + if nln != inline + let [inline, inbegin] = searchpos( '\\@input{', 'ecW' ) + continue + endif + let matches += [ LatexBox_kpsewhich(strpart( getline( inline ), inbegin, inend - inbegin - 1 )) ] + + let [inline, inbegin] = searchpos( '\\@input{', 'ecW' ) + endwhile + + " Remove empty strings for nonexistant .aux files + return filter(matches, 'v:val != ""') +endfunction +"}}} + +" LabelCache {{{ +" Cache of all labels. +" +" LabelCache is a dictionary mapping filenames to tuples +" [ time, labels, inputs ] +" where +" * time is modification time of the cache entry +" * labels is a list like returned by ExtractLabels +" * inputs is a list like returned by ExtractInputs +let s:LabelCache = {} +"}}} + +" GetLabelCache {{{ +" Extract labels from LabelCache and update it. +" +" Compares modification time of each entry in the label +" cache and updates it, if necessary. During traversal of +" the LabelCache, all current labels are collected and +" returned. +function! s:GetLabelCache(file) + if !filereadable(a:file) + return [] + endif + + if !has_key(s:LabelCache , a:file) || s:LabelCache[a:file][0] != getftime(a:file) + " Open file in temporary split window for label extraction. + silent execute '1sp +let\ labels=s:ExtractLabels()|let\ inputs=s:ExtractInputs()|quit! ' . a:file + let s:LabelCache[a:file] = [ getftime(a:file), labels, inputs ] + endif + + " We need to create a copy of s:LabelCache[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:LabelCache[a:file][1]) + + for input in s:LabelCache[a:file][2] + let labels += s:GetLabelCache(input) + endfor + + return labels +endfunction +"}}} + +" Complete Labels {{{ +function! s:CompleteLabels(regex) + let labels = s:GetLabelCache(LatexBox_GetAuxFile()) + + let matches = filter( copy(labels), 'match(v:val[0], "' . a:regex . '") != -1' ) + if empty(matches) + " also try to match label and number + 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), 'match(v:val[0], "' . base . '") != -1 && match(v:val[1], "' . number . '") != -1' ) + endif + endif + if empty(matches) + " also try to match number + let matches = filter( copy(labels), 'match(v:val[1], "' . a:regex . '") != -1' ) + endif + + let suggestions = [] + for m in matches + let entry = {'word': m[0], 'menu': printf("%7s [p. %s]", '('.m[1].')', m[2])} + if g:LatexBox_completion_close_braces && !s:NextCharsMatch('^\s*[,}]') + " add trailing '}' + let entry = copy(entry) + let entry.abbr = entry.word + let entry.word = entry.word . '}' + endif + call add(suggestions, entry) + endfor + + return suggestions +endfunction +" }}} + +" Complete Inline Math Or Not {{{ +" Return 1, when cursor is in a math env: +" 1, there is a single $ in the current line on the left of cursor +" 2, there is an open-eq-env on/above the current line +" (open-eq-env : \(, \[, and \begin{eq-env} ) +" Return 0, when cursor is not in a math env +function! s:LatexBox_complete_inlineMath_or_not() + + " switch of inline math completion feature + if g:LatexBox_complete_inlineMath == 0 + return 0 + endif + + " env names that can't appear in an eq env + if !exists('s:LatexBox_doc_structure_patterns') + let s:LatexBox_doc_structure_patterns = '\%(' . '\\begin\s*{document}\|' . + \ '\\\%(chapter\|section\|subsection\|subsubsection\)\*\?\s*{' . '\)' + endif + + if !exists('s:LatexBox_eq_env_open_patterns') + let s:LatexBox_eq_env_open_patterns = ['\\(','\\\['] + endif + if !exists('s:LatexBox_eq_env_close_patterns') + let s:LatexBox_eq_env_close_patterns = ['\\)','\\\]'] + endif + + let notcomment = '\%(\%(\\\@<!\%(\\\\\)*\)\@<=%.*\)\@<!' + + let lnum_saved = line('.') + let cnum_saved = col('.') -1 + + let line = getline('.') + let line_start_2_cnum_saved = line[:cnum_saved] + + " determine whether there is a single $ before cursor + let cursor_dollar_pair = 0 + while matchend(line_start_2_cnum_saved, '\$[^$]\+\$', cursor_dollar_pair) >= 0 + " find the end of dollar pair + let cursor_dollar_pair = matchend(line_start_2_cnum_saved, '\$[^$]\+\$', cursor_dollar_pair) + endwhile + " find single $ after cursor_dollar_pair + let cursor_single_dollar = matchend(line_start_2_cnum_saved, '\$', cursor_dollar_pair) + + " if single $ is found + if cursor_single_dollar >= 0 + " check whether $ is in \(...\), \[...\], or \begin{eq}...\end{eq} + + " check current line, + " search for LatexBox_eq_env_close_patterns: \[ and \( + let lnum = line('.') + for i in range(0, (len(s:LatexBox_eq_env_open_patterns)-1)) + call cursor(lnum_saved, cnum_saved) + let cnum_close = searchpos(''. s:LatexBox_eq_env_close_patterns[i].'', 'cbW', lnum_saved)[1] + let cnum_open = matchend(line_start_2_cnum_saved, s:LatexBox_eq_env_open_patterns[i], cnum_close) + if cnum_open >= 0 + let s:eq_dollar_parenthesis_bracket_empty = '' + let s:eq_pos = cursor_single_dollar - 1 + return 1 + end + endfor + + " check the lines above + " search for s:LatexBox_doc_structure_patterns, and end-of-math-env + let lnum -= 1 + while lnum > 0 + let line = getline(lnum) + if line =~ notcomment . '\(' . s:LatexBox_doc_structure_patterns . + \ '\|' . '\\end\s*{\(' . g:LatexBox_eq_env_patterns . '\)\*\?}\)' + " when s:LatexBox_doc_structure_patterns or g:LatexBox_eq_env_patterns + " are found first, complete math, leave with $ at both sides + let s:eq_dollar_parenthesis_bracket_empty = '$' + let s:eq_pos = cursor_single_dollar + break + elseif line =~ notcomment . '\\begin\s*{\(' . g:LatexBox_eq_env_patterns . '\)\*\?}' + " g:LatexBox_eq_env_patterns is found, complete math, remove $ + let s:eq_dollar_parenthesis_bracket_empty = '' + let s:eq_pos = cursor_single_dollar - 1 + break + endif + let lnum -= 1 + endwhile + + return 1 + else + " no $ is found, then search for \( or \[ in current line + " 1, whether there is \( + call cursor(lnum_saved, cnum_saved) + let cnum_parenthesis_close = searchpos('\\)', 'cbW', lnum_saved)[1] + let cnum_parenthesis_open = matchend(line_start_2_cnum_saved, '\\(', cnum_parenthesis_close) + if cnum_parenthesis_open >= 0 + let s:eq_dollar_parenthesis_bracket_empty = '\)' + let s:eq_pos = cnum_parenthesis_open + return 1 + end + + " 2, whether there is \[ + call cursor(lnum_saved, cnum_saved) + let cnum_bracket_close = searchpos('\\\]', 'cbW', lnum_saved)[1] + let cnum_bracket_open = matchend(line_start_2_cnum_saved, '\\\[', cnum_bracket_close) + if cnum_bracket_open >= 0 + let s:eq_dollar_parenthesis_bracket_empty = '\]' + let s:eq_pos = cnum_bracket_open + return 1 + end + + " not inline math completion + return 0 + endif + +endfunction +" }}} + +" Complete inline euqation{{{ +function! s:LatexBox_inlineMath_completion(regex, ...) + + if a:0 == 0 + let file = LatexBox_GetMainTexFile() + else + let file = a:1 + endif + + if empty(glob(file, 1)) + return '' + endif + + if empty(s:eq_dollar_parenthesis_bracket_empty) + let inline_pattern1 = '\$\s*\(' . escape(substitute(a:regex[1:], '^\s\+', '', ""), '\.*^') . '[^$]*\)\s*\$' + let inline_pattern2 = '\\(\s*\(' . escape(substitute(a:regex[1:], '^\s\+', '', ""), '\.*^') . '.*\)\s*\\)' + else + let inline_pattern1 = '\$\s*\(' . escape(substitute(a:regex, '^\s\+', '', ""), '\.*^') . '[^$]*\)\s*\$' + let inline_pattern2 = '\\(\s*\(' . escape(substitute(a:regex, '^\s\+', '', ""), '\.*^') . '.*\)\s*\\)' + endif + + + let suggestions = [] + let line_num = 0 + for line in readfile(file) + let line_num = line_num + 1 + + let suggestions += s:LatexBox_inlineMath_mathlist(line,inline_pattern1 , line_num) + s:LatexBox_inlineMath_mathlist( line,inline_pattern2, line_num) + + " search for included files + let included_file = matchstr(line, '^\\@input{\zs[^}]*\ze}') + if included_file != '' + let included_file = LatexBox_kpsewhich(included_file) + call extend(suggestions, s:LatexBox_inlineMath_completion(a:regex, included_file)) + endif + endfor + + return suggestions +endfunction +" }}} + +" Search for inline maths {{{ +" search for $ ... $ and \( ... \) in each line +function! s:LatexBox_inlineMath_mathlist(line,inline_pattern, line_num) + let col_start = 0 + let suggestions = [] + while 1 + let matches = matchlist(a:line, a:inline_pattern, col_start) + if !empty(matches) + + " show line number of inline math + let entry = {'word': matches[1], 'menu': '[' . a:line_num . ']'} + + if s:eq_dollar_parenthesis_bracket_empty != '' + let entry = copy(entry) + let entry.abbr = entry.word + let entry.word = entry.word . s:eq_dollar_parenthesis_bracket_empty + endif + call add(suggestions, entry) + + " update col_start + let col_start = matchend(a:line, a:inline_pattern, col_start) + else + break + endif + endwhile + + return suggestions +endfunction +" }}} + +" Close Current Environment {{{ +function! s:CloseCurEnv() + " first, try with \left/\right pairs + let [lnum, cnum] = searchpairpos('\C\\left\>', '', '\C\\right\>', 'bnW', 'LatexBox_InComment()') + if lnum + let line = strpart(getline(lnum), cnum - 1) + let bracket = matchstr(line, '^\\left\zs\((\|\[\|\\{\||\|\.\)\ze') + for [open, close] in [['(', ')'], ['\[', '\]'], ['\\{', '\\}'], ['|', '|'], ['\.', '|']] + let bracket = substitute(bracket, open, close, 'g') + endfor + return '\right' . bracket + endif + + " second, try with environments + let env = LatexBox_GetCurrentEnvironment() + if env == '\[' + return '\]' + elseif env == '\(' + return '\)' + elseif env != '' + return '\end{' . env . '}' + endif + return '' +endfunction +" }}} + +" Wrap Selection {{{ +function! s:WrapSelection(wrapper) + keepjumps normal! `>a} + execute 'keepjumps normal! `<i\' . a:wrapper . '{' +endfunction +" }}} + +" Wrap Selection in Environment with Prompt {{{ +function! s:PromptEnvWrapSelection(...) + let env = input('environment: ', '', 'customlist,' . s:SIDWrap('GetEnvironmentList')) + if empty(env) + return + endif + " LaTeXBox's custom indentation can interfere with environment + " insertion when environments are indented (common for nested + " environments). Temporarily disable it for this operation: + 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 +" }}} + +" Change Environment {{{ +function! s:ChangeEnvPrompt() + + let [env, lnum, cnum, lnum2, cnum2] = LatexBox_GetCurrentEnvironment(1) + + let new_env = input('change ' . env . ' for: ', '', 'customlist,' . s:SIDWrap('GetEnvironmentList')) + if empty(new_env) + return + endif + + if new_env == '\[' || new_env == '[' + let begin = '\[' + let end = '\]' + elseif new_env == '\(' || new_env == '(' + let begin = '\(' + let end = '\)' + else + let l:begin = '\begin{' . new_env . '}' + let l:end = '\end{' . new_env . '}' + endif + + if env == '\[' || env == '\(' + let line = getline(lnum2) + let line = strpart(line, 0, cnum2 - 1) . l:end . strpart(line, cnum2 + 1) + call setline(lnum2, line) + + let line = getline(lnum) + let line = strpart(line, 0, cnum - 1) . l:begin . strpart(line, cnum + 1) + call setline(lnum, line) + else + let line = getline(lnum2) + let line = strpart(line, 0, cnum2 - 1) . l:end . strpart(line, cnum2 + len(env) + 5) + call setline(lnum2, line) + + let line = getline(lnum) + let line = strpart(line, 0, cnum - 1) . l:begin . strpart(line, cnum + len(env) + 7) + call setline(lnum, line) + endif +endfunction + +function! s:GetEnvironmentList(lead, cmdline, pos) + let suggestions = [] + for entry in g:LatexBox_completion_environments + let env = entry.word + if env =~ '^' . a:lead + call add(suggestions, env) + endif + endfor + return suggestions +endfunction +" }}} + +" Next Charaters Match {{{ +function! s:NextCharsMatch(regex) + let rest_of_line = strpart(getline('.'), col('.') - 1) + return rest_of_line =~ a:regex +endfunction +" }}} + +" Mappings {{{ +inoremap <silent> <Plug>LatexCloseCurEnv <C-R>=<SID>CloseCurEnv()<CR> +vnoremap <silent> <Plug>LatexWrapSelection :<c-u>call <SID>WrapSelection('')<CR>i +vnoremap <silent> <Plug>LatexEnvWrapSelection :<c-u>call <SID>PromptEnvWrapSelection()<CR> +vnoremap <silent> <Plug>LatexEnvWrapFmtSelection :<c-u>call <SID>PromptEnvWrapSelection(1)<CR> +nnoremap <silent> <Plug>LatexChangeEnv :call <SID>ChangeEnvPrompt()<CR> +" }}} + +" vim:fdm=marker:ff=unix:noet:ts=4:sw=4 |