add bspCompile task

This commit is contained in:
Adrien Piquerez 2020-04-28 18:03:42 +02:00
parent 994e05ef12
commit f89cef1fd0
17 changed files with 624 additions and 103 deletions

View File

@ -339,8 +339,11 @@ object Keys {
val closeClassLoaders = settingKey[Boolean]("Close classloaders in run and test when the task completes.").withRank(DSetting)
val allowZombieClassLoaders = settingKey[Boolean]("Allow a classloader that has previously been closed by `run` or `test` to continue loading classes.")
val buildTargetIdentifier = settingKey[BuildTargetIdentifier]("Id for BSP build target.").withRank(DSetting)
val bspBuildTarget = settingKey[BuildTarget]("Description of the BSP build target").withRank(DSetting)
val bspBuildTargetSources = inputKey[Unit]("").withRank(DTask)
val bspBuildTargetSourcesItem = taskKey[SourcesItem]("").withRank(DTask)
val bspBuildTargetCompile = inputKey[Unit]("").withRank(DTask)
val bspBuildTargetCompileItem = taskKey[Int]("").withRank(DTask)
val bspBuildTargetScalacOptions = inputKey[Unit]("").withRank(DTask)
val bspBuildTargetScalacOptionsItem = taskKey[ScalacOptionsItem]("").withRank(DTask)

View File

@ -10,12 +10,14 @@ package internal
package server
import java.net.URI
import sbt.internal.bsp._
import sbt.internal.util.complete.DefaultParsers
import sbt.librarymanagement.{ Configuration, Configurations }
import Configurations.{ Compile, Test }
import sbt.SlashSyntax0._
import sbt.BuildSyntax._
import scala.collection.mutable
import sjsonnew.support.scalajson.unsafe.Converter
import Def._
@ -44,6 +46,17 @@ object BuildServerProtocol {
}
}).evaluated,
bspBuildTargetSources / aggregate := false,
bspBuildTargetCompile := Def.inputTaskDyn {
val s: State = state.value
val args: Seq[String] = spaceDelimited().parsed
val filter = toScopeFilter(args)
Def.task {
import sbt.internal.bsp.codec.JsonProtocol._
val statusCode = Keys.bspBuildTargetCompileItem.all(filter).value.max
s.respondEvent(BspCompileResult(None, statusCode))
}
}.evaluated,
bspBuildTargetCompile / aggregate := false,
bspBuildTargetScalacOptions := (Def.inputTaskDyn {
import DefaultParsers._
val s = state.value
@ -57,16 +70,17 @@ object BuildServerProtocol {
s.respondEvent(result)
}
}).evaluated,
bspBuildTargetScalacOptions / aggregate := false,
bspBuildTargetScalacOptions / aggregate := false
)
// This will be coped to Compile, Test, etc
// This will be scoped to Compile, Test, etc
lazy val configSettings: Seq[Def.Setting[_]] = Seq(
buildTargetIdentifier := {
val ref = thisProjectRef.value
val c = configuration.value
toId(ref, c)
},
bspBuildTarget := bspBuildTargetSetting.value,
bspBuildTargetSourcesItem := {
val id = buildTargetIdentifier.value
val dirs = unmanagedSourceDirectories.value
@ -79,15 +93,70 @@ object BuildServerProtocol {
})
SourcesItem(id, items)
},
bspBuildTargetCompileItem := bspCompileTask.value,
bspBuildTargetScalacOptionsItem :=
ScalacOptionsItem(
target = buildTargetIdentifier.value,
options = scalacOptions.value.toVector,
classpath = fullClasspath.value.toVector.map(_.data.toURI),
classDirectory = classDirectory.value.toURI
),
)
)
private def bspBuildTargetSetting: Def.Initialize[BuildTarget] = Def.settingDyn {
import sbt.internal.bsp.codec.JsonProtocol._
val buildTargetIdentifier = Keys.buildTargetIdentifier.value
val thisProject = Keys.thisProject.value
val thisProjectRef = Keys.thisProjectRef.value
val compileData = ScalaBuildTarget(
scalaOrganization = scalaOrganization.value,
scalaVersion = scalaVersion.value,
scalaBinaryVersion = scalaBinaryVersion.value,
platform = ScalaPlatform.JVM,
jars = Vector("scala-library")
)
val configuration = Keys.configuration.value
val displayName = configuration.name match {
case "compile" => thisProject.id
case configName => s"${thisProject.id} $configName"
}
val baseDirectory = Keys.baseDirectory.value.toURI
val internalDependencies = configuration.name match {
case "test" =>
thisProject.dependencies :+
ResolvedClasspathDependency(thisProjectRef, Some("test->compile"))
case _ => thisProject.dependencies
}
val dependencies = Initialize.join {
for {
dependencyRef <- internalDependencies
dependencyId <- dependencyTargetKeys(dependencyRef, configuration)
} yield dependencyId
}
Def.setting {
BuildTarget(
buildTargetIdentifier,
Some(displayName),
Some(baseDirectory),
tags = Vector.empty,
languageIds = Vector("scala"),
dependencies = dependencies.value.toVector,
dataKind = Some("scala"),
data = Some(Converter.toJsonUnsafe(compileData)),
)
}
}
private def bspCompileTask: Def.Initialize[Task[Int]] = Def.task {
import sbt.Project._
Keys.compile.result.value match {
case Value(_) => StatusCode.Success
case Inc(_) =>
// Cancellation is not yet implemented
StatusCode.Error
}
}
def toScopeFilter(args: Seq[String]): ScopeFilter = {
val filters = args map { arg =>
val id = BuildTargetIdentifier(new URI(arg))
@ -103,12 +172,28 @@ object BuildServerProtocol {
BuildTargetIdentifier(new URI(s"$build#$project/${config.id}"))
case _ => sys.error(s"unexpected $ref")
}
private def dependencyTargetKeys(
ref: ClasspathDep[ProjectRef],
fromConfig: Configuration
): Seq[SettingKey[BuildTargetIdentifier]] = {
val from = fromConfig.name
val depConfig = ref.configuration.getOrElse("compile")
for {
configExpr <- depConfig.split(",").toSeq
depId <- configExpr.split("->").toList match {
case "compile" :: Nil | `from` :: "compile" :: Nil =>
Some(ref.project / Compile / Keys.buildTargetIdentifier)
case "test" :: Nil | `from` :: "test" :: Nil =>
Some(ref.project / Test / Keys.buildTargetIdentifier)
case _ => None
}
} yield depId
}
}
// This is mixed into NetworkChannel
trait BuildServerImpl { self: LanguageServerProtocol with NetworkChannel =>
import BuildServerProtocol._
protected def structure: BuildStructure
protected def getSetting[A](key: SettingKey[A]): Option[A]
protected def setting[A](key: SettingKey[A]): A
@ -129,83 +214,18 @@ trait BuildServerImpl { self: LanguageServerProtocol with NetworkChannel =>
*/
protected def onBspBuildTargets(execId: Option[String]): Unit = {
import sbt.internal.bsp.codec.JsonProtocol._
val targets = buildTargets
respondResult(targets, execId)
}
def buildTargets: WorkspaceBuildTargetsResult = {
import sbt.internal.bsp.codec.JsonProtocol._
val allProjectPairs = structure.allProjectPairs
val ts = allProjectPairs flatMap {
case (p, ref) =>
val baseOpt = getSetting(ref / Keys.baseDirectory).map(_.toURI)
val internalCompileDeps = p.dependencies.flatMap(idForConfig(_, Compile)).toVector
val compileId = getSetting(ref / Compile / Keys.buildTargetIdentifier).get
idMap(compileId) = (ref, Compile)
val compileData = ScalaBuildTarget(
scalaOrganization = getSetting(ref / Compile / Keys.scalaOrganization).get,
scalaVersion = getSetting(ref / Compile / Keys.scalaVersion).get,
scalaBinaryVersion = getSetting(ref / Compile / Keys.scalaBinaryVersion).get,
platform = ScalaPlatform.JVM,
jars = Vector("scala-library")
)
val t0 = BuildTarget(
compileId,
displayName = Some(p.id),
baseDirectory = baseOpt,
tags = Vector.empty,
languageIds = Vector("scala"),
dependencies = internalCompileDeps,
dataKind = Some("scala"),
data = Some(Converter.toJsonUnsafe(compileData)),
)
val testId = getSetting(ref / Test / Keys.buildTargetIdentifier).get
idMap(testId) = (ref, Test)
// encode Test extending Compile
val internalTestDeps =
(p.dependencies ++ Seq(ResolvedClasspathDependency(ref, Some("test->compile"))))
.flatMap(idForConfig(_, Test))
.toVector
val testData = ScalaBuildTarget(
scalaOrganization = getSetting(ref / Test / Keys.scalaOrganization).get,
scalaVersion = getSetting(ref / Test / Keys.scalaVersion).get,
scalaBinaryVersion = getSetting(ref / Test / Keys.scalaBinaryVersion).get,
platform = ScalaPlatform.JVM,
jars = Vector("scala-library")
)
val t1 = BuildTarget(
testId,
displayName = Some(p.id + " test"),
baseDirectory = baseOpt,
tags = Vector.empty,
languageIds = Vector("scala"),
dependencies = internalTestDeps,
dataKind = Some("scala"),
data = Some(Converter.toJsonUnsafe(testData)),
)
Seq(t0, t1)
}
WorkspaceBuildTargetsResult(ts.toVector)
}
def idForConfig(
ref: ClasspathDep[ProjectRef],
from: Configuration
): Seq[BuildTargetIdentifier] = {
val configStr = ref.configuration.getOrElse("compile")
val configExprs0 = configStr.split(",").toList
val configExprs1 = configExprs0 map { expr =>
if (expr.contains("->")) {
val xs = expr.split("->")
(xs(0), xs(1))
} else ("compile", expr)
}
configExprs1 flatMap {
case (fr, "compile") if fr == from.name =>
Some(getSetting(ref.project / Compile / Keys.buildTargetIdentifier).get)
case (fr, "test") if fr == from.name =>
Some(getSetting(ref.project / Test / Keys.buildTargetIdentifier).get)
case _ => None
val buildTargets = structure.allProjectRefs.flatMap { ref =>
val compileTarget = getSetting(ref / Compile / Keys.bspBuildTarget).get
val testTarget = getSetting(ref / Test / Keys.bspBuildTarget).get
BuildServerProtocol.idMap ++= Seq(
compileTarget.id -> ((ref, Compile)),
testTarget.id -> ((ref, Test))
)
Seq(compileTarget, testTarget)
}
respondResult(
WorkspaceBuildTargetsResult(buildTargets.toVector),
execId
)
}
}

View File

@ -55,24 +55,6 @@ private[sbt] object LanguageServerProtocol {
)
{
case r: JsonRpcRequestMessage if r.method == "initialize" =>
if (authOptions(ServerAuthentication.Token)) {
val param = Converter.fromJson[InitializeParams](json(r)).get
val optionJson = param.initializationOptions.getOrElse(
throw LangServerError(
ErrorCodes.InvalidParams,
"initializationOptions is expected on 'initialize' param."
)
)
val opt = Converter.fromJson[InitializeOption](optionJson).get
val token = opt.token.getOrElse(sys.error("'token' is missing."))
if (authenticate(token)) ()
else throw LangServerError(ErrorCodes.InvalidRequest, "invalid token")
} else ()
setInitialized(true)
appendExec(Exec(s"collectAnalyses", None, Some(CommandSource(name))))
jsonRpcRespond(InitializeResult(serverCapabilities), Option(r.id))
case r: JsonRpcRequestMessage if r.method == "textDocument/definition" =>
implicit val executionContext: ExecutionContext = StandardMain.executionContext
Definition.lspDefinition(json(r), r.id, CommandSource(name), converter, log)
@ -94,7 +76,6 @@ private[sbt] object LanguageServerProtocol {
val param = Converter.fromJson[CP](json(r)).get
onCompletionRequest(Option(r.id), param)
case r: JsonRpcRequestMessage if r.method == "build/initialize" =>
import sbt.protocol.codec.JsonProtocol._
val param = Converter.fromJson[InitializeBuildParams](json(r)).get
onBspInitialize(Option(r.id), param)
case r: JsonRpcRequestMessage if r.method == "workspace/buildTargets" =>
@ -117,6 +98,19 @@ private[sbt] object LanguageServerProtocol {
)
)
()
case r if r.method == "buildTarget/compile" =>
val param = Converter.fromJson[CompileParams](json(r)).get
log.info(param.toString)
val targetsUris = param.targets.map(_.uri).mkString(" ")
val key = Keys.bspBuildTargetCompile.key.toString
appendExec(
Exec(
s"$key $targetsUris",
Option(r.id),
Some(CommandSource(name))
)
)
()
case r: JsonRpcRequestMessage if r.method == "buildTarget/scalacOptions" =>
import sbt.internal.bsp.codec.JsonProtocol._
val param = Converter.fromJson[ScalacOptionsParams](json(r)).get

View File

@ -0,0 +1,45 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/**
* Compile Response
* @param originId An optional request id to know the origin of this report.
* @param statusCode A status code for the execution.
*/
final class BspCompileResult private (
val originId: Option[String],
val statusCode: Int) extends Serializable {
override def equals(o: Any): Boolean = o match {
case x: BspCompileResult => (this.originId == x.originId) && (this.statusCode == x.statusCode)
case _ => false
}
override def hashCode: Int = {
37 * (37 * (37 * (17 + "sbt.internal.bsp.BspCompileResult".##) + originId.##) + statusCode.##)
}
override def toString: String = {
"BspCompileResult(" + originId + ", " + statusCode + ")"
}
private[this] def copy(originId: Option[String] = originId, statusCode: Int = statusCode): BspCompileResult = {
new BspCompileResult(originId, statusCode)
}
def withOriginId(originId: Option[String]): BspCompileResult = {
copy(originId = originId)
}
def withOriginId(originId: String): BspCompileResult = {
copy(originId = Option(originId))
}
def withStatusCode(statusCode: Int): BspCompileResult = {
copy(statusCode = statusCode)
}
}
object BspCompileResult {
def apply(originId: Option[String], statusCode: Int): BspCompileResult = new BspCompileResult(originId, statusCode)
def apply(originId: String, statusCode: Int): BspCompileResult = new BspCompileResult(Option(originId), statusCode)
}

View File

@ -0,0 +1,51 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/**
* Compile Request
* @param targets A sequence of build targets to compile
* @param originId An optional unique identifier generated by the client to identify this request.
The server may include this id in triggered notifications or response.
* @param arguments Optional arguments to the compilation process
*/
final class CompileParams private (
val targets: Vector[sbt.internal.bsp.BuildTargetIdentifier],
val originId: Option[String],
val arguments: Vector[String]) extends Serializable {
override def equals(o: Any): Boolean = o match {
case x: CompileParams => (this.targets == x.targets) && (this.originId == x.originId) && (this.arguments == x.arguments)
case _ => false
}
override def hashCode: Int = {
37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.CompileParams".##) + targets.##) + originId.##) + arguments.##)
}
override def toString: String = {
"CompileParams(" + targets + ", " + originId + ", " + arguments + ")"
}
private[this] def copy(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier] = targets, originId: Option[String] = originId, arguments: Vector[String] = arguments): CompileParams = {
new CompileParams(targets, originId, arguments)
}
def withTargets(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]): CompileParams = {
copy(targets = targets)
}
def withOriginId(originId: Option[String]): CompileParams = {
copy(originId = originId)
}
def withOriginId(originId: String): CompileParams = {
copy(originId = Option(originId))
}
def withArguments(arguments: Vector[String]): CompileParams = {
copy(arguments = arguments)
}
}
object CompileParams {
def apply(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier], originId: Option[String], arguments: Vector[String]): CompileParams = new CompileParams(targets, originId, arguments)
def apply(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier], originId: String, arguments: Vector[String]): CompileParams = new CompileParams(targets, Option(originId), arguments)
}

View File

@ -0,0 +1,57 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
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 status Task completion status: 1 -> success, 2 -> error, 3 -> cancelled
*/
final class TaskFinishParams private (
val taskId: sbt.internal.bsp.TaskId,
val eventTime: Option[Long],
val message: Option[String],
val status: Int) 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 _ => false
}
override def hashCode: Int = {
37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.TaskFinishParams".##) + taskId.##) + eventTime.##) + message.##) + status.##)
}
override def toString: String = {
"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): TaskFinishParams = {
new TaskFinishParams(taskId, eventTime, message, status)
}
def withTaskId(taskId: sbt.internal.bsp.TaskId): TaskFinishParams = {
copy(taskId = taskId)
}
def withEventTime(eventTime: Option[Long]): TaskFinishParams = {
copy(eventTime = eventTime)
}
def withEventTime(eventTime: Long): TaskFinishParams = {
copy(eventTime = Option(eventTime))
}
def withMessage(message: Option[String]): TaskFinishParams = {
copy(message = message)
}
def withMessage(message: String): TaskFinishParams = {
copy(message = Option(message))
}
def withStatus(status: Int): TaskFinishParams = {
copy(status = status)
}
}
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)
}

