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,41 +19,38 @@ 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.
27
40
*/
28
41
def workspaceSetup (workspace : Workspace ): String = {
29
42
def showSeq [T ](lst : Seq [T ]): String = lst.map(elem => '"' + elem.toString + '"' ).mkString(" [ " , " , " , " ]" )
30
43
31
- def classDirectory (workspace : Workspace ): Path = {
32
- val path = testFolder.resolve(workspace.name).resolve(" out" )
33
- Files .createDirectories(path)
34
- path.toAbsolutePath
35
- }
36
-
37
- val dependencyClasspath =
38
- BuildInfo .ideTestsDependencyClasspath.map(_.getAbsolutePath) ++
39
- workspace.dependsOn.map(w => classDirectory(w).toString)
40
-
41
- val sourceDirectory : Path = {
42
- val path = TestFile .sourceDir.resolve(workspace.name).toAbsolutePath
43
- Files .createDirectories(path)
44
- path
45
- }
44
+ // Compile all the dependencies of this workspace
45
+ workspace.dependsOn.foreach(compileWorkspaceAndDependencies)
46
46
47
47
s """ {
48
48
| "id" : " ${workspace.name}",
49
49
| "compilerVersion" : " ${BuildInfo .ideTestsCompilerVersion}",
50
50
| "compilerArguments" : ${showSeq(BuildInfo .ideTestsCompilerArguments)},
51
- | "sourceDirectories" : ${showSeq(sourceDirectory :: Nil )},
52
- | "dependencyClasspath" : ${showSeq(dependencyClasspath)},
53
- | "classDirectory" : " ${classDirectory(workspace)}"
51
+ | "sourceDirectories" : ${showSeq(sourceDirectory(workspace, wipe = false ) :: Nil )},
52
+ | "dependencyClasspath" : ${showSeq(dependencyClasspath(workspace) )},
53
+ | "classDirectory" : " ${classDirectory(workspace, wipe = false )}"
54
54
|}
55
55
| """ .stripMargin
56
56
}
@@ -78,7 +78,7 @@ class TestServer(testFolder: Path, workspaces: List[Workspace]) {
78
78
* @return the file opened
79
79
*/
80
80
def openCode (code : String , workspace : Workspace , fileName : String ): TestFile = {
81
- val testFile = new TestFile (workspace.name + sep + fileName)
81
+ val testFile = new TestFile (workspace.name + separator + fileName)
82
82
val dotdp = new DidOpenTextDocumentParams ()
83
83
val tdi = new TextDocumentItem ()
84
84
tdi.setUri(testFile.uri)
@@ -88,4 +88,50 @@ class TestServer(testFolder: Path, workspaces: List[Workspace]) {
88
88
testFile
89
89
}
90
90
91
+ private def classDirectory (workspace : Workspace , wipe : Boolean ): Path = {
92
+ val path = testFolder.resolve(workspace.name).resolve(" out" )
93
+ if (wipe) {
94
+ Directory (path).deleteRecursively()
95
+ Files .createDirectories(path)
96
+ }
97
+ path.toAbsolutePath
98
+ }
99
+
100
+ private def dependencyClasspath (workspace : Workspace ) =
101
+ BuildInfo .ideTestsDependencyClasspath.map(_.getAbsolutePath) ++
102
+ workspace.dependsOn.map(w => classDirectory(w, wipe = false ).toString)
103
+
104
+ private def sourceDirectory (workspace : Workspace , wipe : Boolean ): Path = {
105
+ val path = TestFile .sourceDir.resolve(workspace.name).toAbsolutePath
106
+ if (wipe) {
107
+ Directory (path).deleteRecursively()
108
+ Files .createDirectories(path)
109
+ }
110
+ path
111
+ }
112
+
113
+ /**
114
+ * Sets up the sources of the given workspace, creates the necessary directories
115
+ * and compile the sources.
116
+ *
117
+ * @param workspace The workspace to set up.
118
+ */
119
+ private def compileWorkspace (workspace : Workspace ): Unit = {
120
+ val sourcesDir = sourceDirectory(workspace, wipe = true )
121
+ val sources = workspace.sources.zipWithIndex.map { case (src, id) =>
122
+ val path = sourcesDir.resolve(s " Source ${id}.scala " ).toAbsolutePath
123
+ Files .write(path, src.text.getBytes(" UTF-8" ))
124
+ path.toString
125
+ }
126
+
127
+ val compileOptions =
128
+ sources.toArray ++
129
+ Array (
130
+ " -classpath" , dependencyClasspath(workspace).mkString(pathSeparator),
131
+ " -d" , classDirectory(workspace, wipe = true ).toString
132
+ )
133
+ val reporter = new ThrowingReporter (Reporter .NoReporter )
134
+ Main .process(compileOptions, reporter)
135
+ }
136
+
91
137
}
0 commit comments