@@ -20,6 +20,14 @@ import ch.epfl.scala.bsp
2020import ch .epfl .scala .bsp .BuildTargetIdentifier
2121import ch .epfl .scala .bsp .MessageType
2222import ch .epfl .scala .bsp .ShowMessageParams
23+ import ch .epfl .scala .bsp .CompileResult
24+ import ch .epfl .scala .bsp .StatusCode
25+ import ch .epfl .scala .bsp .Uri
26+ import ch .epfl .scala .bsp .endpoints
27+ import ch .epfl .scala .bsp .CompileResult
28+ import ch .epfl .scala .bsp .MessageType
29+ import ch .epfl .scala .bsp .ShowMessageParams
30+ import ch .epfl .scala .bsp .StatusCode
2331import ch .epfl .scala .bsp .Uri
2432import ch .epfl .scala .bsp .endpoints
2533import ch .epfl .scala .debugadapter .DebugServer
@@ -302,7 +310,7 @@ final class BloopBspServices(
302310 compileProvider = Some (BloopBspServices .DefaultCompileProvider ),
303311 testProvider = Some (BloopBspServices .DefaultTestProvider ),
304312 runProvider = Some (BloopBspServices .DefaultRunProvider ),
305- debugProvider = None , // todo kpodsiad
313+ debugProvider = Some ( BloopBspServices . DefaultDebugProvider ),
306314 inverseSourcesProvider = Some (true ),
307315 dependencySourcesProvider = Some (true ),
308316 dependencyModulesProvider = None ,
@@ -689,10 +697,7 @@ final class BloopBspServices(
689697 }
690698
691699 def test (params : bsp.TestParams ): BspEndpointResponse [bsp.TestResult ] = {
692- def test (
693- project : Project ,
694- state : State
695- ): Task [State ] = {
700+ def test (project : Project , state : State ): Task [Tasks .TestRuns ] = {
696701 val testFilter = TestInternals .parseFilters(Nil ) // Don't support test only for now
697702 val handler = new LoggingEventHandler (state.logger)
698703 Tasks .test(
@@ -717,25 +722,35 @@ final class BloopBspServices(
717722 val args = params.arguments.getOrElse(Nil )
718723 val logger = logger0.asBspServerVerbose
719724 compileProjects(mappings, state, args, originId, logger).flatMap {
720- case (newState, compileResult) =>
721- compileResult match {
722- case Right (_) =>
723- val sequentialTestExecution = mappings.foldLeft(Task .now(newState)) {
724- case (taskState, (_, p)) => taskState.flatMap(state => test(p, state))
725- }
726-
727- sequentialTestExecution.materialize.map(_.toEither).map {
728- case Right (newState) =>
725+ case (newState, Right (CompileResult (_, StatusCode .Ok , _, _))) =>
726+ val sequentialTestExecution : Task [Seq [Tasks .TestRuns ]] =
727+ Task .sequence(mappings.map { case (_, p) => test(p, state) })
728+
729+ sequentialTestExecution.materialize.map {
730+ case Success (testRunsSeq) =>
731+ testRunsSeq.reduceOption(_ ++ _) match {
732+ case None =>
729733 (newState, Right (bsp.TestResult (originId, bsp.StatusCode .Ok , None , None )))
730- case Left (e) =>
731- // (newState, Right(bsp.TestResult(None, bsp.StatusCode.Error, None)))
732- val errorMessage =
733- Response .internalError(s " Failed test execution: ${e.getMessage}" )
734- (newState, Left (errorMessage))
734+ case Some (testRuns) =>
735+ val status = testRuns.status
736+ val bspStatus =
737+ if (status == ExitStatus .Ok ) bsp.StatusCode .Ok else bsp.StatusCode .Error
738+ (
739+ newState.mergeStatus(status),
740+ Right (bsp.TestResult (originId, bspStatus, None , None ))
741+ )
735742 }
736-
737- case Left (error) => Task .now((newState, Left (error)))
743+ case Failure (e) =>
744+ val errorMessage =
745+ Response .internalError(s " Failed test execution: ${e.getMessage}" )
746+ (newState, Left (errorMessage))
738747 }
748+
749+ case (newState, Right (CompileResult (_, errorCode, _, _))) =>
750+ Task .now((newState, Right (bsp.TestResult (originId, errorCode, None , None ))))
751+
752+ case (newState, Left (error)) =>
753+ Task .now((newState, Left (error)))
739754 }
740755 }
741756 }
@@ -1026,7 +1041,8 @@ final class BloopBspServices(
10261041 val capabilities = bsp.BuildTargetCapabilities (
10271042 canCompile = true ,
10281043 canTest = true ,
1029- canRun = true
1044+ canRun = true ,
1045+ canDebug = true
10301046 )
10311047 val isJavaOnly = p.scalaInstance.isEmpty
10321048 val languageIds =
@@ -1064,29 +1080,49 @@ final class BloopBspServices(
10641080 projects : Seq [ProjectMapping ],
10651081 state : State
10661082 ): BspResult [bsp.SourcesResult ] = {
1067- val sourcesItems = projects.iterator.map {
1068- case (target, project) =>
1069- project.allSourceFilesAndDirectories.map { sources =>
1070- val items = sources.map { s =>
1071- import bsp .SourceItemKind ._
1072- val uri = s.underlying.toUri()
1073- val (bspUri, kind) = if (s.exists) {
1074- (uri, if (s.isFile) File else Directory )
1075- } else {
1076- val fileMatcher = FileSystems .getDefault.getPathMatcher(" glob:*.{scala, java}" )
1077- if (fileMatcher.matches(s.underlying.getFileName)) (uri, File )
1078- // If path doesn't exist and its name doesn't look like a file, assume it's a dir
1079- else (new URI (uri.toString + " /" ), Directory )
1080- }
1081- // TODO(jvican): Don't default on false for generated, add this info to JSON fields
1082- bsp.SourceItem (bsp.Uri (bspUri), kind, false )
1083- }
1083+ def sourceItem (s : AbsolutePath , isGenerated : Boolean ): bsp.SourceItem = {
1084+ import bsp .SourceItemKind ._
1085+ val uri = s.underlying.toUri()
1086+ val (bspUri, kind) = if (s.exists) {
1087+ (uri, if (s.isFile) File else Directory )
1088+ } else {
1089+ val fileMatcher = FileSystems .getDefault.getPathMatcher(" glob:*.{scala, java}" )
1090+ if (fileMatcher.matches(s.underlying.getFileName)) (uri, File )
1091+ // If path doesn't exist and its name doesn't look like a file, assume it's a dir
1092+ else (new URI (uri.toString + " /" ), Directory )
1093+ }
1094+ bsp.SourceItem (bsp.Uri (bspUri), kind, isGenerated)
1095+ }
1096+
1097+ val dag = Aggregate (projects.map(p => state.build.getDagFor(p._2)).toList)
1098+
1099+ // Collect the projects' sources following the projects topological sorting, so that
1100+ // source generators that depend on other source generators' outputs can run correctly.
1101+ val collectSourcesTasks = Dag .topologicalSort(dag).map { project =>
1102+ val unmanagedSources = project.allUnmanagedSourceFilesAndDirectories.map { sources =>
1103+ sources.map(sourceItem(_, isGenerated = false ))
1104+ }
1105+
1106+ val managedSources = {
1107+ val tasks = project.sourceGenerators
1108+ .map(state.sourceGeneratorCache.update(_, state.logger, state.commonOptions))
1109+ Task .gatherUnordered(tasks).map(_.flatten.map(sourceItem(_, isGenerated = true )))
1110+ }
1111+
1112+ for {
1113+ unmanaged <- unmanagedSources
1114+ managed <- managedSources
1115+ } yield (project, unmanaged ++ managed)
1116+ }
1117+
1118+ val projectToTarget = projects.map { case (target, project) => project -> target }.toMap
1119+ Task .sequence(collectSourcesTasks).map { results =>
1120+ val items = results.flatMap {
1121+ case (project, items) =>
10841122 val roots = project.sourceRoots.map(_.map(p => bsp.Uri (p.toBspUri)))
1085- bsp.SourcesItem (target, items, roots)
1086- }
1087- }.toList
1123+ projectToTarget.get(project).map(bsp.SourcesItem (_, items, roots))
1124+ }
10881125
1089- Task .sequence(sourcesItems).map { items =>
10901126 (state, Right (bsp.SourcesResult (items)))
10911127 }
10921128 }
@@ -1309,4 +1345,5 @@ object BloopBspServices {
13091345 private [bloop] val DefaultCompileProvider = bsp.CompileProvider (DefaultLanguages )
13101346 private [bloop] val DefaultTestProvider = bsp.TestProvider (DefaultLanguages )
13111347 private [bloop] val DefaultRunProvider = bsp.RunProvider (DefaultLanguages )
1348+ private [bloop] val DefaultDebugProvider = bsp.DebugProvider (DefaultLanguages )
13121349}
0 commit comments