vimtex/autoload/latex/util.vim
Enno Nagel f71ecc279d ensure that under MS Windows standard cmd shell executes bang commands
all of the latexmk and util library assumes that
under MS Windows the cmd shell is used.

The commit does this assumption justice.
2014-12-15 09:45:16 +01:00

383 lines
10 KiB
VimL

" LaTeX plugin for Vim
"
" Maintainer: Karl Yngve Lervåg
" Email: karl.yngve@gmail.com
"
" Utility functions sorted by name
"
function! latex#util#convert_back(line) " {{{1
"
" Substitute stuff like '\IeC{\"u}' to corresponding unicode symbols
"
let line = a:line
for [pat, symbol] in s:convert_back_list
let line = substitute(line, pat, symbol, 'g')
endfor
"
" There might be some missing conversions, which might be fixed by the last
" substitution
"
return substitute(line, '\C\(\\IeC\s*{\)\?\\.\(.\)}', '\1', 'g')
endfunction
let s:convert_back_list = map([
\ ['\\''A}' , 'Á'],
\ ['\\`A}' , 'À'],
\ ['\\^A}' , 'À'],
\ ['\\¨A}' , 'Ä'],
\ ['\\"A}' , 'Ä'],
\ ['\\''a}' , 'á'],
\ ['\\`a}' , 'à'],
\ ['\\^a}' , 'à'],
\ ['\\¨a}' , 'ä'],
\ ['\\"a}' , 'ä'],
\ ['\\''E}' , 'É'],
\ ['\\`E}' , 'È'],
\ ['\\^E}' , 'Ê'],
\ ['\\¨E}' , 'Ë'],
\ ['\\"E}' , 'Ë'],
\ ['\\''e}' , 'é'],
\ ['\\`e}' , 'è'],
\ ['\\^e}' , 'ê'],
\ ['\\¨e}' , 'ë'],
\ ['\\"e}' , 'ë'],
\ ['\\''I}' , 'Í'],
\ ['\\`I}' , 'Î'],
\ ['\\^I}' , 'Ì'],
\ ['\\¨I}' , 'Ï'],
\ ['\\"I}' , 'Ï'],
\ ['\\''i}' , 'í'],
\ ['\\`i}' , 'î'],
\ ['\\^i}' , 'ì'],
\ ['\\¨i}' , 'ï'],
\ ['\\"i}' , 'ï'],
\ ['\\''{\?\\i }' , 'í'],
\ ['\\''O}' , 'Ó'],
\ ['\\`O}' , 'Ò'],
\ ['\\^O}' , 'Ô'],
\ ['\\¨O}' , 'Ö'],
\ ['\\"O}' , 'Ö'],
\ ['\\''o}' , 'ó'],
\ ['\\`o}' , 'ò'],
\ ['\\^o}' , 'ô'],
\ ['\\¨o}' , 'ö'],
\ ['\\"o}' , 'ö'],
\ ['\\o }' , 'ø'],
\ ['\\''U}' , 'Ú'],
\ ['\\`U}' , 'Ù'],
\ ['\\^U}' , 'Û'],
\ ['\\¨U}' , 'Ü'],
\ ['\\"U}' , 'Ü'],
\ ['\\''u}' , 'ú'],
\ ['\\`u}' , 'ù'],
\ ['\\^u}' , 'û'],
\ ['\\¨u}' , 'ü'],
\ ['\\"u}' , 'ü'],
\ ['\\`N}' , 'Ǹ'],
\ ['\\\~N}' , 'Ñ'],
\ ['\\''n}' , 'ń'],
\ ['\\`n}' , 'ǹ'],
\ ['\\\~n}' , 'ñ'],
\], '[''\C\(\\IeC\s*{\)\?'' . v:val[0], v:val[1]]')
function! latex#util#error_deprecated(variable) " {{{1
if exists(a:variable)
echoerr "Deprecation error: " . a:variable
echoerr "Please red docs for more info!"
echoerr ":h vim-latex-changelog"
endif
endfunction
function! latex#util#execute(exe) " {{{1
" Execute the given command on the current system. Wrapper function to make
" it easier to run on both windows and unix.
"
" The command is given in the argument exe, which should be a dictionary with
" the following entries:
"
" exe.cmd String String that contains the command to run
" exe.bg 0 or 1 Run in background or not
" exe.silent 0 or 1 Show output or not
" exe.null 0 or 1 Send output to /dev/null
" exe.wd String Run command in provided working directory
"
" Only exe.cmd is required.
"
" Check and parse arguments
if !has_key(a:exe, 'cmd')
echoerr "Error in latex#util#execute!"
echoerr "Argument error, exe.cmd does not exist!"
return
endif
let bg = has_key(a:exe, 'bg') ? a:exe.bg : 1
let silent = has_key(a:exe, 'silent') ? a:exe.silent : 1
let null = has_key(a:exe, 'null') ? a:exe.null : 1
" Change directory if wanted
if has_key(a:exe, 'wd')
let pwd = getcwd()
execute 'lcd ' . fnameescape(a:exe.wd)
endif
" Set up command string based on the given system
if has('win32')
let cmd = a:exe.cmd
if null
let cmd .= ' >nul'
endif
if bg
let cmd = '!start /b "' . cmd . '"'
else
let cmd = '!' . cmd
endif
else
let cmd = '!' . a:exe.cmd
if null
let cmd .= ' &>/dev/null'
endif
if bg
let cmd .= ' &'
endif
endif
if has('win32') && &shell !~? 'cmd'
let savedShell=[&shell, &shellcmdflag, &shellxquote, &shellxescape, &shellquote, &shellpipe, &shellredir, &shellslash]
set shell& shellcmdflag& shellxquote& shellxescape& shellquote& shellpipe& shellredir& shellslash&
endif
if silent
silent execute cmd
else
execute cmd
endif
if has('win32') && &shell !~? 'cmd'
let [&shell, &shellcmdflag, &shellxquote, &shellxescape, &shellquote, &shellpipe, &shellredir, &shellslash]=savedShell
endif
" Return to previous working directory
if has_key(a:exe, 'wd')
execute 'lcd ' . fnameescape(pwd)
endif
if !has("gui_running")
redraw!
endif
endfunction
" }}}1
function! latex#util#get_env(...) " {{{1
" latex#util#get_env([with_pos])
" Returns:
" - environment
" if with_pos is not given
" - [environment, lnum_begin, cnum_begin, lnum_end, cnum_end]
" if with_pos is nonzero
let with_pos = a:0 > 0 ? a:1 : 0
let begin_pat = '\C\\begin\_\s*{[^}]*}\|\\\@<!\\\[\|\\\@<!\\('
let end_pat = '\C\\end\_\s*{[^}]*}\|\\\@<!\\\]\|\\\@<!\\)'
let saved_pos = getpos('.')
" move to the left until on a backslash
let [bufnum, lnum, cnum, off] = getpos('.')
let line = getline(lnum)
while cnum > 1 && line[cnum - 1] != '\'
let cnum -= 1
endwhile
call cursor(lnum, cnum)
" match begin/end pairs but skip comments
let flags = 'bnW'
if strpart(getline('.'), col('.') - 1) =~ '^\%(' . begin_pat . '\)'
let flags .= 'c'
endif
let [lnum1, cnum1] = searchpairpos(begin_pat, '', end_pat, flags,
\ 'latex#util#in_comment()')
let env = ''
if lnum1
let line = strpart(getline(lnum1), cnum1 - 1)
if empty(env)
let env = matchstr(line, '^\C\\begin\_\s*{\zs[^}]*\ze}')
endif
if empty(env)
let env = matchstr(line, '^\\\[')
endif
if empty(env)
let env = matchstr(line, '^\\(')
endif
endif
if with_pos == 1
let flags = 'nW'
if !(lnum1 == lnum && cnum1 == cnum)
let flags .= 'c'
endif
let [lnum2, cnum2] = searchpairpos(begin_pat, '', end_pat, flags,
\ 'latex#util#in_comment()')
call setpos('.', saved_pos)
return [env, lnum1, cnum1, lnum2, cnum2]
else
call setpos('.', saved_pos)
return env
endif
endfunction
function! latex#util#get_delim() " {{{1
" Save position in order to restore before finishing
let pos_original = getpos('.')
" Save position for more work later
let pos_save = getpos('.')
" Check if the cursor is on top of a closing delimiter
let close_pats = '\(' . join(s:delimiters_close, '\|') . '\)'
let lnum = pos_save[1]
let cnum = pos_save[2]
let [lnum, cnum] = searchpos(close_pats, 'cbnW', lnum)
let delim = matchstr(getline(lnum), '^'. close_pats, cnum-1)
if pos_save[2] <= (cnum + len(delim) - 1)
let pos_save[1] = lnum
let pos_save[2] = cnum
call setpos('.', pos_save)
endif
let d1=''
let d2=''
let l1=1000000
let l2=1000000
let c1=1000000
let c2=1000000
for i in range(len(s:delimiters_open))
call setpos('.', pos_save)
let open = s:delimiters_open[i]
let close = s:delimiters_close[i]
let flags = 'W'
" Check if the cursor is on top of an opening delimiter. If it is not,
" then we want to include matches at cursor position to match closing
" delimiters.
if searchpos(open, 'cn') != pos_save[1:2]
let flags .= 'c'
endif
" Search for closing delimiter
let pos = searchpairpos(open, '', close, flags, 'latex#util#in_comment()')
" Check if the current is pair is the closest pair
if pos[0] && pos[0]*1000 + pos[1] < l2*1000 + c2
let l2=pos[0]
let c2=pos[1]
let d2=matchstr(strpart(getline(l2), c2 - 1), close)
let pos = searchpairpos(open,'',close,'bW', 'latex#util#in_comment()')
let l1=pos[0]
let c1=pos[1]
let d1=matchstr(strpart(getline(l1), c1 - 1), open)
endif
endfor
" Restore cursor position and return delimiters and positions
call setpos('.', pos_original)
return [d1,l1,c1,d2,l2,c2]
endfunction
let s:delimiters_open = [
\ '(',
\ '\[',
\ '\\{',
\ '\\\Cleft\s*\%([^\\a-zA-Z0-9]\|\\.\|\\\a*\)',
\ '\\\cbigg\?\((\|\[\|\\{\)',
\ ]
let s:delimiters_close = [
\ ')',
\ '\]',
\ '\\}',
\ '\\\Cright\s*\%([^\\a-zA-Z0-9]\|\\.\|\\\a*\)',
\ '\\\cbigg\?\()\|\]\|\\}\)',
\ ]
function! latex#util#has_syntax(name, ...) " {{{1
" Usage: latex#util#has_syntax(name, [line], [col])
let line = a:0 >= 1 ? a:1 : line('.')
let col = a:0 >= 2 ? a:2 : col('.')
return 0 <= index(map(synstack(line, col),
\ 'synIDattr(v:val, "name") == "' . a:name . '"'), 1)
endfunction
function! latex#util#in_comment(...) " {{{1
return synIDattr(synID(line('.'), col('.'), 0), "name") =~# '^texComment'
endfunction
function! latex#util#kpsewhich(file, ...) " {{{1
let cmd = 'kpsewhich '
let cmd .= a:0 > 0 ? a:1 : ''
let cmd .= ' "' . a:file . '"'
let out = system(cmd)
" If kpsewhich has found something, it returns a non-empty string with a
" newline at the end; otherwise the string is empty
if len(out)
" Remove the trailing newline
let out = fnamemodify(out[:-2], ':p')
endif
return out
endfunction
function! latex#util#set_default(variable, default) " {{{1
if !exists(a:variable)
let {a:variable} = a:default
endif
endfunction
function! latex#util#tex2tree(str) " {{{1
let tree = []
let i1 = 0
let i2 = -1
let depth = 0
while i2 < len(a:str)
let i2 = match(a:str, '[{}]', i2 + 1)
if i2 < 0
let i2 = len(a:str)
endif
if i2 >= len(a:str) || a:str[i2] == '{'
if depth == 0
let item = substitute(strpart(a:str, i1, i2 - i1),
\ '^\s*\|\s*$', '', 'g')
if !empty(item)
call add(tree, item)
endif
let i1 = i2 + 1
endif
let depth += 1
else
let depth -= 1
if depth == 0
call add(tree, latex#util#tex2tree(strpart(a:str, i1, i2 - i1)))
let i1 = i2 + 1
endif
endif
endwhile
return tree
endfunction
function! latex#util#tree2tex(tree) " {{{1
if type(a:tree) == type('')
return a:tree
else
return '{' . join(map(a:tree, 'latex#util#tree2tex(v:val)'), '') . '}'
endif
endfunction
" }}}1
" vim: fdm=marker sw=2