This document describes the high-level architecture of Metals following the philosophy of rust-analyzer's ARCHITECTURE.md
- For the general contributing guidelines, see Getting started guide for contributors.
- If you're interested in the overview of how Metals works, A Dive into how Metals works video will be helpful.
- For LSP specification, please refer the LSP document, you don't have to read all of the
specification
, just read theoverview
and pick out the interesting parts when you need it.
The most important file of this project is MetalsLanguageServer.scala
. In this file, we define all of the LSP endpoints, for example, you will find the endpoint for textDocument/completion
request as follows.
@JsonRequest("textDocument/completion")
def completion(...) = ...
In addition to the LSP endpoints, this file contains many components, for example private var semanticdbs: Semanticdbs = _
. Those components will be initialized later at some points like on LSP's initialize
request.
Metals features are powered by presentation compilers, if you hit Compilers.scala
it is the client of compilers.
mtags
module is the Scala version specific module used to interact with the Scala presentation compiler using Java defined interfaces. You can find the interfaces under mtags-interface
project.
For example, ScalaPresentationCompiler.java
in mtags-interface
is the interface for ScalaPresentationCompiler.scala
under scala-2
and scala-3
directories of mtags
module.
For more details
- An introduction to the Scala presentation compiler
- Presentation compilers' endpoint, which are the class from the compiler jar that Metals uses.
- Scala3
InteractiveDriver.scala
andInteractive.scala
in lampepfl/dotty - Scala2:
interactive/Global.scala
in scala/scala
- Scala3
Metals uses semanticdb for many features (Providers that receive the instance of Semanticdbs
) such as references and renames. Semanticdb offers us information from the compiler that are written to disk and easily consumable. Metals consumes SemanticDBs in two ways:
FileSystemsSemanticdbs
consumes SemanticDBs on disks- Semanticdb will be generated by the build servers to disk, see https://scalameta.org/metals/docs/integrations/new-build-tool#enable-semanticdb
InteractiveSemanticdbs
will generate SemanticDB on the fly using the presentation compiler viamtags
, in caseFileSystemsSemanticdbs
failed or when the build tool doesn't compiler specific files such as dependency sources or sbt files.
In addition, classes extend SemanticdbFeatureProvider
index the semanticdb symbols, that will be updated by SemanticdbIndexer
.
Metals communicates with build server such as bloop
and sbt
using Build Server Protocol.
BspConnector.scala
manages the connections between Metals and build server, and BuildServerConnection.scala
represents the API wrapper for the build server.
For more details about sbt's BSP support in Metals, see the blog post.
Worksheet support is provided by mdoc, which is able to typecheck and evaluate each line of the input. The main class responsible for worksheets is WorksheetProvider.scala. It is responsible for downloading mdoc instance for each Scala version that is supported and running the evaluation in the file input.
Later the evaluations are published using decoration extension or via additional Text Edits for editors that do not support decorations. This is done in the two classes implementing WorksheetPublisher.scala:
- DecorationWorksheetPublisher.scala for decoration publishing
- WorkspaceEditWorksheetPublisher.scala for publishing decorations as comments in the code
FormattingProvider.scala
takes care of how Metals handles textDocument/formatting
. It uses scalafmt as a code formatter downloading dynamically using scalafmt-dynamic
.
We don't embed a specific version of scalafmt into Metals so that users can switch scalafmt's version using .scalafmt.conf
.
Note that FormattingProvider
doesn't handle textDocument/rangeFormatting
.
Scalafix support is implemented in the ScalafixProvider.scala. The class uses scalafix API scalafix.interfaces.Scalafix
to run the rules and get text edits, which are later changed to LSP TextEdits and applied to the file using WorkspaceEdit.
Metals downloads separate version of Scalafix for each binary version of Scala. It can also download additional dependencies for each of the used rules.
Debugging is handled by Debug Adapter Protocol, which is a complementary protocol to LSP.
The main code for debugging resides in scala.meta.internal.metals.debug
package with DebugProvider.scala being the main entrypoint.
DebugProvider sets up the communication between the debug server process started by the build server and the client. This communication is handled in DebugProxy.scala which translates some of the messages in order to enrich them with the information from Metals itself.
You can find more information about DAP here