View File

@ -0,0 +1,41 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/**
* @param id A unique identifier
* @param parents The parent task ids, if any. A non-empty parents field means
this task is a sub-task of every parent task.
*/
final class TaskId private (
val id: String,
val parents: Vector[String]) extends Serializable {
override def equals(o: Any): Boolean = o match {
case x: TaskId => (this.id == x.id) && (this.parents == x.parents)
case _ => false
}
override def hashCode: Int = {
37 * (37 * (37 * (17 + "sbt.internal.bsp.TaskId".##) + id.##) + parents.##)
}
override def toString: String = {
"TaskId(" + id + ", " + parents + ")"
}
private[this] def copy(id: String = id, parents: Vector[String] = parents): TaskId = {
new TaskId(id, parents)
}
def withId(id: String): TaskId = {
copy(id = id)
}
def withParents(parents: Vector[String]): TaskId = {
copy(parents = parents)
}
}
object TaskId {
def apply(id: String, parents: Vector[String]): TaskId = new TaskId(id, parents)
}

View File

@ -0,0 +1,53 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/**
* Task Notifications
* @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.
*/
final class TaskStartParams private (
val taskId: sbt.internal.bsp.TaskId,
val eventTime: Option[Long],
val message: Option[String]) 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 _ => false
}
override def hashCode: Int = {
37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.TaskStartParams".##) + taskId.##) + eventTime.##) + message.##)
}
override def toString: String = {
"TaskStartParams(" + taskId + ", " + eventTime + ", " + message + ")"
}
private[this] def copy(taskId: sbt.internal.bsp.TaskId = taskId, eventTime: Option[Long] = eventTime, message: Option[String] = message): TaskStartParams = {
new TaskStartParams(taskId, eventTime, message)
}
def withTaskId(taskId: sbt.internal.bsp.TaskId): TaskStartParams = {
copy(taskId = taskId)
}
def withEventTime(eventTime: Option[Long]): TaskStartParams = {
copy(eventTime = eventTime)
}
def withEventTime(eventTime: Long): TaskStartParams = {
copy(eventTime = Option(eventTime))
}
def withMessage(message: Option[String]): TaskStartParams = {
copy(message = message)
}
def withMessage(message: String): TaskStartParams = {
copy(message = Option(message))
}
}
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))
}

