11package dotty .tools .languageserver .util .server
22
33import java .io .PrintWriter
4- import java .io .File .{separator => sep }
4+ import java .io .File .{pathSeparator , separator }
55import java .net .URI
66import java .nio .file .{Files , Path }
77import java .util
88
9+ import dotty .tools .dotc .Main
10+ import dotty .tools .dotc .reporting .{Reporter , ThrowingReporter }
11+ import dotty .tools .io .Directory
912import dotty .tools .languageserver .DottyLanguageServer
1013import dotty .tools .languageserver .util .Code .Workspace
1114import org .eclipse .lsp4j .{ DidOpenTextDocumentParams , InitializeParams , InitializeResult , TextDocumentItem }
@@ -18,11 +21,21 @@ class TestServer(testFolder: Path, workspaces: List[Workspace]) {
1821 init()
1922
2023 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+
2134 /**
2235 * Set up given workspace, return JSON config.
2336 *
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 .
2639 *
2740 * @param workspace The workspace to configure.
2841 * @return A JSON object representing the configuration for this workspace.
@@ -33,29 +46,16 @@ class TestServer(testFolder: Path, workspaces: List[Workspace]) {
3346 .map(elem => '"' + elem.toString.replace('\\ ' , '/' ) + '"' )
3447 .mkString(" [ " , " , " , " ]" )
3548
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)
5151
5252 s """ {
5353 | "id" : " ${workspace.name}",
5454 | "compilerVersion" : " ${BuildInfo .ideTestsCompilerVersion}",
5555 | "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('\\ ' ,'/' )}"
5959 |}
6060 | """ .stripMargin
6161 }
@@ -83,7 +83,7 @@ class TestServer(testFolder: Path, workspaces: List[Workspace]) {
8383 * @return the file opened
8484 */
8585 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)
8787 val dotdp = new DidOpenTextDocumentParams ()
8888 val tdi = new TextDocumentItem ()
8989 tdi.setUri(testFile.uri)
@@ -93,4 +93,50 @@ class TestServer(testFolder: Path, workspaces: List[Workspace]) {
9393 testFile
9494 }
9595
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+
96142}
0 commit comments