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