Vim
Metals works with most LSP clients for Vim:
vim-lsc
: simple installation and low resource usage but limited functionality (no auto-import, cancellation, formatting, folding).coc.nvim
: installation requires neovim or Vim v8.1 along with npm. Feature rich, supports all of LSP.LanguageClient-neovim
: client written in Rust.vim-lsp
: simple installation but limited functionality (no auto-import, cancellation and no prompt for build import).
In this page, we use coc.nvim
(Conquer Of Completion) since it offers a richer
user experience but the same steps can be adapted to use Metals with other LSP
clients.
Requirements
Java 8 or 11 provided by OpenJDK or Oracle. Eclipse OpenJ9 is not
supported, please make sure the JAVA_HOME
environment variable
points to a valid Java 8 or 11 installation.
macOS, Linux or Windows. Metals is developed on macOS and every PR is tested on Ubuntu+Windows.
Scala 2.13, 2.12 and 2.11. Metals supports these Scala versions 2.13.0, 2.13.1, 2.12.8, 2.12.9, 2.12.10, 2.12.7 and 2.11.12. Note that 2.11.x support is deprecated and it will be removed in future releases. It's recommended to upgrade to Scala 2.12 or Scala 2.13
Installing Vim
The coc.nvim plugin requires either Vim >= 8.1 or Neovim >= 0.3.1. Make sure you have the correct version installed.
# If using Vim
vim --version | head
VIM - Vi IMproved 8.1
# If using Neovim
nvim --version | head
NVIM v0.3.7
Installing yarn
coc.nvim
requires Node.js in order to work.
It also uses Yarn to manage
extensions but you could opt-out of it and use vim-plug
instead for example.
For convenience we recommend installing both:
curl -sL install-node.now.sh/lts | sh
curl --compressed -o- -L https://yarnpkg.com/install.sh | bash
Installing coc.nvim
Once the requirements are satisfied, we can now proceed to install the following plugins:
neoclide/coc.nvim
: Language Server Protocol client to communicate with the Metals language server.derekwyatt/vim-scala
: for syntax highlighting Scala and sbt source files.
Assuming vim-plug
is used (another
plugin manager like vundle works too), update ~/.vimrc
to include the
following settings.
" ~/.vimrc
" Configuration for vim-plug
Plug 'derekwyatt/vim-scala'
Plug 'neoclide/coc.nvim', {'do': { -> coc#util#install()}}
" Configuration for vim-scala
au BufRead,BufNewFile *.sbt set filetype=scala
Run :PlugInstall
to install the plugin. If you already have coc.nvim
installed, be sure to update to the latest version with :PlugUpdate
.
Configuration
We need to tell coc.nvim
that our LSP server is going to be metals
. In order
to do so, we need to run :CocConfig
and input our configuration. Here's the
recommended default:
// vim: ~/.vim/coc-settings.json
// neovim: ~/.config/nvim/coc-settings.json
{
"languageserver": {
"metals": {
"command": "metals-vim",
"rootPatterns": ["build.sbt"],
"filetypes": ["scala", "sbt"]
}
}
}
coc.nvim
uses jsonc as
configuration file format. It's basically json with comments support.
In order to get comments highlighting, please add:
autocmd FileType json syntax match Comment +\/\/.\+$+
Generating metals binary
If you now start Vim in a Scala project then it will fail since the metals-vim
binary does not exist yet.
Next, build a metals-vim
binary for the latest Metals release using the
Coursier command-line interface.
Version | Published | Resolver |
---|---|---|
0.7.7-SNAPSHOT | 10 Oct 2019 22:08 | -r sonatype:releases |
0.7.7-SNAPSHOT | 10 Oct 2019 22:08 | -r sonatype:snapshots |
# Make sure to use coursier v1.1.0-M9 or newer.
curl -L -o coursier https://git.io/coursier
chmod +x coursier
./coursier bootstrap \
--java-opt -Xss4m \
--java-opt -Xms100m \
--java-opt -Dmetals.client=coc.nvim \
org.scalameta:metals_2.12:0.7.7-SNAPSHOT \
-r bintray:scalacenter/releases \
-r sonatype:snapshots \
-o /usr/local/bin/metals-vim -f
Make sure the generated metals-vim
binary is available on your $PATH
.
Configure the system properties -Dhttps.proxyHost=… -Dhttps.proxyPort=…
if you are behind an HTTP proxy.
The -Dmetals.client=coc.nvim
flag is important since it configures Metals for
usage with the coc.nvim
client.
Importing a build
The first time you open Metals in a new workspace it prompts you to import the build. Click "Import build" to start the installation step.
- "Not now" disables this prompt for 2 minutes.
- "Don't show again" disables this prompt forever, use
rm -rf .metals/
to re-enable the prompt. - Use
tail -f .metals/metals.log
to watch the build import progress. - Behind the scenes, Metals uses Bloop to import sbt builds, but you don't need Bloop installed on your machine to run this step.
Once the import step completes, compilation starts for your open *.scala
files.
Once the sources have compiled successfully, you can navigate the codebase with goto definition.
Custom sbt launcher
By default, Metals runs an embedded sbt-launch.jar
launcher that respects .sbtopts
and .jvmopts
.
However, the environment variables SBT_OPTS
and JAVA_OPTS
are not respected.
Update the server property -Dmetals.sbt-script=/path/to/sbt
to use a custom
sbt
script instead of the default Metals launcher if you need further
customizations like reading environment variables.
Speeding up import
The "Import build" step can take a long time, especially the first time you run it in a new build. The exact time depends on the complexity of the build and if library dependencies need to be downloaded. For example, this step can take everything from 10 seconds in small cached builds up to 10-15 minutes in large uncached builds.
Consult the Bloop documentation to learn how to speed up build import.
Importing changes
When you change build.sbt
or sources under project/
, you will be prompted to
re-import the build.
LSP commands key mapping
coc.nvim
doesn't come with a default key mapping for LSP commands, you need to
configure it yourself.
Here's a recommended configuration:
" ~/.vimrc
" Configuration for coc.nvim
" Smaller updatetime for CursorHold & CursorHoldI
set updatetime=300
" don't give |ins-completion-menu| messages.
set shortmess+=c
" always show signcolumns
set signcolumn=yes
" Some server have issues with backup files, see #649
set nobackup
set nowritebackup
" Better display for messages
set cmdheight=2
" Use <c-space> for trigger completion.
inoremap <silent><expr> <c-space> coc#refresh()
" Use <cr> for confirm completion, `<C-g>u` means break undo chain at current position.
" Coc only does snippet and additional edit on confirm.
inoremap <expr> <cr> pumvisible() ? "\<C-y>" : "\<C-g>u\<CR>"
" Use `[c` and `]c` for 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)
" Remap for do codeAction of current line
nmap <leader>ac <Plug>(coc-codeaction)
" Remap for do action format
nnoremap <silent> F :call CocAction('format')<CR>
" Use K for show documentation in preview window
nnoremap <silent> K :call <SID>show_documentation()<CR>
function! s:show_documentation()
if &filetype == 'vim'
execute 'h '.expand('<cword>')
else
call CocAction('doHover')
endif
endfunction
" Highlight symbol under cursor on CursorHold
autocmd CursorHold * silent call CocActionAsync('highlight')
" Remap for rename current word
nmap <leader>rn <Plug>(coc-rename)
" Show all diagnostics
nnoremap <silent> <space>a :<C-u>CocList diagnostics<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>
Learn more about coc.nvim
For comprehensive documentation about coc.nvim
, run the following command.
:help coc-contents
List all workspace compile errors
To list all compilation errors and warnings in the workspace, run the following command.
:CocList diagnostics
Or use the default recommended mapping <space> a
.
This is helpful to see compilation errors in different files from your current open buffer.
Close buffer without exiting
To close a buffer and return to the previous buffer, run the following command.
:bd
This command is helpful when navigating in library dependency sources in the
.metals/readonly
directory.
Shut down the language server
The Metals server is shutdown when you exit vim as usual.
:wq
This step clean ups resources that are used by the server.
Run doctor
To troubleshoot problems with your build workspace execute the following command.
:call CocRequestAsync('metals', 'workspace/executeCommand', { 'command': 'doctor-run' })
This command opens your browser with a table like this.
Note: the binary metals-vim
needs to be built using -Dmetals.http=true
for
this command to work.
Manually start build import
To manually start the sbt bloopInstall
step, call the following command below.
This command works only for sbt builds at the moment.
:call CocRequestAsync('metals', 'workspace/executeCommand', { 'command': 'build-import' })
Manually connect with build server
To manually tell Metals to establish a connection with the build server, call
the command below. This command works only at the moment if there is a .bloop/
directory containing JSON files.
:call CocRequestAsync('metals', 'workspace/executeCommand', { 'command': 'build-connect' })
Show document symbols
Run :CocList outline
to show a symbol outline for the current file or use the
default key <space> o
.
.metals/
and .bloop/
Gitignore The Metals server places logs and other files in the .metals/
directory. The
Bloop compile server places logs and compilation artifacts in the .bloop
directory. It's recommended to ignore these directories from version control
systems like git.
# ~/.gitignore
.metals/
.bloop/