Add option to skip collectAnalysis on network init

The collectAnalysis task an be a bit slow and delays client connections
from running commands. This commit adds an option to skip the analysis
if it isn't needed. The default behavior is left as it was.
This commit is contained in:
Ethan Atkins 2020-06-22 10:58:29 -07:00
parent e53c8f6f01
commit af5afef271
9 changed files with 53 additions and 28 deletions

View File

@ -58,7 +58,7 @@ class NetworkClient(configuration: xsbti.AppConfiguration, arguments: List[Strin
}
// initiate handshake
val execId = UUID.randomUUID.toString
val initCommand = InitCommand(tkn, Option(execId))
val initCommand = InitCommand(tkn, Option(execId), Some(true))
conn.sendString(Serialization.serializeCommandAsJsonMessage(initCommand))
conn
}

View File

@ -47,21 +47,21 @@ private[sbt] object LanguageServerProtocol {
ServerIntent(
{
case r: JsonRpcRequestMessage if r.method == "initialize" =>
if (authOptions(ServerAuthentication.Token)) {
val param = Converter.fromJson[InitializeParams](json(r)).get
val optionJson = param.initializationOptions.getOrElse(
throw LangServerError(
ErrorCodes.InvalidParams,
"initializationOptions is expected on 'initialize' param."
)
val param = Converter.fromJson[InitializeParams](json(r)).get
val optionJson = param.initializationOptions.getOrElse(
throw LangServerError(
ErrorCodes.InvalidParams,
"initializationOptions is expected on 'initialize' param."
)
val opt = Converter.fromJson[InitializeOption](optionJson).get
)
val opt = Converter.fromJson[InitializeOption](optionJson).get
if (authOptions(ServerAuthentication.Token)) {
val token = opt.token.getOrElse(sys.error("'token' is missing."))
if (authenticate(token)) ()
else throw LangServerError(ErrorCodes.InvalidRequest, "invalid token")
} else ()
setInitialized(true)
appendExec("collectAnalyses", None)
if (!opt.skipAnalysis.getOrElse(false)) appendExec("collectAnalyses", None)
jsonRpcRespond(InitializeResult(serverCapabilities), Some(r.id))
case r: JsonRpcRequestMessage if r.method == "textDocument/definition" =>

View File

@ -5,22 +5,23 @@
// DO NOT EDIT MANUALLY
package sbt.internal.protocol
final class InitializeOption private (
val token: Option[String]) extends Serializable {
val token: Option[String],
val skipAnalysis: Option[Boolean]) extends Serializable {
private def this(token: Option[String]) = this(token, None)
override def equals(o: Any): Boolean = o match {
case x: InitializeOption => (this.token == x.token)
case x: InitializeOption => (this.token == x.token) && (this.skipAnalysis == x.skipAnalysis)
case _ => false
}
override def hashCode: Int = {
37 * (37 * (17 + "sbt.internal.protocol.InitializeOption".##) + token.##)
37 * (37 * (37 * (17 + "sbt.internal.protocol.InitializeOption".##) + token.##) + skipAnalysis.##)
}
override def toString: String = {
"InitializeOption(" + token + ")"
"InitializeOption(" + token + ", " + skipAnalysis + ")"
}
private[this] def copy(token: Option[String] = token): InitializeOption = {
new InitializeOption(token)
private[this] def copy(token: Option[String] = token, skipAnalysis: Option[Boolean] = skipAnalysis): InitializeOption = {
new InitializeOption(token, skipAnalysis)
}
def withToken(token: Option[String]): InitializeOption = {
copy(token = token)
@ -28,9 +29,17 @@ final class InitializeOption private (
def withToken(token: String): InitializeOption = {
copy(token = Option(token))
}
def withSkipAnalysis(skipAnalysis: Option[Boolean]): InitializeOption = {
copy(skipAnalysis = skipAnalysis)
}
def withSkipAnalysis(skipAnalysis: Boolean): InitializeOption = {
copy(skipAnalysis = Option(skipAnalysis))
}
}
object InitializeOption {
def apply(token: Option[String]): InitializeOption = new InitializeOption(token)
def apply(token: String): InitializeOption = new InitializeOption(Option(token))
def apply(token: Option[String], skipAnalysis: Option[Boolean]): InitializeOption = new InitializeOption(token, skipAnalysis)
def apply(token: String, skipAnalysis: Boolean): InitializeOption = new InitializeOption(Option(token), Option(skipAnalysis))
}

View File

@ -12,8 +12,9 @@ implicit lazy val InitializeOptionFormat: JsonFormat[sbt.internal.protocol.Initi
case Some(__js) =>
unbuilder.beginObject(__js)
val token = unbuilder.readField[Option[String]]("token")
val skipAnalysis = unbuilder.readField[Option[Boolean]]("skipAnalysis")
unbuilder.endObject()
sbt.internal.protocol.InitializeOption(token)
sbt.internal.protocol.InitializeOption(token, skipAnalysis)
case None =>
deserializationError("Expected JsObject but found None")
}
@ -21,6 +22,7 @@ implicit lazy val InitializeOptionFormat: JsonFormat[sbt.internal.protocol.Initi
override def write[J](obj: sbt.internal.protocol.InitializeOption, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("token", obj.token)
builder.addField("skipAnalysis", obj.skipAnalysis)
builder.endObject()
}
}

View File

@ -6,22 +6,23 @@
package sbt.protocol
final class InitCommand private (
val token: Option[String],
val execId: Option[String]) extends sbt.protocol.CommandMessage() with Serializable {
val execId: Option[String],
val skipAnalysis: Option[Boolean]) extends sbt.protocol.CommandMessage() with Serializable {
private def this(token: Option[String], execId: Option[String]) = this(token, execId, None)
override def equals(o: Any): Boolean = o match {
case x: InitCommand => (this.token == x.token) && (this.execId == x.execId)
case x: InitCommand => (this.token == x.token) && (this.execId == x.execId) && (this.skipAnalysis == x.skipAnalysis)
case _ => false
}
override def hashCode: Int = {
37 * (37 * (37 * (17 + "sbt.protocol.InitCommand".##) + token.##) + execId.##)
37 * (37 * (37 * (37 * (17 + "sbt.protocol.InitCommand".##) + token.##) + execId.##) + skipAnalysis.##)
}
override def toString: String = {
"InitCommand(" + token + ", " + execId + ")"
"InitCommand(" + token + ", " + execId + ", " + skipAnalysis + ")"
}
private[this] def copy(token: Option[String] = token, execId: Option[String] = execId): InitCommand = {
new InitCommand(token, execId)
private[this] def copy(token: Option[String] = token, execId: Option[String] = execId, skipAnalysis: Option[Boolean] = skipAnalysis): InitCommand = {
new InitCommand(token, execId, skipAnalysis)
}
def withToken(token: Option[String]): InitCommand = {
copy(token = token)
@ -35,9 +36,17 @@ final class InitCommand private (
def withExecId(execId: String): InitCommand = {
copy(execId = Option(execId))
}
def withSkipAnalysis(skipAnalysis: Option[Boolean]): InitCommand = {
copy(skipAnalysis = skipAnalysis)
}
def withSkipAnalysis(skipAnalysis: Boolean): InitCommand = {
copy(skipAnalysis = Option(skipAnalysis))
}
}
object InitCommand {
def apply(token: Option[String], execId: Option[String]): InitCommand = new InitCommand(token, execId)
def apply(token: String, execId: String): InitCommand = new InitCommand(Option(token), Option(execId))
def apply(token: Option[String], execId: Option[String], skipAnalysis: Option[Boolean]): InitCommand = new InitCommand(token, execId, skipAnalysis)
def apply(token: String, execId: String, skipAnalysis: Boolean): InitCommand = new InitCommand(Option(token), Option(execId), Option(skipAnalysis))
}

View File

@ -13,8 +13,9 @@ implicit lazy val InitCommandFormat: JsonFormat[sbt.protocol.InitCommand] = new
unbuilder.beginObject(__js)
val token = unbuilder.readField[Option[String]]("token")
val execId = unbuilder.readField[Option[String]]("execId")
val skipAnalysis = unbuilder.readField[Option[Boolean]]("skipAnalysis")
unbuilder.endObject()
sbt.protocol.InitCommand(token, execId)
sbt.protocol.InitCommand(token, execId, skipAnalysis)
case None =>
deserializationError("Expected JsObject but found None")
}
@ -23,6 +24,7 @@ implicit lazy val InitCommandFormat: JsonFormat[sbt.protocol.InitCommand] = new
builder.beginObject()
builder.addField("token", obj.token)
builder.addField("execId", obj.execId)
builder.addField("skipAnalysis", obj.skipAnalysis)
builder.endObject()
}
}

View File

@ -18,4 +18,5 @@ type TokenFile {
type InitializeOption {
token: String
skipAnalysis: Boolean @since("1.4.0")
}

View File

@ -10,6 +10,7 @@ interface CommandMessage {
type InitCommand implements CommandMessage {
token: String
execId: String
skipAnalysis: Boolean @since("1.4.0")
}
## Command to execute sbt command.

View File

@ -44,12 +44,13 @@ object Serialization {
command match {
case x: InitCommand =>
val execId = x.execId.getOrElse(UUID.randomUUID.toString)
val analysis = s""""skipAnalysis" : ${x.skipAnalysis.getOrElse(false)}"""
val opt = x.token match {
case Some(t) =>
val json: JValue = Converter.toJson[String](t).get
val v = CompactPrinter(json)
s"""{ "token": $v }"""
case None => "{}"
s"""{ "token": $v, $analysis }"""
case None => s"{ $analysis }"
}
s"""{ "jsonrpc": "2.0", "id": "$execId", "method": "initialize", "params": { "initializationOptions": $opt } }"""
case x: ExecCommand =>