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