mirror of
https://github.com/sheerun/vim-polyglot.git
synced 2025-11-09 20:13:51 -05:00
701 lines
19 KiB
VimL
701 lines
19 KiB
VimL
if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1
|
|
|
|
" vimtex - LaTeX plugin for Vim
|
|
"
|
|
" Maintainer: Karl Yngve Lervåg
|
|
" Email: karl.yngve@gmail.com
|
|
"
|
|
|
|
function! vimtex#compiler#latexmk#init(options) abort " {{{1
|
|
let l:compiler = deepcopy(s:compiler)
|
|
|
|
call l:compiler.init(extend(a:options,
|
|
\ get(g:, 'vimtex_compiler_latexmk', {}), 'keep'))
|
|
|
|
return l:compiler
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! vimtex#compiler#latexmk#wrap_option(name, value) abort " {{{1
|
|
return has('win32')
|
|
\ ? ' -e "$' . a:name . ' = ''' . a:value . '''"'
|
|
\ : ' -e ''$' . a:name . ' = "' . a:value . '"'''
|
|
endfunction
|
|
|
|
"}}}1
|
|
|
|
function! vimtex#compiler#latexmk#get_rc_opt(root, opt, type, default) abort " {{{1
|
|
"
|
|
" Parse option from .latexmkrc.
|
|
"
|
|
" Arguments:
|
|
" root Root of LaTeX project
|
|
" opt Name of options
|
|
" type 0 if string, 1 if integer, 2 if list
|
|
" default Value to return if option not found in latexmkrc file
|
|
"
|
|
" Output:
|
|
" [value, location]
|
|
"
|
|
" value Option value (integer or string)
|
|
" location An integer that indicates where option was found
|
|
" -1: not found (default value returned)
|
|
" 0: global latexmkrc file
|
|
" 1: local latexmkrc file
|
|
"
|
|
|
|
if a:type == 0
|
|
let l:pattern = '^\s*\$' . a:opt . '\s*=\s*[''"]\(.\+\)[''"]'
|
|
elseif a:type == 1
|
|
let l:pattern = '^\s*\$' . a:opt . '\s*=\s*\(\d\+\)'
|
|
elseif a:type == 2
|
|
let l:pattern = '^\s*@' . a:opt . '\s*=\s*(\(.*\))'
|
|
else
|
|
throw 'vimtex: argument error'
|
|
endif
|
|
|
|
" Candidate files
|
|
" - each element is a pair [path_to_file, is_local_rc_file].
|
|
let l:files = [
|
|
\ [a:root . '/latexmkrc', 1],
|
|
\ [a:root . '/.latexmkrc', 1],
|
|
\ [fnamemodify('~/.latexmkrc', ':p'), 0],
|
|
\]
|
|
if !empty($XDG_CONFIG_HOME)
|
|
call add(l:files, [$XDG_CONFIG_HOME . '/latexmk/latexmkrc', 0])
|
|
endif
|
|
|
|
let l:result = [a:default, -1]
|
|
|
|
for [l:file, l:is_local] in l:files
|
|
if filereadable(l:file)
|
|
let l:match = matchlist(readfile(l:file), l:pattern)
|
|
if len(l:match) > 1
|
|
let l:result = [l:match[1], l:is_local]
|
|
break
|
|
end
|
|
endif
|
|
endfor
|
|
|
|
" Parse the list
|
|
if a:type == 2 && l:result[1] > -1
|
|
let l:array = split(l:result[0], ',')
|
|
let l:result[0] = []
|
|
for l:x in l:array
|
|
let l:x = substitute(l:x, "^'", '', '')
|
|
let l:x = substitute(l:x, "'$", '', '')
|
|
let l:result[0] += [l:x]
|
|
endfor
|
|
endif
|
|
|
|
return l:result
|
|
endfunction
|
|
|
|
" }}}1
|
|
|
|
let s:compiler = {
|
|
\ 'name' : 'latexmk',
|
|
\ 'executable' : 'latexmk',
|
|
\ 'backend' : has('nvim') ? 'nvim'
|
|
\ : v:version >= 800 ? 'jobs' : 'process',
|
|
\ 'root' : '',
|
|
\ 'target' : '',
|
|
\ 'target_path' : '',
|
|
\ 'background' : 1,
|
|
\ 'build_dir' : '',
|
|
\ 'callback' : 1,
|
|
\ 'continuous' : 1,
|
|
\ 'output' : tempname(),
|
|
\ 'options' : [
|
|
\ '-verbose',
|
|
\ '-file-line-error',
|
|
\ '-synctex=1',
|
|
\ '-interaction=nonstopmode',
|
|
\ ],
|
|
\ 'hooks' : [],
|
|
\ 'shell' : fnamemodify(&shell, ':t'),
|
|
\}
|
|
|
|
function! s:compiler.init(options) abort dict " {{{1
|
|
call extend(self, a:options)
|
|
|
|
call self.init_check_requirements()
|
|
call self.init_build_dir_option()
|
|
call self.init_pdf_mode_option()
|
|
|
|
call extend(self, deepcopy(s:compiler_{self.backend}))
|
|
|
|
" Continuous processes can't run in foreground, neither can processes run
|
|
" with the new jobs api
|
|
if self.continuous || self.backend !=# 'process'
|
|
let self.background = 1
|
|
endif
|
|
|
|
if self.backend !=# 'process'
|
|
let self.shell = 'sh'
|
|
endif
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:compiler.init_build_dir_option() abort dict " {{{1
|
|
"
|
|
" Check if .latexmkrc sets the build_dir - if so this should be respected
|
|
"
|
|
let l:out_dir =
|
|
\ vimtex#compiler#latexmk#get_rc_opt(self.root, 'out_dir', 0, '')[0]
|
|
|
|
if !empty(l:out_dir)
|
|
if !empty(self.build_dir) && (self.build_dir !=# l:out_dir)
|
|
call vimtex#log#warning(
|
|
\ 'Setting out_dir from latexmkrc overrides build_dir!',
|
|
\ 'Changed build_dir from: ' . self.build_dir,
|
|
\ 'Changed build_dir to: ' . l:out_dir)
|
|
endif
|
|
let self.build_dir = l:out_dir
|
|
endif
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:compiler.init_pdf_mode_option() abort dict " {{{1
|
|
" If the TeX program directive was not set, and if the pdf_mode is set in
|
|
" a .latexmkrc file, then deduce the compiler engine from the value of
|
|
" pdf_mode.
|
|
|
|
" Parse the pdf_mode option. If not found, it is set to -1.
|
|
let [l:pdf_mode, l:is_local] =
|
|
\ vimtex#compiler#latexmk#get_rc_opt(self.root, 'pdf_mode', 1, -1)
|
|
|
|
" If pdf_mode has a supported value (1: pdflatex, 4: lualatex, 5: xelatex),
|
|
" override the value of self.tex_program.
|
|
if l:pdf_mode == 1
|
|
let l:tex_program = 'pdflatex'
|
|
elseif l:pdf_mode == 3
|
|
let l:tex_program = 'pdfdvi'
|
|
elseif l:pdf_mode == 4
|
|
let l:tex_program = 'lualatex'
|
|
elseif l:pdf_mode == 5
|
|
let l:tex_program = 'xelatex'
|
|
else
|
|
return
|
|
endif
|
|
|
|
if self.tex_program ==# '_'
|
|
" The TeX program directive was not specified
|
|
let self.tex_program = l:tex_program
|
|
elseif l:is_local && self.tex_program !=# l:tex_program
|
|
call vimtex#log#warning(
|
|
\ 'Value of pdf_mode from latexmkrc is inconsistent with ' .
|
|
\ 'TeX program directive!',
|
|
\ 'TeX program: ' . self.tex_program,
|
|
\ 'pdf_mode: ' . l:tex_program,
|
|
\ 'The value of pdf_mode will be ignored.')
|
|
endif
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:compiler.init_check_requirements() abort dict " {{{1
|
|
" Check option validity
|
|
if self.callback
|
|
if !(has('clientserver') || has('nvim') || has('job'))
|
|
let self.callback = 0
|
|
call vimtex#log#warning(
|
|
\ 'Can''t use callbacks without +job, +nvim, or +clientserver',
|
|
\ 'Callback option has been disabled.')
|
|
endif
|
|
endif
|
|
|
|
" Check for required executables
|
|
let l:required = [self.executable]
|
|
if self.continuous && !(has('win32') || has('win32unix'))
|
|
let l:required += ['pgrep']
|
|
endif
|
|
let l:missing = filter(l:required, '!executable(v:val)')
|
|
|
|
" Disable latexmk if required programs are missing
|
|
if len(l:missing) > 0
|
|
for l:cmd in l:missing
|
|
call vimtex#log#warning(l:cmd . ' is not executable')
|
|
endfor
|
|
throw 'vimtex: Requirements not met'
|
|
endif
|
|
endfunction
|
|
|
|
" }}}1
|
|
|
|
function! s:compiler.build_cmd() abort dict " {{{1
|
|
if has('win32')
|
|
let l:cmd = 'set max_print_line=2000 & ' . self.executable
|
|
else
|
|
if self.shell ==# 'fish'
|
|
let l:cmd = 'set max_print_line 2000; and ' . self.executable
|
|
else
|
|
let l:cmd = 'max_print_line=2000 ' . self.executable
|
|
endif
|
|
endif
|
|
|
|
for l:opt in self.options
|
|
let l:cmd .= ' ' . l:opt
|
|
endfor
|
|
|
|
let l:cmd .= ' ' . self.get_engine()
|
|
|
|
if !empty(self.build_dir)
|
|
let l:cmd .= ' -outdir=' . fnameescape(self.build_dir)
|
|
endif
|
|
|
|
if self.continuous
|
|
let l:cmd .= ' -pvc'
|
|
|
|
" Set viewer options
|
|
if !get(g:, 'vimtex_view_automatic', 1)
|
|
\ || get(get(b:vimtex, 'viewer', {}), 'xwin_id') > 0
|
|
\ || get(s:, 'silence_next_callback', 0)
|
|
let l:cmd .= ' -view=none'
|
|
elseif g:vimtex_view_enabled
|
|
\ && has_key(b:vimtex.viewer, 'latexmk_append_argument')
|
|
let l:cmd .= b:vimtex.viewer.latexmk_append_argument()
|
|
endif
|
|
|
|
if self.callback
|
|
if has('job') || has('nvim')
|
|
for [l:opt, l:val] in items({
|
|
\ 'success_cmd' : 'vimtex_compiler_callback_success',
|
|
\ 'failure_cmd' : 'vimtex_compiler_callback_failure',
|
|
\})
|
|
let l:func = 'echo ' . l:val
|
|
let l:cmd .= vimtex#compiler#latexmk#wrap_option(l:opt, l:func)
|
|
endfor
|
|
elseif empty(v:servername)
|
|
call vimtex#log#warning('Can''t use callbacks with empty v:servername')
|
|
else
|
|
" Some notes:
|
|
" - We excape the v:servername because this seems necessary on Windows
|
|
" for neovim, see e.g. Github Issue #877
|
|
for [l:opt, l:val] in items({'success_cmd' : 1, 'failure_cmd' : 0})
|
|
let l:callback = has('win32')
|
|
\ ? '"vimtex#compiler#callback(' . l:val . ')"'
|
|
\ : '\"vimtex\#compiler\#callback(' . l:val . ')\"'
|
|
let l:func = vimtex#util#shellescape('""')
|
|
\ . g:vimtex_compiler_progname
|
|
\ . vimtex#util#shellescape('""')
|
|
\ . ' --servername ' . vimtex#util#shellescape(v:servername)
|
|
\ . ' --remote-expr ' . l:callback
|
|
let l:cmd .= vimtex#compiler#latexmk#wrap_option(l:opt, l:func)
|
|
endfor
|
|
endif
|
|
endif
|
|
endif
|
|
|
|
return l:cmd . ' ' . vimtex#util#shellescape(self.target)
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:compiler.get_engine() abort dict " {{{1
|
|
return get(extend(g:vimtex_compiler_latexmk_engines,
|
|
\ {
|
|
\ 'pdfdvi' : '-pdfdvi',
|
|
\ 'pdflatex' : '-pdf',
|
|
\ 'luatex' : '-lualatex',
|
|
\ 'lualatex' : '-lualatex',
|
|
\ 'xelatex' : '-xelatex',
|
|
\ 'context (pdftex)' : '-pdf -pdflatex=texexec',
|
|
\ 'context (luatex)' : '-pdf -pdflatex=context',
|
|
\ 'context (xetex)' : '-pdf -pdflatex=''texexec --xtx''',
|
|
\ }, 'keep'), self.tex_program, '-pdf')
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:compiler.cleanup() abort dict " {{{1
|
|
if self.is_running()
|
|
call self.kill()
|
|
endif
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:compiler.pprint_items() abort dict " {{{1
|
|
let l:configuration = [
|
|
\ ['continuous', self.continuous],
|
|
\ ['callback', self.callback],
|
|
\]
|
|
|
|
if self.backend ==# 'process' && !self.continuous
|
|
call add(l:configuration, ['background', self.background])
|
|
endif
|
|
|
|
if !empty(self.build_dir)
|
|
call add(l:configuration, ['build_dir', self.build_dir])
|
|
endif
|
|
call add(l:configuration, ['latexmk options', self.options])
|
|
call add(l:configuration, ['latexmk engine', self.get_engine()])
|
|
|
|
let l:list = []
|
|
call add(l:list, ['backend', self.backend])
|
|
if self.executable !=# s:compiler.executable
|
|
call add(l:list, ['latexmk executable', self.executable])
|
|
endif
|
|
if self.background
|
|
call add(l:list, ['output', self.output])
|
|
endif
|
|
|
|
if self.target_path !=# b:vimtex.tex
|
|
call add(l:list, ['root', self.root])
|
|
call add(l:list, ['target', self.target_path])
|
|
endif
|
|
|
|
call add(l:list, ['configuration', l:configuration])
|
|
|
|
if has_key(self, 'process')
|
|
call add(l:list, ['process', self.process])
|
|
endif
|
|
|
|
if has_key(self, 'job')
|
|
if self.continuous
|
|
if self.backend ==# 'jobs'
|
|
call add(l:list, ['job', self.job])
|
|
else
|
|
call add(l:list, ['pid', self.get_pid()])
|
|
endif
|
|
endif
|
|
call add(l:list, ['cmd', self.cmd])
|
|
endif
|
|
|
|
return l:list
|
|
endfunction
|
|
|
|
" }}}1
|
|
|
|
function! s:compiler.clean(full) abort dict " {{{1
|
|
let l:restart = self.is_running()
|
|
if l:restart
|
|
call self.stop()
|
|
endif
|
|
|
|
" Define and run the latexmk clean cmd
|
|
let l:cmd = (has('win32')
|
|
\ ? 'cd /D "' . self.root . '" & '
|
|
\ : 'cd ' . vimtex#util#shellescape(self.root) . '; ')
|
|
\ . self.executable . ' ' . (a:full ? '-C ' : '-c ')
|
|
if !empty(self.build_dir)
|
|
let l:cmd .= printf(' -outdir=%s ', fnameescape(self.build_dir))
|
|
endif
|
|
let l:cmd .= vimtex#util#shellescape(self.target)
|
|
call vimtex#process#run(l:cmd)
|
|
|
|
call vimtex#log#info('Compiler clean finished' . (a:full ? ' (full)' : ''))
|
|
|
|
if l:restart
|
|
let self.silent_next_callback = 1
|
|
silent call self.start()
|
|
endif
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:compiler.start(...) abort dict " {{{1
|
|
if self.is_running()
|
|
call vimtex#log#warning(
|
|
\ 'Compiler is already running for `' . self.target . "'")
|
|
return
|
|
endif
|
|
|
|
"
|
|
" Create build dir if it does not exist
|
|
"
|
|
if !empty(self.build_dir)
|
|
let l:dirs = split(glob(self.root . '/**/*.tex'), '\n')
|
|
call map(l:dirs, 'fnamemodify(v:val, '':h'')')
|
|
call map(l:dirs, 'strpart(v:val, strlen(self.root) + 1)')
|
|
call vimtex#util#uniq(sort(filter(l:dirs, "v:val !=# ''")))
|
|
call map(l:dirs,
|
|
\ (vimtex#paths#is_abs(self.build_dir) ? '' : "self.root . '/' . ")
|
|
\ . "self.build_dir . '/' . v:val")
|
|
call filter(l:dirs, '!isdirectory(v:val)')
|
|
|
|
" Create the non-existing directories
|
|
for l:dir in l:dirs
|
|
call mkdir(l:dir, 'p')
|
|
endfor
|
|
endif
|
|
|
|
call self.exec()
|
|
|
|
if self.continuous
|
|
call vimtex#log#info('Compiler started in continuous mode'
|
|
\ . (a:0 > 0 ? ' (single shot)' : ''))
|
|
if exists('#User#VimtexEventCompileStarted')
|
|
doautocmd <nomodeline> User VimtexEventCompileStarted
|
|
endif
|
|
else
|
|
if self.background
|
|
call vimtex#log#info('Compiler started in background!')
|
|
else
|
|
call vimtex#compiler#callback(!vimtex#qf#inquire(self.target))
|
|
endif
|
|
endif
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:compiler.stop() abort dict " {{{1
|
|
if self.is_running()
|
|
call self.kill()
|
|
call vimtex#log#info('Compiler stopped (' . self.target . ')')
|
|
if exists('#User#VimtexEventCompileStopped')
|
|
doautocmd <nomodeline> User VimtexEventCompileStopped
|
|
endif
|
|
else
|
|
call vimtex#log#warning(
|
|
\ 'There is no process to stop (' . self.target . ')')
|
|
endif
|
|
endfunction
|
|
|
|
" }}}1
|
|
|
|
let s:compiler_process = {}
|
|
function! s:compiler_process.exec() abort dict " {{{1
|
|
let l:process = vimtex#process#new()
|
|
let l:process.name = 'latexmk'
|
|
let l:process.continuous = self.continuous
|
|
let l:process.background = self.background
|
|
let l:process.workdir = self.root
|
|
let l:process.output = self.output
|
|
let l:process.cmd = self.build_cmd()
|
|
|
|
if l:process.continuous
|
|
if (has('win32') || has('win32unix'))
|
|
" Not implemented
|
|
else
|
|
for l:pid in split(system(
|
|
\ 'pgrep -f "^[^ ]*perl.*latexmk.*' . self.target . '"'), "\n")
|
|
let l:path = resolve('/proc/' . l:pid . '/cwd') . '/' . self.target
|
|
if l:path ==# self.target_path
|
|
let l:process.pid = str2nr(l:pid)
|
|
break
|
|
endif
|
|
endfor
|
|
endif
|
|
endif
|
|
|
|
function! l:process.set_pid() abort dict " {{{2
|
|
if (has('win32') || has('win32unix'))
|
|
let pidcmd = 'tasklist /fi "imagename eq latexmk.exe"'
|
|
let pidinfo = vimtex#process#capture(pidcmd)[-1]
|
|
let self.pid = str2nr(split(pidinfo,'\s\+')[1])
|
|
else
|
|
let self.pid = str2nr(system('pgrep -nf "^[^ ]*perl.*latexmk"')[:-2])
|
|
endif
|
|
|
|
return self.pid
|
|
endfunction
|
|
|
|
" }}}2
|
|
|
|
let self.process = l:process
|
|
call self.process.run()
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:compiler_process.start_single() abort dict " {{{1
|
|
let l:continuous = self.continuous
|
|
let self.continuous = self.background && self.callback && !empty(v:servername)
|
|
|
|
if self.continuous
|
|
let g:vimtex_compiler_callback_hooks += ['VimtexSSCallback']
|
|
function! VimtexSSCallback(status) abort
|
|
silent call vimtex#compiler#stop()
|
|
call remove(g:vimtex_compiler_callback_hooks, 'VimtexSSCallback')
|
|
endfunction
|
|
endif
|
|
|
|
call self.start(1)
|
|
let self.continuous = l:continuous
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:compiler_process.is_running() abort dict " {{{1
|
|
return exists('self.process.pid') && self.process.pid > 0
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:compiler_process.kill() abort dict " {{{1
|
|
call self.process.stop()
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:compiler_process.get_pid() abort dict " {{{1
|
|
return has_key(self, 'process') ? self.process.pid : 0
|
|
endfunction
|
|
|
|
" }}}1
|
|
|
|
let s:compiler_jobs = {}
|
|
function! s:compiler_jobs.exec() abort dict " {{{1
|
|
let self.cmd = self.build_cmd()
|
|
let l:cmd = has('win32')
|
|
\ ? 'cmd /s /c "' . self.cmd . '"'
|
|
\ : ['sh', '-c', self.cmd]
|
|
|
|
let l:options = {
|
|
\ 'out_io' : 'file',
|
|
\ 'err_io' : 'file',
|
|
\ 'out_name' : self.output,
|
|
\ 'err_name' : self.output,
|
|
\}
|
|
if self.continuous
|
|
let l:options.out_io = 'pipe'
|
|
let l:options.err_io = 'pipe'
|
|
let l:options.out_cb = function('s:callback_continuous_output')
|
|
let l:options.err_cb = function('s:callback_continuous_output')
|
|
call writefile([], self.output, 'a')
|
|
else
|
|
let s:cb_target = self.target_path !=# b:vimtex.tex
|
|
\ ? self.target_path : ''
|
|
let l:options.exit_cb = function('s:callback')
|
|
endif
|
|
|
|
call vimtex#paths#pushd(self.root)
|
|
let self.job = job_start(l:cmd, l:options)
|
|
call vimtex#paths#popd()
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:compiler_jobs.start_single() abort dict " {{{1
|
|
let l:continuous = self.continuous
|
|
let self.continuous = 0
|
|
call self.start()
|
|
let self.continuous = l:continuous
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:compiler_jobs.kill() abort dict " {{{1
|
|
call job_stop(self.job)
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:compiler_jobs.is_running() abort dict " {{{1
|
|
return has_key(self, 'job') && job_status(self.job) ==# 'run'
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:compiler_jobs.get_pid() abort dict " {{{1
|
|
return has_key(self, 'job')
|
|
\ ? get(job_info(self.job), 'process') : 0
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:callback(ch, msg) abort " {{{1
|
|
call vimtex#compiler#callback(!vimtex#qf#inquire(s:cb_target))
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:callback_continuous_output(channel, msg) abort " {{{1
|
|
if exists('b:vimtex') && filewritable(b:vimtex.compiler.output)
|
|
call writefile([a:msg], b:vimtex.compiler.output, 'a')
|
|
endif
|
|
|
|
if a:msg ==# 'vimtex_compiler_callback_success'
|
|
call vimtex#compiler#callback(1)
|
|
elseif a:msg ==# 'vimtex_compiler_callback_failure'
|
|
call vimtex#compiler#callback(0)
|
|
endif
|
|
|
|
try
|
|
for l:Hook in get(get(get(b:, 'vimtex', {}), 'compiler', {}), 'hooks', [])
|
|
call l:Hook(a:msg)
|
|
endfor
|
|
catch /E716/
|
|
endtry
|
|
endfunction
|
|
|
|
" }}}1
|
|
|
|
let s:compiler_nvim = {}
|
|
function! s:compiler_nvim.exec() abort dict " {{{1
|
|
let self.cmd = self.build_cmd()
|
|
let l:cmd = has('win32')
|
|
\ ? 'cmd /s /c "' . self.cmd . '"'
|
|
\ : ['sh', '-c', self.cmd]
|
|
|
|
let l:shell = {
|
|
\ 'on_stdout' : function('s:callback_nvim_output'),
|
|
\ 'on_stderr' : function('s:callback_nvim_output'),
|
|
\ 'cwd' : self.root,
|
|
\ 'target' : self.target_path,
|
|
\ 'output' : self.output,
|
|
\}
|
|
|
|
if !self.continuous
|
|
let l:shell.on_exit = function('s:callback_nvim_exit')
|
|
endif
|
|
|
|
" Initialize output file
|
|
try
|
|
call writefile([], self.output)
|
|
endtry
|
|
|
|
let self.job = jobstart(l:cmd, l:shell)
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:compiler_nvim.start_single() abort dict " {{{1
|
|
let l:continuous = self.continuous
|
|
let self.continuous = 0
|
|
call self.start()
|
|
let self.continuous = l:continuous
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:compiler_nvim.kill() abort dict " {{{1
|
|
call jobstop(self.job)
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:compiler_nvim.is_running() abort dict " {{{1
|
|
try
|
|
let pid = jobpid(self.job)
|
|
return 1
|
|
catch
|
|
return 0
|
|
endtry
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:compiler_nvim.get_pid() abort dict " {{{1
|
|
try
|
|
return jobpid(self.job)
|
|
catch
|
|
return 0
|
|
endtry
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:callback_nvim_output(id, data, event) abort dict " {{{1
|
|
" Filter out unwanted newlines
|
|
let l:data = split(substitute(join(a:data, 'QQ'), '^QQ\|QQ$', '', ''), 'QQ')
|
|
|
|
if !empty(l:data) && filewritable(self.output)
|
|
call writefile(l:data, self.output, 'a')
|
|
endif
|
|
|
|
if match(a:data, 'vimtex_compiler_callback_success') != -1
|
|
call vimtex#compiler#callback(!vimtex#qf#inquire(self.target))
|
|
elseif match(a:data, 'vimtex_compiler_callback_failure') != -1
|
|
call vimtex#compiler#callback(0)
|
|
endif
|
|
|
|
try
|
|
for l:Hook in get(get(get(b:, 'vimtex', {}), 'compiler', {}), 'hooks', [])
|
|
call l:Hook(join(a:data, "\n"))
|
|
endfor
|
|
catch /E716/
|
|
endtry
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:callback_nvim_exit(id, data, event) abort dict " {{{1
|
|
let l:target = self.target !=# b:vimtex.tex ? self.target : ''
|
|
call vimtex#compiler#callback(!vimtex#qf#inquire(l:target))
|
|
endfunction
|
|
|
|
" }}}1
|
|
|
|
endif
|