1" Language: ConTeXt typesetting engine 2" Maintainer: Nicola Vitacolonna <[email protected]> 3" Latest Revision: 2016 Oct 21 4 5let s:keepcpo= &cpo 6set cpo&vim 7 8" Helper functions {{{ 9function! s:context_echo(message, mode) 10 redraw 11 echo "\r" 12 execute 'echohl' a:mode 13 echomsg '[ConTeXt]' a:message 14 echohl None 15endf 16 17function! s:sh() 18 return has('win32') || has('win64') || has('win16') || has('win95') 19 \ ? ['cmd.exe', '/C'] 20 \ : ['/bin/sh', '-c'] 21endfunction 22 23" For backward compatibility 24if exists('*win_getid') 25 26 function! s:win_getid() 27 return win_getid() 28 endf 29 30 function! s:win_id2win(winid) 31 return win_id2win(a:winid) 32 endf 33 34else 35 36 function! s:win_getid() 37 return winnr() 38 endf 39 40 function! s:win_id2win(winnr) 41 return a:winnr 42 endf 43 44endif 45" }}} 46 47" ConTeXt jobs {{{ 48if has('job') 49 50 let g:context_jobs = [] 51 52 " Print the status of ConTeXt jobs 53 function! context#job_status() 54 let l:jobs = filter(g:context_jobs, 'job_status(v:val) == "run"') 55 let l:n = len(l:jobs) 56 call s:context_echo( 57 \ 'There '.(l:n == 1 ? 'is' : 'are').' '.(l:n == 0 ? 'no' : l:n) 58 \ .' job'.(l:n == 1 ? '' : 's').' running' 59 \ .(l:n == 0 ? '.' : ' (' . join(l:jobs, ', ').').'), 60 \ 'ModeMsg') 61 endfunction 62 63 " Stop all ConTeXt jobs 64 function! context#stop_jobs() 65 let l:jobs = filter(g:context_jobs, 'job_status(v:val) == "run"') 66 for job in l:jobs 67 call job_stop(job) 68 endfor 69 sleep 1 70 let l:tmp = [] 71 for job in l:jobs 72 if job_status(job) == "run" 73 call add(l:tmp, job) 74 endif 75 endfor 76 let g:context_jobs = l:tmp 77 if empty(g:context_jobs) 78 call s:context_echo('Done. No jobs running.', 'ModeMsg') 79 else 80 call s:context_echo('There are still some jobs running. Please try again.', 'WarningMsg') 81 endif 82 endfunction 83 84 function! context#callback(path, job, status) 85 if index(g:context_jobs, a:job) != -1 && job_status(a:job) != 'run' " just in case 86 call remove(g:context_jobs, index(g:context_jobs, a:job)) 87 endif 88 call s:callback(a:path, a:job, a:status) 89 endfunction 90 91 function! context#close_cb(channel) 92 call job_status(ch_getjob(a:channel)) " Trigger exit_cb's callback for faster feedback 93 endfunction 94 95 function! s:typeset(path) 96 call add(g:context_jobs, 97 \ job_start(add(s:sh(), context#command() . ' ' . shellescape(fnamemodify(a:path, ":t"))), { 98 \ 'close_cb' : 'context#close_cb', 99 \ 'exit_cb' : function(get(b:, 'context_callback', get(g:, 'context_callback', 'context#callback')), 100 \ [a:path]), 101 \ 'in_io' : 'null' 102 \ })) 103 endfunction 104 105else " No jobs 106 107 function! context#job_status() 108 call s:context_echo('Not implemented', 'WarningMsg') 109 endfunction! 110 111 function! context#stop_jobs() 112 call s:context_echo('Not implemented', 'WarningMsg') 113 endfunction 114 115 function! context#callback(path, job, status) 116 call s:callback(a:path, a:job, a:status) 117 endfunction 118 119 function! s:typeset(path) 120 execute '!' . context#command() . ' ' . shellescape(fnamemodify(a:path, ":t")) 121 call call(get(b:, 'context_callback', get(g:, 'context_callback', 'context#callback')), 122 \ [a:path, 0, v:shell_error]) 123 endfunction 124 125endif " has('job') 126 127function! s:callback(path, job, status) abort 128 if a:status < 0 " Assume the job was terminated 129 return 130 endif 131 " Get info about the current window 132 let l:winid = s:win_getid() " Save window id 133 let l:efm = &l:errorformat " Save local errorformat 134 let l:cwd = fnamemodify(getcwd(), ":p") " Save local working directory 135 " Set errorformat to parse ConTeXt errors 136 execute 'setl efm=' . escape(b:context_errorformat, ' ') 137 try " Set cwd to expand error file correctly 138 execute 'lcd' fnameescape(fnamemodify(a:path, ':h')) 139 catch /.*/ 140 execute 'setl efm=' . escape(l:efm, ' ') 141 throw v:exception 142 endtry 143 try 144 execute 'cgetfile' fnameescape(fnamemodify(a:path, ':r') . '.log') 145 botright cwindow 146 finally " Restore cwd and errorformat 147 execute s:win_id2win(l:winid) . 'wincmd w' 148 execute 'lcd ' . fnameescape(l:cwd) 149 execute 'setl efm=' . escape(l:efm, ' ') 150 endtry 151 if a:status == 0 152 call s:context_echo('Success!', 'ModeMsg') 153 else 154 call s:context_echo('There are errors. ', 'ErrorMsg') 155 endif 156endfunction 157 158function! context#command() 159 return get(b:, 'context_mtxrun', get(g:, 'context_mtxrun', 'mtxrun')) 160 \ . ' --script context --autogenerate --nonstopmode' 161 \ . ' --synctex=' . (get(b:, 'context_synctex', get(g:, 'context_synctex', 0)) ? '1' : '0') 162 \ . ' ' . get(b:, 'context_extra_options', get(g:, 'context_extra_options', '')) 163endfunction 164 165" Accepts an optional path (useful for big projects, when the file you are 166" editing is not the project's root document). If no argument is given, uses 167" the path of the current buffer. 168function! context#typeset(...) abort 169 let l:path = fnamemodify(strlen(a:000[0]) > 0 ? a:1 : expand("%"), ":p") 170 let l:cwd = fnamemodify(getcwd(), ":p") " Save local working directory 171 call s:context_echo('Typesetting...', 'ModeMsg') 172 execute 'lcd' fnameescape(fnamemodify(l:path, ":h")) 173 try 174 call s:typeset(l:path) 175 finally " Restore local working directory 176 execute 'lcd ' . fnameescape(l:cwd) 177 endtry 178endfunction! 179"}}} 180 181let &cpo = s:keepcpo 182unlet s:keepcpo 183 184" vim: sw=2 fdm=marker 185