build server protocol

Initial draft for bsp support.

This shows two communication pattern around BSP.
First, if the request can be handled with the build knowledge is readily available in `NetworkChannel` we can reply immediately. `BuildServerImpl#onBspBuildTargets` is an example for that.

Second, if the request requires `State`, then we can forward the parameter into a custom command, and reply back from a command. `BuildServerProtocol.bspBuildTargetSources` is an example of that since it needs to invoke tasks to generate sources.
This commit is contained in:
Eugene Yokota 2020-02-16 18:01:45 -05:00 committed by Adrien Piquerez
parent 7e806effa2
commit cb93d20492
32 changed files with 1245 additions and 4 deletions

View File

@ -14,6 +14,7 @@ import sbt.internal.protocol._
import sbt.util.Logger
import sbt.protocol.{ SettingQuery => Q, CompletionParams => CP }
import sbt.internal.langserver.{ CancelRequestParams => CRP }
import sbt.internal.bsp._
/**
* ServerHandler allows plugins to extend sbt server.
@ -73,4 +74,6 @@ trait ServerCallback {
private[sbt] def onSettingQuery(execId: Option[String], req: Q): Unit
private[sbt] def onCompletionRequest(execId: Option[String], cp: CP): Unit
private[sbt] def onCancellationRequest(execId: Option[String], crp: CRP): Unit
private[sbt] def onBspInitialize(execId: Option[String], param: InitializeBuildParams): Unit
private[sbt] def onBspBuildTargets(execId: Option[String]): Unit
}

View File

@ -242,7 +242,7 @@ object BuiltinCommands {
act,
continuous,
clearCaches,
) ++ allBasicCommands
) ++ allBasicCommands ++ server.BuildServerProtocol.commands
def DefaultBootCommands: Seq[String] =
WriteSbtVersion :: LoadProject :: NotifyUsersAboutShell :: s"$IfLast $Shell" :: Nil

View File

@ -0,0 +1,149 @@
/*
* sbt
* Copyright 2011 - 2018, Lightbend, Inc.
* Copyright 2008 - 2010, Mark Harrah
* Licensed under Apache License 2.0 (see LICENSE)
*/
package sbt
package internal
package server
import java.net.URI
import sbt.internal.bsp._
import sbt.librarymanagement.{ Configuration, Configurations }
import Configurations.{ Compile, Test }
import sbt.SlashSyntax0._
import sbt.BuildSyntax._
import scala.collection.mutable
object BuildServerProtocol {
private[sbt] val idMap: mutable.Map[BuildTargetIdentifier, (ProjectRef, Configuration)] =
mutable.Map.empty
val BspBuildTargetSource = "bspBuildTargetSources"
def commands: List[Command] = List(bspBuildTargetSources)
/**
* Command that expects list of URIs.
* https://github.com/build-server-protocol/build-server-protocol/blob/master/docs/specification.md#build-target-sources-request
*/
def bspBuildTargetSources: Command = Command.args(BspBuildTargetSource, "<args>") {
(s0: State, args: Seq[String]) =>
import sbt.internal.bsp.codec.JsonProtocol._
var s: State = s0
val items = args map { arg =>
val id = BuildTargetIdentifier(new URI(arg))
val pair = idMap(id)
println(pair.toString)
val dirs = s0.setting(pair._1 / pair._2 / Keys.unmanagedSourceDirectories)
val (next, managed) = s.unsafeRunTask(pair._1 / pair._2 / Keys.managedSources)
s = next
val items = (dirs.toVector map { dir =>
SourceItem(dir.toURI, SourceItemKind.Directory, false)
}) ++
(managed.toVector map { x =>
SourceItem(x.toURI, SourceItemKind.File, true)
})
SourcesItem(id, items)
}
val result = SourcesResult(items.toVector)
s0.respondEvent(result)
s
}
// def json(s: String): JValue = Parser.parseUnsafe(s)
def toId(ref: ProjectReference, config: Configuration): BuildTargetIdentifier =
ref match {
case ProjectRef(build, project) =>
BuildTargetIdentifier(new URI(s"$build#$project/${config.id}"))
case _ => sys.error(s"unexpected $ref")
}
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(toId(ref.project, Compile))
case (fr, "test") if fr == from.name => Some(toId(ref.project, Test))
case _ => None
}
}
}
// 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
protected def onBspInitialize(execId: Option[String], param: InitializeBuildParams): Unit = {
import sbt.internal.bsp.codec.JsonProtocol._
val bspVersion = "2.0.0-M5"
// https://microsoft.github.io/language-server-protocol/specification#textDocumentItem
val languageIds = Vector("scala")
val sbtV = setting(Keys.sbtVersion)
val response =
InitializeBuildResult("sbt", sbtV, bspVersion, BuildClientCapabilities(languageIds))
respondResult(response, execId)
}
/**
* https://github.com/build-server-protocol/build-server-protocol/blob/master/docs/specification.md#workspace-build-targets-request
*/
protected def onBspBuildTargets(execId: Option[String]): Unit = {
import sbt.internal.bsp.codec.JsonProtocol._
val targets = buildTargets
respondResult(targets, execId)
}
def buildTargets: WorkspaceBuildTargetsResult = {
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 = toId(ref, Compile)
idMap(compileId) = (ref, Compile)
val t0 = BuildTarget(
compileId,
displayName = Some(p.id),
baseDirectory = baseOpt,
tags = Vector.empty,
languageIds = Vector("scala"),
dependencies = internalCompileDeps,
dataKind = None
)
val testId = toId(ref, Test)
idMap(testId) = (ref, Test)
// encode Test extending Compile
val internalTestDeps =
(p.dependencies ++ Seq(ResolvedClasspathDependency(ref, Some("test->compile"))))
.flatMap(idForConfig(_, Test))
.toVector
val t1 = BuildTarget(
testId,
displayName = Some(p.id + " test"),
baseDirectory = baseOpt,
tags = Vector.empty,
languageIds = Vector("scala"),
dependencies = internalTestDeps,
dataKind = None
)
Seq(t0, t1)
}
WorkspaceBuildTargetsResult(ts.toVector)
}
}

