Skip to main content

Vim

Vim demo

Metals works with most LSP clients for Vim, but we recommend using one of the Metals-specific extensions to get the best experience since they offer Metals-specific commands and implement the Metals LSP extensions.

  • coc-metals An extension for coc.nvim If you're already using other coc.nvim plugins or you are using Vim instead of Neovim, then this is probably the best option for you. Most of the documentation below refers to coc-metals.
  • nvim-metals A Lua extension for the built-in LSP support in Neovim. Note that this requires at least the 0.5.0 release of Neovim. You can find the full documentation for nvim-metals here.

Requirements#

Java 8, 11, 17 provided by OpenJDK or Oracle. Eclipse OpenJ9 is not supported, please make sure the JAVA_HOME environment variable points to a valid Java 8, 11 or 17 installation.

macOS, Linux or Windows. Metals is developed on many operating systems and every PR is tested on Ubuntu, Windows and MacOS.

Scala 2.13, 2.12, 2.11 and Scala 3. Metals supports these Scala versions:

  • Scala 2.13: 2.13.6, 2.13.5, 2.13.4, 2.13.3, 2.13.2, 2.13.1, 2.13.0

  • Scala 2.12: 2.12.15, 2.12.14, 2.12.13, 2.12.12, 2.12.11, 2.12.10, 2.12.9, 2.12.8

  • Scala 2.11: 2.11.12

  • Scala 3: 3.1.0-RC2, 3.0.2, 3.0.1, 3.0.0

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. While it works with both Vim and Neovim, we recommend using Neovim since it provides a smoother experience with some of the features.

# If using Vim
vim --version | head
VIM - Vi IMproved 8.2
# If using Neovim
nvim --version | head
NVIM v0.4.3

Installing Node#

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 convenience we recommend installing both via your favorite package manager or manually:

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 neoclide/coc.nvim, which provides Language Server Protocol support to Vim/Nvim to communicate with the Metals language server.

Assuming vim-plug is used (another plugin manager like vundle works too), update your ~/.vimrc to include the following settings.

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

Run :PlugInstall to install the plugin. If you already have coc.nvim installed, be sure to update to the latest version with :PlugUpdate.

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 +\/\/.\+$+

Recommended coc.nvim mappings#

coc.nvim doesn't come with a default key mapping for LSP commands, so you need to configure it yourself. You can see an example of default mappings here. Below you'll find examples of additional coc-metals specific mappings that you'll also want to ensure you have:

" Help Vim recognize *.sbt and *.sc as Scala files
au BufRead,BufNewFile *.sbt,*.sc set filetype=scala
" Used to expand decorations in worksheets
nmap <Leader>ws <Plug>(coc-metals-expand-decoration)
" Toggle panel with Tree Views
nnoremap <silent> <space>t :<C-u>CocCommand metals.tvp<CR>
" Toggle Tree View 'metalsPackages'
nnoremap <silent> <space>tp :<C-u>CocCommand metals.tvp metalsPackages<CR>
" Toggle Tree View 'metalsCompile'
nnoremap <silent> <space>tc :<C-u>CocCommand metals.tvp metalsCompile<CR>
" Toggle Tree View 'metalsBuild'
nnoremap <silent> <space>tb :<C-u>CocCommand metals.tvp metalsBuild<CR>
" Reveal current current class (trait or object) in Tree View 'metalsPackages'
nnoremap <silent> <space>tf :<C-u>CocCommand metals.revealInTreeView metalsPackages<CR>

Installing coc-metals#

Once you have coc.nvim installed, you can then install Metals a few different ways. The easiest is by running:

:CocInstall coc-metals

If you are using the latest stable release of coc.nvim, then this will automatically check for updates each day. However, if you're on the master branch of coc.nvim, this will no longer happen by default. You can read more about this here.

If you'd like to use the latest changes on master, you can also just build from source by using your vim plugin manager. Here is an example using vim-plug:

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.

NOTE* Make sure you don't have the extension installed both ways. So if you have installed it with the built-in extension management of coc.nvim first and are not switching, make sure to uninstall the old version first.

:CocUninstall coc-metals

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.

Import build

  • "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.

Sbt Launcher

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.

Import sbt changes

Configure Java version#

The coc-metals extension uses by default the JAVA_HOME environment variable (via find-java-home) to locate the java executable.

No Java Home

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.

Enter Java Home

Using latest Metals SNAPSHOT#

Update the "Server Version" setting to try out the latest pending Metals features.

VersionPublished
0.10.716 Sep 2021 16:28
0.10.7+17-f589e8b6-SNAPSHOT18 Sep 2021 10:35
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.

Update Metals Version

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.

