diff --git a/main/src/main/scala/sbt/internal/server/LanguageServerProtocol.scala b/main/src/main/scala/sbt/internal/server/LanguageServerProtocol.scala index 5c18b926b..ce1131d0f 100644 --- a/main/src/main/scala/sbt/internal/server/LanguageServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/LanguageServerProtocol.scala @@ -34,6 +34,15 @@ private[sbt] trait LanguageServerProtocol extends CommandChannel { protected def log: Logger protected def onSettingQuery(execId: Option[String], req: Q): Unit + protected def onNotification(notification: JsonRpcNotificationMessage): Unit = { + log.debug(s"onNotification: $notification") + notification.method match { + case "textDocument/didSave" => + append(Exec(";compile; collectAnalyses", None, Some(CommandSource(name)))) + case u => log.debug(s"Unhandled notification received: $u") + } + } + protected def onRequestMessage(request: JsonRpcRequestMessage): Unit = { import sbt.internal.langserver.codec.JsonProtocol._ import internalJsonProtocol._ @@ -57,8 +66,6 @@ private[sbt] trait LanguageServerProtocol extends CommandChannel { setInitialized(true) append(Exec(s"collectAnalyses", Some(request.id), Some(CommandSource(name)))) langRespond(InitializeResult(serverCapabilities), Option(request.id)) - case "textDocument/didSave" => - append(Exec(";compile; collectAnalyses", Some(request.id), Some(CommandSource(name)))) case "textDocument/definition" => import scala.concurrent.ExecutionContext.Implicits.global Definition.lspDefinition(json, request.id, CommandSource(name), log) diff --git a/main/src/main/scala/sbt/internal/server/NetworkChannel.scala b/main/src/main/scala/sbt/internal/server/NetworkChannel.scala index 26b489347..7c27063de 100644 --- a/main/src/main/scala/sbt/internal/server/NetworkChannel.scala +++ b/main/src/main/scala/sbt/internal/server/NetworkChannel.scala @@ -18,6 +18,7 @@ import sbt.protocol._ import sbt.internal.langserver.ErrorCodes import sbt.internal.util.{ ObjectEvent, StringEvent } import sbt.internal.util.codec.JValueFormats +import sbt.internal.protocol.{ JsonRpcRequestMessage, JsonRpcNotificationMessage } import sbt.util.Logger final class NetworkChannel(val name: String, @@ -166,8 +167,8 @@ final class NetworkChannel(val name: String, def handleBody(chunk: Vector[Byte]): Unit = { if (isLanguageServerProtocol) { - Serialization.deserializeJsonRequest(chunk) match { - case Right(req) => + Serialization.deserializeJsonMessage(chunk) match { + case Right(req: JsonRpcRequestMessage) => try { onRequestMessage(req) } catch { @@ -175,6 +176,16 @@ final class NetworkChannel(val name: String, log.debug(s"sending error: $code: $message") langError(Option(req.id), code, message) } + case Right(ntf: JsonRpcNotificationMessage) => + try { + onNotification(ntf) + } catch { + case LangServerError(code, message) => + log.debug(s"sending error: $code: $message") + langError(None, code, message) // new id? + } + case Right(msg) => + log.debug(s"Unhandled message: $msg") case Left(errorDesc) => val msg = s"Got invalid chunk from client (${new String(chunk.toArray, "UTF-8")}): " + errorDesc langError(None, ErrorCodes.ParseError, msg) diff --git a/protocol/src/main/scala/sbt/protocol/Serialization.scala b/protocol/src/main/scala/sbt/protocol/Serialization.scala index 2a6e174b4..75b9e7c83 100644 --- a/protocol/src/main/scala/sbt/protocol/Serialization.scala +++ b/protocol/src/main/scala/sbt/protocol/Serialization.scala @@ -15,6 +15,7 @@ import java.nio.ByteBuffer import scala.util.{ Success, Failure } import sbt.internal.util.StringEvent import sbt.internal.protocol.{ + JsonRpcMessage, JsonRpcRequestMessage, JsonRpcResponseMessage, JsonRpcNotificationMessage @@ -143,15 +144,20 @@ object Serialization { } } - private[sbt] def deserializeJsonRequest( - bytes: Seq[Byte]): Either[String, JsonRpcRequestMessage] = { + private[sbt] def deserializeJsonMessage(bytes: Seq[Byte]): Either[String, JsonRpcMessage] = { val buffer = ByteBuffer.wrap(bytes.toArray) Parser.parseFromByteBuffer(buffer) match { case Success(json) => import sbt.internal.protocol.codec.JsonRPCProtocol._ Converter.fromJson[JsonRpcRequestMessage](json) match { - case Success(msg) => Right(msg) - case Failure(e) => throw e + case Success(request) if (request.id.nonEmpty) => Right(request) + case Failure(e) => throw e + case _ => { + Converter.fromJson[JsonRpcNotificationMessage](json) match { + case Success(notification) => Right(notification) + case Failure(e) => throw e + } + } } case Failure(e) => Left(s"Parse error: ${e.getMessage}")