neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

spotbugs.vim (10781B)


      1 " Default pre- and post-compiler actions and commands for SpotBugs
      2 " Maintainers:  @konfekt and @zzzyxwvut
      3 " Last Change:  2024 Dec 08
      4 
      5 let s:save_cpo = &cpo
      6 set cpo&vim
      7 
      8 " Look for the setting of "g:spotbugs#state" in "ftplugin/java.vim".
      9 let s:state = get(g:, 'spotbugs#state', {})
     10 let s:commands = get(s:state, 'commands', {})
     11 let s:compiler = get(s:state, 'compiler', '')
     12 let s:readable = filereadable($VIMRUNTIME . '/compiler/' . s:compiler . '.vim')
     13 
     14 if has_key(s:commands, 'DefaultPreCompilerCommand')
     15  let g:SpotBugsPreCompilerCommand = s:commands.DefaultPreCompilerCommand
     16 else
     17 
     18  function! s:DefaultPreCompilerCommand(arguments) abort
     19    execute 'make ' . a:arguments
     20    cc
     21  endfunction
     22 
     23  let g:SpotBugsPreCompilerCommand = function('s:DefaultPreCompilerCommand')
     24 endif
     25 
     26 if has_key(s:commands, 'DefaultPreCompilerTestCommand')
     27  let g:SpotBugsPreCompilerTestCommand = s:commands.DefaultPreCompilerTestCommand
     28 else
     29 
     30  function! s:DefaultPreCompilerTestCommand(arguments) abort
     31    execute 'make ' . a:arguments
     32    cc
     33  endfunction
     34 
     35  let g:SpotBugsPreCompilerTestCommand = function('s:DefaultPreCompilerTestCommand')
     36 endif
     37 
     38 if has_key(s:commands, 'DefaultPostCompilerCommand')
     39  let g:SpotBugsPostCompilerCommand = s:commands.DefaultPostCompilerCommand
     40 else
     41 
     42  function! s:DefaultPostCompilerCommand(arguments) abort
     43    execute 'make ' . a:arguments
     44  endfunction
     45 
     46  let g:SpotBugsPostCompilerCommand = function('s:DefaultPostCompilerCommand')
     47 endif
     48 
     49 if v:version > 900 || has('nvim')
     50 
     51  function! spotbugs#DeleteClassFiles() abort
     52    if !exists('b:spotbugs_class_files')
     53      return
     54    endif
     55 
     56    for pathname in b:spotbugs_class_files
     57      let classname = pathname =~# "^'.\\+\\.class'$"
     58          \ ? eval(pathname)
     59          \ : pathname
     60 
     61      if classname =~# '\.class$' && filereadable(classname)
     62        " Since v9.0.0795.
     63        let octad = readblob(classname, 0, 8)
     64 
     65        " Test the magic number and the major version number (45 for v1.0).
     66        " Since v9.0.2027.
     67        if len(octad) == 8 && octad[0 : 3] == 0zcafe.babe &&
     68              " Nvim: no << operator
     69              "\ or((octad[6] << 8), octad[7]) >= 45
     70              \ or((octad[6] * 256), octad[7]) >= 45
     71          echomsg printf('Deleting %s: %d', classname, delete(classname))
     72        endif
     73      endif
     74    endfor
     75 
     76    let b:spotbugs_class_files = []
     77  endfunction
     78 
     79 else
     80 
     81  function! s:DeleteClassFilesWithNewLineCodes(classname) abort
     82    " The distribution of "0a"s in class file versions 2560 and 2570:
     83    "
     84    " 0zca.fe.ba.be.00.00.0a.00    0zca.fe.ba.be.00.00.0a.0a
     85    " 0zca.fe.ba.be.00.0a.0a.00    0zca.fe.ba.be.00.0a.0a.0a
     86    " 0zca.fe.ba.be.0a.00.0a.00    0zca.fe.ba.be.0a.00.0a.0a
     87    " 0zca.fe.ba.be.0a.0a.0a.00    0zca.fe.ba.be.0a.0a.0a.0a
     88    let numbers = [0, 0, 0, 0, 0, 0, 0, 0]
     89    let offset = 0
     90    let lines = readfile(a:classname, 'b', 4)
     91 
     92    " Track NL byte counts to handle files of less than 8 bytes.
     93    let nl_cnt = len(lines)
     94    " Track non-NL byte counts for "0zca.fe.ba.be.0a.0a.0a.0a".
     95    let non_nl_cnt = 0
     96 
     97    for line in lines
     98      for idx in range(strlen(line))
     99        " Remap NLs to Nuls.
    100        let numbers[offset] = (line[idx] == "\n") ? 0 : char2nr(line[idx]) % 256
    101        let non_nl_cnt += 1
    102        let offset += 1
    103 
    104        if offset > 7
    105          break
    106        endif
    107      endfor
    108 
    109      let nl_cnt -= 1
    110 
    111      if offset > 7 || (nl_cnt < 1 && non_nl_cnt > 4)
    112        break
    113      endif
    114 
    115      " Reclaim NLs.
    116      let numbers[offset] = 10
    117      let offset += 1
    118 
    119      if offset > 7
    120        break
    121      endif
    122    endfor
    123 
    124    " Test the magic number and the major version number (45 for v1.0).
    125    if offset > 7 && numbers[0] == 0xca && numbers[1] == 0xfe &&
    126          \ numbers[2] == 0xba && numbers[3] == 0xbe &&
    127          \ (numbers[6] * 256 + numbers[7]) >= 45
    128      echomsg printf('Deleting %s: %d', a:classname, delete(a:classname))
    129    endif
    130  endfunction
    131 
    132  function! spotbugs#DeleteClassFiles() abort
    133    if !exists('b:spotbugs_class_files')
    134      return
    135    endif
    136 
    137    let encoding = &encoding
    138 
    139    try
    140      set encoding=latin1
    141 
    142      for pathname in b:spotbugs_class_files
    143        let classname = pathname =~# "^'.\\+\\.class'$"
    144            \ ? eval(pathname)
    145            \ : pathname
    146 
    147        if classname =~# '\.class$' && filereadable(classname)
    148          let line = get(readfile(classname, 'b', 1), 0, '')
    149          let length = strlen(line)
    150 
    151          " Test the magic number and the major version number (45 for v1.0).
    152          if length > 3 && line[0 : 3] == "\xca\xfe\xba\xbe"
    153            if length > 7 && ((line[6] == "\n" ? 0 : char2nr(line[6]) % 256) * 256 +
    154                    \ (line[7] == "\n" ? 0 : char2nr(line[7]) % 256)) >= 45
    155              echomsg printf('Deleting %s: %d', classname, delete(classname))
    156            else
    157              call s:DeleteClassFilesWithNewLineCodes(classname)
    158            endif
    159          endif
    160        endif
    161      endfor
    162    finally
    163      let &encoding = encoding
    164    endtry
    165 
    166    let b:spotbugs_class_files = []
    167  endfunction
    168 
    169 endif
    170 
    171 function! spotbugs#DefaultPostCompilerAction() abort
    172  " Since v7.4.191.
    173  call call(g:SpotBugsPostCompilerCommand, ['%:S'])
    174 endfunction
    175 
    176 if s:readable && s:compiler ==# 'maven' && executable('mvn')
    177 
    178  function! spotbugs#DefaultPreCompilerAction() abort
    179    call spotbugs#DeleteClassFiles()
    180    compiler maven
    181    call call(g:SpotBugsPreCompilerCommand, ['compile'])
    182  endfunction
    183 
    184  function! spotbugs#DefaultPreCompilerTestAction() abort
    185    call spotbugs#DeleteClassFiles()
    186    compiler maven
    187    call call(g:SpotBugsPreCompilerTestCommand, ['test-compile'])
    188  endfunction
    189 
    190  function! spotbugs#DefaultProperties() abort
    191    return {
    192        \ 'PreCompilerAction':
    193            \ function('spotbugs#DefaultPreCompilerAction'),
    194        \ 'PreCompilerTestAction':
    195            \ function('spotbugs#DefaultPreCompilerTestAction'),
    196        \ 'PostCompilerAction':
    197            \ function('spotbugs#DefaultPostCompilerAction'),
    198        \ 'sourceDirPath':      ['src/main/java'],
    199        \ 'classDirPath':       ['target/classes'],
    200        \ 'testSourceDirPath':  ['src/test/java'],
    201        \ 'testClassDirPath':   ['target/test-classes'],
    202        \ }
    203  endfunction
    204 
    205  unlet s:readable s:compiler
    206 elseif s:readable && s:compiler ==# 'ant' && executable('ant')
    207 
    208  function! spotbugs#DefaultPreCompilerAction() abort
    209    call spotbugs#DeleteClassFiles()
    210    compiler ant
    211    call call(g:SpotBugsPreCompilerCommand, ['compile'])
    212  endfunction
    213 
    214  function! spotbugs#DefaultPreCompilerTestAction() abort
    215    call spotbugs#DeleteClassFiles()
    216    compiler ant
    217    call call(g:SpotBugsPreCompilerTestCommand, ['compile-test'])
    218  endfunction
    219 
    220  function! spotbugs#DefaultProperties() abort
    221    return {
    222        \ 'PreCompilerAction':
    223            \ function('spotbugs#DefaultPreCompilerAction'),
    224        \ 'PreCompilerTestAction':
    225            \ function('spotbugs#DefaultPreCompilerTestAction'),
    226        \ 'PostCompilerAction':
    227            \ function('spotbugs#DefaultPostCompilerAction'),
    228        \ 'sourceDirPath':      ['src'],
    229        \ 'classDirPath':       ['build/classes'],
    230        \ 'testSourceDirPath':  ['test'],
    231        \ 'testClassDirPath':   ['build/test/classes'],
    232        \ }
    233  endfunction
    234 
    235  unlet s:readable s:compiler
    236 elseif s:readable && s:compiler ==# 'javac' && executable('javac')
    237  let s:filename = tempname()
    238 
    239  function! spotbugs#DefaultPreCompilerAction() abort
    240    call spotbugs#DeleteClassFiles()
    241    compiler javac
    242 
    243    if get(b:, 'javac_makeprg_params', get(g:, 'javac_makeprg_params', '')) =~ '\s@\S'
    244      " Only read options and filenames from @options [@sources ...] and do
    245      " not update these files when filelists change.
    246      call call(g:SpotBugsPreCompilerCommand, [''])
    247    else
    248      " Collect filenames so that Javac can figure out what to compile.
    249      let filelist = []
    250 
    251      for arg_num in range(argc(-1))
    252        let arg_name = argv(arg_num)
    253 
    254        if arg_name =~# '\.java\=$'
    255          call add(filelist, fnamemodify(arg_name, ':p:S'))
    256        endif
    257      endfor
    258 
    259      for buf_num in range(1, bufnr('$'))
    260        if !buflisted(buf_num)
    261          continue
    262        endif
    263 
    264        let buf_name = bufname(buf_num)
    265 
    266        if buf_name =~# '\.java\=$'
    267          let buf_name = fnamemodify(buf_name, ':p:S')
    268 
    269          if index(filelist, buf_name) < 0
    270            call add(filelist, buf_name)
    271          endif
    272        endif
    273      endfor
    274 
    275      noautocmd call writefile(filelist, s:filename)
    276      call call(g:SpotBugsPreCompilerCommand, [shellescape('@' . s:filename)])
    277    endif
    278  endfunction
    279 
    280  function! spotbugs#DefaultPreCompilerTestAction() abort
    281    call spotbugs#DefaultPreCompilerAction()
    282  endfunction
    283 
    284  function! spotbugs#DefaultProperties() abort
    285    return {
    286        \ 'PreCompilerAction':
    287            \ function('spotbugs#DefaultPreCompilerAction'),
    288        \ 'PostCompilerAction':
    289            \ function('spotbugs#DefaultPostCompilerAction'),
    290        \ }
    291  endfunction
    292 
    293  unlet s:readable s:compiler g:SpotBugsPreCompilerTestCommand
    294  delfunction! s:DefaultPreCompilerTestCommand
    295 else
    296 
    297  function! spotbugs#DefaultPreCompilerAction() abort
    298    echomsg printf('Not supported: "%s"', s:compiler)
    299  endfunction
    300 
    301  function! spotbugs#DefaultPreCompilerTestAction() abort
    302    call spotbugs#DefaultPreCompilerAction()
    303  endfunction
    304 
    305  function! spotbugs#DefaultProperties() abort
    306    return {}
    307  endfunction
    308 
    309  " XXX: Keep "s:compiler" around for "spotbugs#DefaultPreCompilerAction()",
    310  " "s:DefaultPostCompilerCommand" -- "spotbugs#DefaultPostCompilerAction()".
    311  unlet s:readable g:SpotBugsPreCompilerCommand g:SpotBugsPreCompilerTestCommand
    312  delfunction! s:DefaultPreCompilerCommand
    313  delfunction! s:DefaultPreCompilerTestCommand
    314 endif
    315 
    316 function! s:DefineBufferAutocmd(event, ...) abort
    317  if !exists('#java_spotbugs#User')
    318    return 1
    319  endif
    320 
    321  for l:event in insert(copy(a:000), a:event)
    322    if l:event != 'User'
    323      execute printf('silent! autocmd! java_spotbugs %s <buffer>', l:event)
    324      execute printf('autocmd java_spotbugs %s <buffer> doautocmd User', l:event)
    325    endif
    326  endfor
    327 
    328  return 0
    329 endfunction
    330 
    331 function! s:RemoveBufferAutocmd(event, ...) abort
    332  if !exists('#java_spotbugs')
    333    return 1
    334  endif
    335 
    336  for l:event in insert(copy(a:000), a:event)
    337    if l:event != 'User'
    338      execute printf('silent! autocmd! java_spotbugs %s <buffer>', l:event)
    339    endif
    340  endfor
    341 
    342  return 0
    343 endfunction
    344 
    345 " Documented in ":help compiler-spotbugs".
    346 command! -bar -nargs=+ -complete=event SpotBugsDefineBufferAutocmd
    347    \ call s:DefineBufferAutocmd(<f-args>)
    348 command! -bar -nargs=+ -complete=event SpotBugsRemoveBufferAutocmd
    349    \ call s:RemoveBufferAutocmd(<f-args>)
    350 
    351 let &cpo = s:save_cpo
    352 unlet s:commands s:state s:save_cpo
    353 
    354 " vim: set foldmethod=syntax shiftwidth=2 expandtab: