context.vim 5.3 KB

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