Configuring Vim for Java Development

Thu, Jan 11, 2018 8-minute read

Welcome back, my fellow Vimmers.

Today I will show you how to convert (Neo)Vim into a Java IDE. We will be discussing multiple plugins, mappings, and external tools in this post.

Plugins

So in my .vimrc I have a plethora of different plugins directly related to Java development.

Also we will be assuming that you have vim-plug installed as you plugin manager. If you don’t, I recommend getting it. but if you don’t want to make the switch you can find all of the installation instructions on the plugins GitHub.

BE SURE TO RUN :PlugInstall WHEN WE ARE DONE!

Deoplete.nvim

So autocompletion in programming has been a hot topic recently. As many developers are claiming that we rely too much on autocompletion and don’t learn as much about the actual syntax of the language. I disagree. I think that developers use autocompleting to be faster at what we do!

Note: this plugin only works on NeoVim. Or with Vim 8 and python support installed

deoplete

Installation

To install Deoplete add the following to your .vimrc

" Code completion
if has('nvim')
  Plug 'Shougo/deoplete.nvim', { 'do': ':UpdateRemotePlugins' }
else
  Plug 'Shougo/deoplete.nvim'
  Plug 'roxma/nvim-yarp'
  Plug 'roxma/vim-hug-neovim-rpc'
endif

Configuration

I recommend adding the following to your .vimrc:

" Don't forget to start deoplete let g:deoplete#enable_at_startup = 1 " Less spam let g:deoplete#auto_complete_start_length = 2 
" Use smartcase
let g:deoplete#enable_smart_case = 1


" Setup completion sources
let g:deoplete#sources = {}

" IMPORTANT: PLEASE INSTALL JAVACOMPLETE2  AND ULTISNIPS OR DONT ADD THIS LINE!
" =====================================

let g:deoplete#sources.java = ['jc', 'javacomplete2', 'file', 'buffer', 'ultisnips']

" =====================================

""use TAB as the mapping
inoremap <silent><expr> <TAB>
    \ pumvisible() ?  "\<C-n>" :
    \ <SID>check_back_space() ? "\<TAB>" :
    \ deoplete#mappings#manual_complete()
function! s:check_back_space() abort "" {{{
    let col = col('.') - 1
    return !col || getline('.')[col - 1]  =~ '\s'
endfunction "" }}}

Now you’re ready to go!

Vim-Javacomplete2

So now that we have a working completion plugin for vim let’s get some Java syntax up in there.

Installation

Install the plugin by adding the following to your .vimrc

" Java-completion
Plug 'junegunn/vim-javacomplete2'

OR if you have a fast machine

" Java-completion
Plug 'junegunn/vim-javacomplete2', {'for': 'java'} " Load only for java files 

Configuring

To get completion automatically when you open a Java file, add this to your .vimrc

" Java completion
autocmd FileType java setlocal omnifunc=javacomplete#Complete
autocmd FileType java JCEnable

ALE

Another great plugin I use (not just for Java) is ALE. Which stands for Asynchronous Linting Engine, which basically means that it tells you if you miswrote any code, and it’s really fast.

You can use ale for other languages than just Java, it has a long list of support including python. C#, C++, Lua, Haskell, JavaScript (yes including node.js), a full list is available here

ale

Installation

So in order to magically fix all your code… add the following to your .vimrc

Plug 'w0rp-ale'

You’re done.

Configuring

Add this and your brand new linter will work!

" Shorten error/warning flags
let g:ale_echo_msg_error_str = 'E'
let g:ale_echo_msg_warning_str = 'W'
" I have some custom icons for errors and warnings but feel free to change them.
let g:ale_sign_error = '✘✘'
let g:ale_sign_warning = '⚠⚠'

" Disable or enable loclist at the bottom of vim 
" Comes down to personal preferance.
let g:ale_open_list = 0
let g:ale_loclist = 0


" Setup compilers for languages

let g:ale_linters = {
      \  'cs':['syntax', 'semantic', 'issues'],
      \  'python': ['pylint'],
      \  'java': ['javac']
      \ }

That’s it. Now enjoy your nonerroneous code!

UltiSnips

Another tool I like to use is Ultisnips, a snippet manager worthy of your time. For those of you who don’t know what a snippet is: Wikipedia - Snippet

Note: This one takes a bit longer to set up. But can be extremely rewarding.

ultisnips

Installation

Install the plugin by adding the following to your .vimrc

" Snippet manager
Plug 'SirVer/ultisnips'

Configuring

So as a mentioned above this one takes a lot longer to setup, so grab your popcorn ladies and gentlemen…

.vimrc config

" Trigger configuration. Do not use <tab> if you use https://github.com/Valloric/YouCompleteMe.

" Since we are already using Deoplete, and using tab with both doesn't work nice use <c-j> instead
let g:UltiSnipsExpandTrigger="<c-j>"
let g:UltiSnipsJumpForwardTrigger="<c-b>"
let g:UltiSnipsJumpBackwardTrigger="<c-z>"

