javac.vim 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. "============================================================================
  2. "File: javac.vim
  3. "Description: Syntax checking plugin for syntastic.vim
  4. "Maintainer: Jochen Keil <jochen.keil at gmail dot com>
  5. " Dmitry Geurkov <d.geurkov at gmail dot com>
  6. "License: This program is free software. It comes without any warranty,
  7. " to the extent permitted by applicable law. You can redistribute
  8. " it and/or modify it under the terms of the Do What The Fuck You
  9. " Want To Public License, Version 2, as published by Sam Hocevar.
  10. " See http://sam.zoy.org/wtfpl/COPYING for more details.
  11. "============================================================================
  12. if exists('g:loaded_syntastic_java_javac_checker')
  13. finish
  14. endif
  15. let g:loaded_syntastic_java_javac_checker = 1
  16. let g:syntastic_java_javac_maven_pom_tags = ['build', 'properties']
  17. let g:syntastic_java_javac_maven_pom_properties = {}
  18. let s:has_maven = 0
  19. let s:save_cpo = &cpo
  20. set cpo&vim
  21. " Checker options {{{1
  22. if !exists('g:syntastic_java_javac_executable')
  23. let g:syntastic_java_javac_executable = 'javac'
  24. endif
  25. if !exists('g:syntastic_java_maven_executable')
  26. let g:syntastic_java_maven_executable = 'mvn'
  27. endif
  28. if !exists('g:syntastic_java_javac_options')
  29. let g:syntastic_java_javac_options = '-Xlint'
  30. endif
  31. if !exists('g:syntastic_java_maven_options')
  32. let g:syntastic_java_maven_options = ''
  33. endif
  34. if !exists('g:syntastic_java_javac_classpath')
  35. let g:syntastic_java_javac_classpath = ''
  36. endif
  37. if !exists('g:syntastic_java_javac_delete_output')
  38. let g:syntastic_java_javac_delete_output = 1
  39. endif
  40. if !exists('g:syntastic_java_javac_autoload_maven_classpath')
  41. let g:syntastic_java_javac_autoload_maven_classpath = 1
  42. endif
  43. if !exists('g:syntastic_java_javac_config_file_enabled')
  44. let g:syntastic_java_javac_config_file_enabled = 0
  45. endif
  46. if !exists('g:syntastic_java_javac_config_file')
  47. let g:syntastic_java_javac_config_file = '.syntastic_javac_config'
  48. endif
  49. if !exists('g:syntastic_java_javac_custom_classpath_command')
  50. let g:syntastic_java_javac_custom_classpath_command = ''
  51. endif
  52. if !exists('g:syntastic_java_javac_maven_pom_ftime')
  53. let g:syntastic_java_javac_maven_pom_ftime = {}
  54. endif
  55. if !exists('g:syntastic_java_javac_maven_pom_classpath')
  56. let g:syntastic_java_javac_maven_pom_classpath = {}
  57. endif
  58. " }}}1
  59. command! SyntasticJavacEditClasspath call s:EditClasspath()
  60. if g:syntastic_java_javac_config_file_enabled
  61. command! SyntasticJavacEditConfig call s:EditConfig()
  62. endif
  63. function! SyntaxCheckers_java_javac_IsAvailable() dict " {{{1
  64. let s:has_maven = executable(expand(g:syntastic_java_maven_executable, 1))
  65. return executable(expand(g:syntastic_java_javac_executable, 1))
  66. endfunction " }}}1
  67. function! SyntaxCheckers_java_javac_GetLocList() dict " {{{1
  68. let javac_opts = g:syntastic_java_javac_options
  69. let output_dir = ''
  70. if g:syntastic_java_javac_delete_output
  71. let output_dir = syntastic#util#tmpdir()
  72. let javac_opts .= ' -d ' . syntastic#util#shescape(output_dir)
  73. endif
  74. " load classpath from config file
  75. if g:syntastic_java_javac_config_file_enabled
  76. call s:LoadConfigFile()
  77. endif
  78. " add classpathes to javac_classpath {{{2
  79. let javac_classpath = ''
  80. for path in split(g:syntastic_java_javac_classpath, s:ClassSep())
  81. if path !=# ''
  82. try
  83. let ps = glob(path, 1, 1)
  84. catch
  85. let ps = split(glob(path, 1), "\n")
  86. endtry
  87. if type(ps) == type([])
  88. for p in ps
  89. let javac_classpath = s:AddToClasspath(javac_classpath, p)
  90. endfor
  91. else
  92. let javac_classpath = s:AddToClasspath(javac_classpath, ps)
  93. endif
  94. endif
  95. endfor
  96. if s:has_maven && g:syntastic_java_javac_autoload_maven_classpath
  97. if !g:syntastic_java_javac_delete_output
  98. let javac_opts .= ' -d ' . syntastic#util#shescape(s:MavenOutputDirectory())
  99. endif
  100. let javac_classpath = s:AddToClasspath(javac_classpath, s:GetMavenClasspath())
  101. endif
  102. " }}}2
  103. " load custom classpath {{{2
  104. if g:syntastic_java_javac_custom_classpath_command !=# ''
  105. let lines = syntastic#util#system(g:syntastic_java_javac_custom_classpath_command)
  106. if syntastic#util#isRunningWindows() || has('win32unix')
  107. let lines = substitute(lines, "\r\n", "\n", 'g')
  108. endif
  109. for l in split(lines, "\n")
  110. let javac_classpath = s:AddToClasspath(javac_classpath, l)
  111. endfor
  112. endif
  113. if javac_classpath !=# ''
  114. let javac_opts .= ' -cp ' . syntastic#util#shexpand(javac_classpath)
  115. endif
  116. " }}}2
  117. let fname = expand('%:p:h', 1) . syntastic#util#Slash() . expand ('%:t', 1)
  118. if has('win32unix')
  119. let fname = syntastic#util#CygwinPath(fname)
  120. endif
  121. let makeprg = self.makeprgBuild({
  122. \ 'args': javac_opts,
  123. \ 'fname': syntastic#util#shescape(fname) })
  124. " unashamedly stolen from *errorformat-javac* (quickfix.txt) and modified to include error types
  125. let errorformat =
  126. \ '%E%f:%l: error: %m,'.
  127. \ '%W%f:%l: warning: %m,'.
  128. \ '%A%f:%l: %m,'.
  129. \ '%+Z%p^,'.
  130. \ '%+C%.%#,'.
  131. \ '%-G%.%#'
  132. if output_dir !=# ''
  133. silent! call mkdir(output_dir, 'p')
  134. endif
  135. let errors = SyntasticMake({
  136. \ 'makeprg': makeprg,
  137. \ 'errorformat': errorformat,
  138. \ 'postprocess': ['cygwinRemoveCR'] })
  139. if output_dir !=# ''
  140. call syntastic#util#rmrf(output_dir)
  141. endif
  142. return errors
  143. endfunction " }}}1
  144. " Utilities {{{1
  145. function! s:RemoveCarriageReturn(line) " {{{2
  146. return substitute(a:line, "\r", '', 'g')
  147. endfunction " }}}2
  148. function! s:ClassSep() " {{{2
  149. return (syntastic#util#isRunningWindows() || has('win32unix')) ? ';' : ':'
  150. endfunction " }}}2
  151. function! s:AddToClasspath(classpath, path) " {{{2
  152. if a:path ==# ''
  153. return a:classpath
  154. endif
  155. return (a:classpath !=# '') ? a:classpath . s:ClassSep() . a:path : a:path
  156. endfunction " }}}2
  157. function! s:SplitClasspath(classpath) " {{{2
  158. return split(a:classpath, s:ClassSep())
  159. endfunction " }}}2
  160. function! s:LoadConfigFile() " {{{2
  161. if filereadable(expand(g:syntastic_java_javac_config_file, 1))
  162. execute 'source ' . fnameescape(expand(g:syntastic_java_javac_config_file, 1))
  163. endif
  164. endfunction " }}}2
  165. function! s:SaveClasspath() " {{{2
  166. " build classpath from lines
  167. let path = ''
  168. let lines = getline(1, line('$'))
  169. for l in lines
  170. let path = s:AddToClasspath(path, l)
  171. endfor
  172. " save classpath to config file
  173. if g:syntastic_java_javac_config_file_enabled
  174. if filereadable(expand(g:syntastic_java_javac_config_file, 1))
  175. " load lines from config file
  176. let lines = readfile(expand(g:syntastic_java_javac_config_file, 1))
  177. " strip g:syntastic_java_javac_classpath options from config file lines
  178. let i = 0
  179. while i < len(lines)
  180. if match(lines[i], 'g:syntastic_java_javac_classpath') != -1
  181. call remove(lines, i)
  182. else
  183. let i += 1
  184. endif
  185. endwhile
  186. else
  187. let lines = []
  188. endif
  189. " add new g:syntastic_java_javac_classpath option to config
  190. call add(lines, 'let g:syntastic_java_javac_classpath = ' . string(path))
  191. " save config file lines
  192. call writefile(lines, expand(g:syntastic_java_javac_config_file, 1))
  193. endif
  194. " set new classpath
  195. let g:syntastic_java_javac_classpath = path
  196. let &modified = 0
  197. endfunction " }}}2
  198. function! s:EditClasspath() " {{{2
  199. let command = 'syntastic javac classpath'
  200. let winnr = bufwinnr('^' . command . '$')
  201. if winnr < 0
  202. let path = []
  203. let pathlines = split(g:syntastic_java_javac_classpath, "\n")
  204. for p in pathlines
  205. call extend(path, s:SplitClasspath(p))
  206. endfor
  207. execute (len(path) + 5) . 'sp ' . fnameescape(command)
  208. augroup syntastic
  209. autocmd BufWriteCmd <buffer> call s:SaveClasspath() | bwipeout
  210. augroup END
  211. setlocal buftype=acwrite bufhidden=wipe nobuflisted noswapfile nowrap number
  212. for p in path
  213. call append(line('$') - 1, p)
  214. endfor
  215. let &modified = 0
  216. else
  217. execute winnr . 'wincmd w'
  218. endif
  219. endfunction " }}}2
  220. function! s:SaveConfig() " {{{2
  221. " get lines
  222. let lines = getline(1, line('$'))
  223. if g:syntastic_java_javac_config_file_enabled
  224. " save config file lines
  225. call writefile(lines, expand(g:syntastic_java_javac_config_file, 1))
  226. endif
  227. let &modified = 0
  228. endfunction " }}}2
  229. function! s:EditConfig() " {{{2
  230. let command = 'syntastic javac config'
  231. let winnr = bufwinnr('^' . command . '$')
  232. if winnr < 0
  233. let lines = []
  234. if filereadable(expand(g:syntastic_java_javac_config_file, 1))
  235. let lines = readfile(expand(g:syntastic_java_javac_config_file, 1))
  236. endif
  237. execute (len(lines) + 5) . 'sp ' . fnameescape(command)
  238. augroup syntastic
  239. autocmd BufWriteCmd <buffer> call s:SaveConfig() | bwipeout
  240. augroup END
  241. setlocal ft=vim buftype=acwrite bufhidden=wipe nobuflisted noswapfile nowrap number
  242. for l in lines
  243. call append(line('$') - 1, l)
  244. endfor
  245. let &modified = 0
  246. else
  247. execute winnr . 'wincmd w'
  248. endif
  249. endfunction " }}}2
  250. function! s:GetMavenProperties() " {{{2
  251. let mvn_properties = {}
  252. let pom = findfile('pom.xml', '.;')
  253. if s:has_maven && filereadable(pom)
  254. if !has_key(g:syntastic_java_javac_maven_pom_properties, pom)
  255. let mvn_cmd = syntastic#util#shexpand(g:syntastic_java_maven_executable) .
  256. \ ' -f ' . syntastic#util#shescape(pom) .
  257. \ ' ' . g:syntastic_java_maven_options
  258. let mvn_is_managed_tag = 1
  259. let mvn_settings_output = split(syntastic#util#system(mvn_cmd . ' help:effective-pom'), "\n")
  260. let current_path = 'project'
  261. for line in mvn_settings_output
  262. let matches = matchlist(line, '\m^\s*<\([a-zA-Z0-9\-\.]\+\)>\s*$')
  263. if mvn_is_managed_tag && !empty(matches)
  264. let mvn_is_managed_tag = index(g:syntastic_java_javac_maven_pom_tags, matches[1]) >= 0
  265. let current_path .= '.' . matches[1]
  266. else
  267. let matches = matchlist(line, '\m^\s*</\([a-zA-Z0-9\-\.]\+\)>\s*$')
  268. if !empty(matches)
  269. let mvn_is_managed_tag = index(g:syntastic_java_javac_maven_pom_tags, matches[1]) < 0
  270. let current_path = substitute(current_path, '\m\.' . matches[1] . '$', '', '')
  271. else
  272. let matches = matchlist(line, '\m^\s*<\([a-zA-Z0-9\-\.]\+\)>\(.\+\)</[a-zA-Z0-9\-\.]\+>\s*$')
  273. if mvn_is_managed_tag && !empty(matches)
  274. let mvn_properties[current_path . '.' . matches[1]] = matches[2]
  275. endif
  276. endif
  277. endif
  278. endfor
  279. let g:syntastic_java_javac_maven_pom_properties[pom] = mvn_properties
  280. endif
  281. return g:syntastic_java_javac_maven_pom_properties[pom]
  282. endif
  283. return mvn_properties
  284. endfunction " }}}2
  285. function! s:GetMavenClasspath() " {{{2
  286. let pom = findfile('pom.xml', '.;')
  287. if s:has_maven && filereadable(pom)
  288. if !has_key(g:syntastic_java_javac_maven_pom_ftime, pom) || g:syntastic_java_javac_maven_pom_ftime[pom] != getftime(pom)
  289. let mvn_cmd = syntastic#util#shexpand(g:syntastic_java_maven_executable) .
  290. \ ' -f ' . syntastic#util#shescape(pom) .
  291. \ ' ' . g:syntastic_java_maven_options
  292. let mvn_classpath_output = split(syntastic#util#system(mvn_cmd . ' dependency:build-classpath'), "\n")
  293. let mvn_classpath = ''
  294. let class_path_next = 0
  295. for line in mvn_classpath_output
  296. if class_path_next == 1
  297. let mvn_classpath = s:RemoveCarriageReturn(line)
  298. break
  299. endif
  300. if stridx(line, 'Dependencies classpath:') >= 0
  301. let class_path_next = 1
  302. endif
  303. endfor
  304. let mvn_properties = s:GetMavenProperties()
  305. let sep = syntastic#util#Slash()
  306. let output_dir = join(['target', 'classes'], sep)
  307. if has_key(mvn_properties, 'project.build.outputDirectory')
  308. let output_dir = mvn_properties['project.build.outputDirectory']
  309. endif
  310. let mvn_classpath = s:AddToClasspath(mvn_classpath, output_dir)
  311. let test_output_dir = join(['target', 'test-classes'], sep)
  312. if has_key(mvn_properties, 'project.build.testOutputDirectory')
  313. let test_output_dir = mvn_properties['project.build.testOutputDirectory']
  314. endif
  315. let mvn_classpath = s:AddToClasspath(mvn_classpath, test_output_dir)
  316. let g:syntastic_java_javac_maven_pom_ftime[pom] = getftime(pom)
  317. let g:syntastic_java_javac_maven_pom_classpath[pom] = mvn_classpath
  318. endif
  319. return g:syntastic_java_javac_maven_pom_classpath[pom]
  320. endif
  321. return ''
  322. endfunction " }}}2
  323. function! s:MavenOutputDirectory() " {{{2
  324. let pom = findfile('pom.xml', '.;')
  325. if s:has_maven && filereadable(pom)
  326. let mvn_properties = s:GetMavenProperties()
  327. let output_dir = getcwd()
  328. if has_key(mvn_properties, 'project.properties.build.dir')
  329. let output_dir = mvn_properties['project.properties.build.dir']
  330. endif
  331. let sep = syntastic#util#Slash()
  332. if stridx(expand('%:p:h', 1), join(['src', 'main', 'java'], sep)) >= 0
  333. let output_dir = join ([output_dir, 'target', 'classes'], sep)
  334. if has_key(mvn_properties, 'project.build.outputDirectory')
  335. let output_dir = mvn_properties['project.build.outputDirectory']
  336. endif
  337. endif
  338. if stridx(expand('%:p:h', 1), join(['src', 'test', 'java'], sep)) >= 0
  339. let output_dir = join([output_dir, 'target', 'test-classes'], sep)
  340. if has_key(mvn_properties, 'project.build.testOutputDirectory')
  341. let output_dir = mvn_properties['project.build.testOutputDirectory']
  342. endif
  343. endif
  344. if has('win32unix')
  345. let output_dir = syntastic#util#CygwinPath(output_dir)
  346. endif
  347. return output_dir
  348. endif
  349. return '.'
  350. endfunction " }}}2
  351. " }}}1
  352. call g:SyntasticRegistry.CreateAndRegisterChecker({
  353. \ 'filetype': 'java',
  354. \ 'name': 'javac'})
  355. let &cpo = s:save_cpo
  356. unlet s:save_cpo
  357. " vim: set sw=4 sts=4 et fdm=marker: