Contents

usable java setup vim

Vim + Java

This post covers a usable vim setup for writing java.

I assume that you are familiar enough with vim to be able to configure it, and install packages.

Code completion

The main part of writing java in vim is having decent code completion. We are going to use coc.nvim as the engine, and coc-java as the language server. Both are borrowed and forked from VSCode plugins.

  1. Install https://github.com/neoclide/coc.nvim
  2. In vim, run :CocInstall coc-java to install coc-java.

We can also install deoplete, which is a completion framework that can help with words and symbols that are already in the open document.

Useful config for coc-java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
""" -------
""" coc.nvim
""" -------

""" coc.nvim settings

set hidden
set cmdheight=2
set updatetime=300
set shortmess+=c
set signcolumn=yes

""" tab triggers and navigation
""" tab / shift-tab navigate, enter select

inoremap <silent><expr> <TAB>
      \ pumvisible() ? "\<C-n>" :
      \ <SID>check_back_space() ? "\<TAB>" :
      \ coc#refresh()
inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<C-h>"
inoremap <expr> <CR> pumvisible() ? "\<C-Y>" : "\<CR>"

function! s:check_back_space() abort
  let col = col('.') - 1
  return !col || getline('.')[col - 1]  =~# '\s'
endfunction

""" <c-space> to trigger completion.
inoremap <silent><expr> <c-space> coc#refresh()

""" `[c` and `]c` to navigate diagnostics
nmap <silent> [c <Plug>(coc-diagnostic-prev)
nmap <silent> ]c <Plug>(coc-diagnostic-next)

""" Remap keys for gotos
nmap <silent> gd <Plug>(coc-definition)
nmap <silent> gy <Plug>(coc-type-definition)
nmap <silent> gi <Plug>(coc-implementation)
nmap <silent> gr <Plug>(coc-references)

""" Use U to show documentation in preview window
function! s:show_documentation()
  if (index(['vim','help'], &filetype) >= 0)
    execute 'h '.expand('<cword>')
  else
    call CocAction('doHover')
  endif
endfunction
nnoremap <silent> U :call <SID>show_documentation()<CR>

""" rename current word
nmap <leader>rn <Plug>(coc-rename)

""" Remap for format selected region
vmap <leader>f  <Plug>(coc-format-selected)
nmap <leader>f  <Plug>(coc-format-selected)

""" Show all diagnostics
nnoremap <silent> <space>a  :<C-u>CocList diagnostics<cr>

""" Manage extensions
nnoremap <silent> <space>e  :<C-u>CocList extensions<cr>

""" Show commands
nnoremap <silent> <space>c  :<C-u>CocList commands<cr>

""" Find symbol of current document
nnoremap <silent> <space>o  :<C-u>CocList outline<cr>

""" Search workspace symbols
nnoremap <silent> <space>s  :<C-u>CocList -I symbols<cr>

""" Do default action for next item.
nnoremap <silent> <space>j  :<C-u>CocNext<CR>

""" Do default action for previous item.
nnoremap <silent> <space>k  :<C-u>CocPrev<CR>

""" Resume latest coc list
nnoremap <silent> <space>p  :<C-u>CocListResume<CR>

""" trigger CocAction popover
nnoremap <silent> <space>g :CocAction<CR>

""" highlight current symbol CocInstall('coc-highligh')
autocmd CursorHold * silent call CocActionAsync('highlight')

" Add `:Format` command to format current buffer.
command! -nargs=0 Format :call CocAction('format')

" Add `:OR` command for organize imports of the current buffer.
command! -nargs=0 OR   :call     CocAction('runCommand', 'editor.action.organizeImport')

File navigation

We can jump to files using ctrl-p

For file tree we can use nerdtree

To make these plugins nice to work with we can configure them as:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
""" -------
""" misc aliases
""" -------

"Remove all trailing whitespace by pressing F5
nnoremap <F5> :let _s=@/<Bar>:%s/\s\+$//e<Bar>:let @/=_s<Bar><CR>

:inoremap jj <Esc>

let g:ctrlp_custom_ignore = '\v[\/](node_modules|target|dist|build)|(\.(swp|ico|git|svn|class))$'

" write content of file automatically on :make, also applies go :GoXXX
" commands
set autowrite

""" -------
""" nerdtree
""" -------

" toggle nerdtree with ctrl-t
map <C-t> :NERDTreeToggle<CR>

" open nerdtree if we vim into a directory
autocmd StdinReadPre * let s:std_in=1
autocmd VimEnter * if argc() == 1 && isdirectory(argv()[0]) && !exists("s:std_in") | exe 'NERDTree' argv()[0] | wincmd p | ene | exe 'cd '.argv()[0] | endif

" close nerdtree if it's the last remaining buffer
autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTree") && b:NERDTree.isTabTree()) | q | endif

Unit tests

We can use vim-test to run our unit tests, it will delegate to maven or gradle, but you’ll need to set the test runner;

1
2
3
4
5
6
7
8
9
" to use gradle instead of maven
let test#java#runner = 'gradletest'

" map keys
nmap <silent> <leader>t :TestNearest<CR>
nmap <silent> <leader>T :TestFile<CR>
nmap <silent> <leader>a :TestSuite<CR>
nmap <silent> <leader>l :TestLast<CR>
nmap <silent> <leader>g :TestVisit<CR>

Missing pieces

With the plugins above we have code completion, language server, file navigation, and test runner. This makes it possible to write java in vim. We are still missing a few things.

Debugger

I am still to fix this, but I’ll be looking at https://github.com/puremourning/vimspector.