diff --git a/autoload/vimtex/compiler/_template.vim b/autoload/vimtex/compiler/_template.vim index 71a810285a..675ba0faed 100644 --- a/autoload/vimtex/compiler/_template.vim +++ b/autoload/vimtex/compiler/_template.vim @@ -88,7 +88,7 @@ function! s:compiler.__pprint() abort dict " {{{1 if self.continuous call add(l:job, ['pid', self.get_pid()]) endif - call add(l:list, ['process', l:job]) + call add(l:list, ['job', l:job]) endif return l:list @@ -105,7 +105,7 @@ function! s:compiler.clean(full) abort dict " {{{1 call map(l:files, {_, x -> printf('%s/%s.%s', \ self.build_dir, fnamemodify(self.state.tex, ':t:r:S'), x)}) - call vimtex#process#run('rm -f ' . join(l:files)) + call vimtex#jobs#run('rm -f ' . join(l:files), {'cwd': self.state.root}) endfunction " }}}1 @@ -152,18 +152,6 @@ function! s:compiler.stop() abort dict " {{{1 endif endfunction -" }}}1 -function! s:compiler.wait() abort dict " {{{1 - for l:dummy in range(50) - sleep 100m - if !self.is_running() - return - endif - endfor - - call self.stop() -endfunction - " }}}1 function! s:compiler.create_build_dir() abort dict " {{{1 @@ -221,6 +209,7 @@ function! s:compiler_jobs.exec(cmd) abort dict " {{{1 \ 'err_io' : 'file', \ 'out_name' : self.output, \ 'err_name' : self.output, + \ 'cwd': self.state.root, \} if self.continuous let l:options.out_io = 'pipe' @@ -232,14 +221,23 @@ function! s:compiler_jobs.exec(cmd) abort dict " {{{1 let l:options.exit_cb = function('s:callback') endif - call vimtex#paths#pushd(self.state.root) let self.job = job_start(a:cmd, l:options) - call vimtex#paths#popd() endfunction " }}}1 function! s:compiler_jobs.kill() abort dict " {{{1 call job_stop(self.job) + sleep 25m +endfunction + +" }}}1 +function! s:compiler_jobs.wait() abort dict " {{{1 + for l:dummy in range(500) + sleep 10m + if !self.is_running() | return | endif + endfor + + call self.stop() endfunction " }}}1 @@ -300,13 +298,23 @@ function! s:compiler_nvim.kill() abort dict " {{{1 call jobstop(self.job) endfunction +" }}}1 +function! s:compiler_nvim.wait() abort dict " {{{1 + let l:retvals = jobwait([self.job], 5000) + if empty(l:retvals) | return | endif + let l:status = l:retvals[0] + if l:status >= 0 | return | endif + + if l:status == -1 | call self.stop() | endif +endfunction + " }}}1 function! s:compiler_nvim.is_running() abort dict " {{{1 try let pid = jobpid(self.job) - return 1 + return l:pid > 0 catch - return 0 + return v:false endtry endfunction diff --git a/autoload/vimtex/compiler/latexmk.vim b/autoload/vimtex/compiler/latexmk.vim index dd160a903f..20569de979 100644 --- a/autoload/vimtex/compiler/latexmk.vim +++ b/autoload/vimtex/compiler/latexmk.vim @@ -191,16 +191,13 @@ endfunction " }}}1 function! s:compiler.clean(full) abort dict " {{{1 - let l:cmd = (has('win32') - \ ? 'cd /D "' . self.state.root . '" & ' - \ : 'cd ' . vimtex#util#shellescape(self.state.root) . '; ') - \ . self.executable . ' ' . (a:full ? '-C ' : '-c ') + let l:cmd = 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.state.base) - call vimtex#process#run(l:cmd) + call vimtex#jobs#run(l:cmd, {'cwd': self.state.root}) endfunction " }}}1 diff --git a/autoload/vimtex/compiler/latexrun.vim b/autoload/vimtex/compiler/latexrun.vim index e499e82bd4..c26bf2e72c 100644 --- a/autoload/vimtex/compiler/latexrun.vim +++ b/autoload/vimtex/compiler/latexrun.vim @@ -37,13 +37,9 @@ endfunction " }}}1 function! s:compiler.clean(...) abort dict " {{{1 - let l:cmd = (has('win32') - \ ? 'cd /D "' . self.state.root . '" & ' - \ : 'cd ' . vimtex#util#shellescape(self.state.root) . '; ') - \ . 'latexrun --clean-all' - \ . ' -O ' - \ . (empty(self.build_dir) ? '.' : fnameescape(self.build_dir)) - call vimtex#process#run(l:cmd) + let l:cmd = printf('latexrun --clean-all -O %s', + \ empty(self.build_dir) ? '.' : fnameescape(self.build_dir)) + call vimtex#jobs#run(l:cmd, {'cwd': self.state.root}) endfunction " }}}1 diff --git a/autoload/vimtex/context/cite.vim b/autoload/vimtex/context/cite.vim index 62c60e93e7..a28b1f9a0c 100644 --- a/autoload/vimtex/context/cite.vim +++ b/autoload/vimtex/context/cite.vim @@ -168,7 +168,7 @@ function! s:actions.open_pdf() abort dict " {{{1 \}) if empty(l:file) | return | endif - call vimtex#process#start( + call vimtex#jobs#start( \ g:vimtex_context_pdf_viewer \ . ' ' . vimtex#util#shellescape(l:file)) endfunction diff --git a/autoload/vimtex/info.vim b/autoload/vimtex/info.vim index bdca5f4584..1d513dee51 100644 --- a/autoload/vimtex/info.vim +++ b/autoload/vimtex/info.vim @@ -192,7 +192,7 @@ function! s:get_os_info() abort " {{{1 return l:name . ' ' . l:version . ' (' . l:build . ')' else if !exists('s:win_info') - let s:win_info = vimtex#process#capture('systeminfo') + let s:win_info = vimtex#jobs#capture('systeminfo') endif try diff --git a/autoload/vimtex/jobs.vim b/autoload/vimtex/jobs.vim new file mode 100644 index 0000000000..1407616411 --- /dev/null +++ b/autoload/vimtex/jobs.vim @@ -0,0 +1,214 @@ +" VimTeX - LaTeX plugin for Vim +" +" Maintainer: Karl Yngve Lervåg +" Email: karl.yngve@gmail.com +" + +function! vimtex#jobs#start(cmd, ...) abort " {{{1 + let l:opts = a:0 > 0 ? a:1 : {} + return s:job.start(a:cmd, l:opts) +endfunction + +" }}}1 +function! vimtex#jobs#run(cmd, ...) abort " {{{1 + let l:opts = a:0 > 0 ? a:1 : {} + let l:job = s:job.start(a:cmd, l:opts) + call l:job.wait() +endfunction + +" }}}1 +function! vimtex#jobs#capture(cmd, ...) abort " {{{1 + let l:opts = a:0 > 0 ? a:1 : {} + let l:opts.collect_output = v:true + let l:job = s:job.start(a:cmd, l:opts) + return l:job.output() +endfunction + +" }}}1 + + +let s:job = {} + +function! s:job.start(cmd, opts) abort dict " {{{1 + let l:job = deepcopy(self) + unlet l:job.start + + let l:job.cmd_raw = a:cmd + let l:job.cwd = get(a:opts, 'cwd', + \ exists('b:vimtex.root') ? b:vimtex.root : '') + let l:job.wait_timeout = str2nr(get(a:opts, 'wait_timeout', 5000)) + let l:job.collect_output = get(a:opts, 'collect_output', v:false) + + let l:job.cmd = has('win32') + \ ? 'cmd /s /c "' . l:job.cmd_raw . '"' + \ : ['sh', '-c', l:job.cmd_raw] + + call l:job.exec() + + return l:job +endfunction + +" }}}1 + +function! s:job.__pprint() abort dict " {{{1 + let l:pid = self.get_pid() + + return [ + \ ['pid', l:pid ? l:pid : '-'], + \ ['cmd', self.cmd_raw], + \] +endfunction + +" }}}1 + +if has('nvim') + function! s:job.exec() abort dict " {{{1 + let l:options = {} + + if self.collect_output + let self._output = [] + let l:options.on_stdout = function('s:__callback') + let l:options.on_stderr = function('s:__callback') + let l:options.stdout_buffered = v:true + let l:options.stderr_buffered = v:true + let l:options.output = self._output + endif + if !empty(self.cwd) + let l:options.cwd = self.cwd + endif + + let self.job = jobstart(self.cmd, l:options) + endfunction + + function! s:__callback(id, data, event) abort dict + call extend(self.output, a:data) + endfunction + + " }}}1 + function! s:job.stop() abort dict " {{{1 + call jobstop(self.job) + endfunction + + " }}}1 +function! s:job.wait() abort dict " {{{1 + let l:retvals = jobwait([self.job], self.wait_timeout) + if empty(l:retvals) | return | endif + let l:status = l:retvals[0] + if l:status >= 0 | return | endif + + if l:status == -1 + call vimtex#log#warning('Job timed out while waiting!', join(self.cmd)) + call self.stop() + elseif l:status == -2 + call vimtex#log#warning('Job interrupted!', self.cmd) + endif +endfunction + +" }}}1 +function! s:job.is_running() abort dict " {{{1 + try + let l:pid = jobpid(self.job) + return l:pid > 0 + catch + return v:false + endtry +endfunction + +" }}}1 + function! s:job.get_pid() abort dict " {{{1 + if !has_key(self, 'pid') + try + let self.pid = jobpid(self.job) + catch + let self.pid = 0 + endtry + endif + + return self.pid + endfunction + + " }}}1 + function! s:job.output() abort dict " {{{1 + call self.wait() + + if !self.collect_output | return [] | endif + + " Trim output + while len(self._output) > 0 + if !empty(self._output[0]) | break | endif + call remove(self._output, 0) + endwhile + while len(self._output) > 0 + if !empty(self._output[-1]) | break | endif + call remove(self._output, -1) + endwhile + + return self._output + endfunction + + " }}}1 +else + function! s:job.exec() abort dict " {{{1 + let l:options = {} + + if self.collect_output + let self._output = tempname() + let l:options.out_io = 'file' + let l:options.err_io = 'file' + let l:options.out_name = self._output + let l:options.err_name = self._output + else + let l:options.in_io = 'null' + let l:options.out_io = 'null' + let l:options.err_io = 'null' + endif + if !empty(self.cwd) + let l:options.cwd = self.cwd + endif + + let self.job = job_start(self.cmd, l:options) + endfunction + + " }}}1 + function! s:job.stop() abort dict " {{{1 + call job_stop(self.job) + sleep 25m + endfunction + + " }}}1 +function! s:job.wait() abort dict " {{{1 + for l:dummy in range(self.wait_timeout/10) + sleep 10m + if !self.is_running() | return | endif + endfor + + call vimtex#log#warning('Job timed out while waiting!', join(self.cmd)) + call self.stop() +endfunction + +" }}}1 +function! s:job.is_running() abort dict " {{{1 + return job_status(self.job) ==# 'run' +endfunction + +" }}}1 + function! s:job.get_pid() abort dict " {{{1 + if !has_key(self, 'pid') + try + return get(job_info(self.job), 'process') + catch + return 0 + endtry + endif + + return self.pid + endfunction + + " }}}1 + function! s:job.output() abort dict " {{{1 + call self.wait() + return self.collect_output ? readfile(self._output) : [] + endfunction + + " }}}1 +endif diff --git a/autoload/vimtex/kpsewhich.vim b/autoload/vimtex/kpsewhich.vim index 70fb1b43c4..e66666b566 100644 --- a/autoload/vimtex/kpsewhich.vim +++ b/autoload/vimtex/kpsewhich.vim @@ -49,7 +49,7 @@ function! vimtex#kpsewhich#run(args) abort " {{{1 if exists('b:vimtex.root') call vimtex#paths#pushd(b:vimtex.root) endif - let l:output = vimtex#process#capture('kpsewhich ' . a:args) + let l:output = vimtex#jobs#capture('kpsewhich ' . a:args) if exists('b:vimtex.root') call vimtex#paths#popd() endif diff --git a/autoload/vimtex/misc.vim b/autoload/vimtex/misc.vim index 9dd3873049..390efe3aa9 100644 --- a/autoload/vimtex/misc.vim +++ b/autoload/vimtex/misc.vim @@ -48,24 +48,22 @@ function! vimtex#misc#wordcount(...) abort " {{{1 let l:file = vimtex#parser#selection_to_texfile({'range': l:range}) endif - let cmd = 'cd ' . vimtex#util#shellescape(l:file.root) - let cmd .= has('win32') ? '& ' : '; ' - let cmd .= 'texcount -nosub -sum ' - let cmd .= get(l:opts, 'count_letters') ? '-letter ' : '' - let cmd .= get(l:opts, 'detailed') ? '-inc ' : '-q -1 -merge ' - let cmd .= g:vimtex_texcount_custom_arg . ' ' - let cmd .= vimtex#util#shellescape(l:file.base) - let lines = vimtex#process#capture(cmd) + let l:lines = vimtex#jobs#capture('texcount -nosub -sum ' + \ . (get(l:opts, 'count_letters') ? '-letter ' : '') + \ . (get(l:opts, 'detailed') ? '-inc ' : '-q -1 -merge ') + \ . g:vimtex_texcount_custom_arg . ' ' + \ . vimtex#util#shellescape(l:file.base), + \ {'cwd': l:file.root}) if l:file.base !=# b:vimtex.base call delete(l:file.tex) endif if get(l:opts, 'detailed') - return lines + return l:lines else - call filter(lines, 'v:val !~# ''ERROR\|^\s*$''') - return join(lines, '') + call filter(l:lines, 'v:val !~# ''ERROR\|^\s*$''') + return join(l:lines, '') endif endfunction diff --git a/autoload/vimtex/parser/bib.vim b/autoload/vimtex/parser/bib.vim index 625e5b3134..ce83e1cd9c 100644 --- a/autoload/vimtex/parser/bib.vim +++ b/autoload/vimtex/parser/bib.vim @@ -112,9 +112,7 @@ function! s:parse_with_bibtex(file) abort " {{{1 \ ], tmp.aux) " Create the temporary bbl file - call vimtex#process#run( - \ 'bibtex -terse ' . fnameescape(tmp.aux), - \ {'background' : 0}) + call vimtex#jobs#run('bibtex -terse ' . fnameescape(tmp.aux)) " Parse temporary bbl file let lines = join(readfile(tmp.bbl), "\n") @@ -182,11 +180,7 @@ function! s:parse_with_bibparse(file) abort " {{{1 call s:parse_with_bibparse_init() if s:bibparse_not_executable | return [] | endif - call vimtex#process#run( - \ 'bibparse ' . fnameescape(a:file) . ' >_vimtex_bibparsed.log', - \ {'background' : 0}) - let l:lines = readfile('_vimtex_bibparsed.log') - call delete('_vimtex_bibparsed.log') + let l:lines = vimtex#jobs#capture('bibparse ' . fnameescape(a:file)) let l:current = {} let l:entries = [] diff --git a/autoload/vimtex/process.vim b/autoload/vimtex/process.vim deleted file mode 100644 index aade8b8d74..0000000000 --- a/autoload/vimtex/process.vim +++ /dev/null @@ -1,224 +0,0 @@ -" VimTeX - LaTeX plugin for Vim -" -" Maintainer: Karl Yngve Lervåg -" Email: karl.yngve@gmail.com -" - -function! vimtex#process#new(...) abort " {{{1 - let l:opts = a:0 > 0 ? a:1 : {} - return extend(deepcopy(s:process), l:opts) -endfunction - -" }}}1 -function! vimtex#process#run(cmd, ...) abort " {{{1 - let l:opts = a:0 > 0 ? a:1 : {} - let l:opts.cmd = a:cmd - let l:process = vimtex#process#new(l:opts) - - return l:process.run() -endfunction - -" }}}1 -function! vimtex#process#capture(cmd) abort " {{{1 - return vimtex#process#run(a:cmd, {'capture': 1}) -endfunction - -" }}}1 -function! vimtex#process#start(cmd, ...) abort " {{{1 - let l:opts = a:0 > 0 ? a:1 : {} - let l:opts.continuous = 1 - return vimtex#process#run(a:cmd, l:opts) -endfunction - -" }}}1 - -let s:process = { - \ 'cmd' : '', - \ 'pid' : 0, - \ 'background' : 1, - \ 'continuous' : 0, - \ 'output' : '', - \ 'workdir' : '', - \ 'silent' : 1, - \ 'capture' : 0, - \ 'result' : '', - \} - -function! s:process.__pprint() abort dict " {{{1 - return [ - \ ['pid', self.pid ? self.pid : '-'], - \ ['cmd', get(self, 'prepared_cmd', self.cmd)], - \] -endfunction - -" }}}1 - -function! s:process.run() abort dict " {{{1 - if self._do_not_run() | return | endif - - call self._pre_run() - call self._prepare() - call self._execute() - call self._restore() - call self._post_run() - - return self.capture ? self.result : self -endfunction - -" }}}1 -function! s:process.stop() abort dict " {{{1 - if !self.pid | return | endif - - let l:cmd = has('win32') - \ ? 'taskkill /PID ' . self.pid . ' /T /F' - \ : 'kill ' . self.pid - call vimtex#process#run(l:cmd, {'background': 0}) - - let self.pid = 0 -endfunction - -" }}}1 - -function! s:process._do_not_run() abort dict " {{{1 - if empty(self.cmd) - call vimtex#log#warning('Can''t run empty command') - return 1 - endif - if self.pid - call vimtex#log#warning('Process already running!') - return 1 - endif - - return 0 -endfunction - -" }}}1 -function! s:process._pre_run() abort dict " {{{1 - if self.capture - let self.silent = 0 - let self.background = 0 - elseif empty(self.output) && self.background - let self.output = 'null' - endif - - call vimtex#paths#pushd(self.workdir) -endfunction - -" }}}1 -function! s:process._execute() abort dict " {{{1 - if self.capture - let self.result = split(system(self.prepared_cmd), '\n') - elseif self.silent - silent call system(self.prepared_cmd) - elseif self.background - silent execute '!' . self.prepared_cmd - if !has('gui_running') - redraw! - endif - else - execute '!' . self.prepared_cmd - endif - - " Capture the pid if relevant - if has_key(self, 'set_pid') && self.continuous - call self.set_pid() - endif -endfunction - -" }}}1 -function! s:process._post_run() abort dict " {{{1 - call vimtex#paths#popd() -endfunction - -" }}}1 - -if has('win32') - function! s:process._prepare() abort dict " {{{1 - if &shell !~? 'cmd' - let self.win32_restore_shell = 1 - let self.win32_saved_shell = [ - \ &shell, - \ &shellcmdflag, - \ &shellxquote, - \ &shellxescape, - \ &shellquote, - \ &shellpipe, - \ &shellredir, - \ &shellslash - \] - set shell& shellcmdflag& shellxquote& shellxescape& - set shellquote& shellpipe& shellredir& shellslash& - else - let self.win32_restore_shell = 0 - endif - - let l:cmd = self.cmd - - if self.background - if !empty(self.output) - let l:cmd .= self.output ==# 'null' - \ ? ' >nul' - \ : ' >' . self.output - let l:cmd = 'cmd /s /c "' . l:cmd . '"' - else - let l:cmd = 'cmd /c "' . l:cmd . '"' - endif - let l:cmd = 'start /b ' . cmd - endif - - let self.prepared_cmd = l:cmd - endfunction - - " }}}1 - function! s:process._restore() abort dict " {{{1 - if self.win32_restore_shell - let [ &shell, - \ &shellcmdflag, - \ &shellxquote, - \ &shellxescape, - \ &shellquote, - \ &shellpipe, - \ &shellredir, - \ &shellslash] = self.win32_saved_shell - endif - endfunction - - " }}}1 - function! s:process.get_pid() abort dict " {{{1 - let self.pid = 0 - endfunction - - " }}}1 -else - function! s:process._prepare() abort dict " {{{1 - let l:cmd = self.cmd - - if self.background - if !empty(self.output) - let l:cmd .= ' >' - \ . (self.output ==# 'null' - \ ? '/dev/null' - \ : shellescape(self.output)) - \ . ' 2>&1' - endif - let l:cmd .= ' &' - endif - - if !self.silent - let l:cmd = escape(l:cmd, '%#') - endif - - let self.prepared_cmd = l:cmd - endfunction - - " }}}1 - function! s:process._restore() abort dict " {{{1 - endfunction - - " }}}1 - function! s:process.get_pid() abort dict " {{{1 - let self.pid = 0 - endfunction - - " }}}1 -endif diff --git a/autoload/vimtex/qf/pplatex.vim b/autoload/vimtex/qf/pplatex.vim index b4730701ae..38a72ee5fb 100644 --- a/autoload/vimtex/qf/pplatex.vim +++ b/autoload/vimtex/qf/pplatex.vim @@ -85,9 +85,10 @@ function! s:qf.addqflist(tex, log) abort dict " {{{1 endif let l:tmp = fnamemodify(a:log, ':r') . '.pplatex' - silent call system(printf('pplatex -i "%s" >"%s"', a:log, l:tmp)) + + call system(printf('pplatex -i "%s" >"%s"', a:log, l:tmp)) call vimtex#qf#u#caddfile(self, l:tmp) - silent call delete(l:tmp) + call delete(l:tmp) endfunction " }}}1 diff --git a/autoload/vimtex/qf/pulp.vim b/autoload/vimtex/qf/pulp.vim index 8da2f671c7..7716be8bdd 100644 --- a/autoload/vimtex/qf/pulp.vim +++ b/autoload/vimtex/qf/pulp.vim @@ -49,12 +49,12 @@ function! s:qf.addqflist(tex, log) abort dict " {{{1 throw 'VimTeX: No log file found' endif - let l:tmp = fnameescape(fnamemodify(a:log, ':r') . '.pulp') + let l:tmp = fnamemodify(a:log, ':r') . '.pulp' let l:log = fnameescape(a:log) - silent call system(printf('pulp %s >%s', l:log, l:tmp)) + call system(printf('pulp %s >%s', l:log, fnameescape(l:tmp))) call vimtex#qf#u#caddfile(self, l:tmp) - silent call system('rm ' . l:tmp) + call delete(l:tmp) endfunction " }}}1 diff --git a/autoload/vimtex/test.vim b/autoload/vimtex/test.vim index 4eaae3a6da..2d9cd211bb 100644 --- a/autoload/vimtex/test.vim +++ b/autoload/vimtex/test.vim @@ -57,7 +57,7 @@ function! vimtex#test#completion(context, ...) abort " {{{1 catch call assert_report( \ printf("\n Context: %s\n Base: %s\n%s", - \ a:context, l:Base, v:exception)) + \ a:context, l:base, v:exception)) endtry endfunction diff --git a/autoload/vimtex/view.vim b/autoload/vimtex/view.vim index 9eec5889ac..f3fe495cf1 100644 --- a/autoload/vimtex/view.vim +++ b/autoload/vimtex/view.vim @@ -133,12 +133,12 @@ function! s:focus_vim() abort " {{{1 let l:pids = l:pids[: index(l:pids, string(l:current_pid))] for l:pid in reverse(l:pids) - let l:xwinids = filter(reverse(split(system( - \ 'xdotool search --onlyvisible --pid ' . l:pid))), - \ '!empty(v:val)') + let l:xwinids = filter(reverse( + \ systemlist('xdotool search --onlyvisible --pid ' . l:pid)), + \ '!empty(v:val)') if !empty(l:xwinids) - silent call system('xdotool windowactivate ' . l:xwinids[0] . ' &') + call system('xdotool windowactivate ' . l:xwinids[0] . ' &') call feedkeys("\", 'tn') return l:xwinids[0] break diff --git a/autoload/vimtex/view/_template.vim b/autoload/vimtex/view/_template.vim index e60eeb46e4..4e281994ad 100644 --- a/autoload/vimtex/view/_template.vim +++ b/autoload/vimtex/view/_template.vim @@ -20,8 +20,8 @@ function! s:template.__pprint() abort dict " {{{1 call add(l:list, ['xwin id', self.xwin_id]) endif - if has_key(self, 'process') - call add(l:list, ['process', self.process]) + if has_key(self, 'job') + call add(l:list, ['job', self.job]) endif for l:key in filter(keys(self), 'v:val =~# ''^cmd_''') diff --git a/autoload/vimtex/view/_template_xwin.vim b/autoload/vimtex/view/_template_xwin.vim index 1102efeb10..13bc245d2a 100644 --- a/autoload/vimtex/view/_template_xwin.vim +++ b/autoload/vimtex/view/_template_xwin.vim @@ -87,7 +87,7 @@ function! s:template.xwin_get_id() dict abort " {{{1 " Get the window ID " let cmd = 'xdotool search --class ' . self.name - let xwin_ids = split(system(cmd), '\n') + let xwin_ids = systemlist(cmd) if len(xwin_ids) == 0 call vimtex#log#warning('Viewer cannot find ' . self.name . ' window ID!') let self.xwin_id = 0 @@ -107,7 +107,7 @@ function! s:template.xwin_exists() dict abort " {{{1 " if self.xwin_id > 0 let cmd = 'xdotool search --class ' . self.name - if index(split(system(cmd), '\n'), self.xwin_id) < 0 + if index(systemlist(cmd), self.xwin_id) < 0 let self.xwin_id = 0 endif endif @@ -121,10 +121,10 @@ function! s:template.xwin_exists() dict abort " {{{1 let cmd = 'xdotool search' \ . ' --all --pid ' . l:pid \ . ' --name ' . fnamemodify(self.out(), ':t') - let self.xwin_id = get(split(system(cmd), '\n'), 0) + let self.xwin_id = get(systemlist(cmd), 0) else let cmd = 'xdotool search --name ' . fnamemodify(self.out(), ':t') - let ids = split(system(cmd), '\n') + let ids = systemlist(cmd) let ids_already_used = filter(map( \ deepcopy(vimtex#state#list_all()), \ {_, x -> get(get(x, 'viewer', {}), 'xwin_id')}), @@ -147,9 +147,7 @@ function! s:template.xwin_send_keys(keys) dict abort " {{{1 return endif - let cmd = 'xdotool key --window ' . self.xwin_id - let cmd .= ' ' . a:keys - silent call system(cmd) + call system('xdotool key --window ' . self.xwin_id . ' ' . a:keys) endfunction " }}}1 @@ -158,8 +156,7 @@ function! s:template.move(arg) abort " {{{1 return endif - let l:cmd = 'xdotool windowmove ' . self.xwin_get_id() . ' ' . a:arg - silent call system(l:cmd) + call system('xdotool windowmove ' . self.xwin_get_id() . ' ' . a:arg) endfunction " }}}1 @@ -168,8 +165,7 @@ function! s:template.resize(arg) abort " {{{1 return endif - let l:cmd = 'xdotool windowsize ' . self.xwin_get_id() . ' ' . a:arg - silent call system(l:cmd) + call system('xdotool windowsize ' . self.xwin_get_id() . ' ' . a:arg) endfunction " }}}1 @@ -177,8 +173,8 @@ function! s:template.focus_viewer() dict abort " {{{1 if !executable('xdotool') | return | endif if self.xwin_id > 0 - silent call system('xdotool windowactivate ' . self.xwin_id . ' --sync') - silent call system('xdotool windowraise ' . self.xwin_id) + call system('xdotool windowactivate ' . self.xwin_id . ' --sync') + call system('xdotool windowraise ' . self.xwin_id) endif endfunction @@ -186,8 +182,8 @@ endfunction function! s:template.focus_vim() dict abort " {{{1 if !executable('xdotool') | return | endif - silent call system('xdotool windowactivate ' . v:windowid . ' --sync') - silent call system('xdotool windowraise ' . v:windowid) + call system('xdotool windowactivate ' . v:windowid . ' --sync') + call system('xdotool windowraise ' . v:windowid) endfunction " }}}1 diff --git a/autoload/vimtex/view/general.vim b/autoload/vimtex/view/general.vim index 09ece188a0..d818541ea0 100644 --- a/autoload/vimtex/view/general.vim +++ b/autoload/vimtex/view/general.vim @@ -45,13 +45,13 @@ function! s:general.view(file) dict abort " {{{1 " Update the path for Windows on cygwin if executable('cygpath') let outfile = join( - \ vimtex#process#capture('cygpath -aw "' . outfile . '"'), '') + \ vimtex#jobs#capture('cygpath -aw "' . outfile . '"'), '') endif if vimtex#view#not_readable(outfile) | return | endif " Parse options - let l:cmd = g:vimtex_view_general_viewer + let l:cmd = g:vimtex_view_general_viewer let l:cmd .= ' ' . g:vimtex_view_general_options " Substitute magic patterns @@ -62,7 +62,7 @@ function! s:general.view(file) dict abort " {{{1 let l:cmd = substitute(l:cmd, '@pdf', vimtex#util#shellescape(outfile), 'g') " Start the view process - let self.process = vimtex#process#start(l:cmd, {'silent': 0}) + let self.job = vimtex#jobs#start(l:cmd) if exists('#User#VimtexEventView') doautocmd User VimtexEventView diff --git a/autoload/vimtex/view/mupdf.vim b/autoload/vimtex/view/mupdf.vim index 94e76669a4..c71d08621c 100644 --- a/autoload/vimtex/view/mupdf.vim +++ b/autoload/vimtex/view/mupdf.vim @@ -24,9 +24,9 @@ let s:mupdf = { \} function! s:mupdf.start(outfile) dict abort " {{{1 - let l:cmd = 'mupdf ' . g:vimtex_view_mupdf_options - \ . ' ' . vimtex#util#shellescape(a:outfile) - let self.process = vimtex#process#start(l:cmd) + let self.job = vimtex#jobs#start('mupdf ' + \ . g:vimtex_view_mupdf_options + \ . ' ' . vimtex#util#shellescape(a:outfile)) call self.xwin_get_id() call self.xwin_send_keys(g:vimtex_view_mupdf_send_keys) @@ -50,11 +50,10 @@ function! s:mupdf.forward_search(outfile) dict abort " {{{1 let self.page = system(self.cmd_synctex_view) if self.page > 0 - let l:cmd = 'xdotool' + let self.cmd_forward_search = 'xdotool' \ . ' type --window ' . self.xwin_id \ . ' "' . self.page . 'g"' - call vimtex#process#run(l:cmd) - let self.cmd_forward_search = l:cmd + call vimtex#jobs#run(self.cmd_forward_search) endif call self.focus_viewer() diff --git a/autoload/vimtex/view/skim.vim b/autoload/vimtex/view/skim.vim index e951790921..ee13f5a112 100644 --- a/autoload/vimtex/view/skim.vim +++ b/autoload/vimtex/view/skim.vim @@ -34,7 +34,7 @@ function! vimtex#view#skim#compiler_callback() abort " {{{1 \ '-e ''end tell''', \]) - let b:vimtex.viewer.process = vimtex#process#start(l:cmd) + let b:vimtex.viewer.job = vimtex#jobs#start(l:cmd) endfunction " }}}1 @@ -98,7 +98,7 @@ function! s:skim.view(file) dict abort " {{{1 \ '-e ''end tell''', \]) - let self.process = vimtex#process#start(l:cmd) + let self.job = vimtex#jobs#start(l:cmd) if exists('#User#VimtexEventView') doautocmd User VimtexEventView diff --git a/autoload/vimtex/view/zathura.vim b/autoload/vimtex/view/zathura.vim index 78fc8d85c2..0fcb0691b4 100644 --- a/autoload/vimtex/view/zathura.vim +++ b/autoload/vimtex/view/zathura.vim @@ -12,7 +12,7 @@ function! vimtex#view#zathura#new() abort " {{{1 endif if g:vimtex_view_zathura_check_libsynctex && executable('ldd') - let l:shared = split(system("sh -c 'ldd $(which zathura)'")) + let l:shared = systemlist("sh -c 'ldd $(which zathura)'") if v:shell_error == 0 \ && empty(filter(l:shared, 'v:val =~# ''libsynctex''')) call vimtex#log#warning('Zathura is not linked to libsynctex!') @@ -48,7 +48,7 @@ function! s:zathura.start(outfile) dict abort " {{{1 endif let l:cmd .= ' ' . g:vimtex_view_zathura_options let l:cmd .= ' ' . vimtex#util#shellescape(a:outfile) - let self.process = vimtex#process#start(l:cmd) + let self.job = vimtex#jobs#start(l:cmd) call self.xwin_get_id() let self.outfile = a:outfile @@ -62,13 +62,12 @@ function! s:zathura.forward_search(outfile) dict abort " {{{1 let self.texfile = vimtex#paths#relative(expand('%:p'), b:vimtex.root) let self.outfile = vimtex#paths#relative(a:outfile, getcwd()) - let l:cmd = 'zathura --synctex-forward ' - let l:cmd .= line('.') - let l:cmd .= ':' . col('.') - let l:cmd .= ':' . vimtex#util#shellescape(self.texfile) - let l:cmd .= ' ' . vimtex#util#shellescape(self.outfile) - call vimtex#process#run(l:cmd) - let self.cmd_forward_search = l:cmd + let self.cmd_forward_search = printf( + \ 'zathura --synctex-forward %d:%d:%s %s', + \ line('.'), col('.'), + \ vimtex#util#shellescape(self.texfile), + \ vimtex#util#shellescape(self.outfile)) + call vimtex#jobs#run(self.cmd_forward_search) endfunction " }}}1 diff --git a/test/test-jobs/Makefile b/test/test-jobs/Makefile new file mode 100644 index 0000000000..43954ee363 --- /dev/null +++ b/test/test-jobs/Makefile @@ -0,0 +1,14 @@ +MYVIM ?= nvim --headless + +INMAKE := 1 +export INMAKE + +TESTS := $(wildcard test-*.vim) +TESTS := $(TESTS:.vim=) + +.PHONY: test $(TESTS) + +test: $(TESTS) + +$(TESTS): + @$(MYVIM) -u $@.vim diff --git a/test/test-jobs/test-basic.vim b/test/test-jobs/test-basic.vim new file mode 100644 index 0000000000..5932d25bb6 --- /dev/null +++ b/test/test-jobs/test-basic.vim @@ -0,0 +1,29 @@ +set nocompatible +let &rtp = '../..,' . &rtp +filetype plugin on + +nnoremap q :qall! + +if vimtex#util#get_os() ==# 'win' | quitall | endif +call vimtex#log#set_silent() + + +let s:output = vimtex#jobs#capture("echo 'a\nb'") +call assert_equal(['a', 'b'], s:output) + +call vimtex#jobs#run('sleep 0.2', {'wait_timeout': 150}) +let s:log = vimtex#log#get() +call assert_equal(1, len(s:log)) +call assert_equal('Job timed out while waiting!', s:log[0].msg[0]) + +let s:job = vimtex#jobs#start('sleep 100') +call assert_true(s:job.is_running()) +call s:job.stop() +call assert_false(s:job.is_running()) +call s:job.stop() + +let s:output = vimtex#jobs#capture("echobaad foobar") +call assert_match('not found', s:output[0]) + + +call vimtex#test#finished()