Diagnostics

Worksheets#

Worksheets are a great way to explore an api, try out an idea, or code up an example and quickly see the evaluated expression or result. Behind the scenes worksheets are powered by the great work done in mdoc.

Getting started with Worksheets#

To get started with a worksheet you can either use the metals.new-scala-file command and select Worksheet or create a file called *.worksheet.sc. This format is important since this is what tells Metals that it's meant to be treated as a worksheet and not just a Scala script. Where you create the script also matters. If you'd like to use classes and values from your project, you need to make sure the worksheet is created inside of your src directory. You can still create a worksheet in other places, but you will only have access to the standard library and your dependencies.

Evaluations#

After saving you'll see the result of the expression differently depending on whether you are using Neovim or Vim. If using Vim, you will see them appear as comments at the end of the line. If you're using Nvim you will see this as virtual text. Keep in mind that if you're using coc-metals with Nvim you'll need to make sure codeLens.enable is set to true. You may not see the full result for example if it's too long, so you are also able to hover on the comment if you're in Vim or expand the virtual text by using the coc-metals-expand-decoration command. The default for this is:

nmap <Leader>ws <Plug>(coc-metals-expand-decoration)

Keep in mind that you don't need to wrap your code in an object. In worksheets everything can be evaluated at the top level.

Using dependencies in worksheets#

You are able to include an external dependency in your worksheet by including it in one of the following two ways.

// $dep.`organisation`::artifact:version` style
import $dep.`com.lihaoyi::scalatags:0.7.0`
// $ivy.`organisation::artifact:version` style
import $ivy.`com.lihaoyi::scalatags:0.7.0`

:: is the same as %% in sbt, which will append the current Scala binary version to the artifact name.

You can also import scalac options in a special $scalac import like below:

import $scalac.`-Ywarn-unused`

Decorations with worksheets

Tree View Protocol#

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 three parts to the panel. The first being the MetalsCompile window where you can see ongoing compilations, the second is the MetalsPackages window where you are able to see a tree view of all your packages, and finally the metalsBuild window where you have build related commands.

You are able to trigger the commands 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.

Tree View Protocol configuration options#

Configuration OptionDescription
metals.treeviews.toggleNodeExpand / Collapse tree node (default <CR>)
metals.treeviews.initialWidthInitial Tree Views panels (default 40)
metals.treeviews.initialViewsInitial views that the Tree View Panel displays. Don't mess with this unless you know what you're doing.
metals.treeviews.gotoLastChildGo to the last child Node (default J)
metals.treeviews.gotoParentNodeGo to parent Node (default p)
metals.treeviews.gotoFirstChildGo to first child Node (default K)
metals.treeviews.executeCommandExecute command for node (default r)
metals.treeviews.gotoPrevSiblingGo to prev sibling (default <C-k>)
metals.treeviews.gotoNextSiblingGo to next sibling (default <C-j>)
metals.treeviews.forceChildrenReloadForce 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.executeCommandAndOpenTabExecute command and open node under cursor in tab (if node is class, trait and so on) (default t)
metals.treeviews.executeCommandAndOpenSplitExecute command and open node under cursor in horizontal split (if node is class, trait and so on) (default s)
metals.treeviews.executeCommandAndOpenVSplitExecute command and open node under cursor in vertical split (if node is class, trait and so on) (default v)

Goto Super Method#

Depending on whether you're using Vim or Neovim, you'll have a slightly different behavior with this feature. If you're using Neovim, you'll want to ensure that you have codeLens.enable set to true in your :CocConfig since you'll be able to quickly see via code lenses which members are overridden. Then, you'll be able to simply trigger a code lens action on the line of the member that is overridden. The default mapping for this is <leader> cl.

If you're using Vim, you'll still have access to this functionality, but you'll have to infer which members are overridden and utilize the metals.go-to-super-method command.

There is also a metals.super-method-hierarchy command which will show you the entire hierarchy of the overridden method.

Goto super method

If you don't utilize this feature you can disable it by setting metals.superMethodLensesEnabled to false.

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.

Run Doctor 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.

Embedded Doctor

Other Available Commands#

You can see a full list of the Metals server commands here.

Show document symbols#

Run :CocList outline to show a symbol outline for the current file or use the default mapping <space> o.

Document Symbols

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.

Java Home directory#

The Java Home directory used for indexing JDK sources and locating the java binary.

Default: JAVA_HOME environment variable with fallback to user.home system property.

Example:

{
"metals": {
"javaHome": "/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home"
}
}

sbt script#

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.

Default: empty string "".

Example:

{
"metals": {
"sbtScript": "/usr/local/bin/sbt"
}
}

