Integrating a new editor
Metals is a language server implemented in Scala that communicates with a single client over JSON-RPC.
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.13, 2.13.12, 2.13.11, 2.13.10, 2.13.9, 2.13.8, 2.13.7, 2.13.6
-
Scala 2.12: 2.12.19, 2.12.18, 2.12.17, 2.12.16, 2.12.15, 2.12.14, 2.12.13, 2.12.12
-
Scala 2.11: 2.11.12
-
Scala 3: 3.3.3, 3.3.2, 3.3.1, 3.2.2, 3.2.1, 3.2.0, 3.1.3, 3.1.2, 3.1.1, 3.1.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
Starting the server
Use Coursier to obtain the JVM classpath of Metals:
coursier bootstrap org.scalameta:metals_2.13:1.2.2 -o metals -f
(optional) It's recommended to enable JVM string de-duplication and provide a generous stack size and memory options.
coursier bootstrap \
--java-opt -XX:+UseG1GC \
--java-opt -XX:+UseStringDeduplication \
--java-opt -Xss4m \
--java-opt -Xms100m \
org.scalameta:metals_2.13:1.2.2 -o metals -f
See Metals server properties for additional system properties that are supported by the server.
JSON-RPC communication takes place over standard input/output so the Metals server doesn't print anything to the console when it starts. Instead, before establishing a connection with the client, Metals logs notifications to a global directory:
# macOS
~/Library/Caches/org.scalameta.metals/global.log
# Linux
$XDG_CACHE_HOME/org.scalameta.metals/global.log
# Linux (alternative)
$HOME/.cache/org.scalameta.metals/global.log
# Windows
{FOLDERID_LocalApplicationData}\.cache\org.scalameta.metals\global.log
After establishing a connection with the client, Metals redirects logs to the
.metals/metals.log
file in the LSP workspace root directory.
Metals supports two kinds of JSON-RPC endpoints:
- Language Server Protocol: for the main functionality of the server, including editor text synchronization and semantic features such as goto definition.
- Metals extensions: for additional functionality that is missing in LSP but improves the user experience.
Configuring the server
Over time the recommended way to configure Metals has shifted from heavily
relying on the Metals server properties to being
fully able to be configured via InitializationOptions
which are exchanged
during the
initialize
process. While Metals will still work being fully configured by server
properties, we strongly recommend that instead you rely on the
InitializationOptions
which are thoroughly covered below in the
initialize
section.
Language Server Protocol
Consult the LSP specification to learn more about how LSP works. Metals uses the following endpoints from the specification.
initialize
- the
rootUri
field is used to configure Metals for that workspace directory. The working directory for where server is started has no significant meaning. - at this point, Metals uses only full text synchronization. In the future, it will be able to use incremental text synchronization.
didChangeWatchedFiles
client capability is used to determine whether to register file watchers.
InitializationOptions
During initialize
we also have the ability to pass in InitializationOptions
.
This is the primary way to configure Metals. In Metals we have a few different
"providers". Some are LSP extensions, such as metals/inputBox
which you read
about below, and others used to be server properties that have been migrated to
InitializationOptions
. M
The currently available settings for InitializationOptions
are listed below.
interface InitializationOptions: {
compilerOptions: {
completionCommand?: string;
isCompletionItemDetailEnabled?: boolean;
isCompletionItemDocumentationEnabled?: boolean;
isCompletionItemResolve?: boolean;
isHoverDocumentationEnabled?: boolean;
isSignatureHelpDocumentationEnabled?: boolean;
overrideDefFormat?: "ascii" | "unicode";
parameterHintsCommand?: string;
snippetAutoIndent?: boolean;
}
debuggingProvider?: boolean;
decorationProvider?: boolean;
inlineDecorationProvider?: boolean;
didFocusProvider?: boolean;
doctorProvider?: "json" | "html";
executeClientCommandProvider?: boolean;
globSyntax?: "vscode" | "uri";
icons?: "vscode" | "octicons" | "atom" | "unicode";
inputBoxProvider?: boolean;
isVirtualDocumentSupported?: boolean;
isExitOnShutdown?: boolean;
isHttpEnabled?: boolean;
openFilesOnRenameProvider?: boolean;
quickPickProvider?: boolean;
renameFileThreshold?: number;
slowTaskProvider?: boolean;
statusBarProvider?: "on" | "off" | "log-message" | "show-message";
treeViewProvider?: boolean;
testExplorerProvider?: boolean;
openNewWindowProvider?: boolean;
copyWorksheetOutputProvider?: boolean;
commandInHtmlFormat?: "vscode" | "sublime";
doctorVisibilityProvider?: boolean;
}
You can also always check these in the
InitializationOptions.scala
file where you'll find all of the options and descriptions. Alternatively you can check out the typescript equivalent - MetalsInitializationOptions.ts
compilerOptions.completionCommand
An optional string value for a command identifier to trigger completion
(textDocument/signatureHelp
) in the editor.
Possible values:
"editor.action.triggerSuggest"
: currently used by Visual Studio Code and coc.nvim.- empty: for all other editors.
compilerOptions.isCompletionItemDetailEnabled
Boolean value signifying whether or not the CompletionItem.detail
field should
be populated.
Default value: true
compilerOptions.isCompletionItemDocumentationEnabled
Boolean value signifying whether or not the CompletionItem.documentation
field
should be populated.
Default value: true
compilerOptions.isCompletionItemResolve
Boolean value signifying whether the client wants Metals to handle the
completionItem/resolve
request.
https://microsoft.github.io/language-server-protocol/specification#completionItem_resolve
Default value: true
compilerOptions.isHoverDocumentationEnabled
Boolean value signifying whether to include docstrings in a textDocument/hover
request.
Default value: true
compilerOptions.isSignatureHelpDocumentationEnabled
Boolean value signifying whether or not the SignatureHelp.documentation
field
should be populated.
Default value: true
compilerOptions.overrideDefFormat
Whether or not the presentation compiler overrides should show unicode icon or just be in ascii format.
Possible Values:
"ascii"
(default)unicode
show the "🔼" icon in overrides.
compilerOptions.parameterHintsCommand
An optional string value for a command identifier to trigger parameter hints
(textDocument/signatureHelp
) in the editor. Metals uses this setting to
populate CompletionItem.command
for completion items that move the cursor
inside an argument list. For example, when completing "".stripSu@@
into
"".stripSuffix(@@)
, Metals will automatically trigger parameter hints if this
setting is provided by the editor.
Possible values:
"editor.action.triggerParameterHints"
: Used by Visual Studio Code and coc.nvim.- empty: for all other editors.
compilerOptions.snippetAutoIndent
Certain editors will automatically insert indentation equal to that of the reference line that the operation started on. This is relevant in the case of multiline textEdits such as the "implement all methods" completion.
Possible values:
on
: (default): the client automatically adds in the indentation. This is the case for VS Code, Sublime, and coc.nvim.off
: the client does not add any indentation when receiving a multi-line textEdit
copyWorksheetOutputProvider
Boolean value signifying whether or not the client supports running CopyWorksheetOutput server command and copying its results into the local buffer.
Default value: false
debuggingProvider
Boolean value to signify that the client supports the Debug Adapter Protocol.
Default value: false
decorationProvider
Boolean value to signify that the client supports the Decoration Protocol.
Default value: false
didFocusProvider
Boolean value to signify that the client supports the
metals/didFocusTextDocument
extension.
Default value: false
disableColorOutput
Useful for certain DAP clients that are unable to handle color codes for output. This will remove the color codes coming from whatever DAP server is currently being used.
Default value: false
doctorProvider
Format that you'd like Doctor to return information in.
Possible values:
html
: (default): Metals will return html that can be rendered directly in the browser or web viewjson
: json representation of the information returned by Doctor. See the json format here.
executeClientCommandProvider
Possible values:
off
(default): themetals/executeClientCommand
notification is not supported. Client commands can still be handled by enabling-Dmetals.http=on
.on
: themetals/executeClientCommand
notification is supported and all Metals client commands are handled.
globSyntax
Controls the glob syntax for registering file watchers on absolute directories.
Registration happens via client/registerCapability
for the
workspace/didChangeWatchedFiles
method, if
the editor client supports it.
Possible values:
uri
(default): URI-encoded file paths, with forward slash/
for file separators regardless of the operating system. Includesfile://
prefix.vscode
: use regular Path.toString for the absolute directory parts (/
on macOS+Linux and\
on Windows) and forward slashes/
for relative parts. For example,C:\Users\IEUser\workspace\project/*.{scala,sbt,properties}
. This mode is used by the VS Code client.
inlineDecorationProvider
If the client implements the Metals Decoration Protocol and supports decorations to be shown inline and not only at the end of a line.
Default: false
icons
Possible values:
none
(default): don't display icons in messages.vscode
: use Octicons such as$(rocket)
for status bar messages, as supported by th VS Code status bar.unicode
: use unicode emojis like 🚀 for status bar messages.
inputBoxProvider
Possible values:
off
(default): themetals/inputBox
request is not supported. In this case, Metals tries to fall back towindow/showMessageRequest
when possible.on
: themetals/inputBox
request is fully supported.
isExitOnShutdown
Possible values:
off
(default): runSystem.exit
only on theexit
notification, as required by the LSP specification.on
: runSystem.exit
after theshutdown
request, going against the LSP specification. This option is enabled by default for Sublime Text to prevent the Metals process from staying alive after Sublime Text has quit withCmd+Q
. It's not possible for Sublime Text packages to register a callback when the editor has quit. See LSP#410 for more details.
isHttpEnabled
Possible values:
off
(default): don't start a server with the Metals HTTP client.on
: start a server with the [Metals HTTP client] to interact with the server through a basic web UI. This option is needed for editor clients that don't support necessary requests such aswindow/showMessageRequest
.
openFilesOnRenameProvider
Boolean value to signify whether or not the client opens files when doing a rename.
Default: false
openNewWindowProvider
Boolean value signifying whether or not the client supports opening up a new window with the newly created project. Used in conjunction with the New Project Provider.
Default value: false
quickPickProvider
Boolean value to signify whether or not the client implements the
metals/quickPick
extensions.
Default value: false
renameFileThreshold
The max amount of files that you would like the client to open if the client is
a openFilesOnRenameProvider
.
Default value: 300
slowTaskProvider
Possible values:
off
(default): themetals/slowTask
request is not supported.on
: themetals/slowTask
request is fully supported.
statusBarProvider
Possible values:
off
(default): themetals/status
notification is not supported.on
: themetals/status
notification is supported.log-message
: translatemetals/status
notifications towindow/logMessage
notifications.show-message
: translatemetals/status
notifications towindow/showMessage
show notifications however the client displays messages to the user.
treeViewProvider
Boolean value signifying whether or not the client supports the Tree View Protocol.
Default value: false
testExplorerProvider
Boolean value to signify whether or not the client implements the Test Explorer.
doctorVisibilityProvider
Boolean value to signify whether or not the client implements the "metals/doctorVisibilityDidChange"
.
This JSON notification is used to keep track of doctor state. If client implements this provider then Metals server
will send updates to the doctor view.
Experimental Capabilities
All of the features that used to be set with experimental
can now all be set
via InitializationOptions
. This is the preferred way to configure Metals.
initialized
Triggers build server initialization and workspace indexing. The initialized
notification is critical for any Metals functionality to work.
shutdown
It is very important that the client sends a shutdown request in order for Metals to clean up open resources.
- persists incremental compilation analysis files. Without a
shutdown
hook, Metals will need to re-compile the entire workspace on next startup. - stops ongoing processes such as
sbt bloopInstall
- closes database connections
exit
Kills the process using System.exit
.
$/cancelRequest
Used by metals/slowTask
to notify when a long-running process has finished.
client/registerCapability
If the client declares the workspace.didChangeWatchedFiles
capability during
the initialize
request, then Metals follows up with a
client/registerCapability
request to register file watchers for certain glob
patterns.
textDocument/didOpen
Triggers compilation in the build server for the build target containing the
opened document. Related, see metals/didFocusTextDocument
.
textDocument/didChange
Required to know the text contents of the current unsaved buffer.
textDocument/didClose
Cleans up resources.
textDocument/didSave
Triggers compilation in the build server and analyses if the build needs to be re-imported.
textDocument/publishDiagnostics
Metals forwards diagnostics from the build server to the editor client.
Additionally, Metals publishes Information
diagnostics for unexpected
compilation errors when navigating external library sources.
textDocument/definition
Metals supports goto definition for workspace sources in addition to external library sources.
- Library sources live under the directory
.metals/readonly
and they are marked as read-only to prevent the user from editing them. - The destination location can either be a Scala or Java source file. It is recommended to have a Java language server installed to navigate Java sources.
textDocument/references
Metals finds symbol references for workspace sources but not external library dependencies.
LSP does not support streaming references so when project sources have not been
compiled at the point of a request, Metals returns immediately with potentially
incomplete results and triggers a background cascade compilation to find new
symbol references. If new symbol references are discovered after the background
compilation completes, Metals sends a notification via metals/status
and
window/logMessage
asking the user to run "find references" again.
textDocument/documentSymbol
Returns DocumentSymbol[]
if the client declares support for hierarchical
document symbol or SymbolInformation[]
otherwise.
textDocument/formatting
Formats the sources with the Scalafmt version
that is declared in .scalafmt.conf
.
- when
.scalafmt.conf
is missing, Metals sends awindow/showMessageRequest
to create the file. - when
.scalafmt.conf
exists but doesn't declare aversion
setting, Metals sends ametals/inputBox
when supported (with fallback towindow/showMessageRequest
when unsupported) to prependversion=$VERSION
to the.scalafmt.conf
file. - the first format request is usually slow because Metals needs to download
Scalafmt artifacts from Maven Central. While the download happens, Metals adds
a message in the status bar via
metals/status
and detailed download progress information is logged to.metals/metals.log
.