java.vim (13669B)
1 " Vim filetype plugin file 2 " Language: Java 3 " Maintainer: Aliaksei Budavei <0x000c70 AT gmail DOT com> 4 " Former Maintainer: Dan Sharp 5 " Repository: https://github.com/zzzyxwvut/java-vim.git 6 " Last Change: 2025 May 08 7 8 " Make sure the continuation lines below do not cause problems in 9 " compatibility mode. 10 let s:save_cpo = &cpo 11 set cpo-=C 12 13 if (exists("g:java_ignore_javadoc") || exists("g:java_ignore_markdown")) && 14 \ exists("*javaformat#RemoveCommonMarkdownWhitespace") 15 delfunction javaformat#RemoveCommonMarkdownWhitespace 16 unlet! g:loaded_javaformat 17 endif 18 19 if exists("b:did_ftplugin") 20 let &cpo = s:save_cpo 21 unlet s:save_cpo 22 finish 23 endif 24 25 let b:did_ftplugin = 1 26 27 " For filename completion, prefer the .java extension over the .class 28 " extension. 29 set suffixes+=.class 30 31 " Set up "&define" and "&include". 32 let s:peek = '' 33 34 try 35 " Since v7.3.1037. 36 if 'ab' !~ 'a\@1<!b' 37 let s:peek = string(strlen('instanceof') + 8) 38 endif 39 catch /\<E59:/ 40 endtry 41 42 " Treat "s:common" as a non-backtracking unit to avoid matching constructor 43 " declarations whose package-private headers are indistinguishable from method 44 " invocation. Note that "[@-]" must not and "$" may not be in "&l:iskeyword". 45 let s:common = '\%(\%(\%(@\%(interface\)\@!\%(\K\k*\.\)*\K\k*\)\s\+\)*' . 46 \ '\%(p\%(rivate\|rotected\|ublic\)\s\+\)\=\)\@>' 47 let s:types = '\%(\%(abstract\|final\|non-sealed\|s\%(ealed\|tatic\|trictfp\)\)\s\+\)*' . 48 \ '\%(class\|enum\|@\=interface\|record\)\s\+\ze\K\k*\>' 49 let s:methods = '\%(\%(abstract\|default\|final\|native\|s\%(tatic\|trictfp\|ynchronized\)\)\s\+\)*' . 50 \ '\%(<.\{-1,}>\s\+\)\=\%(\K\k*\.\)*\K\k*\s*\%(<.\{-1,}>\%(\s\|\[\)\@=\)\=\s*\%(\[\]\s*\)*' . 51 \ '\s\+\ze\%(\<\%(assert\|case\|instanceof\|new\|return\|throw\|when\)\s\+\)\@' . 52 \ s:peek . '<!\K\k*\s*(' 53 let &l:define = printf('\C\m^\s*%s\%%(%s\|%s\)', s:common, s:types, s:methods) 54 let &l:include = '\C\m^\s*import\s\+\ze\%(\K\k*\.\)\+\K\k*;' 55 unlet s:methods s:types s:common s:peek 56 57 " Enable gf on import statements. Convert . in the package 58 " name to / and append .java to the name, then search the path. 59 setlocal includeexpr=substitute(v:fname,'\\.','/','g') 60 setlocal suffixesadd=.java 61 62 " Clean up in case this file is sourced again. 63 unlet! s:zip_func_upgradable 64 65 """" STRIVE TO REMAIN COMPATIBLE FOR AT LEAST VIM 7.0. 66 67 " Documented in ":help ft-java-plugin". 68 if exists("g:ftplugin_java_source_path") && 69 \ type(g:ftplugin_java_source_path) == type("") 70 if filereadable(g:ftplugin_java_source_path) 71 if exists("#zip") && 72 \ g:ftplugin_java_source_path =~# '.\.\%(jar\|zip\)$' 73 if !exists("s:zip_files") 74 let s:zip_files = {} 75 endif 76 77 let s:zip_files[bufnr('%')] = g:ftplugin_java_source_path 78 let s:zip_files[0] = g:ftplugin_java_source_path 79 let s:zip_func_upgradable = 1 80 81 function! JavaFileTypeZipFile() abort 82 let @/ = substitute(v:fname, '\.', '\\/', 'g') . '.java' 83 return get(s:zip_files, bufnr('%'), s:zip_files[0]) 84 endfunction 85 86 " E120 for "inex=s:JavaFileTypeZipFile()" before v8.2.3900. 87 setlocal includeexpr=JavaFileTypeZipFile() 88 setlocal suffixesadd< 89 endif 90 else 91 let &l:path = g:ftplugin_java_source_path . ',' . &l:path 92 endif 93 endif 94 95 " Set 'formatoptions' to break comment lines but not other lines, 96 " and insert the comment leader when hitting <CR> or using "o". 97 setlocal formatoptions-=t formatoptions+=croql 98 99 " Set 'comments' to format Markdown Javadoc comments and dashed lists 100 " in other multi-line comments (it behaves just like C). 101 setlocal comments& comments^=:///,sO:*\ -,mO:*\ \ ,exO:*/ 102 103 setlocal commentstring=//\ %s 104 105 " Change the :browse e filter to primarily show Java-related files. 106 if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter") 107 let b:browsefilter="Java Files (*.java)\t*.java\n" . 108 \ "Properties Files (*.prop*)\t*.prop*\n" . 109 \ "Manifest Files (*.mf)\t*.mf\n" 110 if has("win32") 111 let b:browsefilter .= "All Files (*.*)\t*\n" 112 else 113 let b:browsefilter .= "All Files (*)\t*\n" 114 endif 115 endif 116 117 """" Support pre- and post-compiler actions for SpotBugs. 118 if (!empty(get(g:, 'spotbugs_properties', {})) || 119 \ !empty(get(b:, 'spotbugs_properties', {}))) && 120 \ filereadable($VIMRUNTIME . '/compiler/spotbugs.vim') 121 122 function! s:SpotBugsGetProperty(name, default) abort 123 return get( 124 \ {s:spotbugs_properties_scope}spotbugs_properties, 125 \ a:name, 126 \ a:default) 127 endfunction 128 129 function! s:SpotBugsHasProperty(name) abort 130 return has_key( 131 \ {s:spotbugs_properties_scope}spotbugs_properties, 132 \ a:name) 133 endfunction 134 135 function! s:SpotBugsGetProperties() abort 136 return {s:spotbugs_properties_scope}spotbugs_properties 137 endfunction 138 139 " Work around ":bar"s and ":autocmd"s. 140 function! JavaFileTypeExecuteActionOnce(cleanup_cmd, action_cmd) abort 141 try 142 execute a:cleanup_cmd 143 finally 144 execute a:action_cmd 145 endtry 146 endfunction 147 148 if exists("b:spotbugs_properties") 149 let s:spotbugs_properties_scope = 'b:' 150 151 " Merge global entries, if any, in buffer-local entries, favouring 152 " defined buffer-local ones. 153 call extend( 154 \ b:spotbugs_properties, 155 \ get(g:, 'spotbugs_properties', {}), 156 \ 'keep') 157 elseif exists("g:spotbugs_properties") 158 let s:spotbugs_properties_scope = 'g:' 159 endif 160 161 let s:commands = {} 162 163 for s:name in ['DefaultPreCompilerCommand', 164 \ 'DefaultPreCompilerTestCommand', 165 \ 'DefaultPostCompilerCommand'] 166 if s:SpotBugsHasProperty(s:name) 167 let s:commands[s:name] = remove( 168 \ s:SpotBugsGetProperties(), 169 \ s:name) 170 endif 171 endfor 172 173 if s:SpotBugsHasProperty('compiler') 174 " XXX: Postpone loading the script until all state, if any, has been 175 " collected. 176 if !empty(s:commands) 177 let g:spotbugs#state = { 178 \ 'compiler': remove(s:SpotBugsGetProperties(), 'compiler'), 179 \ 'commands': copy(s:commands), 180 \ } 181 else 182 let g:spotbugs#state = { 183 \ 'compiler': remove(s:SpotBugsGetProperties(), 'compiler'), 184 \ } 185 endif 186 187 " Merge default entries in global (or buffer-local) entries, favouring 188 " defined global (or buffer-local) ones. 189 call extend( 190 \ {s:spotbugs_properties_scope}spotbugs_properties, 191 \ spotbugs#DefaultProperties(), 192 \ 'keep') 193 elseif !empty(s:commands) 194 " XXX: Postpone loading the script until all state, if any, has been 195 " collected. 196 let g:spotbugs#state = {'commands': copy(s:commands)} 197 endif 198 199 unlet s:commands s:name 200 let s:request = 0 201 202 if s:SpotBugsHasProperty('PostCompilerAction') 203 let s:request += 4 204 endif 205 206 if s:SpotBugsHasProperty('PreCompilerTestAction') 207 let s:dispatcher = printf('call call(%s, [])', 208 \ string(s:SpotBugsGetProperties().PreCompilerTestAction)) 209 let s:request += 2 210 endif 211 212 if s:SpotBugsHasProperty('PreCompilerAction') 213 let s:dispatcher = printf('call call(%s, [])', 214 \ string(s:SpotBugsGetProperties().PreCompilerAction)) 215 let s:request += 1 216 endif 217 218 " Adapt the tests for "s:FindClassFiles()" from "compiler/spotbugs.vim". 219 if (s:request == 3 || s:request == 7) && 220 \ (!empty(s:SpotBugsGetProperty('sourceDirPath', [])) && 221 \ !empty(s:SpotBugsGetProperty('classDirPath', [])) && 222 \ !empty(s:SpotBugsGetProperty('testSourceDirPath', [])) && 223 \ !empty(s:SpotBugsGetProperty('testClassDirPath', []))) 224 function! s:DispatchAction(paths_action_pairs) abort 225 let name = expand('%:p') 226 227 for [paths, Action] in a:paths_action_pairs 228 for path in paths 229 if name =~# (path . '.\{-}\.java\=$') 230 call Action() 231 return 232 endif 233 endfor 234 endfor 235 endfunction 236 237 let s:dir_cnt = min([ 238 \ len(s:SpotBugsGetProperties().sourceDirPath), 239 \ len(s:SpotBugsGetProperties().classDirPath)]) 240 let s:test_dir_cnt = min([ 241 \ len(s:SpotBugsGetProperties().testSourceDirPath), 242 \ len(s:SpotBugsGetProperties().testClassDirPath)]) 243 244 " Do not break up path pairs with filtering! 245 let s:dispatcher = printf('call s:DispatchAction(%s)', 246 \ string([[s:SpotBugsGetProperties().sourceDirPath[0 : s:dir_cnt - 1], 247 \ s:SpotBugsGetProperties().PreCompilerAction], 248 \ [s:SpotBugsGetProperties().testSourceDirPath[0 : s:test_dir_cnt - 1], 249 \ s:SpotBugsGetProperties().PreCompilerTestAction]])) 250 unlet s:test_dir_cnt s:dir_cnt 251 endif 252 253 if exists("s:dispatcher") 254 function! s:ExecuteActions(pre_action, post_action) abort 255 try 256 execute a:pre_action 257 catch /\<E42:/ 258 execute a:post_action 259 endtry 260 endfunction 261 endif 262 263 if s:request 264 if exists("b:spotbugs_syntax_once") || empty(join(getline(1, 8), '')) 265 let s:actions = [{'event': 'User'}] 266 else 267 " XXX: Handle multiple FileType events when vimrc contains more 268 " than one filetype setting for the language, e.g.: 269 " :filetype plugin indent on 270 " :autocmd BufRead,BufNewFile *.java setlocal filetype=java ... 271 " XXX: DO NOT ADD b:spotbugs_syntax_once TO b:undo_ftplugin ! 272 let b:spotbugs_syntax_once = 1 273 let s:actions = [{ 274 \ 'event': 'Syntax', 275 \ 'once': 1, 276 \ }, { 277 \ 'event': 'User', 278 \ }] 279 endif 280 281 for s:idx in range(len(s:actions)) 282 if s:request == 7 || s:request == 6 || s:request == 5 283 let s:actions[s:idx].cmd = printf('call s:ExecuteActions(%s, %s)', 284 \ string(s:dispatcher), 285 \ string(printf('compiler spotbugs | call call(%s, [])', 286 \ string(s:SpotBugsGetProperties().PostCompilerAction)))) 287 elseif s:request == 4 288 let s:actions[s:idx].cmd = printf( 289 \ 'compiler spotbugs | call call(%s, [])', 290 \ string(s:SpotBugsGetProperties().PostCompilerAction)) 291 elseif s:request == 3 || s:request == 2 || s:request == 1 292 let s:actions[s:idx].cmd = printf('call s:ExecuteActions(%s, %s)', 293 \ string(s:dispatcher), 294 \ string('compiler spotbugs')) 295 else 296 let s:actions[s:idx].cmd = '' 297 endif 298 endfor 299 300 if !exists("#java_spotbugs") 301 augroup java_spotbugs 302 augroup END 303 endif 304 305 " The events are defined in s:actions. 306 silent! autocmd! java_spotbugs User <buffer> 307 silent! autocmd! java_spotbugs Syntax <buffer> 308 309 for s:action in s:actions 310 if has_key(s:action, 'once') 311 execute printf('autocmd java_spotbugs %s <buffer> ' . 312 \ 'call JavaFileTypeExecuteActionOnce(%s, %s)', 313 \ s:action.event, 314 \ string(printf('autocmd! java_spotbugs %s <buffer>', 315 \ s:action.event)), 316 \ string(s:action.cmd)) 317 else 318 execute printf('autocmd java_spotbugs %s <buffer> %s', 319 \ s:action.event, 320 \ s:action.cmd) 321 endif 322 endfor 323 324 if s:SpotBugsHasProperty('PostCompilerActionExecutor') && 325 \ (s:request == 7 || s:request == 6 || 326 \ s:request == 5 || s:request == 4) 327 let s:augroup = s:SpotBugsGetProperty( 328 \ 'augroupForPostCompilerAction', 329 \ 'java_spotbugs_post') 330 let s:augroup = !empty(s:augroup) ? s:augroup : 'java_spotbugs_post' 331 332 for s:candidate in ['java_spotbugs_post', s:augroup] 333 if !exists("#" . s:candidate) 334 execute printf('augroup %s | augroup END', s:candidate) 335 endif 336 endfor 337 338 silent! autocmd! java_spotbugs_post User <buffer> 339 340 " Define a User ":autocmd" to define a once-only ShellCmdPost 341 " ":autocmd" that will invoke "PostCompilerActionExecutor" and let 342 " it decide whether to proceed with ":compiler spotbugs" etc.; and 343 " seek explicit synchronisation with ":doautocmd ShellCmdPost" by 344 " omitting "nested" for "java_spotbugs_post" and "java_spotbugs". 345 execute printf('autocmd java_spotbugs_post User <buffer> ' . 346 \ 'call JavaFileTypeExecuteActionOnce(%s, %s)', 347 \ string(printf('autocmd! %s ShellCmdPost <buffer>', s:augroup)), 348 \ string(printf('autocmd %s ShellCmdPost <buffer> ' . 349 \ 'call JavaFileTypeExecuteActionOnce(%s, %s)', 350 \ s:augroup, 351 \ string(printf('autocmd! %s ShellCmdPost <buffer>', s:augroup)), 352 \ string(printf('call call(%s, [%s])', 353 \ string(s:SpotBugsGetProperties().PostCompilerActionExecutor), 354 \ string(printf('compiler spotbugs | call call(%s, [])', 355 \ string(s:SpotBugsGetProperties().PostCompilerAction)))))))) 356 endif 357 358 unlet! s:candidate s:augroup s:action s:actions s:idx s:dispatcher 359 endif 360 361 delfunction s:SpotBugsGetProperties 362 delfunction s:SpotBugsHasProperty 363 delfunction s:SpotBugsGetProperty 364 unlet! s:request s:spotbugs_properties_scope 365 endif 366 367 function! JavaFileTypeCleanUp() abort 368 setlocal suffixes< suffixesadd< formatoptions< comments< commentstring< path< includeexpr< include< define< 369 unlet! b:browsefilter 370 371 " The concatenated ":autocmd" removals may be misparsed as an ":autocmd". 372 " A _once-only_ ShellCmdPost ":autocmd" is always a call-site definition. 373 silent! autocmd! java_spotbugs User <buffer> 374 silent! autocmd! java_spotbugs Syntax <buffer> 375 silent! autocmd! java_spotbugs_post User <buffer> 376 endfunction 377 378 " Undo the stuff we changed. 379 let b:undo_ftplugin = 'call JavaFileTypeCleanUp() | delfunction JavaFileTypeCleanUp' 380 381 " See ":help vim9-mix". 382 if !has("vim9script") 383 let &cpo = s:save_cpo 384 unlet s:save_cpo 385 finish 386 endif 387 388 if exists("s:zip_func_upgradable") 389 delfunction! JavaFileTypeZipFile 390 391 def! s:JavaFileTypeZipFile(): string 392 @/ = substitute(v:fname, '\.', '\\/', 'g') .. '.java' 393 return get(zip_files, bufnr('%'), zip_files[0]) 394 enddef 395 396 setlocal includeexpr=s:JavaFileTypeZipFile() 397 setlocal suffixesadd< 398 endif 399 400 if exists("*s:DispatchAction") 401 def! s:DispatchAction(paths_action_pairs: list<list<any>>) 402 const name: string = expand('%:p') 403 404 for [paths: list<string>, Action: func: any] in paths_action_pairs 405 for path in paths 406 if name =~# (path .. '.\{-}\.java\=$') 407 Action() 408 return 409 endif 410 endfor 411 endfor 412 enddef 413 endif 414 415 " Restore the saved compatibility options. 416 let &cpo = s:save_cpo 417 unlet s:save_cpo 418 " vim: fdm=syntax sw=4 ts=8 noet sta