diff options
| author | Adam Stankiewicz <sheerun@sher.pl> | 2017-12-30 11:10:32 +0100 | 
|---|---|---|
| committer | Adam Stankiewicz <sheerun@sher.pl> | 2017-12-30 11:10:32 +0100 | 
| commit | bb85059bacd5b415a012f25679111a0e55d3c6d9 (patch) | |
| tree | 315b2238ec4840aa4bf00ae48276bdffded07673 /ftplugin | |
| parent | 11f53253ad9fd0cd3e7a44ed9f8c80a4f265b46e (diff) | |
| download | vim-polyglot-bb85059bacd5b415a012f25679111a0e55d3c6d9.tar.gz vim-polyglot-bb85059bacd5b415a012f25679111a0e55d3c6d9.zip | |
Update
Diffstat (limited to '')
| -rw-r--r-- | ftplugin/ansible.vim | 2 | ||||
| -rw-r--r-- | ftplugin/latex-box/common.vim | 417 | ||||
| -rw-r--r-- | ftplugin/latex-box/complete.vim | 936 | ||||
| -rw-r--r-- | ftplugin/latex-box/findmain.vim | 66 | ||||
| -rw-r--r-- | ftplugin/latex-box/folding.vim | 382 | ||||
| -rw-r--r-- | ftplugin/latex-box/latexmk.vim | 558 | ||||
| -rw-r--r-- | ftplugin/latex-box/mappings.vim | 110 | ||||
| -rw-r--r-- | ftplugin/latex-box/motion.vim | 548 | ||||
| -rw-r--r-- | ftplugin/latextoc.vim | 206 | ||||
| -rw-r--r-- | ftplugin/tex_LatexBox.vim | 37 | ||||
| -rw-r--r-- | ftplugin/vue.vim | 7 | 
11 files changed, 3268 insertions, 1 deletions
| diff --git a/ftplugin/ansible.vim b/ftplugin/ansible.vim index bbfd05df..e068dd3a 100644 --- a/ftplugin/ansible.vim +++ b/ftplugin/ansible.vim @@ -4,6 +4,6 @@ if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'ansible') == -1  if exists('+regexpengine') && ('®expengine' == 0)    setlocal regexpengine=1  endif -set path+=./../templates,./../files +set path+=./../templates,./../files,templates,files  endif diff --git a/ftplugin/latex-box/common.vim b/ftplugin/latex-box/common.vim new file mode 100644 index 00000000..20488846 --- /dev/null +++ b/ftplugin/latex-box/common.vim @@ -0,0 +1,417 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1 +   +" LaTeX Box common functions + +" Error Format {{{ +" Note: The error formats assume we're using the -file-line-error with +"       [pdf]latex. +" Note: See |errorformat-LaTeX| for more info. + +" Check for options +if !exists("g:LatexBox_show_warnings") +	let g:LatexBox_show_warnings=1 +endif +if !exists("g:LatexBox_ignore_warnings") +	let g:LatexBox_ignore_warnings = +				\['Underfull', +				\ 'Overfull', +				\ 'specifier changed to'] +endif + +" Standard error message formats +" Note: We consider statements that starts with "!" as 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 + +" More info for some errors +setlocal efm+=%Cl.%l\ %m + +" Show or ignore warnings +if g:LatexBox_show_warnings +	" Parse biblatex warnings +	setlocal efm+=%-C(biblatex)%.%#in\ t%.%# +	setlocal efm+=%-C(biblatex)%.%#Please\ v%.%# +	setlocal efm+=%-C(biblatex)%.%#LaTeX\ a%.%# +	setlocal efm+=%-Z(biblatex)%m + +	" Parse hyperref warnings +	setlocal efm+=%-C(hyperref)%.%#on\ input\ line\ %l. + +	for w in g:LatexBox_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 +else +	setlocal efm+=%-WLaTeX\ %.%#Warning:\ %.%#line\ %l%.%# +	setlocal efm+=%-W%.%#\ at\ lines\ %l--%*\\d +	setlocal efm+=%-WLaTeX\ %.%#Warning:\ %m +	setlocal efm+=%-W%.%#Warning:\ %m +endif + +" Push file to file stack +setlocal efm+=%+P**%f +setlocal efm+=%+P**\"%f\" + +" Ignore unmatched lines +setlocal efm+=%-G%.%# +" }}} + +" Vim Windows {{{ + +" Type of split, "new" for horiz. "vnew" for vert. +if !exists('g:LatexBox_split_type') +	let g:LatexBox_split_type = "vnew" +endif + +" Length of vertical splits +if !exists('g:LatexBox_split_length') +	let g:LatexBox_split_length = 15 +endif + +" Width of horizontal splits +if !exists('g:LatexBox_split_width') +	let g:LatexBox_split_width = 30 +endif + +" Where splits appear +if !exists('g:LatexBox_split_side') +	let g:LatexBox_split_side = "aboveleft" +endif + +" Resize when split? +if !exists('g:LatexBox_split_resize') +	let g:LatexBox_split_resize = 0 +endif + +" Toggle help info +if !exists('g:LatexBox_toc_hidehelp') +	let g:LatexBox_toc_hidehelp = 0 +endif +" }}} + +" Filename utilities {{{ +function! LatexBox_GetMainTexFile() + +	" 1. check for the b:main_tex_file variable +	if exists('b:main_tex_file') && filereadable(b:main_tex_file) +		return b:main_tex_file +	endif + + +	" 2. scan the first few lines of the file for root = filename +	for linenum in range(1,5) +		let linecontents = getline(linenum) +		if linecontents =~ 'root\s*=' +			" Remove everything but the filename +			let b:main_tex_file = substitute(linecontents, +						\ '.*root\s*=\s*', "", "") +			let b:main_tex_file = substitute(b:main_tex_file, '\s*$', "", "") +			" Prepend current directory if this isn't an absolute path +			if b:main_tex_file !~ '^/' +				let b:main_tex_file = expand('%:p:h') . '/' . b:main_tex_file +			endif +			let b:main_tex_file = fnamemodify(b:main_tex_file, ":p") +			if b:main_tex_file !~ '\.tex$' +				let b:main_tex_file .= '.tex' +			endif +			return b:main_tex_file +		endif +	endfor + +	" 3. scan current file for "\begin{document}" +	if &filetype == 'tex' && search('\m\C\\begin\_\s*{document}', 'nw') != 0 +		return expand('%:p') +	endif + +	" 4. use 'main.tex' if it exists in the same directory (and is readable) +	let s:main_dot_tex_file=expand('%:p:h') . '/main.tex' +	if filereadable(s:main_dot_tex_file) +		let b:main_tex_file=s:main_dot_tex_file +		return b:main_tex_file +	endif + +	" 5. borrow the Vim-Latex-Suite method of finding it +	if LatexBox_GetMainFileName() != expand('%:p') +		let b:main_tex_file = LatexBox_GetMainFileName() +		return b:main_tex_file +	endif + +	" 6. prompt for file with completion +	let b:main_tex_file = s:PromptForMainFile() +	return b:main_tex_file +endfunction + +function! s:PromptForMainFile() +	let saved_dir = getcwd() +	execute 'cd ' . fnameescape(expand('%:p:h')) + +	" Prompt for file +	let l:file = '' +	while !filereadable(l:file) +		let l:file = input('main LaTeX file: ', '', 'file') +		if l:file !~ '\.tex$' +			let l:file .= '.tex' +		endif +	endwhile +	let l:file = fnamemodify(l:file, ':p') + +	" Make persistent +	let l:persistent = '' +	while l:persistent !~ '\v^(y|n)' +		let l:persistent = input('make choice persistent? (y, n) ') +		if l:persistent == 'y' +			call writefile([], l:file . '.latexmain') +		endif +	endwhile + +	execute 'cd ' . fnameescape(saved_dir) +	return l:file +endfunction + +" Return the directory of the main tex file +function! LatexBox_GetTexRoot() +	return fnamemodify(LatexBox_GetMainTexFile(), ':h') +endfunction + +function! LatexBox_GetBuildBasename(with_dir) +	" 1. Check for g:LatexBox_jobname +	if exists('g:LatexBox_jobname') +		return g:LatexBox_jobname +	endif + +	" 2. Get the basename from the main tex file +	if a:with_dir +		return fnamemodify(LatexBox_GetMainTexFile(), ':r') +	else +		return fnamemodify(LatexBox_GetMainTexFile(), ':t:r') +	endif +endfunction + +function! LatexBox_GetAuxFile() +	" 1. check for b:build_dir variable +	if exists('b:build_dir') && isdirectory(b:build_dir) +		return b:build_dir . '/' . LatexBox_GetBuildBasename(0) . '.aux' +	endif + +	" 2. check for g:LatexBox_build_dir variable +	if exists('g:LatexBox_build_dir') && isdirectory(g:LatexBox_build_dir) +		return g:LatexBox_build_dir . '/' . LatexBox_GetBuildBasename(0) . '.aux' +	endif + +	" 3. use the base name of main tex file +	return LatexBox_GetBuildBasename(1) . '.aux' +endfunction + +function! LatexBox_GetLogFile() +	" 1. check for b:build_dir variable +	if exists('b:build_dir') && isdirectory(b:build_dir) +		return b:build_dir . '/' . LatexBox_GetBuildBasename(0) . '.log' +	endif + +	" 2. check for g:LatexBox_build_dir variable +	if exists('g:LatexBox_build_dir') && isdirectory(g:LatexBox_build_dir) +		return g:LatexBox_build_dir . '/' . LatexBox_GetBuildBasename(0) . '.log' +	endif + +	" 3. use the base name of main tex file +	return LatexBox_GetBuildBasename(1) . '.log' +endfunction + +function! LatexBox_GetOutputFile() +	" 1. check for b:build_dir variable +	if exists('b:build_dir') && isdirectory(b:build_dir) +		return b:build_dir . '/' . LatexBox_GetBuildBasename(0) +					\ . '.' . g:LatexBox_output_type +	endif + +	" 2. check for g:LatexBox_build_dir variable +	if exists('g:LatexBox_build_dir') && isdirectory(g:LatexBox_build_dir) +		return g:LatexBox_build_dir . '/' . LatexBox_GetBuildBasename(0) +					\ . '.' . g:LatexBox_output_type +	endif + +	" 3. use the base name of main tex file +	return LatexBox_GetBuildBasename(1) . '.' . g:LatexBox_output_type +endfunction +" }}} + +" View Output {{{ + +" Default pdf viewer +if !exists('g:LatexBox_viewer') +	" On windows, 'running' a file will open it with the default program +	let s:viewer = '' +	if has('unix') +	  " echo -n necessary as uname -s will append \n otherwise +      let s:uname = system('echo -n $(uname -s)') +	  if s:uname == "Darwin" +		  let s:viewer = 'open' +	  else +		  let s:viewer = 'xdg-open' +	  endif +	endif +	let g:LatexBox_viewer = s:viewer +endif + +function! LatexBox_View(...) +	let lvargs = join(a:000, ' ') +	let outfile = LatexBox_GetOutputFile() +	if !filereadable(outfile) +		echomsg fnamemodify(outfile, ':.') . ' is not readable' +		return +	endif +	let cmd = g:LatexBox_viewer . ' ' . lvargs . ' ' . shellescape(outfile) +	if has('win32') +		let cmd = '!start /b ' . cmd . ' >nul' +	else +		let cmd = '!' . cmd . ' ' +		if fnamemodify(&shell, ':t') ==# 'fish' +			let cmd .= ' >/dev/null ^/dev/null &' +		else +			let cmd .= ' &>/dev/null &' +		endif +	endif +	silent execute cmd +	if !has("gui_running") +		redraw! +	endif +endfunction + +command! -nargs=* LatexView call LatexBox_View('<args>') +" }}} + +" In Comment {{{ + +" LatexBox_InComment([line], [col]) +" return true if inside comment +function! LatexBox_InComment(...) +	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 +" }}} + +" Get Current Environment {{{ + +" LatexBox_GetCurrentEnvironment([with_pos]) +" Returns: +" - environment +"	  if with_pos is not given +" - [envirnoment, lnum_begin, cnum_begin, lnum_end, cnum_end] +"	  if with_pos is nonzero +function! LatexBox_GetCurrentEnvironment(...) +	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, +				\ 'LatexBox_InComment()') + +	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, +					\ 'LatexBox_InComment()') + +		call setpos('.', saved_pos) +		return [env, lnum1, cnum1, lnum2, cnum2] +	else +		call setpos('.', saved_pos) +		return env +	endif +endfunction +" }}} + +" Tex To Tree {{{ +" stores nested braces in a tree structure +function! LatexBox_TexToTree(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, LatexBox_TexToTree(strpart(a:str, i1, i2 - i1))) +				let i1 = i2 + 1 +			endif +		endif +	endwhile +	return tree +endfunction +" }}} + +" Tree To Tex {{{ +function! LatexBox_TreeToTex(tree) +	if type(a:tree) == type('') +		return a:tree +	else +		return '{' . join(map(a:tree, 'LatexBox_TreeToTex(v:val)'), '') . '}' +	endif +endfunction +" }}} + +" vim:fdm=marker:ff=unix:noet:ts=4:sw=4 + +endif diff --git a/ftplugin/latex-box/complete.vim b/ftplugin/latex-box/complete.vim new file mode 100644 index 00000000..aecb0d8d --- /dev/null +++ b/ftplugin/latex-box/complete.vim @@ -0,0 +1,936 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1 +   +" 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]\|labelc\|name\|auto\)\?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 =~ '\m\C\\begin\_\s*{$' +			let s:completion_type = 'begin' +		elseif line_start =~ '\m\C\\end\_\s*{$' +			let s:completion_type = 'end' +		elseif line_start =~ '\m' . g:LatexBox_ref_pattern . '$' +			let s:completion_type = 'ref' +		elseif line_start =~ '\m' . 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 lines = readfile(file) +	let bibdata_list = [] + +	" +	" Search for added bibliographies +	" +	let bibliography_cmds = [ +				\ '\\bibliography', +				\ '\\addbibresource', +				\ '\\addglobalbib', +				\ '\\addsectionbib', +				\ ] +	for cmd in bibliography_cmds +		let filtered = filter(copy(lines), +					\ 'v:val =~ ''\C' . cmd . '\s*{[^}]\+}''') +		let files = map(filtered, +					\ 'matchstr(v:val, ''\C' . cmd . '\s*{\zs[^}]\+\ze}'')') +		for file in files +			let bibdata_list += map(split(file, ','), +						\ 'fnamemodify(v:val, '':r'')') +		endfor +	endfor + +	" +	" Also search included files +	" +	for input in filter(lines, +				\ 'v:val =~ ''\C\\\%(input\|include\)\s*{[^}]\+}''') +		let bibdata_list += s:FindBibData(LatexBox_kpsewhich( +					\ matchstr(input, +						\ '\C\\\%(input\|include\)\s*{\zs[^}]\+\ze}'))) +	endfor + +	return bibdata_list +endfunction + +let s:bstfile = expand('<sfile>:p:h') . '/vimcomplete' + +function! LatexBox_BibSearch(regexp) +	let res = [] + +	" Find data from bib files +	let bibdata = join(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) + +		if has('win32') +			let l:old_shellslash = &l:shellslash +			setlocal noshellslash +			call system('cd ' . shellescape(LatexBox_GetTexRoot()) . +						\ ' & bibtex -terse ' +						\ . fnamemodify(auxfile, ':t') . ' >nul') +			let &l:shellslash = l:old_shellslash +		else +			call system('cd ' . shellescape(LatexBox_GetTexRoot()) . +						\ ' ; bibtex -terse ' +						\ . fnamemodify(auxfile, ':t') . ' >/dev/null') +		endif + +		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]) +				let s:type_length = max([s:type_length, +							\ len(matches[2]) + 3]) +				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}') >= 0 +		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 {{{ +let s:type_length=0 +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 = [] +	let s:type_length = 4 +	for m in LatexBox_BibSearch(regexp) +		let type = m['type']   == '' ? '[-]' : '[' . m['type']   . '] ' +		let type = printf('%-' . s:type_length . 's', type) +		let auth = m['author'] == '' ? ''    :       m['author'][:20] . ' ' +		let auth = substitute(auth, '\~', ' ', 'g') +		let auth = substitute(auth, ',.*\ze', ' et al. ', '') +		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$" +		    let [lblline, lblbegin] = searchpos( '\\newlabel{', 'ecW' ) +			continue +		endif + +		if 0 == search( '\m{\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( '\m\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. +		let main_tex_file = LatexBox_GetMainTexFile() +		silent execute '1sp +let\ b:main_tex_file=main_tex_file|let\ labels=s:ExtractLabels()|let\ inputs=s:ExtractInputs()|quit! ' . fnameescape(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 +" }}} + +" List Labels with Prompt {{{ +function! s:PromptLabelList(...) +	" Check if window already exists +	let winnr = bufwinnr(bufnr('LaTeX Labels')) +	if winnr >= 0 +		if a:0 == 0 +			silent execute winnr . 'wincmd w' +		else +			" Supplying an argument to this function causes toggling instead +			" of jumping to the labels window +			if g:LatexBox_split_resize +				silent exe "set columns-=" . g:LatexBox_split_width +			endif +			silent execute 'bwipeout' . bufnr('LaTeX Labels') +		endif +		return +	endif + +	" Get label suggestions +	let regexp = input('filter labels with regexp: ', '') +	let labels = s:CompleteLabels(regexp) + +	let calling_buf = bufnr('%') + +	" Create labels window and set local settings +	if g:LatexBox_split_resize +		silent exe "set columns+=" . g:LatexBox_split_width +	endif +	silent exe g:LatexBox_split_side g:LatexBox_split_width . 'vnew LaTeX\ Labels' +	let b:toc = [] +	let b:toc_numbers = 1 +	let b:calling_win = bufwinnr(calling_buf) +	setlocal filetype=latextoc + +	" Add label entries and jump to the closest section +	for entry in labels +		let number = matchstr(entry['menu'], '^\s*(\zs[^)]\+\ze)') +		let page = matchstr(entry['menu'], '^[^)]*)\s*\[\zs[^]]\+\ze\]') +		let e = {'file': bufname(calling_buf), +					\ 'level': 'label', +					\ 'number': number, +					\ 'text': entry['abbr'], +					\ 'page': page} +		call add(b:toc, e) +		if b:toc_numbers +			call append('$', e['number'] . "\t" . e['text']) +		else +			call append('$', e['text']) +		endif +	endfor +	if !g:LatexBox_toc_hidehelp +		call append('$', "") +		call append('$', "<Esc>/q: close") +		call append('$', "<Space>: jump") +		call append('$', "<Enter>: jump and close") +		call append('$', "s:       hide numbering") +	endif +	0delete _ + +	" Lock buffer +	setlocal nomodifiable +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 + +function! s:LatexToggleStarEnv() +	let [env, lnum, cnum, lnum2, cnum2] = LatexBox_GetCurrentEnvironment(1) + +	if env == '\(' +		return +	elseif env == '\[' +		let begin = '\begin{equation}' +		let end = '\end{equation}' +	elseif env[-1:] == '*' +		let begin = '\begin{' . env[:-2] . '}' +		let end   = '\end{'   . env[:-2] . '}' +	else +		let begin = '\begin{' . env . '*}' +		let end   = '\end{'   . env . '*}' +	endif + +	if 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 +" }}} + +" 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> +nnoremap <silent> <Plug>LatexToggleStarEnv			:call <SID>LatexToggleStarEnv()<CR> +" }}} + +" Commands {{{ +command! LatexLabels call <SID>PromptLabelList() +" }}} + +" vim:fdm=marker:ff=unix:noet:ts=4:sw=4 + +endif diff --git a/ftplugin/latex-box/findmain.vim b/ftplugin/latex-box/findmain.vim new file mode 100644 index 00000000..3b81b0d7 --- /dev/null +++ b/ftplugin/latex-box/findmain.vim @@ -0,0 +1,66 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1 +   +" LatexBox_GetMainFileName: gets the name of the main file being compiled. {{{ +" Description:  returns the full path name of the main file. +"               This function checks for the existence of a .latexmain file +"               which might point to the location of a "main" latex file. +"               If .latexmain exists, then return the full path name of the +"               file being pointed to by it. +" +"               Otherwise, return the full path name of the current buffer. +" +"               You can supply an optional "modifier" argument to the +"               function, which will optionally modify the file name before +"               returning. +"               NOTE: From version 1.6 onwards, this function always trims +"               away the .latexmain part of the file name before applying the +"               modifier argument. +"               NOTE: This function is copied from the Latex-Suite project! +function! LatexBox_GetMainFileName(...) +	if a:0 > 0 +		let modifier = a:1 +	else +		let modifier = ':p' +	endif + +	let s:origdir = fnameescape(getcwd()) + +	let dirmodifier = '%:p:h' +	let dirLast = fnameescape(expand(dirmodifier)) +	exe 'cd '.dirLast + +	" move up the directory tree until we find a .latexmain file. +	" TODO: Should we be doing this recursion by default, or should there be a +	"       setting? +	while glob('*.latexmain',1) == '' +		let dirmodifier = dirmodifier.':h' +		let dirNew = fnameescape(expand(dirmodifier)) +		" break from the loop if we cannot go up any further. +		if dirNew == dirLast +			break +		endif +		let dirLast = dirNew +		exe 'cd '.dirLast +	endwhile + +	let lheadfile = glob('*.latexmain',1) +	if lheadfile != '' +		" Remove the trailing .latexmain part of the filename... We never want +		" that. +		let lheadfile = fnamemodify(substitute(lheadfile, '\.latexmain$', '', ''), modifier) +	else +		" If we cannot find any main file, just modify the filename of the +		" current buffer. +		let lheadfile = expand('%'.modifier) +	endif + +	exe 'cd '.s:origdir + +	" NOTE: The caller of this function needs to escape the file name with +	"       fnameescape() . The reason its not done here is that escaping is not +	"       safe if this file is to be used as part of an external command on +	"       certain platforms. +	return lheadfile +endfunction + +endif diff --git a/ftplugin/latex-box/folding.vim b/ftplugin/latex-box/folding.vim new file mode 100644 index 00000000..d6f36272 --- /dev/null +++ b/ftplugin/latex-box/folding.vim @@ -0,0 +1,382 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1 +   +" Folding support for LaTeX + +" +" Options +" g:LatexBox_Folding         - Turn on/off folding +" g:LatexBox_fold_text       - Turn on/off LatexBox fold text function +" g:LatexBox_fold_preamble   - Turn on/off folding of preamble +" g:LatexBox_fold_parts      - Define parts (eq. appendix, frontmatter) to fold +" g:LatexBox_fold_sections   - Define section levels to fold +" g:LatexBox_fold_envs       - Turn on/off folding of environments +" g:LatexBox_fold_toc        - Turn on/off folding of TOC +" g:LatexBox_fold_toc_levels - Set max TOC fold level +" +" {{{1 Initialize options to default values. +if !exists('g:LatexBox_Folding') +	let g:LatexBox_Folding=0 +endif +if !exists('g:LatexBox_fold_text') +    let g:LatexBox_fold_text=1 +endif +if !exists('g:LatexBox_fold_preamble') +    let g:LatexBox_fold_preamble=1 +endif +if !exists('g:LatexBox_fold_envs') +    let g:LatexBox_fold_envs=1 +endif +if !exists('g:LatexBox_fold_envs_force') +    let g:LatexBox_fold_envs_force = [] +endif +if !exists('g:LatexBox_fold_parts') +    let g:LatexBox_fold_parts=[ +                \ "appendix", +                \ "frontmatter", +                \ "mainmatter", +                \ "backmatter" +                \ ] +endif +if !exists('g:LatexBox_fold_sections') +    let g:LatexBox_fold_sections=[ +                \ "part", +                \ "chapter", +                \ "section", +                \ "subsection", +                \ "subsubsection" +                \ ] +endif +if !exists('g:LatexBox_fold_toc') +    let g:LatexBox_fold_toc=0 +endif +if !exists('g:LatexBox_fold_toc_levels') +    let g:LatexBox_fold_toc_levels=1 +endif +if !exists('g:LatexBox_fold_automatic') +	let g:LatexBox_fold_automatic=1 +endif +" }}}1 + +if g:LatexBox_Folding == 0 +    finish +endif + +" {{{1 Set folding options for vim +setl foldexpr=LatexBox_FoldLevel(v:lnum) +if g:LatexBox_fold_text == 1 +    setl foldtext=LatexBox_FoldText() +endif +if g:LatexBox_fold_automatic == 1 +    setl foldmethod=expr + +	" +	" 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 +	" +	augroup FastFold +		autocmd! +		autocmd InsertEnter *.tex if !&diff | setlocal foldmethod=manual | endif +		autocmd InsertLeave *.tex if !&diff | setlocal foldmethod=expr | endif +	augroup end +else +	setl foldmethod=manual +endif + +function! LatexBox_FoldOnDemand() +	setl foldmethod=expr +	normal! zx +	setl foldmethod=manual +endfunction + +command! LatexFold  call LatexBox_FoldOnDemand() + +" {{{1 LatexBox_FoldLevel help functions + +" 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. +function! s:FoldSectionLevels() +    " 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:LatexBox_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:LatexBox_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 LatexBox_FoldLevel + +" Parse file to dynamically set the sectioning fold levels +let b:LatexBox_FoldSections = s:FoldSectionLevels() + +" Optimize by predefine common patterns +let s:notbslash = '\%(\\\@<!\%(\\\\\)*\)\@<=' +let s:notcomment = '\%(\%(\\\@<!\%(\\\\\)*\)\@<=%.*\)\@<!' +let s:envbeginpattern = s:notcomment . s:notbslash . '\\begin\s*{.\{-}}' +let s:envendpattern = s:notcomment . s:notbslash . '\\end\s*{.\{-}}' +let s:foldparts = '^\s*\\\%(' . join(g:LatexBox_fold_parts, '\|') . '\)' +let s:folded = '\(% Fake\|\\\(document\|begin\|end\|paragraph\|' +            \ . 'front\|main\|back\|app\|sub\|section\|chapter\|part\)\)' + +function! LatexBox_FoldLevel(lnum) +    " Check for normal lines first (optimization) +    let line  = getline(a:lnum) +    if line !~ s:folded +        return "=" +    endif + +    " Fold preamble +    if g:LatexBox_fold_preamble == 1 +        if line =~# s:notcomment . s:notbslash . '\s*\\documentclass' +            return ">1" +        elseif line =~# s:notcomment . s:notbslash . '\s*\\begin\s*{\s*document\s*}' +            return "0" +        endif +    endif + +    " Fold parts (\frontmatter, \mainmatter, \backmatter, and \appendix) +    if line =~# s:foldparts +        return ">1" +    endif + +    " Fold chapters and sections +    for [part, level] in b:LatexBox_FoldSections +        if line =~# part +            return ">" . level +        endif +    endfor + +    " Never fold \end{document} +    if line =~# '^\s*\\end{document}' +        return 0 +    endif + +    " Fold environments +    if line =~# s:envbeginpattern && line =~# s:envendpattern +        " If the begin and end pattern are on the same line , do not fold +        return "=" +    else +        if line =~# s:envbeginpattern +            if g:LatexBox_fold_envs == 1 +                return "a1" +            else +                let env = matchstr(line,'\\begin\*\?{\zs\w*\*\?\ze}') +                if index(g:LatexBox_fold_envs_force, env) >= 0 +                    return "a1" +                else +                    return "=" +                endif +            endif +        elseif line =~# s:envendpattern +            if g:LatexBox_fold_envs == 1 +                return "s1" +            else +                let env = matchstr(line,'\\end\*\?{\zs\w*\*\?\ze}') +                if index(g:LatexBox_fold_envs_force, env) >= 0 +                    return "s1" +                else +                    return "=" +                endif +            endif +        endif +    endif + +    " Return foldlevel of previous line +    return "=" +endfunction + +" {{{1 LatexBox_FoldText help functions +function! s:LabelEnv() +    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 + +function! s:CaptionEnv() +    let i = v:foldend +    while i >= v:foldstart +        if getline(i) =~ '^\s*\\caption' +            return matchstr(getline(i), '^\s*\\caption\(\[.*\]\)\?{\zs.\+') +        end +        let i -= 1 +    endwhile +    return "" +endfunction + +function! s:CaptionTable() +    let i = v:foldstart +    while i <= v:foldend +        if getline(i) =~ '^\s*\\caption' +            return matchstr(getline(i), '^\s*\\caption\(\[.*\]\)\?{\zs.\+') +        end +        let i += 1 +    endwhile +    return "" +endfunction + +function! s:CaptionFrame(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.\+') +            end +            let i += 1 +        endwhile + +        return "" +    endif +endfunction + +function! LatexBox_FoldText_title() +    let line = getline(v:foldstart) +    let title = 'Not defined' + +    " Preamble +    if line =~ '\s*\\documentclass' +        return "Preamble" +    endif + +    " Parts, sections and fakesections +    let sections = '\(\(sub\)*\(section\|paragraph\)\|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 based on type of environment +        if env == 'frame' +            let label = '' +            let caption = s:CaptionFrame(line) +        elseif env == 'table' +            let label = s:LabelEnv() +            let caption = s:CaptionTable() +        else +            let label = s:LabelEnv() +            let caption = s:CaptionEnv() +        endif + +        " If no caption found, check for a caption comment +        if caption == '' +            let caption = matchstr(line,'\\begin\*\?{.*}\s*%\s*\zs.*') +        endif + +        " Create title based on caption and label +        if caption . label == '' +            let title = env +        elseif label == '' +            let title = printf('%-12s%s', env . ':', +                        \ substitute(caption, '}\s*$', '','')) +        elseif caption == '' +            let title = printf('%-12s%56s', env, '(' . label . ')') +        else +            let title = printf('%-12s%-30s %21s', env . ':', +                        \ strpart(substitute(caption, '}\s*$', '',''),0,34), +                        \ '(' . label . ')') +        endif +    endif + +    return title +endfunction + +" {{{1 LatexBox_FoldText +function! LatexBox_FoldText() +    let nlines = v:foldend - v:foldstart + 1 +    let title = strpart(LatexBox_FoldText_title(), 0, 68) +    let level = '' + +    " 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) + +    return printf('%-3s %-68s #%5d', level, title, nlines) +endfunction + +" {{{1 Footer +" vim:fdm=marker:ff=unix:ts=4:sw=4 + +endif diff --git a/ftplugin/latex-box/latexmk.vim b/ftplugin/latex-box/latexmk.vim new file mode 100644 index 00000000..15db3686 --- /dev/null +++ b/ftplugin/latex-box/latexmk.vim @@ -0,0 +1,558 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1 +   +" LaTeX Box latexmk functions + +" Options and variables {{{ + +if !exists('g:LatexBox_latexmk_options') +	let g:LatexBox_latexmk_options = '' +endif +if !exists('g:LatexBox_latexmk_env') +	let g:LatexBox_latexmk_env = '' +endif +if !exists('g:LatexBox_latexmk_async') +	let g:LatexBox_latexmk_async = 0 +endif +if !exists('g:LatexBox_latexmk_preview_continuously') +	let g:LatexBox_latexmk_preview_continuously = 0 +endif +if !exists('g:LatexBox_output_type') +	let g:LatexBox_output_type = 'pdf' +endif +if !exists('g:LatexBox_autojump') +	let g:LatexBox_autojump = 0 +endif +if ! exists('g:LatexBox_quickfix') +	let g:LatexBox_quickfix = 1 +endif +if ! exists('g:LatexBox_personal_latexmkrc') +	let g:LatexBox_personal_latexmkrc = 0 +endif + +" }}} + +" Process ID management (used for asynchronous and continuous mode) {{{ + +" A dictionary of latexmk PID's (basename: pid) +if !exists('g:latexmk_running_pids') +	let g:latexmk_running_pids = {} +endif + +" Set PID {{{ +function! s:LatexmkSetPID(basename, pid) +	let g:latexmk_running_pids[a:basename] = a:pid +endfunction +" }}} + +" kill_latexmk_process {{{ +function! s:kill_latexmk_process(pid) +	if has('win32') +		silent execute '!taskkill /PID ' . a:pid . ' /T /F' +	else +		if g:LatexBox_latexmk_async +			" vim-server mode +			let pids = [] +			let tmpfile = tempname() +			silent execute '!ps x -o pgid,pid > ' . tmpfile +			for line in readfile(tmpfile) +				let new_pid = matchstr(line, '^\s*' . a:pid . '\s\+\zs\d\+\ze') +				if !empty(new_pid) +					call add(pids, new_pid) +				endif +			endfor +			call delete(tmpfile) +			if !empty(pids) +				silent execute '!kill ' . join(pids) +			endif +		else +			" single background process +			silent execute '!kill ' . a:pid +		endif +	endif +	if !has('gui_running') +		redraw! +	endif +endfunction +" }}} + +" kill_all_latexmk_processes {{{ +function! s:kill_all_latexmk_processes() +	for pid in values(g:latexmk_running_pids) +		call s:kill_latexmk_process(pid) +	endfor +endfunction +" }}} + +" }}} + +" Setup for vim-server {{{ +function! s:SIDWrap(func) +	if !exists('s:SID') +		let s:SID = matchstr(expand('<sfile>'), '\zs<SNR>\d\+_\ze.*$') +	endif +	return s:SID . a:func +endfunction + +function! s:LatexmkCallback(basename, status) +	" Only remove the pid if not in continuous mode +	if !g:LatexBox_latexmk_preview_continuously +		call remove(g:latexmk_running_pids, a:basename) +	endif +	call LatexBox_LatexErrors(a:status, a:basename) +endfunction + +function! s:setup_vim_server() +	if !exists('g:vim_program') + +		" attempt autodetection of vim executable +		let g:vim_program = '' +		if has('win32') +			" Just drop through to the default for windows +		else +			if match(&shell, '\(bash\|zsh\)$') >= 0 +				let ppid = '$PPID' +			else +				let ppid = '$$' +			endif + +			let tmpfile = tempname() +			silent execute '!ps -o command= -p ' . ppid . ' > ' . tmpfile +			for line in readfile(tmpfile) +				let line = matchstr(line, '^\S\+\>') +				if !empty(line) && executable(line) +					let g:vim_program = line . ' -g' +					break +				endif +			endfor +			call delete(tmpfile) +		endif + +		if empty(g:vim_program) +			if has('gui_macvim') +				let g:vim_program +						\ = '/Applications/MacVim.app/Contents/MacOS/Vim -g' +			else +				let g:vim_program = v:progname +			endif +		endif +	endif +endfunction +" }}} + +" Latexmk {{{ + +function! LatexBox_Latexmk(force) +	" Define often used names +	let basepath = LatexBox_GetBuildBasename(1) +	let basename = fnamemodify(basepath, ':t') +	let texroot = shellescape(LatexBox_GetTexRoot()) +	let mainfile = fnameescape(fnamemodify(LatexBox_GetMainTexFile(), ':t')) + +	" Check if latexmk is installed +	if !executable('latexmk') +		echomsg "Error: LaTeX-Box relies on latexmk for compilation, but it" . +					\ " is not installed!" +		return +	endif + +	" Check if already running +	if has_key(g:latexmk_running_pids, basepath) +		echomsg "latexmk is already running for `" . basename . "'" +		return +	endif + +	" Set wrap width in log file +	let max_print_line = 2000 +	if has('win32') +		let env = 'set max_print_line=' . max_print_line . ' & ' +	elseif match(&shell, '/tcsh$') >= 0 +		let env = 'setenv max_print_line ' . max_print_line . '; ' +	else +		if fnamemodify(&shell, ':t') ==# 'fish' +			let env = 'set max_print_line ' . max_print_line . '; and ' +		else +			let env = 'max_print_line=' . max_print_line +		endif +	endif + +	" Set environment options +	let env .= ' ' . g:LatexBox_latexmk_env . ' ' + +	" Set latexmk command with options +	if has('win32') +		" Make sure to switch drive as well as directory +		let cmd = 'cd /D ' . texroot . ' && ' +	else +		if fnamemodify(&shell, ':t') ==# 'fish' +			let cmd = 'cd ' . texroot . '; and ' +		else +			let cmd = 'cd ' . texroot . ' && ' +		endif +	endif +	let cmd .= env . ' latexmk' +	if ! g:LatexBox_personal_latexmkrc +		let cmd .= ' -' . g:LatexBox_output_type +	endif +	let cmd .= ' -quiet ' +	let cmd .= g:LatexBox_latexmk_options +	if a:force +		let cmd .= ' -g' +	endif +	if g:LatexBox_latexmk_preview_continuously +		let cmd .= ' -pvc' +	endif +	let cmd .= ' -e ' . shellescape('$pdflatex =~ s/ / -file-line-error /') +	let cmd .= ' -e ' . shellescape('$latex =~ s/ / -file-line-error /') +	if g:LatexBox_latexmk_preview_continuously +		let cmd .= ' -e ' . shellescape('$success_cmd = $ENV{SUCCESSCMD}') +		let cmd .= ' -e ' . shellescape('$failure_cmd = $ENV{FAILURECMD}') +	endif +	let cmd .= ' ' . mainfile + +	" Redirect output to null +	if has('win32') +		let cmd .= ' >nul' +	else +		if fnamemodify(&shell, ':t') ==# 'fish' +			let cmd .= ' >/dev/null ^/dev/null' +		else +			let cmd .= ' &>/dev/null' +		endif +	endif + +	if g:LatexBox_latexmk_async +		" Check if VIM server exists +		if empty(v:servername) +			echoerr "cannot run latexmk in background without a VIM server" +			echoerr "set g:LatexBox_latexmk_async to 0 to change compiling mode" +			return +		endif + +		" Start vim server if necessary +		call s:setup_vim_server() + +		let setpidfunc = s:SIDWrap('LatexmkSetPID') +		let callbackfunc = s:SIDWrap('LatexmkCallback') +		if has('win32') +			let vim_program = substitute(g:vim_program, +						\ 'gvim\.exe$', 'vim.exe', '') + +			" Define callback to set the pid +			let callsetpid = setpidfunc . '(''' . basepath . ''', %CMDPID%)' +			let vimsetpid = vim_program . ' --servername ' . v:servername +						\ . ' --remote-expr ' . shellescape(callsetpid) + +			" Define callback after latexmk is finished +			let callback = callbackfunc . '(''' . basepath . ''', %LATEXERR%)' +			let vimcmd = vim_program . ' --servername ' . v:servername +						\ . ' --remote-expr ' . shellescape(callback) +			let scallback = callbackfunc . '(''' . basepath . ''', 0)' +			let svimcmd = vim_program . ' --servername ' . v:servername +						\ . ' --remote-expr ' . shellescape(scallback) +			let fcallback = callbackfunc . '(''' . basepath . ''', 1)' +			let fvimcmd = vim_program . ' --servername ' . v:servername +						\ . ' --remote-expr ' . shellescape(fcallback) + +			let asyncbat = tempname() . '.bat' +			if g:LatexBox_latexmk_preview_continuously +				call writefile(['setlocal', +							\ 'set T=%TEMP%\sthUnique.tmp', +							\ 'wmic process where (Name="WMIC.exe" AND CommandLine LIKE "%%%TIME%%%") ' +							\ . 'get ParentProcessId /value | find "ParentProcessId" >%T%', +							\ 'set /P A=<%T%', +							\ 'set CMDPID=%A:~16% & del %T%', +							\ vimsetpid, +							\ 'set SUCCESSCMD='.svimcmd, +							\ 'set FAILURECMD='.fvimcmd, +							\ cmd, +							\ 'endlocal'], asyncbat) +			else +				call writefile(['setlocal', +							\ 'set T=%TEMP%\sthUnique.tmp', +							\ 'wmic process where (Name="WMIC.exe" AND CommandLine LIKE "%%%TIME%%%") ' +							\ . 'get ParentProcessId /value | find "ParentProcessId" >%T%', +							\ 'set /P A=<%T%', +							\ 'set CMDPID=%A:~16% & del %T%', +							\ vimsetpid, +							\ cmd, +							\ 'set LATEXERR=%ERRORLEVEL%', +							\ vimcmd, +							\ 'endlocal'], asyncbat) +			endif + +			" Define command +			let cmd = '!start /b ' . asyncbat . ' & del ' . asyncbat +		else +			" Define callback to set the pid +			let callsetpid = shellescape(setpidfunc).'"(\"'.basepath.'\",$$)"' +			let vimsetpid = g:vim_program . ' --servername ' . v:servername +			                        \ . ' --remote-expr ' . callsetpid + +			" Define callback after latexmk is finished +			let callback = shellescape(callbackfunc).'"(\"'.basepath.'\",$?)"' +			let vimcmd = g:vim_program . ' --servername ' . v:servername +									\ . ' --remote-expr ' . callback +			let scallback = shellescape(callbackfunc).'"(\"'.basepath.'\",0)"' +			let svimcmd = g:vim_program . ' --servername ' . v:servername +			                        \ . ' --remote-expr ' . scallback +			let fcallback = shellescape(callbackfunc).'"(\"'.basepath.'\",1)"' +			let fvimcmd = g:vim_program . ' --servername ' . v:servername +			                        \ . ' --remote-expr ' . fcallback + +			" Define command +			" Note: Here we escape '%' because it may be given as a user option +			" through g:LatexBox_latexmk_options, for instance with +			" g:Latex..._options = "-pdflatex='pdflatex -synctex=1 \%O \%S'" +			if g:LatexBox_latexmk_preview_continuously +				let cmd = vimsetpid . ' ; ' +						\ . 'export SUCCESSCMD=' . shellescape(svimcmd) . ' ' +						\ . '       FAILURECMD=' . shellescape(fvimcmd) . ' ; ' +						\ . escape(cmd, '%') +			else +				let cmd = vimsetpid . ' ; ' . escape(cmd, '%') . ' ; ' . vimcmd +			endif +			let cmd = '! (' . cmd . ') >/dev/null &' +		endif + +		if g:LatexBox_latexmk_preview_continuously +			echo 'Compiling to ' . g:LatexBox_output_type +						\ . ' with continuous preview.' +		else +			echo 'Compiling to ' . g:LatexBox_output_type . ' ...' +		endif +		silent execute cmd +	else +		if g:LatexBox_latexmk_preview_continuously +			if has('win32') +				let cmd = '!start /b cmd /s /c "' . cmd . '"' +			else +				let cmd = '!' . cmd . ' &' +			endif +			echo 'Compiling to ' . g:LatexBox_output_type . ' ...' +			silent execute cmd + +			" Save PID in order to be able to kill the process when wanted. +			if has('win32') +				let tmpfile = tempname() +				let pidcmd = 'cmd /c "wmic process where ' +							\ . '(CommandLine LIKE "latexmk\%'.mainfile.'\%") ' +							\ . 'get ProcessId /value | find "ProcessId" ' +							\ . '>'.tmpfile.' "' +				silent execute '! ' . pidcmd +				let pids = readfile(tmpfile) +				let pid = strpart(pids[0], 10) +				let g:latexmk_running_pids[basepath] = pid +			else +				let pid = substitute(system('pgrep -f "perl.*' +							\ . mainfile . '" | head -n 1'),'\D','','') +				let g:latexmk_running_pids[basepath] = pid +			endif +		else +			" Execute command and check for errors +			echo 'Compiling to ' . g:LatexBox_output_type . ' ... (async off!)' +			call system(cmd) +			call LatexBox_LatexErrors(v:shell_error) +		endif +	endif + +	" Redraw screen if necessary +	if !has("gui_running") +		redraw! +	endif +endfunction +" }}} + +" LatexmkClean {{{ +function! LatexBox_LatexmkClean(cleanall) +	" Check if latexmk is installed +	if !executable('latexmk') +		echomsg "Error: LaTeX-Box relies on latexmk for compilation, but it" . +					\ " is not installed!" +		return +	endif + +	let basename = LatexBox_GetBuildBasename(1) + +	if has_key(g:latexmk_running_pids, basename) +		echomsg "don't clean when latexmk is running" +		return +	endif + +	if has('win32') +		let cmd = 'cd /D ' . shellescape(LatexBox_GetTexRoot()) . ' & ' +	else +		let cmd = 'cd ' . shellescape(LatexBox_GetTexRoot()) . ';' +	endif +	if a:cleanall +		let cmd .= 'latexmk -C ' +	else +		let cmd .= 'latexmk -c ' +	endif +	let cmd .= shellescape(LatexBox_GetMainTexFile()) +	if has('win32') +		let cmd .= ' >nul' +	else +		let cmd .= ' >&/dev/null' +	endif + +	call system(cmd) +	if !has('gui_running') +		redraw! +	endif + +	echomsg "latexmk clean finished" +endfunction +" }}} + +" LatexErrors {{{ +function! LatexBox_LatexErrors(status, ...) +	if a:0 >= 1 +		let log = a:1 . '.log' +	else +		let log = LatexBox_GetLogFile() +	endif + +	cclose + +	" set cwd to expand error file correctly +	let l:cwd = fnamemodify(getcwd(), ':p') +	execute 'lcd ' . fnameescape(LatexBox_GetTexRoot()) +	try +		if g:LatexBox_autojump +			execute 'cfile ' . fnameescape(log) +		else +			execute 'cgetfile ' . fnameescape(log) +		endif +	finally +		" restore cwd +		execute 'lcd ' . fnameescape(l:cwd) +	endtry + +	" Always open window if started by LatexErrors command +	if a:status < 0 +		botright copen +	else +		" Only open window when an error/warning is detected +		if g:LatexBox_quickfix >= 3 +					\ ? s:log_contains_error(log) +					\ : g:LatexBox_quickfix > 0 +			belowright cw +			if g:LatexBox_quickfix == 2 || g:LatexBox_quickfix == 4 +				wincmd p +			endif +		endif +		redraw + +		" Write status message to screen +		if a:status > 0 || len(getqflist())>1 +			if s:log_contains_error(log) +				let l:status_msg = ' ... failed!' +			else +				let l:status_msg = ' ... there were warnings!' +			endif +		else +			let l:status_msg = ' ... success!' +		endif +		echomsg 'Compiling to ' . g:LatexBox_output_type . l:status_msg +	endif +endfunction + +" Redefine uniq() for compatibility with older Vim versions (< 7.4.218) +function! s:uniq(list) +        if exists('*uniq') +                return uniq(a:list) +        elseif len(a:list) <= 1 +                return a:list +        endif + +        let last_element = get(a:list,0) +        let uniq_list = [last_element] + +        for i in range(1, len(a:list)-1) +                let next_element = get(a:list, i) +                if last_element == next_element +                        continue +                endif +                let last_element = next_element +                call add(uniq_list, next_element) +        endfor +        return uniq_list +endfunction + +function! s:log_contains_error(file) +	let lines = readfile(a:file) +	let lines = filter(lines, 'v:val =~ ''^.*:\d\+: ''') +	let lines = s:uniq(map(lines, 'matchstr(v:val, ''^.*\ze:\d\+:'')')) +	let lines = filter(lines, 'filereadable(fnameescape(v:val))') +	return len(lines) > 0 +endfunction +" }}} + +" LatexmkStatus {{{ +function! LatexBox_LatexmkStatus(detailed) +	if a:detailed +		if empty(g:latexmk_running_pids) +			echo "latexmk is not running" +		else +			let plist = "" +			for [basename, pid] in items(g:latexmk_running_pids) +				if !empty(plist) +					let plist .= '; ' +				endif +				let plist .= fnamemodify(basename, ':t') . ':' . pid +			endfor +			echo "latexmk is running (" . plist . ")" +		endif +	else +		let basename = LatexBox_GetBuildBasename(1) +		if has_key(g:latexmk_running_pids, basename) +			echo "latexmk is running" +		else +			echo "latexmk is not running" +		endif +	endif +endfunction +" }}} + +" LatexmkStop {{{ +function! LatexBox_LatexmkStop(silent) +	if empty(g:latexmk_running_pids) +		if !a:silent +			let basepath = LatexBox_GetBuildBasename(1) +			let basename = fnamemodify(basepath, ':t') +			echoerr "latexmk is not running for `" . basename . "'" +		endif +	else +		let basepath = LatexBox_GetBuildBasename(1) +		let basename = fnamemodify(basepath, ':t') +		if has_key(g:latexmk_running_pids, basepath) +			call s:kill_latexmk_process(g:latexmk_running_pids[basepath]) +			call remove(g:latexmk_running_pids, basepath) +			if !a:silent +				echomsg "latexmk stopped for `" . basename . "'" +			endif +		elseif !a:silent +			echoerr "latexmk is not running for `" . basename . "'" +		endif +	endif +endfunction +" }}} + +" Commands {{{ + +command! -bang	Latexmk			call LatexBox_Latexmk(<q-bang> == "!") +command! -bang	LatexmkClean	call LatexBox_LatexmkClean(<q-bang> == "!") +command! -bang	LatexmkStatus	call LatexBox_LatexmkStatus(<q-bang> == "!") +command! LatexmkStop			call LatexBox_LatexmkStop(0) +command! LatexErrors			call LatexBox_LatexErrors(-1) + +if g:LatexBox_latexmk_async || g:LatexBox_latexmk_preview_continuously +	autocmd BufUnload <buffer> 	call LatexBox_LatexmkStop(1) +	autocmd VimLeave * 			call <SID>kill_all_latexmk_processes() +endif + +" }}} + +" vim:fdm=marker:ff=unix:noet:ts=4:sw=4 + +endif diff --git a/ftplugin/latex-box/mappings.vim b/ftplugin/latex-box/mappings.vim new file mode 100644 index 00000000..7141635e --- /dev/null +++ b/ftplugin/latex-box/mappings.vim @@ -0,0 +1,110 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1 +   +" LaTeX Box mappings + +if exists("g:LatexBox_no_mappings") +	finish +endif + +" latexmk {{{ +noremap <buffer> <LocalLeader>ll :Latexmk<CR> +noremap <buffer> <LocalLeader>lL :Latexmk!<CR> +noremap <buffer> <LocalLeader>lc :LatexmkClean<CR> +noremap <buffer> <LocalLeader>lC :LatexmkClean!<CR> +noremap <buffer> <LocalLeader>lg :LatexmkStatus<CR> +noremap <buffer> <LocalLeader>lG :LatexmkStatus!<CR> +noremap <buffer> <LocalLeader>lk :LatexmkStop<CR> +noremap <buffer> <LocalLeader>le :LatexErrors<CR> +" }}} + +" View {{{ +noremap <buffer> <LocalLeader>lv :LatexView<CR> +" }}} + +" TOC {{{ +noremap <silent> <buffer> <LocalLeader>lt :LatexTOC<CR> +" }}} + +" List of labels {{{ +noremap <silent> <buffer> <LocalLeader>lj :LatexLabels<CR> +" }}} + +" Folding {{{ +if g:LatexBox_Folding == 1 +	noremap <buffer> <LocalLeader>lf :LatexFold<CR> +endif +" }}} + +" Jump to match {{{ +if !exists('g:LatexBox_loaded_matchparen') +	nmap <buffer> % <Plug>LatexBox_JumpToMatch +	vmap <buffer> % <Plug>LatexBox_JumpToMatch +	omap <buffer> % <Plug>LatexBox_JumpToMatch +endif +" }}} + +" Define text objects {{{ +vmap <buffer> ie <Plug>LatexBox_SelectCurrentEnvInner +vmap <buffer> ae <Plug>LatexBox_SelectCurrentEnvOuter +onoremap <buffer> ie :normal vie<CR> +onoremap <buffer> ae :normal vae<CR> +vmap <buffer> i$ <Plug>LatexBox_SelectInlineMathInner +vmap <buffer> a$ <Plug>LatexBox_SelectInlineMathOuter +onoremap <buffer> i$ :normal vi$<CR> +onoremap <buffer> a$ :normal va$<CR> +" }}} + +" Jump between sections {{{ +function! s:LatexBoxNextSection(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 +	let notcomment = '\%(\%(\\\@<!\%(\\\\\)*\)\@<=%.*\)\@<!' +	let pattern = notcomment . '\v\s*\\(' . join([ +				\ '(sub)*section', +				\ 'chapter', +				\ 'part', +				\ 'appendix', +				\ '(front|back|main)matter'], '|') . ')>' +	call search(pattern, 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 +noremap  <buffer> <silent> ]] :call <SID>LatexBoxNextSection(0,0,0)<CR> +noremap  <buffer> <silent> ][ :call <SID>LatexBoxNextSection(1,0,0)<CR> +noremap  <buffer> <silent> [] :call <SID>LatexBoxNextSection(1,1,0)<CR> +noremap  <buffer> <silent> [[ :call <SID>LatexBoxNextSection(0,1,0)<CR> +vnoremap <buffer> <silent> ]] :<c-u>call <SID>LatexBoxNextSection(0,0,1)<CR> +vnoremap <buffer> <silent> ][ :<c-u>call <SID>LatexBoxNextSection(1,0,1)<CR> +vnoremap <buffer> <silent> [] :<c-u>call <SID>LatexBoxNextSection(1,1,1)<CR> +vnoremap <buffer> <silent> [[ :<c-u>call <SID>LatexBoxNextSection(0,1,1)<CR> +" }}} + +" vim:fdm=marker:ff=unix:noet:ts=4:sw=4 + +endif diff --git a/ftplugin/latex-box/motion.vim b/ftplugin/latex-box/motion.vim new file mode 100644 index 00000000..2053149c --- /dev/null +++ b/ftplugin/latex-box/motion.vim @@ -0,0 +1,548 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1 +   +" LaTeX Box motion functions + +" Motion options {{{ +" Opening and closing patterns +if !exists('g:LatexBox_open_pats') +	let g:LatexBox_open_pats  = [ '\\{','{','\\(','(','\\\[','\[', +				\ '\\begin\s*{.\{-}}', '\\left\s*\%([^\\]\|\\.\|\\\a*\)'] +	let g:LatexBox_close_pats = [ '\\}','}','\\)',')','\\\]','\]', +				\ '\\end\s*{.\{-}}',   '\\right\s*\%([^\\]\|\\.\|\\\a*\)'] +endif +" }}} + +" HasSyntax {{{ +" s:HasSyntax(syntaxName, [line], [col]) +function! s:HasSyntax(syntaxName, ...) +	let line = a:0 >= 1 ? a:1 : line('.') +	let col  = a:0 >= 2 ? a:2 : col('.') +	return index(map(synstack(line, col), +				\ 'synIDattr(v:val, "name") == "' . a:syntaxName . '"'), +				\ 1) >= 0 +endfunction +" }}} + +" Search and Skip Comments {{{ +" s:SearchAndSkipComments(pattern, [flags], [stopline]) +function! s:SearchAndSkipComments(pat, ...) +	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 LatexBox_InComment() +			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 +" }}} + +" Finding Matching Pair {{{ +function! s:FindMatchingPair(mode) + +	if a:mode =~ 'h\|i' +		2match none +	elseif a:mode == 'v' +		normal! gv +	endif + +	if LatexBox_InComment() | return | endif + +	" open/close pairs (dollars signs are treated apart) +	let dollar_pat = '\$' +	let notbslash = '\%(\\\@<!\%(\\\\\)*\)\@<=' +	let notcomment = '\%(\%(\\\@<!\%(\\\\\)*\)\@<=%.*\)\@<!' +	let anymatch =  '\(' +				\ . join(g:LatexBox_open_pats + g:LatexBox_close_pats, '\|') +				\ . '\|' . dollar_pat . '\)' + +	let lnum = line('.') +	let cnum = searchpos('\A', 'cbnW', 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^'. anymatch , 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'. anymatch , col('.') - 1) + 1 +			if cnum == 0 | return | endif +			call cursor(lnum, cnum) +			let delim = matchstr(getline(lnum), '\C^'. anymatch , 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^'. anymatch , 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 && s:HasSyntax('texMathZoneX', lnum0, cnum0) +			let [lnum2, cnum2] = searchpos(notcomment . notbslash. dollar_pat, 'nW', line('w$')*(a:mode =~ 'h\|i') , 200) +		else +			let [lnum2, cnum2] = searchpos('\%(\%'. lnum . 'l\%' . cnum . 'c\)\@!'. notcomment . notbslash . dollar_pat, '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:LatexBox_open_pats)) +			let open_pat = notbslash . g:LatexBox_open_pats[i] +			let close_pat = notbslash . g:LatexBox_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', 'LatexBox_InComment()', +							\ line('w$')*(a:mode =~ 'h\|i') , 200) +				if a:mode =~ 'h\|i' +					execute '2match MatchParen /\%(\%' . lnum . 'l\%' . cnum +								\ . 'c' . g:LatexBox_open_pats[i] . '\|\%' +								\ . lnum2 . 'l\%' . cnum2 . 'c' +								\ . g:LatexBox_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', 'LatexBox_InComment()', +							\ line('w0')*(a:mode =~ 'h\|i') , 200) +				if a:mode =~ 'h\|i' +					execute '2match MatchParen /\%(\%' . lnum2 . 'l\%' . cnum2 +								\ . 'c' . g:LatexBox_open_pats[i] . '\|\%' +								\ . lnum . 'l\%' . cnum . 'c' +								\ . g:LatexBox_close_pats[i] . '\)/' +				elseif a:mode =~ 'n\|v\|o' +					call cursor(lnum2,cnum2) +				endif +				break +			endif +		endfor + +	endif +endfunction + +" Allow to disable functionality if desired +if !exists('g:LatexBox_loaded_matchparen') +	" Disable matchparen autocommands +	augroup LatexBox_HighlightPairs +		autocmd BufEnter * if !exists("g:loaded_matchparen") || !g:loaded_matchparen | runtime plugin/matchparen.vim | endif +		autocmd BufEnter *.tex 3match none | unlet! g:loaded_matchparen | au! matchparen +		autocmd! CursorMoved *.tex call s:FindMatchingPair('h') +		autocmd! CursorMovedI *.tex call s:FindMatchingPair('i') +	augroup END +endif + +" Use LatexBox'es FindMatchingPair as '%' (enable jump between e.g. $'s) +nnoremap <silent> <Plug>LatexBox_JumpToMatch	:call <SID>FindMatchingPair('n')<CR> +vnoremap <silent> <Plug>LatexBox_JumpToMatch	:call <SID>FindMatchingPair('v')<CR> +onoremap <silent> <Plug>LatexBox_JumpToMatch	v:call <SID>FindMatchingPair('o')<CR> + +" }}} + +" select inline math {{{ +" s:SelectInlineMath(seltype) +" where seltype is either 'inner' or 'outer' +function! s:SelectInlineMath(seltype) + +	let dollar_pat = '\\\@<!\$' + +	if s:HasSyntax('texMathZoneX') +		call s:SearchAndSkipComments(dollar_pat, 'cbW') +	elseif getline('.')[col('.') - 1] == '$' +		call s:SearchAndSkipComments(dollar_pat, 'bW') +	else +		return +	endif + +	if a:seltype == 'inner' +		normal! l +	endif + +	if visualmode() ==# 'V' +		normal! V +	else +		normal! v +	endif + +	call s:SearchAndSkipComments(dollar_pat, 'W') + +	if a:seltype == 'inner' +		normal! h +	endif +endfunction + +vnoremap <silent> <Plug>LatexBox_SelectInlineMathInner +			\ :<C-U>call <SID>SelectInlineMath('inner')<CR> +vnoremap <silent> <Plug>LatexBox_SelectInlineMathOuter +			\ :<C-U>call <SID>SelectInlineMath('outer')<CR> +" }}} + +" select current environment {{{ +function! s:SelectCurrentEnv(seltype) +	let [env, lnum, cnum, lnum2, cnum2] = LatexBox_GetCurrentEnvironment(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 +vnoremap <silent> <Plug>LatexBox_SelectCurrentEnvInner :<C-U>call <SID>SelectCurrentEnv('inner')<CR> +vnoremap <silent> <Plug>LatexBox_SelectCurrentEnvOuter :<C-U>call <SID>SelectCurrentEnv('outer')<CR> +" }}} + +" Jump to the next braces {{{ +" +function! LatexBox_JumpToNextBraces(backward) +	let flags = '' +	if a:backward +		normal h +		let flags .= 'b' +	else +		let flags .= 'c' +	endif +	if search('[][}{]', flags) > 0 +		normal l +	endif +	let prev = strpart(getline('.'), col('.') - 2, 1) +	let next = strpart(getline('.'), col('.') - 1, 1) +	if next =~ '[]}]' && prev !~ '[][{}]' +		return "\<Right>" +	else +		return '' +	endif +endfunction +" }}} + +" Table of Contents {{{ + +" Special UTF-8 conversion +function! s:ConvertBack(line) +	let line = a:line +	if exists('g:LatexBox_plaintext_toc') +		" +		" Substitute stuff like '\IeC{\"u}' to plain 'u' +		" +		let line = substitute(line, '\\IeC\s*{\\.\(.\)}', '\1', 'g') +	else +		" +		" Substitute stuff like '\IeC{\"u}' to corresponding unicode symbols +		" +		for [pat, symbol] in s:ConvBackPats +			let line = substitute(line, pat, symbol, 'g') +		endfor +	endif +	return line +endfunction + +function! s:ReadTOC(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) +		let included = matchstr(line, '^\\@input{\zs[^}]*\ze}') +		if included != '' +			" append the input TOX to `toc` and `fileindices` +			let newaux = prefix . '/' . included +			let newtex = fnamemodify(newaux, ':r') . '.tex' +			call s:ReadTOC(newaux, newtex, toc, fileindices) +			continue +		endif + +		" Parse statements like: +		" \@writefile{toc}{\contentsline {section}{\numberline {secnum}Section Title}{pagenumber}} +		" \@writefile{toc}{\contentsline {section}{\tocsection {}{1}{Section Title}}{pagenumber}} +		" \@writefile{toc}{\contentsline {section}{\numberline {secnum}Section Title}{pagenumber}{otherstuff}} + +		let line = matchstr(line, +					\ '\\@writefile{toc}{\\contentsline\s*\zs.*\ze}\s*$') +		if empty(line) +			continue +		endif + +		let tree = LatexBox_TexToTree(s:ConvertBack(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 section number +		let secnum = '' +		let tree = tree[1] +		if len(tree) > 3 && empty(tree[1]) +			call remove(tree, 1) +		endif +		if len(tree) > 1 && type(tree[0]) == type("") && tree[0] =~ '^\\\(\(chapter\)\?numberline\|tocsection\)' +			let secnum = LatexBox_TreeToTex(tree[1]) +			let secnum = substitute(secnum, '\\\S\+\s', '', 'g') +			let secnum = substitute(secnum, '\\\S\+{\(.\{-}\)}', '\1', 'g') +			let secnum = substitute(secnum, '^{\+\|}\+$', '', 'g') +			call remove(tree, 1) +		endif +		" parse section title +		let text = LatexBox_TreeToTex(tree) +		let text = substitute(text, '^{\+\|}\+$',                 '', 'g') +		let text = substitute(text, '\m^\\\(no\)\?\(chapter\)\?numberline\s*', '', '') +		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 [toc, fileindices] + +endfunction + +function! LatexBox_TOC(...) + +	" Check if window already exists +	let winnr = bufwinnr(bufnr('LaTeX TOC')) +	" Two types of splits, horizontal and vertical +	let l:hori = "new" +	let l:vert = "vnew" + +	" Set General Vars and initialize size +	let l:type = g:LatexBox_split_type +	let l:size = 10 + +	" Size detection +	if l:type == l:hori +	  let l:size = g:LatexBox_split_length +	elseif l:type == l:vert +	  let l:size = g:LatexBox_split_width +	endif + +	if winnr >= 0 +		if a:0 == 0 +			silent execute winnr . 'wincmd w' +		else +			" Supplying an argument to this function causes toggling instead +			" of jumping to the TOC window +			if g:LatexBox_split_resize +				silent exe "set columns-=" . l:size +			endif +			silent execute 'bwipeout' . bufnr('LaTeX TOC') +		endif +		return +	endif +	" Read TOC +	let [toc, fileindices] = s:ReadTOC(LatexBox_GetAuxFile(), +									 \ LatexBox_GetMainTexFile()) +	let calling_buf = bufnr('%') + +	" Find closest section in current buffer +	let closest_index = s:FindClosestSection(toc,fileindices) + +	" Create TOC window and set local settings +	if g:LatexBox_split_resize +		silent exe "set columns+=" . l:size +	endif +	silent exe g:LatexBox_split_side l:size . l:type . ' LaTeX\ TOC' + +	let b:toc = toc +	let b:toc_numbers = 1 +	let b:calling_win = bufwinnr(calling_buf) +	setlocal filetype=latextoc + +	" Add TOC entries and jump to the closest section +	for entry in toc +		call append('$', entry['number'] . "\t" . entry['text']) +	endfor +	if !g:LatexBox_toc_hidehelp +		call append('$', "") +		call append('$', "<Esc>/q: close") +		call append('$', "<Space>: jump") +		call append('$', "<Enter>: jump and close") +		call append('$', "s:       hide numbering") +	endif +	0delete _ + +	execute 'normal! ' . (closest_index + 1) . 'G' + +	" Lock buffer +	setlocal nomodifiable +endfunction + +" Binary search for the closest section +" return the index of the TOC entry +function! s:FindClosestSection(toc, fileindices) +	let file = expand('%:p') +	if !has_key(a:fileindices, file) +		return 0 +	endif + +	let imax = len(a:fileindices[file]) +	if imax > 0 +		let imin = 0 +		while imin < imax - 1 +			let i = (imax + imin) / 2 +			let tocindex = a:fileindices[file][i] +			let entry = a:toc[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:fileindices[file][imin] +	else +		return 0 +	endif +endfunction + +let s:ConvBackPats = 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}'         , 'ö'], +			\ ['\\''U}'        , 'Ú'], +			\ ['\\`U}'         , 'Ù'], +			\ ['\\^U}'         , 'Û'], +			\ ['\\¨U}'         , 'Ü'], +			\ ['\\"U}'         , 'Ü'], +			\ ['\\''u}'        , 'ú'], +			\ ['\\`u}'         , 'ù'], +			\ ['\\^u}'         , 'û'], +			\ ['\\¨u}'         , 'ü'], +			\ ['\\"u}'         , 'ü'], +			\ ['\\`N}'         , 'Ǹ'], +			\ ['\\\~N}'        , 'Ñ'], +			\ ['\\''n}'        , 'ń'], +			\ ['\\`n}'         , 'ǹ'], +			\ ['\\\~n}'        , 'ñ'], +			\], '[''\C\(\\IeC\s*{\)\?'' . v:val[0], v:val[1]]') +" }}} + +" TOC Command {{{ +command! LatexTOC call LatexBox_TOC() +command! LatexTOCToggle call LatexBox_TOC(1) +" }}} + +" vim:fdm=marker:ff=unix:noet:ts=4:sw=4 + +endif diff --git a/ftplugin/latextoc.vim b/ftplugin/latextoc.vim new file mode 100644 index 00000000..bfb8658e --- /dev/null +++ b/ftplugin/latextoc.vim @@ -0,0 +1,206 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1 +   +" {{{1 Settings +setlocal buftype=nofile +setlocal bufhidden=wipe +setlocal nobuflisted +setlocal noswapfile +setlocal nowrap +setlocal nospell +setlocal cursorline +setlocal nonumber +setlocal nolist +setlocal tabstop=8 +setlocal cole=0 +setlocal cocu=nvic +if g:LatexBox_fold_toc +    setlocal foldmethod=expr +    setlocal foldexpr=TOCFoldLevel(v:lnum) +    setlocal foldtext=TOCFoldText() +endif +" }}}1 + +" {{{1 Functions +" {{{2 TOCClose +function! s:TOCClose() +    if g:LatexBox_split_resize +        silent exe "set columns-=" . g:LatexBox_split_width +    endif +    bwipeout +endfunction + +" {{{2 TOCToggleNumbers +function! s:TOCToggleNumbers() +    if b:toc_numbers +        setlocal conceallevel=3 +        let b:toc_numbers = 0 +    else +        setlocal conceallevel=0 +        let b:toc_numbers = 1 +    endif +endfunction + +" {{{2 EscapeTitle +function! s:EscapeTitle(titlestr) +    let titlestr = substitute(a:titlestr, '\\[a-zA-Z@]*\>\s*{\?', '.*', 'g') +    let titlestr = substitute(titlestr, '}', '', 'g') +    let titlestr = substitute(titlestr, '\%(\.\*\s*\)\{2,}', '.*', 'g') +    return titlestr +endfunction + +" {{{2 TOCActivate +function! s:TOCActivate(close) +    let n = getpos('.')[1] - 1 + +    if n >= len(b:toc) +        return +    endif + +    let entry = b:toc[n] + +    let titlestr = s:EscapeTitle(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:EscapeTitle(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 root = fnamemodify(entry['file'], ':h') . '/' +    let files = [entry['file']] +    for line in filter(readfile(entry['file']), 'v:val =~ ''\\input{''') +        let file = matchstr(line, '{\zs.\{-}\ze\(\.tex\)\?}') . '.tex' +        if file[0] != '/' +            let file = root . file +        endif +        call add(files, file) +    endfor + +    " Find section in buffer (or inputted files) +    if entry['level'] == 'label' +        let re = '\(\\label\_\s*{\|label\s*=\s*\)' . titlestr . '\>' +    else +        let re = '\\' . entry['level'] . '\_\s*{' . titlestr . '}' +    endif +    call s:TOCFindMatch(re, duplicates, files) + +    if a:close +        if g:LatexBox_split_resize +            silent exe "set columns-=" . g:LatexBox_split_width +        endif +        execute 'bwipeout ' . toc_bnr +    else +        execute toc_wnr . 'wincmd w' +    endif +endfunction + +" {{{2 TOCFindMatch +function! s:TOCFindMatch(strsearch,duplicates,files) +    if len(a:files) == 0 +        echoerr "Could not find: " . a:strsearch +        return +    endif + +    call s:TOCOpenBuf(a:files[0]) +    let dups = a:duplicates + +    " Skip duplicates +    while dups > 0 +        if search(a:strsearch, 'w') +            let dups -= 1 +        else +            break +        endif +    endwhile + +    if search(a:strsearch, 'w') +        normal! zv +        return +    endif + +    call s:TOCFindMatch(a:strsearch,dups,a:files[1:]) +endfunction + +" {{{2 TOCFoldLevel +function! TOCFoldLevel(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:LatexBox_fold_toc_levels >= 3 +        if match_s3 +            return ">3" +        endif +    endif + +    if g:LatexBox_fold_toc_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 + +" {{{2 TOCFoldText +function! TOCFoldText() +    let parts = matchlist(getline(v:foldstart), '^\(.*\)\t\(.*\)$') +    return printf('%-8s%-72s', parts[1], parts[2]) +endfunction + +" {{{2 TOCOpenBuf +function! s:TOCOpenBuf(file) + +    let bnr = bufnr(a:file) +    if bnr == -1 +        execute 'badd ' . a:file +        let bnr = bufnr(a:file) +    endif +    execute 'buffer! ' . bnr +    normal! gg + +endfunction + +" }}}1 + +" {{{1 Mappings +nnoremap <buffer> <silent> s :call <SID>TOCToggleNumbers()<CR> +nnoremap <buffer> <silent> q :call <SID>TOCClose()<CR> +nnoremap <buffer> <silent> <Esc> :call <SID>TOCClose()<CR> +nnoremap <buffer> <silent> <Space> :call <SID>TOCActivate(0)<CR> +nnoremap <buffer> <silent> <CR> :call <SID>TOCActivate(1)<CR> +nnoremap <buffer> <silent> <leftrelease> :call <SID>TOCActivate(0)<cr> +nnoremap <buffer> <silent> <2-leftmouse> :call <SID>TOCActivate(1)<cr> +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 +" }}}1 + +" vim:fdm=marker:ff=unix:et:ts=4:sw=4 + +endif diff --git a/ftplugin/tex_LatexBox.vim b/ftplugin/tex_LatexBox.vim new file mode 100644 index 00000000..6c8899a6 --- /dev/null +++ b/ftplugin/tex_LatexBox.vim @@ -0,0 +1,37 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1 +   +" LaTeX Box plugin for Vim +" Maintainer: David Munger +" Email: mungerd@gmail.com +" Version: 0.9.6 + +if exists('*fnameescape') +	function! s:FNameEscape(s) +		return fnameescape(a:s) +	endfunction +else +	function! s:FNameEscape(s) +		return a:s +	endfunction +endif + +if !exists('b:LatexBox_loaded') + +	let prefix = expand('<sfile>:p:h') . '/latex-box/' + +	execute 'source ' . s:FNameEscape(prefix . 'common.vim') +	execute 'source ' . s:FNameEscape(prefix . 'complete.vim') +	execute 'source ' . s:FNameEscape(prefix . 'motion.vim') +	execute 'source ' . s:FNameEscape(prefix . 'latexmk.vim') +	execute 'source ' . s:FNameEscape(prefix . 'folding.vim') +	" added by AH to add main.tex file finder +	execute 'source ' . s:FNameEscape(prefix . 'findmain.vim') +	execute 'source ' . s:FNameEscape(prefix . 'mappings.vim') + +	let b:LatexBox_loaded = 1 + +endif + +" vim:fdm=marker:ff=unix:noet:ts=4:sw=4 + +endif diff --git a/ftplugin/vue.vim b/ftplugin/vue.vim index 14ad26a0..cc10c561 100644 --- a/ftplugin/vue.vim +++ b/ftplugin/vue.vim @@ -13,6 +13,13 @@ runtime! ftplugin/html.vim  setlocal suffixesadd+=.vue +if !exists('g:no_plugin_maps') && !exists('g:no_vue_maps') +  nnoremap <silent> <buffer> [[ :call search('^<\(template\<Bar>script\<Bar>style\)', 'bW')<CR> +  nnoremap <silent> <buffer> ]] :call search('^<\(template\<Bar>script\<Bar>style\)', 'W')<CR> +  nnoremap <silent> <buffer> [] :call search('^</\(template\<Bar>script\<Bar>style\)', 'bW')<CR> +  nnoremap <silent> <buffer> ][ :call search('^</\(template\<Bar>script\<Bar>style\)', 'W')<CR> +endif +  if exists('g:loaded_ale')    let g:ale_linters = get(g:, 'ale_linters', {})    let g:ale_linters.vue = get(g:ale_linters, 'vue', ['eslint']) | 
