coc-metals
coc-metals
is the recommended coc.nvim
extension for Metals, the
Scala language server. coc-metals
offers automated Metals installation, easy configuration,
Metals-specific commands, an embedded doctor, implementation of the decoration protocol, and many other small features.
NOTE: The readme is up-to-date with the master branch, so not all features
will be available if you're using the latest stable release. The vim
page on the Metals site is synced with the
latest stable release
Table of Contents
Requirements
coc-metals
works with both Vim and Neovim, but
we recommend neovim for a smoother experience and extra features such as the decoration protocol.
- coc.nvim - There are detailed instructions in their repo on
how to get set up and running quickly.
- 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.
coc.nvim
doesn't come with a default mapping for LSP commands, so you need to configure this in
order for any of the commands to work. You can find an example configuration and instructions
here
Installing coc-metals
Once you have coc.nvim
installed, you can then install Metals a few different ways, but the
easiest is by running.
:CocInstall coc-metals
If you'd like to use the latest changes on master, you can also just build from source by using
:CocInstall
with the repository url.
:CocInstall https://github.com/scalameta/coc-metals
If you'd like to use the latest changes on master, but manage it using a plugin
manager to download the extension, then if you are using vim-plug
for example, enter the following into where you manage your plugins:
Plug 'scalameta/coc-metals', {'do': 'yarn install --frozen-lockfile'}
Then, issue a :PlugInstall
to install the extension, and regularly a :PlugUpdate
to update it
and pull in the latest changes.
*** Keep in mind that if you are installing directly from the repo via :CocInstall
with the
repository url or through a plugin manager, remove coc-metals
with :CocUninstall coc-metals
before you add it in with one of the other methods to not conflict with one another.
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 metals.sbtScript setting 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.
Configure Java version
The coc-metals
extension uses by default the JAVA_HOME
environment variable
(via find-java-home
) to locate the java
executable.
If no JAVA_HOME
is detected you can then Open Settings by following the instructions or do it at
a later time by using :CocConfig
or :CocConfigLocal
which will open up your configuration where
you can manually enter your JAVA_HOME location.
coc.nvim
uses jsonc as
a configuration file format. It's basically json with comment support.
In order to get comment highlighting, please add:
autocmd FileType json syntax match Comment +\/\/.\+$+
Using latest Metals SNAPSHOT
Update the "Server Version" setting to try out the latest pending Metals
features.
After updating the version, you'll be triggered to reload the window.
This will be necessary before the new version will be downloaded and used.
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.
Run doctor
To troubleshoot problems with your build workspace, open your coc commands by either
using :CocCommand
or the recommend mapping <space> c
. This will open your command
window allowing you to search for metals.doctor-run
command.
This command opens an embedded doctor in your preview window. If you're not familiar with
having multiple windows, you can use <C-w> + w
to jump into it.
Worksheets
Metals allows users to create a *.worksheet.sc
file and see evaluations right in the file. In Vim,
this is done using comments that are inserted which will allow you to hover on them to expand. In
Neovim, this is done using Neovim's virtual text
to implement Metal's Decoration Protocol.
If using Neovim, make sure to have the following line in included in your .vimrc
along with your coc.nvim
mappings.
nmap <Leader>ws <Plug>(coc-metals-expand-decoration)
Then, when on the line that you'd like to expand the decoration to get the hover information, execute a
<leader>ws
in order to see the expanded text for that line.
Tree View Protocol
coc-metals has a built-in implementation of the Tree View Protocol.
If you have the recommended mappings copied, you'll notice
that in the bottom you'll have some TVP related settings. You can start by
opening the TVP panel by using the default <space> t
. Once open, you'll see
there are two parts to the panel. The first being the MetalsCompile
where you
can see the status of ongoing compilations for your modules and also options to
compile.
You are able to trigger the compiles while being on top of the option you are
attempting to trigger and pressing r
. You can change this default in the
settings. You can find all the relevant TVP settings below in the Available Configuration Options.
The second part of the TVP panel is a view of your project and external dependencies.
You can navigate through them by jumping to the next or previous nodes, the last
or first nodes, or jumping to parent or first child nodes. There are shortcuts
to all of these found below. You will see the traits, classes, objects,
members, and methods are all color coded.
All Available Commands
metals.restartServer
metals.build-import
metals.build-connect
metals.sources-scan
metals.compile-cascade
metals.compile-cancel
metals.doctor-run
metals.logs-toggle
metals.tvp
metals.tvp.view
metals.revealInTreeView
metals.new-scala-file
Show document symbols
Run :CocList outline
to show a symbol outline for the current file or use the
default mapping <space> o
.
Available Configuration Options
The following configuration options are currently available. The easiest way to set these
configurations is to enter :CocConfig
or :CocLocalConfig
to set your global or local
configuration settings respectively.
If you'd like to get autocompletion help for the configuration values you can install coc-json.
Configuration Option | Description |
---|
metals.serverVersion | The version of the Metals server artifact. Requires reloading the window. |
metals.serverProperties | Optional list of properties to pass along to the Metals server. By default, the environment variable JAVA_OPTS and .jvmopts file are respected. |
metals.javaHome | Optional path to the Java home directory. Requires reloading the window. Defaults to the most recent Java 8 version computed by the locate-java-home npm package. |
metals.sbtScript | Optional absolute path to an sbt executable to use for running sbt bloopInstall . By default, Metals uses java -jar sbt-launch.jar with an embedded launcher while respecting .jvmopts and .sbtopts . Update this setting if your sbt script requires more customizations like using environment variables. |
metals.millScript | Optional absolute path to a mill executable to use for running mill mill.contrib.Bloop/install . By default, Metals uses an embedded millw script while respecting .mill-version file. Update this setting if your mill script requires more customizations. |
metals.mavenScript | Optional absolute path to a mvn executable to use for running mvn ch.epfl.scala:maven-bloop_2.10:<bloop_version>:bloopInstall . By default, Metals uses an embedded mvnw script. Update this setting if your mvn script requires more customizations. |
metals.gradleScript | Optional absolute path to a gradle executable to use for running gradle bloopInstall . By default, Metals uses an embedded gradlew script. Update this setting if your gradle script requires more customizations. |
metals.pantsTargets | The pants targets to export. Space separated list of Pants targets to export, for example src/main/scala:: src/main/java:: . Syntax such as src/{main,test}:: is not supported." |
metals.scalafmtConfigPath | Optional custom path to the .scalafmt.conf file. Should be relative to the workspace root directory and use forward slashes / for file separators (even on Windows). |
metals.customRepositories | Optional list of custom resolvers passed to Coursier when fetching metals dependencies. For documentation on accepted values see the Coursier documentation. The extension will pass these to Coursier using the COURSIER_REPOSITORIES environment variable after joining the custom repositories with a pipe character ( |
metals.treeviews.toggleNode | Expand / Collapse tree node (default <CR> ) |
metals.treeviews.initialWidth | Initial Tree Views panels (default 40 ) |
metals.treeviews.initialViews | Initial views that the Tree View Panel Dispalys. Done mess with this unless you know what you're doing. |
metals.treeviews.gotoLastChild | Go to the last child Node (defalt J ) |
metals.treeviews.gotoParentNode | Go to parent Node (default p ) |
metals.treeviews.gotoFirstChild | Go to first child Node (default K ) |
metals.treeviews.executeCommand | Execute command for node (default r ) |
metals.treeviews.gotoPrevSibling | Go to prev sibling (default <C-k> ) |
metals.treeviews.gotoNextSibling | Go to next sibling (default <C-j> ) |
metals.treeviews.forceChildrenReload | Force the reloading of the children of this node. May be useful when the wrong result is cached and tree contains invalid data. (default f ) |
metals.treeviews.executeCommandAndOpenTab | Execute command and open node under cursor in tab (if node is class, trait and so on) (default t ) |
metals.treeviews.executeCommandAndOpenSplit | Execute command and open node under cursor in horizontal split (if node is class, trait and so on) (default s ) |
metals.treeviews.executeCommandAndOpenVSplit | Execute command and open node under cursor in horizontal split (if node is class, trait and so on) (default v ) |
Enable on type formatting for multiline string formatting
To properly support adding |
in multiline strings we are using the
onTypeFormatting
method. To enable the functionality you need to enable
coc.preferences.formatOnType
setting.
Shut down the language server
The Metals server is shutdown when you exit vim as you normally would.
:wq
This step clean ups resources that are used by the server.
Statusline integration
coc.nvim
has multiple ways to integrate with various statusline plugins. You can find instructions
for each of them located here.
Two noteworthy things that they add are the ability to see diagnostic information in the current
buffer...
... and also progress information for longer standing processes.
If you don't use a statusline integration, but would still like to see this information, the easiest
way is to add the following to your .vimrc
.
set statusline^=%{coc#status()}
The coc#status()
function will display both status and diagnostic information. However, if you are
using an integration like I am in the photos that display your diagnostic information in the far
right, but you'd like to see the status information in the middle, you can make a small function to
just grab that information, and use it in your statusline. This is what I use for lightline to
display only the status information in the middle of the statusline (section_c
).
function! CocExtensionStatus() abort
return get(g:, 'coc_status', '')
endfunction
let g:airline_section_c = '%f%{CocExtensionStatus()}'
Formatting on save
If you'd like to have :w
format using Metals + Scalafmt, then make sure you have the following in
your :CocConfig
.
"coc.preferences.formatOnSaveFiletypes": ["scala"]
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. A Bloop plugin that generates Bloop
configuration is added in the project/metals.sbt file. It's recommended to ignore these
directories and file from version control systems like git.
# ~/.gitignore
.metals/
.bloop/
project/metals.sbt
Troubleshooting
If you have any questions or issues with coc-metals, please submit an issue
in this repo if it pertains to the extension. If the issues is general to Metals, please submit it
in the Metals issue repo. If you have any feature
requests, we also have a feature request issue repo.
Contributing
If you're interested in contributing, please visit the CONTRIBUTING guide for
help on getting started.
Theme
The screen shots are in Neovim. The theme is
onedark with syntax highlighting added by
vim-scala. The status bar is
vim-airline, and all being ran in
iTerm2.