From d43aff2414009db94b8d5d52138f4d36ec00b683 Mon Sep 17 00:00:00 2001 From: Pawel Sadlo Date: Thu, 1 Aug 2024 13:26:51 +0200 Subject: [PATCH 01/24] adding SyntheticRootBspBuildTargetData --- .../SyntheticRootBspBuildTargetData.scala | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala diff --git a/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala b/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala new file mode 100644 index 00000000000..90ab4312104 --- /dev/null +++ b/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala @@ -0,0 +1,32 @@ +package mill.bsp.worker + +import ch.epfl.scala.bsp4j.{BuildTargetIdentifier, SourceItem, SourceItemKind, SourcesItem} +import mill.bsp.worker.Utils.{makeBuildTarget, sanitizeUri} +import mill.scalalib.bsp.BspBuildTarget +import mill.scalalib.bsp.BspModule.Tag + +import java.util.UUID +import scala.jdk.CollectionConverters._ + +/** + * Synthesised [[BspBuildTarget]] to handle exclusions. + * Intellij-Bsp doesn't provide a way to exclude files outside of module,so if there is no module with [[topLevelProjectRoot]] as content root [[SyntheticRootBspBuildTargetData]] will be created +*/ +class SyntheticRootBspBuildTargetData(topLevelProjectRoot:os.Path) { + val id: BuildTargetIdentifier = new BuildTargetIdentifier(Utils.sanitizeUri(topLevelProjectRoot / s"synth-build-target${UUID.randomUUID()}")) + + val bt = BspBuildTarget( + displayName = Some(topLevelProjectRoot.last + "-root"), + baseDirectory = Some(topLevelProjectRoot), + tags = Seq(Tag.Manual), + languageIds = Seq.empty, + canCompile = false, + canTest = false, + canRun = false, + canDebug = false + ) + + val target = makeBuildTarget(id,Seq.empty,bt,None) + private val sourcePath = topLevelProjectRoot / "src" + def synthSources = new SourcesItem(id,Seq(new SourceItem(sanitizeUri(sourcePath), SourceItemKind.DIRECTORY,false)).asJava) //intellijBSP does not create contentRootData for module with only outputPaths (this is probably a bug) +} From 4407915590c31bf96d5a7089ca5262d71144eaf0 Mon Sep 17 00:00:00 2001 From: Pawel Sadlo Date: Thu, 1 Aug 2024 13:29:19 +0200 Subject: [PATCH 02/24] adding topLevelBuildRopt param to BspServer, BspWorker, State --- bsp/src/mill/bsp/BspContext.scala | 5 +++-- bsp/src/mill/bsp/BspWorker.scala | 1 + .../src/mill/bsp/worker/BspWorkerImpl.scala | 10 ++++++---- .../src/mill/bsp/worker/MillBuildServer.scala | 17 +++++++++-------- bsp/worker/src/mill/bsp/worker/State.scala | 2 +- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/bsp/src/mill/bsp/BspContext.scala b/bsp/src/mill/bsp/BspContext.scala index 25a7ab6dbfa..44b7cdb40fc 100644 --- a/bsp/src/mill/bsp/BspContext.scala +++ b/bsp/src/mill/bsp/BspContext.scala @@ -61,10 +61,11 @@ private[mill] class BspContext( override def rawOutputStream: PrintStream = systemStreams.out } - - BspWorker(os.pwd, home, log).flatMap { worker => + val workspace = os.pwd + BspWorker(workspace, home, log).flatMap { worker => os.makeDir.all(home / Constants.bspDir) worker.startBspServer( + workspace, streams, logStream.getOrElse(streams.err), home / Constants.bspDir, diff --git a/bsp/src/mill/bsp/BspWorker.scala b/bsp/src/mill/bsp/BspWorker.scala index c8c435c6f18..1f64c6fc529 100644 --- a/bsp/src/mill/bsp/BspWorker.scala +++ b/bsp/src/mill/bsp/BspWorker.scala @@ -8,6 +8,7 @@ import java.net.URL private trait BspWorker { def startBspServer( + topLevelBuildRoot:os.Path, streams: SystemStreams, logStream: PrintStream, logDir: os.Path, diff --git a/bsp/worker/src/mill/bsp/worker/BspWorkerImpl.scala b/bsp/worker/src/mill/bsp/worker/BspWorkerImpl.scala index b48d244a5d1..66103314f88 100644 --- a/bsp/worker/src/mill/bsp/worker/BspWorkerImpl.scala +++ b/bsp/worker/src/mill/bsp/worker/BspWorkerImpl.scala @@ -15,14 +15,16 @@ import scala.concurrent.{Await, CancellationException, Promise} private class BspWorkerImpl() extends BspWorker { override def startBspServer( - streams: SystemStreams, - logStream: PrintStream, - logDir: os.Path, - canReload: Boolean + topLevelBuildRoot: os.Path, + streams: SystemStreams, + logStream: PrintStream, + logDir: os.Path, + canReload: Boolean ): Either[String, BspServerHandle] = { val millServer = new MillBuildServer( + topLevelProjectRoot = topLevelBuildRoot, bspVersion = Constants.bspProtocolVersion, serverVersion = BuildInfo.millVersion, serverName = Constants.serverName, diff --git a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala index 2d8d300366f..d8b3449e521 100644 --- a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala @@ -82,13 +82,14 @@ import mill.eval.Evaluator.TaskResult import scala.util.chaining.scalaUtilChainingOps import scala.util.control.NonFatal private class MillBuildServer( - bspVersion: String, - serverVersion: String, - serverName: String, - logStream: PrintStream, - canReload: Boolean -) extends ExternalModule - with BuildServer { + topLevelProjectRoot: os.Path, + bspVersion: String, + serverVersion: String, + serverName: String, + logStream: PrintStream, + canReload: Boolean + ) extends ExternalModule + with BuildServer { lazy val millDiscover: Discover[this.type] = Discover[this.type] @@ -110,7 +111,7 @@ private class MillBuildServer( if (statePromise.isCompleted) statePromise = Promise[State]() // replace the promise evaluatorsOpt.foreach { evaluators => statePromise.success( - new State(evaluators, debug) + new State(topLevelProjectRoot, evaluators, debug) ) } } diff --git a/bsp/worker/src/mill/bsp/worker/State.scala b/bsp/worker/src/mill/bsp/worker/State.scala index f9a97a75840..10d96229905 100644 --- a/bsp/worker/src/mill/bsp/worker/State.scala +++ b/bsp/worker/src/mill/bsp/worker/State.scala @@ -6,7 +6,7 @@ import mill.scalalib.internal.JavaModuleUtils import mill.define.Module import mill.eval.Evaluator -private class State(evaluators: Seq[Evaluator], debug: String => Unit) { +private class State(workspaceDir:os.Path,evaluators: Seq[Evaluator], debug: String => Unit) { lazy val bspModulesById: Map[BuildTargetIdentifier, (BspModule, Evaluator)] = { val modules: Seq[(Module, Seq[Module], Evaluator)] = evaluators .map(ev => (ev.rootModule, JavaModuleUtils.transitiveModules(ev.rootModule), ev)) From a058b18f9496b235132135e7272c13a806f6d2af Mon Sep 17 00:00:00 2001 From: Pawel Sadlo Date: Thu, 1 Aug 2024 13:32:55 +0200 Subject: [PATCH 03/24] add syntheticRootBspBuildTarget to State --- bsp/worker/src/mill/bsp/worker/State.scala | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bsp/worker/src/mill/bsp/worker/State.scala b/bsp/worker/src/mill/bsp/worker/State.scala index 10d96229905..92526b59b82 100644 --- a/bsp/worker/src/mill/bsp/worker/State.scala +++ b/bsp/worker/src/mill/bsp/worker/State.scala @@ -34,4 +34,9 @@ private class State(workspaceDir:os.Path,evaluators: Seq[Evaluator], debug: Stri lazy val bspIdByModule: Map[BspModule, BuildTargetIdentifier] = bspModulesById.view.mapValues(_._1).map(_.swap).toMap + lazy val syntheticRootBspBuildTarget:Option[SyntheticRootBspBuildTargetData] = { + def containsWorkspaceDir(path: Option[os.Path]) = path.exists(workspaceDir.startsWith) + + if (bspModulesById.values.exists { case (m, _) => containsWorkspaceDir(m.bspBuildTarget.baseDirectory) }) None else Some(new SyntheticRootBspBuildTargetData(workspaceDir)) + } } From 45d1d9e8058f6f34e544541ad803d2363391a81f Mon Sep 17 00:00:00 2001 From: Pawel Sadlo Date: Thu, 1 Aug 2024 13:33:29 +0200 Subject: [PATCH 04/24] extract makeBuildTarget to Utils, create outputPaths --- bsp/worker/src/mill/bsp/worker/Utils.scala | 60 ++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/bsp/worker/src/mill/bsp/worker/Utils.scala b/bsp/worker/src/mill/bsp/worker/Utils.scala index 42a06af854c..f372fc30056 100644 --- a/bsp/worker/src/mill/bsp/worker/Utils.scala +++ b/bsp/worker/src/mill/bsp/worker/Utils.scala @@ -46,6 +46,66 @@ private object Utils { else StatusCode.OK } + def makeBuildTarget(id: BuildTargetIdentifier, depsIds: Seq[BuildTargetIdentifier], bt: BspBuildTarget,data:Option[(String,Object)]) = { + val buildTarget = new BuildTarget( + id, + bt.tags.asJava, + bt.languageIds.asJava, + depsIds.asJava, + new BuildTargetCapabilities().tap { it => + it.setCanCompile(bt.canCompile) + it.setCanTest(bt.canTest) + it.setCanRun(bt.canRun) + it.setCanDebug(bt.canDebug) + } + ) + + bt.displayName.foreach(buildTarget.setDisplayName) + bt.baseDirectory.foreach(p =>buildTarget.setBaseDirectory(sanitizeUri(p))) + + for ((dataKind, data) <- data) { + buildTarget.setDataKind(dataKind) + buildTarget.setData(data) + } + buildTarget + } + + def outputPaths(outDir: os.Path, buildTargetBaseDir: os.Path,topLevelProjectRoot:os.Path) = { + val output = new OutputPathItem( + // Spec says, a directory must end with a forward slash + sanitizeUri(outDir) + "/", + OutputPathItemKind.DIRECTORY + ) + + def ignore(path: os.Path): Boolean = { + path.last.startsWith(".") || + path.endsWith(os.RelPath("out")) || + path.endsWith(os.RelPath("target")) || + path.endsWith(os.RelPath("docs")) || + path.endsWith(os.RelPath("mill-build")) + } + + def projectsRootPaths = os.walk(topLevelProjectRoot, ignore).collect { + case p if p.endsWith(os.RelPath("build.sc")) => p / up + } + def outputPathItem(path:os.Path) = + new OutputPathItem( + // Spec says, a directory must end with a forward slash + sanitizeUri(path) + "/", + OutputPathItemKind.DIRECTORY + ) + def additionalExclusions = projectsRootPaths.flatMap { path => + Seq( + outputPathItem(path / ".idea"), + outputPathItem(path / "out"), + outputPathItem(path / ".bsp"), + outputPathItem(path / ".bloop"), + ) + } + output +: (if (topLevelProjectRoot.startsWith(buildTargetBaseDir)) { + additionalExclusions + } else Nil) + } private[this] def getStatusCodePerTask( results: Evaluator.Results, task: mill.define.Task[_] From 7526305b51e0a8be994886d4015d1d6c6e9b2b50 Mon Sep 17 00:00:00 2001 From: Pawel Sadlo Date: Thu, 1 Aug 2024 13:33:36 +0200 Subject: [PATCH 05/24] extract makeBuildTarget to Utils, create outputPaths --- bsp/worker/src/mill/bsp/worker/Utils.scala | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bsp/worker/src/mill/bsp/worker/Utils.scala b/bsp/worker/src/mill/bsp/worker/Utils.scala index f372fc30056..58b3ecabc66 100644 --- a/bsp/worker/src/mill/bsp/worker/Utils.scala +++ b/bsp/worker/src/mill/bsp/worker/Utils.scala @@ -1,11 +1,15 @@ package mill.bsp.worker -import ch.epfl.scala.bsp4j.{BuildClient, BuildTargetIdentifier, StatusCode, TaskId} +import ch.epfl.scala.bsp4j.{BuildClient, BuildTarget, BuildTargetCapabilities, BuildTargetIdentifier, OutputPathItem, OutputPathItemKind, StatusCode, TaskId} import mill.api.{CompileProblemReporter, PathRef} import mill.api.Result.{Skipped, Success} import mill.eval.Evaluator import mill.scalalib.JavaModule -import mill.scalalib.bsp.BspModule +import mill.scalalib.bsp.{BspBuildTarget, BspModule} +import os.up + +import scala.jdk.CollectionConverters._ +import scala.util.chaining.scalaUtilChainingOps private object Utils { From ce5c96e167108222355ca9f78972d320f037e0d7 Mon Sep 17 00:00:00 2001 From: Pawel Sadlo Date: Thu, 1 Aug 2024 13:35:40 +0200 Subject: [PATCH 06/24] filter synthetic module from bspClient requests --- bsp/worker/src/mill/bsp/worker/MillBuildServer.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala index d8b3449e521..12134822d0a 100644 --- a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala @@ -452,6 +452,7 @@ private class MillBuildServer( // already has some from the build file, what to do? override def buildTargetCompile(p: CompileParams): CompletableFuture[CompileResult] = completable(s"buildTargetCompile ${p}") { state => + p.setTargets(p.getTargets.asScala.filterNot(state.syntheticRootBspBuildTarget.map(_.id).contains).toList.asJava) val params = TaskParameters.fromCompileParams(p) val taskId = params.hashCode() val compileTasksEvs = params.getTargets.distinct.map(state.bspModulesById).map { @@ -537,6 +538,7 @@ private class MillBuildServer( override def buildTargetTest(testParams: TestParams): CompletableFuture[TestResult] = completable(s"buildTargetTest ${testParams}") { state => + testParams.setTargets(testParams.getTargets.asScala.toSeq.filterNot(state.syntheticRootBspBuildTarget.map(_.id).contains).toList.asJava) val millBuildTargetIds = state .rootModules .map { case m: BspModule => state.bspIdByModule(m) } @@ -628,6 +630,7 @@ private class MillBuildServer( override def buildTargetCleanCache(cleanCacheParams: CleanCacheParams) : CompletableFuture[CleanCacheResult] = completable(s"buildTargetCleanCache ${cleanCacheParams}") { state => + cleanCacheParams.setTargets(cleanCacheParams.getTargets.asScala.toSeq.filterNot(state.syntheticRootBspBuildTarget.map(_.id).contains).toList.asJava) val (msg, cleaned) = cleanCacheParams.getTargets.asScala.foldLeft(( "", @@ -676,6 +679,7 @@ private class MillBuildServer( override def debugSessionStart(debugParams: DebugSessionParams) : CompletableFuture[DebugSessionAddress] = completable(s"debugSessionStart ${debugParams}") { state => + debugParams.setTargets(debugParams.getTargets.asScala.toSeq.filterNot(state.syntheticRootBspBuildTarget.map(_.id).contains).toList.asJava) throw new NotImplementedError("debugSessionStart endpoint is not implemented") } @@ -691,7 +695,7 @@ private class MillBuildServer( : CompletableFuture[V] = { val prefix = hint.split(" ").head completable(hint) { state: State => - val ids = targetIds(state) + val ids = targetIds(state).filterNot(state.syntheticRootBspBuildTarget.map(_.id).contains) val tasksSeq = ids.flatMap { id => val (m, ev) = state.bspModulesById(id) tasks.lift.apply(m).map(ts => (ts, (ev, id))) From 22e787490b5ff15d9e96210bf2f7ab008a34020d Mon Sep 17 00:00:00 2001 From: Pawel Sadlo Date: Thu, 1 Aug 2024 13:37:14 +0200 Subject: [PATCH 07/24] change completableTasks, handle syntheticRootmodule --- .../src/mill/bsp/worker/MillBuildServer.scala | 151 +++++------------- .../mill/bsp/worker/MillJavaBuildServer.scala | 4 +- .../mill/bsp/worker/MillJvmBuildServer.scala | 8 +- .../bsp/worker/MillScalaBuildServer.scala | 12 +- 4 files changed, 50 insertions(+), 125 deletions(-) diff --git a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala index 12134822d0a..68f37a92199 100644 --- a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala @@ -1,86 +1,29 @@ package mill.bsp.worker -import ch.epfl.scala.bsp4j.{ - BuildClient, - BuildServer, - BuildServerCapabilities, - BuildTarget, - BuildTargetCapabilities, - BuildTargetIdentifier, - CleanCacheParams, - CleanCacheResult, - CompileParams, - CompileProvider, - CompileResult, - DebugProvider, - DebugSessionAddress, - DebugSessionParams, - DependencyModule, - DependencyModulesItem, - DependencyModulesParams, - DependencyModulesResult, - DependencySourcesItem, - DependencySourcesParams, - DependencySourcesResult, - InitializeBuildParams, - InitializeBuildResult, - InverseSourcesParams, - InverseSourcesResult, - LogMessageParams, - MessageType, - OutputPathItem, - OutputPathItemKind, - OutputPathsItem, - OutputPathsParams, - OutputPathsResult, - ReadParams, - ResourcesItem, - ResourcesParams, - ResourcesResult, - RunParams, - RunProvider, - RunResult, - SourceItem, - SourceItemKind, - SourcesItem, - SourcesParams, - SourcesResult, - StatusCode, - TaskFinishDataKind, - TaskFinishParams, - TaskId, - TaskStartDataKind, - TaskStartParams, - TestParams, - TestProvider, - TestResult, - TestTask, - WorkspaceBuildTargetsResult -} import ch.epfl.scala.bsp4j +import ch.epfl.scala.bsp4j._ import com.google.gson.JsonObject import mill.T import mill.api.{DummyTestReporter, Result, Strict} +import mill.bsp.BspServerResult +import mill.bsp.worker.Utils.{makeBuildTarget, outputPaths, sanitizeUri} import mill.define.Segment.Label import mill.define.{Args, Discover, ExternalModule, Task} import mill.eval.Evaluator +import mill.eval.Evaluator.TaskResult import mill.main.MainModule -import mill.scalalib.{JavaModule, SemanticDbJavaModule, TestModule} -import mill.scalalib.bsp.{BspModule, JvmBuildTarget, ScalaBuildTarget} import mill.runner.MillBuildRootModule +import mill.scalalib.bsp.{BspModule, JvmBuildTarget, ScalaBuildTarget} +import mill.scalalib.{JavaModule, SemanticDbJavaModule, TestModule} import java.io.PrintStream import java.util.concurrent.CompletableFuture import scala.concurrent.Promise import scala.jdk.CollectionConverters._ import scala.reflect.ClassTag -import scala.util.{Failure, Success, Try} -import Utils.sanitizeUri -import mill.bsp.BspServerResult -import mill.eval.Evaluator.TaskResult - import scala.util.chaining.scalaUtilChainingOps import scala.util.control.NonFatal +import scala.util.{Failure, Success, Try} private class MillBuildServer( topLevelProjectRoot: os.Path, bspVersion: String, @@ -247,30 +190,12 @@ private class MillBuildServer( } val bt = m.bspBuildTarget - val buildTarget = new BuildTarget( - id, - bt.tags.asJava, - bt.languageIds.asJava, - depsIds.asJava, - new BuildTargetCapabilities().tap { it => - it.setCanCompile(bt.canCompile) - it.setCanTest(bt.canTest) - it.setCanRun(bt.canRun) - it.setCanDebug(bt.canDebug) - } - ) + makeBuildTarget(id, depsIds, bt, data) - bt.displayName.foreach(buildTarget.setDisplayName) - bt.baseDirectory.foreach(p => buildTarget.setBaseDirectory(sanitizeUri(p))) - - for ((dataKind, data) <- data) { - buildTarget.setDataKind(dataKind) - buildTarget.setData(data) - } - - buildTarget + } { case (targets,state) => + new WorkspaceBuildTargetsResult((targets.asScala ++ state.syntheticRootBspBuildTarget.map(_.target)).asJava) + } - }(new WorkspaceBuildTargetsResult(_)) override def workspaceReload(): CompletableFuture[Object] = completableNoState("workspaceReload", false) { @@ -317,8 +242,8 @@ private class MillBuildServer( } ) { case (ev, state, id, module, items) => new SourcesItem(id, items.asJava) - } { - new SourcesResult(_) + } { case (sourceItems,state) => + new SourcesResult((sourceItems.asScala.toSeq ++ state.syntheticRootBspBuildTarget.map(_.synthSources)).asJava) } } @@ -388,8 +313,8 @@ private class MillBuildServer( val cp = (resolveDepsSources ++ unmanagedClasspath).map(sanitizeUri).toSeq ++ buildSources new DependencySourcesItem(id, cp.asJava) - } { - new DependencySourcesResult(_) + } {x => + new DependencySourcesResult(x._1) } /** @@ -427,8 +352,8 @@ private class MillBuildServer( new DependencyModule(s"unmanaged-${dep.path.last}", "") } new DependencyModulesItem(id, (deps ++ unmanged).iterator.toSeq.asJava) - } { - new DependencyModulesResult(_) + } {x => + new DependencyModulesResult(x._1) } override def buildTargetResources(p: ResourcesParams): CompletableFuture[ResourcesResult] = @@ -444,8 +369,8 @@ private class MillBuildServer( val resourcesUrls = resources.map(_.path).filter(os.exists).map(sanitizeUri) new ResourcesItem(id, resourcesUrls.asJava) - } { - new ResourcesResult(_) + } {x => + new ResourcesResult(x._1) } // TODO: if the client wants to give compilation arguments and the module @@ -485,29 +410,29 @@ private class MillBuildServer( override def buildTargetOutputPaths(params: OutputPathsParams) : CompletableFuture[OutputPathsResult] = completable(s"buildTargetOutputPaths ${params}") { state => + + val synthOutpaths = for { + synthTarget <- state.syntheticRootBspBuildTarget + if params.getTargets.contains(synthTarget.id) + baseDir <- synthTarget.bt.baseDirectory + } yield new OutputPathsItem(synthTarget.id,outputPaths(baseDir / "out", baseDir,topLevelProjectRoot).asJava) + val items = for { target <- params.getTargets.asScala (module, ev) <- state.bspModulesById.get(target) } yield { - val items = - if (module.millOuterCtx.external) List( - new OutputPathItem( - // Spec says, a directory must end with a forward slash - sanitizeUri(ev.externalOutPath) + "/", - OutputPathItemKind.DIRECTORY - ) - ) - else List( - new OutputPathItem( - // Spec says, a directory must end with a forward slash - sanitizeUri(ev.outPath) + "/", - OutputPathItemKind.DIRECTORY - ) - ) + val items = { + module match { + case external if external.millOuterCtx.external => + outputPaths(ev.externalOutPath, module.bspBuildTarget.baseDirectory.get,topLevelProjectRoot) + case _ => outputPaths(ev.outPath, module.bspBuildTarget.baseDirectory.get,topLevelProjectRoot) + } + } + new OutputPathsItem(target, items.asJava) } - new OutputPathsResult(items.asJava) + new OutputPathsResult((items ++ synthOutpaths).asJava) } override def buildTargetRun(runParams: RunParams): CompletableFuture[RunResult] = @@ -690,8 +615,8 @@ private class MillBuildServer( def completableTasks[T, V, W: ClassTag]( hint: String, targetIds: State => Seq[BuildTargetIdentifier], - tasks: PartialFunction[BspModule, Task[W]] - )(f: (Evaluator, State, BuildTargetIdentifier, BspModule, W) => T)(agg: java.util.List[T] => V) + tasks: PartialFunction[BspModule, Task[W]], + )(f: (Evaluator, State, BuildTargetIdentifier, BspModule, W) => T)(agg: ((java.util.List[T], State)) => V) : CompletableFuture[V] = { val prefix = hint.split(" ").head completable(hint) { state: State => @@ -734,7 +659,7 @@ private class MillBuildServer( } } - agg(evaluated.flatten.toSeq.asJava) + agg(evaluated.flatten.toSeq.asJava,state) } } diff --git a/bsp/worker/src/mill/bsp/worker/MillJavaBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillJavaBuildServer.scala index 4e43072beb5..acf003ae586 100644 --- a/bsp/worker/src/mill/bsp/worker/MillJavaBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillJavaBuildServer.scala @@ -41,7 +41,7 @@ private trait MillJavaBuildServer extends JavaBuildServer { this: MillBuildServe classpath.iterator.toSeq.asJava, sanitizeUri(classesPath.resolve(pathResolver)) ) - } { - new JavacOptionsResult(_) + } {x=> + new JavacOptionsResult(x._1) } } diff --git a/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala index b358ddcc28e..0cd52ba33e7 100644 --- a/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala @@ -83,8 +83,8 @@ private trait MillJvmBuildServer extends JvmBuildServer { this: MillBuildServer val classes = mainClass.toList ++ zincWorker.discoverMainClasses(compile) item.setMainClasses(classes.map(new JvmMainClass(_, Nil.asJava)).asJava) item - } { - agg + } {x=> + agg(x._1) } } @@ -106,7 +106,7 @@ private trait MillJvmBuildServer extends JvmBuildServer { this: MillBuildServer .map(_.resolve(pathResolver)) .map(sanitizeUri).toSeq.asJava ) - } { - new JvmCompileClasspathResult(_) + } {x => + new JvmCompileClasspathResult(x._1) } } diff --git a/bsp/worker/src/mill/bsp/worker/MillScalaBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillScalaBuildServer.scala index a34a6ab037a..fef139faabe 100644 --- a/bsp/worker/src/mill/bsp/worker/MillScalaBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillScalaBuildServer.scala @@ -75,8 +75,8 @@ private trait MillScalaBuildServer extends ScalaBuildServer { this: MillBuildSer .map(sanitizeUri).toSeq.asJava, sanitizeUri(classesPathTask.resolve(pathResolver)) ) - } { - new ScalacOptionsResult(_) + } {x => + new ScalacOptionsResult(x._1) } override def buildTargetScalaMainClasses(p: ScalaMainClassesParams) @@ -101,8 +101,8 @@ private trait MillScalaBuildServer extends ScalaBuildServer { this: MillBuildSer case (ev, state, id, _, _) => // no Java module, so no main classes new ScalaMainClassesItem(id, Seq.empty[ScalaMainClass].asJava) - } { - new ScalaMainClassesResult(_) + } {x => + new ScalaMainClassesResult(x._1) } override def buildTargetScalaTestClasses(p: ScalaTestClassesParams) @@ -141,8 +141,8 @@ private trait MillScalaBuildServer extends ScalaBuildServer { this: MillBuildSer case (ev, state, id, _, _) => // Not a test module, so no test classes new ScalaTestClassesItem(id, Seq.empty[String].asJava) - } { - new ScalaTestClassesResult(_) + } {x => + new ScalaTestClassesResult(x._1) } } From a695dbaa72c90da9d65482b931cc72e19eb06538 Mon Sep 17 00:00:00 2001 From: Pawel Sadlo Date: Thu, 1 Aug 2024 13:44:52 +0200 Subject: [PATCH 08/24] fixing name --- .../src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala b/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala index 90ab4312104..e844990c59a 100644 --- a/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala +++ b/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala @@ -13,7 +13,7 @@ import scala.jdk.CollectionConverters._ * Intellij-Bsp doesn't provide a way to exclude files outside of module,so if there is no module with [[topLevelProjectRoot]] as content root [[SyntheticRootBspBuildTargetData]] will be created */ class SyntheticRootBspBuildTargetData(topLevelProjectRoot:os.Path) { - val id: BuildTargetIdentifier = new BuildTargetIdentifier(Utils.sanitizeUri(topLevelProjectRoot / s"synth-build-target${UUID.randomUUID()}")) + val id: BuildTargetIdentifier = new BuildTargetIdentifier(Utils.sanitizeUri(topLevelProjectRoot / s"synth-build-target-${UUID.randomUUID()}")) val bt = BspBuildTarget( displayName = Some(topLevelProjectRoot.last + "-root"), From 5ef1b6705a9714737f8581685da3a0e5ffe21415 Mon Sep 17 00:00:00 2001 From: Pawel Sadlo Date: Thu, 1 Aug 2024 13:51:47 +0200 Subject: [PATCH 09/24] extract SyntheticRootBspBuildTargetData creation logic to companion object --- .../mill/bsp/worker/SyntheticRootBspBuildTargetData.scala | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala b/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala index e844990c59a..bd04a16a276 100644 --- a/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala +++ b/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala @@ -2,7 +2,7 @@ package mill.bsp.worker import ch.epfl.scala.bsp4j.{BuildTargetIdentifier, SourceItem, SourceItemKind, SourcesItem} import mill.bsp.worker.Utils.{makeBuildTarget, sanitizeUri} -import mill.scalalib.bsp.BspBuildTarget +import mill.scalalib.bsp.{BspBuildTarget, BspModule} import mill.scalalib.bsp.BspModule.Tag import java.util.UUID @@ -30,3 +30,9 @@ class SyntheticRootBspBuildTargetData(topLevelProjectRoot:os.Path) { private val sourcePath = topLevelProjectRoot / "src" def synthSources = new SourcesItem(id,Seq(new SourceItem(sanitizeUri(sourcePath), SourceItemKind.DIRECTORY,false)).asJava) //intellijBSP does not create contentRootData for module with only outputPaths (this is probably a bug) } +object SyntheticRootBspBuildTargetData{ + def makeIfNeeded(existingModules:Iterable[BspModule],workspaceDir:os.Path) = { + def containsWorkspaceDir(path: Option[os.Path]) = path.exists(workspaceDir.startsWith) + if (existingModules.exists { m => containsWorkspaceDir(m.bspBuildTarget.baseDirectory) }) None else Some(new SyntheticRootBspBuildTargetData(workspaceDir)) + } +} From 870acf5b57ffb02bdd0c6f3532a28ddcbdc69508 Mon Sep 17 00:00:00 2001 From: Pawel Sadlo Date: Thu, 1 Aug 2024 13:54:21 +0200 Subject: [PATCH 10/24] docs --- .../src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala b/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala index bd04a16a276..81948cac16f 100644 --- a/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala +++ b/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala @@ -10,7 +10,7 @@ import scala.jdk.CollectionConverters._ /** * Synthesised [[BspBuildTarget]] to handle exclusions. - * Intellij-Bsp doesn't provide a way to exclude files outside of module,so if there is no module with [[topLevelProjectRoot]] as content root [[SyntheticRootBspBuildTargetData]] will be created + * Intellij-Bsp doesn't provide a way to exclude files outside of module,so if there is no module having content root as [[topLevelProjectRoot]], [[SyntheticRootBspBuildTargetData]] will be created */ class SyntheticRootBspBuildTargetData(topLevelProjectRoot:os.Path) { val id: BuildTargetIdentifier = new BuildTargetIdentifier(Utils.sanitizeUri(topLevelProjectRoot / s"synth-build-target-${UUID.randomUUID()}")) From c0207b53dcbd819ecda7570cc2939b1cd3d4ff5a Mon Sep 17 00:00:00 2001 From: Pawel Sadlo Date: Thu, 1 Aug 2024 13:54:42 +0200 Subject: [PATCH 11/24] moving syntheticRootBspBuildTarget creation logic to companion object --- bsp/worker/src/mill/bsp/worker/State.scala | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/bsp/worker/src/mill/bsp/worker/State.scala b/bsp/worker/src/mill/bsp/worker/State.scala index 92526b59b82..9cfb8730668 100644 --- a/bsp/worker/src/mill/bsp/worker/State.scala +++ b/bsp/worker/src/mill/bsp/worker/State.scala @@ -34,9 +34,6 @@ private class State(workspaceDir:os.Path,evaluators: Seq[Evaluator], debug: Stri lazy val bspIdByModule: Map[BspModule, BuildTargetIdentifier] = bspModulesById.view.mapValues(_._1).map(_.swap).toMap - lazy val syntheticRootBspBuildTarget:Option[SyntheticRootBspBuildTargetData] = { - def containsWorkspaceDir(path: Option[os.Path]) = path.exists(workspaceDir.startsWith) + lazy val syntheticRootBspBuildTarget:Option[SyntheticRootBspBuildTargetData] = SyntheticRootBspBuildTargetData.makeIfNeeded(bspModulesById.values.map(_._1),workspaceDir) - if (bspModulesById.values.exists { case (m, _) => containsWorkspaceDir(m.bspBuildTarget.baseDirectory) }) None else Some(new SyntheticRootBspBuildTargetData(workspaceDir)) - } } From d547e3421386c1da978336d5952faeea2b7a2adf Mon Sep 17 00:00:00 2001 From: Pawel Sadlo Date: Thu, 1 Aug 2024 14:15:22 +0200 Subject: [PATCH 12/24] fixing agg --- bsp/worker/src/mill/bsp/worker/MillBuildServer.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala index 68f37a92199..a3551b37ff7 100644 --- a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala @@ -659,7 +659,7 @@ private class MillBuildServer( } } - agg(evaluated.flatten.toSeq.asJava,state) + agg((evaluated.flatten.toSeq.asJava,state)) } } From 613eb596c4773742f1c4e8c8b7924721fe9a9b0b Mon Sep 17 00:00:00 2001 From: Pawel Sadlo Date: Thu, 1 Aug 2024 15:59:12 +0200 Subject: [PATCH 13/24] format --- bsp/src/mill/bsp/BspWorker.scala | 2 +- .../src/mill/bsp/worker/BspWorkerImpl.scala | 10 +-- .../src/mill/bsp/worker/MillBuildServer.scala | 75 ++++++++++++------- .../mill/bsp/worker/MillJavaBuildServer.scala | 2 +- .../mill/bsp/worker/MillJvmBuildServer.scala | 4 +- .../bsp/worker/MillScalaBuildServer.scala | 6 +- bsp/worker/src/mill/bsp/worker/State.scala | 5 +- .../SyntheticRootBspBuildTargetData.scala | 22 ++++-- bsp/worker/src/mill/bsp/worker/Utils.scala | 40 ++++++---- 9 files changed, 102 insertions(+), 64 deletions(-) diff --git a/bsp/src/mill/bsp/BspWorker.scala b/bsp/src/mill/bsp/BspWorker.scala index 1f64c6fc529..f24a3b6c3a9 100644 --- a/bsp/src/mill/bsp/BspWorker.scala +++ b/bsp/src/mill/bsp/BspWorker.scala @@ -8,7 +8,7 @@ import java.net.URL private trait BspWorker { def startBspServer( - topLevelBuildRoot:os.Path, + topLevelBuildRoot: os.Path, streams: SystemStreams, logStream: PrintStream, logDir: os.Path, diff --git a/bsp/worker/src/mill/bsp/worker/BspWorkerImpl.scala b/bsp/worker/src/mill/bsp/worker/BspWorkerImpl.scala index 66103314f88..9bbb172c77c 100644 --- a/bsp/worker/src/mill/bsp/worker/BspWorkerImpl.scala +++ b/bsp/worker/src/mill/bsp/worker/BspWorkerImpl.scala @@ -15,11 +15,11 @@ import scala.concurrent.{Await, CancellationException, Promise} private class BspWorkerImpl() extends BspWorker { override def startBspServer( - topLevelBuildRoot: os.Path, - streams: SystemStreams, - logStream: PrintStream, - logDir: os.Path, - canReload: Boolean + topLevelBuildRoot: os.Path, + streams: SystemStreams, + logStream: PrintStream, + logDir: os.Path, + canReload: Boolean ): Either[String, BspServerHandle] = { val millServer = diff --git a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala index a3551b37ff7..4137ef330a2 100644 --- a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala @@ -25,14 +25,14 @@ import scala.util.chaining.scalaUtilChainingOps import scala.util.control.NonFatal import scala.util.{Failure, Success, Try} private class MillBuildServer( - topLevelProjectRoot: os.Path, - bspVersion: String, - serverVersion: String, - serverName: String, - logStream: PrintStream, - canReload: Boolean - ) extends ExternalModule - with BuildServer { + topLevelProjectRoot: os.Path, + bspVersion: String, + serverVersion: String, + serverName: String, + logStream: PrintStream, + canReload: Boolean +) extends ExternalModule + with BuildServer { lazy val millDiscover: Discover[this.type] = Discover[this.type] @@ -192,11 +192,12 @@ private class MillBuildServer( val bt = m.bspBuildTarget makeBuildTarget(id, depsIds, bt, data) - } { case (targets,state) => - new WorkspaceBuildTargetsResult((targets.asScala ++ state.syntheticRootBspBuildTarget.map(_.target)).asJava) + } { case (targets, state) => + new WorkspaceBuildTargetsResult( + (targets.asScala ++ state.syntheticRootBspBuildTarget.map(_.target)).asJava + ) } - override def workspaceReload(): CompletableFuture[Object] = completableNoState("workspaceReload", false) { // Instead stop and restart the command @@ -242,8 +243,10 @@ private class MillBuildServer( } ) { case (ev, state, id, module, items) => new SourcesItem(id, items.asJava) - } { case (sourceItems,state) => - new SourcesResult((sourceItems.asScala.toSeq ++ state.syntheticRootBspBuildTarget.map(_.synthSources)).asJava) + } { case (sourceItems, state) => + new SourcesResult( + (sourceItems.asScala.toSeq ++ state.syntheticRootBspBuildTarget.map(_.synthSources)).asJava + ) } } @@ -313,7 +316,7 @@ private class MillBuildServer( val cp = (resolveDepsSources ++ unmanagedClasspath).map(sanitizeUri).toSeq ++ buildSources new DependencySourcesItem(id, cp.asJava) - } {x => + } { x => new DependencySourcesResult(x._1) } @@ -352,7 +355,7 @@ private class MillBuildServer( new DependencyModule(s"unmanaged-${dep.path.last}", "") } new DependencyModulesItem(id, (deps ++ unmanged).iterator.toSeq.asJava) - } {x => + } { x => new DependencyModulesResult(x._1) } @@ -369,7 +372,7 @@ private class MillBuildServer( val resourcesUrls = resources.map(_.path).filter(os.exists).map(sanitizeUri) new ResourcesItem(id, resourcesUrls.asJava) - } {x => + } { x => new ResourcesResult(x._1) } @@ -377,7 +380,9 @@ private class MillBuildServer( // already has some from the build file, what to do? override def buildTargetCompile(p: CompileParams): CompletableFuture[CompileResult] = completable(s"buildTargetCompile ${p}") { state => - p.setTargets(p.getTargets.asScala.filterNot(state.syntheticRootBspBuildTarget.map(_.id).contains).toList.asJava) + p.setTargets(p.getTargets.asScala.filterNot( + state.syntheticRootBspBuildTarget.map(_.id).contains + ).toList.asJava) val params = TaskParameters.fromCompileParams(p) val taskId = params.hashCode() val compileTasksEvs = params.getTargets.distinct.map(state.bspModulesById).map { @@ -410,12 +415,11 @@ private class MillBuildServer( override def buildTargetOutputPaths(params: OutputPathsParams) : CompletableFuture[OutputPathsResult] = completable(s"buildTargetOutputPaths ${params}") { state => - val synthOutpaths = for { synthTarget <- state.syntheticRootBspBuildTarget if params.getTargets.contains(synthTarget.id) baseDir <- synthTarget.bt.baseDirectory - } yield new OutputPathsItem(synthTarget.id,outputPaths(baseDir / "out", baseDir,topLevelProjectRoot).asJava) + } yield new OutputPathsItem(synthTarget.id, outputPaths(baseDir / "out", baseDir, topLevelProjectRoot).asJava) val items = for { target <- params.getTargets.asScala @@ -424,15 +428,20 @@ private class MillBuildServer( val items = { module match { case external if external.millOuterCtx.external => - outputPaths(ev.externalOutPath, module.bspBuildTarget.baseDirectory.get,topLevelProjectRoot) - case _ => outputPaths(ev.outPath, module.bspBuildTarget.baseDirectory.get,topLevelProjectRoot) + outputPaths( + ev.externalOutPath, + module.bspBuildTarget.baseDirectory.get, + topLevelProjectRoot + ) + case _ => + outputPaths(ev.outPath, module.bspBuildTarget.baseDirectory.get, topLevelProjectRoot) } } new OutputPathsItem(target, items.asJava) } - new OutputPathsResult((items ++ synthOutpaths).asJava) + new OutputPathsResult((items ++ synthOutpaths).asJava) } override def buildTargetRun(runParams: RunParams): CompletableFuture[RunResult] = @@ -463,7 +472,9 @@ private class MillBuildServer( override def buildTargetTest(testParams: TestParams): CompletableFuture[TestResult] = completable(s"buildTargetTest ${testParams}") { state => - testParams.setTargets(testParams.getTargets.asScala.toSeq.filterNot(state.syntheticRootBspBuildTarget.map(_.id).contains).toList.asJava) + testParams.setTargets(testParams.getTargets.asScala.toSeq.filterNot( + state.syntheticRootBspBuildTarget.map(_.id).contains + ).toList.asJava) val millBuildTargetIds = state .rootModules .map { case m: BspModule => state.bspIdByModule(m) } @@ -555,7 +566,9 @@ private class MillBuildServer( override def buildTargetCleanCache(cleanCacheParams: CleanCacheParams) : CompletableFuture[CleanCacheResult] = completable(s"buildTargetCleanCache ${cleanCacheParams}") { state => - cleanCacheParams.setTargets(cleanCacheParams.getTargets.asScala.toSeq.filterNot(state.syntheticRootBspBuildTarget.map(_.id).contains).toList.asJava) + cleanCacheParams.setTargets(cleanCacheParams.getTargets.asScala.toSeq.filterNot( + state.syntheticRootBspBuildTarget.map(_.id).contains + ).toList.asJava) val (msg, cleaned) = cleanCacheParams.getTargets.asScala.foldLeft(( "", @@ -604,7 +617,9 @@ private class MillBuildServer( override def debugSessionStart(debugParams: DebugSessionParams) : CompletableFuture[DebugSessionAddress] = completable(s"debugSessionStart ${debugParams}") { state => - debugParams.setTargets(debugParams.getTargets.asScala.toSeq.filterNot(state.syntheticRootBspBuildTarget.map(_.id).contains).toList.asJava) + debugParams.setTargets(debugParams.getTargets.asScala.toSeq.filterNot( + state.syntheticRootBspBuildTarget.map(_.id).contains + ).toList.asJava) throw new NotImplementedError("debugSessionStart endpoint is not implemented") } @@ -615,9 +630,11 @@ private class MillBuildServer( def completableTasks[T, V, W: ClassTag]( hint: String, targetIds: State => Seq[BuildTargetIdentifier], - tasks: PartialFunction[BspModule, Task[W]], - )(f: (Evaluator, State, BuildTargetIdentifier, BspModule, W) => T)(agg: ((java.util.List[T], State)) => V) - : CompletableFuture[V] = { + tasks: PartialFunction[BspModule, Task[W]] + )(f: (Evaluator, State, BuildTargetIdentifier, BspModule, W) => T)(agg: (( + java.util.List[T], + State + )) => V): CompletableFuture[V] = { val prefix = hint.split(" ").head completable(hint) { state: State => val ids = targetIds(state).filterNot(state.syntheticRootBspBuildTarget.map(_.id).contains) @@ -659,7 +676,7 @@ private class MillBuildServer( } } - agg((evaluated.flatten.toSeq.asJava,state)) + agg((evaluated.flatten.toSeq.asJava, state)) } } diff --git a/bsp/worker/src/mill/bsp/worker/MillJavaBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillJavaBuildServer.scala index acf003ae586..ac85ba78dd1 100644 --- a/bsp/worker/src/mill/bsp/worker/MillJavaBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillJavaBuildServer.scala @@ -41,7 +41,7 @@ private trait MillJavaBuildServer extends JavaBuildServer { this: MillBuildServe classpath.iterator.toSeq.asJava, sanitizeUri(classesPath.resolve(pathResolver)) ) - } {x=> + } { x => new JavacOptionsResult(x._1) } } diff --git a/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala index 0cd52ba33e7..e35ed7fa93f 100644 --- a/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala @@ -83,7 +83,7 @@ private trait MillJvmBuildServer extends JvmBuildServer { this: MillBuildServer val classes = mainClass.toList ++ zincWorker.discoverMainClasses(compile) item.setMainClasses(classes.map(new JvmMainClass(_, Nil.asJava)).asJava) item - } {x=> + } { x => agg(x._1) } } @@ -106,7 +106,7 @@ private trait MillJvmBuildServer extends JvmBuildServer { this: MillBuildServer .map(_.resolve(pathResolver)) .map(sanitizeUri).toSeq.asJava ) - } {x => + } { x => new JvmCompileClasspathResult(x._1) } } diff --git a/bsp/worker/src/mill/bsp/worker/MillScalaBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillScalaBuildServer.scala index fef139faabe..be4e073ad28 100644 --- a/bsp/worker/src/mill/bsp/worker/MillScalaBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillScalaBuildServer.scala @@ -75,7 +75,7 @@ private trait MillScalaBuildServer extends ScalaBuildServer { this: MillBuildSer .map(sanitizeUri).toSeq.asJava, sanitizeUri(classesPathTask.resolve(pathResolver)) ) - } {x => + } { x => new ScalacOptionsResult(x._1) } @@ -101,7 +101,7 @@ private trait MillScalaBuildServer extends ScalaBuildServer { this: MillBuildSer case (ev, state, id, _, _) => // no Java module, so no main classes new ScalaMainClassesItem(id, Seq.empty[ScalaMainClass].asJava) - } {x => + } { x => new ScalaMainClassesResult(x._1) } @@ -141,7 +141,7 @@ private trait MillScalaBuildServer extends ScalaBuildServer { this: MillBuildSer case (ev, state, id, _, _) => // Not a test module, so no test classes new ScalaTestClassesItem(id, Seq.empty[String].asJava) - } {x => + } { x => new ScalaTestClassesResult(x._1) } diff --git a/bsp/worker/src/mill/bsp/worker/State.scala b/bsp/worker/src/mill/bsp/worker/State.scala index 9cfb8730668..baab0bd0864 100644 --- a/bsp/worker/src/mill/bsp/worker/State.scala +++ b/bsp/worker/src/mill/bsp/worker/State.scala @@ -6,7 +6,7 @@ import mill.scalalib.internal.JavaModuleUtils import mill.define.Module import mill.eval.Evaluator -private class State(workspaceDir:os.Path,evaluators: Seq[Evaluator], debug: String => Unit) { +private class State(workspaceDir: os.Path, evaluators: Seq[Evaluator], debug: String => Unit) { lazy val bspModulesById: Map[BuildTargetIdentifier, (BspModule, Evaluator)] = { val modules: Seq[(Module, Seq[Module], Evaluator)] = evaluators .map(ev => (ev.rootModule, JavaModuleUtils.transitiveModules(ev.rootModule), ev)) @@ -34,6 +34,7 @@ private class State(workspaceDir:os.Path,evaluators: Seq[Evaluator], debug: Stri lazy val bspIdByModule: Map[BspModule, BuildTargetIdentifier] = bspModulesById.view.mapValues(_._1).map(_.swap).toMap - lazy val syntheticRootBspBuildTarget:Option[SyntheticRootBspBuildTargetData] = SyntheticRootBspBuildTargetData.makeIfNeeded(bspModulesById.values.map(_._1),workspaceDir) + lazy val syntheticRootBspBuildTarget: Option[SyntheticRootBspBuildTargetData] = + SyntheticRootBspBuildTargetData.makeIfNeeded(bspModulesById.values.map(_._1), workspaceDir) } diff --git a/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala b/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala index 81948cac16f..616bd316d4f 100644 --- a/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala +++ b/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala @@ -11,9 +11,11 @@ import scala.jdk.CollectionConverters._ /** * Synthesised [[BspBuildTarget]] to handle exclusions. * Intellij-Bsp doesn't provide a way to exclude files outside of module,so if there is no module having content root as [[topLevelProjectRoot]], [[SyntheticRootBspBuildTargetData]] will be created -*/ -class SyntheticRootBspBuildTargetData(topLevelProjectRoot:os.Path) { - val id: BuildTargetIdentifier = new BuildTargetIdentifier(Utils.sanitizeUri(topLevelProjectRoot / s"synth-build-target-${UUID.randomUUID()}")) + */ +class SyntheticRootBspBuildTargetData(topLevelProjectRoot: os.Path) { + val id: BuildTargetIdentifier = new BuildTargetIdentifier( + Utils.sanitizeUri(topLevelProjectRoot / s"synth-build-target-${UUID.randomUUID()}") + ) val bt = BspBuildTarget( displayName = Some(topLevelProjectRoot.last + "-root"), @@ -26,13 +28,17 @@ class SyntheticRootBspBuildTargetData(topLevelProjectRoot:os.Path) { canDebug = false ) - val target = makeBuildTarget(id,Seq.empty,bt,None) + val target = makeBuildTarget(id, Seq.empty, bt, None) private val sourcePath = topLevelProjectRoot / "src" - def synthSources = new SourcesItem(id,Seq(new SourceItem(sanitizeUri(sourcePath), SourceItemKind.DIRECTORY,false)).asJava) //intellijBSP does not create contentRootData for module with only outputPaths (this is probably a bug) + def synthSources = new SourcesItem( + id, + Seq(new SourceItem(sanitizeUri(sourcePath), SourceItemKind.DIRECTORY, false)).asJava + ) // intellijBSP does not create contentRootData for module with only outputPaths (this is probably a bug) } -object SyntheticRootBspBuildTargetData{ - def makeIfNeeded(existingModules:Iterable[BspModule],workspaceDir:os.Path) = { +object SyntheticRootBspBuildTargetData { + def makeIfNeeded(existingModules: Iterable[BspModule], workspaceDir: os.Path) = { def containsWorkspaceDir(path: Option[os.Path]) = path.exists(workspaceDir.startsWith) - if (existingModules.exists { m => containsWorkspaceDir(m.bspBuildTarget.baseDirectory) }) None else Some(new SyntheticRootBspBuildTargetData(workspaceDir)) + if (existingModules.exists { m => containsWorkspaceDir(m.bspBuildTarget.baseDirectory) }) None + else Some(new SyntheticRootBspBuildTargetData(workspaceDir)) } } diff --git a/bsp/worker/src/mill/bsp/worker/Utils.scala b/bsp/worker/src/mill/bsp/worker/Utils.scala index 58b3ecabc66..6f789455005 100644 --- a/bsp/worker/src/mill/bsp/worker/Utils.scala +++ b/bsp/worker/src/mill/bsp/worker/Utils.scala @@ -1,6 +1,15 @@ package mill.bsp.worker -import ch.epfl.scala.bsp4j.{BuildClient, BuildTarget, BuildTargetCapabilities, BuildTargetIdentifier, OutputPathItem, OutputPathItemKind, StatusCode, TaskId} +import ch.epfl.scala.bsp4j.{ + BuildClient, + BuildTarget, + BuildTargetCapabilities, + BuildTargetIdentifier, + OutputPathItem, + OutputPathItemKind, + StatusCode, + TaskId +} import mill.api.{CompileProblemReporter, PathRef} import mill.api.Result.{Skipped, Success} import mill.eval.Evaluator @@ -50,7 +59,12 @@ private object Utils { else StatusCode.OK } - def makeBuildTarget(id: BuildTargetIdentifier, depsIds: Seq[BuildTargetIdentifier], bt: BspBuildTarget,data:Option[(String,Object)]) = { + def makeBuildTarget( + id: BuildTargetIdentifier, + depsIds: Seq[BuildTargetIdentifier], + bt: BspBuildTarget, + data: Option[(String, Object)] + ) = { val buildTarget = new BuildTarget( id, bt.tags.asJava, @@ -65,7 +79,7 @@ private object Utils { ) bt.displayName.foreach(buildTarget.setDisplayName) - bt.baseDirectory.foreach(p =>buildTarget.setBaseDirectory(sanitizeUri(p))) + bt.baseDirectory.foreach(p => buildTarget.setBaseDirectory(sanitizeUri(p))) for ((dataKind, data) <- data) { buildTarget.setDataKind(dataKind) @@ -74,7 +88,7 @@ private object Utils { buildTarget } - def outputPaths(outDir: os.Path, buildTargetBaseDir: os.Path,topLevelProjectRoot:os.Path) = { + def outputPaths(outDir: os.Path, buildTargetBaseDir: os.Path, topLevelProjectRoot: os.Path) = { val output = new OutputPathItem( // Spec says, a directory must end with a forward slash sanitizeUri(outDir) + "/", @@ -83,16 +97,16 @@ private object Utils { def ignore(path: os.Path): Boolean = { path.last.startsWith(".") || - path.endsWith(os.RelPath("out")) || - path.endsWith(os.RelPath("target")) || - path.endsWith(os.RelPath("docs")) || - path.endsWith(os.RelPath("mill-build")) + path.endsWith(os.RelPath("out")) || + path.endsWith(os.RelPath("target")) || + path.endsWith(os.RelPath("docs")) || + path.endsWith(os.RelPath("mill-build")) } def projectsRootPaths = os.walk(topLevelProjectRoot, ignore).collect { case p if p.endsWith(os.RelPath("build.sc")) => p / up } - def outputPathItem(path:os.Path) = + def outputPathItem(path: os.Path) = new OutputPathItem( // Spec says, a directory must end with a forward slash sanitizeUri(path) + "/", @@ -103,12 +117,12 @@ private object Utils { outputPathItem(path / ".idea"), outputPathItem(path / "out"), outputPathItem(path / ".bsp"), - outputPathItem(path / ".bloop"), - ) + outputPathItem(path / ".bloop") + ) } output +: (if (topLevelProjectRoot.startsWith(buildTargetBaseDir)) { - additionalExclusions - } else Nil) + additionalExclusions + } else Nil) } private[this] def getStatusCodePerTask( results: Evaluator.Results, From 01075742b002c0b8399f6cdfea52da5064b018d5 Mon Sep 17 00:00:00 2001 From: Pawel Sadlo Date: Thu, 1 Aug 2024 16:24:39 +0200 Subject: [PATCH 14/24] format --- .../mill/bsp/worker/SyntheticRootBspBuildTargetData.scala | 7 ++++--- bsp/worker/src/mill/bsp/worker/Utils.scala | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala b/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala index 616bd316d4f..fed39b5b547 100644 --- a/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala +++ b/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala @@ -7,6 +7,7 @@ import mill.scalalib.bsp.BspModule.Tag import java.util.UUID import scala.jdk.CollectionConverters._ +import ch.epfl.scala.bsp4j.BuildTarget /** * Synthesised [[BspBuildTarget]] to handle exclusions. @@ -17,7 +18,7 @@ class SyntheticRootBspBuildTargetData(topLevelProjectRoot: os.Path) { Utils.sanitizeUri(topLevelProjectRoot / s"synth-build-target-${UUID.randomUUID()}") ) - val bt = BspBuildTarget( + val bt: BspBuildTarget = BspBuildTarget( displayName = Some(topLevelProjectRoot.last + "-root"), baseDirectory = Some(topLevelProjectRoot), tags = Seq(Tag.Manual), @@ -28,7 +29,7 @@ class SyntheticRootBspBuildTargetData(topLevelProjectRoot: os.Path) { canDebug = false ) - val target = makeBuildTarget(id, Seq.empty, bt, None) + val target: BuildTarget = makeBuildTarget(id, Seq.empty, bt, None) private val sourcePath = topLevelProjectRoot / "src" def synthSources = new SourcesItem( id, @@ -36,7 +37,7 @@ class SyntheticRootBspBuildTargetData(topLevelProjectRoot: os.Path) { ) // intellijBSP does not create contentRootData for module with only outputPaths (this is probably a bug) } object SyntheticRootBspBuildTargetData { - def makeIfNeeded(existingModules: Iterable[BspModule], workspaceDir: os.Path) = { + def makeIfNeeded(existingModules: Iterable[BspModule], workspaceDir: os.Path): Option[SyntheticRootBspBuildTargetData] = { def containsWorkspaceDir(path: Option[os.Path]) = path.exists(workspaceDir.startsWith) if (existingModules.exists { m => containsWorkspaceDir(m.bspBuildTarget.baseDirectory) }) None else Some(new SyntheticRootBspBuildTargetData(workspaceDir)) diff --git a/bsp/worker/src/mill/bsp/worker/Utils.scala b/bsp/worker/src/mill/bsp/worker/Utils.scala index 6f789455005..a7fbc76caf6 100644 --- a/bsp/worker/src/mill/bsp/worker/Utils.scala +++ b/bsp/worker/src/mill/bsp/worker/Utils.scala @@ -64,7 +64,7 @@ private object Utils { depsIds: Seq[BuildTargetIdentifier], bt: BspBuildTarget, data: Option[(String, Object)] - ) = { + ): BuildTarget = { val buildTarget = new BuildTarget( id, bt.tags.asJava, @@ -88,7 +88,7 @@ private object Utils { buildTarget } - def outputPaths(outDir: os.Path, buildTargetBaseDir: os.Path, topLevelProjectRoot: os.Path) = { + def outputPaths(outDir: os.Path, buildTargetBaseDir: os.Path, topLevelProjectRoot: os.Path): Seq[OutputPathItem] = { val output = new OutputPathItem( // Spec says, a directory must end with a forward slash sanitizeUri(outDir) + "/", From 2ade14a33d8deb356d03e2681d958e95d82b9127 Mon Sep 17 00:00:00 2001 From: Pawel Sadlo Date: Thu, 1 Aug 2024 16:47:19 +0200 Subject: [PATCH 15/24] format --- .../mill/bsp/worker/SyntheticRootBspBuildTargetData.scala | 5 ++++- bsp/worker/src/mill/bsp/worker/Utils.scala | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala b/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala index fed39b5b547..3eda421be9a 100644 --- a/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala +++ b/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala @@ -37,7 +37,10 @@ class SyntheticRootBspBuildTargetData(topLevelProjectRoot: os.Path) { ) // intellijBSP does not create contentRootData for module with only outputPaths (this is probably a bug) } object SyntheticRootBspBuildTargetData { - def makeIfNeeded(existingModules: Iterable[BspModule], workspaceDir: os.Path): Option[SyntheticRootBspBuildTargetData] = { + def makeIfNeeded( + existingModules: Iterable[BspModule], + workspaceDir: os.Path + ): Option[SyntheticRootBspBuildTargetData] = { def containsWorkspaceDir(path: Option[os.Path]) = path.exists(workspaceDir.startsWith) if (existingModules.exists { m => containsWorkspaceDir(m.bspBuildTarget.baseDirectory) }) None else Some(new SyntheticRootBspBuildTargetData(workspaceDir)) diff --git a/bsp/worker/src/mill/bsp/worker/Utils.scala b/bsp/worker/src/mill/bsp/worker/Utils.scala index a7fbc76caf6..235dff59c14 100644 --- a/bsp/worker/src/mill/bsp/worker/Utils.scala +++ b/bsp/worker/src/mill/bsp/worker/Utils.scala @@ -88,7 +88,11 @@ private object Utils { buildTarget } - def outputPaths(outDir: os.Path, buildTargetBaseDir: os.Path, topLevelProjectRoot: os.Path): Seq[OutputPathItem] = { + def outputPaths( + outDir: os.Path, + buildTargetBaseDir: os.Path, + topLevelProjectRoot: os.Path + ): Seq[OutputPathItem] = { val output = new OutputPathItem( // Spec says, a directory must end with a forward slash sanitizeUri(outDir) + "/", From 392280b6c2b18102325ef7af7b6b26ac38980b49 Mon Sep 17 00:00:00 2001 From: pawelsadlo <106806258+pawelsadlo@users.noreply.github.com> Date: Thu, 1 Aug 2024 20:38:02 +0200 Subject: [PATCH 16/24] Update SyntheticRootBspBuildTargetData.scala --- .../src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala b/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala index 3eda421be9a..45302e0ce97 100644 --- a/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala +++ b/bsp/worker/src/mill/bsp/worker/SyntheticRootBspBuildTargetData.scala @@ -11,7 +11,7 @@ import ch.epfl.scala.bsp4j.BuildTarget /** * Synthesised [[BspBuildTarget]] to handle exclusions. - * Intellij-Bsp doesn't provide a way to exclude files outside of module,so if there is no module having content root as [[topLevelProjectRoot]], [[SyntheticRootBspBuildTargetData]] will be created + * Intellij-Bsp doesn't provide a way to exclude files outside of module,so if there is no module having content root of [[topLevelProjectRoot]], [[SyntheticRootBspBuildTargetData]] will be created */ class SyntheticRootBspBuildTargetData(topLevelProjectRoot: os.Path) { val id: BuildTargetIdentifier = new BuildTargetIdentifier( From a0e81628e166570d7ef01960f601b5cc4d2a457d Mon Sep 17 00:00:00 2001 From: Pawel Sadlo Date: Sun, 4 Aug 2024 10:31:49 +0200 Subject: [PATCH 17/24] review suggestions --- .../src/mill/bsp/worker/MillBuildServer.scala | 38 ++++++++++++------- .../mill/bsp/worker/MillJavaBuildServer.scala | 4 +- .../mill/bsp/worker/MillJvmBuildServer.scala | 8 ++-- .../bsp/worker/MillScalaBuildServer.scala | 12 +++--- bsp/worker/src/mill/bsp/worker/Utils.scala | 3 +- 5 files changed, 38 insertions(+), 27 deletions(-) diff --git a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala index 4137ef330a2..cf62e8ae250 100644 --- a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala @@ -153,7 +153,7 @@ private class MillBuildServer( } override def workspaceBuildTargets(): CompletableFuture[WorkspaceBuildTargetsResult] = - completableTasks( + completableTasksWithState( "workspaceBuildTargets", targetIds = _.bspModulesById.keySet.toSeq, tasks = { case m: BspModule => m.bspBuildTargetData } @@ -192,7 +192,7 @@ private class MillBuildServer( val bt = m.bspBuildTarget makeBuildTarget(id, depsIds, bt, data) - } { case (targets, state) => + } { (targets, state) => new WorkspaceBuildTargetsResult( (targets.asScala ++ state.syntheticRootBspBuildTarget.map(_.target)).asJava ) @@ -225,7 +225,7 @@ private class MillBuildServer( generated ) - completableTasks( + completableTasksWithState( hint = s"buildTargetSources ${sourcesParams}", targetIds = _ => sourcesParams.getTargets.asScala.toSeq, tasks = { @@ -243,7 +243,7 @@ private class MillBuildServer( } ) { case (ev, state, id, module, items) => new SourcesItem(id, items.asJava) - } { case (sourceItems, state) => + } { (sourceItems, state) => new SourcesResult( (sourceItems.asScala.toSeq ++ state.syntheticRootBspBuildTarget.map(_.synthSources)).asJava ) @@ -316,8 +316,8 @@ private class MillBuildServer( val cp = (resolveDepsSources ++ unmanagedClasspath).map(sanitizeUri).toSeq ++ buildSources new DependencySourcesItem(id, cp.asJava) - } { x => - new DependencySourcesResult(x._1) + } { + new DependencySourcesResult(_) } /** @@ -355,8 +355,8 @@ private class MillBuildServer( new DependencyModule(s"unmanaged-${dep.path.last}", "") } new DependencyModulesItem(id, (deps ++ unmanged).iterator.toSeq.asJava) - } { x => - new DependencyModulesResult(x._1) + } { + new DependencyModulesResult(_) } override def buildTargetResources(p: ResourcesParams): CompletableFuture[ResourcesResult] = @@ -372,8 +372,8 @@ private class MillBuildServer( val resourcesUrls = resources.map(_.path).filter(os.exists).map(sanitizeUri) new ResourcesItem(id, resourcesUrls.asJava) - } { x => - new ResourcesResult(x._1) + } { + new ResourcesResult(_) } // TODO: if the client wants to give compilation arguments and the module @@ -631,10 +631,22 @@ private class MillBuildServer( hint: String, targetIds: State => Seq[BuildTargetIdentifier], tasks: PartialFunction[BspModule, Task[W]] - )(f: (Evaluator, State, BuildTargetIdentifier, BspModule, W) => T)(agg: (( + )(f: (Evaluator, State, BuildTargetIdentifier, BspModule, W) => T)(agg: java.util.List[T] => V) + : CompletableFuture[V] = + completableTasksWithState[T, V, W](hint, targetIds, tasks)(f)((l, _) => agg(l)) + + /** + * @params tasks A partial function + * @param f The function must accept the same modules as the partial function given by `tasks`. + */ + def completableTasksWithState[T, V, W: ClassTag]( + hint: String, + targetIds: State => Seq[BuildTargetIdentifier], + tasks: PartialFunction[BspModule, Task[W]] + )(f: (Evaluator, State, BuildTargetIdentifier, BspModule, W) => T)(agg: ( java.util.List[T], State - )) => V): CompletableFuture[V] = { + ) => V): CompletableFuture[V] = { val prefix = hint.split(" ").head completable(hint) { state: State => val ids = targetIds(state).filterNot(state.syntheticRootBspBuildTarget.map(_.id).contains) @@ -676,7 +688,7 @@ private class MillBuildServer( } } - agg((evaluated.flatten.toSeq.asJava, state)) + agg(evaluated.flatten.toSeq.asJava, state) } } diff --git a/bsp/worker/src/mill/bsp/worker/MillJavaBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillJavaBuildServer.scala index ac85ba78dd1..4e43072beb5 100644 --- a/bsp/worker/src/mill/bsp/worker/MillJavaBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillJavaBuildServer.scala @@ -41,7 +41,7 @@ private trait MillJavaBuildServer extends JavaBuildServer { this: MillBuildServe classpath.iterator.toSeq.asJava, sanitizeUri(classesPath.resolve(pathResolver)) ) - } { x => - new JavacOptionsResult(x._1) + } { + new JavacOptionsResult(_) } } diff --git a/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala index e35ed7fa93f..af8b7a6759d 100644 --- a/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala @@ -83,8 +83,8 @@ private trait MillJvmBuildServer extends JvmBuildServer { this: MillBuildServer val classes = mainClass.toList ++ zincWorker.discoverMainClasses(compile) item.setMainClasses(classes.map(new JvmMainClass(_, Nil.asJava)).asJava) item - } { x => - agg(x._1) + } { + agg(_) } } @@ -106,7 +106,7 @@ private trait MillJvmBuildServer extends JvmBuildServer { this: MillBuildServer .map(_.resolve(pathResolver)) .map(sanitizeUri).toSeq.asJava ) - } { x => - new JvmCompileClasspathResult(x._1) + } { + new JvmCompileClasspathResult(_) } } diff --git a/bsp/worker/src/mill/bsp/worker/MillScalaBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillScalaBuildServer.scala index be4e073ad28..a34a6ab037a 100644 --- a/bsp/worker/src/mill/bsp/worker/MillScalaBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillScalaBuildServer.scala @@ -75,8 +75,8 @@ private trait MillScalaBuildServer extends ScalaBuildServer { this: MillBuildSer .map(sanitizeUri).toSeq.asJava, sanitizeUri(classesPathTask.resolve(pathResolver)) ) - } { x => - new ScalacOptionsResult(x._1) + } { + new ScalacOptionsResult(_) } override def buildTargetScalaMainClasses(p: ScalaMainClassesParams) @@ -101,8 +101,8 @@ private trait MillScalaBuildServer extends ScalaBuildServer { this: MillBuildSer case (ev, state, id, _, _) => // no Java module, so no main classes new ScalaMainClassesItem(id, Seq.empty[ScalaMainClass].asJava) - } { x => - new ScalaMainClassesResult(x._1) + } { + new ScalaMainClassesResult(_) } override def buildTargetScalaTestClasses(p: ScalaTestClassesParams) @@ -141,8 +141,8 @@ private trait MillScalaBuildServer extends ScalaBuildServer { this: MillBuildSer case (ev, state, id, _, _) => // Not a test module, so no test classes new ScalaTestClassesItem(id, Seq.empty[String].asJava) - } { x => - new ScalaTestClassesResult(x._1) + } { + new ScalaTestClassesResult(_) } } diff --git a/bsp/worker/src/mill/bsp/worker/Utils.scala b/bsp/worker/src/mill/bsp/worker/Utils.scala index 235dff59c14..fde1231b798 100644 --- a/bsp/worker/src/mill/bsp/worker/Utils.scala +++ b/bsp/worker/src/mill/bsp/worker/Utils.scala @@ -15,7 +15,6 @@ import mill.api.Result.{Skipped, Success} import mill.eval.Evaluator import mill.scalalib.JavaModule import mill.scalalib.bsp.{BspBuildTarget, BspModule} -import os.up import scala.jdk.CollectionConverters._ import scala.util.chaining.scalaUtilChainingOps @@ -108,7 +107,7 @@ private object Utils { } def projectsRootPaths = os.walk(topLevelProjectRoot, ignore).collect { - case p if p.endsWith(os.RelPath("build.sc")) => p / up + case p if p.endsWith(os.RelPath("build.sc")) => p / os.up } def outputPathItem(path: os.Path) = new OutputPathItem( From 6dee46364c180f1be577d8b97c83a8b198c23285 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Mon, 5 Aug 2024 14:29:57 -0700 Subject: [PATCH 18/24] Update Utils.scala --- bsp/worker/src/mill/bsp/worker/Utils.scala | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/bsp/worker/src/mill/bsp/worker/Utils.scala b/bsp/worker/src/mill/bsp/worker/Utils.scala index fde1231b798..22a693ae298 100644 --- a/bsp/worker/src/mill/bsp/worker/Utils.scala +++ b/bsp/worker/src/mill/bsp/worker/Utils.scala @@ -100,10 +100,8 @@ private object Utils { def ignore(path: os.Path): Boolean = { path.last.startsWith(".") || - path.endsWith(os.RelPath("out")) || - path.endsWith(os.RelPath("target")) || - path.endsWith(os.RelPath("docs")) || - path.endsWith(os.RelPath("mill-build")) + path.last == "out" || + path.last == "target" } def projectsRootPaths = os.walk(topLevelProjectRoot, ignore).collect { From ce1e933108f60b0a0958b8aa7e81a97c9276cf59 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Thu, 22 Aug 2024 14:50:17 +0800 Subject: [PATCH 19/24] top level ignored folders only --- .../src/mill/bsp/worker/MillBuildServer.scala | 5 +-- bsp/worker/src/mill/bsp/worker/Utils.scala | 39 +++++-------------- 2 files changed, 12 insertions(+), 32 deletions(-) diff --git a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala index cf62e8ae250..f418a9dbcce 100644 --- a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala @@ -419,7 +419,7 @@ private class MillBuildServer( synthTarget <- state.syntheticRootBspBuildTarget if params.getTargets.contains(synthTarget.id) baseDir <- synthTarget.bt.baseDirectory - } yield new OutputPathsItem(synthTarget.id, outputPaths(baseDir / "out", baseDir, topLevelProjectRoot).asJava) + } yield new OutputPathsItem(synthTarget.id, outputPaths(baseDir, topLevelProjectRoot).asJava) val items = for { target <- params.getTargets.asScala @@ -429,12 +429,11 @@ private class MillBuildServer( module match { case external if external.millOuterCtx.external => outputPaths( - ev.externalOutPath, module.bspBuildTarget.baseDirectory.get, topLevelProjectRoot ) case _ => - outputPaths(ev.outPath, module.bspBuildTarget.baseDirectory.get, topLevelProjectRoot) + outputPaths(module.bspBuildTarget.baseDirectory.get, topLevelProjectRoot) } } diff --git a/bsp/worker/src/mill/bsp/worker/Utils.scala b/bsp/worker/src/mill/bsp/worker/Utils.scala index 22a693ae298..cb17c6b3f34 100644 --- a/bsp/worker/src/mill/bsp/worker/Utils.scala +++ b/bsp/worker/src/mill/bsp/worker/Utils.scala @@ -88,43 +88,24 @@ private object Utils { } def outputPaths( - outDir: os.Path, buildTargetBaseDir: os.Path, topLevelProjectRoot: os.Path ): Seq[OutputPathItem] = { - val output = new OutputPathItem( - // Spec says, a directory must end with a forward slash - sanitizeUri(outDir) + "/", - OutputPathItemKind.DIRECTORY - ) - - def ignore(path: os.Path): Boolean = { - path.last.startsWith(".") || - path.last == "out" || - path.last == "target" - } - def projectsRootPaths = os.walk(topLevelProjectRoot, ignore).collect { - case p if p.endsWith(os.RelPath("build.sc")) => p / os.up - } def outputPathItem(path: os.Path) = - new OutputPathItem( - // Spec says, a directory must end with a forward slash - sanitizeUri(path) + "/", - OutputPathItemKind.DIRECTORY - ) - def additionalExclusions = projectsRootPaths.flatMap { path => + // Spec says, a directory must end with a forward slash + new OutputPathItem(sanitizeUri(path) + "/", OutputPathItemKind.DIRECTORY) + + if (topLevelProjectRoot.startsWith(buildTargetBaseDir)) Seq( - outputPathItem(path / ".idea"), - outputPathItem(path / "out"), - outputPathItem(path / ".bsp"), - outputPathItem(path / ".bloop") + outputPathItem(topLevelProjectRoot / ".idea"), + outputPathItem(topLevelProjectRoot / "out"), + outputPathItem(topLevelProjectRoot / ".bsp"), + outputPathItem(topLevelProjectRoot / ".bloop") ) - } - output +: (if (topLevelProjectRoot.startsWith(buildTargetBaseDir)) { - additionalExclusions - } else Nil) + else Nil } + private[this] def getStatusCodePerTask( results: Evaluator.Results, task: mill.define.Task[_] From 94a01c9656ff3050d51193fad8cb2a018a460b77 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Thu, 22 Aug 2024 14:55:04 +0800 Subject: [PATCH 20/24] . --- .../src/mill/bsp/worker/MillBuildServer.scala | 18 +++++------------- bsp/worker/src/mill/bsp/worker/State.scala | 4 ++++ bsp/worker/src/mill/bsp/worker/Utils.scala | 2 +- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala index f418a9dbcce..73c47bcb3d5 100644 --- a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala @@ -380,9 +380,7 @@ private class MillBuildServer( // already has some from the build file, what to do? override def buildTargetCompile(p: CompileParams): CompletableFuture[CompileResult] = completable(s"buildTargetCompile ${p}") { state => - p.setTargets(p.getTargets.asScala.filterNot( - state.syntheticRootBspBuildTarget.map(_.id).contains - ).toList.asJava) + p.setTargets(state.filterNonSynthetic(p.getTargets)) val params = TaskParameters.fromCompileParams(p) val taskId = params.hashCode() val compileTasksEvs = params.getTargets.distinct.map(state.bspModulesById).map { @@ -471,9 +469,7 @@ private class MillBuildServer( override def buildTargetTest(testParams: TestParams): CompletableFuture[TestResult] = completable(s"buildTargetTest ${testParams}") { state => - testParams.setTargets(testParams.getTargets.asScala.toSeq.filterNot( - state.syntheticRootBspBuildTarget.map(_.id).contains - ).toList.asJava) + testParams.setTargets(state.filterNonSynthetic(testParams.getTargets)) val millBuildTargetIds = state .rootModules .map { case m: BspModule => state.bspIdByModule(m) } @@ -565,9 +561,7 @@ private class MillBuildServer( override def buildTargetCleanCache(cleanCacheParams: CleanCacheParams) : CompletableFuture[CleanCacheResult] = completable(s"buildTargetCleanCache ${cleanCacheParams}") { state => - cleanCacheParams.setTargets(cleanCacheParams.getTargets.asScala.toSeq.filterNot( - state.syntheticRootBspBuildTarget.map(_.id).contains - ).toList.asJava) + cleanCacheParams.setTargets(state.filterNonSynthetic(cleanCacheParams.getTargets)) val (msg, cleaned) = cleanCacheParams.getTargets.asScala.foldLeft(( "", @@ -616,9 +610,7 @@ private class MillBuildServer( override def debugSessionStart(debugParams: DebugSessionParams) : CompletableFuture[DebugSessionAddress] = completable(s"debugSessionStart ${debugParams}") { state => - debugParams.setTargets(debugParams.getTargets.asScala.toSeq.filterNot( - state.syntheticRootBspBuildTarget.map(_.id).contains - ).toList.asJava) + debugParams.setTargets(state.filterNonSynthetic(debugParams.getTargets)) throw new NotImplementedError("debugSessionStart endpoint is not implemented") } @@ -648,7 +640,7 @@ private class MillBuildServer( ) => V): CompletableFuture[V] = { val prefix = hint.split(" ").head completable(hint) { state: State => - val ids = targetIds(state).filterNot(state.syntheticRootBspBuildTarget.map(_.id).contains) + val ids = state.filterNonSynthetic(targetIds(state).asJava).asScala val tasksSeq = ids.flatMap { id => val (m, ev) = state.bspModulesById(id) tasks.lift.apply(m).map(ts => (ts, (ev, id))) diff --git a/bsp/worker/src/mill/bsp/worker/State.scala b/bsp/worker/src/mill/bsp/worker/State.scala index baab0bd0864..919781189b8 100644 --- a/bsp/worker/src/mill/bsp/worker/State.scala +++ b/bsp/worker/src/mill/bsp/worker/State.scala @@ -37,4 +37,8 @@ private class State(workspaceDir: os.Path, evaluators: Seq[Evaluator], debug: St lazy val syntheticRootBspBuildTarget: Option[SyntheticRootBspBuildTargetData] = SyntheticRootBspBuildTargetData.makeIfNeeded(bspModulesById.values.map(_._1), workspaceDir) + def filterNonSynthetic(input: java.util.List[BuildTargetIdentifier]): java.util.List[BuildTargetIdentifier] = { + import collection.JavaConverters._ + input.asScala.filterNot(syntheticRootBspBuildTarget.map(_.id).contains).toList.asJava + } } diff --git a/bsp/worker/src/mill/bsp/worker/Utils.scala b/bsp/worker/src/mill/bsp/worker/Utils.scala index cb17c6b3f34..5fe3f57b190 100644 --- a/bsp/worker/src/mill/bsp/worker/Utils.scala +++ b/bsp/worker/src/mill/bsp/worker/Utils.scala @@ -93,7 +93,7 @@ private object Utils { ): Seq[OutputPathItem] = { def outputPathItem(path: os.Path) = - // Spec says, a directory must end with a forward slash + // Spec says, a directory must end with a forward slash new OutputPathItem(sanitizeUri(path) + "/", OutputPathItemKind.DIRECTORY) if (topLevelProjectRoot.startsWith(buildTargetBaseDir)) From 7a6e3b34998aa8f0c19c24fc3086c83d884dfad3 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Thu, 22 Aug 2024 14:57:58 +0800 Subject: [PATCH 21/24] . --- .../src/mill/bsp/worker/MillBuildServer.scala | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala index db2ed3aca8c..eb5a99bb58f 100644 --- a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala @@ -423,17 +423,15 @@ private class MillBuildServer( target <- params.getTargets.asScala (module, ev) <- state.bspModulesById.get(target) } yield { - val items = { - module match { - case external if external.millOuterCtx.external => - outputPaths( - module.bspBuildTarget.baseDirectory.get, - topLevelProjectRoot - ) - case _ => - outputPaths(module.bspBuildTarget.baseDirectory.get, topLevelProjectRoot) - } - } + val items = + if (module.millOuterCtx.external) + outputPaths( + module.bspBuildTarget.baseDirectory.get, + topLevelProjectRoot + ) + else + outputPaths(module.bspBuildTarget.baseDirectory.get, topLevelProjectRoot) + new OutputPathsItem(target, items.asJava) } From 2533d492d672fb09488283193b3db06bcce0531a Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Thu, 22 Aug 2024 15:01:06 +0800 Subject: [PATCH 22/24] . --- bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala index af8b7a6759d..b358ddcc28e 100644 --- a/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala @@ -84,7 +84,7 @@ private trait MillJvmBuildServer extends JvmBuildServer { this: MillBuildServer item.setMainClasses(classes.map(new JvmMainClass(_, Nil.asJava)).asJava) item } { - agg(_) + agg } } From 317210181e42fb68047ccd085b289913e9918d0c Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Thu, 22 Aug 2024 15:13:57 +0800 Subject: [PATCH 23/24] . --- bsp/src/mill/bsp/BspContext.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bsp/src/mill/bsp/BspContext.scala b/bsp/src/mill/bsp/BspContext.scala index 25a7ab6dbfa..9b5cadcbbd2 100644 --- a/bsp/src/mill/bsp/BspContext.scala +++ b/bsp/src/mill/bsp/BspContext.scala @@ -62,7 +62,7 @@ private[mill] class BspContext( override def rawOutputStream: PrintStream = systemStreams.out } - BspWorker(os.pwd, home, log).flatMap { worker => + BspWorker(mill.api.WorkspaceRoot.workspaceRoot, home, log).flatMap { worker => os.makeDir.all(home / Constants.bspDir) worker.startBspServer( streams, From 1c8ad5ffb0c66d092c77b8c8d30d3e3c7526e29e Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Thu, 22 Aug 2024 15:58:09 +0800 Subject: [PATCH 24/24] . --- bsp/worker/src/mill/bsp/worker/MillBuildServer.scala | 1 - bsp/worker/src/mill/bsp/worker/State.scala | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala index eb5a99bb58f..e10f60c8702 100644 --- a/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala +++ b/bsp/worker/src/mill/bsp/worker/MillBuildServer.scala @@ -432,7 +432,6 @@ private class MillBuildServer( else outputPaths(module.bspBuildTarget.baseDirectory.get, topLevelProjectRoot) - new OutputPathsItem(target, items.asJava) } diff --git a/bsp/worker/src/mill/bsp/worker/State.scala b/bsp/worker/src/mill/bsp/worker/State.scala index 4574eaf8a28..c3b70f322f1 100644 --- a/bsp/worker/src/mill/bsp/worker/State.scala +++ b/bsp/worker/src/mill/bsp/worker/State.scala @@ -37,7 +37,8 @@ private class State(workspaceDir: os.Path, evaluators: Seq[Evaluator], debug: St lazy val syntheticRootBspBuildTarget: Option[SyntheticRootBspBuildTargetData] = SyntheticRootBspBuildTargetData.makeIfNeeded(bspModulesById.values.map(_._1), workspaceDir) - def filterNonSynthetic(input: java.util.List[BuildTargetIdentifier]): java.util.List[BuildTargetIdentifier] = { + def filterNonSynthetic(input: java.util.List[BuildTargetIdentifier]) + : java.util.List[BuildTargetIdentifier] = { import collection.JavaConverters._ input.asScala.filterNot(syntheticRootBspBuildTarget.map(_.id).contains).toList.asJava }