View File

@ -0,0 +1,29 @@
/**
* 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 BspCompileResultFormats { self: sjsonnew.BasicJsonProtocol =>
implicit lazy val BspCompileResultFormat: JsonFormat[sbt.internal.bsp.BspCompileResult] = new JsonFormat[sbt.internal.bsp.BspCompileResult] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.BspCompileResult = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val originId = unbuilder.readField[Option[String]]("originId")
val statusCode = unbuilder.readField[Int]("statusCode")
unbuilder.endObject()
sbt.internal.bsp.BspCompileResult(originId, statusCode)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.BspCompileResult, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("originId", obj.originId)
builder.addField("statusCode", obj.statusCode)
builder.endObject()
}
}
}

View File

@ -0,0 +1,31 @@
/**
* 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 CompileParamsFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats with sjsonnew.BasicJsonProtocol =>
implicit lazy val CompileParamsFormat: JsonFormat[sbt.internal.bsp.CompileParams] = new JsonFormat[sbt.internal.bsp.CompileParams] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.CompileParams = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val targets = unbuilder.readField[Vector[sbt.internal.bsp.BuildTargetIdentifier]]("targets")
val originId = unbuilder.readField[Option[String]]("originId")
val arguments = unbuilder.readField[Vector[String]]("arguments")
unbuilder.endObject()
sbt.internal.bsp.CompileParams(targets, originId, arguments)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.CompileParams, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("targets", obj.targets)
builder.addField("originId", obj.originId)
builder.addField("arguments", obj.arguments)
builder.endObject()
}
}
}

View File

@ -8,6 +8,7 @@ trait JsonProtocol extends sjsonnew.BasicJsonProtocol
with sbt.internal.bsp.codec.BuildTargetIdentifierFormats
with sbt.internal.util.codec.JValueFormats
with sbt.internal.bsp.codec.BuildTargetFormats
with sbt.internal.bsp.codec.TaskIdFormats
with sbt.internal.bsp.codec.BuildClientCapabilitiesFormats
with sbt.internal.bsp.codec.InitializeBuildParamsFormats
with sbt.internal.bsp.codec.InitializeBuildResultFormats
@ -16,6 +17,10 @@ trait JsonProtocol extends sjsonnew.BasicJsonProtocol
with sbt.internal.bsp.codec.SourceItemFormats
with sbt.internal.bsp.codec.SourcesItemFormats
with sbt.internal.bsp.codec.SourcesResultFormats
with sbt.internal.bsp.codec.TaskStartParamsFormats
with sbt.internal.bsp.codec.TaskFinishParamsFormats
with sbt.internal.bsp.codec.CompileParamsFormats
with sbt.internal.bsp.codec.BspCompileResultFormats
with sbt.internal.bsp.codec.ScalaBuildTargetFormats
with sbt.internal.bsp.codec.SbtBuildTargetFormats
with sbt.internal.bsp.codec.ScalacOptionsParamsFormats

View File

@ -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.codec
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait TaskFinishParamsFormats { self: sbt.internal.bsp.codec.TaskIdFormats 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 {
case Some(__js) =>
unbuilder.beginObject(__js)
val taskId = unbuilder.readField[sbt.internal.bsp.TaskId]("taskId")
val eventTime = unbuilder.readField[Option[Long]]("eventTime")
val message = unbuilder.readField[Option[String]]("message")
val status = unbuilder.readField[Int]("status")
unbuilder.endObject()
sbt.internal.bsp.TaskFinishParams(taskId, eventTime, message, status)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.TaskFinishParams, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("taskId", obj.taskId)
builder.addField("eventTime", obj.eventTime)
builder.addField("message", obj.message)
builder.addField("status", obj.status)
builder.endObject()
}
}
}

View File

@ -0,0 +1,29 @@
/**
* 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 TaskIdFormats { self: sjsonnew.BasicJsonProtocol =>
implicit lazy val TaskIdFormat: JsonFormat[sbt.internal.bsp.TaskId] = new JsonFormat[sbt.internal.bsp.TaskId] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.TaskId = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val id = unbuilder.readField[String]("id")
val parents = unbuilder.readField[Vector[String]]("parents")
unbuilder.endObject()
sbt.internal.bsp.TaskId(id, parents)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.TaskId, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("id", obj.id)
builder.addField("parents", obj.parents)
builder.endObject()
}
}
}

View File

@ -0,0 +1,31 @@
/**
* 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 TaskStartParamsFormats { self: sbt.internal.bsp.codec.TaskIdFormats 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 {
case Some(__js) =>
unbuilder.beginObject(__js)
val taskId = unbuilder.readField[sbt.internal.bsp.TaskId]("taskId")
val eventTime = unbuilder.readField[Option[Long]]("eventTime")
val message = unbuilder.readField[Option[String]]("message")
unbuilder.endObject()
sbt.internal.bsp.TaskStartParams(taskId, eventTime, message)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.TaskStartParams, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("taskId", obj.taskId)
builder.addField("eventTime", obj.eventTime)
builder.addField("message", obj.message)
builder.endObject()
}
}
}

View File

@ -52,6 +52,15 @@ type BuildTargetIdentifier {
uri: java.net.URI!
}
type TaskId {
## A unique identifier
id: String!
## The parent task ids, if any. A non-empty parents field means
## this task is a sub-task of every parent task.
parents: [String]
}
## Initialize Build Request
type InitializeBuildParams {
## Name of the client
@ -136,6 +145,75 @@ type SourceItem {
generated: Boolean!
}
## Task Notifications
type TaskStartParams {
## Unique id of the task with optional reference to parent task id.
taskId: sbt.internal.bsp.TaskId!
## Optional timestamp of when the event started in milliseconds since Epoch.
eventTime: Long
## Optional message describing the task.
message: String
## Kind of data to expect in the `data` field.
# dataKind: String
## Optional metadata about the task.
# data: Any
}
type TaskFinishParams {
## Unique id of the task with optional reference to parent task id.
taskId: sbt.internal.bsp.TaskId!
## Optional timestamp of when the event started in milliseconds since Epoch.
eventTime: Long
## Optional message describing the task.
message: String
## Task completion status: 1 -> success, 2 -> error, 3 -> cancelled
status: Int!
# Kind of data to expect in the `data` field.
# dataKind: String
# Optional metadata about the task.
# data: Any
}
## Compile Request
type CompileParams {
## A sequence of build targets to compile
targets: [sbt.internal.bsp.BuildTargetIdentifier]
## An optional unique identifier generated by the client to identify this request.
## The server may include this id in triggered notifications or response.
originId: String
## Optional arguments to the compilation process
arguments: [String]
}
## Compile Response
type BspCompileResult {
## An optional request id to know the origin of this report.
originId: String
## A status code for the execution.
statusCode: Int!
# Kind of data to expect in the `data` field.
# If this field is not set, the kind of data is not specified.
# dataKind: String
# A field containing language-specific information, like products
# of compilation or compiler-specific metadata the client needs to know.
# data: any
}
# Scala Extension
## Contains scala-specific metadata for compiling a target containing Scala sources.

View File

@ -0,0 +1,7 @@
package sbt.internal.bsp
object StatusCode {
final val Success: Int = 1
final val Error: Int = 2
final val Cancelled: Int = 3
}

View File

@ -46,16 +46,30 @@ object BuildServerTest extends AbstractServerTest {
})
}
test("buildTarget/compile") { _ =>
val x = s"${svr.baseDirectory.getAbsoluteFile.toURI}#util/Compile"
svr.sendJsonRpc(
s"""{ "jsonrpc": "2.0", "id": "13", "method": "buildTarget/compile", "params": {
| "targets": [{ "uri": "$x" }]
|} }""".stripMargin
)
assert(svr.waitForString(10.seconds) { s =>
println(s)
(s contains """"id":"13"""") &&
(s contains """"statusCode":1""")
})
}
test("buildTarget/scalacOptions") { _ =>
val x = s"${svr.baseDirectory.getAbsoluteFile.toURI}#util/Compile"
svr.sendJsonRpc(
s"""{ "jsonrpc": "2.0", "id": "13", "method": "buildTarget/scalacOptions", "params": {
s"""{ "jsonrpc": "2.0", "id": "14", "method": "buildTarget/scalacOptions", "params": {
| "targets": [{ "uri": "$x" }]
|} }""".stripMargin
)
assert(svr.waitForString(10.seconds) { s =>
println(s)
(s contains """"id":"13"""") &&
(s contains """"id":"14"""") &&
(s contains "scala-library-2.13.1.jar")
})
}