|
| 1 | +" Language: ConTeXt typesetting engine |
| 2 | +" Maintainer: Nicola Vitacolonna <[email protected]> |
| 3 | +" Latest Revision: 2016 Oct 21 |
| 4 | + |
| 5 | +let s:keepcpo= &cpo |
| 6 | +set cpo&vim |
| 7 | + |
| 8 | +" Helper functions {{{ |
| 9 | +function! s:context_echo(message, mode) |
| 10 | + redraw |
| 11 | + echo "\r" |
| 12 | + execute 'echohl' a:mode |
| 13 | + echomsg '[ConTeXt]' a:message |
| 14 | + echohl None |
| 15 | +endf |
| 16 | + |
| 17 | +function! s:sh() |
| 18 | + return has('win32') || has('win64') || has('win16') || has('win95') |
| 19 | + \ ? ['cmd.exe', '/C'] |
| 20 | + \ : ['/bin/sh', '-c'] |
| 21 | +endfunction |
| 22 | + |
| 23 | +" For backward compatibility |
| 24 | +if 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 | + |
| 34 | +else |
| 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 | + |
| 44 | +endif |
| 45 | +" }}} |
| 46 | + |
| 47 | +" ConTeXt jobs {{{ |
| 48 | +if 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 | + |
| 105 | +else " 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 | + |
| 125 | +endif " has('job') |
| 126 | + |
| 127 | +function! 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 |
| 156 | +endfunction |
| 157 | + |
| 158 | +function! 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', '')) |
| 163 | +endfunction |
| 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. |
| 168 | +function! 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 |
| 178 | +endfunction! |
| 179 | +"}}} |
| 180 | + |
| 181 | +let &cpo = s:keepcpo |
| 182 | +unlet s:keepcpo |
| 183 | + |
| 184 | +" vim: sw=2 fdm=marker |
0 commit comments