View File

@ -14,6 +14,7 @@ import sjsonnew.support.scalajson.unsafe.Converter
import sbt.protocol.Serialization
import sbt.protocol.{ CompletionParams => CP, SettingQuery => Q }
import sbt.internal.langserver.{ CancelRequestParams => CRP }
import sbt.internal.bsp._
import sbt.internal.protocol._
import sbt.internal.protocol.codec._
import sbt.internal.langserver._
@ -44,6 +45,7 @@ private[sbt] object LanguageServerProtocol {
{
import sbt.internal.langserver.codec.JsonProtocol._
import internalJsonProtocol._
import sbt.internal.bsp.codec.JsonProtocol._
def json(r: JsonRpcRequestMessage) =
r.params.getOrElse(
throw LangServerError(
@ -91,6 +93,36 @@ private[sbt] object LanguageServerProtocol {
import sbt.protocol.codec.JsonProtocol._
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" =>
onBspBuildTargets(Option(r.id))
case r: JsonRpcRequestMessage if r.method == "buildTarget/sources" =>
import sbt.internal.bsp.codec.JsonProtocol._
val param = Converter.fromJson[SourcesParams](json(r)).get
appendExec(
Exec(
s"""${BuildServerProtocol.BspBuildTargetSource} ${param.targets
.map(_.uri)
.mkString(" ")}""",
Option(r.id),
Some(CommandSource(name))
)
)
()
case r: JsonRpcRequestMessage if r.method == "sbt/setting" =>
import sbt.protocol.codec.JsonProtocol._
val param = Converter.fromJson[Q](json(r)).get
onSettingQuery(Option(r.id), param)
case r: JsonRpcRequestMessage if r.method == "sbt/cancelRequest" =>
val param = Converter.fromJson[CRP](json(r)).get
onCancellationRequest(Option(r.id), param)
case r: JsonRpcRequestMessage if r.method == "sbt/completion" =>
import sbt.protocol.codec.JsonProtocol._
val param = Converter.fromJson[CP](json(r)).get
onCompletionRequest(Option(r.id), param)
}
}, {
case n: JsonRpcNotificationMessage if n.method == "textDocument/didSave" =>
@ -113,6 +145,8 @@ private[sbt] trait LanguageServerProtocol { self: NetworkChannel =>
protected def onSettingQuery(execId: Option[String], req: Q): Unit
protected def onCompletionRequest(execId: Option[String], cp: CP): Unit
protected def onCancellationRequest(execId: Option[String], crp: CRP): Unit
protected def onBspInitialize(execId: Option[String], param: InitializeBuildParams): Unit
protected def onBspBuildTargets(execId: Option[String]): Unit
protected lazy val callbackImpl: ServerCallback = new ServerCallback {
def jsonRpcRespond[A: JsonFormat](event: A, execId: Option[String]): Unit =
@ -136,6 +170,10 @@ private[sbt] trait LanguageServerProtocol { self: NetworkChannel =>
self.onCompletionRequest(execId, cp)
private[sbt] def onCancellationRequest(execId: Option[String], crp: CancelRequestParams): Unit =
self.onCancellationRequest(execId, crp)
private[sbt] def onBspInitialize(execId: Option[String], param: InitializeBuildParams): Unit =
self.onBspInitialize(execId, param)
private[sbt] def onBspBuildTargets(execId: Option[String]): Unit =
self.onBspBuildTargets(execId)
}
/**

View File

@ -34,13 +34,14 @@ import scala.util.control.NonFatal
final class NetworkChannel(
val name: String,
connection: Socket,
structure: BuildStructure,
protected val structure: BuildStructure,
auth: Set[ServerAuthentication],
instance: ServerInstance,
handlers: Seq[ServerHandler],
val log: Logger
) extends CommandChannel
with LanguageServerProtocol {
with LanguageServerProtocol
with BuildServerImpl {
import NetworkChannel._
private val running = new AtomicBoolean(true)
@ -395,6 +396,18 @@ final class NetworkChannel(
}
}
protected def getSetting[A](key: SettingKey[A]): Option[A] =
structure.data.get(key.scope, key.key)
protected def getTaskValue[A](key: TaskKey[A]): Option[Task[A]] =
structure.data.get(key.scope, key.key)
protected def setting[A](key: SettingKey[A]): A =
getSetting(key).getOrElse(sys.error(s"key ${Def.displayFull(key.scopedKey)} is not defined"))
protected def taskValue[A](key: TaskKey[A]): Task[A] =
getTaskValue(key).getOrElse(sys.error(s"key ${Def.displayFull(key.scopedKey)} is not defined"))
private def onExecCommand(cmd: ExecCommand) = {
if (initialized) {
append(

View File

@ -0,0 +1,36 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/** @param languageIds The languages that this client supports.
The ID strings for each language is defined in the LSP.
The server must never respond with build targets for other
languages than those that appear in this list. */
final class BuildClientCapabilities private (
val languageIds: Vector[String]) extends Serializable {
override def equals(o: Any): Boolean = o match {
case x: BuildClientCapabilities => (this.languageIds == x.languageIds)
case _ => false
}
override def hashCode: Int = {
37 * (37 * (17 + "sbt.internal.bsp.BuildClientCapabilities".##) + languageIds.##)
}
override def toString: String = {
"BuildClientCapabilities(" + languageIds + ")"
}
private[this] def copy(languageIds: Vector[String] = languageIds): BuildClientCapabilities = {
new BuildClientCapabilities(languageIds)
}
def withLanguageIds(languageIds: Vector[String]): BuildClientCapabilities = {
copy(languageIds = languageIds)
}
}
object BuildClientCapabilities {
def apply(languageIds: Vector[String]): BuildClientCapabilities = new BuildClientCapabilities(languageIds)
}

View File

@ -0,0 +1,87 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/**
* Build target
* @param id The targets unique identifier
* @param displayName A human readable name for this target.
May be presented in the user interface.
Should be unique if possible.
The id.uri is used if None.
* @param baseDirectory The directory where this target belongs to. Multiple build targets are allowed to map
to the same base directory, and a build target is not required to have a base directory.
A base directory does not determine the sources of a target, see buildTarget/sources.
* @param tags Free-form string tags to categorize or label this build target.
For example, can be used by the client to:
- customize how the target should be translated into the client's project model.
- group together different but related targets in the user interface.
- display icons or colors in the user interface.
Pre-defined tags are listed in `BuildTargetTag` but clients and servers
are free to define new tags for custom purposes.
* @param languageIds The set of languages that this target contains.
The ID string for each language is defined in the LSP.
* @param dataKind Kind of data to expect in the `data` field. If this field is not set, the kind of data is not specified.
*/
final class BuildTarget private (
val id: sbt.internal.bsp.BuildTargetIdentifier,
val displayName: Option[String],
val baseDirectory: Option[java.net.URI],
val tags: Vector[String],
val languageIds: Vector[String],
val dependencies: Vector[sbt.internal.bsp.BuildTargetIdentifier],
val dataKind: Option[String]) extends Serializable {
override def equals(o: Any): Boolean = o match {
case x: BuildTarget => (this.id == x.id) && (this.displayName == x.displayName) && (this.baseDirectory == x.baseDirectory) && (this.tags == x.tags) && (this.languageIds == x.languageIds) && (this.dependencies == x.dependencies) && (this.dataKind == x.dataKind)
case _ => false
}
override def hashCode: Int = {
37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.BuildTarget".##) + id.##) + displayName.##) + baseDirectory.##) + tags.##) + languageIds.##) + dependencies.##) + dataKind.##)
}
override def toString: String = {
"BuildTarget(" + id + ", " + displayName + ", " + baseDirectory + ", " + tags + ", " + languageIds + ", " + dependencies + ", " + dataKind + ")"
}
private[this] def copy(id: sbt.internal.bsp.BuildTargetIdentifier = id, displayName: Option[String] = displayName, baseDirectory: Option[java.net.URI] = baseDirectory, tags: Vector[String] = tags, languageIds: Vector[String] = languageIds, dependencies: Vector[sbt.internal.bsp.BuildTargetIdentifier] = dependencies, dataKind: Option[String] = dataKind): BuildTarget = {
new BuildTarget(id, displayName, baseDirectory, tags, languageIds, dependencies, dataKind)
}
def withId(id: sbt.internal.bsp.BuildTargetIdentifier): BuildTarget = {
copy(id = id)
}
def withDisplayName(displayName: Option[String]): BuildTarget = {
copy(displayName = displayName)
}
def withDisplayName(displayName: String): BuildTarget = {
copy(displayName = Option(displayName))
}
def withBaseDirectory(baseDirectory: Option[java.net.URI]): BuildTarget = {
copy(baseDirectory = baseDirectory)
}
def withBaseDirectory(baseDirectory: java.net.URI): BuildTarget = {
copy(baseDirectory = Option(baseDirectory))
}
def withTags(tags: Vector[String]): BuildTarget = {
copy(tags = tags)
}
def withLanguageIds(languageIds: Vector[String]): BuildTarget = {
copy(languageIds = languageIds)
}
def withDependencies(dependencies: Vector[sbt.internal.bsp.BuildTargetIdentifier]): BuildTarget = {
copy(dependencies = dependencies)
}
def withDataKind(dataKind: Option[String]): BuildTarget = {
copy(dataKind = dataKind)
}
def withDataKind(dataKind: String): BuildTarget = {
copy(dataKind = Option(dataKind))
}
}
object BuildTarget {
def apply(id: sbt.internal.bsp.BuildTargetIdentifier, displayName: Option[String], baseDirectory: Option[java.net.URI], tags: Vector[String], languageIds: Vector[String], dependencies: Vector[sbt.internal.bsp.BuildTargetIdentifier], dataKind: Option[String]): BuildTarget = new BuildTarget(id, displayName, baseDirectory, tags, languageIds, dependencies, dataKind)
def apply(id: sbt.internal.bsp.BuildTargetIdentifier, displayName: String, baseDirectory: java.net.URI, tags: Vector[String], languageIds: Vector[String], dependencies: Vector[sbt.internal.bsp.BuildTargetIdentifier], dataKind: String): BuildTarget = new BuildTarget(id, Option(displayName), Option(baseDirectory), tags, languageIds, dependencies, Option(dataKind))
}

View File

@ -0,0 +1,36 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/**
* Build Target Identifier
* @param uri The target's Uri
*/
final class BuildTargetIdentifier private (
val uri: java.net.URI) extends Serializable {
override def equals(o: Any): Boolean = o match {
case x: BuildTargetIdentifier => (this.uri == x.uri)
case _ => false
}
override def hashCode: Int = {
37 * (37 * (17 + "sbt.internal.bsp.BuildTargetIdentifier".##) + uri.##)
}
override def toString: String = {
"BuildTargetIdentifier(" + uri + ")"
}
private[this] def copy(uri: java.net.URI = uri): BuildTargetIdentifier = {
new BuildTargetIdentifier(uri)
}
def withUri(uri: java.net.URI): BuildTargetIdentifier = {
copy(uri = uri)
}
}
object BuildTargetIdentifier {
def apply(uri: java.net.URI): BuildTargetIdentifier = new BuildTargetIdentifier(uri)
}

View File

@ -0,0 +1,56 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/**
* Initialize Build Request
* @param displayName Name of the client
* @param version The version of the client
* @param bspVersion The BSP version that the client speaks
* @param rootUri The rootUri of the workspace
* @param capabilities The capabilities of the client
*/
final class InitializeBuildParams private (
val displayName: String,
val version: String,
val bspVersion: String,
val rootUri: java.net.URI,
val capabilities: sbt.internal.bsp.BuildClientCapabilities) extends Serializable {
override def equals(o: Any): Boolean = o match {
case x: InitializeBuildParams => (this.displayName == x.displayName) && (this.version == x.version) && (this.bspVersion == x.bspVersion) && (this.rootUri == x.rootUri) && (this.capabilities == x.capabilities)
case _ => false
}
override def hashCode: Int = {
37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.InitializeBuildParams".##) + displayName.##) + version.##) + bspVersion.##) + rootUri.##) + capabilities.##)
}
override def toString: String = {
"InitializeBuildParams(" + displayName + ", " + version + ", " + bspVersion + ", " + rootUri + ", " + capabilities + ")"
}
private[this] def copy(displayName: String = displayName, version: String = version, bspVersion: String = bspVersion, rootUri: java.net.URI = rootUri, capabilities: sbt.internal.bsp.BuildClientCapabilities = capabilities): InitializeBuildParams = {
new InitializeBuildParams(displayName, version, bspVersion, rootUri, capabilities)
}
def withDisplayName(displayName: String): InitializeBuildParams = {
copy(displayName = displayName)
}
def withVersion(version: String): InitializeBuildParams = {
copy(version = version)
}
def withBspVersion(bspVersion: String): InitializeBuildParams = {
copy(bspVersion = bspVersion)
}
def withRootUri(rootUri: java.net.URI): InitializeBuildParams = {
copy(rootUri = rootUri)
}
def withCapabilities(capabilities: sbt.internal.bsp.BuildClientCapabilities): InitializeBuildParams = {
copy(capabilities = capabilities)
}
}
object InitializeBuildParams {
def apply(displayName: String, version: String, bspVersion: String, rootUri: java.net.URI, capabilities: sbt.internal.bsp.BuildClientCapabilities): InitializeBuildParams = new InitializeBuildParams(displayName, version, bspVersion, rootUri, capabilities)
}

View File

@ -0,0 +1,50 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/**
* @param displayName Name of the server
* @param version The version of the server
* @param bspVersion The BSP version that the server speaks
* @param capabilities The capabilities of the build server
*/
final class InitializeBuildResult private (
val displayName: String,
val version: String,
val bspVersion: String,
val capabilities: sbt.internal.bsp.BuildClientCapabilities) extends Serializable {
override def equals(o: Any): Boolean = o match {
case x: InitializeBuildResult => (this.displayName == x.displayName) && (this.version == x.version) && (this.bspVersion == x.bspVersion) && (this.capabilities == x.capabilities)
case _ => false
}
override def hashCode: Int = {
37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.InitializeBuildResult".##) + displayName.##) + version.##) + bspVersion.##) + capabilities.##)
}
override def toString: String = {
"InitializeBuildResult(" + displayName + ", " + version + ", " + bspVersion + ", " + capabilities + ")"
}
private[this] def copy(displayName: String = displayName, version: String = version, bspVersion: String = bspVersion, capabilities: sbt.internal.bsp.BuildClientCapabilities = capabilities): InitializeBuildResult = {
new InitializeBuildResult(displayName, version, bspVersion, capabilities)
}
def withDisplayName(displayName: String): InitializeBuildResult = {
copy(displayName = displayName)
}
def withVersion(version: String): InitializeBuildResult = {
copy(version = version)
}
def withBspVersion(bspVersion: String): InitializeBuildResult = {
copy(bspVersion = bspVersion)
}
def withCapabilities(capabilities: sbt.internal.bsp.BuildClientCapabilities): InitializeBuildResult = {
copy(capabilities = capabilities)
}
}
object InitializeBuildResult {
def apply(displayName: String, version: String, bspVersion: String, capabilities: sbt.internal.bsp.BuildClientCapabilities): InitializeBuildResult = new InitializeBuildResult(displayName, version, bspVersion, capabilities)
}

View File

@ -0,0 +1,49 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/**
* @param uri Either a text document or a directory. A directory entry must end with a forward
slash "/" and a directory entry implies that every nested text document within the
directory belongs to this source item.
* @param kind Type of file of the source item, such as whether it is file or directory.
* @param generated Indicates if this source is automatically generated by the build and is not
intended to be manually edited by the user.
*/
final class SourceItem private (
val uri: java.net.URI,
val kind: Int,
val generated: Boolean) extends Serializable {
override def equals(o: Any): Boolean = o match {
case x: SourceItem => (this.uri == x.uri) && (this.kind == x.kind) && (this.generated == x.generated)
case _ => false
}
override def hashCode: Int = {
37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.SourceItem".##) + uri.##) + kind.##) + generated.##)
}
override def toString: String = {
"SourceItem(" + uri + ", " + kind + ", " + generated + ")"
}
private[this] def copy(uri: java.net.URI = uri, kind: Int = kind, generated: Boolean = generated): SourceItem = {
new SourceItem(uri, kind, generated)
}
def withUri(uri: java.net.URI): SourceItem = {
copy(uri = uri)
}
def withKind(kind: Int): SourceItem = {
copy(kind = kind)
}
def withGenerated(generated: Boolean): SourceItem = {
copy(generated = generated)
}
}
object SourceItem {
def apply(uri: java.net.URI, kind: Int, generated: Boolean): SourceItem = new SourceItem(uri, kind, generated)
}

View File

@ -0,0 +1,37 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/** @param sources The text documents or and directories that belong to this build target. */
final class SourcesItem private (
val target: sbt.internal.bsp.BuildTargetIdentifier,
val sources: Vector[sbt.internal.bsp.SourceItem]) extends Serializable {
override def equals(o: Any): Boolean = o match {
case x: SourcesItem => (this.target == x.target) && (this.sources == x.sources)
case _ => false
}
override def hashCode: Int = {
37 * (37 * (37 * (17 + "sbt.internal.bsp.SourcesItem".##) + target.##) + sources.##)
}
override def toString: String = {
"SourcesItem(" + target + ", " + sources + ")"
}
private[this] def copy(target: sbt.internal.bsp.BuildTargetIdentifier = target, sources: Vector[sbt.internal.bsp.SourceItem] = sources): SourcesItem = {
new SourcesItem(target, sources)
}
def withTarget(target: sbt.internal.bsp.BuildTargetIdentifier): SourcesItem = {
copy(target = target)
}
def withSources(sources: Vector[sbt.internal.bsp.SourceItem]): SourcesItem = {
copy(sources = sources)
}
}
object SourcesItem {
def apply(target: sbt.internal.bsp.BuildTargetIdentifier, sources: Vector[sbt.internal.bsp.SourceItem]): SourcesItem = new SourcesItem(target, sources)
}

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
/** Build Target Sources Request */
final class SourcesParams private (
val targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]) extends Serializable {
override def equals(o: Any): Boolean = o match {
case x: SourcesParams => (this.targets == x.targets)
case _ => false
}
override def hashCode: Int = {
37 * (37 * (17 + "sbt.internal.bsp.SourcesParams".##) + targets.##)
}
override def toString: String = {
"SourcesParams(" + targets + ")"
}
private[this] def copy(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier] = targets): SourcesParams = {
new SourcesParams(targets)
}
def withTargets(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]): SourcesParams = {
copy(targets = targets)
}
}
object SourcesParams {
def apply(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]): SourcesParams = new SourcesParams(targets)
}

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
/** Build Target Sources response */
final class SourcesResult private (
val items: Vector[sbt.internal.bsp.SourcesItem]) extends Serializable {
override def equals(o: Any): Boolean = o match {
case x: SourcesResult => (this.items == x.items)
case _ => false
}
override def hashCode: Int = {
37 * (37 * (17 + "sbt.internal.bsp.SourcesResult".##) + items.##)
}
override def toString: String = {
"SourcesResult(" + items + ")"
}
private[this] def copy(items: Vector[sbt.internal.bsp.SourcesItem] = items): SourcesResult = {
new SourcesResult(items)
}
def withItems(items: Vector[sbt.internal.bsp.SourcesItem]): SourcesResult = {
copy(items = items)
}
}
object SourcesResult {
def apply(items: Vector[sbt.internal.bsp.SourcesItem]): SourcesResult = new SourcesResult(items)
}

View File

@ -0,0 +1,37 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/**
* Workspace Build Targets response
* @param targets The build targets in this workspace that
contain sources with the given language ids.
*/
final class WorkspaceBuildTargetsResult private (
val targets: Vector[sbt.internal.bsp.BuildTarget]) extends Serializable {
override def equals(o: Any): Boolean = o match {
case x: WorkspaceBuildTargetsResult => (this.targets == x.targets)
case _ => false
}
override def hashCode: Int = {
37 * (37 * (17 + "sbt.internal.bsp.WorkspaceBuildTargetsResult".##) + targets.##)
}
override def toString: String = {
"WorkspaceBuildTargetsResult(" + targets + ")"
}
private[this] def copy(targets: Vector[sbt.internal.bsp.BuildTarget] = targets): WorkspaceBuildTargetsResult = {
new WorkspaceBuildTargetsResult(targets)
}
def withTargets(targets: Vector[sbt.internal.bsp.BuildTarget]): WorkspaceBuildTargetsResult = {
copy(targets = targets)
}
}
object WorkspaceBuildTargetsResult {
def apply(targets: Vector[sbt.internal.bsp.BuildTarget]): WorkspaceBuildTargetsResult = new WorkspaceBuildTargetsResult(targets)
}

View File

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

View File

@ -0,0 +1,39 @@
/**
* 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 BuildTargetFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats with sjsonnew.BasicJsonProtocol =>
implicit lazy val BuildTargetFormat: JsonFormat[sbt.internal.bsp.BuildTarget] = new JsonFormat[sbt.internal.bsp.BuildTarget] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.BuildTarget = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val id = unbuilder.readField[sbt.internal.bsp.BuildTargetIdentifier]("id")
val displayName = unbuilder.readField[Option[String]]("displayName")
val baseDirectory = unbuilder.readField[Option[java.net.URI]]("baseDirectory")
val tags = unbuilder.readField[Vector[String]]("tags")
val languageIds = unbuilder.readField[Vector[String]]("languageIds")
val dependencies = unbuilder.readField[Vector[sbt.internal.bsp.BuildTargetIdentifier]]("dependencies")
val dataKind = unbuilder.readField[Option[String]]("dataKind")
unbuilder.endObject()
sbt.internal.bsp.BuildTarget(id, displayName, baseDirectory, tags, languageIds, dependencies, dataKind)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.BuildTarget, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("id", obj.id)
builder.addField("displayName", obj.displayName)
builder.addField("baseDirectory", obj.baseDirectory)
builder.addField("tags", obj.tags)
builder.addField("languageIds", obj.languageIds)
builder.addField("dependencies", obj.dependencies)
builder.addField("dataKind", obj.dataKind)
builder.endObject()
}
}
}

View File

@ -0,0 +1,27 @@
/**
* This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp.codec
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait BuildTargetIdentiferFormats { self: sjsonnew.BasicJsonProtocol =>
implicit lazy val BuildTargetIdentiferFormat: JsonFormat[sbt.internal.bsp.BuildTargetIdentifer] = new JsonFormat[sbt.internal.bsp.BuildTargetIdentifer] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.BuildTargetIdentifer = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val uri = unbuilder.readField[java.net.URI]("uri")
unbuilder.endObject()
sbt.internal.bsp.BuildTargetIdentifer(uri)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.BuildTargetIdentifer, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("uri", obj.uri)
builder.endObject()
}
}
}

View File

@ -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 BuildTargetIdentifierFormats { self: sjsonnew.BasicJsonProtocol =>
implicit lazy val BuildTargetIdentifierFormat: JsonFormat[sbt.internal.bsp.BuildTargetIdentifier] = new JsonFormat[sbt.internal.bsp.BuildTargetIdentifier] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.BuildTargetIdentifier = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val uri = unbuilder.readField[java.net.URI]("uri")
unbuilder.endObject()
sbt.internal.bsp.BuildTargetIdentifier(uri)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.BuildTargetIdentifier, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("uri", obj.uri)
builder.endObject()
}
}
}

View File

@ -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 InitializeBuildParamsFormats { self: sbt.internal.bsp.codec.BuildClientCapabilitiesFormats with sjsonnew.BasicJsonProtocol =>
implicit lazy val InitializeBuildParamsFormat: JsonFormat[sbt.internal.bsp.InitializeBuildParams] = new JsonFormat[sbt.internal.bsp.InitializeBuildParams] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.InitializeBuildParams = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val displayName = unbuilder.readField[String]("displayName")
val version = unbuilder.readField[String]("version")
val bspVersion = unbuilder.readField[String]("bspVersion")
val rootUri = unbuilder.readField[java.net.URI]("rootUri")
val capabilities = unbuilder.readField[sbt.internal.bsp.BuildClientCapabilities]("capabilities")
unbuilder.endObject()
sbt.internal.bsp.InitializeBuildParams(displayName, version, bspVersion, rootUri, capabilities)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.InitializeBuildParams, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("displayName", obj.displayName)
builder.addField("version", obj.version)
builder.addField("bspVersion", obj.bspVersion)
builder.addField("rootUri", obj.rootUri)
builder.addField("capabilities", obj.capabilities)
builder.endObject()
}
}
}

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 InitializeBuildResultFormats { self: sbt.internal.bsp.codec.BuildClientCapabilitiesFormats with sjsonnew.BasicJsonProtocol =>
implicit lazy val InitializeBuildResultFormat: JsonFormat[sbt.internal.bsp.InitializeBuildResult] = new JsonFormat[sbt.internal.bsp.InitializeBuildResult] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.InitializeBuildResult = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val displayName = unbuilder.readField[String]("displayName")
val version = unbuilder.readField[String]("version")
val bspVersion = unbuilder.readField[String]("bspVersion")
val capabilities = unbuilder.readField[sbt.internal.bsp.BuildClientCapabilities]("capabilities")
unbuilder.endObject()
sbt.internal.bsp.InitializeBuildResult(displayName, version, bspVersion, capabilities)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.InitializeBuildResult, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("displayName", obj.displayName)
builder.addField("version", obj.version)
builder.addField("bspVersion", obj.bspVersion)
builder.addField("capabilities", obj.capabilities)
builder.endObject()
}
}
}

View File

@ -0,0 +1,18 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp.codec
trait JsonProtocol extends sjsonnew.BasicJsonProtocol
with sbt.internal.bsp.codec.BuildTargetIdentifierFormats
with sbt.internal.bsp.codec.BuildTargetFormats
with sbt.internal.bsp.codec.BuildClientCapabilitiesFormats
with sbt.internal.bsp.codec.InitializeBuildParamsFormats
with sbt.internal.bsp.codec.InitializeBuildResultFormats
with sbt.internal.bsp.codec.WorkspaceBuildTargetsResultFormats
with sbt.internal.bsp.codec.SourcesParamsFormats
with sbt.internal.bsp.codec.SourceItemFormats
with sbt.internal.bsp.codec.SourcesItemFormats
with sbt.internal.bsp.codec.SourcesResultFormats
object JsonProtocol extends JsonProtocol

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 SourceItemFormats { self: sjsonnew.BasicJsonProtocol =>
implicit lazy val SourceItemFormat: JsonFormat[sbt.internal.bsp.SourceItem] = new JsonFormat[sbt.internal.bsp.SourceItem] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.SourceItem = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val uri = unbuilder.readField[java.net.URI]("uri")
val kind = unbuilder.readField[Int]("kind")
val generated = unbuilder.readField[Boolean]("generated")
unbuilder.endObject()
sbt.internal.bsp.SourceItem(uri, kind, generated)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.SourceItem, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("uri", obj.uri)
builder.addField("kind", obj.kind)
builder.addField("generated", obj.generated)
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 SourcesItemFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats with sbt.internal.bsp.codec.SourceItemFormats with sjsonnew.BasicJsonProtocol =>
implicit lazy val SourcesItemFormat: JsonFormat[sbt.internal.bsp.SourcesItem] = new JsonFormat[sbt.internal.bsp.SourcesItem] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.SourcesItem = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val target = unbuilder.readField[sbt.internal.bsp.BuildTargetIdentifier]("target")
val sources = unbuilder.readField[Vector[sbt.internal.bsp.SourceItem]]("sources")
unbuilder.endObject()
sbt.internal.bsp.SourcesItem(target, sources)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.SourcesItem, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("target", obj.target)
builder.addField("sources", obj.sources)
builder.endObject()
}
}
}

View File

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

View File

@ -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 SourcesResultFormats { self: sbt.internal.bsp.codec.SourcesItemFormats with sjsonnew.BasicJsonProtocol =>
implicit lazy val SourcesResultFormat: JsonFormat[sbt.internal.bsp.SourcesResult] = new JsonFormat[sbt.internal.bsp.SourcesResult] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.SourcesResult = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val items = unbuilder.readField[Vector[sbt.internal.bsp.SourcesItem]]("items")
unbuilder.endObject()
sbt.internal.bsp.SourcesResult(items)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.SourcesResult, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("items", obj.items)
builder.endObject()
}
}
}

View File

@ -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 WorkspaceBuildTargetsResultFormats { self: sbt.internal.bsp.codec.BuildTargetFormats with sjsonnew.BasicJsonProtocol =>
implicit lazy val WorkspaceBuildTargetsResultFormat: JsonFormat[sbt.internal.bsp.WorkspaceBuildTargetsResult] = new JsonFormat[sbt.internal.bsp.WorkspaceBuildTargetsResult] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.WorkspaceBuildTargetsResult = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val targets = unbuilder.readField[Vector[sbt.internal.bsp.BuildTarget]]("targets")
unbuilder.endObject()
sbt.internal.bsp.WorkspaceBuildTargetsResult(targets)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.WorkspaceBuildTargetsResult, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("targets", obj.targets)
builder.endObject()
}
}
}

View File

@ -0,0 +1,136 @@
package sbt.internal.bsp
@target(Scala)
@codecPackage("sbt.internal.bsp.codec")
@fullCodec("JsonProtocol")
## Build target
type BuildTarget {
## The targets unique identifier
id: sbt.internal.bsp.BuildTargetIdentifier!
## A human readable name for this target.
## May be presented in the user interface.
## Should be unique if possible.
## The id.uri is used if None.
displayName: String
## The directory where this target belongs to. Multiple build targets are allowed to map
## to the same base directory, and a build target is not required to have a base directory.
## A base directory does not determine the sources of a target, see buildTarget/sources.
baseDirectory: java.net.URI
## Free-form string tags to categorize or label this build target.
## For example, can be used by the client to:
## - customize how the target should be translated into the client's project model.
## - group together different but related targets in the user interface.
## - display icons or colors in the user interface.
## Pre-defined tags are listed in `BuildTargetTag` but clients and servers
## are free to define new tags for custom purposes.
tags: [String]
# The capabilities of this build target.
# capabilities: BuildTargetCapabilities
## The set of languages that this target contains.
## The ID string for each language is defined in the LSP.
languageIds: [String]
# The direct upstream build target dependencies of this build target
dependencies: [sbt.internal.bsp.BuildTargetIdentifier]
## 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 about this target.
# data: any
}
## Build Target Identifier
type BuildTargetIdentifier {
## The target's Uri
uri: java.net.URI!
}
## Initialize Build Request
type InitializeBuildParams {
## Name of the client
displayName: String!
## The version of the client
version: String!
## The BSP version that the client speaks
bspVersion: String!
## The rootUri of the workspace
rootUri: java.net.URI!
## The capabilities of the client
capabilities: sbt.internal.bsp.BuildClientCapabilities!
# Additional metadata about the client
# data: any
}
type BuildClientCapabilities {
## The languages that this client supports.
## The ID strings for each language is defined in the LSP.
## The server must never respond with build targets for other
## languages than those that appear in this list.
languageIds: [String]
}
type InitializeBuildResult {
## Name of the server
displayName: String!
## The version of the server
version: String!
## The BSP version that the server speaks
bspVersion: String!
## The capabilities of the build server
capabilities: sbt.internal.bsp.BuildClientCapabilities!
# Additional metadata about the server
# data: any
}
## Workspace Build Targets response
type WorkspaceBuildTargetsResult {
## The build targets in this workspace that
## contain sources with the given language ids.
targets: [sbt.internal.bsp.BuildTarget]
}
## Build Target Sources Request
type SourcesParams {
targets: [sbt.internal.bsp.BuildTargetIdentifier]
}
## Build Target Sources response
type SourcesResult {
items: [sbt.internal.bsp.SourcesItem]
}
type SourcesItem {
target: sbt.internal.bsp.BuildTargetIdentifier!
## The text documents or and directories that belong to this build target.
sources: [sbt.internal.bsp.SourceItem]
}
type SourceItem {
## Either a text document or a directory. A directory entry must end with a forward
## slash "/" and a directory entry implies that every nested text document within the
## directory belongs to this source item.
##
uri: java.net.URI!
## Type of file of the source item, such as whether it is file or directory.
kind: Int!
## Indicates if this source is automatically generated by the build and is not
## intended to be manually edited by the user.
generated: Boolean!
}

View File

@ -0,0 +1,19 @@
/*
* sbt
* Copyright 2011 - 2018, Lightbend, Inc.
* Copyright 2008 - 2010, Mark Harrah
* Licensed under Apache License 2.0 (see LICENSE)
*/
package sbt
package internal
package bsp
object SourceItemKind {
/** The source item references a normal file. */
val File: Int = 1
/** The source item references a directory. */
val Directory: Int = 2
}

View File

@ -0,0 +1,11 @@
ThisBuild / scalaVersion := "2.13.1"
Global / serverLog / logLevel := Level.Debug
lazy val root = (project in file("."))
.aggregate(foo, util)
lazy val foo = project
.dependsOn(util)
lazy val util = project

View File

@ -0,0 +1,61 @@
/*
* sbt
* Copyright 2011 - 2018, Lightbend, Inc.
* Copyright 2008 - 2010, Mark Harrah
* Licensed under Apache License 2.0 (see LICENSE)
*/
package testpkg
import scala.concurrent.duration._
// starts svr using server-test/buildserver and perform custom server tests
object BuildServerTest extends AbstractServerTest {
override val testDirectory: String = "buildserver"
test("build/initialize") { _ =>
initializeRequest()
assert(svr.waitForString(10.seconds) { s =>
println(s)
(s contains """"id":"10"""")
})
}
test("workspace/buildTargets") { _ =>
svr.sendJsonRpc(
"""{ "jsonrpc": "2.0", "id": "11", "method": "workspace/buildTargets", "params": {} }"""
)
assert(svr.waitForString(10.seconds) { s =>
println(s)
(s contains """"id":"11"""") &&
(s contains """"displayName":"util"""")
})
}
test("buildTarget/sources") { _ =>
val x = s"${svr.baseDirectory.getAbsoluteFile.toURI}#util/Compile"
svr.sendJsonRpc(
s"""{ "jsonrpc": "2.0", "id": "12", "method": "buildTarget/sources", "params": {
| "targets": [{ "uri": "$x" }]
|} }""".stripMargin
)
assert(svr.waitForString(10.seconds) { s =>
println(s)
(s contains """"id":"12"""")
})
}
def initializeRequest(): Unit = {
svr.sendJsonRpc(
"""{ "jsonrpc": "2.0", "id": "10", "method": "build/initialize",
| "params": {
| "displayName": "test client",
| "version": "1.0.0",
| "bspVersion": "2.0.0-M5",
| "rootUri": "file://root/",
| "capabilities": { "languageIds": ["scala"] }
| }
|}""".stripMargin
)
}
}

View File

@ -26,8 +26,18 @@ trait AbstractServerTest extends TestSuite[Unit] {
var svr: TestServer = _
def testDirectory: String
private val targetDir: File = {
val p0 = new File("..").getAbsoluteFile.getCanonicalFile / "target"
val p1 = new File("target").getAbsoluteFile
if (p0.exists) p0
else p1
}
override def setupSuite(): Unit = {
temp = IO.createTemporaryDirectory
temp = targetDir / "test-server" / testDirectory
if (temp.exists) {
IO.delete(temp)
}
val classpath = sys.props.get("sbt.server.classpath") match {
case Some(s: String) => s.split(java.io.File.pathSeparator).map(file)
case _ => throw new IllegalStateException("No server classpath was specified.")