diff --git a/build.sbt b/build.sbt index ada3efc42b5..115c47d8324 100644 --- a/build.sbt +++ b/build.sbt @@ -485,9 +485,9 @@ lazy val gateway = (project in file("engine/gateway")) .dependsOn(language_server) .settings( libraryDependencies ++= akka ++ circe ++ Seq( - akkaTestkit % Test, "io.circe" %% "circe-generic-extras" % "0.12.2", "io.circe" %% "circe-literal" % circeVersion, + akkaTestkit % Test, "org.scalatest" %% "scalatest" % "3.2.0-SNAP10" % Test, "org.scalacheck" %% "scalacheck" % "1.14.0" % Test ) @@ -496,7 +496,10 @@ lazy val gateway = (project in file("engine/gateway")) lazy val language_server = (project in file("engine/language-server")) .settings( libraryDependencies ++= akka ++ Seq( - "org.graalvm.sdk" % "polyglot-tck" % graalVersion % Provided + "org.graalvm.sdk" % "polyglot-tck" % graalVersion % Provided, + akkaTestkit % Test, + "org.scalatest" %% "scalatest" % "3.2.0-SNAP10" % Test, + "org.scalacheck" %% "scalacheck" % "1.14.0" % Test ) ) .dependsOn(polyglot_api) diff --git a/engine/gateway/src/main/resources/application.conf b/engine/gateway/src/main/resources/application.conf index 9a7f26cd360..2f53d86b256 100644 --- a/engine/gateway/src/main/resources/application.conf +++ b/engine/gateway/src/main/resources/application.conf @@ -3,7 +3,9 @@ gateway { host = "localhost" port = 30000 route = "" - timeout = 5 + timeoutSecs = 5 + bindingTimeoutSecs = 5 + hardDeadlineSecs = 5 } languageServer { diff --git a/engine/gateway/src/main/scala/org/enso/Gateway.scala b/engine/gateway/src/main/scala/org/enso/Gateway.scala index 8e8e30a5f07..8cbe9b04093 100644 --- a/engine/gateway/src/main/scala/org/enso/Gateway.scala +++ b/engine/gateway/src/main/scala/org/enso/Gateway.scala @@ -2,46 +2,82 @@ package org.enso import akka.actor.{Actor, ActorLogging, ActorRef, Props} import com.typesafe.config.ConfigFactory -import org.enso.gateway.protocol.response.Result.InitializeResult +import org.enso.gateway.protocol.response.Result.{InitializeResult, NullResult} import org.enso.gateway.protocol.{Id, Notifications, Requests, Response} import org.enso.gateway.protocol.response.result.{ ServerCapabilities, ServerInfo } +import org.enso.languageserver.{ + NotificationReceived, + RequestReceived, + Notifications => LsNotifications, + Requests => LsRequests +} -/** The gateway component talks directly to clients using protocol messages, - * and then handles these messages by talking to the language server. +/** The Gateway component of Enso Engine. + * + * Talks directly to clients using protocol messages, and then handles these + * messages by talking to the language server. * * @param languageServer [[ActorRef]] of [[LanguageServer]] actor. */ class Gateway(languageServer: ActorRef) extends Actor with ActorLogging { override def receive: Receive = { - case Requests.Initialize(Id.Number(id), _) => + case Requests.Initialize(id, _) => val msg = "Gateway: Initialize received" log.info(msg) - languageServer ! LanguageServer.Initialize(id, sender()) + languageServer ! LsRequests.Initialize( + id.toLsModel, + sender() + ) - case LanguageServer.InitializeReceived(id, replyTo) => - val msg = "Gateway: InitializeReceived received" + case RequestReceived.Initialize(id, replyTo) => + val msg = "Gateway: RequestReceived.Initialize received" log.info(msg) replyTo ! Response.result( - id = Some(Id.Number(id)), - result = InitializeResult(ServerCapabilities(), Some(serverInfo)) + id = Some(Id.fromLsModel(id)), + result = InitializeResult( + capabilities = ServerCapabilities(), + serverInfo = Some(serverInfo) + ) + ) + + case Requests.Shutdown(id, _) => + val msg = "Gateway: Shutdown received" + log.info(msg) + languageServer ! LsRequests.Shutdown(id.toLsModel, sender()) + + case RequestReceived.Shutdown(id, replyTo) => + val msg = "Gateway: RequestReceived.Shutdown received" + log.info(msg) + replyTo ! Response.result( + id = Some(Id.fromLsModel(id)), + result = NullResult ) case Notifications.Initialized(_) => val msg = "Gateway: Initialized received" log.info(msg) - languageServer ! LanguageServer.Initialized + languageServer ! LsNotifications.Initialized - case LanguageServer.InitializedReceived => - val msg = "Gateway: InitializedReceived received" + case NotificationReceived.Initialized => + val msg = "Gateway: NotificationReceived.Initialized received" + log.info(msg) + + case Notifications.Exit(_) => + val msg = "Gateway: Exit received" + log.info(msg) + languageServer ! LsNotifications.Exit + + case NotificationReceived.Exit => + val msg = "Gateway: NotificationReceived.Exit received" log.info(msg) case requestOrNotification => - val err = - s"unimplemented request or notification: $requestOrNotification" - throw new Exception(err) + val err = "Gateway: unimplemented request or notification: " + + requestOrNotification + log.error(err) } private val serverInfo: ServerInfo = { @@ -51,8 +87,10 @@ class Gateway(languageServer: ActorRef) extends Actor with ActorLogging { val languageServerVersionPath = "version" val gatewayConfig = ConfigFactory.load.getConfig(gatewayPath) val languageServerConfig = gatewayConfig.getConfig(languageServerPath) - val name = languageServerConfig.getString(languageServerNamePath) - val version = languageServerConfig.getString(languageServerVersionPath) + val name = + languageServerConfig.getString(languageServerNamePath) + val version = + languageServerConfig.getString(languageServerVersionPath) ServerInfo(name, Some(version)) } } diff --git a/engine/gateway/src/main/scala/org/enso/gateway/JsonRpcController.scala b/engine/gateway/src/main/scala/org/enso/gateway/JsonRpcController.scala index ddcfe364af0..431feb8ff09 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/JsonRpcController.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/JsonRpcController.scala @@ -23,6 +23,7 @@ import scala.concurrent.Future object JsonRpcController { /** A string specifying the version of the JSON-RPC protocol. + * * Must be exactly "2.0". * * @see LSP Spec: @@ -33,6 +34,7 @@ object JsonRpcController { } /** Helper for implementing protocol over text-based transport. + * * Requests and responses are marshaled as text using JSON-RPC. * It handles and decodes all JSON-RPC messages and dispatch them to the * Gateway. @@ -40,10 +42,9 @@ object JsonRpcController { * @param gateway [[ActorRef]] of Gateway actor. */ class JsonRpcController(gateway: ActorRef)(implicit system: ActorSystem) { - import system.dispatcher - /** Generate text reply for given request text message, no reply for + /** Generates text reply for given request text message, no reply for * notification. */ def getTextOutput( diff --git a/engine/gateway/src/main/scala/org/enso/gateway/Server.scala b/engine/gateway/src/main/scala/org/enso/gateway/Server.scala index 6e74547e508..0b84b4bc9a6 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/Server.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/Server.scala @@ -4,9 +4,7 @@ import akka.NotUsed import akka.actor.ActorSystem import akka.event.{Logging, LoggingAdapter} import akka.http.scaladsl.Http -import akka.http.scaladsl.model.ws.BinaryMessage -import akka.http.scaladsl.model.ws.Message -import akka.http.scaladsl.model.ws.TextMessage +import akka.http.scaladsl.model.ws.{BinaryMessage, Message, TextMessage} import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.server.Route import akka.stream.ActorMaterializer @@ -14,54 +12,16 @@ import akka.stream.scaladsl.Flow import akka.stream.scaladsl.Sink import akka.stream.scaladsl.Source import akka.util.Timeout -import com.typesafe.config.{Config, ConfigFactory} +import org.enso.gateway.server.Config -import scala.concurrent.duration._ +import scala.concurrent.{Await, Future} import scala.util.Failure import scala.util.Success -object Server { - - /** Describes endpoint to which [[Server]] can bind (host, port, route) and - * timeout for waiting response. - * - * Gets parameters from typesafe config. - */ - object Config { - private val gatewayPath = "gateway" - private val serverPath = "server" - private val hostPath = "host" - private val portPath = "port" - private val routePath = "route" - private val timeoutPath = "timeout" - private val gatewayConfig: Config = - ConfigFactory.load.getConfig(gatewayPath) - private val serverConfig: Config = gatewayConfig.getConfig(serverPath) - - /** Host of endpoint. */ - val host: String = serverConfig.getString(hostPath) - - /** Port of endpoint. */ - val port: Int = serverConfig.getInt(portPath) - - /** Route of endpoint. */ - val route: String = serverConfig.getString(routePath) - - /** Timeout for waiting response after request. */ - implicit val timeout: Timeout = Timeout( - serverConfig.getLong(timeoutPath).seconds - ) - - /** Creates address string. */ - val addressString: String = s"ws://$host:$port" - } -} - /** WebSocket server supporting synchronous request-response protocol. * * Server when run binds to endpoint and accepts establishing web socket * connection for any number of peers. - * * Server replies to each incoming text request with a single text response, * no response for notifications. * Server accepts a single Text Message from a peer and responds with another @@ -69,17 +29,17 @@ object Server { * * @param jsonRpcController Encapsulates encoding JSONs and talking to * [[org.enso.Gateway]]. + * @param config Server config. */ -class Server(jsonRpcController: JsonRpcController)( +class Server(jsonRpcController: JsonRpcController, config: Config)( implicit system: ActorSystem, materializer: ActorMaterializer ) { - import system.dispatcher - import Server.Config.timeout - private val log: LoggingAdapter = Logging.getLogger(system, this) + implicit private val timeout: Timeout = Timeout(config.timeout) + private val log: LoggingAdapter = Logging.getLogger(system, this) /** Akka stream defining server behavior. * @@ -88,7 +48,7 @@ class Server(jsonRpcController: JsonRpcController)( * @see [[JsonRpcController.getTextOutput]]. * Incoming binary messages are ignored. */ - val handlerFlow: Flow[Message, TextMessage.Strict, NotUsed] = + private val handlerFlow: Flow[Message, TextMessage.Strict, NotUsed] = Flow[Message] .flatMapConcat { case tm: TextMessage => @@ -117,31 +77,31 @@ class Server(jsonRpcController: JsonRpcController)( * * The request's URI is not checked. */ - val route: Route = - path(Server.Config.route) { + private val route: Route = + path(config.route) { get { handleWebSocketMessages(handlerFlow) } } + private val bindingFuture: Future[Http.ServerBinding] = + Http().bindAndHandle( + handler = route, + interface = config.host, + port = config.port + ) + /** Starts a HTTP server listening at the given endpoint. * * Function is asynchronous, will return immediately. If the server fails to * start, function will exit the process with a non-zero code. */ def run(): Unit = { - val bindingFuture = - Http().bindAndHandle( - handler = route, - interface = Server.Config.host, - port = Server.Config.port - ) - bindingFuture .onComplete { case Success(_) => val serverOnlineMessage = - s"Server online at ${Server.Config.addressString}" + s"Server online at ${config.addressString}" val shutDownMessage = "Press ENTER to shut down" Seq( serverOnlineMessage, @@ -154,4 +114,11 @@ class Server(jsonRpcController: JsonRpcController)( System.exit(1) } } + + /** Stops the HTTP server gracefully. */ + def shutdown(): Future[Http.HttpTerminated] = { + Await + .result(bindingFuture, config.bindingTimeout) + .terminate(hardDeadline = config.hardDeadline) + } } diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/CodeActionKind.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/CodeActionKind.scala new file mode 100644 index 00000000000..cd8991ff5a0 --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/CodeActionKind.scala @@ -0,0 +1,65 @@ +package org.enso.gateway.protocol + +import io.circe.{Decoder, Encoder} + +/** Kind of + * [[org.enso.gateway.protocol.request.clientcapabilities.textdocument.CodeAction]]. + * + * Used also in + * [[org.enso.gateway.protocol.response.result.servercapabilities.CodeActionProvider]]. + */ +sealed abstract class CodeActionKind(val value: String) +object CodeActionKind { + private val empty = "" + private val quickfix = "quickfix" + private val refactor = "refactor" + private val refactorExtract = "refactor.extract" + private val refactorInline = "refactor.inline" + private val refactorRewrite = "refactor.rewrite" + private val source = "source" + private val sourceOrganizeImports = "source.organizeImports" + private val invalidCodeActionKind = "Invalid CodeActionKind" + + /** Empty kind. */ + case object Empty extends CodeActionKind(empty) + + /** Base kind for quickfix actions. */ + case object QuickFix extends CodeActionKind(quickfix) + + /** Base kind for refactoring actions. */ + case object Refactor extends CodeActionKind(refactor) + + /** Base kind for refactoring extraction actions. */ + case object RefactorExtract extends CodeActionKind(refactorExtract) + + /** Base kind for refactoring inline actions. */ + case object RefactorInline extends CodeActionKind(refactorInline) + + /** Base kind for refactoring rewrite actions. */ + case object RefactorRewrite extends CodeActionKind(refactorRewrite) + + /** Base kind for source actions. Source code actions apply to the entire + * file. + */ + case object Source extends CodeActionKind(source) + + /** Base kind for an organize imports source action. */ + case object SourceOrganizeImports + extends CodeActionKind(sourceOrganizeImports) + + implicit val codeActionKindDecoder: Decoder[CodeActionKind] = + Decoder.decodeString.emap { + case `empty` => Right(Empty) + case `quickfix` => Right(QuickFix) + case `refactor` => Right(Refactor) + case `refactorExtract` => Right(RefactorExtract) + case `refactorInline` => Right(RefactorInline) + case `refactorRewrite` => Right(RefactorRewrite) + case `source` => Right(Source) + case `sourceOrganizeImports` => Right(SourceOrganizeImports) + case _ => Left(invalidCodeActionKind) + } + + implicit val codeActionKindEncoder: Encoder[CodeActionKind] = + Encoder.encodeString.contramap(_.value) +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/Id.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/Id.scala index 4dcdf1aeabe..7eafb4a82b6 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/Id.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/Id.scala @@ -7,10 +7,21 @@ import io.circe.generic.extras.semiauto.{ } import cats.syntax.functor._ import io.circe.syntax._ +import org.enso.languageserver /** Id of [[RequestOrNotification]] or [[Response]]. */ -sealed trait Id +sealed trait Id { + def toLsModel: languageserver.Id = this match { + case Id.Number(value) => languageserver.Id.Number(value) + case Id.Text(value) => languageserver.Id.Text(value) + } +} object Id { + def fromLsModel(id: languageserver.Id): Id = id match { + case languageserver.Id.Number(value) => Id.Number(value) + case languageserver.Id.Text(value) => Id.Text(value) + } + implicit val idEncoder: Encoder[Id] = Encoder.instance { case number: Number => number.asJson case text: Text => text.asJson diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/NotificationDecoder.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/NotificationDecoder.scala index ba394dd54be..9ea787b2490 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/NotificationDecoder.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/NotificationDecoder.scala @@ -3,15 +3,12 @@ package org.enso.gateway.protocol import io.circe.{ACursor, Decoder, DecodingFailure} import org.enso.gateway.JsonRpcController.jsonRpcVersion import org.enso.gateway.protocol.request.Params -import org.enso.gateway.protocol.request.Params.{ - InitializeParams, - InitializedParams -} +import org.enso.gateway.protocol.request.Params.{InitializeParams, VoidParams} /** Helper object for decoding [[Notification]]. */ object NotificationDecoder { - /** Make Circe decoder for notifications and notification fields of requests. + /** Makes Circe decoder for notifications and notification fields of requests. * * @tparam P Subtype of [[Params]] for a notification with specific method. * @return the Circe decoder. @@ -38,9 +35,11 @@ object NotificationDecoder { (method match { case Requests.Initialize.method => Decoder[Option[InitializeParams]] + case Requests.Shutdown.method => + Decoder[Option[VoidParams]] - case Notifications.Initialized.method => - Decoder[Option[InitializedParams]] + case Notifications.Initialized.method | Notifications.Exit.method => + Decoder[Option[VoidParams]] case m => Decoder.failed( diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/Notifications.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/Notifications.scala index dfa1115f537..e8367900d01 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/Notifications.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/Notifications.scala @@ -1,12 +1,13 @@ package org.enso.gateway.protocol import org.enso.gateway.protocol.request.Params +import org.enso.gateway.protocol.request.Params.VoidParams -/** Parent trait for notifications extractor objects. */ -sealed trait Notifications { +/** Parent class for notification extractor objects. */ +sealed abstract class NotificationExtractor[T <: Params]( val method: String - - def unapply[T <: Params]( +) { + def unapply( request: Notification[T] ): Option[Option[T]] = request.method match { @@ -19,10 +20,20 @@ sealed trait Notifications { /** All notifications. */ object Notifications { - /** LSP Spec: + /** Sent from the client to the server after the client received the result of + * the initialize request but before the client is sending any other request + * or notification to the server. + * + * LSP Spec: * https://microsoft.github.io/language-server-protocol/specifications/specification-3-15/#initialized */ - object Initialized extends Notifications { - override val method = "initialized" - } + object Initialized extends NotificationExtractor[VoidParams]("initialized") + + /** Asks the server to exit its process. + * + * LSP Spec: + * https://microsoft.github.io/language-server-protocol/specifications/specification-3-15/#exit + */ + object Exit extends NotificationExtractor[VoidParams]("exit") + } diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/RequestDecoder.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/RequestDecoder.scala index fbfdb265d54..2441b06da0f 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/RequestDecoder.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/RequestDecoder.scala @@ -3,12 +3,10 @@ package org.enso.gateway.protocol import io.circe.Decoder import org.enso.gateway.protocol.request.Params -/** - * Helper object for decoding [[Request]]. - */ +/** Helper object for decoding [[Request]]. */ object RequestDecoder { - /** Make Circe decoder for requests. + /** Makes Circe decoder for requests. * * @tparam P Subtype of [[Params]] for a request with specific method. * @return The decoder. diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/RequestOrNotification.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/RequestOrNotification.scala index fda17778536..d9f80c345b8 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/RequestOrNotification.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/RequestOrNotification.scala @@ -3,9 +3,7 @@ package org.enso.gateway.protocol import io.circe.Decoder import org.enso.gateway.protocol.request.Params -/** - * Parent trait for [[Request]] and [[Notification]] - */ +/** Parent trait for [[Request]] and [[Notification]]. */ sealed trait RequestOrNotification { /** JSON-RPC Version. @@ -22,7 +20,8 @@ object RequestOrNotification { RequestOrNotificationDecoder.instance } -/** `RequestMessage` in LSP Spec: +/** `RequestMessage` in LSP Spec. + * * https://microsoft.github.io/language-server-protocol/specifications/specification-3-15/#requestMessage * * @param jsonrpc JSON-RPC Version @@ -38,20 +37,18 @@ case class Request[P <: Params]( method: String, params: Option[P] ) extends RequestOrNotification - object Request { - - /** Field `id`. */ val idField = "id" implicit def requestDecoder[T <: Params]: Decoder[Request[T]] = RequestDecoder.instance } -/** `NotificationMessage` in LSP Spec: - * https://microsoft.github.io/language-server-protocol/specifications/specification-3-15/#notificationMessage +/** `NotificationMessage` in LSP Spec. + * * A processed notification message must not send a response back (they work * like events). Therefore no `id`. + * https://microsoft.github.io/language-server-protocol/specifications/specification-3-15/#notificationMessage * * @param jsonrpc JSON-RPC Version. * @param method The JSON-RPC method to be invoked. @@ -66,15 +63,9 @@ case class Notification[P <: Params]( params: Option[P] ) extends RequestOrNotification object Notification { - - /** Field `jsonrpc` to be validated. */ val jsonrpcField = "jsonrpc" - - /** Field `method`, which is discriminator. */ - val methodField = "method" - - /** Field `params`. */ - val paramsField = "params" + val methodField = "method" + val paramsField = "params" implicit def notificationDecoder[P <: Params]: Decoder[Notification[P]] = NotificationDecoder.instance diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/RequestOrNotificationDecoder.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/RequestOrNotificationDecoder.scala index 4223f3e03cd..cbd630145e9 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/RequestOrNotificationDecoder.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/RequestOrNotificationDecoder.scala @@ -2,10 +2,7 @@ package org.enso.gateway.protocol import io.circe.CursorOp.DownField import io.circe.{Decoder, DecodingFailure} -import org.enso.gateway.protocol.request.Params.{ - InitializeParams, - InitializedParams -} +import org.enso.gateway.protocol.request.Params.{InitializeParams, VoidParams} /** Helper object for decoding [[RequestOrNotification]]. */ object RequestOrNotificationDecoder { @@ -19,7 +16,7 @@ object RequestOrNotificationDecoder { .flatMap(selectRequestOrNotificationDecoder(_).apply(cursor)) } - /** Make Circe failure if method is unknown. + /** Makes Circe failure if method is unknown. * * @param method Name of method. * @return The failure. @@ -36,9 +33,11 @@ object RequestOrNotificationDecoder { method match { case Requests.Initialize.method => Decoder[Request[InitializeParams]] + case Requests.Shutdown.method => + Decoder[Request[VoidParams]] - case Notifications.Initialized.method => - Decoder[Notification[InitializedParams]] + case Notifications.Initialized.method | Notifications.Exit.method => + Decoder[Notification[VoidParams]] case m => Decoder.failed( diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/Requests.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/Requests.scala index 0e4ef0c260f..18b392a6884 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/Requests.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/Requests.scala @@ -1,14 +1,16 @@ package org.enso.gateway.protocol import org.enso.gateway.protocol.request.Params +import org.enso.gateway.protocol.request.Params.{InitializeParams, VoidParams} -/** Parent trait for requests extractor objects. */ -sealed trait Requests { +/** Parent trait for request (Scala) extractor objects. + * + * Simplifies matching in [[org.enso.Gateway.receive()]]. + */ +sealed abstract class RequestExtractor[T <: Params]( val method: String - - def unapply[T <: Params]( - request: Request[T] - ): Option[(Id, Option[T])] = +) { + def unapply(request: Request[T]): Option[(Id, Option[T])] = request.method match { case `method` => Some((request.id, request.params)) @@ -19,11 +21,19 @@ sealed trait Requests { /** All requests. */ object Requests { - /** LSP Spec: + /** The request sent as the first request from the client to the server. + * + * LSP Spec: * https://microsoft.github.io/language-server-protocol/specifications/specification-3-15/#initialize */ - object Initialize extends Requests { - override val method = "initialize" - } + object Initialize extends RequestExtractor[InitializeParams]("initialize") + + /** Asks the server to shut down, but to not exit (otherwise the response + * might not be delivered correctly to the client). + * + * LSP Spec: + * https://microsoft.github.io/language-server-protocol/specifications/specification-3-15/#shutdown + */ + object Shutdown extends RequestExtractor[VoidParams]("shutdown") } diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/Response.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/Response.scala index 19b61d42d52..33190c49ec0 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/Response.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/Response.scala @@ -5,7 +5,8 @@ import io.circe.generic.semiauto.deriveEncoder import org.enso.gateway.JsonRpcController.jsonRpcVersion import org.enso.gateway.protocol.response.{ResponseError, Result} -/** `ResponseMessage` in LSP Spec: +/** `ResponseMessage` in LSP Spec. + * * https://microsoft.github.io/language-server-protocol/specifications/specification-3-15/#responseMessage * * @param jsonrpc JSON-RPC Version. @@ -20,10 +21,9 @@ case class Response private ( result: Option[Result], error: Option[ResponseError] ) - object Response { - /** Create response with a result. + /** Creates response with a result. * * @param id Id of request. * @param result [[Result]] of response. @@ -35,7 +35,7 @@ object Response { ): Response = Response(jsonRpcVersion, id, Some(result), None) - /** Create response with an error. + /** Creates response with an error. * * @param id Id of request. * @param error [[ResponseError]] of response. diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/Param.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/Param.scala index 8e9406c6588..694b689adf9 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/Param.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/Param.scala @@ -7,6 +7,7 @@ import io.circe.generic.extras.semiauto.{ } import io.circe.generic.semiauto.deriveDecoder import cats.syntax.functor._ +import org.enso.gateway.protocol.request.Params.DocumentUri /** An element of [[Params.Array]]. */ sealed trait Param @@ -53,7 +54,7 @@ object Param { * * @see [[org.enso.gateway.protocol.request.Params.InitializeParams]]. */ - case class InitializationOptions(value: Text) extends Param + case class InitializationOptions(value: String) extends Param object InitializationOptions { implicit val initializationOptionsDecoder: Decoder[InitializationOptions] = deriveUnwrappedDecoder @@ -64,17 +65,18 @@ object Param { * @see [[org.enso.gateway.protocol.request.Params.InitializeParams]]. */ case class ClientInfo( - name: Text, - version: Option[Text] + name: String, + version: Option[String] ) extends Param object ClientInfo { implicit val clientInfoDecoder: Decoder[ClientInfo] = deriveDecoder } /** A param of the request [[org.enso.gateway.protocol.Requests.Initialize]]. + * + * The initial trace setting. * * @see [[org.enso.gateway.protocol.request.Params.InitializeParams]]. - * The initial trace setting. */ sealed trait Trace extends Param object Trace { @@ -91,26 +93,22 @@ object Param { * * @see [[org.enso.gateway.protocol.request.Params.InitializeParams]]. */ - sealed trait WorkspaceFolder extends Param + case class WorkspaceFolder( + uri: DocumentUri, + name: String + ) extends Param object WorkspaceFolder { implicit val workspaceFolderDecoder: Decoder[WorkspaceFolder] = - List[Decoder[WorkspaceFolder]]( - Decoder[WorkspaceFolderImpl].widen - ).reduceLeft(_ or _) - - case class WorkspaceFolderImpl() extends WorkspaceFolder - object WorkspaceFolderImpl { - implicit val workspaceFolderImplDecoder: Decoder[WorkspaceFolderImpl] = - deriveDecoder - } + deriveDecoder } /** A param of the request [[org.enso.gateway.protocol.Requests.Initialize]]. + * + * The capabilities provided by the client (editor or tool). + * Define capabilities for dynamic registration, workspace and text document + * features the client supports. * * @see [[org.enso.gateway.protocol.request.Params.InitializeParams]]. - * The capabilities provided by the client (editor or tool). - * Define capabilities for dynamic registration, workspace and text document - * features the client supports. */ case class ClientCapabilities( workspace: Option[clientcapabilities.Workspace] = None, diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/Params.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/Params.scala index 72c07a38684..8ee26c4d0ec 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/Params.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/Params.scala @@ -18,15 +18,33 @@ import org.enso.gateway.protocol.request.Param.{ sealed trait Params object Params { implicit val paramsDecoder: Decoder[Params] = List[Decoder[Params]]( - Decoder[InitializeParams].widen, - Decoder[InitializedParams].widen, - Decoder[Array].widen + Decoder[Array].widen, + Decoder[VoidParams].widen, + Decoder[InitializeParams].widen ).reduceLeft(_ or _) type DocumentUri = String - /** Params of the request - * [[org.enso.gateway.protocol.Requests.Initialize]]. + /** Array params. */ + case class Array(value: Seq[Option[Param]]) extends Params + object Array { + implicit val paramsArrayDecoder: Decoder[Array] = + deriveUnwrappedDecoder + } + + /** Void params. + * + * Params of [[org.enso.gateway.protocol.Requests.Shutdown]], + * [[org.enso.gateway.protocol.Notifications.Initialized]], + * [[org.enso.gateway.protocol.Notifications.Exit]]. + */ + case class VoidParams() extends Params + object VoidParams { + implicit val voidParamsDecoder: Decoder[VoidParams] = + deriveDecoder + } + + /** Params of the request [[org.enso.gateway.protocol.Requests.Initialize]]. */ case class InitializeParams( processId: Option[Int] = None, @@ -39,32 +57,14 @@ object Params { trace: Option[Trace] = None, workspaceFolders: Option[Seq[WorkspaceFolder]] = None ) extends Params - object InitializeParams { implicit val initializeParamsDecoder: Decoder[InitializeParams] = deriveDecoder } /* Note [rootPath deprecated] - * ~~~~~~~~~~~~~~~~~~~~~~~~~~ - * `rootPath` is deprecated: use `rootUri`, LSP Spec. - */ + * ~~~~~~~~~~~~~~~~~~~~~~~~~~ + * `rootPath` is deprecated: use `rootUri`, LSP Spec. + */ - /** Params of the notification - * [[org.enso.gateway.protocol.Notifications.Initialized]]. - */ - case class InitializedParams() extends Params - - object InitializedParams { - implicit val initializedParamsDecoder: Decoder[InitializedParams] = - deriveDecoder - } - - /** Array params. */ - case class Array(value: Seq[Option[Param]]) extends Params - - object Array { - implicit val paramsArrayDecoder: Decoder[Array] = - deriveUnwrappedDecoder - } } diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/Experimental.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/Experimental.scala index 26ae9dee368..50bdf31d114 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/Experimental.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/Experimental.scala @@ -3,7 +3,7 @@ package org.enso.gateway.protocol.request.clientcapabilities import io.circe.Decoder import io.circe.generic.extras.semiauto.deriveUnwrappedDecoder -/** Define capabilities for experimental features the client supports. */ +/** Defines capabilities for experimental features the client supports. */ case class Experimental(value: String) extends AnyVal object Experimental { implicit val clientCapabilitiesExperimentalDecoder: Decoder[Experimental] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/TextDocument.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/TextDocument.scala index 386600a62b4..0febd27bfc2 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/TextDocument.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/TextDocument.scala @@ -26,7 +26,7 @@ import org.enso.gateway.protocol.request.clientcapabilities.textdocument.{ TypeDefinition } -/** Define capabilities for text document features the client supports. */ +/** Defines capabilities for text document features the client supports. */ case class TextDocument( synchronization: Option[Sync] = None, completion: Option[Completion] = None, diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/Workspace.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/Workspace.scala index 270e72ad08f..09a9a14c9a1 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/Workspace.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/Workspace.scala @@ -10,7 +10,7 @@ import org.enso.gateway.protocol.request.clientcapabilities.workspace.{ WorkspaceSymbol } -/** Define capabilities for workspace features the client supports. +/** Defines capabilities for workspace features the client supports. * * @param applyEdit The client supports applying batch edits to * the workspace by supporting the request diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/common/SymbolKind.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/common/SymbolKind.scala new file mode 100644 index 00000000000..9c83066ac3b --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/common/SymbolKind.scala @@ -0,0 +1,118 @@ +package org.enso.gateway.protocol.request.clientcapabilities.common + +import io.circe.Decoder + +/** A symbol kind. */ +sealed abstract class SymbolKind(value: Int) +object SymbolKind { + private val file = 1 + private val module = 2 + private val namespace = 3 + private val packageKind = 4 + private val classKind = 5 + private val method = 6 + private val property = 7 + private val field = 8 + private val constructor = 9 + private val enum = 10 + private val interface = 11 + private val function = 12 + private val variable = 13 + private val constant = 14 + private val string = 15 + private val number = 16 + private val boolean = 17 + private val array = 18 + private val objectKind = 19 + private val key = 20 + private val nullKind = 21 + private val enumMember = 22 + private val struct = 23 + private val event = 24 + private val operator = 25 + private val typeParameter = 26 + private val invalidSymbolKind = "Invalid SymbolKind" + + case object File extends SymbolKind(file) + + case object Module extends SymbolKind(module) + + case object Namespace extends SymbolKind(namespace) + + case object Package extends SymbolKind(packageKind) + + case object Class extends SymbolKind(classKind) + + case object Method extends SymbolKind(method) + + case object Property extends SymbolKind(property) + + case object Field extends SymbolKind(field) + + case object Constructor extends SymbolKind(constructor) + + case object Enum extends SymbolKind(enum) + + case object Interface extends SymbolKind(interface) + + case object Function extends SymbolKind(function) + + case object Variable extends SymbolKind(variable) + + case object Constant extends SymbolKind(constant) + + case object StringKind extends SymbolKind(string) + + case object Number extends SymbolKind(number) + + case object BooleanKind extends SymbolKind(boolean) + + case object ArrayKind extends SymbolKind(array) + + case object ObjectKind extends SymbolKind(objectKind) + + case object Key extends SymbolKind(key) + + case object NullKind extends SymbolKind(nullKind) + + case object EnumMember extends SymbolKind(enumMember) + + case object Struct extends SymbolKind(struct) + + case object Event extends SymbolKind(event) + + case object Operator extends SymbolKind(operator) + + case object TypeParameter extends SymbolKind(typeParameter) + + implicit val SymbolKindDecoder: Decoder[SymbolKind] = + Decoder.decodeInt.emap { + case `file` => Right(File) + case `module` => Right(Module) + case `namespace` => Right(Namespace) + case `packageKind` => Right(Package) + case `classKind` => Right(Class) + case `method` => Right(Method) + case `property` => Right(Property) + case `field` => Right(Field) + case `constructor` => Right(Constructor) + case `enum` => Right(Enum) + case `interface` => Right(Interface) + case `function` => Right(Function) + case `variable` => Right(Variable) + case `constant` => Right(Constant) + case `string` => Right(StringKind) + case `number` => Right(Number) + case `boolean` => Right(BooleanKind) + case `array` => Right(ArrayKind) + case `objectKind` => Right(ObjectKind) + case `key` => Right(Key) + case `nullKind` => Right(NullKind) + case `enumMember` => Right(EnumMember) + case `struct` => Right(Struct) + case `event` => Right(Event) + case `operator` => Right(Operator) + case `typeParameter` => Right(TypeParameter) + case _ => Left(invalidSymbolKind) + } +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/common/SymbolKinds.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/common/SymbolKinds.scala new file mode 100644 index 00000000000..0e93a9aa442 --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/common/SymbolKinds.scala @@ -0,0 +1,13 @@ +package org.enso.gateway.protocol.request.clientcapabilities.common + +import io.circe.Decoder +import io.circe.generic.semiauto.deriveDecoder + +/** Part of + * [[org.enso.gateway.protocol.request.clientcapabilities.workspace.WorkspaceSymbol]]. + */ +case class SymbolKinds(valueSet: Option[Seq[SymbolKind]]) extends AnyVal +object SymbolKinds { + implicit val symbolKindsDecoder: Decoder[SymbolKinds] = + deriveDecoder +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/CodeAction.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/CodeAction.scala index 0ee17fb6cad..73ec23bd125 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/CodeAction.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/CodeAction.scala @@ -2,9 +2,14 @@ package org.enso.gateway.protocol.request.clientcapabilities.textdocument import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder +import org.enso.gateway.protocol.request.clientcapabilities.textdocument.codeaction.CodeActionLiteralSupport /** Capabilities specific to the `textDocument/codeAction` request. */ -case class CodeAction() +case class CodeAction( + dynamicRegistration: Option[Boolean] = None, + codeActionLiteralSupport: Option[CodeActionLiteralSupport] = None, + isPreferredSupport: Option[Boolean] = None +) object CodeAction { implicit val clientCapabilitiesTextDocumentCodeActionDecoder : Decoder[CodeAction] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/CodeLens.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/CodeLens.scala index 90903248ffd..c98df979e58 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/CodeLens.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/CodeLens.scala @@ -4,7 +4,9 @@ import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder /** Capabilities specific to the `textDocument/codeLens` request. */ -case class CodeLens() +case class CodeLens( + dynamicRegistration: Option[Boolean] = None +) extends AnyVal object CodeLens { implicit val clientCapabilitiesTextDocumentCodeLensDecoder : Decoder[CodeLens] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Color.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Color.scala index bf96594b26d..41e8eb4cc5b 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Color.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Color.scala @@ -6,7 +6,9 @@ import io.circe.generic.semiauto.deriveDecoder /** Capabilities specific to the `textDocument/documentColor` and the * `textDocument/colorPresentation` request. */ -case class Color() +case class Color( + dynamicRegistration: Option[Boolean] = None +) object Color { implicit val clientCapabilitiesTextDocumentColorDecoder: Decoder[Color] = deriveDecoder diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Completion.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Completion.scala index 6c00707c05e..9ee97eb2b31 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Completion.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Completion.scala @@ -2,9 +2,18 @@ package org.enso.gateway.protocol.request.clientcapabilities.textdocument import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder +import org.enso.gateway.protocol.request.clientcapabilities.textdocument.completion.{ + CompletionItem, + CompletionItemKinds +} /** Capabilities specific to the `textDocument/completion` request. */ -case class Completion() +case class Completion( + dynamicRegistration: Option[Boolean] = None, + completionItem: Option[CompletionItem] = None, + completionItemKind: Option[CompletionItemKinds] = None, + contextSupport: Option[Boolean] = None +) object Completion { implicit val clientCapabilitiesTextDocumentCompletionDecoder : Decoder[Completion] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Declaration.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Declaration.scala index b599da20c9a..1d2fbcbdd27 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Declaration.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Declaration.scala @@ -4,7 +4,10 @@ import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder /** Capabilities specific to the `textDocument/declaration` request. */ -case class Declaration() +case class Declaration( + dynamicRegistration: Option[Boolean] = None, + linkSupport: Option[Boolean] = None +) object Declaration { implicit val clientCapabilitiesTextDocumentDeclarationDecoder : Decoder[Declaration] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Definition.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Definition.scala index a1adf6a41a4..a8a67f7c698 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Definition.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Definition.scala @@ -4,7 +4,10 @@ import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder /** Capabilities specific to the `textDocument/definition` request. */ -case class Definition() +case class Definition( + dynamicRegistration: Option[Boolean] = None, + linkSupport: Option[Boolean] = None +) object Definition { implicit val clientCapabilitiesTextDocumentDefinitionDecoder : Decoder[Definition] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/DocumentSymbol.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/DocumentSymbol.scala index e7d9dc5bd52..e2a79fd9723 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/DocumentSymbol.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/DocumentSymbol.scala @@ -2,9 +2,14 @@ package org.enso.gateway.protocol.request.clientcapabilities.textdocument import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder +import org.enso.gateway.protocol.request.clientcapabilities.common.SymbolKinds /** Capabilities specific to the `textDocument/documentSymbol` request. */ -case class DocumentSymbol() +case class DocumentSymbol( + dynamicRegistration: Option[Boolean] = None, + symbolKind: Option[SymbolKinds] = None, + hierarchicalDocumentSymbolSupport: Option[Boolean] = None +) object DocumentSymbol { implicit val clientCapabilitiesTextDocumentSymbolDecoder : Decoder[DocumentSymbol] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/FoldingRange.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/FoldingRange.scala index 92bc224edc4..8e789cf8cf4 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/FoldingRange.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/FoldingRange.scala @@ -4,7 +4,11 @@ import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder /** Capabilities specific to the `textDocument/foldingRange` request. */ -case class FoldingRange() +case class FoldingRange( + dynamicRegistration: Option[Boolean] = None, + rangeLimit: Option[Int] = None, + lineFoldingOnly: Option[Boolean] = None +) object FoldingRange { implicit val clientCapabilitiesTextDocumentFoldingRangeDecoder : Decoder[FoldingRange] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Formatting.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Formatting.scala index 91f2a5284f0..a16873a6ad7 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Formatting.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Formatting.scala @@ -4,7 +4,9 @@ import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder /** Capabilities specific to the `textDocument/formatting` request. */ -case class Formatting() +case class Formatting( + dynamicRegistration: Option[Boolean] = None +) object Formatting { implicit val clientCapabilitiesTextDocumentFormattingDecoder : Decoder[Formatting] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Highlight.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Highlight.scala index 98825b9e249..b627945db97 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Highlight.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Highlight.scala @@ -4,7 +4,9 @@ import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder /** Capabilities specific to the `textDocument/documentHighlight` request. */ -case class Highlight() +case class Highlight( + dynamicRegistration: Option[Boolean] = None +) object Highlight { implicit val clientCapabilitiesTextDocumentHighlightDecoder : Decoder[Highlight] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Hover.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Hover.scala index e02411edc7a..4ce51f2ad32 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Hover.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Hover.scala @@ -2,9 +2,13 @@ package org.enso.gateway.protocol.request.clientcapabilities.textdocument import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder +import org.enso.gateway.protocol.request.clientcapabilities.textdocument.common.MarkupKind /** Capabilities specific to the `textDocument/hover` request. */ -case class Hover() +case class Hover( + dynamicRegistration: Option[Boolean] = None, + contentFormat: Option[MarkupKind] = None +) object Hover { implicit val clientCapabilitiesTextDocumentHoverDecoder: Decoder[Hover] = deriveDecoder diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Implementation.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Implementation.scala index 6072394c6bb..aafbe4d8784 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Implementation.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Implementation.scala @@ -4,7 +4,10 @@ import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder /** Capabilities specific to the `textDocument/implementation` request. */ -case class Implementation() +case class Implementation( + dynamicRegistration: Option[Boolean] = None, + linkSupport: Option[Boolean] = None +) object Implementation { implicit val clientCapabilitiesTextDocumentImplementationDecoder : Decoder[Implementation] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Link.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Link.scala index cd229d6bf7e..d39428f68dd 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Link.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Link.scala @@ -4,7 +4,10 @@ import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder /** Capabilities specific to the `textDocument/documentLink` request. */ -case class Link() +case class Link( + dynamicRegistration: Option[Boolean] = None, + tooltipSupport: Option[Boolean] = None +) object Link { implicit val clientCapabilitiesTextDocumentLinkDecoder: Decoder[Link] = deriveDecoder diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/OnTypeFormatting.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/OnTypeFormatting.scala index bdfb85fde5c..f030792e08c 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/OnTypeFormatting.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/OnTypeFormatting.scala @@ -4,7 +4,9 @@ import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder /** Capabilities specific to the `textDocument/onTypeFormatting` request. */ -case class OnTypeFormatting() +case class OnTypeFormatting( + dynamicRegistration: Option[Boolean] = None +) object OnTypeFormatting { implicit val clientCapabilitiesTextDocumentOnTypeFormattingDecoder : Decoder[OnTypeFormatting] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/PublishDiagnostics.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/PublishDiagnostics.scala index 6e4471837b2..a83c19adc18 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/PublishDiagnostics.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/PublishDiagnostics.scala @@ -2,10 +2,15 @@ package org.enso.gateway.protocol.request.clientcapabilities.textdocument import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder +import org.enso.gateway.protocol.request.clientcapabilities.textdocument.publishdiagnostics.TagSupport /** Capabilities specific to the `textDocument/publishDiagnostics` notification. */ -case class PublishDiagnostics() +case class PublishDiagnostics( + relatedInformation: Option[Boolean] = None, + tagSupport: Option[TagSupport] = None, + versionSupport: Option[Boolean] = None +) object PublishDiagnostics { implicit val clientCapabilitiesTextDocumentPublishDiagnosticsDecoder : Decoder[PublishDiagnostics] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/RangeFormatting.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/RangeFormatting.scala index 5e1e5eda4f7..5b479636163 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/RangeFormatting.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/RangeFormatting.scala @@ -4,7 +4,9 @@ import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder /** Capabilities specific to the `textDocument/rangeFormatting` request. */ -case class RangeFormatting() +case class RangeFormatting( + dynamicRegistration: Option[Boolean] = None +) object RangeFormatting { implicit val clientCapabilitiesTextDocumentRangeFormattingDecoder : Decoder[RangeFormatting] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Reference.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Reference.scala index d586e2264dc..eca760512a3 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Reference.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Reference.scala @@ -4,7 +4,9 @@ import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder /** Capabilities specific to the `textDocument/references` request. */ -case class Reference() +case class Reference( + dynamicRegistration: Option[Boolean] = None +) object Reference { implicit val clientCapabilitiesTextDocumentReferenceDecoder : Decoder[Reference] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Rename.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Rename.scala index 181a6978f10..46b96300408 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Rename.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Rename.scala @@ -4,7 +4,10 @@ import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder /** Capabilities specific to the `textDocument/rename` request. */ -case class Rename() +case class Rename( + dynamicRegistration: Option[Boolean] = None, + prepareSupport: Option[Boolean] = None +) object Rename { implicit val clientCapabilitiesTextDocumentRenameDecoder: Decoder[Rename] = deriveDecoder diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/SignatureHelp.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/SignatureHelp.scala index 2994c33769c..1b0d7ce986b 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/SignatureHelp.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/SignatureHelp.scala @@ -2,9 +2,14 @@ package org.enso.gateway.protocol.request.clientcapabilities.textdocument import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder +import org.enso.gateway.protocol.request.clientcapabilities.textdocument.signaturehelp.SignatureInformation /** Capabilities specific to the `textDocument/signatureHelp` request. */ -case class SignatureHelp() +case class SignatureHelp( + dynamicRegistration: Option[Boolean] = None, + signatureInformation: Option[SignatureInformation] = None, + contextSupport: Option[Boolean] = None +) object SignatureHelp { implicit val clientCapabilitiesTextDocumentSignatureHelpDecoder : Decoder[SignatureHelp] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Sync.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Sync.scala index a4cd487b20f..364096c4cf3 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Sync.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/Sync.scala @@ -4,7 +4,12 @@ import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder /** Synchronization capabilities. */ -case class Sync() +case class Sync( + dynamicRegistration: Option[Boolean] = None, + willSave: Option[Boolean] = None, + willSaveWaitUntil: Option[Boolean] = None, + didSave: Option[Boolean] = None +) object Sync { implicit val clientCapabilitiesTextDocumentSyncDecoder: Decoder[Sync] = deriveDecoder diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/TypeDefinition.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/TypeDefinition.scala index 6dad693e111..48e3cbc0dba 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/TypeDefinition.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/TypeDefinition.scala @@ -4,7 +4,10 @@ import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder /** Capabilities specific to the `textDocument/typeDefinition` request. */ -case class TypeDefinition() +case class TypeDefinition( + dynamicRegistration: Option[Boolean] = None, + linkSupport: Option[Boolean] = None +) object TypeDefinition { implicit val clientCapabilitiesTextDocumentTypeDefinitionDecoder : Decoder[TypeDefinition] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/codeaction/CodeActionKinds.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/codeaction/CodeActionKinds.scala new file mode 100644 index 00000000000..5f6eda1e7b0 --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/codeaction/CodeActionKinds.scala @@ -0,0 +1,12 @@ +package org.enso.gateway.protocol.request.clientcapabilities.textdocument.codeaction + +import io.circe.Decoder +import io.circe.generic.semiauto.deriveDecoder +import org.enso.gateway.protocol.CodeActionKind + +/** Array of [[CodeActionKind]]. */ +case class CodeActionKinds(valueSet: Seq[CodeActionKind]) extends AnyVal +object CodeActionKinds { + implicit val codeActionKindsDecoder: Decoder[CodeActionKinds] = + deriveDecoder +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/codeaction/CodeActionLiteralSupport.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/codeaction/CodeActionLiteralSupport.scala new file mode 100644 index 00000000000..7c86d9fb319 --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/codeaction/CodeActionLiteralSupport.scala @@ -0,0 +1,14 @@ +package org.enso.gateway.protocol.request.clientcapabilities.textdocument.codeaction + +import io.circe.Decoder +import io.circe.generic.semiauto.deriveDecoder + +/** Part of + * [[org.enso.gateway.protocol.request.clientcapabilities.textdocument.CodeAction]]. + */ +case class CodeActionLiteralSupport(codeActionKind: CodeActionKinds) +object CodeActionLiteralSupport { + implicit val codeActionLiteralSupportDecoder + : Decoder[CodeActionLiteralSupport] = + deriveDecoder +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/common/MarkupKind.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/common/MarkupKind.scala new file mode 100644 index 00000000000..21c3b676387 --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/common/MarkupKind.scala @@ -0,0 +1,22 @@ +package org.enso.gateway.protocol.request.clientcapabilities.textdocument.common + +import io.circe.Decoder +import io.circe.generic.extras.semiauto.deriveEnumerationDecoder + +/** Part of + * [[org.enso.gateway.protocol.request.clientcapabilities.textdocument.completion.CompletionItem]] + * and + * [[org.enso.gateway.protocol.request.clientcapabilities.textdocument.signaturehelp.SignatureInformation]]. + */ +sealed trait MarkupKind +object MarkupKind { + + /** Plain text is supported as a content format. */ + case object plaintext extends MarkupKind + + /** Markdown is supported as a content format. */ + case object markdown extends MarkupKind + + implicit val clientCapabilitiesTextDocumentCompletionMarkupKindDecoder + : Decoder[MarkupKind] = deriveEnumerationDecoder +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/completion/CompletionItem.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/completion/CompletionItem.scala new file mode 100644 index 00000000000..efbc1734553 --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/completion/CompletionItem.scala @@ -0,0 +1,22 @@ +package org.enso.gateway.protocol.request.clientcapabilities.textdocument.completion + +import io.circe.Decoder +import io.circe.generic.semiauto.deriveDecoder +import org.enso.gateway.protocol.request.clientcapabilities.textdocument.common.MarkupKind + +/** Part of + * [[org.enso.gateway.protocol.request.clientcapabilities.textdocument.Completion]]. + */ +case class CompletionItem( + snippetSupport: Option[Boolean] = None, + commitCharactersSupport: Option[Boolean] = None, + documentationFormat: Option[Seq[MarkupKind]] = None, + deprecatedSupport: Option[Boolean] = None, + preselectSupport: Option[Boolean] = None, + tagSupport: Option[TagSupport] = None +) +object CompletionItem { + implicit val clientCapabilitiesTextDocumentCompletionItemDecoder + : Decoder[CompletionItem] = + deriveDecoder +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/completion/CompletionItemKind.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/completion/CompletionItemKind.scala new file mode 100644 index 00000000000..456e2c98d22 --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/completion/CompletionItemKind.scala @@ -0,0 +1,114 @@ +package org.enso.gateway.protocol.request.clientcapabilities.textdocument.completion + +import io.circe.Decoder + +/** Kind of [[CompletionItem]]. */ +sealed abstract class CompletionItemKind(value: Int) +object CompletionItemKind { + private val text = 1 + private val method = 2 + private val function = 3 + private val constructor = 4 + private val field = 5 + private val variable = 6 + private val classKind = 7 + private val interface = 8 + private val module = 9 + private val property = 10 + private val unit = 11 + private val value = 12 + private val enum = 13 + private val keyword = 14 + private val snippet = 15 + private val color = 16 + private val file = 17 + private val reference = 18 + private val folder = 19 + private val enumMember = 20 + private val constant = 21 + private val struct = 22 + private val event = 23 + private val operator = 24 + private val typeParameter = 25 + private val invalidCompletionItemKind = "Invalid CompletionItemKind" + + case object Text extends CompletionItemKind(text) + + case object Method extends CompletionItemKind(method) + + case object Function extends CompletionItemKind(function) + + case object Constructor extends CompletionItemKind(constructor) + + case object Field extends CompletionItemKind(field) + + case object Variable extends CompletionItemKind(variable) + + case object Class extends CompletionItemKind(classKind) + + case object Interface extends CompletionItemKind(interface) + + case object Module extends CompletionItemKind(module) + + case object Property extends CompletionItemKind(property) + + case object Unit extends CompletionItemKind(unit) + + case object Value extends CompletionItemKind(value) + + case object Enum extends CompletionItemKind(enum) + + case object Keyword extends CompletionItemKind(keyword) + + case object Snippet extends CompletionItemKind(snippet) + + case object Color extends CompletionItemKind(color) + + case object File extends CompletionItemKind(file) + + case object Reference extends CompletionItemKind(reference) + + case object Folder extends CompletionItemKind(folder) + + case object EnumMember extends CompletionItemKind(enumMember) + + case object Constant extends CompletionItemKind(constant) + + case object Struct extends CompletionItemKind(struct) + + case object Event extends CompletionItemKind(event) + + case object Operator extends CompletionItemKind(operator) + + case object TypeParameter extends CompletionItemKind(typeParameter) + + implicit val textDocumentSyncKindDecoder: Decoder[CompletionItemKind] = + Decoder.decodeInt.emap { + case `text` => Right(Text) + case `method` => Right(Method) + case `function` => Right(Function) + case `constructor` => Right(Constructor) + case `field` => Right(Field) + case `variable` => Right(Variable) + case `classKind` => Right(Class) + case `interface` => Right(Interface) + case `module` => Right(Module) + case `property` => Right(Property) + case `unit` => Right(Unit) + case `value` => Right(Value) + case `enum` => Right(Enum) + case `keyword` => Right(Keyword) + case `snippet` => Right(Snippet) + case `color` => Right(Color) + case `file` => Right(File) + case `reference` => Right(Reference) + case `folder` => Right(Folder) + case `enumMember` => Right(EnumMember) + case `constant` => Right(Constant) + case `struct` => Right(Struct) + case `event` => Right(Event) + case `operator` => Right(Operator) + case `typeParameter` => Right(TypeParameter) + case _ => Left(invalidCompletionItemKind) + } +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/completion/CompletionItemKinds.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/completion/CompletionItemKinds.scala new file mode 100644 index 00000000000..cd2ec570ac0 --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/completion/CompletionItemKinds.scala @@ -0,0 +1,14 @@ +package org.enso.gateway.protocol.request.clientcapabilities.textdocument.completion + +import io.circe.Decoder +import io.circe.generic.semiauto.deriveDecoder + +/** Array of [[CompletionItemKind]]. */ +case class CompletionItemKinds( + valueSet: Option[Seq[CompletionItemKind]] = None +) extends AnyVal +object CompletionItemKinds { + implicit val clientCapabilitiesTextDocumentCompletionItemKindHolderDecoder + : Decoder[CompletionItemKinds] = + deriveDecoder +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/completion/CompletionItemTag.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/completion/CompletionItemTag.scala new file mode 100644 index 00000000000..79c87e4b48d --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/completion/CompletionItemTag.scala @@ -0,0 +1,19 @@ +package org.enso.gateway.protocol.request.clientcapabilities.textdocument.completion + +import io.circe.Decoder + +/** Tag of [[CompletionItem]]. */ +sealed abstract class CompletionItemTag(value: Int) +object CompletionItemTag { + private val deprecated = 1 + private val invalidCompletionItemTag = "Invalid CompletionItemTag" + + object Deprecated extends CompletionItemTag(deprecated) + + implicit val textDocumentCompletionItemTagDecoder + : Decoder[CompletionItemTag] = + Decoder.decodeInt.emap { + case `deprecated` => Right(Deprecated) + case _ => Left(invalidCompletionItemTag) + } +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/completion/TagSupport.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/completion/TagSupport.scala new file mode 100644 index 00000000000..6eb071bbb07 --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/completion/TagSupport.scala @@ -0,0 +1,16 @@ +package org.enso.gateway.protocol.request.clientcapabilities.textdocument.completion + +import io.circe.Decoder +import io.circe.generic.semiauto.deriveDecoder + +/** Array of [[CompletionItemTag]]. + * + * Part of [[CompletionItem]]. + */ +case class TagSupport( + valueSet: Seq[CompletionItemTag] +) extends AnyVal +object TagSupport { + implicit val clientCapabilitiesTextDocumentCompletionTagSupportDecoder + : Decoder[TagSupport] = deriveDecoder +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/publishdiagnostics/DiagnosticTag.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/publishdiagnostics/DiagnosticTag.scala new file mode 100644 index 00000000000..b08b166a920 --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/publishdiagnostics/DiagnosticTag.scala @@ -0,0 +1,31 @@ +package org.enso.gateway.protocol.request.clientcapabilities.textdocument.publishdiagnostics + +import io.circe.Decoder + +/** Element of [[TagSupport]]. */ +sealed abstract class DiagnosticTag(value: Int) +object DiagnosticTag { + private val unnecessary = 1 + private val deprecated = 2 + private val invalidDiagnosticTag = "Invalid DiagnosticTag" + + /** Unused or unnecessary code. + * + * Clients are allowed to render diagnostics with this tag faded out instead + * of having an error squiggle. + */ + case object Unnecessary extends DiagnosticTag(unnecessary) + + /** Deprecated or obsolete code. + * + * Clients are allowed to rendered diagnostics with this tag strike through. + */ + case object Deprecated extends DiagnosticTag(deprecated) + + implicit val diagnosticTagDecoder: Decoder[DiagnosticTag] = + Decoder.decodeInt.emap { + case `unnecessary` => Right(Unnecessary) + case `deprecated` => Right(Deprecated) + case _ => Left(invalidDiagnosticTag) + } +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/publishdiagnostics/TagSupport.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/publishdiagnostics/TagSupport.scala new file mode 100644 index 00000000000..53e1e12a7a7 --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/publishdiagnostics/TagSupport.scala @@ -0,0 +1,13 @@ +package org.enso.gateway.protocol.request.clientcapabilities.textdocument.publishdiagnostics + +import io.circe.Decoder +import io.circe.generic.semiauto.deriveDecoder + +/** Part of + * [[org.enso.gateway.protocol.request.clientcapabilities.textdocument.PublishDiagnostics]]. + */ +case class TagSupport(valueSet: Seq[DiagnosticTag]) extends AnyVal +object TagSupport { + implicit val tagSupportDecoder: Decoder[TagSupport] = + deriveDecoder +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/signaturehelp/ParameterInformation.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/signaturehelp/ParameterInformation.scala new file mode 100644 index 00000000000..a30a4efad02 --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/signaturehelp/ParameterInformation.scala @@ -0,0 +1,12 @@ +package org.enso.gateway.protocol.request.clientcapabilities.textdocument.signaturehelp + +import io.circe.Decoder +import io.circe.generic.semiauto.deriveDecoder + +/** Part of [[SignatureInformation]]. */ +case class ParameterInformation(labelOffsetSupport: Option[Boolean] = None) + extends AnyVal +object ParameterInformation { + implicit val parameterInformationDecoder: Decoder[ParameterInformation] = + deriveDecoder +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/signaturehelp/SignatureInformation.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/signaturehelp/SignatureInformation.scala new file mode 100644 index 00000000000..a4396ed338e --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/textdocument/signaturehelp/SignatureInformation.scala @@ -0,0 +1,17 @@ +package org.enso.gateway.protocol.request.clientcapabilities.textdocument.signaturehelp + +import io.circe.Decoder +import io.circe.generic.semiauto.deriveDecoder +import org.enso.gateway.protocol.request.clientcapabilities.textdocument.common.MarkupKind + +/** Part of + * [[org.enso.gateway.protocol.request.clientcapabilities.textdocument.SignatureHelp]]. + */ +case class SignatureInformation( + documentationFormat: Option[Seq[MarkupKind]] = None, + parameterInformation: Option[ParameterInformation] = None +) +object SignatureInformation { + implicit val signatureInformationDecoder: Decoder[SignatureInformation] = + deriveDecoder +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/DidChangeConfiguration.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/DidChangeConfiguration.scala index 1a0eb4f09e6..009668a9c7f 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/DidChangeConfiguration.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/DidChangeConfiguration.scala @@ -6,7 +6,7 @@ import io.circe.generic.semiauto.deriveDecoder /** Capabilities specific to the `workspace/didChangeConfiguration` * notification. */ -case class DidChangeConfiguration() +case class DidChangeConfiguration(dynamicRegistration: Option[Boolean] = None) object DidChangeConfiguration { implicit val clientCapabilitiesWorkspaceDidChangeConfigurationDecoder : Decoder[DidChangeConfiguration] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/DidChangeWatchedFiles.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/DidChangeWatchedFiles.scala index ac4cd611d45..205c5bf9333 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/DidChangeWatchedFiles.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/DidChangeWatchedFiles.scala @@ -5,7 +5,7 @@ import io.circe.generic.semiauto.deriveDecoder /** Capabilities specific to the `workspace/didChangeWatchedFiles` notification. */ -case class DidChangeWatchedFiles() +case class DidChangeWatchedFiles(dynamicRegistration: Option[Boolean] = None) object DidChangeWatchedFiles { implicit val clientCapabilitiesWorkspaceDidChangeWatchedFilesDecoder : Decoder[DidChangeWatchedFiles] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/Edit.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/Edit.scala index 3af927df187..803f9c4533e 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/Edit.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/Edit.scala @@ -2,9 +2,17 @@ package org.enso.gateway.protocol.request.clientcapabilities.workspace import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder +import org.enso.gateway.protocol.request.clientcapabilities.workspace.edit.{ + FailureHandlingKind, + ResourceOperationKind +} /** Capabilities specific to `WorkspaceEdit`s. */ -case class Edit() +case class Edit( + documentChanges: Option[Boolean], + resourceOperations: Option[Seq[ResourceOperationKind]], + failureHandling: Option[FailureHandlingKind] +) object Edit { implicit val clientCapabilitiesWorkspaceEditDecoder: Decoder[Edit] = deriveDecoder diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/ExecuteCommand.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/ExecuteCommand.scala index afcd0e22f16..3fbbf6cd52e 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/ExecuteCommand.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/ExecuteCommand.scala @@ -4,7 +4,7 @@ import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder /** Capabilities specific to the `workspace/executeCommand` request. */ -case class ExecuteCommand() +case class ExecuteCommand(dynamicRegistration: Option[Boolean] = None) object ExecuteCommand { implicit val clientCapabilitiesWorkspaceExecuteCommandDecoder : Decoder[ExecuteCommand] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/WorkspaceSymbol.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/WorkspaceSymbol.scala index 899e9962f0e..d6646d532fc 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/WorkspaceSymbol.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/WorkspaceSymbol.scala @@ -2,9 +2,13 @@ package org.enso.gateway.protocol.request.clientcapabilities.workspace import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder +import org.enso.gateway.protocol.request.clientcapabilities.common.SymbolKinds /** Capabilities specific to the `workspace/symbol` request. */ -case class WorkspaceSymbol() +case class WorkspaceSymbol( + dynamicRegistration: Option[Boolean] = None, + symbolKind: Option[SymbolKinds] = None +) object WorkspaceSymbol { implicit val clientCapabilitiesWorkspaceWorkspaceSymbolDecoder : Decoder[WorkspaceSymbol] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/edit/FailureHandlingKind.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/edit/FailureHandlingKind.scala new file mode 100644 index 00000000000..c1c30ebf819 --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/edit/FailureHandlingKind.scala @@ -0,0 +1,39 @@ +package org.enso.gateway.protocol.request.clientcapabilities.workspace.edit + +import io.circe.Decoder +import io.circe.generic.extras.semiauto.deriveEnumerationDecoder + +/** Part of + * [[org.enso.gateway.protocol.request.clientcapabilities.workspace.Edit]]. + */ +sealed trait FailureHandlingKind +object FailureHandlingKind { + + /** Applying the workspace change is simply aborted if one of the changes + * provided fails. All operations executed before the failing operation stay + * executed. + */ + case object abort extends FailureHandlingKind + + /** + * All operations are executed transactional. That means they either all + * succeed or no changes at all are applied to the workspace. + */ + case object transactional extends FailureHandlingKind + + /** + * The client tries to undo the operations already executed. But there is no + * guarantee that this is succeeding. + */ + case object undo extends FailureHandlingKind + + /** + * If the workspace edit contains only textual file changes they are executed + * transactional. If resource changes (create, rename or delete file) are + * part of the change the failure handling strategy is abort. + */ + case object textOnlyTransactional extends FailureHandlingKind + + implicit val failureHandlingKindDecoder: Decoder[FailureHandlingKind] = + deriveEnumerationDecoder +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/edit/ResourceOperationKind.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/edit/ResourceOperationKind.scala new file mode 100644 index 00000000000..c8e75a9b170 --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/request/clientcapabilities/workspace/edit/ResourceOperationKind.scala @@ -0,0 +1,23 @@ +package org.enso.gateway.protocol.request.clientcapabilities.workspace.edit + +import io.circe.Decoder +import io.circe.generic.extras.semiauto.deriveEnumerationDecoder + +/** Part of + * [[org.enso.gateway.protocol.request.clientcapabilities.workspace.Edit]]. + */ +sealed trait ResourceOperationKind +object ResourceOperationKind { + + /** Supports creating new files and folders. */ + case object create extends ResourceOperationKind + + /** Supports renaming existing files and folders. */ + case object rename extends ResourceOperationKind + + /** Supports deleting existing files and folders. */ + case object delete extends ResourceOperationKind + + implicit val resourceOperationKindDecoder: Decoder[ResourceOperationKind] = + deriveEnumerationDecoder +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/ResponseError.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/ResponseError.scala index 43b2b9b6964..acdf5ee8835 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/ResponseError.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/ResponseError.scala @@ -4,7 +4,7 @@ import io.circe.Encoder import org.enso.gateway.protocol.response.error.{Data, ErrorCode, ErrorMessage} import org.enso.gateway.protocol.response.error.Data.{InitializeData, ParseData} -/** [[org.enso.gateway.protocol.Response]] error. +/** Error of [[org.enso.gateway.protocol.Response]]. * * `ResponseError` in LSP Spec: * https://microsoft.github.io/language-server-protocol/specifications/specification-3-15/#responseMessage @@ -42,7 +42,8 @@ object ResponseError { data ) - /** [[org.enso.gateway.protocol.Requests.Initialize]] error. + /** Error of [[org.enso.gateway.protocol.Requests.Initialize]]. + * * Wrong JSON-RPC version. */ case class InitializeError( diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/Result.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/Result.scala index 30211717052..9a93c0e0743 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/Result.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/Result.scala @@ -1,6 +1,6 @@ package org.enso.gateway.protocol.response -import io.circe.Encoder +import io.circe.{Encoder, Json} import io.circe.generic.extras.semiauto.deriveUnwrappedEncoder import io.circe.generic.semiauto.deriveEncoder import org.enso.gateway.protocol.response.result.{ @@ -9,7 +9,7 @@ import org.enso.gateway.protocol.response.result.{ } import io.circe.syntax._ -/** [[org.enso.gateway.protocol.Response]] result. +/** Result of [[org.enso.gateway.protocol.Response]]. * * LSP Spec: * https://microsoft.github.io/language-server-protocol/specifications/specification-3-15/#responseMessage @@ -17,10 +17,11 @@ import io.circe.syntax._ sealed trait Result object Result { implicit val resultEncoder: Encoder[Result] = Encoder.instance { - case text: Text => text.asJson - case number: Number => number.asJson - case boolean: Bool => boolean.asJson - case initializeResult: InitializeResult => initializeResult.asJson + case text: Text => text.asJson + case number: Number => number.asJson + case boolean: Bool => boolean.asJson + case result: InitializeResult => result.asJson + case result: NullResult.type => result.asJson } /** A string result. */ @@ -36,13 +37,13 @@ object Result { } /** A boolean result. */ - case class Bool(value: scala.Boolean) extends Result + case class Bool(value: Boolean) extends Result object Bool { implicit val resultBooleanEncoder: Encoder[Bool] = deriveUnwrappedEncoder } - /** [[org.enso.gateway.protocol.Requests.Initialize]] result. */ + /** Result of [[org.enso.gateway.protocol.Requests.Initialize]]. */ case class InitializeResult( capabilities: ServerCapabilities, serverInfo: Option[ServerInfo] = None @@ -51,4 +52,9 @@ object Result { implicit val initializeResultEncoder: Encoder[InitializeResult] = deriveEncoder } + + /** Result of [[org.enso.gateway.protocol.Requests.Shutdown]]. */ + case object NullResult extends Result { + implicit val nullResultEncoder: Encoder[NullResult.type] = _ => Json.Null + } } diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/error/ErrorCode.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/error/ErrorCode.scala index 1b1d1f5224e..0ab1915e796 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/error/ErrorCode.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/error/ErrorCode.scala @@ -6,22 +6,35 @@ import io.circe.Encoder sealed abstract class ErrorCode(val code: Int) object ErrorCode { - /** Invalid JSON was received by the server. An error occurred on the server - * while parsing the JSON text. Defined by JSON-RPC Spec. + /** Signals that invalid JSON was received by the server. + * + * An error occurred on the server while parsing the JSON text. + * Defined by JSON-RPC Spec. */ case object ParseError extends ErrorCode(-32700) - /** The JSON sent is not a valid Request object. Defined by JSON-RPC Spec. */ + /** Signals that the JSON sent is not a valid Request object. + * + * Defined by JSON-RPC Spec. + */ case object InvalidRequest extends ErrorCode(-32600) - /** The method does not exist or is not available. Defined by JSON-RPC Spec. + /** Signals that the method does not exist or is not available. + * + * Defined by JSON-RPC Spec. */ case object MethodNotFound extends ErrorCode(-32601) - /** Invalid method parameters. Defined by JSON-RPC Spec. */ + /** Signals that method parameters are invalid. + * + * Defined by JSON-RPC Spec. + */ case object InvalidParams extends ErrorCode(-32602) - /** Internal JSON-RPC error. Defined by JSON-RPC Spec. */ + /** Internal JSON-RPC error. + * + * Defined by JSON-RPC Spec. + */ case object InternalError extends ErrorCode(-32603) /** Codes from -32000 to -32099 reserved for implementation-defined diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/ServerCapabilities.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/ServerCapabilities.scala index 7c59294b857..b019c64c2b5 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/ServerCapabilities.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/ServerCapabilities.scala @@ -2,17 +2,18 @@ package org.enso.gateway.protocol.response.result import io.circe.generic.semiauto.deriveEncoder import io.circe.Encoder +import org.enso.gateway.protocol.response.result.servercapabilities.declarationprovider.DocumentFilter import org.enso.gateway.protocol.response.result.servercapabilities.{ CodeActionProvider, - CodeLensProvider, + CodeLensOptions, ColorProvider, CompletionOptions, DeclarationProvider, DefinitionProvider, DocumentFormattingProvider, DocumentHighlightProvider, - DocumentLinkProvider, - DocumentOnTypeFormattingProvider, + DocumentLinkOptions, + DocumentOnTypeFormattingOptions, DocumentRangeFormattingProvider, DocumentSymbolProvider, ExecuteCommandOptions, @@ -28,8 +29,8 @@ import org.enso.gateway.protocol.response.result.servercapabilities.{ Workspace } -/** [[org.enso.gateway.protocol.response.Result.InitializeResult]] server - * capabilities. +/** Server capabilities in + * [[org.enso.gateway.protocol.response.Result.InitializeResult]]. * * @param textDocumentSync @see [[TextDocumentSync]] * @param completionProvider @see [[CompletionOptions]] @@ -43,14 +44,14 @@ import org.enso.gateway.protocol.response.result.servercapabilities.{ * @param documentHighlightProvider @see [[DocumentHighlightProvider]] * @param documentSymbolProvider @see [[DocumentSymbolProvider]] * @param codeActionProvider @see [[CodeActionProvider]] - * @param codeLensProvider @see [[CodeLensProvider]] - * @param documentLinkProvider @see [[DocumentLinkProvider]] + * @param codeLensProvider @see [[CodeLensOptions]] + * @param documentLinkProvider @see [[DocumentLinkOptions]] * @param colorProvider @see [[ColorProvider]] * @param documentFormattingProvider @see [[DocumentFormattingProvider]] * @param documentRangeFormattingProvider @see * [[DocumentRangeFormattingProvider]] * @param documentOnTypeFormattingProvider @see - * [[DocumentOnTypeFormattingProvider]] + * [[DocumentOnTypeFormattingOptions]] * @param renameProvider @see [[RenameProvider]] * @param foldingRangeProvider @see [[FoldingRangeProvider]] * @param executeCommandProvider @see [[ExecuteCommandOptions]] @@ -72,13 +73,13 @@ case class ServerCapabilities( documentHighlightProvider: Option[DocumentHighlightProvider] = None, documentSymbolProvider: Option[DocumentSymbolProvider] = None, codeActionProvider: Option[CodeActionProvider] = None, - codeLensProvider: Option[CodeLensProvider] = None, - documentLinkProvider: Option[DocumentLinkProvider] = None, + codeLensProvider: Option[CodeLensOptions] = None, + documentLinkProvider: Option[DocumentLinkOptions] = None, colorProvider: Option[ColorProvider] = None, documentFormattingProvider: Option[DocumentFormattingProvider] = None, documentRangeFormattingProvider: Option[DocumentRangeFormattingProvider] = None, - documentOnTypeFormattingProvider: Option[DocumentOnTypeFormattingProvider] = + documentOnTypeFormattingProvider: Option[DocumentOnTypeFormattingOptions] = None, renameProvider: Option[RenameProvider] = None, foldingRangeProvider: Option[FoldingRangeProvider] = None, @@ -88,6 +89,7 @@ case class ServerCapabilities( experimental: Option[Experimental] = None ) object ServerCapabilities { + type DocumentSelector = Seq[DocumentFilter] implicit val serverCapabilitiesEncoder: Encoder[ServerCapabilities] = deriveEncoder } diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/ServerInfo.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/ServerInfo.scala index cd37971214f..03718f18618 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/ServerInfo.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/ServerInfo.scala @@ -3,7 +3,8 @@ package org.enso.gateway.protocol.response.result import io.circe.generic.semiauto.deriveEncoder import io.circe.Encoder -/** [[org.enso.gateway.protocol.response.Result.InitializeResult]] server info. +/** Server info in + * [[org.enso.gateway.protocol.response.Result.InitializeResult]]. * * @param name Name of Language Server * @param version Version of Language Server diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/CodeActionProvider.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/CodeActionProvider.scala index 621801630c3..f1afe8afbed 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/CodeActionProvider.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/CodeActionProvider.scala @@ -1,15 +1,39 @@ package org.enso.gateway.protocol.response.result.servercapabilities import io.circe.Encoder +import io.circe.syntax._ +import io.circe.generic.extras.semiauto.deriveUnwrappedEncoder import io.circe.generic.semiauto.deriveEncoder +import org.enso.gateway.protocol.CodeActionKind -/** The server provides code actions. The `CodeActionOptions` return type is - * only valid if the client signals code action literal support via the - * property `textDocument.codeAction.codeActionLiteralSupport`. +/** Server capability to provide code actions. + * + * The [[CodeActionProvider.CodeActionOptions]] return type is only valid if + * the client signals code action literal support via the property + * `textDocument.codeAction.codeActionLiteralSupport`. */ -case class CodeActionProvider() +sealed trait CodeActionProvider object CodeActionProvider { + + case class Bool(value: Boolean) extends CodeActionProvider + object Bool { + implicit val boolEncoder: Encoder[Bool] = + deriveUnwrappedEncoder + } + + case class CodeActionOptions( + workDoneProgress: Option[Boolean] = None, + codeActionKinds: Option[Seq[CodeActionKind]] = None + ) extends CodeActionProvider + object CodeActionOptions { + implicit val codeActionOptionsEncoder: Encoder[CodeActionOptions] = + deriveEncoder + } + implicit val serverCapabilitiesCodeActionProviderEncoder : Encoder[CodeActionProvider] = - deriveEncoder + Encoder.instance { + case boolean: Bool => boolean.asJson + case options: CodeActionOptions => options.asJson + } } diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/CodeLensOptions.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/CodeLensOptions.scala new file mode 100644 index 00000000000..3df21dae402 --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/CodeLensOptions.scala @@ -0,0 +1,15 @@ +package org.enso.gateway.protocol.response.result.servercapabilities + +import io.circe.Encoder +import io.circe.generic.semiauto.deriveEncoder + +/** Server capability to provide code lens. */ +case class CodeLensOptions( + workDoneProgress: Option[Boolean] = None, + resolveProvider: Option[Boolean] = None +) +object CodeLensOptions { + implicit val serverCapabilitiesCodeLensOptionsEncoder + : Encoder[CodeLensOptions] = + deriveEncoder +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/CodeLensProvider.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/CodeLensProvider.scala deleted file mode 100644 index ac6a8b55b8a..00000000000 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/CodeLensProvider.scala +++ /dev/null @@ -1,12 +0,0 @@ -package org.enso.gateway.protocol.response.result.servercapabilities - -import io.circe.Encoder -import io.circe.generic.semiauto.deriveEncoder - -/** The server provides code lens. */ -case class CodeLensProvider() -object CodeLensProvider { - implicit val serverCapabilitiesCodeLensProviderEncoder - : Encoder[CodeLensProvider] = - deriveEncoder -} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/ColorProvider.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/ColorProvider.scala index e8d7321690a..8002e101560 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/ColorProvider.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/ColorProvider.scala @@ -1,11 +1,43 @@ package org.enso.gateway.protocol.response.result.servercapabilities import io.circe.Encoder +import io.circe.syntax._ +import io.circe.generic.extras.semiauto.deriveUnwrappedEncoder import io.circe.generic.semiauto.deriveEncoder +import org.enso.gateway.protocol.response.result.ServerCapabilities.DocumentSelector -/** The server provides color provider support. */ -case class ColorProvider() +/** Server capability to provide color provider support. */ +sealed trait ColorProvider object ColorProvider { + + case class Bool(value: Boolean) extends ColorProvider + object Bool { + implicit val boolEncoder: Encoder[Bool] = + deriveUnwrappedEncoder + } + + case class DocumentColorOptions(workDoneProgress: Option[Boolean] = None) + extends ColorProvider + object DocumentColorOptions { + implicit val documentColorOptionsEncoder: Encoder[DocumentColorOptions] = + deriveEncoder + } + + case class DocumentColorRegistrationOptions( + workDoneProgress: Option[Boolean] = None, + documentSelector: Option[DocumentSelector] = None, + id: Option[String] = None + ) extends ColorProvider + object DocumentColorRegistrationOptions { + implicit val documentColorRegistrationOptionsEncoder + : Encoder[DocumentColorRegistrationOptions] = + deriveEncoder + } + implicit val serverCapabilitiesColorProviderEncoder: Encoder[ColorProvider] = - deriveEncoder + Encoder.instance { + case boolean: Bool => boolean.asJson + case options: DocumentColorOptions => options.asJson + case options: DocumentColorRegistrationOptions => options.asJson + } } diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/CompletionOptions.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/CompletionOptions.scala index c3570400de4..ee1eacca802 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/CompletionOptions.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/CompletionOptions.scala @@ -3,8 +3,13 @@ package org.enso.gateway.protocol.response.result.servercapabilities import io.circe.Encoder import io.circe.generic.semiauto.deriveEncoder -/** The server provides completion support. */ -case class CompletionOptions() +/** Server capability to provide completion support. */ +case class CompletionOptions( + triggerCharacters: Option[Seq[String]] = None, + allCommitCharacters: Option[Seq[String]] = None, + resolveProvider: Option[Boolean] = None, + workDoneProgress: Option[Boolean] = None +) object CompletionOptions { implicit val serverCapabilitiesCompletionOptionsEncoder : Encoder[CompletionOptions] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DeclarationProvider.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DeclarationProvider.scala index dbb96032c71..06bb21057b3 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DeclarationProvider.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DeclarationProvider.scala @@ -1,12 +1,44 @@ package org.enso.gateway.protocol.response.result.servercapabilities import io.circe.Encoder +import io.circe.syntax._ import io.circe.generic.semiauto.deriveEncoder +import io.circe.generic.extras.semiauto.deriveUnwrappedEncoder +import org.enso.gateway.protocol.response.result.ServerCapabilities.DocumentSelector -/** The server provides go to declaration support. */ -case class DeclarationProvider() +/** Server capability to provide "go to declaration" support. */ +sealed trait DeclarationProvider object DeclarationProvider { + + case class Bool(value: Boolean) extends DeclarationProvider + object Bool { + implicit val boolEncoder: Encoder[Bool] = + deriveUnwrappedEncoder + } + + case class DeclarationOptions(workDoneProgress: Option[Boolean] = None) + extends DeclarationProvider + object DeclarationOptions { + implicit val declarationOptionsEncoder: Encoder[DeclarationOptions] = + deriveEncoder + } + + case class DeclarationRegistrationOptions( + workDoneProgress: Option[Boolean] = None, + documentSelector: Option[DocumentSelector] = None, + id: Option[String] = None + ) extends DeclarationProvider + object DeclarationRegistrationOptions { + implicit val declarationRegistrationOptionsEncoder + : Encoder[DeclarationRegistrationOptions] = + deriveEncoder + } + implicit val serverCapabilitiesDeclarationProviderEncoder : Encoder[DeclarationProvider] = - deriveEncoder + Encoder.instance { + case boolean: Bool => boolean.asJson + case options: DeclarationOptions => options.asJson + case options: DeclarationRegistrationOptions => options.asJson + } } diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DefinitionProvider.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DefinitionProvider.scala index e70a8c7798b..6f50f55ad68 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DefinitionProvider.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DefinitionProvider.scala @@ -1,12 +1,31 @@ package org.enso.gateway.protocol.response.result.servercapabilities import io.circe.Encoder +import io.circe.syntax._ +import io.circe.generic.extras.semiauto.deriveUnwrappedEncoder import io.circe.generic.semiauto.deriveEncoder -/** The server provides goto definition support. */ -case class DefinitionProvider() +/** Server capability to provide "go to definition" support. */ +sealed trait DefinitionProvider object DefinitionProvider { + + case class Bool(value: Boolean) extends DefinitionProvider + object Bool { + implicit val boolEncoder: Encoder[Bool] = + deriveUnwrappedEncoder + } + + case class DefinitionOptions(workDoneProgress: Option[Boolean] = None) + extends DefinitionProvider + object DefinitionOptions { + implicit val definitionOptionsEncoder: Encoder[DefinitionOptions] = + deriveEncoder + } + implicit val serverCapabilitiesDefinitionProviderEncoder : Encoder[DefinitionProvider] = - deriveEncoder + Encoder.instance { + case boolean: Bool => boolean.asJson + case options: DefinitionOptions => options.asJson + } } diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentFormattingProvider.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentFormattingProvider.scala index aed9cb44a26..1f1ac7d352c 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentFormattingProvider.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentFormattingProvider.scala @@ -1,12 +1,32 @@ package org.enso.gateway.protocol.response.result.servercapabilities import io.circe.Encoder +import io.circe.syntax._ +import io.circe.generic.extras.semiauto.deriveUnwrappedEncoder import io.circe.generic.semiauto.deriveEncoder -/** The server provides document formatting. */ -case class DocumentFormattingProvider() +/** Server capability to provide document formatting. */ +sealed trait DocumentFormattingProvider object DocumentFormattingProvider { + + case class Bool(value: Boolean) extends DocumentFormattingProvider + object Bool { + implicit val boolEncoder: Encoder[Bool] = + deriveUnwrappedEncoder + } + + case class DocumentFormattingOptions(workDoneProgress: Option[Boolean] = None) + extends DocumentFormattingProvider + object DocumentFormattingOptions { + implicit val documentFormattingOptionsEncoder + : Encoder[DocumentFormattingOptions] = + deriveEncoder + } + implicit val serverCapabilitiesDocumentFormattingProviderEncoder : Encoder[DocumentFormattingProvider] = - deriveEncoder + Encoder.instance { + case boolean: Bool => boolean.asJson + case options: DocumentFormattingOptions => options.asJson + } } diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentHighlightProvider.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentHighlightProvider.scala index 6cf6e067667..ba78b37523d 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentHighlightProvider.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentHighlightProvider.scala @@ -1,12 +1,32 @@ package org.enso.gateway.protocol.response.result.servercapabilities import io.circe.Encoder +import io.circe.syntax._ +import io.circe.generic.extras.semiauto.deriveUnwrappedEncoder import io.circe.generic.semiauto.deriveEncoder -/** The server provides document highlight support. */ -case class DocumentHighlightProvider() +/** Server capability to provide document highlight support. */ +sealed trait DocumentHighlightProvider object DocumentHighlightProvider { + + case class Bool(value: Boolean) extends DocumentHighlightProvider + object Bool { + implicit val boolEncoder: Encoder[Bool] = + deriveUnwrappedEncoder + } + + case class DocumentHighlightOptions(workDoneProgress: Option[Boolean] = None) + extends DocumentHighlightProvider + object DocumentHighlightOptions { + implicit val documentHighlightOptionsEncoder + : Encoder[DocumentHighlightOptions] = + deriveEncoder + } + implicit val serverCapabilitiesDocumentHighlightProviderEncoder : Encoder[DocumentHighlightProvider] = - deriveEncoder + Encoder.instance { + case boolean: Bool => boolean.asJson + case options: DocumentHighlightOptions => options.asJson + } } diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentLinkOptions.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentLinkOptions.scala new file mode 100644 index 00000000000..9082e8cbab7 --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentLinkOptions.scala @@ -0,0 +1,15 @@ +package org.enso.gateway.protocol.response.result.servercapabilities + +import io.circe.Encoder +import io.circe.generic.semiauto.deriveEncoder + +/** Server capability to provide document link support. */ +case class DocumentLinkOptions( + workDoneProgress: Option[Boolean] = None, + resolveProvider: Option[Boolean] = None +) +object DocumentLinkOptions { + implicit val serverCapabilitiesDocumentLinkOptionsEncoder + : Encoder[DocumentLinkOptions] = + deriveEncoder +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentLinkProvider.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentLinkProvider.scala deleted file mode 100644 index 6082d8800a8..00000000000 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentLinkProvider.scala +++ /dev/null @@ -1,12 +0,0 @@ -package org.enso.gateway.protocol.response.result.servercapabilities - -import io.circe.Encoder -import io.circe.generic.semiauto.deriveEncoder - -/** The server provides document link support. */ -case class DocumentLinkProvider() -object DocumentLinkProvider { - implicit val serverCapabilitiesDocumentLinkProviderEncoder - : Encoder[DocumentLinkProvider] = - deriveEncoder -} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentOnTypeFormattingOptions.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentOnTypeFormattingOptions.scala new file mode 100644 index 00000000000..f1966001348 --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentOnTypeFormattingOptions.scala @@ -0,0 +1,15 @@ +package org.enso.gateway.protocol.response.result.servercapabilities + +import io.circe.Encoder +import io.circe.generic.semiauto.deriveEncoder + +/** Server capability to provide document formatting on typing. */ +case class DocumentOnTypeFormattingOptions( + firstTriggerCharacter: String, + moreTriggerCharacter: Option[Seq[String]] +) +object DocumentOnTypeFormattingOptions { + implicit val serverCapabilitiesDocumentOnTypeFormattingOptionsEncoder + : Encoder[DocumentOnTypeFormattingOptions] = + deriveEncoder +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentOnTypeFormattingProvider.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentOnTypeFormattingProvider.scala deleted file mode 100644 index 91039b822b1..00000000000 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentOnTypeFormattingProvider.scala +++ /dev/null @@ -1,12 +0,0 @@ -package org.enso.gateway.protocol.response.result.servercapabilities - -import io.circe.Encoder -import io.circe.generic.semiauto.deriveEncoder - -/** The server provides document formatting on typing. */ -case class DocumentOnTypeFormattingProvider() -object DocumentOnTypeFormattingProvider { - implicit val serverCapabilitiesDocumentOnTypeFormattingProviderEncoder - : Encoder[DocumentOnTypeFormattingProvider] = - deriveEncoder -} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentRangeFormattingProvider.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentRangeFormattingProvider.scala index 4b6174bcdc5..25b43c786a0 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentRangeFormattingProvider.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentRangeFormattingProvider.scala @@ -1,12 +1,33 @@ package org.enso.gateway.protocol.response.result.servercapabilities import io.circe.Encoder +import io.circe.syntax._ +import io.circe.generic.extras.semiauto.deriveUnwrappedEncoder import io.circe.generic.semiauto.deriveEncoder -/** The server provides document range formatting. */ -case class DocumentRangeFormattingProvider() +/** Server capability to provide document range formatting. */ +sealed trait DocumentRangeFormattingProvider object DocumentRangeFormattingProvider { + + case class Bool(value: Boolean) extends DocumentRangeFormattingProvider + object Bool { + implicit val boolEncoder: Encoder[Bool] = + deriveUnwrappedEncoder + } + + case class DocumentRangeFormattingOptions( + workDoneProgress: Option[Boolean] = None + ) extends DocumentRangeFormattingProvider + object DocumentRangeFormattingOptions { + implicit val DocumentRangeFormattingOptiondEncoder + : Encoder[DocumentRangeFormattingOptions] = + deriveEncoder + } + implicit val serverCapabilitiesDocumentRangeFormattingProviderEncoder : Encoder[DocumentRangeFormattingProvider] = - deriveEncoder + Encoder.instance { + case boolean: Bool => boolean.asJson + case options: DocumentRangeFormattingOptions => options.asJson + } } diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentSymbolProvider.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentSymbolProvider.scala index 677d4f78df7..af99eca108b 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentSymbolProvider.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/DocumentSymbolProvider.scala @@ -1,12 +1,31 @@ package org.enso.gateway.protocol.response.result.servercapabilities import io.circe.Encoder +import io.circe.syntax._ +import io.circe.generic.extras.semiauto.deriveUnwrappedEncoder import io.circe.generic.semiauto.deriveEncoder -/** The server provides document symbol support. */ -case class DocumentSymbolProvider() +/** Server capability to provide document symbol support. */ +sealed trait DocumentSymbolProvider object DocumentSymbolProvider { + + case class Bool(value: Boolean) extends DocumentSymbolProvider + object Bool { + implicit val boolEncoder: Encoder[Bool] = + deriveUnwrappedEncoder + } + + case class DocumentSymbolOptions(workDoneProgress: Option[Boolean] = None) + extends DocumentSymbolProvider + object DocumentSymbolOptions { + implicit val documentSymbolOptionsEncoder: Encoder[DocumentSymbolOptions] = + deriveEncoder + } + implicit val serverCapabilitiesDocumentSymbolProviderEncoder : Encoder[DocumentSymbolProvider] = - deriveEncoder + Encoder.instance { + case boolean: Bool => boolean.asJson + case options: DocumentSymbolOptions => options.asJson + } } diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/ExecuteCommandOptions.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/ExecuteCommandOptions.scala index 578b1907834..2b2a590afaa 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/ExecuteCommandOptions.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/ExecuteCommandOptions.scala @@ -3,8 +3,11 @@ package org.enso.gateway.protocol.response.result.servercapabilities import io.circe.Encoder import io.circe.generic.semiauto.deriveEncoder -/** The server provides execute command support. */ -case class ExecuteCommandOptions() +/** Server capability to provide execute command support. */ +case class ExecuteCommandOptions( + workDoneProgress: Option[Boolean] = None, + commands: Seq[String] +) object ExecuteCommandOptions { implicit val serverCapabilitiesExecuteCommandOptionsEncoder : Encoder[ExecuteCommandOptions] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/Experimental.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/Experimental.scala index fc58d483373..17d9445eaeb 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/Experimental.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/Experimental.scala @@ -4,7 +4,7 @@ import io.circe.Encoder import io.circe.generic.extras.semiauto.deriveUnwrappedEncoder /** Experimental - * [[org.enso.gateway.protocol.response.result.ServerCapabilities]] + * [[org.enso.gateway.protocol.response.result.ServerCapabilities]]. */ case class Experimental(value: String) extends AnyVal object Experimental { diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/FoldingRangeProvider.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/FoldingRangeProvider.scala index 14513d964a2..d3e954fba11 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/FoldingRangeProvider.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/FoldingRangeProvider.scala @@ -1,12 +1,43 @@ package org.enso.gateway.protocol.response.result.servercapabilities import io.circe.Encoder +import io.circe.syntax._ +import io.circe.generic.extras.semiauto.deriveUnwrappedEncoder import io.circe.generic.semiauto.deriveEncoder +import org.enso.gateway.protocol.response.result.ServerCapabilities.DocumentSelector -/** The server provides folding provider support. */ -case class FoldingRangeProvider() +/** Server capability to provide folding provider support. */ +sealed trait FoldingRangeProvider object FoldingRangeProvider { + + case class Bool(value: Boolean) extends FoldingRangeProvider + object Bool { + implicit val boolEncoder: Encoder[Bool] = deriveUnwrappedEncoder + } + + case class FoldingRangeOptions(workDoneProgress: Option[Boolean] = None) + extends FoldingRangeProvider + object FoldingRangeOptions { + implicit val foldingRangeOptionsEncoder: Encoder[FoldingRangeOptions] = + deriveEncoder + } + + case class FoldingRangeRegistrationOptions( + documentSelector: Option[DocumentSelector] = None, + workDoneProgress: Option[Boolean] = None, + id: Option[String] = None + ) extends FoldingRangeProvider + object FoldingRangeRegistrationOptions { + implicit val foldingRangeRegistrationOptionsEncoder + : Encoder[FoldingRangeRegistrationOptions] = + deriveEncoder + } + implicit val serverCapabilitiesFoldingRangeProviderEncoder : Encoder[FoldingRangeProvider] = - deriveEncoder + Encoder.instance { + case boolean: Bool => boolean.asJson + case options: FoldingRangeOptions => options.asJson + case options: FoldingRangeRegistrationOptions => options.asJson + } } diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/HoverProvider.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/HoverProvider.scala index 62e0f59b522..c43fff15b0f 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/HoverProvider.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/HoverProvider.scala @@ -1,11 +1,28 @@ package org.enso.gateway.protocol.response.result.servercapabilities import io.circe.Encoder +import io.circe.generic.extras.semiauto.deriveUnwrappedEncoder import io.circe.generic.semiauto.deriveEncoder +import io.circe.syntax._ -/** The server provides hover support. */ -case class HoverProvider() +/** Server capability to provide hover support. */ +sealed trait HoverProvider object HoverProvider { + + case class Bool(value: Boolean) extends HoverProvider + object Bool { + implicit val boolEncoder: Encoder[Bool] = deriveUnwrappedEncoder + } + + case class HoverOptions(workDoneProgress: Option[Boolean] = None) + extends HoverProvider + object HoverOptions { + implicit val hoverOptionsEncoder: Encoder[HoverOptions] = deriveEncoder + } + implicit val serverCapabilitiesHoverProviderEncoder: Encoder[HoverProvider] = - deriveEncoder + Encoder.instance { + case boolean: Bool => boolean.asJson + case options: HoverOptions => options.asJson + } } diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/ImplementationProvider.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/ImplementationProvider.scala index d41bf06e8a2..8bee1307d2f 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/ImplementationProvider.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/ImplementationProvider.scala @@ -1,12 +1,43 @@ package org.enso.gateway.protocol.response.result.servercapabilities import io.circe.Encoder +import io.circe.syntax._ +import io.circe.generic.extras.semiauto.deriveUnwrappedEncoder import io.circe.generic.semiauto.deriveEncoder +import org.enso.gateway.protocol.response.result.ServerCapabilities.DocumentSelector -/** The server provides goto implementation support. */ -case class ImplementationProvider() +/** Server capability to provide "go to implementation" support. */ +sealed trait ImplementationProvider object ImplementationProvider { + + case class Bool(value: Boolean) extends ImplementationProvider + object Bool { + implicit val boolEncoder: Encoder[Bool] = deriveUnwrappedEncoder + } + + case class ImplementationOptions(workDoneProgress: Option[Boolean] = None) + extends ImplementationProvider + object ImplementationOptions { + implicit val implementationOptionsEncoder: Encoder[ImplementationOptions] = + deriveEncoder + } + + case class ImplementationRegistrationOptions( + documentSelector: Option[DocumentSelector] = None, + workDoneProgress: Option[Boolean] = None, + id: Option[String] = None + ) extends ImplementationProvider + object ImplementationRegistrationOptions { + implicit val implementationRegistrationOptionsEncoder + : Encoder[ImplementationRegistrationOptions] = + deriveEncoder + } + implicit val serverCapabilitiesImplementationProviderEncoder : Encoder[ImplementationProvider] = - deriveEncoder + Encoder.instance { + case boolean: Bool => boolean.asJson + case options: ImplementationOptions => options.asJson + case options: ImplementationRegistrationOptions => options.asJson + } } diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/ReferencesProvider.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/ReferencesProvider.scala index 32a2e0e1d73..bcedbe358c1 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/ReferencesProvider.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/ReferencesProvider.scala @@ -1,12 +1,30 @@ package org.enso.gateway.protocol.response.result.servercapabilities import io.circe.Encoder +import io.circe.syntax._ +import io.circe.generic.extras.semiauto.deriveUnwrappedEncoder import io.circe.generic.semiauto.deriveEncoder -/** The server provides find references support. */ -case class ReferencesProvider() +/** Server capability to provide find references support. */ +sealed trait ReferencesProvider object ReferencesProvider { + + case class Bool(value: Boolean) extends ReferencesProvider + object Bool { + implicit val boolEncoder: Encoder[Bool] = deriveUnwrappedEncoder + } + + case class ReferenceOptions(workDoneProgress: Option[Boolean] = None) + extends ReferencesProvider + object ReferenceOptions { + implicit val referenceOptionsEncoder: Encoder[ReferenceOptions] = + deriveEncoder + } + implicit val serverCapabilitiesReferencesProviderEncoder : Encoder[ReferencesProvider] = - deriveEncoder + Encoder.instance { + case boolean: Bool => boolean.asJson + case options: ReferenceOptions => options.asJson + } } diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/RenameProvider.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/RenameProvider.scala index 8777a50f15b..0ef58c773ee 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/RenameProvider.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/RenameProvider.scala @@ -1,15 +1,37 @@ package org.enso.gateway.protocol.response.result.servercapabilities import io.circe.Encoder +import io.circe.syntax._ +import io.circe.generic.extras.semiauto.deriveUnwrappedEncoder import io.circe.generic.semiauto.deriveEncoder -/** The server provides rename support. RenameOptions may only be specified if +/** Server capability to provide rename support. + * + * [[RenameProvider.RenameOptions]] may only be specified if * the client states that it supports `prepareSupport` in its initial * `initialize` request. */ -case class RenameProvider() +sealed trait RenameProvider object RenameProvider { + + case class Bool(value: Boolean) extends RenameProvider + object Bool { + implicit val boolEncoder: Encoder[Bool] = deriveUnwrappedEncoder + } + + case class RenameOptions( + workDoneProgress: Option[Boolean] = None, + prepareProvider: Option[Boolean] = None + ) extends RenameProvider + object RenameOptions { + implicit val renameOptionsEncoder: Encoder[RenameOptions] = + deriveEncoder + } + implicit val serverCapabilitiesRenameProviderEncoder : Encoder[RenameProvider] = - deriveEncoder + Encoder.instance { + case boolean: Bool => boolean.asJson + case options: RenameOptions => options.asJson + } } diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/SignatureHelpOptions.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/SignatureHelpOptions.scala index 3f0b99547b9..0b642371e46 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/SignatureHelpOptions.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/SignatureHelpOptions.scala @@ -3,8 +3,12 @@ package org.enso.gateway.protocol.response.result.servercapabilities import io.circe.Encoder import io.circe.generic.semiauto.deriveEncoder -/** The server provides signature help support. */ -case class SignatureHelpOptions() +/** Server capability to provide signature help support. */ +case class SignatureHelpOptions( + triggerCharacters: Option[Seq[String]] = None, + retriggerCharacters: Option[Seq[String]] = None, + workDoneProgress: Option[Boolean] = None +) object SignatureHelpOptions { implicit val serverCapabilitiesSignatureHelpOptionsEncoder : Encoder[SignatureHelpOptions] = diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/TextDocumentSync.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/TextDocumentSync.scala index b5a92f3d724..b0399c9ee53 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/TextDocumentSync.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/TextDocumentSync.scala @@ -1,16 +1,46 @@ package org.enso.gateway.protocol.response.result.servercapabilities import io.circe.Encoder +import io.circe.syntax._ +import io.circe.generic.extras.semiauto.deriveUnwrappedEncoder import io.circe.generic.semiauto.deriveEncoder +import org.enso.gateway.protocol.response.result.servercapabilities.textdocumentsync.TextDocumentSyncKind -/** Defines how text documents are synced. Is either a detailed structure - * defining each notification or for backwards compatibility the - * `TextDocumentSyncKind` number. If omitted it defaults to - * `TextDocumentSyncKind.None`. +/** Defines how text documents are synced. + * + * Is either a detailed structure defining each notification or for backwards + * compatibility the [[TextDocumentSyncKind]] number. If omitted it defaults to + * [[TextDocumentSyncKind.NoneKind]]. */ -case class TextDocumentSync() +sealed trait TextDocumentSync object TextDocumentSync { + + case class Number(value: Int) extends TextDocumentSync + object Number { + implicit val textDocumentSyncNumberEncoder: Encoder[Number] = + deriveUnwrappedEncoder + } + + case class TextDocumentSyncOptions( + openClose: Option[Boolean] = None, + change: Option[TextDocumentSyncKind] = None + ) extends TextDocumentSync + object TextDocumentSyncOptions { + implicit val textDocumentSyncTextDocumentSyncOptionsEncoder + : Encoder[TextDocumentSyncOptions] = deriveEncoder + } + + case class WillSaveWaitUntil(willSaveWaitUntil: Boolean) + extends TextDocumentSync + object WillSaveWaitUntil { + implicit val textDocumentSyncWillSaveWaitUntilEncoder + : Encoder[WillSaveWaitUntil] = deriveEncoder + } + implicit val serverCapabilitiesTextDocumentSyncEncoder - : Encoder[TextDocumentSync] = - deriveEncoder + : Encoder[TextDocumentSync] = Encoder.instance { + case number: Number => number.asJson + case capability: TextDocumentSyncOptions => capability.asJson + case capability: WillSaveWaitUntil => capability.asJson + } } diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/TypeDefinitionProvider.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/TypeDefinitionProvider.scala index 5fdd09a53ad..2290e5f4ebf 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/TypeDefinitionProvider.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/TypeDefinitionProvider.scala @@ -1,12 +1,44 @@ package org.enso.gateway.protocol.response.result.servercapabilities import io.circe.Encoder +import io.circe.syntax._ +import io.circe.generic.extras.semiauto.deriveUnwrappedEncoder import io.circe.generic.semiauto.deriveEncoder +import org.enso.gateway.protocol.response.result.ServerCapabilities.DocumentSelector -/** The server provides goto type definition support. */ -case class TypeDefinitionProvider() +/** Server capability to provide "go to type definition" support. */ +sealed trait TypeDefinitionProvider object TypeDefinitionProvider { + + case class Bool(value: Boolean) extends TypeDefinitionProvider + object Bool { + implicit val boolEncoder: Encoder[Bool] = deriveUnwrappedEncoder + } + + case class TypeDefinitionOptions(workDoneProgress: Option[Boolean] = None) + extends TypeDefinitionProvider + object TypeDefinitionOptions { + implicit val typeDefinitionOptionsEncoder: Encoder[TypeDefinitionOptions] = + deriveEncoder + } + + case class TypeDefinitionRegistrationOptions( + documentSelector: Option[DocumentSelector] = None, + workDoneProgress: Option[Boolean] = None, + id: Option[String] = None + ) extends TypeDefinitionProvider + + object TypeDefinitionRegistrationOptions { + implicit val typeDefinitionRegistrationOptionsEncoder + : Encoder[TypeDefinitionRegistrationOptions] = + deriveEncoder + } + implicit val serverCapabilitiesTypeDefinitionProviderEncoder : Encoder[TypeDefinitionProvider] = - deriveEncoder + Encoder.instance { + case boolean: Bool => boolean.asJson + case options: TypeDefinitionOptions => options.asJson + case options: TypeDefinitionRegistrationOptions => options.asJson + } } diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/Workspace.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/Workspace.scala index 9046c9f46a2..c2d3b3ed50e 100644 --- a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/Workspace.scala +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/Workspace.scala @@ -2,11 +2,14 @@ package org.enso.gateway.protocol.response.result.servercapabilities import io.circe.Encoder import io.circe.generic.semiauto.deriveEncoder +import org.enso.gateway.protocol.response.result.servercapabilities.workspace.WorkspaceFoldersServerCapabilities -/** Workspace specific +/** Workspace-specific * [[org.enso.gateway.protocol.response.result.ServerCapabilities]]. */ -case class Workspace() +case class Workspace( + workspaceFolders: Option[WorkspaceFoldersServerCapabilities] = None +) object Workspace { implicit val serverCapabilitiesWorkspaceEncoder: Encoder[Workspace] = deriveEncoder diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/declarationprovider/DocumentFilter.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/declarationprovider/DocumentFilter.scala new file mode 100644 index 00000000000..4ba1ed75360 --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/declarationprovider/DocumentFilter.scala @@ -0,0 +1,15 @@ +package org.enso.gateway.protocol.response.result.servercapabilities.declarationprovider + +import io.circe.Encoder +import io.circe.generic.semiauto.deriveEncoder + +/** A document filter. */ +case class DocumentFilter( + language: Option[String] = None, + scheme: Option[String] = None, + pattern: Option[String] = None +) +object DocumentFilter { + implicit val documentFilterEncoder: Encoder[DocumentFilter] = + deriveEncoder +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/textdocumentsync/TextDocumentSyncKind.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/textdocumentsync/TextDocumentSyncKind.scala new file mode 100644 index 00000000000..e63ff1991c9 --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/textdocumentsync/TextDocumentSyncKind.scala @@ -0,0 +1,28 @@ +package org.enso.gateway.protocol.response.result.servercapabilities.textdocumentsync + +import io.circe.Encoder + +/** Kind of document sync. */ +sealed abstract class TextDocumentSyncKind(val value: Int) +object TextDocumentSyncKind { + private val none = 0 + private val full = 1 + private val incremental = 2 + + /** Signals that documents should not be synced at all. */ + object NoneKind extends TextDocumentSyncKind(none) + + /** Signals that documents are synced by always sending the full content of + * the document. + */ + object Full extends TextDocumentSyncKind(full) + + /** Signals that documents are synced by sending the full content on open. + * + * After that only incremental updates to the document are sent. + */ + object Incremental extends TextDocumentSyncKind(incremental) + + implicit val textDocumentSyncKindEncoder: Encoder[TextDocumentSyncKind] = + Encoder.encodeInt.contramap(_.value) +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/workspace/ChangeNotifications.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/workspace/ChangeNotifications.scala new file mode 100644 index 00000000000..c33fefeb24d --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/workspace/ChangeNotifications.scala @@ -0,0 +1,30 @@ +package org.enso.gateway.protocol.response.result.servercapabilities.workspace + +import io.circe.Encoder +import io.circe.syntax._ +import io.circe.generic.extras.semiauto.deriveUnwrappedEncoder + +/** Part of [[WorkspaceFoldersServerCapabilities]]. */ +sealed trait ChangeNotifications +object ChangeNotifications { + + /** String [[ChangeNotifications]]. */ + case class Text(value: String) extends ChangeNotifications + object Text { + implicit val textEncoder: Encoder[Text] = + deriveUnwrappedEncoder + } + + /** Boolean [[ChangeNotifications]]. */ + case class Bool(value: Boolean) extends ChangeNotifications + object Bool { + implicit val boolEncoder: Encoder[Bool] = + deriveUnwrappedEncoder + } + + implicit val textEncoder: Encoder[ChangeNotifications] = + Encoder.instance { + case text: Text => text.asJson + case boolean: Bool => boolean.asJson + } +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/workspace/WorkspaceFoldersServerCapabilities.scala b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/workspace/WorkspaceFoldersServerCapabilities.scala new file mode 100644 index 00000000000..62297576a9e --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/protocol/response/result/servercapabilities/workspace/WorkspaceFoldersServerCapabilities.scala @@ -0,0 +1,17 @@ +package org.enso.gateway.protocol.response.result.servercapabilities.workspace + +import io.circe.Encoder +import io.circe.generic.semiauto.deriveEncoder + +/** @see + * [[org.enso.gateway.protocol.response.result.servercapabilities.Workspace]]. + */ +case class WorkspaceFoldersServerCapabilities( + supported: Option[Boolean] = None, + changeNotifications: Option[ChangeNotifications] = None +) +object WorkspaceFoldersServerCapabilities { + implicit val workspaceFoldersServerCapabilitiesEncoder + : Encoder[WorkspaceFoldersServerCapabilities] = + deriveEncoder +} diff --git a/engine/gateway/src/main/scala/org/enso/gateway/server/Config.scala b/engine/gateway/src/main/scala/org/enso/gateway/server/Config.scala new file mode 100644 index 00000000000..ff6fd363449 --- /dev/null +++ b/engine/gateway/src/main/scala/org/enso/gateway/server/Config.scala @@ -0,0 +1,55 @@ +package org.enso.gateway.server + +import com.typesafe.config.{ConfigFactory, Config => TypesafeConfig} + +import scala.concurrent.duration.FiniteDuration +import scala.concurrent.duration._ + +/** Describes endpoint to which [[org.enso.gateway.Server]] can bind and + * timeouts. + * + * Gets default values of parameters from typesafe config. + * + * @param port Port of endpoint. + * @param host Host of endpoint. + * @param route Route of endpoint. + * @param timeout Timeout for waiting response after request. + * @param bindingTimeout Timeout for waiting binding result. + * @param hardDeadline Timeout for waiting result of binding termination. + */ +class Config( + val port: Int = Config.port, + val host: String = Config.host, + val route: String = Config.route, + val timeout: FiniteDuration = Config.timeout, + val bindingTimeout: FiniteDuration = Config.bindingTimeout, + val hardDeadline: FiniteDuration = Config.hardDeadline +) { + val addressString: String = s"ws://$host:$port" +} + +object Config { + private val gatewayPath = "gateway" + private val serverPath = "server" + private val hostPath = "host" + private val portPath = "port" + private val routePath = "route" + private val timeoutPath = "timeoutSecs" + private val bindingTimeoutPath = "bindingTimeoutSecs" + private val hardDeadlinePath = "hardDeadlineSecs" + + private val gatewayConfig: TypesafeConfig = + ConfigFactory.load.getConfig(gatewayPath) + private val serverConfig: TypesafeConfig = + gatewayConfig.getConfig(serverPath) + + private val host: String = serverConfig.getString(hostPath) + private val port: Int = serverConfig.getInt(portPath) + private val route: String = serverConfig.getString(routePath) + private val timeout: FiniteDuration = + serverConfig.getLong(timeoutPath).seconds + private val bindingTimeout: FiniteDuration = + serverConfig.getLong(bindingTimeoutPath).seconds + private val hardDeadline: FiniteDuration = + serverConfig.getLong(hardDeadlinePath).seconds +} diff --git a/engine/gateway/src/test/scala/org/enso/gateway/GatewaySpec.scala b/engine/gateway/src/test/scala/org/enso/gateway/GatewayJsonSpec.scala similarity index 62% rename from engine/gateway/src/test/scala/org/enso/gateway/GatewaySpec.scala rename to engine/gateway/src/test/scala/org/enso/gateway/GatewayJsonSpec.scala index 1123edf67df..a455de7f8ec 100644 --- a/engine/gateway/src/test/scala/org/enso/gateway/GatewaySpec.scala +++ b/engine/gateway/src/test/scala/org/enso/gateway/GatewayJsonSpec.scala @@ -7,8 +7,12 @@ import akka.http.scaladsl.model.ws.{Message, TextMessage, WebSocketRequest} import akka.stream.ActorMaterializer import akka.stream.scaladsl.{Flow, Keep, Sink, Source} import io.circe.Json -import org.enso.gateway.Server.Config -import org.enso.gateway.TestJson.{Initialize, WrongJsonrpc, WrongMethod} +import org.enso.gateway.TestJson.{ + Initialize, + Shutdown, + WrongJsonrpc, + WrongMethod +} import org.enso.{Gateway, LanguageServer} import org.scalatest.{ Assertion, @@ -18,10 +22,12 @@ import org.scalatest.{ Matchers } import io.circe.parser.parse +import org.enso.gateway.server.Config -import scala.concurrent.Future +import scala.concurrent.{Await, Future} +import scala.concurrent.duration._ -class GatewaySpec +class GatewayJsonSpec extends AsyncFlatSpec with Matchers with BeforeAndAfterAll @@ -32,22 +38,34 @@ class GatewaySpec import system.dispatcher - override def beforeAll: Unit = { - val languageServerActorName = "languageServer" - val gatewayActorName = "gateway" - val languageServer: ActorRef = - system.actorOf(LanguageServer.props(null), languageServerActorName) - val gateway: ActorRef = - system.actorOf(Gateway.props(languageServer), gatewayActorName) + private val languageServerActorName = "testingLanguageServer" + private val gatewayActorName = "testingGateway" + private val languageServer: ActorRef = + system.actorOf(LanguageServer.props(null), languageServerActorName) + private val gateway: ActorRef = + system.actorOf(Gateway.props(languageServer), gatewayActorName) - val jsonRpcController = new JsonRpcController(gateway) - val server = new Server(jsonRpcController) + private val jsonRpcController = new JsonRpcController(gateway) + + private val config = { + val port = 30001 + val host = "localhost" + new Config(port, host) + } + + private val server = new Server(jsonRpcController, config) + + override def beforeAll: Unit = { server.run() } override def afterAll: Unit = { - system.terminate() - () + val terminationFuture = for { + _ <- server.shutdown() + _ <- system.terminate() + } yield () + val timeout = 5.seconds + Await.result(terminationFuture, timeout) } "Gateway" should "reply with a proper response to request with initialize method" in { @@ -62,19 +80,23 @@ class GatewaySpec checkRequestResponse(WrongMethod) } + "Gateway" should "reply with a proper response to request with shutdown method" in { + checkRequestResponse(Shutdown) + } + private def checkRequestResponse( - testJsons: TestJson + testJson: TestJson ): Future[Assertion] = { Given("server replies with responses to requests") val messageToMessageFlow: Flow[Message, Message, Future[Message]] = createFlow( - TextMessage(testJsons.request.toString) + TextMessage(testJson.request.toString) ) When("server receives request") val (_, messageFuture) = Http() .singleWebSocketRequest( - WebSocketRequest(Config.addressString), + WebSocketRequest(config.addressString), messageToMessageFlow ) @@ -82,7 +104,7 @@ class GatewaySpec messageFuture.map { case message: TextMessage.Strict => val actualResponse = parse(message.text).getOrElse(Json.Null) - assert(actualResponse === testJsons.expectedResponse) + assert(actualResponse === testJson.expectedResponse) case _ => assert(false, "binary or streamed text message") } } diff --git a/engine/gateway/src/test/scala/org/enso/gateway/GatewayMessageSpec.scala b/engine/gateway/src/test/scala/org/enso/gateway/GatewayMessageSpec.scala new file mode 100644 index 00000000000..0a546fdebec --- /dev/null +++ b/engine/gateway/src/test/scala/org/enso/gateway/GatewayMessageSpec.scala @@ -0,0 +1,43 @@ +package org.enso.gateway + +import akka.actor.{ActorRef, ActorSystem} +import akka.testkit.{ImplicitSender, TestKit} +import org.enso.{Gateway, LanguageServer} +import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike} +import org.enso.gateway.TestMessage.{Initialize, Shutdown} +import org.enso.gateway.TestNotification.{Exit, Initialized} + +class GatewayMessageSpec() + extends TestKit(ActorSystem("GatewayMessageSpec")) + with ImplicitSender + with WordSpecLike + with Matchers + with BeforeAndAfterAll { + + private val languageServerActorName = "testingLanguageServer" + private val gatewayActorName = "testingGateway" + private val languageServer: ActorRef = + system.actorOf(LanguageServer.props(null), languageServerActorName) + protected val gateway: ActorRef = + system.actorOf(Gateway.props(languageServer), gatewayActorName) + + override def afterAll: Unit = { + TestKit.shutdownActorSystem(system) + } + + "Gateway" must { + "properly handle init/shutdown workflow" in { + gateway ! Initialize.request + expectMsg(Initialize.response) + + gateway ! Initialized.notification + expectNoMessage() + + gateway ! Shutdown.request + expectMsg(Shutdown.response) + + gateway ! Exit.notification + expectNoMessage() + } + } +} diff --git a/engine/gateway/src/test/scala/org/enso/gateway/TestJson.scala b/engine/gateway/src/test/scala/org/enso/gateway/TestJson.scala index 1517e24b6a7..ec0e4b47ddc 100644 --- a/engine/gateway/src/test/scala/org/enso/gateway/TestJson.scala +++ b/engine/gateway/src/test/scala/org/enso/gateway/TestJson.scala @@ -81,4 +81,21 @@ object TestJson { } }""" } + + object Shutdown extends TestJson { + val request = + json""" + { + "jsonrpc": "2.0", + "id": 10, + "method": "shutdown" + }""" + + val expectedResponse = + json""" + { + "jsonrpc" : "2.0", + "id" : 10 + }""" + } } diff --git a/engine/gateway/src/test/scala/org/enso/gateway/TestMessage.scala b/engine/gateway/src/test/scala/org/enso/gateway/TestMessage.scala new file mode 100644 index 00000000000..0e7e53246a0 --- /dev/null +++ b/engine/gateway/src/test/scala/org/enso/gateway/TestMessage.scala @@ -0,0 +1,69 @@ +package org.enso.gateway + +import org.enso.gateway.JsonRpcController.jsonRpcVersion +import org.enso.gateway.protocol.request.Param.{ClientCapabilities, ClientInfo} +import org.enso.gateway.protocol.{Request, Requests, Response} +import org.enso.gateway.protocol.request.Params +import org.enso.gateway.protocol.request.Params.{InitializeParams, VoidParams} +import org.enso.gateway.protocol.response.Result.{InitializeResult, NullResult} +import org.enso.gateway.protocol.response.result.{ + ServerCapabilities, + ServerInfo +} +import TestMessageDefinitions._ + +trait TestMessage[P <: Params] { + def request: Request[P] + + def response: Response +} + +object TestMessage { + + object Initialize extends TestMessage[InitializeParams] { + val request = Request( + jsonrpc = jsonRpcVersion, + id = id1, + method = Requests.Initialize.method, + params = Some( + InitializeParams( + clientInfo = Some( + ClientInfo( + name = clientName, + version = Some(clientVersion) + ) + ), + capabilities = ClientCapabilities() + ) + ) + ) + + val response = Response.result( + id = Some(id1), + result = InitializeResult( + capabilities = ServerCapabilities(), + serverInfo = Some( + ServerInfo( + name = serverName, + version = Some(serverVersion) + ) + ) + ) + ) + } + + object Shutdown extends TestMessage[VoidParams] { + val request = Request( + jsonrpc = jsonRpcVersion, + id = id2, + method = Requests.Shutdown.method, + params = Some(VoidParams()) + ) + + val response = Response.result( + id = Some(id2), + result = NullResult + ) + } + +} diff --git a/engine/gateway/src/test/scala/org/enso/gateway/TestMessageDefinitions.scala b/engine/gateway/src/test/scala/org/enso/gateway/TestMessageDefinitions.scala new file mode 100644 index 00000000000..2707a71d899 --- /dev/null +++ b/engine/gateway/src/test/scala/org/enso/gateway/TestMessageDefinitions.scala @@ -0,0 +1,12 @@ +package org.enso.gateway + +import org.enso.gateway.protocol.Id + +object TestMessageDefinitions { + val clientName = "Enso IDE" + val clientVersion = "1.0" + val serverName = "Enso Language Server" + val serverVersion = "1.0" + val id1 = Id.Number(1) + val id2 = Id.Number(2) +} diff --git a/engine/gateway/src/test/scala/org/enso/gateway/TestNotification.scala b/engine/gateway/src/test/scala/org/enso/gateway/TestNotification.scala new file mode 100644 index 00000000000..42ebc590a8f --- /dev/null +++ b/engine/gateway/src/test/scala/org/enso/gateway/TestNotification.scala @@ -0,0 +1,30 @@ +package org.enso.gateway + +import org.enso.gateway.JsonRpcController.jsonRpcVersion +import org.enso.gateway.protocol.{Notification, Notifications} +import org.enso.gateway.protocol.request.Params +import org.enso.gateway.protocol.request.Params.VoidParams + +trait TestNotification[P <: Params] { + def notification: Notification[P] +} + +object TestNotification { + + object Initialized extends TestNotification[VoidParams] { + val notification = Notification( + jsonrpc = jsonRpcVersion, + method = Notifications.Initialized.method, + params = Some(VoidParams()) + ) + } + + object Exit extends TestNotification[VoidParams] { + val notification = Notification( + jsonrpc = jsonRpcVersion, + method = Notifications.Exit.method, + params = Some(VoidParams()) + ) + } + +} diff --git a/engine/language-server/src/main/scala/org/enso/LanguageServer.scala b/engine/language-server/src/main/scala/org/enso/LanguageServer.scala index b0836f7cb26..66fa6ecedb3 100644 --- a/engine/language-server/src/main/scala/org/enso/LanguageServer.scala +++ b/engine/language-server/src/main/scala/org/enso/LanguageServer.scala @@ -1,41 +1,52 @@ package org.enso -import akka.actor.{Actor, ActorLogging, ActorRef, Props} +import akka.actor.{Actor, ActorLogging, Props} +import org.enso.languageserver.{ + NotificationReceived, + Notifications, + RequestReceived, + Requests +} import org.enso.polyglot.ExecutionContext -/** The language server component wraps the runtime itself, and uses the APIs - * provided by the interpreter and the compiler to service the requests sent - * to the Enso Engine. +/** The Language Server component of Enso Engine. + * + * Wraps the runtime itself, and uses the APIs provided by the interpreter + * and the compiler to service the requests sent to the Enso Engine. + * + * @param context Polyglot Execution context. */ class LanguageServer(context: ExecutionContext) extends Actor with ActorLogging { override def receive: Receive = { - case LanguageServer.Initialize(id, actorRef) => + case Requests.Initialize(id, actorRef) => val msg = "LanguageServer: Initialize received" log.info(msg) - sender() ! LanguageServer.InitializeReceived(id, actorRef) + sender() ! RequestReceived.Initialize(id, actorRef) - case LanguageServer.Initialized => + case Requests.Shutdown(id, actorRef) => + val msg = "LanguageServer: Shutdown received" + log.info(msg) + sender() ! RequestReceived.Shutdown(id, actorRef) + + case Notifications.Initialized => val msg = "LanguageServer: Initialized received" log.info(msg) - sender() ! LanguageServer.InitializedReceived + sender() ! NotificationReceived.Initialized + + case Notifications.Exit => + val msg = "LanguageServer: Exit received" + log.info(msg) + sender() ! NotificationReceived.Exit + + case requestOrNotification => + val msg = "LanguageServer: unexpected request or notification " + + requestOrNotification + log.error(msg) } } object LanguageServer { - - /** Akka message sent by Gateway received LSP request `initialize`. */ - case class Initialize(id: Int, replyTo: ActorRef) - - /** Akka message sent by Gateway received LSP notification `initialized`. */ - case object Initialized - - /** Language server response to [[Initialize]]. */ - case class InitializeReceived(id: Int, replyTo: ActorRef) - - /** Language server response to [[Initialized]]. */ - case object InitializedReceived - def props(context: ExecutionContext): Props = Props(new LanguageServer(context)) } diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/Id.scala b/engine/language-server/src/main/scala/org/enso/languageserver/Id.scala new file mode 100644 index 00000000000..4f3ed14cb92 --- /dev/null +++ b/engine/language-server/src/main/scala/org/enso/languageserver/Id.scala @@ -0,0 +1,13 @@ +package org.enso.languageserver + +/** Id of [[Requests]], [[RequestReceived]]. */ +sealed trait Id +object Id { + + /** A number id. */ + case class Number(value: Int) extends Id + + /** A string id. */ + case class Text(value: String) extends Id + +} diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/NotificationReceived.scala b/engine/language-server/src/main/scala/org/enso/languageserver/NotificationReceived.scala new file mode 100644 index 00000000000..e824c9a873c --- /dev/null +++ b/engine/language-server/src/main/scala/org/enso/languageserver/NotificationReceived.scala @@ -0,0 +1,12 @@ +package org.enso.languageserver + +/** Language server responses to [[Notifications]]. */ +object NotificationReceived { + + /** Language server response to [[Notifications.Initialized]]. */ + case object Initialized + + /** Language server response to [[Notifications.Exit]]. */ + case object Exit + +} diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/Notifications.scala b/engine/language-server/src/main/scala/org/enso/languageserver/Notifications.scala new file mode 100644 index 00000000000..90bd7e29fd9 --- /dev/null +++ b/engine/language-server/src/main/scala/org/enso/languageserver/Notifications.scala @@ -0,0 +1,12 @@ +package org.enso.languageserver + +/** Akka messages sent by Gateway received LSP notifications. */ +object Notifications { + + /** Akka message sent by Gateway received LSP notification `initialized`. */ + case object Initialized + + /** Akka message sent by Gateway received LSP notification `exit`. */ + case object Exit + +} diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/RequestReceived.scala b/engine/language-server/src/main/scala/org/enso/languageserver/RequestReceived.scala new file mode 100644 index 00000000000..e91748f3a90 --- /dev/null +++ b/engine/language-server/src/main/scala/org/enso/languageserver/RequestReceived.scala @@ -0,0 +1,14 @@ +package org.enso.languageserver + +import akka.actor.ActorRef + +/** Language server responses to [[Requests]]. */ +object RequestReceived { + + /** Language server response to [[Requests.Initialize]]. */ + case class Initialize(id: Id, replyTo: ActorRef) + + /** Language server response to [[Requests.Shutdown]]. */ + case class Shutdown(id: Id, replyTo: ActorRef) + +} diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/Requests.scala b/engine/language-server/src/main/scala/org/enso/languageserver/Requests.scala new file mode 100644 index 00000000000..6f4ce48d932 --- /dev/null +++ b/engine/language-server/src/main/scala/org/enso/languageserver/Requests.scala @@ -0,0 +1,17 @@ +package org.enso.languageserver + +import akka.actor.ActorRef + +/** Akka messages sent by Gateway received LSP requests. */ +object Requests { + + /** Akka message sent by Gateway received LSP request `initialize`. */ + case class Initialize( + id: Id, + replyTo: ActorRef + ) + + /** Akka message sent by Gateway received LSP request `shutdown`. */ + case class Shutdown(id: Id, replyTo: ActorRef) + +} diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/LanguageServerSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/LanguageServerSpec.scala new file mode 100644 index 00000000000..a0f695ab58d --- /dev/null +++ b/engine/language-server/src/test/scala/org/enso/languageserver/LanguageServerSpec.scala @@ -0,0 +1,46 @@ +package org.enso.languageserver + +import akka.actor.{ActorRef, ActorSystem} +import akka.testkit.{ImplicitSender, TestKit, TestProbe} +import org.enso.LanguageServer +import org.enso.languageserver.Notifications.{Exit, Initialized} +import org.enso.languageserver.Requests.{Initialize, Shutdown} +import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike} + +class LanguageServerSpec() + extends TestKit(ActorSystem("LanguageServerSpec")) + with ImplicitSender + with WordSpecLike + with Matchers + with BeforeAndAfterAll { + + private val languageServerActorName = "testingLanguageServer" + private val languageServer: ActorRef = + system.actorOf(LanguageServer.props(null), languageServerActorName) + + override def afterAll: Unit = { + TestKit.shutdownActorSystem(system) + } + + "Language Server" must { + "properly handle init/shutdown workflow" in { + val probe = TestProbe() + val probeRef = probe.ref + + val id1 = Id.Number(1) + val id2 = Id.Number(2) + + languageServer ! Initialize(id1, probeRef) + expectMsg(RequestReceived.Initialize(id1, probeRef)) + + languageServer ! Initialized + expectMsg(NotificationReceived.Initialized) + + languageServer ! Shutdown(id2, probeRef) + expectMsg(RequestReceived.Shutdown(id2, probeRef)) + + languageServer ! Exit + expectMsg(NotificationReceived.Exit) + } + } +} diff --git a/engine/runner/src/main/scala/org/enso/runner/Main.scala b/engine/runner/src/main/scala/org/enso/runner/Main.scala index 761f6acfcc7..5eb23420f23 100644 --- a/engine/runner/src/main/scala/org/enso/runner/Main.scala +++ b/engine/runner/src/main/scala/org/enso/runner/Main.scala @@ -14,6 +14,8 @@ import org.enso.gateway.JsonRpcController import scala.io.StdIn import scala.util.Try +import scala.concurrent.Await +import scala.concurrent.duration._ /** The main CLI entry point class. */ object Main { @@ -185,6 +187,7 @@ object Main { implicit val system: ActorSystem = ActorSystem() implicit val materializer: ActorMaterializer = ActorMaterializer.create(system) + import system.dispatcher val languageServerActorName = "languageServer" val gatewayActorName = "gateway" @@ -194,11 +197,17 @@ object Main { system.actorOf(Gateway.props(languageServer), gatewayActorName) val jsonRpcController = new JsonRpcController(gateway) - val server = new enso.gateway.Server(jsonRpcController) + val config = new enso.gateway.server.Config + val server = new enso.gateway.Server(jsonRpcController, config) server.run() StdIn.readLine() - system.terminate() + val terminationFuture = for { + _ <- server.shutdown() + _ <- system.terminate() + } yield () + val timeout = 5.seconds + Await.result(terminationFuture, timeout) exitSuccess() }