Gradle script#

Optional absolute path to a gradle executable to use for running gradle bloopInstall. By default, Metals uses gradlew with 5.3.1 gradle version. Update this setting if your gradle script requires more customizations like using environment variables.

Default: empty string "".

Example:

{
"metals": {
"gradleScript": "/usr/local/bin/gradle"
}
}

Maven script#

Optional absolute path to a maven executable to use for generating bloop config. By default, Metals uses mvnw maven wrapper with 3.6.1 maven version. Update this setting if your maven script requires more customizations

Default: empty string "".

Example:

{
"metals": {
"mavenScript": "/usr/local/bin/mvn"
}
}

Mill script#

Optional absolute path to a mill executable to use for running mill mill.contrib.Bloop/install. By default, Metals uses mill wrapper script with 0.5.0 mill version. Update this setting if your mill script requires more customizations like using environment variables.

Default: empty string "".

Example:

{
"metals": {
"millScript": "/usr/local/bin/mill"
}
}

Scalafmt config path#

Optional custom path to the .scalafmt.conf file. Should be an absolute path and use forward slashes / for file separators (even on Windows).

Default: empty string "".

Example:

{
"metals": {
"scalafmtConfigPath": "project/.scalafmt.conf"
}
}

Scalafix config path#

Optional custom path to the .scalafix.conf file. Should be an absolute path and use forward slashes / for file separators (even on Windows).

Default: empty string "".

Example:

{
"metals": {
"scalafixConfigPath": "project/.scalafix.conf"
}
}

Ammonite JVM Properties#

Optional list of JVM properties to pass along to the Ammonite server. Each property needs to be a separate item.\n\nExample: -Xmx1G or -Xms100M"

Default: [].

Example:

{
"metals": {
"ammoniteJvmProperties": ["-Xmx1G"]
}
}

Excluded Packages#

Packages that will be excluded from completions, imports, and symbol searches.

Note that this is in addition to some default packages that are already excluded. The default excluded packages are listed below:

META-INF
images
toolbarButtonGraphics
jdk
sun
oracle
java.awt.desktop
org.jcp
org.omg
org.graalvm
com.oracle
com.sun
com.apple
apple

If there is a need to remove one of the defaults, you are able to do so by including the package in your list and prepending -- to it.

Example:

["--sun"]

Default: [].

Example:

{
"metals": {
"excludedPackages": ["akka.actor.typed.javadsl"]
}
}

Don't generate Bloop plugin file for sbt#

If true, Metals will not generate metals.sbt files under the assumption that sbt-bloop is already manually installed in the sbt build. Build import will fail with a 'not valid command bloopInstall' error in case Bloop is not manually installed in the build when using this option.

Default: false

Example:

{
"metals": {
"bloopSbtAlreadyInstalled": false
}
}

Version of Bloop#

This version will be used for the Bloop build tool plugin, for any supported build tool, while importing in Metals as well as for running the embedded server

Default: 1.4.9

Example:

{
"metals": {
"bloopVersion": "1.4.0-RC1"
}
}

Should display lenses with links to super methods#

Super method lenses are visible above methods definition that override another methods. Clicking on a lens jumps to super method definition. Disabled lenses are not calculated for opened documents which might speed up document processing.

Default: false

Example:

{
"metals": {
"superMethodLensesEnabled": false
}
}

Should display type annotations for inferred types#

When this option is enabled, each method that can have inferred types has them displayed either as additional decorations if they are supported by the editor or shown in the hover.

Default: false

Example:

{
"metals": {
"showInferredType": false
}
}

Should display implicit parameter at usage sites#

When this option is enabled, each method that has implicit arguments has them displayed either as additional decorations if they are supported by the editor or shown in the hover.

Default: false

Example:

{
"metals": {
"showImplicitArguments": false
}
}

Should display implicit conversion at usage sites#

When this option is enabled, each place where an implicit method or class is used has it displayed either as additional decorations if they are supported by the editor or shown in the hover.

Default: false

Example:

{
"metals": {
"showImplicitConversionsAndClasses": false
}
}

Should try adjust indentation on range formatting.#

When this option is enabled, when user pastes any snippet into a Scala file, Metals will try to adjust the indentation to that of the current cursor.

Default: false

Example:

{
"metals": {
"enableIndentOnPaste": false
}
}

Remote language server#

A URL pointing to an endpoint that implements a remote language server.

See https://scalameta.org/metals/docs/contributors/remote-language-server.html for documentation on remote language servers.

Default: empty string "".

Example:

{
"metals": {
"remoteLanguageServer": "https://language-server.company.com/message"
}
}

Default fallback Scala version#

