mirror of https://github.com/sbt/sbt.git
Merge pull request #5838 from adpi2/bsp-reload
Add BSP workspace/reload
This commit is contained in:
commit
75da49556c
|
|
@ -23,9 +23,8 @@ import sbt.internal.CommandStrings.BootCommand
|
||||||
import sbt.internal._
|
import sbt.internal._
|
||||||
import sbt.internal.client.BspClient
|
import sbt.internal.client.BspClient
|
||||||
import sbt.internal.inc.ScalaInstance
|
import sbt.internal.inc.ScalaInstance
|
||||||
import sbt.internal.io.Retry
|
|
||||||
import sbt.internal.nio.{ CheckBuildSources, FileTreeRepository }
|
import sbt.internal.nio.{ CheckBuildSources, FileTreeRepository }
|
||||||
import sbt.internal.server.NetworkChannel
|
import sbt.internal.server.{ BuildServerProtocol, NetworkChannel }
|
||||||
import sbt.internal.util.Types.{ const, idFun }
|
import sbt.internal.util.Types.{ const, idFun }
|
||||||
import sbt.internal.util._
|
import sbt.internal.util._
|
||||||
import sbt.internal.util.complete.{ Parser, SizeParser }
|
import sbt.internal.util.complete.{ Parser, SizeParser }
|
||||||
|
|
@ -317,7 +316,10 @@ object BuiltinCommands {
|
||||||
NetworkChannel.disconnect,
|
NetworkChannel.disconnect,
|
||||||
waitCmd,
|
waitCmd,
|
||||||
promptChannel,
|
promptChannel,
|
||||||
) ++ allBasicCommands ++ ContinuousCommands.value
|
) ++
|
||||||
|
allBasicCommands ++
|
||||||
|
ContinuousCommands.value ++
|
||||||
|
BuildServerProtocol.commands
|
||||||
|
|
||||||
def DefaultBootCommands: Seq[String] =
|
def DefaultBootCommands: Seq[String] =
|
||||||
WriteSbtVersion :: LoadProject :: NotifyUsersAboutShell :: s"$IfLast $Shell" :: Nil
|
WriteSbtVersion :: LoadProject :: NotifyUsersAboutShell :: s"$IfLast $Shell" :: Nil
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,13 @@ import sbt.Def._
|
||||||
import sbt.Keys._
|
import sbt.Keys._
|
||||||
import sbt.ScopeFilter.Make._
|
import sbt.ScopeFilter.Make._
|
||||||
import sbt.SlashSyntax0._
|
import sbt.SlashSyntax0._
|
||||||
|
import sbt.StandardMain.exchange
|
||||||
import sbt.internal.bsp._
|
import sbt.internal.bsp._
|
||||||
import sbt.internal.langserver.ErrorCodes
|
import sbt.internal.langserver.ErrorCodes
|
||||||
import sbt.internal.protocol.JsonRpcRequestMessage
|
import sbt.internal.protocol.JsonRpcRequestMessage
|
||||||
import sbt.librarymanagement.Configuration
|
import sbt.librarymanagement.Configuration
|
||||||
import sbt.util.Logger
|
import sbt.util.Logger
|
||||||
|
import sjsonnew.shaded.scalajson.ast.unsafe.JNull
|
||||||
import sjsonnew.shaded.scalajson.ast.unsafe.JValue
|
import sjsonnew.shaded.scalajson.ast.unsafe.JValue
|
||||||
import sjsonnew.support.scalajson.unsafe.Converter
|
import sjsonnew.support.scalajson.unsafe.Converter
|
||||||
|
|
||||||
|
|
@ -29,9 +31,44 @@ import scala.util.control.NonFatal
|
||||||
|
|
||||||
object BuildServerProtocol {
|
object BuildServerProtocol {
|
||||||
import sbt.internal.bsp.codec.JsonProtocol._
|
import sbt.internal.bsp.codec.JsonProtocol._
|
||||||
|
|
||||||
private val capabilities = BuildServerCapabilities(
|
private val capabilities = BuildServerCapabilities(
|
||||||
CompileProvider(BuildServerConnection.languages),
|
CompileProvider(BuildServerConnection.languages),
|
||||||
dependencySourcesProvider = true
|
dependencySourcesProvider = true,
|
||||||
|
canReload = true
|
||||||
|
)
|
||||||
|
|
||||||
|
private val bspReload = "bspReload"
|
||||||
|
private val bspReloadFailed = "bspReloadFailed"
|
||||||
|
private val bspReloadSucceed = "bspReloadSucceed"
|
||||||
|
|
||||||
|
lazy val commands: Seq[Command] = Seq(
|
||||||
|
Command.single(bspReload) { (state, reqId) =>
|
||||||
|
import sbt.BasicCommandStrings._
|
||||||
|
import sbt.internal.CommandStrings._
|
||||||
|
val result = List(
|
||||||
|
StashOnFailure,
|
||||||
|
s"$OnFailure $bspReloadFailed $reqId",
|
||||||
|
LoadProjectImpl,
|
||||||
|
s"$bspReloadSucceed $reqId",
|
||||||
|
PopOnFailure,
|
||||||
|
FailureWall
|
||||||
|
) ::: state
|
||||||
|
result
|
||||||
|
},
|
||||||
|
Command.single(bspReloadFailed) { (state, reqId) =>
|
||||||
|
exchange.respondError(
|
||||||
|
ErrorCodes.InternalError,
|
||||||
|
"reload failed",
|
||||||
|
Some(reqId),
|
||||||
|
state.source
|
||||||
|
)
|
||||||
|
state
|
||||||
|
},
|
||||||
|
Command.single(bspReloadSucceed) { (state, reqId) =>
|
||||||
|
exchange.respondEvent(JNull, Some(reqId), state.source)
|
||||||
|
state
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
lazy val globalSettings: Seq[Def.Setting[_]] = Seq(
|
lazy val globalSettings: Seq[Def.Setting[_]] = Seq(
|
||||||
|
|
@ -59,7 +96,6 @@ object BuildServerProtocol {
|
||||||
val filter = ScopeFilter.in(targets.map(workspace))
|
val filter = ScopeFilter.in(targets.map(workspace))
|
||||||
// run the worker task concurrently
|
// run the worker task concurrently
|
||||||
Def.task {
|
Def.task {
|
||||||
import sbt.internal.bsp.codec.JsonProtocol._
|
|
||||||
val items = bspBuildTargetSourcesItem.all(filter).value
|
val items = bspBuildTargetSourcesItem.all(filter).value
|
||||||
val result = SourcesResult(items.toVector)
|
val result = SourcesResult(items.toVector)
|
||||||
s.respondEvent(result)
|
s.respondEvent(result)
|
||||||
|
|
@ -86,7 +122,6 @@ object BuildServerProtocol {
|
||||||
val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri)))
|
val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri)))
|
||||||
val filter = ScopeFilter.in(targets.map(workspace))
|
val filter = ScopeFilter.in(targets.map(workspace))
|
||||||
Def.task {
|
Def.task {
|
||||||
import sbt.internal.bsp.codec.JsonProtocol._
|
|
||||||
val statusCode = Keys.bspBuildTargetCompileItem.all(filter).value.max
|
val statusCode = Keys.bspBuildTargetCompileItem.all(filter).value.max
|
||||||
s.respondEvent(BspCompileResult(None, statusCode))
|
s.respondEvent(BspCompileResult(None, statusCode))
|
||||||
}
|
}
|
||||||
|
|
@ -155,6 +190,9 @@ object BuildServerProtocol {
|
||||||
case r: JsonRpcRequestMessage if r.method == "workspace/buildTargets" =>
|
case r: JsonRpcRequestMessage if r.method == "workspace/buildTargets" =>
|
||||||
val _ = callback.appendExec(Keys.bspWorkspaceBuildTargets.key.toString, Some(r.id))
|
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 == "build/shutdown" =>
|
case r: JsonRpcRequestMessage if r.method == "build/shutdown" =>
|
||||||
()
|
()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,25 +8,27 @@ package sbt.internal.bsp
|
||||||
* @param compileProvider The languages the server supports compilation via method buildTarget/compile.
|
* @param compileProvider The languages the server supports compilation via method buildTarget/compile.
|
||||||
* @param dependencySourcesProvider The server provides sources for library dependencies
|
* @param dependencySourcesProvider The server provides sources for library dependencies
|
||||||
via method buildTarget/dependencySources
|
via method buildTarget/dependencySources
|
||||||
|
* @param canReload Reloading the workspace state through workspace/reload is supported
|
||||||
*/
|
*/
|
||||||
final class BuildServerCapabilities private (
|
final class BuildServerCapabilities private (
|
||||||
val compileProvider: Option[sbt.internal.bsp.CompileProvider],
|
val compileProvider: Option[sbt.internal.bsp.CompileProvider],
|
||||||
val dependencySourcesProvider: Option[Boolean]) extends Serializable {
|
val dependencySourcesProvider: Option[Boolean],
|
||||||
|
val canReload: Option[Boolean]) extends Serializable {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
override def equals(o: Any): Boolean = o match {
|
override def equals(o: Any): Boolean = o match {
|
||||||
case x: BuildServerCapabilities => (this.compileProvider == x.compileProvider) && (this.dependencySourcesProvider == x.dependencySourcesProvider)
|
case x: BuildServerCapabilities => (this.compileProvider == x.compileProvider) && (this.dependencySourcesProvider == x.dependencySourcesProvider) && (this.canReload == x.canReload)
|
||||||
case _ => false
|
case _ => false
|
||||||
}
|
}
|
||||||
override def hashCode: Int = {
|
override def hashCode: Int = {
|
||||||
37 * (37 * (37 * (17 + "sbt.internal.bsp.BuildServerCapabilities".##) + compileProvider.##) + dependencySourcesProvider.##)
|
37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.BuildServerCapabilities".##) + compileProvider.##) + dependencySourcesProvider.##) + canReload.##)
|
||||||
}
|
}
|
||||||
override def toString: String = {
|
override def toString: String = {
|
||||||
"BuildServerCapabilities(" + compileProvider + ", " + dependencySourcesProvider + ")"
|
"BuildServerCapabilities(" + compileProvider + ", " + dependencySourcesProvider + ", " + canReload + ")"
|
||||||
}
|
}
|
||||||
private[this] def copy(compileProvider: Option[sbt.internal.bsp.CompileProvider] = compileProvider, dependencySourcesProvider: Option[Boolean] = dependencySourcesProvider): BuildServerCapabilities = {
|
private[this] def copy(compileProvider: Option[sbt.internal.bsp.CompileProvider] = compileProvider, dependencySourcesProvider: Option[Boolean] = dependencySourcesProvider, canReload: Option[Boolean] = canReload): BuildServerCapabilities = {
|
||||||
new BuildServerCapabilities(compileProvider, dependencySourcesProvider)
|
new BuildServerCapabilities(compileProvider, dependencySourcesProvider, canReload)
|
||||||
}
|
}
|
||||||
def withCompileProvider(compileProvider: Option[sbt.internal.bsp.CompileProvider]): BuildServerCapabilities = {
|
def withCompileProvider(compileProvider: Option[sbt.internal.bsp.CompileProvider]): BuildServerCapabilities = {
|
||||||
copy(compileProvider = compileProvider)
|
copy(compileProvider = compileProvider)
|
||||||
|
|
@ -40,9 +42,15 @@ final class BuildServerCapabilities private (
|
||||||
def withDependencySourcesProvider(dependencySourcesProvider: Boolean): BuildServerCapabilities = {
|
def withDependencySourcesProvider(dependencySourcesProvider: Boolean): BuildServerCapabilities = {
|
||||||
copy(dependencySourcesProvider = Option(dependencySourcesProvider))
|
copy(dependencySourcesProvider = Option(dependencySourcesProvider))
|
||||||
}
|
}
|
||||||
|
def withCanReload(canReload: Option[Boolean]): BuildServerCapabilities = {
|
||||||
|
copy(canReload = canReload)
|
||||||
|
}
|
||||||
|
def withCanReload(canReload: Boolean): BuildServerCapabilities = {
|
||||||
|
copy(canReload = Option(canReload))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
object BuildServerCapabilities {
|
object BuildServerCapabilities {
|
||||||
|
|
||||||
def apply(compileProvider: Option[sbt.internal.bsp.CompileProvider], dependencySourcesProvider: Option[Boolean]): BuildServerCapabilities = new BuildServerCapabilities(compileProvider, dependencySourcesProvider)
|
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): BuildServerCapabilities = new BuildServerCapabilities(Option(compileProvider), Option(dependencySourcesProvider))
|
def apply(compileProvider: sbt.internal.bsp.CompileProvider, dependencySourcesProvider: Boolean, canReload: Boolean): BuildServerCapabilities = new BuildServerCapabilities(Option(compileProvider), Option(dependencySourcesProvider), Option(canReload))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,9 @@ implicit lazy val BuildServerCapabilitiesFormat: JsonFormat[sbt.internal.bsp.Bui
|
||||||
unbuilder.beginObject(__js)
|
unbuilder.beginObject(__js)
|
||||||
val compileProvider = unbuilder.readField[Option[sbt.internal.bsp.CompileProvider]]("compileProvider")
|
val compileProvider = unbuilder.readField[Option[sbt.internal.bsp.CompileProvider]]("compileProvider")
|
||||||
val dependencySourcesProvider = unbuilder.readField[Option[Boolean]]("dependencySourcesProvider")
|
val dependencySourcesProvider = unbuilder.readField[Option[Boolean]]("dependencySourcesProvider")
|
||||||
|
val canReload = unbuilder.readField[Option[Boolean]]("canReload")
|
||||||
unbuilder.endObject()
|
unbuilder.endObject()
|
||||||
sbt.internal.bsp.BuildServerCapabilities(compileProvider, dependencySourcesProvider)
|
sbt.internal.bsp.BuildServerCapabilities(compileProvider, dependencySourcesProvider, canReload)
|
||||||
case None =>
|
case None =>
|
||||||
deserializationError("Expected JsObject but found None")
|
deserializationError("Expected JsObject but found None")
|
||||||
}
|
}
|
||||||
|
|
@ -23,6 +24,7 @@ implicit lazy val BuildServerCapabilitiesFormat: JsonFormat[sbt.internal.bsp.Bui
|
||||||
builder.beginObject()
|
builder.beginObject()
|
||||||
builder.addField("compileProvider", obj.compileProvider)
|
builder.addField("compileProvider", obj.compileProvider)
|
||||||
builder.addField("dependencySourcesProvider", obj.dependencySourcesProvider)
|
builder.addField("dependencySourcesProvider", obj.dependencySourcesProvider)
|
||||||
|
builder.addField("canReload", obj.canReload)
|
||||||
builder.endObject()
|
builder.endObject()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -186,6 +186,9 @@ type BuildServerCapabilities {
|
||||||
# via method buildTarget/resources
|
# via method buildTarget/resources
|
||||||
# resourcesProvider: Boolean
|
# resourcesProvider: Boolean
|
||||||
|
|
||||||
|
## Reloading the workspace state through workspace/reload is supported
|
||||||
|
canReload: Boolean
|
||||||
|
|
||||||
# The server sends notifications to the client on build
|
# The server sends notifications to the client on build
|
||||||
# target change events via buildTarget/didChange
|
# target change events via buildTarget/didChange
|
||||||
# buildTargetChangedProvider: Boolean
|
# buildTargetChangedProvider: Boolean
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,17 @@ object BuildServerTest extends AbstractServerTest {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test("workspace/reload") { _ =>
|
||||||
|
svr.sendJsonRpc(
|
||||||
|
"""{ "jsonrpc": "2.0", "id": "15", "method": "workspace/reload"}"""
|
||||||
|
)
|
||||||
|
assert(svr.waitForString(10.seconds) { s =>
|
||||||
|
println(s)
|
||||||
|
(s contains """"id":"15"""") &&
|
||||||
|
(s contains """"result":null""")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
def initializeRequest(): Unit = {
|
def initializeRequest(): Unit = {
|
||||||
svr.sendJsonRpc(
|
svr.sendJsonRpc(
|
||||||
"""{ "jsonrpc": "2.0", "id": "10", "method": "build/initialize",
|
"""{ "jsonrpc": "2.0", "id": "10", "method": "build/initialize",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue