blob: 254d710c01abecb9566d041c5452b51743d9c660 [file] [log] [blame]
Bram Moolenaar46fceaa2016-10-23 21:21:08 +02001" Language: ConTeXt typesetting engine
2" Maintainer: Nicola Vitacolonna <nvitacolonna@gmail.com>
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