" If you want :UltiSnipsEdit to split your window.
let g:UltiSnipsEditSplit="vertical"

let g:UltiSnipsSnippetDirectories = ['~/.vim/UltiSnips', 'UltiSnips']
let g:UltiSnipsSnippetsDir="~/.vim/UltiSnips"

Alright now that we have set up Vim to use snippets. Let’s add some to our Ultisnips directory.

cd ~/.vim/UltiSnips/

Now that we are here, add some snippets files depending on what programming language you want.

touch ./<programming language here>.snippets

Since this a Java guide, I will be using Java, but you get the point.

Adding snippets

Now it is time to add some snippets. For example, my java.snippets might look something like:

priority 10


# System.out.println();
snippet sout "System.out.println();" bA
System.out.println($0);
endsnippet

snippet br "break" bA
break;
endsnippet

snippet cs "case" b
case $1:
    $2
$0
endsnippet

snippet ca "catch" b
catch (${1:Exception} ${2:e})`!p nl(snip)`{
    $0
}
endsnippet

# Main method for Java Class
snippet main "public static void main()" bA
public static void main (String[] args){
    $0
}
endsnippet

# if statement
snippet if "If this then that" bA
if ($1){
    $2
}
$3
endsnippet

# Else if statement
snippet elif "else if this then that" bA
else if ($1){
    $2
}
$3
endsnippet

snippet for "for(int i; i < imax; i++)" bA
for ($1; $2; $3){
    $4
}

endsnippet

This allows me to type sout and get System.out.println();, or br turns to break;, or ca to catch (e). There are a lot more snippets in this file which I won’t get into detail for your sake. But if you’re interested you can read more here.

TagBar

Another tool I like using is TagBar a tool that shows you the methods variables and more in a buffer to the right of your file

tagbar

Installation

You can install TagBar by adding the following to your .vimrc

Plug 'majutsushi/tagbar'

Configuring

To open TagBar do :TagbarToggle

or add the following to your .vimrc

" Ctrl-b to open Tagbar
map <C-b> :TagbarToggle<CR>

Now you can use Ctrl-b to open Tagbar.

CtrlP.vim

Ctrlp is a great fuzzy finder which can be configured to use faster tools than grep. It can search buffers, files, and more!

ctrlp

Installation

You can install Ctrl-P by adding the following to your .vimrc

Plug 'ctrlpvim/ctrlp.vim'

Configuring

Map Ctrl-p to open Ctrl-p.

let g:ctrlp_map = '<c-p>'
let g:ctrlp_cmd = 'CtrlP'

" use current git repo/file director with ctrl p
let g:ctrlp_working_path_mode = 'ra'

NERD TREE

NERD TREE is an advance netrw replacement for Vim, I am not saying that there is anything wrong with netrw. However, I do think many would agree with me when I say that NERD TREE is more user freindly.

nerdtree

Some things you can do with NERD TREE includes:

  • Manages files
    • Move
    • Rename
    • Delete
    • Create
  • Check git statuses (i.e. install nerdtree-git-plugin)
  • Change working directory

Installation

You can install NERD TREE by adding the following to your .vimrc

Plug 'scrooloose/nerdtree'

Configuring

Add this to your .vimrc

" Open when no files were speficied on vim launch
autocmd StdinReadPre * let s:std_in=1
autocmd VimEnter * if argc() == 0 && !exists("s:std_in") | NERDTree | endif

" Toggle nerdtree
map <C-n> :NERDTreeToggle<CR>

Now you can use your new file tree.

Mappings

Now we will go over some shortcuts you can add to your .vimrc

Quick Compile

Auto compile java with leader-m

" Easy compile java in vim
autocmd FileType java set makeprg=javac\ %
set errorformat=%A%f:%l:\ %m,%-Z%p^,%-C.%#

Loc List (ALE Output)

Open and close ALEs output window with leader-e leader-w

"Loc List
map <leader>e :lopen<CR>
map <leader>w :lclose<CR>

External Tools

Use RipGrep (RG) with Ctrlp

  1. Make sure RipGrep is installed

  2. Add the following to your .vimrc

function! CtrlPCommand()
  let c = 0
  let wincount = winnr('$')
  " Don't open it here if current buffer is not writable (e.g. NERDTree)
  while !empty(getbufvar(+expand("<abuf>"), "&buftype")) && c < wincount
    exec 'wincmd w'
    let c = c + 1
  endwhile
  exec 'CtrlP'
endfunction
let g:ctrlp_cmd = 'call CtrlPCommand()'

"RipGrep
if executable('rg')
  set grepprg=rg\ --color=never
  let g:ctrlp_user_command = 'rg %s --files --color=never --glob ""'
  let g:ctrlp_use_caching = 0
endif
let g:ctrlp_custom_ignore = {
      \ 'dir':  '',
      \ 'file': '\.so$\|\.dat$|\.DS_Store$|\.meta|\.zip|\.rar|\.ipa|\.apk',
      \ }
  1. Profit!

