mirror of
https://github.com/vim/vim
synced 2025-03-15 14:27:53 +01:00
Problem: SpotBugs compiler can be further improved Solution: Introduce event-driven primitives for SpotBugs (Aliaksei Budavei) closes: #16258 Signed-off-by: Aliaksei Budavei <0x000c70@gmail.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
394 lines
12 KiB
VimL
394 lines
12 KiB
VimL
" Vim filetype plugin file
|
|
" Language: Java
|
|
" Maintainer: Aliaksei Budavei <0x000c70 AT gmail DOT com>
|
|
" Former Maintainer: Dan Sharp
|
|
" Repository: https://github.com/zzzyxwvut/java-vim.git
|
|
" Last Change: 2024 Dec 25
|
|
" 2024 Jan 14 by Vim Project (browsefilter)
|
|
" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
|
|
|
|
" Make sure the continuation lines below do not cause problems in
|
|
" compatibility mode.
|
|
let s:save_cpo = &cpo
|
|
set cpo-=C
|
|
|
|
if (exists("g:java_ignore_javadoc") || exists("g:java_ignore_markdown")) &&
|
|
\ exists("*javaformat#RemoveCommonMarkdownWhitespace")
|
|
delfunction javaformat#RemoveCommonMarkdownWhitespace
|
|
unlet! g:loaded_javaformat
|
|
endif
|
|
|
|
if exists("b:did_ftplugin")
|
|
let &cpo = s:save_cpo
|
|
unlet s:save_cpo
|
|
finish
|
|
endif
|
|
|
|
let b:did_ftplugin = 1
|
|
|
|
" For filename completion, prefer the .java extension over the .class
|
|
" extension.
|
|
set suffixes+=.class
|
|
|
|
" Enable gf on import statements. Convert . in the package
|
|
" name to / and append .java to the name, then search the path.
|
|
setlocal includeexpr=substitute(v:fname,'\\.','/','g')
|
|
setlocal suffixesadd=.java
|
|
|
|
" Clean up in case this file is sourced again.
|
|
unlet! s:zip_func_upgradable
|
|
|
|
"""" STRIVE TO REMAIN COMPATIBLE FOR AT LEAST VIM 7.0.
|
|
|
|
" Documented in ":help ft-java-plugin".
|
|
if exists("g:ftplugin_java_source_path") &&
|
|
\ type(g:ftplugin_java_source_path) == type("")
|
|
if filereadable(g:ftplugin_java_source_path)
|
|
if exists("#zip") &&
|
|
\ g:ftplugin_java_source_path =~# '.\.\%(jar\|zip\)$'
|
|
if !exists("s:zip_files")
|
|
let s:zip_files = {}
|
|
endif
|
|
|
|
let s:zip_files[bufnr('%')] = g:ftplugin_java_source_path
|
|
let s:zip_files[0] = g:ftplugin_java_source_path
|
|
let s:zip_func_upgradable = 1
|
|
|
|
function! JavaFileTypeZipFile() abort
|
|
let @/ = substitute(v:fname, '\.', '\\/', 'g') . '.java'
|
|
return get(s:zip_files, bufnr('%'), s:zip_files[0])
|
|
endfunction
|
|
|
|
" E120 for "inex=s:JavaFileTypeZipFile()" before v8.2.3900.
|
|
setlocal includeexpr=JavaFileTypeZipFile()
|
|
setlocal suffixesadd<
|
|
endif
|
|
else
|
|
let &l:path = g:ftplugin_java_source_path . ',' . &l:path
|
|
endif
|
|
endif
|
|
|
|
" Set 'formatoptions' to break comment lines but not other lines,
|
|
" and insert the comment leader when hitting <CR> or using "o".
|
|
setlocal formatoptions-=t formatoptions+=croql
|
|
|
|
" Set 'comments' to format Markdown Javadoc comments and dashed lists
|
|
" in other multi-line comments (it behaves just like C).
|
|
setlocal comments& comments^=:///,sO:*\ -,mO:*\ \ ,exO:*/
|
|
|
|
setlocal commentstring=//\ %s
|
|
|
|
" Change the :browse e filter to primarily show Java-related files.
|
|
if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
|
|
let b:browsefilter="Java Files (*.java)\t*.java\n" .
|
|
\ "Properties Files (*.prop*)\t*.prop*\n" .
|
|
\ "Manifest Files (*.mf)\t*.mf\n"
|
|
if has("win32")
|
|
let b:browsefilter .= "All Files (*.*)\t*\n"
|
|
else
|
|
let b:browsefilter .= "All Files (*)\t*\n"
|
|
endif
|
|
endif
|
|
|
|
"""" Support pre- and post-compiler actions for SpotBugs.
|
|
if (!empty(get(g:, 'spotbugs_properties', {})) ||
|
|
\ !empty(get(b:, 'spotbugs_properties', {}))) &&
|
|
\ filereadable($VIMRUNTIME . '/compiler/spotbugs.vim')
|
|
|
|
function! s:SpotBugsGetProperty(name, default) abort
|
|
return get(
|
|
\ {s:spotbugs_properties_scope}spotbugs_properties,
|
|
\ a:name,
|
|
\ a:default)
|
|
endfunction
|
|
|
|
function! s:SpotBugsHasProperty(name) abort
|
|
return has_key(
|
|
\ {s:spotbugs_properties_scope}spotbugs_properties,
|
|
\ a:name)
|
|
endfunction
|
|
|
|
function! s:SpotBugsGetProperties() abort
|
|
return {s:spotbugs_properties_scope}spotbugs_properties
|
|
endfunction
|
|
|
|
" Work around ":bar"s and ":autocmd"s.
|
|
function! JavaFileTypeExecuteActionOnce(cleanup_cmd, action_cmd) abort
|
|
try
|
|
execute a:cleanup_cmd
|
|
finally
|
|
execute a:action_cmd
|
|
endtry
|
|
endfunction
|
|
|
|
if exists("b:spotbugs_properties")
|
|
let s:spotbugs_properties_scope = 'b:'
|
|
|
|
" Merge global entries, if any, in buffer-local entries, favouring
|
|
" defined buffer-local ones.
|
|
call extend(
|
|
\ b:spotbugs_properties,
|
|
\ get(g:, 'spotbugs_properties', {}),
|
|
\ 'keep')
|
|
elseif exists("g:spotbugs_properties")
|
|
let s:spotbugs_properties_scope = 'g:'
|
|
endif
|
|
|
|
let s:commands = {}
|
|
|
|
for s:name in ['DefaultPreCompilerCommand',
|
|
\ 'DefaultPreCompilerTestCommand',
|
|
\ 'DefaultPostCompilerCommand']
|
|
if s:SpotBugsHasProperty(s:name)
|
|
let s:commands[s:name] = remove(
|
|
\ s:SpotBugsGetProperties(),
|
|
\ s:name)
|
|
endif
|
|
endfor
|
|
|
|
if s:SpotBugsHasProperty('compiler')
|
|
" XXX: Postpone loading the script until all state, if any, has been
|
|
" collected.
|
|
if !empty(s:commands)
|
|
let g:spotbugs#state = {
|
|
\ 'compiler': remove(s:SpotBugsGetProperties(), 'compiler'),
|
|
\ 'commands': copy(s:commands),
|
|
\ }
|
|
else
|
|
let g:spotbugs#state = {
|
|
\ 'compiler': remove(s:SpotBugsGetProperties(), 'compiler'),
|
|
\ }
|
|
endif
|
|
|
|
" Merge default entries in global (or buffer-local) entries, favouring
|
|
" defined global (or buffer-local) ones.
|
|
call extend(
|
|
\ {s:spotbugs_properties_scope}spotbugs_properties,
|
|
\ spotbugs#DefaultProperties(),
|
|
\ 'keep')
|
|
elseif !empty(s:commands)
|
|
" XXX: Postpone loading the script until all state, if any, has been
|
|
" collected.
|
|
let g:spotbugs#state = {'commands': copy(s:commands)}
|
|
endif
|
|
|
|
unlet s:commands s:name
|
|
let s:request = 0
|
|
|
|
if s:SpotBugsHasProperty('PostCompilerAction')
|
|
let s:request += 4
|
|
endif
|
|
|
|
if s:SpotBugsHasProperty('PreCompilerTestAction')
|
|
let s:dispatcher = printf('call call(%s, [])',
|
|
\ string(s:SpotBugsGetProperties().PreCompilerTestAction))
|
|
let s:request += 2
|
|
endif
|
|
|
|
if s:SpotBugsHasProperty('PreCompilerAction')
|
|
let s:dispatcher = printf('call call(%s, [])',
|
|
\ string(s:SpotBugsGetProperties().PreCompilerAction))
|
|
let s:request += 1
|
|
endif
|
|
|
|
" Adapt the tests for "s:FindClassFiles()" from "compiler/spotbugs.vim".
|
|
if (s:request == 3 || s:request == 7) &&
|
|
\ (!empty(s:SpotBugsGetProperty('sourceDirPath', [])) &&
|
|
\ !empty(s:SpotBugsGetProperty('classDirPath', [])) &&
|
|
\ !empty(s:SpotBugsGetProperty('testSourceDirPath', [])) &&
|
|
\ !empty(s:SpotBugsGetProperty('testClassDirPath', [])))
|
|
function! s:DispatchAction(paths_action_pairs) abort
|
|
let name = expand('%:p')
|
|
|
|
for [paths, Action] in a:paths_action_pairs
|
|
for path in paths
|
|
if name =~# (path . '.\{-}\.java\=$')
|
|
call Action()
|
|
return
|
|
endif
|
|
endfor
|
|
endfor
|
|
endfunction
|
|
|
|
let s:dir_cnt = min([
|
|
\ len(s:SpotBugsGetProperties().sourceDirPath),
|
|
\ len(s:SpotBugsGetProperties().classDirPath)])
|
|
let s:test_dir_cnt = min([
|
|
\ len(s:SpotBugsGetProperties().testSourceDirPath),
|
|
\ len(s:SpotBugsGetProperties().testClassDirPath)])
|
|
|
|
" Do not break up path pairs with filtering!
|
|
let s:dispatcher = printf('call s:DispatchAction(%s)',
|
|
\ string([[s:SpotBugsGetProperties().sourceDirPath[0 : s:dir_cnt - 1],
|
|
\ s:SpotBugsGetProperties().PreCompilerAction],
|
|
\ [s:SpotBugsGetProperties().testSourceDirPath[0 : s:test_dir_cnt - 1],
|
|
\ s:SpotBugsGetProperties().PreCompilerTestAction]]))
|
|
unlet s:test_dir_cnt s:dir_cnt
|
|
endif
|
|
|
|
if exists("s:dispatcher")
|
|
function! s:ExecuteActions(pre_action, post_action) abort
|
|
try
|
|
execute a:pre_action
|
|
catch /\<E42:/
|
|
execute a:post_action
|
|
endtry
|
|
endfunction
|
|
endif
|
|
|
|
if s:request
|
|
if exists("b:spotbugs_syntax_once") || empty(join(getline(1, 8), ''))
|
|
let s:actions = [{'event': 'User'}]
|
|
else
|
|
" XXX: Handle multiple FileType events when vimrc contains more
|
|
" than one filetype setting for the language, e.g.:
|
|
" :filetype plugin indent on
|
|
" :autocmd BufRead,BufNewFile *.java setlocal filetype=java ...
|
|
" XXX: DO NOT ADD b:spotbugs_syntax_once TO b:undo_ftplugin !
|
|
let b:spotbugs_syntax_once = 1
|
|
let s:actions = [{
|
|
\ 'event': 'Syntax',
|
|
\ 'once': 1,
|
|
\ }, {
|
|
\ 'event': 'User',
|
|
\ }]
|
|
endif
|
|
|
|
for s:idx in range(len(s:actions))
|
|
if s:request == 7 || s:request == 6 || s:request == 5
|
|
let s:actions[s:idx].cmd = printf('call s:ExecuteActions(%s, %s)',
|
|
\ string(s:dispatcher),
|
|
\ string(printf('compiler spotbugs | call call(%s, [])',
|
|
\ string(s:SpotBugsGetProperties().PostCompilerAction))))
|
|
elseif s:request == 4
|
|
let s:actions[s:idx].cmd = printf(
|
|
\ 'compiler spotbugs | call call(%s, [])',
|
|
\ string(s:SpotBugsGetProperties().PostCompilerAction))
|
|
elseif s:request == 3 || s:request == 2 || s:request == 1
|
|
let s:actions[s:idx].cmd = printf('call s:ExecuteActions(%s, %s)',
|
|
\ string(s:dispatcher),
|
|
\ string('compiler spotbugs'))
|
|
else
|
|
let s:actions[s:idx].cmd = ''
|
|
endif
|
|
endfor
|
|
|
|
if !exists("#java_spotbugs")
|
|
augroup java_spotbugs
|
|
augroup END
|
|
endif
|
|
|
|
" The events are defined in s:actions.
|
|
silent! autocmd! java_spotbugs User <buffer>
|
|
silent! autocmd! java_spotbugs Syntax <buffer>
|
|
|
|
for s:action in s:actions
|
|
if has_key(s:action, 'once')
|
|
execute printf('autocmd java_spotbugs %s <buffer> ' .
|
|
\ 'call JavaFileTypeExecuteActionOnce(%s, %s)',
|
|
\ s:action.event,
|
|
\ string(printf('autocmd! java_spotbugs %s <buffer>',
|
|
\ s:action.event)),
|
|
\ string(s:action.cmd))
|
|
else
|
|
execute printf('autocmd java_spotbugs %s <buffer> %s',
|
|
\ s:action.event,
|
|
\ s:action.cmd)
|
|
endif
|
|
endfor
|
|
|
|
if s:SpotBugsHasProperty('PostCompilerActionExecutor') &&
|
|
\ (s:request == 7 || s:request == 6 ||
|
|
\ s:request == 5 || s:request == 4)
|
|
let s:augroup = s:SpotBugsGetProperty(
|
|
\ 'augroupForPostCompilerAction',
|
|
\ 'java_spotbugs_post')
|
|
let s:augroup = !empty(s:augroup) ? s:augroup : 'java_spotbugs_post'
|
|
|
|
for s:candidate in ['java_spotbugs_post', s:augroup]
|
|
if !exists("#" . s:candidate)
|
|
execute printf('augroup %s | augroup END', s:candidate)
|
|
endif
|
|
endfor
|
|
|
|
silent! autocmd! java_spotbugs_post User <buffer>
|
|
|
|
" Define a User ":autocmd" to define a once-only ShellCmdPost
|
|
" ":autocmd" that will invoke "PostCompilerActionExecutor" and let
|
|
" it decide whether to proceed with ":compiler spotbugs" etc.; and
|
|
" seek explicit synchronisation with ":doautocmd ShellCmdPost" by
|
|
" omitting "nested" for "java_spotbugs_post" and "java_spotbugs".
|
|
execute printf('autocmd java_spotbugs_post User <buffer> ' .
|
|
\ 'call JavaFileTypeExecuteActionOnce(%s, %s)',
|
|
\ string(printf('autocmd! %s ShellCmdPost <buffer>', s:augroup)),
|
|
\ string(printf('autocmd %s ShellCmdPost <buffer> ' .
|
|
\ 'call JavaFileTypeExecuteActionOnce(%s, %s)',
|
|
\ s:augroup,
|
|
\ string(printf('autocmd! %s ShellCmdPost <buffer>', s:augroup)),
|
|
\ string(printf('call call(%s, [%s])',
|
|
\ string(s:SpotBugsGetProperties().PostCompilerActionExecutor),
|
|
\ string(printf('compiler spotbugs | call call(%s, [])',
|
|
\ string(s:SpotBugsGetProperties().PostCompilerAction))))))))
|
|
endif
|
|
|
|
unlet! s:candidate s:augroup s:action s:actions s:idx s:dispatcher
|
|
endif
|
|
|
|
delfunction s:SpotBugsGetProperties
|
|
delfunction s:SpotBugsHasProperty
|
|
delfunction s:SpotBugsGetProperty
|
|
unlet! s:request s:spotbugs_properties_scope
|
|
endif
|
|
|
|
function! JavaFileTypeCleanUp() abort
|
|
setlocal suffixes< suffixesadd< formatoptions< comments< commentstring< path< includeexpr<
|
|
unlet! b:browsefilter
|
|
|
|
" The concatenated ":autocmd" removals may be misparsed as an ":autocmd".
|
|
" A _once-only_ ShellCmdPost ":autocmd" is always a call-site definition.
|
|
silent! autocmd! java_spotbugs User <buffer>
|
|
silent! autocmd! java_spotbugs Syntax <buffer>
|
|
silent! autocmd! java_spotbugs_post User <buffer>
|
|
endfunction
|
|
|
|
" Undo the stuff we changed.
|
|
let b:undo_ftplugin = 'call JavaFileTypeCleanUp() | delfunction JavaFileTypeCleanUp'
|
|
|
|
" See ":help vim9-mix".
|
|
if !has("vim9script")
|
|
let &cpo = s:save_cpo
|
|
unlet s:save_cpo
|
|
finish
|
|
endif
|
|
|
|
if exists("s:zip_func_upgradable")
|
|
delfunction! JavaFileTypeZipFile
|
|
|
|
def! s:JavaFileTypeZipFile(): string
|
|
@/ = substitute(v:fname, '\.', '\\/', 'g') .. '.java'
|
|
return get(zip_files, bufnr('%'), zip_files[0])
|
|
enddef
|
|
|
|
setlocal includeexpr=s:JavaFileTypeZipFile()
|
|
setlocal suffixesadd<
|
|
endif
|
|
|
|
if exists("*s:DispatchAction")
|
|
def! s:DispatchAction(paths_action_pairs: list<list<any>>)
|
|
const name: string = expand('%:p')
|
|
|
|
for [paths: list<string>, Action: func: any] in paths_action_pairs
|
|
for path in paths
|
|
if name =~# (path .. '.\{-}\.java\=$')
|
|
Action()
|
|
return
|
|
endif
|
|
endfor
|
|
endfor
|
|
enddef
|
|
endif
|
|
|
|
" Restore the saved compatibility options.
|
|
let &cpo = s:save_cpo
|
|
unlet s:save_cpo
|
|
" vim: fdm=syntax sw=4 ts=8 noet sta
|