diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index f4e7d004f..89c8f898d 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -9,7 +9,7 @@ package sbt import java.io.{ File, PrintWriter } import java.net.{ URI, URL, URLClassLoader } -import java.nio.file.{ Path => NioPath, Paths } +import java.nio.file.{ Paths, Path => NioPath } import java.util.Optional import java.util.concurrent.TimeUnit @@ -43,6 +43,7 @@ import sbt.internal.librarymanagement.mavenint.{ import sbt.internal.librarymanagement.{ CustomHttp => _, _ } import sbt.internal.nio.{ CheckBuildSources, Globs } import sbt.internal.server.{ + BspCompileTask, BuildServerProtocol, BuildServerReporter, Definition, @@ -644,7 +645,7 @@ object Defaults extends BuildCommon { compile := compileTask.value, internalDependencyConfigurations := InternalDependencies.configurations.value, manipulateBytecode := compileIncremental.value, - compileIncremental := (compileIncrementalTask tag (Tags.Compile, Tags.CPU)).value, + compileIncremental := compileIncrementalTask.tag(Tags.Compile, Tags.CPU).value, printWarnings := printWarningsTask.value, compileAnalysisFilename := { // Here, if the user wants cross-scala-versioning, we also append it @@ -1854,8 +1855,10 @@ object Defaults extends BuildCommon { analysis } def compileIncrementalTask = Def.task { - // TODO - Should readAnalysis + saveAnalysis be scoped by the compile task too? - compileIncrementalTaskImpl(streams.value, (compileInputs in compile).value) + BspCompileTask.compute(bspTargetIdentifier.value, thisProjectRef.value, configuration.value) { + // TODO - Should readAnalysis + saveAnalysis be scoped by the compile task too? + compileIncrementalTaskImpl(streams.value, (compileInputs in compile).value) + } } private val incCompiler = ZincUtil.defaultIncrementalCompiler private[this] def compileIncrementalTaskImpl(s: TaskStreams, ci: Inputs): CompileResult = { diff --git a/main/src/main/scala/sbt/internal/server/BspCompileTask.scala b/main/src/main/scala/sbt/internal/server/BspCompileTask.scala new file mode 100644 index 000000000..a6efcb6ec --- /dev/null +++ b/main/src/main/scala/sbt/internal/server/BspCompileTask.scala @@ -0,0 +1,109 @@ +package sbt.internal.server + +import sbt._ +import sbt.internal.bsp._ +import sbt.librarymanagement.Configuration +import sjsonnew.support.scalajson.unsafe.Converter +import xsbti.compile.CompileResult +import xsbti.{ CompileFailed, Problem, Severity } + +import scala.util.control.NonFatal + +object BspCompileTask { + import sbt.internal.bsp.codec.JsonProtocol._ + + private lazy val exchange = StandardMain.exchange + + def compute(targetId: BuildTargetIdentifier, project: ProjectRef, config: Configuration)( + compile: => CompileResult + ): CompileResult = { + val task = BspCompileTask(targetId, project, config) + try { + notifyStart(task) + val result = compile + notifySuccess(task, result) + result + } catch { + case NonFatal(cause) => + val compileFailed = cause match { + case failed: CompileFailed => Some(failed) + case _ => None + } + notifyFailure(task, compileFailed) + throw cause + } + } + + private def apply( + targetId: BuildTargetIdentifier, + project: ProjectRef, + config: Configuration + ): BspCompileTask = { + val taskId = TaskId(BuildServerTasks.uniqueId, Vector()) + val targetName = BuildTargetName.fromScope(project.project, config.name) + BspCompileTask(targetId, targetName, taskId, System.currentTimeMillis()) + } + + private def notifyStart(task: BspCompileTask): Unit = { + val message = s"Compiling ${task.targetName}" + val data = Converter.toJsonUnsafe(CompileTask(task.targetId)) + val params = TaskStartParams(task.id, task.startTimeMillis, message, "compile-task", data) + exchange.notifyEvent("build/taskStart", params) + } + + private def notifySuccess(task: BspCompileTask, result: CompileResult): Unit = { + import collection.JavaConverters._ + val endTimeMillis = System.currentTimeMillis() + val elapsedTimeMillis = endTimeMillis - task.startTimeMillis + val problems = result match { + case compileResult: CompileResult => + val sourceInfos = compileResult.analysis().readSourceInfos().getAllSourceInfos.asScala + sourceInfos.values.flatMap(_.getReportedProblems).toSeq + case _ => Seq() + } + val report = compileReport(problems, task.targetId, elapsedTimeMillis) + val params = TaskFinishParams( + task.id, + endTimeMillis, + s"Compiled ${task.targetName}", + StatusCode.Success, + "compile-report", + Converter.toJsonUnsafe(report) + ) + exchange.notifyEvent("build/taskFinish", params) + } + + private def notifyFailure(task: BspCompileTask, cause: Option[CompileFailed]): Unit = { + val endTimeMillis = System.currentTimeMillis() + val elapsedTimeMillis = endTimeMillis - task.startTimeMillis + val problems = cause.map(_.problems().toSeq).getOrElse(Seq.empty[Problem]) + val report = compileReport(problems, task.targetId, elapsedTimeMillis) + val params = TaskFinishParams( + task.id, + endTimeMillis, + s"Compiled ${task.targetName}", + StatusCode.Error, + "compile-report", + Converter.toJsonUnsafe(report) + ) + exchange.notifyEvent("build/taskFinish", params) + } + + private def compileReport( + problems: Seq[Problem], + targetId: BuildTargetIdentifier, + elapsedTimeMillis: Long + ): CompileReport = { + val countBySeverity = problems.groupBy(_.severity()).mapValues(_.size) + val warnings = countBySeverity.getOrElse(Severity.Warn, 0) + val errors = countBySeverity.getOrElse(Severity.Error, 0) + CompileReport(targetId, None, errors, warnings, Some(elapsedTimeMillis.toInt)) + } +} + +case class BspCompileTask private ( + targetId: BuildTargetIdentifier, + targetName: String, + id: TaskId, + startTimeMillis: Long +) diff --git a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala index 5cb176826..74c8e524c 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala @@ -208,10 +208,7 @@ object BuildServerProtocol { jars = scalaJars.toVector ) val configuration = Keys.configuration.value - val displayName = configuration.name match { - case "compile" => thisProject.id - case configName => s"${thisProject.id}-$configName" - } + val displayName = BuildTargetName.fromScope(thisProject.id, configuration.name) val baseDirectory = Keys.baseDirectory.value.toURI val projectDependencies = for { (dep, configs) <- Keys.bspInternalDependencyConfigurations.value @@ -299,14 +296,7 @@ object BuildServerProtocol { } } - def scopeFilter( - targets: Seq[BuildTargetIdentifier], - workspace: Map[BuildTargetIdentifier, Scope] - ): ScopeFilter = { - ScopeFilter.in(targets.map(workspace)) - } - - def toId(ref: ProjectReference, config: Configuration): BuildTargetIdentifier = + private def toId(ref: ProjectReference, config: Configuration): BuildTargetIdentifier = ref match { case ProjectRef(build, project) => BuildTargetIdentifier(new URI(s"$build#$project/${config.id}")) diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/CompileReport.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/CompileReport.scala new file mode 100644 index 000000000..1d839e3ac --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/CompileReport.scala @@ -0,0 +1,62 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp +/** + * @param target The build target that was compiled + * @param originId An optional request id to know the origin of this report + * @param errors The total number of reported errors compiling this target. + * @param warnings The total number of reported warnings compiling the target. + * @param time The total number of milliseconds it took to compile the target. + */ +final class CompileReport private ( + val target: sbt.internal.bsp.BuildTargetIdentifier, + val originId: Option[String], + val errors: Int, + val warnings: Int, + val time: Option[Int]) extends Serializable { + + + + override def equals(o: Any): Boolean = o match { + case x: CompileReport => (this.target == x.target) && (this.originId == x.originId) && (this.errors == x.errors) && (this.warnings == x.warnings) && (this.time == x.time) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.CompileReport".##) + target.##) + originId.##) + errors.##) + warnings.##) + time.##) + } + override def toString: String = { + "CompileReport(" + target + ", " + originId + ", " + errors + ", " + warnings + ", " + time + ")" + } + private[this] def copy(target: sbt.internal.bsp.BuildTargetIdentifier = target, originId: Option[String] = originId, errors: Int = errors, warnings: Int = warnings, time: Option[Int] = time): CompileReport = { + new CompileReport(target, originId, errors, warnings, time) + } + def withTarget(target: sbt.internal.bsp.BuildTargetIdentifier): CompileReport = { + copy(target = target) + } + def withOriginId(originId: Option[String]): CompileReport = { + copy(originId = originId) + } + def withOriginId(originId: String): CompileReport = { + copy(originId = Option(originId)) + } + def withErrors(errors: Int): CompileReport = { + copy(errors = errors) + } + def withWarnings(warnings: Int): CompileReport = { + copy(warnings = warnings) + } + def withTime(time: Option[Int]): CompileReport = { + copy(time = time) + } + def withTime(time: Int): CompileReport = { + copy(time = Option(time)) + } +} +object CompileReport { + + def apply(target: sbt.internal.bsp.BuildTargetIdentifier, originId: Option[String], errors: Int, warnings: Int, time: Option[Int]): CompileReport = new CompileReport(target, originId, errors, warnings, time) + def apply(target: sbt.internal.bsp.BuildTargetIdentifier, originId: String, errors: Int, warnings: Int, time: Int): CompileReport = new CompileReport(target, Option(originId), errors, warnings, Option(time)) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/CompileTask.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/CompileTask.scala new file mode 100644 index 000000000..74173048a --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/CompileTask.scala @@ -0,0 +1,33 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp +/** Compile Notifications */ +final class CompileTask private ( + val target: sbt.internal.bsp.BuildTargetIdentifier) extends Serializable { + + + + override def equals(o: Any): Boolean = o match { + case x: CompileTask => (this.target == x.target) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (17 + "sbt.internal.bsp.CompileTask".##) + target.##) + } + override def toString: String = { + "CompileTask(" + target + ")" + } + private[this] def copy(target: sbt.internal.bsp.BuildTargetIdentifier = target): CompileTask = { + new CompileTask(target) + } + def withTarget(target: sbt.internal.bsp.BuildTargetIdentifier): CompileTask = { + copy(target = target) + } +} +object CompileTask { + + def apply(target: sbt.internal.bsp.BuildTargetIdentifier): CompileTask = new CompileTask(target) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/TaskFinishParams.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/TaskFinishParams.scala index b628645bc..8d417c177 100644 --- a/protocol/src/main/contraband-scala/sbt/internal/bsp/TaskFinishParams.scala +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/TaskFinishParams.scala @@ -9,27 +9,31 @@ package sbt.internal.bsp * @param eventTime Optional timestamp of when the event started in milliseconds since Epoch. * @param message Optional message describing the task. * @param status Task completion status: 1 -> success, 2 -> error, 3 -> cancelled + * @param dataKind Kind of data to expect in the `data` field. + * @param data Optional metadata about the task. */ final class TaskFinishParams private ( val taskId: sbt.internal.bsp.TaskId, val eventTime: Option[Long], val message: Option[String], - val status: Int) extends Serializable { + val status: Int, + val dataKind: Option[String], + val data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]) extends Serializable { override def equals(o: Any): Boolean = o match { - case x: TaskFinishParams => (this.taskId == x.taskId) && (this.eventTime == x.eventTime) && (this.message == x.message) && (this.status == x.status) + case x: TaskFinishParams => (this.taskId == x.taskId) && (this.eventTime == x.eventTime) && (this.message == x.message) && (this.status == x.status) && (this.dataKind == x.dataKind) && (this.data == x.data) case _ => false } override def hashCode: Int = { - 37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.TaskFinishParams".##) + taskId.##) + eventTime.##) + message.##) + status.##) + 37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.TaskFinishParams".##) + taskId.##) + eventTime.##) + message.##) + status.##) + dataKind.##) + data.##) } override def toString: String = { - "TaskFinishParams(" + taskId + ", " + eventTime + ", " + message + ", " + status + ")" + "TaskFinishParams(" + taskId + ", " + eventTime + ", " + message + ", " + status + ", " + dataKind + ", " + data + ")" } - private[this] def copy(taskId: sbt.internal.bsp.TaskId = taskId, eventTime: Option[Long] = eventTime, message: Option[String] = message, status: Int = status): TaskFinishParams = { - new TaskFinishParams(taskId, eventTime, message, status) + private[this] def copy(taskId: sbt.internal.bsp.TaskId = taskId, eventTime: Option[Long] = eventTime, message: Option[String] = message, status: Int = status, dataKind: Option[String] = dataKind, data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue] = data): TaskFinishParams = { + new TaskFinishParams(taskId, eventTime, message, status, dataKind, data) } def withTaskId(taskId: sbt.internal.bsp.TaskId): TaskFinishParams = { copy(taskId = taskId) @@ -49,9 +53,21 @@ final class TaskFinishParams private ( def withStatus(status: Int): TaskFinishParams = { copy(status = status) } + def withDataKind(dataKind: Option[String]): TaskFinishParams = { + copy(dataKind = dataKind) + } + def withDataKind(dataKind: String): TaskFinishParams = { + copy(dataKind = Option(dataKind)) + } + def withData(data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]): TaskFinishParams = { + copy(data = data) + } + def withData(data: sjsonnew.shaded.scalajson.ast.unsafe.JValue): TaskFinishParams = { + copy(data = Option(data)) + } } object TaskFinishParams { - def apply(taskId: sbt.internal.bsp.TaskId, eventTime: Option[Long], message: Option[String], status: Int): TaskFinishParams = new TaskFinishParams(taskId, eventTime, message, status) - def apply(taskId: sbt.internal.bsp.TaskId, eventTime: Long, message: String, status: Int): TaskFinishParams = new TaskFinishParams(taskId, Option(eventTime), Option(message), status) + def apply(taskId: sbt.internal.bsp.TaskId, eventTime: Option[Long], message: Option[String], status: Int, dataKind: Option[String], data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]): TaskFinishParams = new TaskFinishParams(taskId, eventTime, message, status, dataKind, data) + def apply(taskId: sbt.internal.bsp.TaskId, eventTime: Long, message: String, status: Int, dataKind: String, data: sjsonnew.shaded.scalajson.ast.unsafe.JValue): TaskFinishParams = new TaskFinishParams(taskId, Option(eventTime), Option(message), status, Option(dataKind), Option(data)) } diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/TaskStartParams.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/TaskStartParams.scala index 3981c49cb..362d433b0 100644 --- a/protocol/src/main/contraband-scala/sbt/internal/bsp/TaskStartParams.scala +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/TaskStartParams.scala @@ -9,26 +9,30 @@ package sbt.internal.bsp * @param taskId Unique id of the task with optional reference to parent task id. * @param eventTime Optional timestamp of when the event started in milliseconds since Epoch. * @param message Optional message describing the task. + * @param dataKind Kind of data to expect in the `data` field. + * @param data Optional metadata about the task. */ final class TaskStartParams private ( val taskId: sbt.internal.bsp.TaskId, val eventTime: Option[Long], - val message: Option[String]) extends Serializable { + val message: Option[String], + val dataKind: Option[String], + val data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]) extends Serializable { override def equals(o: Any): Boolean = o match { - case x: TaskStartParams => (this.taskId == x.taskId) && (this.eventTime == x.eventTime) && (this.message == x.message) + case x: TaskStartParams => (this.taskId == x.taskId) && (this.eventTime == x.eventTime) && (this.message == x.message) && (this.dataKind == x.dataKind) && (this.data == x.data) case _ => false } override def hashCode: Int = { - 37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.TaskStartParams".##) + taskId.##) + eventTime.##) + message.##) + 37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.TaskStartParams".##) + taskId.##) + eventTime.##) + message.##) + dataKind.##) + data.##) } override def toString: String = { - "TaskStartParams(" + taskId + ", " + eventTime + ", " + message + ")" + "TaskStartParams(" + taskId + ", " + eventTime + ", " + message + ", " + dataKind + ", " + data + ")" } - private[this] def copy(taskId: sbt.internal.bsp.TaskId = taskId, eventTime: Option[Long] = eventTime, message: Option[String] = message): TaskStartParams = { - new TaskStartParams(taskId, eventTime, message) + private[this] def copy(taskId: sbt.internal.bsp.TaskId = taskId, eventTime: Option[Long] = eventTime, message: Option[String] = message, dataKind: Option[String] = dataKind, data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue] = data): TaskStartParams = { + new TaskStartParams(taskId, eventTime, message, dataKind, data) } def withTaskId(taskId: sbt.internal.bsp.TaskId): TaskStartParams = { copy(taskId = taskId) @@ -45,9 +49,21 @@ final class TaskStartParams private ( def withMessage(message: String): TaskStartParams = { copy(message = Option(message)) } + def withDataKind(dataKind: Option[String]): TaskStartParams = { + copy(dataKind = dataKind) + } + def withDataKind(dataKind: String): TaskStartParams = { + copy(dataKind = Option(dataKind)) + } + def withData(data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]): TaskStartParams = { + copy(data = data) + } + def withData(data: sjsonnew.shaded.scalajson.ast.unsafe.JValue): TaskStartParams = { + copy(data = Option(data)) + } } object TaskStartParams { - def apply(taskId: sbt.internal.bsp.TaskId, eventTime: Option[Long], message: Option[String]): TaskStartParams = new TaskStartParams(taskId, eventTime, message) - def apply(taskId: sbt.internal.bsp.TaskId, eventTime: Long, message: String): TaskStartParams = new TaskStartParams(taskId, Option(eventTime), Option(message)) + def apply(taskId: sbt.internal.bsp.TaskId, eventTime: Option[Long], message: Option[String], dataKind: Option[String], data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]): TaskStartParams = new TaskStartParams(taskId, eventTime, message, dataKind, data) + def apply(taskId: sbt.internal.bsp.TaskId, eventTime: Long, message: String, dataKind: String, data: sjsonnew.shaded.scalajson.ast.unsafe.JValue): TaskStartParams = new TaskStartParams(taskId, Option(eventTime), Option(message), Option(dataKind), Option(data)) } diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/CompileReportFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/CompileReportFormats.scala new file mode 100644 index 000000000..953258a86 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/CompileReportFormats.scala @@ -0,0 +1,35 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait CompileReportFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val CompileReportFormat: JsonFormat[sbt.internal.bsp.CompileReport] = new JsonFormat[sbt.internal.bsp.CompileReport] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.CompileReport = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val target = unbuilder.readField[sbt.internal.bsp.BuildTargetIdentifier]("target") + val originId = unbuilder.readField[Option[String]]("originId") + val errors = unbuilder.readField[Int]("errors") + val warnings = unbuilder.readField[Int]("warnings") + val time = unbuilder.readField[Option[Int]]("time") + unbuilder.endObject() + sbt.internal.bsp.CompileReport(target, originId, errors, warnings, time) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.CompileReport, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("target", obj.target) + builder.addField("originId", obj.originId) + builder.addField("errors", obj.errors) + builder.addField("warnings", obj.warnings) + builder.addField("time", obj.time) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/CompileTaskFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/CompileTaskFormats.scala new file mode 100644 index 000000000..b79b825af --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/CompileTaskFormats.scala @@ -0,0 +1,27 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait CompileTaskFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val CompileTaskFormat: JsonFormat[sbt.internal.bsp.CompileTask] = new JsonFormat[sbt.internal.bsp.CompileTask] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.CompileTask = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val target = unbuilder.readField[sbt.internal.bsp.BuildTargetIdentifier]("target") + unbuilder.endObject() + sbt.internal.bsp.CompileTask(target) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.CompileTask, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("target", obj.target) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JsonProtocol.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JsonProtocol.scala index 6eff5c734..eae54770c 100644 --- a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JsonProtocol.scala +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JsonProtocol.scala @@ -32,6 +32,8 @@ trait JsonProtocol extends sjsonnew.BasicJsonProtocol with sbt.internal.bsp.codec.TaskFinishParamsFormats with sbt.internal.bsp.codec.CompileParamsFormats with sbt.internal.bsp.codec.BspCompileResultFormats + with sbt.internal.bsp.codec.CompileTaskFormats + with sbt.internal.bsp.codec.CompileReportFormats with sbt.internal.bsp.codec.ScalaBuildTargetFormats with sbt.internal.bsp.codec.SbtBuildTargetFormats with sbt.internal.bsp.codec.ScalacOptionsParamsFormats diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/TaskFinishParamsFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/TaskFinishParamsFormats.scala index b821a6171..d9186fe33 100644 --- a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/TaskFinishParamsFormats.scala +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/TaskFinishParamsFormats.scala @@ -5,7 +5,7 @@ // DO NOT EDIT MANUALLY package sbt.internal.bsp.codec import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } -trait TaskFinishParamsFormats { self: sbt.internal.bsp.codec.TaskIdFormats with sjsonnew.BasicJsonProtocol => +trait TaskFinishParamsFormats { self: sbt.internal.bsp.codec.TaskIdFormats with sbt.internal.util.codec.JValueFormats with sjsonnew.BasicJsonProtocol => implicit lazy val TaskFinishParamsFormat: JsonFormat[sbt.internal.bsp.TaskFinishParams] = new JsonFormat[sbt.internal.bsp.TaskFinishParams] { override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.TaskFinishParams = { __jsOpt match { @@ -15,8 +15,10 @@ implicit lazy val TaskFinishParamsFormat: JsonFormat[sbt.internal.bsp.TaskFinish val eventTime = unbuilder.readField[Option[Long]]("eventTime") val message = unbuilder.readField[Option[String]]("message") val status = unbuilder.readField[Int]("status") + val dataKind = unbuilder.readField[Option[String]]("dataKind") + val data = unbuilder.readField[Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]]("data") unbuilder.endObject() - sbt.internal.bsp.TaskFinishParams(taskId, eventTime, message, status) + sbt.internal.bsp.TaskFinishParams(taskId, eventTime, message, status, dataKind, data) case None => deserializationError("Expected JsObject but found None") } @@ -27,6 +29,8 @@ implicit lazy val TaskFinishParamsFormat: JsonFormat[sbt.internal.bsp.TaskFinish builder.addField("eventTime", obj.eventTime) builder.addField("message", obj.message) builder.addField("status", obj.status) + builder.addField("dataKind", obj.dataKind) + builder.addField("data", obj.data) builder.endObject() } } diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/TaskStartParamsFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/TaskStartParamsFormats.scala index 74b144237..a6f4ef766 100644 --- a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/TaskStartParamsFormats.scala +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/TaskStartParamsFormats.scala @@ -5,7 +5,7 @@ // DO NOT EDIT MANUALLY package sbt.internal.bsp.codec import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } -trait TaskStartParamsFormats { self: sbt.internal.bsp.codec.TaskIdFormats with sjsonnew.BasicJsonProtocol => +trait TaskStartParamsFormats { self: sbt.internal.bsp.codec.TaskIdFormats with sbt.internal.util.codec.JValueFormats with sjsonnew.BasicJsonProtocol => implicit lazy val TaskStartParamsFormat: JsonFormat[sbt.internal.bsp.TaskStartParams] = new JsonFormat[sbt.internal.bsp.TaskStartParams] { override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.TaskStartParams = { __jsOpt match { @@ -14,8 +14,10 @@ implicit lazy val TaskStartParamsFormat: JsonFormat[sbt.internal.bsp.TaskStartPa val taskId = unbuilder.readField[sbt.internal.bsp.TaskId]("taskId") val eventTime = unbuilder.readField[Option[Long]]("eventTime") val message = unbuilder.readField[Option[String]]("message") + val dataKind = unbuilder.readField[Option[String]]("dataKind") + val data = unbuilder.readField[Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]]("data") unbuilder.endObject() - sbt.internal.bsp.TaskStartParams(taskId, eventTime, message) + sbt.internal.bsp.TaskStartParams(taskId, eventTime, message, dataKind, data) case None => deserializationError("Expected JsObject but found None") } @@ -25,6 +27,8 @@ implicit lazy val TaskStartParamsFormat: JsonFormat[sbt.internal.bsp.TaskStartPa builder.addField("taskId", obj.taskId) builder.addField("eventTime", obj.eventTime) builder.addField("message", obj.message) + builder.addField("dataKind", obj.dataKind) + builder.addField("data", obj.data) builder.endObject() } } diff --git a/protocol/src/main/contraband/bsp.contra b/protocol/src/main/contraband/bsp.contra index 6151fd95d..7405cedda 100644 --- a/protocol/src/main/contraband/bsp.contra +++ b/protocol/src/main/contraband/bsp.contra @@ -284,11 +284,11 @@ type TaskStartParams { ## Optional message describing the task. message: String - # Kind of data to expect in the `data` field. - # dataKind: String + ## Kind of data to expect in the `data` field. + dataKind: String - # Optional metadata about the task. - # data: Any + ## Optional metadata about the task. + data: sjsonnew.shaded.scalajson.ast.unsafe.JValue } type TaskFinishParams { @@ -304,11 +304,11 @@ type TaskFinishParams { ## Task completion status: 1 -> success, 2 -> error, 3 -> cancelled status: Int! - # Kind of data to expect in the `data` field. - # dataKind: String + ## Kind of data to expect in the `data` field. + dataKind: String - # Optional metadata about the task. - # data: Any + ## Optional metadata about the task. + data: sjsonnew.shaded.scalajson.ast.unsafe.JValue } ## Compile Request @@ -341,6 +341,29 @@ type BspCompileResult { # data: any } +## Compile Notifications + +type CompileTask { + target: sbt.internal.bsp.BuildTargetIdentifier! +} + +type CompileReport { + ## The build target that was compiled + target: sbt.internal.bsp.BuildTargetIdentifier! + + ## An optional request id to know the origin of this report + originId: String + + ## The total number of reported errors compiling this target. + errors: Int! + + ## The total number of reported warnings compiling the target. + warnings: Int! + + ## The total number of milliseconds it took to compile the target. + time: Int +} + # Scala Extension ## Contains scala-specific metadata for compiling a target containing Scala sources. diff --git a/protocol/src/main/scala/sbt/internal/bsp/BuildServerTasks.scala b/protocol/src/main/scala/sbt/internal/bsp/BuildServerTasks.scala new file mode 100644 index 000000000..308ad0876 --- /dev/null +++ b/protocol/src/main/scala/sbt/internal/bsp/BuildServerTasks.scala @@ -0,0 +1,8 @@ +package sbt.internal.bsp + +import java.util.concurrent.atomic.AtomicInteger + +object BuildServerTasks { + private val idGenerator = new AtomicInteger(0) + def uniqueId: String = idGenerator.getAndIncrement().toString +} diff --git a/protocol/src/main/scala/sbt/internal/bsp/BuildTargetName.scala b/protocol/src/main/scala/sbt/internal/bsp/BuildTargetName.scala new file mode 100644 index 000000000..48a53cf5c --- /dev/null +++ b/protocol/src/main/scala/sbt/internal/bsp/BuildTargetName.scala @@ -0,0 +1,10 @@ +package sbt.internal.bsp + +object BuildTargetName { + def fromScope(project: String, config: String): String = { + config match { + case "compile" => project + case _ => s"$project-$config" + } + } +}