Subset of LSP - Part 1 (#453)

* Rename language-server -> runner, add language-server, gateway

* Add entry point --lsp

* Add Gateway, LanguageServer

* Add stab for Initialize

* Add stubs for Initialize, Initialized

* Add GatewayTest

* fix PR

* increase timeout

* merge with master

* fix compilation after merge

* reformat with scalafmt

* Add TODOs

* Add doc for gateway

* Update CONTRIBUTING.md

* Refactor code for PR

* Add Request#response(..)

* Make Initialize, Initialized extractor objects

* Refactor for -> map

* Fix docs

* Remove DerivationConfig

* Make Request, Notification polymorphic

* Add Param.Array, Params.Array

* Replace Decoder#apply -> tryDecode

* Refactor code

* Add docs

* Refactor code

* Refactor code

* Refactor code

* Make gateway a pure actor

* Add client capabilities

* Add server capabilities

* Add docs for capabilities

* Add docs

* Add docs

* Fix Server.Config

* Update doc for Server

* Add requests, notifications and params

* Improve PR

* Rename Protocol -> JsonRpcController

* Add docs

* Add requests and notifications

* Fix Result

* Add requests and notifications

* Add WillSaveTextDocumentWaitUntil request params and result

* Add params

* Add tests for requests

* Add textDocumentSync.willSaveWaitUntil server capability

* Handle text id

* Fix Edit workspace client capability

* Clean up

* Add initialize, initialized, shutdown, exit

* Add docs

* Fix identation

* Fix identation

* Refactor code

* Add docs

* Improve PR

* Add tests

* Fix docs for RequestExtractor

* Fix docs
This commit is contained in:
Dmytro Mitin 2020-01-27 13:23:32 +02:00 committed by GitHub
parent 175212bf4c
commit 3412606e2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
111 changed files with 1941 additions and 376 deletions

View File

@ -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)

View File

@ -3,7 +3,9 @@ gateway {
host = "localhost"
port = 30000
route = ""
timeout = 5
timeoutSecs = 5
bindingTimeoutSecs = 5
hardDeadlineSecs = 5
}
languageServer {

View File

@ -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))
}
}

View File

@ -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(

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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

View File

@ -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(

View File

@ -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")
}

View File

@ -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.

View File

@ -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

View File

@ -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(

View File

@ -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")
}

View File

@ -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.

View File

@ -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,

View File

@ -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
}
}

View File

@ -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] =

View File

@ -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,

View File

@ -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

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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] =

View File

@ -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] =

View File

@ -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

View File

@ -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] =

View File

@ -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] =

View File

@ -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] =

View File

@ -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] =

View File

@ -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] =

View File

@ -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] =

View File

@ -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] =

View File

@ -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

View File

@ -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] =

View File

@ -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

View File

@ -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] =

View File

@ -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] =

View File

@ -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] =

View File

@ -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] =

View File

@ -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

View File

@ -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] =

View File

@ -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

View File

@ -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] =

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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] =

View File

@ -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] =

View File

@ -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

View File

@ -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] =

View File

@ -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] =

View File

@ -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
}

View File

@ -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
}

View File

@ -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(

View File

@ -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
}
}

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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] =

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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] =

View File

@ -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 {

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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] =

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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

View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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")
}
}

View File

@ -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()
}
}
}

View File

@ -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
}"""
}
}

Some files were not shown because too many files have changed in this diff Show More