1
1
package dotty.tools.languageserver.util.server
2
2
3
3
import java.io.PrintWriter
4
- import java.io.File.{separator => sep }
4
+ import java.io.File.{pathSeparator, separator }
5
5
import java.net.URI
6
6
import java.nio.file.{Files, Path}
7
7
import java.util
8
8
9
+ import dotty.tools.dotc.Main
10
+ import dotty.tools.dotc.reporting.{Reporter, ThrowingReporter}
11
+ import dotty.tools.io.Directory
9
12
import dotty.tools.languageserver.DottyLanguageServer
10
13
import dotty.tools.languageserver.util.Code.Workspace
11
14
import org.eclipse.lsp4j.{ DidOpenTextDocumentParams, InitializeParams, InitializeResult, TextDocumentItem}
@@ -18,11 +21,21 @@ class TestServer(testFolder: Path, workspaces: List[Workspace]) {
18
21
init()
19
22
20
23
private[this] def init(): InitializeResult = {
24
+ var compiledWorkspaces: Set[Workspace] = Set.empty
25
+
26
+ /** Compile the dependencies of the given workspace, and then the workspace. */
27
+ def compileWorkspaceAndDependencies(workspace: Workspace): Unit =
28
+ if (!compiledWorkspaces.contains(workspace)) {
29
+ workspace.dependsOn.foreach(compileWorkspaceAndDependencies)
30
+ compileWorkspace(workspace)
31
+ compiledWorkspaces += workspace
32
+ }
33
+
21
34
/**
22
35
* Set up given workspace, return JSON config.
23
36
*
24
- * This creates the necessary directories to hold the classes and sources. Some values
25
- * are passed via sbt-buildinfo, such as the classpath containing the scala and dotty libaries .
37
+ * If the workspace has dependencies, these dependencies are compiled. The classfiles of the
38
+ * dependent workspaces are put on the classpath of this workspace .
26
39
*
27
40
* @param workspace The workspace to configure.
28
41
* @return A JSON object representing the configuration for this workspace.
@@ -33,29 +46,16 @@ class TestServer(testFolder: Path, workspaces: List[Workspace]) {
33
46
.map(elem => '"' + elem.toString.replace('\\', '/') + '"')
34
47
.mkString("[ ", ", ", " ]")
35
48
36
- def classDirectory(workspace: Workspace): Path = {
37
- val path = testFolder.resolve(workspace.name).resolve("out")
38
- Files.createDirectories(path)
39
- path.toAbsolutePath
40
- }
41
-
42
- val dependencyClasspath =
43
- BuildInfo.ideTestsDependencyClasspath.map(_.getAbsolutePath) ++
44
- workspace.dependsOn.map(w => classDirectory(w).toString)
45
-
46
- val sourceDirectory: Path = {
47
- val path = TestFile.sourceDir.resolve(workspace.name).toAbsolutePath
48
- Files.createDirectories(path)
49
- path
50
- }
49
+ // Compile all the dependencies of this workspace
50
+ workspace.dependsOn.foreach(compileWorkspaceAndDependencies)
51
51
52
52
s"""{
53
53
| "id" : "${workspace.name}",
54
54
| "compilerVersion" : "${BuildInfo.ideTestsCompilerVersion}",
55
55
| "compilerArguments" : ${showSeq(BuildInfo.ideTestsCompilerArguments)},
56
- | "sourceDirectories" : ${showSeq(sourceDirectory :: Nil)},
57
- | "dependencyClasspath" : ${showSeq(dependencyClasspath)},
58
- | "classDirectory" : "${classDirectory(workspace).toString.replace('\\','/')}"
56
+ | "sourceDirectories" : ${showSeq(sourceDirectory(workspace, wipe = false) :: Nil)},
57
+ | "dependencyClasspath" : ${showSeq(dependencyClasspath(workspace) )},
58
+ | "classDirectory" : "${classDirectory(workspace, wipe = false ).toString.replace('\\','/')}"
59
59
|}
60
60
|""".stripMargin
61
61
}
@@ -83,7 +83,7 @@ class TestServer(testFolder: Path, workspaces: List[Workspace]) {
83
83
* @return the file opened
84
84
*/
85
85
def openCode(code: String, workspace: Workspace, fileName: String): TestFile = {
86
- val testFile = new TestFile(workspace.name + sep + fileName)
86
+ val testFile = new TestFile(workspace.name + separator + fileName)
87
87
val dotdp = new DidOpenTextDocumentParams()
88
88
val tdi = new TextDocumentItem()
89
89
tdi.setUri(testFile.uri)
@@ -93,4 +93,50 @@ class TestServer(testFolder: Path, workspaces: List[Workspace]) {
93
93
testFile
94
94
}
95
95
96
+ private def classDirectory(workspace: Workspace, wipe: Boolean): Path = {
97
+ val path = testFolder.resolve(workspace.name).resolve("out")
98
+ if (wipe) {
99
+ Directory(path).deleteRecursively()
100
+ Files.createDirectories(path)
101
+ }
102
+ path.toAbsolutePath
103
+ }
104
+
105
+ private def dependencyClasspath(workspace: Workspace) =
106
+ BuildInfo.ideTestsDependencyClasspath.map(_.getAbsolutePath) ++
107
+ workspace.dependsOn.map(w => classDirectory(w, wipe = false).toString)
108
+
109
+ private def sourceDirectory(workspace: Workspace, wipe: Boolean): Path = {
110
+ val path = TestFile.sourceDir.resolve(workspace.name).toAbsolutePath
111
+ if (wipe) {
112
+ Directory(path).deleteRecursively()
113
+ Files.createDirectories(path)
114
+ }
115
+ path
116
+ }
117
+
118
+ /**
119
+ * Sets up the sources of the given workspace, creates the necessary directories
120
+ * and compile the sources.
121
+ *
122
+ * @param workspace The workspace to set up.
123
+ */
124
+ private def compileWorkspace(workspace: Workspace): Unit = {
125
+ val sourcesDir = sourceDirectory(workspace, wipe = true)
126
+ val sources = workspace.sources.zipWithIndex.map { case (src, id) =>
127
+ val path = sourcesDir.resolve(s"Source${id}.scala").toAbsolutePath
128
+ Files.write(path, src.text.getBytes("UTF-8"))
129
+ path.toString
130
+ }
131
+
132
+ val compileOptions =
133
+ sources.toArray ++
134
+ Array(
135
+ "-classpath", dependencyClasspath(workspace).mkString(pathSeparator),
136
+ "-d", classDirectory(workspace, wipe = true).toString
137
+ )
138
+ val reporter = new ThrowingReporter(Reporter.NoReporter)
139
+ Main.process(compileOptions, reporter)
140
+ }
141
+
96
142
}
0 commit comments