The Scala compiler version that is used as the default or fallback in case a file doesn't belong to any build target or the specified Scala version isn't supported by Metals. This applies to standalone Scala files, worksheets, and Ammonite scripts.

Default: 2.12.15

Example:

{
"metals": {
"fallbackScalaVersion": 2.12.15
}
}

Create new project from template#

It is possible using Metals to easily setup a new project using the exiting giter8 templates. This is an equivalent to the sbt new command, which uses the same mechanism. There is a great number of templates already available and it should be easy to find something for yourself. To start the setup you can use the new-scala-project command, which works as following:

  1. Choose the template and then:
    1. Use the proposed templates.
    2. Choose "Discover more" and then choose from the list downloaded from the Giter8 wiki page.
    3. Input a custom Github repository following the organization/repo schema.
  2. Navigate to the parent directory that you want to create your new project in.
  3. Choose the name or accept the default one.

If you feel like a template should be included in the default displayed ones do not hesitate to create a PR or file an issue.

Enable on type formatting for multiline string formatting#

on-type

To properly support some of the multiline string options like adding | in the multiline string, we are using the onTypeFormatting method. To enable the functionality you need to enable coc.preferences.formatOnType setting.

coc-preferences-formatOnType

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

Statusline integration#

It's recommended to use a statusline integration with coc-metals in order to allow messages to be displayed in your status line rather than as a message. This will allow for a better experience as you can continue to get status information while entering a command or responding to a prompt. However, we realize that not everyone by default will have this setup, and since the user needs to see messages about the status of their build, the following is defaulted to false.

"metals.statusBarEnabled": true

Again, it's recommended to make this active, and use a statusline plugin, or manually add the coc status information into your statusline. coc.nvim has multiple ways to integrate with various statusline plugins. You can find instructions for each of them located here. If you're unsure of what to use, vim-airline is a great minimal choice that will work out of the box.

With vim-airline you'll notice two noteworthy things. The first will be that you'll have diagnostic information on the far right of your screen.

Diagnostic statusline

You'll also have metals status information in your status bar.

Status bar info

Without a statusline integration, you'll get messages like you see below.

No status line

If you don't use a statusline plugin, but would still like to see this information, the easiest way is to make sure you have the following in your .vimrc.

set statusline^=%{coc#status()}%{get(b:,'coc_current_function','')}

Formatting on save#

Add the following configuration to :CocConfig if you'd like to have :w format using Metals and Scalafmt.

"coc.preferences.formatOnSaveFiletypes": ["scala"]

This step cleans up resources that are used by the server.

Files and Directories to include in your 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. The Bloop plugin that generates Bloop configuration is added in the metals.sbt file, which is added at project/metals.sbt as well as further project directories depending on how deep *.sbt files need to be supported. To support each *.sbt file Metals needs to create an additional file at ./project/project/metals.sbt relative to the sbt file. Working with Ammonite scripts will place compiled scripts into the .ammonite directory. It's recommended to exclude these directories and files from version control systems like git.

# ~/.gitignore
.metals/
.bloop/
.ammonite/
metals.sbt

Using an alternative LSP Client#

While we recommend using the coc-metals extension with coc.nvim, or nvim-metals with Neovim, Metals will work with these alternative LSP clients. Keep in mind that they have varying levels of LSP support, and you need to bootstrap Metals yourself.

Generating metals binary#

If you only want to use the latest stable version of Metals, the easiest way to install Metals is using coursier. Once installed you can simply do a cs install metals to install the latest stable version of Metals. You can then also do a cs update metals to update it.

If you'd like to bootstrap your own Metals for a specific version, you're also able to do so like this:

Next, build a metals-vim binary for the latest Metals release using the Coursier command-line interface.

VersionPublishedResolver
0.10.716 Sep 2021 16:28-r sonatype:releases
0.10.7+17-f589e8b6-SNAPSHOT18 Sep 2021 10:35-r sonatype:snapshots
# Make sure to use coursier v1.1.0-M9 or newer.
curl -L -o coursier https://git.io/coursier-cli
chmod +x coursier
./coursier bootstrap \
--java-opt -Xss4m \
--java-opt -Xms100m \
--java-opt -Dmetals.client=vim-lsc \
org.scalameta:metals_2.12:0.10.7 \
-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.

You can check version of your binary by executing metals-vim -version.

Configure the system properties -Dhttps.proxyHost=… -Dhttps.proxyPort=… if you are behind an HTTP proxy. The -Dmetals.client=vim-lsc flag is there just as a helper to match your potential client. So make sure it matches your client name. This line isn't mandatory though as your client can fully be configured via InitializationOptions, which should be easily configurable by your client. You can read more about his here.