From 9f04358fce7ca8faa086bfde9f04b2213e73c737 Mon Sep 17 00:00:00 2001 From: Adrien Piquerez Date: Thu, 17 Sep 2020 11:52:42 +0200 Subject: [PATCH] Add BSP buildTarget/run endpoint --- main/src/main/scala/sbt/Defaults.scala | 9 +- main/src/main/scala/sbt/Keys.scala | 1 + .../internal/server/BuildServerProtocol.scala | 208 +++++++++++++----- .../bsp/BuildServerCapabilities.scala | 21 +- .../sbt/internal/bsp/RunParams.scala | 71 ++++++ .../sbt/internal/bsp/RunProvider.scala | 32 +++ .../sbt/internal/bsp/RunResult.scala | 45 ++++ .../BuildServerCapabilitiesFormats.scala | 6 +- .../sbt/internal/bsp/codec/JsonProtocol.scala | 3 + .../internal/bsp/codec/RunParamsFormats.scala | 35 +++ .../bsp/codec/RunProviderFormats.scala | 27 +++ .../internal/bsp/codec/RunResultFormats.scala | 29 +++ protocol/src/main/contraband/bsp.contra | 39 +++- 13 files changed, 460 insertions(+), 66 deletions(-) create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/RunParams.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/RunProvider.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/RunResult.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/codec/RunParamsFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/codec/RunProviderFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/codec/RunResultFormats.scala diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 5a7b7ec5d..d58433252 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -412,8 +412,13 @@ object Defaults extends BuildCommon { fullServerHandlers := { Seq( LanguageServerProtocol.handler(fileConverter.value), - BuildServerProtocol - .handler(sbtVersion.value, semanticdbEnabled.value, semanticdbVersion.value), + BuildServerProtocol.handler( + loadedBuild.value, + bspWorkspace.value, + sbtVersion.value, + semanticdbEnabled.value, + semanticdbVersion.value + ), VirtualTerminal.handler, ) ++ serverHandlers.value :+ ServerHandler.fallback }, diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index 1ff8bc7ce..ebf62d8f8 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -398,6 +398,7 @@ object Keys { val bspBuildTargetDependencySourcesItem = taskKey[DependencySourcesItem]("").withRank(DTask) val bspBuildTargetCompile = inputKey[Unit]("").withRank(DTask) val bspBuildTargetCompileItem = taskKey[Int]("").withRank(DTask) + val bspBuildTargetRun = inputKey[Unit]("Corresponds to buildTarget/run request").withRank(DTask) val bspBuildTargetScalacOptions = inputKey[Unit]("").withRank(DTask) val bspBuildTargetScalacOptionsItem = taskKey[ScalacOptionsItem]("").withRank(DTask) val bspScalaMainClasses = inputKey[Unit]("Corresponds to buildTarget/scalaMainClasses request").withRank(DTask) diff --git a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala index 58162d7d1..956061da2 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala @@ -21,12 +21,14 @@ import sbt.StandardMain.exchange import sbt.internal.bsp._ import sbt.internal.langserver.ErrorCodes import sbt.internal.protocol.JsonRpcRequestMessage +import sbt.internal.util.Attributed +import sbt.internal.util.complete.{ Parser, Parsers } import sbt.librarymanagement.Configuration import sbt.util.Logger -import sjsonnew.shaded.scalajson.ast.unsafe.JNull -import sjsonnew.shaded.scalajson.ast.unsafe.JValue -import sjsonnew.support.scalajson.unsafe.Converter +import sjsonnew.shaded.scalajson.ast.unsafe.{ JNull, JValue } +import sjsonnew.support.scalajson.unsafe.{ CompactPrinter, Converter, Parser => JsonParser } +import scala.util.{ Failure, Success } import scala.util.control.NonFatal object BuildServerProtocol { @@ -34,6 +36,7 @@ object BuildServerProtocol { private val capabilities = BuildServerCapabilities( CompileProvider(BuildServerConnection.languages), + RunProvider(BuildServerConnection.languages), dependencySourcesProvider = true, canReload = true ) @@ -174,76 +177,106 @@ object BuildServerProtocol { }, bspBuildTargetDependencySourcesItem := dependencySourcesItemTask.value, bspBuildTargetCompileItem := bspCompileTask.value, + bspBuildTargetRun := bspRunTask.evaluated, bspBuildTargetScalacOptionsItem := scalacOptionsTask.value, bspInternalDependencyConfigurations := internalDependencyConfigurationsSetting.value, bspScalaMainClassesItem := scalaMainClassesTask.value ) def handler( + loadedBuild: LoadedBuild, + workspace: Map[BuildTargetIdentifier, Scope], sbtVersion: String, semanticdbEnabled: Boolean, semanticdbVersion: String - ): ServerHandler = ServerHandler { callback => - ServerIntent( - onRequest = { - case r: JsonRpcRequestMessage if r.method == "build/initialize" => - val params = Converter.fromJson[InitializeBuildParams](json(r)).get - checkMetalsCompatibility(semanticdbEnabled, semanticdbVersion, params, callback.log) + ): ServerHandler = { + val configurationMap: Map[ConfigKey, Configuration] = + loadedBuild.allProjectRefs + .flatMap { case (_, p) => p.configurations } + .distinct + .map(c => ConfigKey(c.name) -> c) + .toMap + ServerHandler { callback => + ServerIntent( + onRequest = { + case r: JsonRpcRequestMessage if r.method == "build/initialize" => + val params = Converter.fromJson[InitializeBuildParams](json(r)).get + checkMetalsCompatibility(semanticdbEnabled, semanticdbVersion, params, callback.log) - val response = InitializeBuildResult( - "sbt", - sbtVersion, - BuildServerConnection.bspVersion, - capabilities, - None - ) - callback.jsonRpcRespond(response, Some(r.id)); () + val response = InitializeBuildResult( + "sbt", + sbtVersion, + BuildServerConnection.bspVersion, + capabilities, + None + ) + callback.jsonRpcRespond(response, Some(r.id)); () - case r: JsonRpcRequestMessage if r.method == "workspace/buildTargets" => - val _ = callback.appendExec(Keys.bspWorkspaceBuildTargets.key.toString, Some(r.id)) + case r: JsonRpcRequestMessage if r.method == "workspace/buildTargets" => + val _ = callback.appendExec(Keys.bspWorkspaceBuildTargets.key.toString, Some(r.id)) - case r: JsonRpcRequestMessage if r.method == "workspace/reload" => - val _ = callback.appendExec(s"$bspReload ${r.id}", None) + case r: JsonRpcRequestMessage if r.method == "workspace/reload" => + val _ = callback.appendExec(s"$bspReload ${r.id}", None) - case r: JsonRpcRequestMessage if r.method == "build/shutdown" => - () + case r: JsonRpcRequestMessage if r.method == "build/shutdown" => + () - case r: JsonRpcRequestMessage if r.method == "build/exit" => - val _ = callback.appendExec(Shutdown, Some(r.id)) + case r: JsonRpcRequestMessage if r.method == "build/exit" => + val _ = callback.appendExec(Shutdown, Some(r.id)) - case r: JsonRpcRequestMessage if r.method == "buildTarget/sources" => - val param = Converter.fromJson[SourcesParams](json(r)).get - val targets = param.targets.map(_.uri).mkString(" ") - val command = Keys.bspBuildTargetSources.key - val _ = callback.appendExec(s"$command $targets", Some(r.id)) + case r: JsonRpcRequestMessage if r.method == "buildTarget/sources" => + val param = Converter.fromJson[SourcesParams](json(r)).get + val targets = param.targets.map(_.uri).mkString(" ") + val command = Keys.bspBuildTargetSources.key + val _ = callback.appendExec(s"$command $targets", Some(r.id)) - case r if r.method == "buildTarget/dependencySources" => - val param = Converter.fromJson[DependencySourcesParams](json(r)).get - val targets = param.targets.map(_.uri).mkString(" ") - val command = Keys.bspBuildTargetDependencySources.key - val _ = callback.appendExec(s"$command $targets", Some(r.id)) + case r if r.method == "buildTarget/dependencySources" => + val param = Converter.fromJson[DependencySourcesParams](json(r)).get + val targets = param.targets.map(_.uri).mkString(" ") + val command = Keys.bspBuildTargetDependencySources.key + val _ = callback.appendExec(s"$command $targets", Some(r.id)) - case r if r.method == "buildTarget/compile" => - val param = Converter.fromJson[CompileParams](json(r)).get - val targets = param.targets.map(_.uri).mkString(" ") - val command = Keys.bspBuildTargetCompile.key - val _ = callback.appendExec(s"$command $targets", Some(r.id)) + case r if r.method == "buildTarget/compile" => + val param = Converter.fromJson[CompileParams](json(r)).get + val targets = param.targets.map(_.uri).mkString(" ") + val command = Keys.bspBuildTargetCompile.key + val _ = callback.appendExec(s"$command $targets", Some(r.id)) - case r: JsonRpcRequestMessage if r.method == "buildTarget/scalacOptions" => - val param = Converter.fromJson[ScalacOptionsParams](json(r)).get - val targets = param.targets.map(_.uri).mkString(" ") - val command = Keys.bspBuildTargetScalacOptions.key - val _ = callback.appendExec(s"$command $targets", Some(r.id)) + case r if r.method == "buildTarget/run" => + val paramJson = json(r) + val param = Converter.fromJson[RunParams](json(r)).get + val scope = workspace.getOrElse( + param.target, + throw LangServerError( + ErrorCodes.InvalidParams, + s"'${param.target}' is not a valid build target identifier" + ) + ) + val project = scope.project.toOption.get.asInstanceOf[ProjectRef].project + val config = configurationMap(scope.config.toOption.get).id + val task = bspBuildTargetRun.key + val paramStr = CompactPrinter(paramJson) + val _ = callback.appendExec( + s"$project / $config / $task $paramStr", + Some(r.id) + ) - case r: JsonRpcRequestMessage if r.method == "buildTarget/scalaMainClasses" => - val param = Converter.fromJson[ScalacOptionsParams](json(r)).get - val targets = param.targets.map(_.uri).mkString(" ") - val command = Keys.bspScalaMainClasses.key - val _ = callback.appendExec(s"$command $targets", Some(r.id)) - }, - onResponse = PartialFunction.empty, - onNotification = PartialFunction.empty, - ) + case r: JsonRpcRequestMessage if r.method == "buildTarget/scalacOptions" => + val param = Converter.fromJson[ScalacOptionsParams](json(r)).get + val targets = param.targets.map(_.uri).mkString(" ") + val command = Keys.bspBuildTargetScalacOptions.key + val _ = callback.appendExec(s"$command $targets", Some(r.id)) + + case r: JsonRpcRequestMessage if r.method == "buildTarget/scalaMainClasses" => + val param = Converter.fromJson[ScalaMainClassesParams](json(r)).get + val targets = param.targets.map(_.uri).mkString(" ") + val command = Keys.bspScalaMainClasses.key + val _ = callback.appendExec(s"$command $targets", Some(r.id)) + }, + onResponse = PartialFunction.empty, + onNotification = PartialFunction.empty, + ) + } } private def checkMetalsCompatibility( @@ -398,6 +431,73 @@ object BuildServerProtocol { } } + private val jsonParser: Parser[JValue] = (Parsers.any *) + .map(_.mkString) + .map(JsonParser.parseUnsafe) + + private def bspRunTask: Def.Initialize[InputTask[Unit]] = Def.inputTaskDyn { + val runParams = jsonParser.map(json => Converter.fromJson[RunParams](json).get).parsed + val defaultClass = Keys.mainClass.value + val defaultJvmOptions = Keys.javaOptions.value + + val mainClass = runParams.dataKind match { + case Some("scala-main-class") => + val data = runParams.data.getOrElse(JNull) + Converter.fromJson[ScalaMainClass](data) match { + case Failure(e) => + throw LangServerError( + ErrorCodes.ParseError, + e.getMessage + ) + case Success(value) => value + } + + case Some(dataKind) => + throw LangServerError( + ErrorCodes.InvalidParams, + s"Unexpected data of kind '$dataKind', 'scala-main-class' is expected" + ) + + case None => + ScalaMainClass( + defaultClass.getOrElse( + throw LangServerError( + ErrorCodes.InvalidParams, + "No default main class is defined" + ) + ), + runParams.arguments, + defaultJvmOptions.toVector + ) + } + + runMainClassTask(mainClass, runParams.originId) + } + + private def runMainClassTask(mainClass: ScalaMainClass, originId: Option[String]) = Def.task { + val state = Keys.state.value + val logger = Keys.streams.value.log + val classpath = Attributed.data(fullClasspath.value) + val forkOpts = ForkOptions( + javaHome = javaHome.value, + outputStrategy = outputStrategy.value, + // bootJars is empty by default because only jars on the user's classpath should be on the boot classpath + bootJars = Vector(), + workingDirectory = Some(baseDirectory.value), + runJVMOptions = mainClass.jvmOptions, + connectInput = connectInput.value, + envVars = envVars.value + ) + val runner = new ForkRun(forkOpts) + val statusCode = runner + .run(mainClass.`class`, classpath, mainClass.arguments, logger) + .fold( + _ => StatusCode.Error, + _ => StatusCode.Success + ) + state.respondEvent(RunResult(originId, statusCode)) + } + private def internalDependencyConfigurationsSetting = Def.settingDyn { val directDependencies = Keys.internalDependencyConfigurations.value.map { case (project, rawConfigs) => diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/BuildServerCapabilities.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/BuildServerCapabilities.scala index 59b512820..b65e97a4e 100644 --- a/protocol/src/main/contraband-scala/sbt/internal/bsp/BuildServerCapabilities.scala +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/BuildServerCapabilities.scala @@ -12,23 +12,24 @@ package sbt.internal.bsp */ final class BuildServerCapabilities private ( val compileProvider: Option[sbt.internal.bsp.CompileProvider], + val runProvider: Option[sbt.internal.bsp.RunProvider], val dependencySourcesProvider: Option[Boolean], val canReload: Option[Boolean]) extends Serializable { override def equals(o: Any): Boolean = o match { - case x: BuildServerCapabilities => (this.compileProvider == x.compileProvider) && (this.dependencySourcesProvider == x.dependencySourcesProvider) && (this.canReload == x.canReload) + case x: BuildServerCapabilities => (this.compileProvider == x.compileProvider) && (this.runProvider == x.runProvider) && (this.dependencySourcesProvider == x.dependencySourcesProvider) && (this.canReload == x.canReload) case _ => false } override def hashCode: Int = { - 37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.BuildServerCapabilities".##) + compileProvider.##) + dependencySourcesProvider.##) + canReload.##) + 37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.BuildServerCapabilities".##) + compileProvider.##) + runProvider.##) + dependencySourcesProvider.##) + canReload.##) } override def toString: String = { - "BuildServerCapabilities(" + compileProvider + ", " + dependencySourcesProvider + ", " + canReload + ")" + "BuildServerCapabilities(" + compileProvider + ", " + runProvider + ", " + dependencySourcesProvider + ", " + canReload + ")" } - private[this] def copy(compileProvider: Option[sbt.internal.bsp.CompileProvider] = compileProvider, dependencySourcesProvider: Option[Boolean] = dependencySourcesProvider, canReload: Option[Boolean] = canReload): BuildServerCapabilities = { - new BuildServerCapabilities(compileProvider, dependencySourcesProvider, canReload) + private[this] def copy(compileProvider: Option[sbt.internal.bsp.CompileProvider] = compileProvider, runProvider: Option[sbt.internal.bsp.RunProvider] = runProvider, dependencySourcesProvider: Option[Boolean] = dependencySourcesProvider, canReload: Option[Boolean] = canReload): BuildServerCapabilities = { + new BuildServerCapabilities(compileProvider, runProvider, dependencySourcesProvider, canReload) } def withCompileProvider(compileProvider: Option[sbt.internal.bsp.CompileProvider]): BuildServerCapabilities = { copy(compileProvider = compileProvider) @@ -36,6 +37,12 @@ final class BuildServerCapabilities private ( def withCompileProvider(compileProvider: sbt.internal.bsp.CompileProvider): BuildServerCapabilities = { copy(compileProvider = Option(compileProvider)) } + def withRunProvider(runProvider: Option[sbt.internal.bsp.RunProvider]): BuildServerCapabilities = { + copy(runProvider = runProvider) + } + def withRunProvider(runProvider: sbt.internal.bsp.RunProvider): BuildServerCapabilities = { + copy(runProvider = Option(runProvider)) + } def withDependencySourcesProvider(dependencySourcesProvider: Option[Boolean]): BuildServerCapabilities = { copy(dependencySourcesProvider = dependencySourcesProvider) } @@ -51,6 +58,6 @@ final class BuildServerCapabilities private ( } object BuildServerCapabilities { - def apply(compileProvider: Option[sbt.internal.bsp.CompileProvider], dependencySourcesProvider: Option[Boolean], canReload: Option[Boolean]): BuildServerCapabilities = new BuildServerCapabilities(compileProvider, dependencySourcesProvider, canReload) - def apply(compileProvider: sbt.internal.bsp.CompileProvider, dependencySourcesProvider: Boolean, canReload: Boolean): BuildServerCapabilities = new BuildServerCapabilities(Option(compileProvider), Option(dependencySourcesProvider), Option(canReload)) + def apply(compileProvider: Option[sbt.internal.bsp.CompileProvider], runProvider: Option[sbt.internal.bsp.RunProvider], dependencySourcesProvider: Option[Boolean], canReload: Option[Boolean]): BuildServerCapabilities = new BuildServerCapabilities(compileProvider, runProvider, dependencySourcesProvider, canReload) + def apply(compileProvider: sbt.internal.bsp.CompileProvider, runProvider: sbt.internal.bsp.RunProvider, dependencySourcesProvider: Boolean, canReload: Boolean): BuildServerCapabilities = new BuildServerCapabilities(Option(compileProvider), Option(runProvider), Option(dependencySourcesProvider), Option(canReload)) } diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/RunParams.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/RunParams.scala new file mode 100644 index 000000000..de765ca81 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/RunParams.scala @@ -0,0 +1,71 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp +/** + * Run Request + * The run request is sent from the client to the server to run a build target. + * The server communicates during the initialize handshake whether this method is supported or not. + * An empty run request is valid. + * @param target The build target to run. + * @param originId An option identifier gnerated by the client to identify this request. + The server may include this id in triggered notifications or responses. + * @param arguments Optional arguments to the executed application. + * @param dataKind Kind of data to expect in the data field. + If this field is not set, the kind of data is not specified. + * @param data Language-specific metadata for this execution. + */ +final class RunParams private ( + val target: sbt.internal.bsp.BuildTargetIdentifier, + val originId: Option[String], + val arguments: Vector[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: RunParams => (this.target == x.target) && (this.originId == x.originId) && (this.arguments == x.arguments) && (this.dataKind == x.dataKind) && (this.data == x.data) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.RunParams".##) + target.##) + originId.##) + arguments.##) + dataKind.##) + data.##) + } + override def toString: String = { + "RunParams(" + target + ", " + originId + ", " + arguments + ", " + dataKind + ", " + data + ")" + } + private[this] def copy(target: sbt.internal.bsp.BuildTargetIdentifier = target, originId: Option[String] = originId, arguments: Vector[String] = arguments, dataKind: Option[String] = dataKind, data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue] = data): RunParams = { + new RunParams(target, originId, arguments, dataKind, data) + } + def withTarget(target: sbt.internal.bsp.BuildTargetIdentifier): RunParams = { + copy(target = target) + } + def withOriginId(originId: Option[String]): RunParams = { + copy(originId = originId) + } + def withOriginId(originId: String): RunParams = { + copy(originId = Option(originId)) + } + def withArguments(arguments: Vector[String]): RunParams = { + copy(arguments = arguments) + } + def withDataKind(dataKind: Option[String]): RunParams = { + copy(dataKind = dataKind) + } + def withDataKind(dataKind: String): RunParams = { + copy(dataKind = Option(dataKind)) + } + def withData(data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]): RunParams = { + copy(data = data) + } + def withData(data: sjsonnew.shaded.scalajson.ast.unsafe.JValue): RunParams = { + copy(data = Option(data)) + } +} +object RunParams { + + def apply(target: sbt.internal.bsp.BuildTargetIdentifier, originId: Option[String], arguments: Vector[String], dataKind: Option[String], data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]): RunParams = new RunParams(target, originId, arguments, dataKind, data) + def apply(target: sbt.internal.bsp.BuildTargetIdentifier, originId: String, arguments: Vector[String], dataKind: String, data: sjsonnew.shaded.scalajson.ast.unsafe.JValue): RunParams = new RunParams(target, Option(originId), arguments, Option(dataKind), Option(data)) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/RunProvider.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/RunProvider.scala new file mode 100644 index 000000000..6cd793226 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/RunProvider.scala @@ -0,0 +1,32 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp +final class RunProvider private ( + val languageIds: Vector[String]) extends Serializable { + + + + override def equals(o: Any): Boolean = o match { + case x: RunProvider => (this.languageIds == x.languageIds) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (17 + "sbt.internal.bsp.RunProvider".##) + languageIds.##) + } + override def toString: String = { + "RunProvider(" + languageIds + ")" + } + private[this] def copy(languageIds: Vector[String] = languageIds): RunProvider = { + new RunProvider(languageIds) + } + def withLanguageIds(languageIds: Vector[String]): RunProvider = { + copy(languageIds = languageIds) + } +} +object RunProvider { + + def apply(languageIds: Vector[String]): RunProvider = new RunProvider(languageIds) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/RunResult.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/RunResult.scala new file mode 100644 index 000000000..33583b0ed --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/RunResult.scala @@ -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 +/** + * Run Result + * @param originId An optional request id to know the origin of this report. + * @param statusCode A status code fore the execution. + */ +final class RunResult private ( + val originId: Option[String], + val statusCode: Int) extends Serializable { + + + + override def equals(o: Any): Boolean = o match { + case x: RunResult => (this.originId == x.originId) && (this.statusCode == x.statusCode) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (37 * (17 + "sbt.internal.bsp.RunResult".##) + originId.##) + statusCode.##) + } + override def toString: String = { + "RunResult(" + originId + ", " + statusCode + ")" + } + private[this] def copy(originId: Option[String] = originId, statusCode: Int = statusCode): RunResult = { + new RunResult(originId, statusCode) + } + def withOriginId(originId: Option[String]): RunResult = { + copy(originId = originId) + } + def withOriginId(originId: String): RunResult = { + copy(originId = Option(originId)) + } + def withStatusCode(statusCode: Int): RunResult = { + copy(statusCode = statusCode) + } +} +object RunResult { + + def apply(originId: Option[String], statusCode: Int): RunResult = new RunResult(originId, statusCode) + def apply(originId: String, statusCode: Int): RunResult = new RunResult(Option(originId), statusCode) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/BuildServerCapabilitiesFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/BuildServerCapabilitiesFormats.scala index 360a19ecd..7864480af 100644 --- a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/BuildServerCapabilitiesFormats.scala +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/BuildServerCapabilitiesFormats.scala @@ -5,17 +5,18 @@ // DO NOT EDIT MANUALLY package sbt.internal.bsp.codec import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } -trait BuildServerCapabilitiesFormats { self: sbt.internal.bsp.codec.CompileProviderFormats with sjsonnew.BasicJsonProtocol => +trait BuildServerCapabilitiesFormats { self: sbt.internal.bsp.codec.CompileProviderFormats with sbt.internal.bsp.codec.RunProviderFormats with sjsonnew.BasicJsonProtocol => implicit lazy val BuildServerCapabilitiesFormat: JsonFormat[sbt.internal.bsp.BuildServerCapabilities] = new JsonFormat[sbt.internal.bsp.BuildServerCapabilities] { override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.BuildServerCapabilities = { __jsOpt match { case Some(__js) => unbuilder.beginObject(__js) val compileProvider = unbuilder.readField[Option[sbt.internal.bsp.CompileProvider]]("compileProvider") + val runProvider = unbuilder.readField[Option[sbt.internal.bsp.RunProvider]]("runProvider") val dependencySourcesProvider = unbuilder.readField[Option[Boolean]]("dependencySourcesProvider") val canReload = unbuilder.readField[Option[Boolean]]("canReload") unbuilder.endObject() - sbt.internal.bsp.BuildServerCapabilities(compileProvider, dependencySourcesProvider, canReload) + sbt.internal.bsp.BuildServerCapabilities(compileProvider, runProvider, dependencySourcesProvider, canReload) case None => deserializationError("Expected JsObject but found None") } @@ -23,6 +24,7 @@ implicit lazy val BuildServerCapabilitiesFormat: JsonFormat[sbt.internal.bsp.Bui override def write[J](obj: sbt.internal.bsp.BuildServerCapabilities, builder: Builder[J]): Unit = { builder.beginObject() builder.addField("compileProvider", obj.compileProvider) + builder.addField("runProvider", obj.runProvider) builder.addField("dependencySourcesProvider", obj.dependencySourcesProvider) builder.addField("canReload", obj.canReload) 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 135d9757b..0cd9acee0 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 @@ -17,6 +17,7 @@ trait JsonProtocol extends sjsonnew.BasicJsonProtocol with sbt.internal.bsp.codec.BuildClientCapabilitiesFormats with sbt.internal.bsp.codec.InitializeBuildParamsFormats with sbt.internal.bsp.codec.CompileProviderFormats + with sbt.internal.bsp.codec.RunProviderFormats with sbt.internal.bsp.codec.BuildServerCapabilitiesFormats with sbt.internal.bsp.codec.InitializeBuildResultFormats with sbt.internal.bsp.codec.PublishDiagnosticsParamsFormats @@ -34,6 +35,8 @@ trait JsonProtocol extends sjsonnew.BasicJsonProtocol with sbt.internal.bsp.codec.BspCompileResultFormats with sbt.internal.bsp.codec.CompileTaskFormats with sbt.internal.bsp.codec.CompileReportFormats + with sbt.internal.bsp.codec.RunParamsFormats + with sbt.internal.bsp.codec.RunResultFormats 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/RunParamsFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/RunParamsFormats.scala new file mode 100644 index 000000000..808c53fcf --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/RunParamsFormats.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 RunParamsFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats with sbt.internal.util.codec.JValueFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val RunParamsFormat: JsonFormat[sbt.internal.bsp.RunParams] = new JsonFormat[sbt.internal.bsp.RunParams] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.RunParams = { + __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 arguments = unbuilder.readField[Vector[String]]("arguments") + val dataKind = unbuilder.readField[Option[String]]("dataKind") + val data = unbuilder.readField[Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]]("data") + unbuilder.endObject() + sbt.internal.bsp.RunParams(target, originId, arguments, dataKind, data) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.RunParams, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("target", obj.target) + builder.addField("originId", obj.originId) + builder.addField("arguments", obj.arguments) + builder.addField("dataKind", obj.dataKind) + builder.addField("data", obj.data) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/RunProviderFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/RunProviderFormats.scala new file mode 100644 index 000000000..09ec6eeae --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/RunProviderFormats.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 RunProviderFormats { self: sjsonnew.BasicJsonProtocol => +implicit lazy val RunProviderFormat: JsonFormat[sbt.internal.bsp.RunProvider] = new JsonFormat[sbt.internal.bsp.RunProvider] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.RunProvider = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val languageIds = unbuilder.readField[Vector[String]]("languageIds") + unbuilder.endObject() + sbt.internal.bsp.RunProvider(languageIds) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.RunProvider, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("languageIds", obj.languageIds) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/RunResultFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/RunResultFormats.scala new file mode 100644 index 000000000..b22aa7e82 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/RunResultFormats.scala @@ -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 RunResultFormats { self: sjsonnew.BasicJsonProtocol => +implicit lazy val RunResultFormat: JsonFormat[sbt.internal.bsp.RunResult] = new JsonFormat[sbt.internal.bsp.RunResult] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.RunResult = { + __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.RunResult(originId, statusCode) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.RunResult, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("originId", obj.originId) + builder.addField("statusCode", obj.statusCode) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband/bsp.contra b/protocol/src/main/contraband/bsp.contra index e043c93c6..c4b184e27 100644 --- a/protocol/src/main/contraband/bsp.contra +++ b/protocol/src/main/contraband/bsp.contra @@ -172,7 +172,7 @@ type BuildServerCapabilities { # testProvider: TestProvider # The languages the server supports run via method buildTarget/run - # runProvider: RunProvider + runProvider: sbt.internal.bsp.RunProvider # The server can provide a list of targets that contain a # single text document via the method buildTarget/inverseSources @@ -198,6 +198,10 @@ type CompileProvider { languageIds: [String] } +type RunProvider { + languageIds: [String] +} + ## Publish Diagnostics type PublishDiagnosticsParams { ## The document where the diagnostics are published. @@ -367,6 +371,39 @@ type CompileReport { time: Int } +## Run Request +## The run request is sent from the client to the server to run a build target. +## The server communicates during the initialize handshake whether this method is supported or not. +## An empty run request is valid. +type RunParams { + ## The build target to run. + target: sbt.internal.bsp.BuildTargetIdentifier! + + ## An option identifier gnerated by the client to identify this request. + ## The server may include this id in triggered notifications or responses. + originId: String + + ## Optional arguments to the executed application. + arguments: [String] + + ## Kind of data to expect in the data field. + ## If this field is not set, the kind of data is not specified. + dataKind: String + + ## Language-specific metadata for this execution. + data: sjsonnew.shaded.scalajson.ast.unsafe.JValue +} + +## Run Result +type RunResult { + ## An optional request id to know the origin of this report. + originId: String + + ## A status code fore the execution. + statusCode: Int! +} + + # Scala Extension ## Contains scala-specific metadata for compiling a target containing Scala sources.