Java compilers and command-line tools

  1. Install the OpenJDK for your Java version these tend to perform better with Vim plugins and Linux.

  2. I have heard good things about JavaKit as an ALE compiler. Let me know what you think.

Conclusion

Now that you have finished setting up your own VimJ IDE. You can now write some Java code in the coziness of your favorite text editor!

tl;dr

Wow, you’re finally done! How does it feel?

Oh, wait a minute… you didn’t actually read this now did you?

Whats this you want me to make a tl;dr?

Shame on YOU. You should know by now just how important it is to know everything that is in your vimrc! But fine, if you insist.

call plug#begin('~/.vim/bundle')

Plug 'Shougo/deoplete.nvim'
Plug 'artur-shaik/vim-javacomplete2' " , { 'for': 'java'}
Plug 'majutsushi/tagbar', { 'on': 'TagbarToggle' }
Plug 'SirVer/ultisnips'
Plug 'scrooloose/nerdtree', { 'on': ['NERDTreeToggle', 'NERDTreeFind'] }
Plug 'w0rp/ale'
Plug 'ctrlpvim/ctrlp.vim'

call plug#end()
"Ctrlp Settings {{{

let g:ctrlp_map = '<c-p>'

let g:ctrlp_cmd = 'ctrlp'
let g:ctrlp_dont_split = 'nerd'
let g:ctrlp_working_path_mode = 'rw'
set wildignore+=*/.git/*,*/tmp/*,*.swp/*,*/node_modules/*,*/temp/*,*/Builds/*,*/ProjectSettings/*
" Set no max file limit
let g:ctrlp_max_files = 0
" Search from current directory instead of project root


function! CtrlPCommand()
  let c = 0
  let wincount = winnr('$')
  " Don't open it here if current buffer is not writable (e.g. NERDTree)
  while !empty(getbufvar(+expand("<abuf>"), "&buftype")) && c < wincount
    exec 'wincmd w'
    let c = c + 1
  endwhile
  exec 'CtrlP'
endfunction
let g:ctrlp_cmd = 'call CtrlPCommand()'

"RipGrep
if executable('rg')
  set grepprg=rg\ --color=never
  let g:ctrlp_user_command = 'rg %s --files --color=never --glob ""'
  let g:ctrlp_use_caching = 0
endif
let g:ctrlp_custom_ignore = {
      \ 'dir':  '',
      \ 'file': '\.so$\|\.dat$|\.DS_Store$|\.meta|\.zip|\.rar|\.ipa|\.apk',
      \ }
" }}}
"Ale Settings {{{

let g:ale_echo_msg_error_str = 'E'
let g:ale_echo_msg_warning_str = 'W'
let g:ale_sign_error = '✘✘'
let g:ale_sign_warning = '⚠⚠'
let g:ale_open_list = 0
let g:ale_loclist = 0
"g:ale_javascript_eslint_use_global = 1
let g:ale_linters = {
      \  'cs':['syntax', 'semantic', 'issues'],
      \  'python': ['pylint'],
      \  'java': ['javac']
      \ }
" }}}
" Deoplete {{{

let g:deoplete#enable_at_startup = 1

let g:deoplete#auto_complete_start_length = 2
let g:deoplete#sources = {}
let g:deoplete#sources._=['buffer', 'ultisnips', 'file', 'dictionary']
let g:deoplete#sources.javascript = ['tern', 'omni', 'file', 'buffer', 'ultisnips']

" Use smartcase.
let g:deoplete#enable_smart_case = 1


"set completeopt-=preview

""use TAB as the mapping
inoremap <silent><expr> <TAB>
      \ pumvisible() ?  "\<C-n>" :
      \ <SID>check_back_space() ? "\<TAB>" :
      \ deoplete#mappings#manual_complete()
function! s:check_back_space() abort "" {{{
  let col = col('.') - 1
  return !col || getline('.')[col - 1]  =~ '\s'
endfunction "" }}}
" }}}
" UltiSnips {{{

" Trigger configuration. Do not use <tab> if you use https://github.com/Valloric/YouCompleteMe.
let g:UltiSnipsExpandTrigger="<c-j>"
let g:UltiSnipsJumpForwardTrigger="<c-b>"
let g:UltiSnipsJumpBackwardTrigger="<c-z>"

" If you want :UltiSnipsEdit to split your window.
let g:UltiSnipsEditSplit="vertical"

let g:UltiSnipsSnippetDirectories = ['~/.vim/UltiSnips', 'UltiSnips']
let g:UltiSnipsSnippetsDir="~/.vim/UltiSnips"

" }}}
" Java {{{

" Easy compile java in vim
autocmd FileType java set makeprg=javac\ %
set errorformat=%A%f:%l:\ %m,%-Z%p^,%-C.%#
" Java completion
autocmd FileType java setlocal omnifunc=javacomplete#Complete
autocmd FileType java JCEnable
" }}}