Skip to content

Documentation for using IntelliJ and Metals #11535

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 10, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions docs/docs/contributing/tools/ide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
layout: doc-page
title: Using an IDE
---

You can use either Metals (VS Code, vim) or IntelliJ IDEA as described on the
[IDE Support](../../usage/ide-support.md) page to work on the Scala 3 codebase. There are however
a few additional considerations to take into account.


## Bootstrapping Projects

The sbt build for dotty implements bootstrapping within the same build, so each component has
two projects:

```
sbt:scala3> projects
...
[info] scala3-compiler
[info] scala3-compiler-bootstrapped
...
```

These duplicated projects can be confusing and cause issues IDEs.

When using Metals, the `-bootstrapped` projects are not exported.

In IntelliJ IDEA, we recommend importing the dotty codebase through BSP as described on the
[IDE Support page](../../usage/ide-support.md), then the `-bootstrapped` projects are not exported.


## Scala Version warning in Metals

When using VS Code, Metals might show a warning that the Scala version (`3.0.0-[...]-NIGHTLY`)
is not supported. The reason is that the dotty repository sometimes uses a nightly build as
reference compiler. The IDE experience is going to be limited in this case (semantic features will
only within single files).
121 changes: 62 additions & 59 deletions docs/docs/usage/ide-support.md
Original file line number Diff line number Diff line change
@@ -1,63 +1,66 @@
---
layout: doc-page
title: "IDE support for Dotty"
title: "IDE support for Scala 3"
---

