summaryrefslogtreecommitdiffstats
path: root/runtime/autoload/context.vim
blob: 254d710c01abecb9566d041c5452b51743d9c660 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
" Language:           ConTeXt typesetting engine
" Maintainer:         Nicola Vitacolonna <nvitacolonna@gmail.com>
" Latest Revision:    2016 Oct 21

let s:keepcpo= &cpo
set cpo&vim

" Helper functions {{{
function! s:context_echo(message, mode)
  redraw
  echo "\r"
  execute 'echohl' a:mode
  echomsg '[ConTeXt]' a:message
  echohl None
endf

function! s:sh()
  return has('win32') || has('win64') || has('win16') || has('win95')
        \ ? ['cmd.exe', '/C']
        \ : ['/bin/sh', '-c']
endfunction

" For backward compatibility
if exists('*win_getid')

  function! s:win_getid()
    return win_getid()
  endf

  function! s:win_id2win(winid)
    return win_id2win(a:winid)
  endf

else

  function! s:win_getid()
    return winnr()
  endf

  function! s:win_id2win(winnr)
    return a:winnr
  endf

endif
" }}}

" ConTeXt jobs {{{
if has('job')

  let g:context_jobs = []

  " Print the status of ConTeXt jobs
  function! context#job_status()
    let l:jobs = filter(g:context_jobs, 'job_status(v:val) == "run"')
    let l:n = len(l:jobs)
    call s:context_echo(
          \ 'There '.(l:n == 1 ? 'is' : 'are').' '.(l:n == 0 ? 'no' : l:n)
          \ .' job'.(l:n == 1 ? '' : 's').' running'
          \ .(l:n == 0 ? '.' : ' (' . join(l:jobs, ', ').').'),
          \ 'ModeMsg')
  endfunction

  " Stop all ConTeXt jobs
  function! context#stop_jobs()
    let l:jobs = filter(g:context_jobs, 'job_status(v:val) == "run"')
    for job in l:jobs
      call job_stop(job)
    endfor
    sleep 1
    let l:tmp = []
    for job in l:jobs
      if job_status(job) == "run"
        call add(l:tmp, job)
      endif
    endfor
    let g:context_jobs = l:tmp
    if empty(g:context_jobs)
      call s:context_echo('Done. No jobs running.', 'ModeMsg')
    else
      call s:context_echo('There are still some jobs running. Please try again.', 'WarningMsg')
    endif
  endfunction

  function! context#callback(path, job, status)
    if index(g:context_jobs, a:job) != -1 && job_status(a:job) != 'run' " just in case
      call remove(g:context_jobs, index(g:context_jobs, a:job))
    endif
    call s:callback(a:path, a:job, a:status)
  endfunction

  function! context#close_cb(channel)
    call job_status(ch_getjob(a:channel)) " Trigger exit_cb's callback for faster feedback
  endfunction

  function! s:typeset(path)
    call add(g:context_jobs,
          \ job_start(add(s:sh(), context#command() . ' ' . shellescape(fnamemodify(a:path, ":t"))), {
          \   'close_cb' : 'context#close_cb',
          \   'exit_cb'  : function(get(b:, 'context_callback', get(g:, 'context_callback', 'context#callback')),
          \                         [a:path]),
          \   'in_io'    : 'null'
          \ }))
  endfunction

else " No jobs

  function! context#job_status()
    call s:context_echo('Not implemented', 'WarningMsg')
  endfunction!

  function! context#stop_jobs()
    call s:context_echo('Not implemented', 'WarningMsg')
  endfunction

  function! context#callback(path, job, status)
    call s:callback(a:path, a:job, a:status)
  endfunction

  function! s:typeset(path)
    execute '!' . context#command() . ' ' . shellescape(fnamemodify(a:path, ":t"))
    call call(get(b:, 'context_callback', get(g:, 'context_callback', 'context#callback')),
          \ [a:path, 0, v:shell_error])
  endfunction

endif " has('job')

function! s:callback(path, job, status) abort
  if a:status < 0 " Assume the job was terminated
    return
  endif
  " Get info about the current window
  let l:winid = s:win_getid()             " Save window id
  let l:efm = &l:errorformat              " Save local errorformat
  let l:cwd = fnamemodify(getcwd(), ":p") " Save local working directory
  " Set errorformat to parse ConTeXt errors
  execute 'setl efm=' . escape(b:context_errorformat, ' ')
  try " Set cwd to expand error file correctly
    execute 'lcd' fnameescape(fnamemodify(a:path, ':h'))
  catch /.*/
    execute 'setl efm=' . escape(l:efm, ' ')
    throw v:exception
  endtry
  try
    execute 'cgetfile' fnameescape(fnamemodify(a:path, ':r') . '.log')
    botright cwindow
  finally " Restore cwd and errorformat
    execute s:win_id2win(l:winid) . 'wincmd w'
    execute 'lcd ' . fnameescape(l:cwd)
    execute 'setl efm=' . escape(l:efm, ' ')
  endtry
  if a:status == 0
    call s:context_echo('Success!', 'ModeMsg')
  else
    call s:context_echo('There are errors. ', 'ErrorMsg')
  endif
endfunction

function! context#command()
  return get(b:, 'context_mtxrun', get(g:, 'context_mtxrun', 'mtxrun'))
        \ . ' --script context --autogenerate --nonstopmode'
        \ . ' --synctex=' . (get(b:, 'context_synctex', get(g:, 'context_synctex', 0)) ? '1' : '0')
        \ . ' ' . get(b:, 'context_extra_options', get(g:, 'context_extra_options', ''))
endfunction

" Accepts an optional path (useful for big projects, when the file you are
" editing is not the project's root document). If no argument is given, uses
" the path of the current buffer.
function! context#typeset(...) abort
  let l:path = fnamemodify(strlen(a:000[0]) > 0 ? a:1 : expand("%"), ":p")
  let l:cwd = fnamemodify(getcwd(), ":p") " Save local working directory
  call s:context_echo('Typesetting...',  'ModeMsg')
  execute 'lcd' fnameescape(fnamemodify(l:path, ":h"))
  try
    call s:typeset(l:path)
  finally " Restore local working directory
    execute 'lcd ' . fnameescape(l:cwd)
  endtry
endfunction!
"}}}

let &cpo = s:keepcpo
unlet s:keepcpo

" vim: sw=2 fdm=marker