This project follows the Scala Code of Conduct.
You need the following tools:
- git
- Java 8 or greater
- the sbt build tool
- one of the Scala code editor:
- VSCode with Metals (recommended)
- IntelliJ IDEA Community Edition with the Scala plugin.
To install Java and sbt we recommend using Coursier (the official Scala installer) and following these instructions.
- Clone the repository and its submodule
$ git clone [email protected]:scalacenter/scala-debug-adapter.git
$ cd scala-debug-adapter
$ git submodule update --init
- Start the sbt shell in the terminal and compile
$ sbt
sbt:root> compile
- Import the project in your code editor
Congratulations! You are now ready to start coding.
All the modules are in the modules
folder. They are composed of:
java-debug
: A fork of microsoft/java-debug on which the scala-debug-adapter depends. Thejava-debug
project was originally a Maven project. Thescala-debug-adapter
only depends on thecom.microsoft.java.debug.core
module and we compile it directly using sbt. So we can ignore the Maven configuration and the other modules.core
: The scala-debug-adapter itself which contains theDebugServer
and all its configuration classes.expression-compiler
: An extension of the Scala compiler for compiling a Scala expression in the context of debugging (the current stack frame of a paused JVM) into a class file that can be loaded and invoked. Theexpression-compiler
is cross-compiled on all supported minor Scala versions. It is class-loaded by theExpressionCompiler
object fromcore
.scala-3-step-filter
: The implementation ofStepFilter
for Scala 3. Thescala-3-step-filter
, compiled with Scala 3, is class-loaded by theScala3StepFilter
object fromcore
in a separate class loader. (The Scala 2 step filter is incore
directly because it is compiled in Scala 2 and does not need to be class-loaded separately)tests
: The test module. It contains the test infrastructure, intests/src/main
, and the unit tests, intests/src/test
.sbt-plugin
: The sbt plugin that allows sbt to start the DAP server.
Most of the tests are hosted in the tests
module.
The tests/src/main
folder contains the testing infrastructure:
- the
TestingDebugClient
class: a client of the debug server used for testing - the
TestingDebuggee
object: to configure, compile and debug some Scala processes as debuggees for testing the debugger. - the
DebugTestSuite
abstract class: an extension ofmunit.TestSuite
that allows describing a debug scenario and checking that it happens as described.
As instance, we can write and run this test:
package ch.epfl.scala.debugadapter
import ch.epfl.scala.debugadapter.testfmk.*
class MyDebugTests extends DebugTestSuite {
private val scalaVersion: ScalaVersion = ScalaVersion.`3.2`
test("my simple test") {
val source =
"""|package example
|
|object Main {
| def main(args: Array[String]): Unit = {
| val x = 42
| val msg = s"Hello, $x"
| println(msg)
| }
|}
|""".stripMargin
// configure the debuggee: a Scala 3 main class `example.Main`
implicit val debuggee: TestingDebuggee = TestingDebuggee.mainClass(source, "example.Main", scalaVersion)
check(
// check that the debuggee stops on a breakpoint on line 7
Breakpoint(7),
// check that the evaluation of expression x is 42
Evaluation.success("x", 42),
// check that a stepIn request goes into the Predef$.println method
StepIn.method("Predef$.println(Object)")
)
}
}
The organization of the tests is:
DebugServerTests
: general tests about starting and exiting debug sessions on all kinds of debugeesScalaDebugTests
: general tests about inspecting threads, stack frames and variables in Scala programsScalaEvaluationTests
: tests about the Scala expression evaluatorSourceBreakpointTests
: tests about the different kinds of source breakpoints: conditional breakpoints, hit count breakpoints, and log points.StepFilterTests
: tests about stepping in and out of Scala methods.
The tests are quite heavy to run because every test compiles a small Scala program, creates a debug server that starts a fresh JVM to run the program, and executes a debugging scenario. All of this is repeated on a few Scala versions.
Running all the test can take more than 30 minutes.
We recommend that locally you run only some tests using the sbt testOnly
task or using your IDE:
sbt:root> testOnly ch.epfl.scala.debugadapter.Scala32EvaluationTests
You can install and start a local version of the scala-debug-adapter using Metals.
- In sbt, check out the version of the scala-debug-adapter project.
sbt:root> version
...
[info] 3.0.2-SNAPSHOT
In the following steps we will use 3.0.2-SNAPSHOT
.
- Publish the scala-debug-adapter locally.
sbt:root> publishLocal
-
Open an sbt project in VS Code with Metals. As we will run the debugger in this project, it must contain a main class or some test suites.
-
Open or create the
project/plugins.sbt
file. This is where we can configure the version of the scala-debug-adapter that we want to use. -
Configure the
sbt-debug-adapter
plugin in theproject/plugins.sbt
file. Here you should use the local version that you just published, instead of"3.0.2-SNAPSHOT"
.
addSbtPlugin("ch.epfl.scala" % "sbt-debug-adapter" % "3.0.2-SNAPSHOT")
-
Switch the build server. In VS Code, open the command palette, run
Metals: switch build server
and selectsbt
. -
Since we changed the build file, we may need to reload sbt and re-import the build. You can do so by opening the command palette and running the
Metals: Import build
command, or by clicking onImport build
in Metals'tab. -
Start the debugger:
- click on the
debug
lens on top of a main method - or right-click on a test and run
Debug test
- or add a
Scala
debug configuration in the.vscode/launch.json
file