Dotty comes built-in with the Dotty Language Server, an implementation of the
[Language Server Protocol](https://github.com/Microsoft/language-server-protocol),
which means that any editor that implements the LSP can be used as a Dotty IDE.
Currently, the only IDE we officially support is
[Visual Studio Code](https://code.visualstudio.com/).

Prerequisites
============
To use this in your own Scala project, you must first get it to compile with
Dotty, please follow the instructions at https://github.com/scala/scala3-example-project

Usage
=====
1. Install [Visual Studio Code](https://code.visualstudio.com/).
2. Make sure `code`, the binary for Visual Studio Code, is on your `$PATH`, this
is the case if you can start the IDE by running `code` in a terminal. This
is the default on all systems except Mac where you'll need to follow these
instructions: https://code.visualstudio.com/docs/setup/mac#_command-line
3. In your project, run:
```shell
sbt launchIDE
```

Status
======

## Fully supported features:
- Typechecking as you type to show compiler errors/warnings
- Type information on hover
- Go to definition (in the current project)
- Find all references
- Documentation on hover
- [Worksheet mode](worksheet-mode.md)

## Partially working features:
- Completion
- Renaming
- Go to definition in external projects

## Unimplemented features:
- Formatting code (requires integrating with scalafmt)
- Quick fixes (probably by integrating with scalafix)

## Current limitations, to be fixed:
- Projects should be compiled with sbt before starting the IDE, this is
automatically done for you if you run `sbt launchIDE`.
- Once the IDE is started, source files that are not opened in the IDE
should not be modified in some other editor, the IDE won't pick up
these changes.
- Not all compiler errors/warnings are displayed, just those occurring
during typechecking.


Feedback
========
Please report issues on https://github.com/lampepfl/dotty/issues,
you can also come chat with use on the
[Dotty gitter channel](https://gitter.im/lampepfl/dotty)!
IDE support for Scala 3 is available in IDEs based on [Scala Metals](https://scalameta.org/metals/)
(e.g., Visual Studio Code, vim) and in [IntelliJ IDEA](https://www.jetbrains.com/idea/).


## Using Visual Studio Code

To use Visual Studio Code on a Scala 3 project, ensure you have the
[Metals](https://scalameta.org/metals/docs/editors/vscode.html) plugin installed. Then open the
project directory in VS code and click the "Import build" button in notification.


### Under the Hood

VS Code implements semantic features (such as completions, "go to definition")
using the [Language Server Protocol (LSP)](https://github.com/Microsoft/language-server-protocol),
so it needs a language server implementation. Metals is the implementation of LSP for Scala. It
extracts semantic information from [semanticdb](https://scalameta.org/docs/semanticdb/guide.html),
which is generated directly by the Scala 3 compiler.

You can read more about Scala 3 support in Metals in
[this blog post](https://medium.com/virtuslab/introduction-to-metals-with-scala-3-79ebf3120a95).

To communicate with the build tool (e.g., to import the project, trigger builds, run tests),
Metals uses the [Build Server Protocol (BSP)](https://build-server-protocol.github.io/). The
default BSP implementation used by metals is [Bloop](https://scalacenter.github.io/bloop/), which
supports Scala 3 projects. Alternatively,
[sbt can used as a BSP server](https://scalameta.org/metals/blog/2020/11/06/sbt-BSP-support.html)
as it directly implements BSP since version 1.4.


## Using IntelliJ IDEA

IntelliJ has its own implementation for semantic features, so it does not use Metals or the
Language Server Protocol (LSP).

In order to import a project into IntelliJ there are two possibilities:
- Use the built-in feature to import sbt builds
- Use IntelliJ's support for the
[Build Server Protocol (BSP)](https://www.jetbrains.com/help/idea/bsp-support.html)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@romanowski the bullet list is not rendered (https://dotty.epfl.ch/docs/usage/ide-support.html) - is that expected? Would be great if the rendering in scaladoc was the same as the preview on GitHub.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that this is a bug in Flexmark, empty line above is needed to render it properly. PR with fix is here: #11701

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Worth a report at flexmark? I understand the situation about markdown standards and specifications is complicated, but...

https://github.com/vsch/flexmark-java#markdown-processor-emulation

flexmark is by default commonmark compliant

https://spec.commonmark.org/0.29/#example-273

no blank line is needed to separate a paragraph from a following list

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It needs a bit more investigation on our side to make sure that Felexmark is to blame, @BarkingBad should take a look soon



### Importing the sbt build

To use IntelliJ's sbt import, go to "File" - "Open..." and select your project's `build.sbt` file.

In this mode, IntelliJ starts sbt with a custom plugin to extract the project structure. After
importing, IntelliJ no longer interacts with other sbt sessions. Building and running the project
within the IDE is done by separate processes.


### Importing the project using BSP

To import a project using BSP, go to "File" - "New" - "Project from Existing Sources" and select
the project directory. In the upcoming dialog select "BSP" to import the project. You may be asked
to choose between "sbt" and "sbt with Bloop", the recommended option is "sbt".

If the project import fails ("Problem executing BSP job"), navigate to your project in a terminal
and just start `sbt`. Once sbt is running, open the "bsp" tab in IntelliJ click the "Reload" button.

When using IntelliJ's BSP mode, build and run commands from the IDE are executed through sbt, so
they have the same effect as building or running the project through sbt in the terminal.
2 changes: 2 additions & 0 deletions docs/sidebar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ sidebar:
url: docs/contributing/debugging.html
- title: IDEs and Tools
subsection:
- title: IDEs
url: docs/contributing/tools/ide.html
- title: Mill
url: docs/contributing/tools/mill.html
- title: Scalafix
Expand Down
9 changes: 6 additions & 3 deletions project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,8 @@ object Build {
)

// Settings used when compiling dotty with a non-bootstrapped dotty
lazy val commonBootstrappedSettings = commonDottySettings ++ Seq(
lazy val commonBootstrappedSettings = commonDottySettings ++ NoBloopExport.settings ++ Seq(
bspEnabled := false,
unmanagedSourceDirectories in Compile += baseDirectory.value / "src-bootstrapped",

version := dottyVersion,
Expand Down Expand Up @@ -419,9 +420,11 @@ object Build {
),

// For convenience, change the baseDirectory when running the compiler
baseDirectory in (Compile, run) := baseDirectory.value / "..",
(Compile / forkOptions) := (Compile / forkOptions).value.withWorkingDirectory((ThisBuild / baseDirectory).value),
(Compile / run / forkOptions) := (Compile / run / forkOptions).value.withWorkingDirectory((ThisBuild / baseDirectory).value),
// And when running the tests
baseDirectory in Test := baseDirectory.value / "..",
(Test / forkOptions) := (Test / forkOptions).value.withWorkingDirectory((ThisBuild / baseDirectory).value),
(Test / testOnly / forkOptions) := (Test / testOnly / forkOptions).value.withWorkingDirectory((ThisBuild / baseDirectory).value),

test in Test := {
// Exclude VulpixMetaTests
Expand Down
31 changes: 31 additions & 0 deletions project/NoBloopExport.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import sbt._
import Keys._

/* With <3 from scala-js */
object NoBloopExport {
private lazy val bloopGenerateKey: Option[TaskKey[Option[File]]] = {
val optBloopKeysClass: Option[Class[_]] = try {
Some(Class.forName("bloop.integrations.sbt.BloopKeys"))
} catch {
case _: ClassNotFoundException => None
}

optBloopKeysClass.map { bloopKeysClass =>
val bloopGenerateGetter = bloopKeysClass.getMethod("bloopGenerate")
bloopGenerateGetter.invoke(null).asInstanceOf[TaskKey[Option[File]]]
}
}

/** Settings to prevent the project from being exported to IDEs. */
lazy val settings: Seq[Setting[_]] = {
bloopGenerateKey match {
case None =>
Nil
case Some(key) =>
Seq(
key in Compile := None,
key in Test := None,
)
}
}
}