This time in my continuing forray into Java, I'm going to setup a Language Server Protocol for Neovim.

Quick Notes:

  • "LSP" stands for Language Server Protocol, and its an awesome standard invented by Microsoft for VSCode designed to help everyone stop reinventing the wheel. The gist is that anyone figures out how to do things like goto-definition for a programming language, all editors that speak the protocol can immediately start using that one implementation. I use this acronym excessively in this article, so I figure it's worth explaining here first :)
  • Probably not important, but just FYI I'm doing all this on Linux. Generally things will actually be easier for you on Mac or Windows (sorry BSDs) than for me.

TL;DR - OpenJDK11 + coc.nvim + coc-java

After trying some other things, I eventually found that Conquer-of-Complete (aka "CoC") really does JustWork (tm). Although, it doesn't advertise the Java LSP implementation, it's out there. The nice thing about this setup is that "coc-java" installs the underlying LSP (a small piece of Eclipse) for you and configures everything. The other thing I like about CoC compared to the nvim-lspconfig project is that CoC allows me to configure key bindings once for all LSPs.

Enough blathering, let's do this!

1. Install OpenJDK

Since I'm on Ubuntu 18.04 ("Bionic"), the most recent JDK available was 11, but really anything greater than Java 8 would have sufficed:

$ sudo apt-get install -y openjdk-11-jdk

The coc-java plugin will need to know where this is. I chose to tell the plugin like so:

set -xU JDK_HOME /usr/lib/jvm/java-1.11.0-openjdk-amd64

Yes, that's fish shell, not bash. It's the equivalent of adding export JDK_HOME=... in my .bashrc and then sourcing immediately.

2. Install coc.nvim plugin

Inside my ~/.config/nvim/init.vim, I added this to install the plugin using vim-plug:

Plug 'neoclide/coc.nvim', {'branch': 'release'}

Then restart Nvim and run :PlugInstall

3. Setup Keybindings

The most interesting bits of functionality to me to set key bindings for in the init.vim I've captured below:

nmap <silent> gd <Plug>(coc-definition)                               " GoTo definition
nmap <silent> gr <Plug>(coc-references)                               " GoTo references
nmap <leader>rn <Plug>(coc-rename)                                    " Rename symbol
nnoremap <silent><nowait> <space>a  :<C-u>CocList diagnostics<cr>     " Show all errors/warnings
nnoremap <silent><nowait> <space>c  :<C-u>CocList commands<cr>        " Kitchen sink of all LSP commands
nnoremap <silent><nowait> <space><S-s>  :<C-u>CocList -I symbols<cr>  " Fuzzy search for ALL symbols

4. Building Muscle Memory

Being a vi user is all about building habits so that we can achieve various actions reflexively. For me that means picking a small number of keybindings and practicing them intentionally.

One new thing I'm trying is to write down the above keybindings on a piece of paper taped to my monitor. My hope is that this will help me memorize these shortcuts a bit more "organically" and I can eventually throw the paper away or replace with new bindings I want to start memorizing.

Every 6-12 months, I'll weed out keybindings that didn't stick. Here's hoping that most of these keybindings are here for the long haul!