mirror of
https://github.com/enso-org/enso.git
synced 2024-12-22 23:01:29 +03:00
Implement Suggestions Updates API (#930)
This commit is contained in:
parent
f0551f7693
commit
8ecc786be6
@ -626,6 +626,7 @@ lazy val `polyglot-api` = project
|
||||
)
|
||||
.dependsOn(pkg)
|
||||
.dependsOn(`text-buffer`)
|
||||
.dependsOn(`searcher`)
|
||||
|
||||
lazy val `language-server` = (project in file("engine/language-server"))
|
||||
.settings(
|
||||
@ -663,6 +664,7 @@ lazy val `language-server` = (project in file("engine/language-server"))
|
||||
.dependsOn(`json-rpc-server`)
|
||||
.dependsOn(`json-rpc-server-test` % Test)
|
||||
.dependsOn(`text-buffer`)
|
||||
.dependsOn(`searcher`)
|
||||
|
||||
lazy val runtime = (project in file("engine/runtime"))
|
||||
.configs(Benchmark)
|
||||
|
@ -55,7 +55,7 @@ transport formats, please look [here](./protocol-architecture).
|
||||
- [`file/receivesTreeUpdates`](#filereceivestreeupdates)
|
||||
- [`executionContext/canModify`](#executioncontextcanmodify)
|
||||
- [`executionContext/receivesUpdates`](#executioncontextreceivesupdates)
|
||||
- [`search/receivesSuggestionsDatabaseUpdates`](#receivessuggestionsdatabaseupdates)
|
||||
- [`search/receivesSuggestionsDatabaseUpdates`](#searchreceivessuggestionsdatabaseupdates)
|
||||
- [File Management Operations](#file-management-operations)
|
||||
- [`file/write`](#filewrite)
|
||||
- [`file/read`](#fileread)
|
||||
@ -162,6 +162,10 @@ An identifier used for execution contexts.
|
||||
type ContextId = UUID;
|
||||
```
|
||||
|
||||
```typescript
|
||||
type SuggestionEntryId = number;
|
||||
```
|
||||
|
||||
### `StackItem`
|
||||
A representation of an executable position in code, used by the execution APIs.
|
||||
|
||||
@ -236,21 +240,19 @@ The argument of a [`SuggestionEntry`](#suggestionentry).
|
||||
|
||||
#### Format
|
||||
|
||||
``` idl
|
||||
namespace org.enso.languageserver.protocol.binary;
|
||||
|
||||
```typescript
|
||||
// The argument of an atom, method or function suggestion
|
||||
table SuggestionEntryArgument {
|
||||
interface SuggestionEntryArgument {
|
||||
// The argument name
|
||||
name: string (required);
|
||||
name: string;
|
||||
// The arguement type. String 'Any' is used to specify genric types
|
||||
type: string (required);
|
||||
type: string;
|
||||
// Indicates whether the argument is lazy
|
||||
isSuspended: bool (required);
|
||||
isSuspended: bool;
|
||||
// Indicates whether the argument has default value
|
||||
hasDefault: bool (required);
|
||||
hasDefault: bool;
|
||||
// Optional default value
|
||||
defaultValue: string;
|
||||
defaultValue?: string;
|
||||
}
|
||||
```
|
||||
|
||||
@ -259,46 +261,58 @@ The language construct that can be returned as a suggestion.
|
||||
|
||||
#### Format
|
||||
|
||||
``` idl
|
||||
namespace org.enso.languageserver.protocol.binary;
|
||||
```typescript
|
||||
// The definition scope
|
||||
interface SuggestionEntryScope {
|
||||
|
||||
// The start of the definition scope
|
||||
start: number;
|
||||
// The end of the definition scope
|
||||
end: number;
|
||||
}
|
||||
|
||||
// A type of suggestion entries.
|
||||
union SuggestionEntry {
|
||||
type SuggestionEntry
|
||||
// A value constructor
|
||||
SuggestionEntryAtom,
|
||||
= SuggestionEntryAtom
|
||||
// A method defined on a type
|
||||
SuggestionEntryMethod,
|
||||
| SuggestionEntryMethod
|
||||
// A function
|
||||
SuggestionEntryFunction,
|
||||
| SuggestionEntryFunction
|
||||
// A local value
|
||||
SuggestionEntryLocal
|
||||
| SuggestionEntryLocal;
|
||||
}
|
||||
|
||||
table SuggestionEntryAtom {
|
||||
name: string (required);
|
||||
arguments: [SuggestionEntryArgument] (required);
|
||||
returnType: string (required);
|
||||
documentation: string;
|
||||
interface SuggestionEntryAtom {
|
||||
name: string;
|
||||
module: string;
|
||||
arguments: [SuggestionEntryArgument];
|
||||
returnType: string;
|
||||
documentation?: string;
|
||||
}
|
||||
|
||||
table SuggestionEntryMethod {
|
||||
name: string (required);
|
||||
arguments: [SuggestionEntryArgument] (required);
|
||||
selfType: string (required);
|
||||
returnType: string (required);
|
||||
documentation: string;
|
||||
interface SuggestionEntryMethod {
|
||||
name: string;
|
||||
module: string;
|
||||
arguments: [SuggestionEntryArgument];
|
||||
selfType: string;
|
||||
returnType: string;
|
||||
documentation?: string;
|
||||
}
|
||||
|
||||
table SuggestionEntryFunction {
|
||||
name: string (required);
|
||||
arguments: [SuggestionEntryArgument] (required);
|
||||
returnType: string (required);
|
||||
documentation: string;
|
||||
interface SuggestionEntryFunction {
|
||||
name: string;
|
||||
module: string;
|
||||
arguments: [SuggestionEntryArgument];
|
||||
returnType: string;
|
||||
scope: SuggestionEntryScope;
|
||||
}
|
||||
|
||||
table SuggestionEntryLocal {
|
||||
name: string (required);
|
||||
returnType: string (required);
|
||||
interface SuggestionEntryLocal {
|
||||
name: string;
|
||||
module: string;
|
||||
returnType: string;
|
||||
scope: SuggestionEntryScope;
|
||||
}
|
||||
```
|
||||
|
||||
@ -307,16 +321,13 @@ The suggestion entry type that is used as a filter in search requests.
|
||||
|
||||
#### Format
|
||||
|
||||
``` idl
|
||||
namespace org.enso.languageserver.protocol.binary;
|
||||
|
||||
```typescript
|
||||
// The kind of a suggestion.
|
||||
enum SuggestionEntryType : byte {
|
||||
Atom,
|
||||
Method,
|
||||
Function,
|
||||
Local
|
||||
}
|
||||
type SuggestionEntryType
|
||||
= Atom
|
||||
| Method
|
||||
| Function
|
||||
| Local;
|
||||
```
|
||||
|
||||
### `SuggestionsDatabaseEntry`
|
||||
@ -324,14 +335,12 @@ The entry in the suggestions database.
|
||||
|
||||
#### Format
|
||||
|
||||
``` idl
|
||||
namespace org.enso.languageserver.protocol.binary;
|
||||
|
||||
```typescript
|
||||
// The suggestions database entry.
|
||||
table SuggestionsDatabaseEntry {
|
||||
interface SuggestionsDatabaseEntry {
|
||||
// suggestion entry id;
|
||||
id: int64 (required);
|
||||
suggestion: Suggestion (required);
|
||||
id: number;
|
||||
suggestion: Suggestion;
|
||||
}
|
||||
```
|
||||
|
||||
@ -340,38 +349,24 @@ The update of the suggestions database.
|
||||
|
||||
#### Format
|
||||
|
||||
``` idl
|
||||
namespace org.enso.languageserver.protocol.binary;
|
||||
|
||||
```typescript
|
||||
// The kind of the suggestions database update.
|
||||
union SuggestionsDatabaseUpdate {
|
||||
// Create or replace the database entry
|
||||
SuggestionsDatabaseUpdateInsert,
|
||||
// Update the entry fields
|
||||
SuggestionsDatabaseUpdateModify,
|
||||
// Remove the database Entry
|
||||
SuggestionsDatabaseUpdateRemove
|
||||
}
|
||||
type SuggestionsDatabaseUpdateKind
|
||||
= Add
|
||||
| Update
|
||||
| Delete
|
||||
|
||||
table SuggestionsDatabaseUpdateInsert {
|
||||
interface SuggestionsDatabaseUpdate {
|
||||
// suggestion entry id
|
||||
id: int64 (required);
|
||||
suggestion: SuggestionEntry (required);
|
||||
}
|
||||
|
||||
table SuggestionsDatabaseUpdateModify {
|
||||
// suggestion entry id
|
||||
id: int64 (required);
|
||||
name: string;
|
||||
arguments: [SuggestionEntryArgument];
|
||||
selfType: string;
|
||||
returnType: string;
|
||||
documentation: string;
|
||||
}
|
||||
|
||||
table SuggestionsDatabaseUpdateRemove {
|
||||
// suggestion entry id
|
||||
id: int64 (required);
|
||||
id: number;
|
||||
kind: SuggestionsDatabaseUpdateKind;
|
||||
name?: string;
|
||||
module?: string;
|
||||
arguments?: [SuggestionEntryArgument];
|
||||
selfType?: string;
|
||||
returnType?: string;
|
||||
documentation?: string;
|
||||
scope?: SuggestionEntryScope;
|
||||
}
|
||||
```
|
||||
|
||||
@ -895,7 +890,7 @@ This capability states that the client receives the search database updates for
|
||||
a given execution context.
|
||||
|
||||
- **method:** `search/receivesSuggestionsDatabaseUpdates`
|
||||
- **registerOptions:** `{ contextId: ContextId; }`
|
||||
- **registerOptions:** `{}`
|
||||
|
||||
### Enables
|
||||
- [`search/suggestionsDatabaseUpdate`](#suggestionsdatabaseupdate)
|
||||
@ -2131,7 +2126,7 @@ None
|
||||
|
||||
### `executionContext/executionFailed`
|
||||
Sent from the server to the client to inform about a failure during execution of
|
||||
an execution context.
|
||||
an execution context.
|
||||
|
||||
- **Type:** Notification
|
||||
- **Direction:** Server -> Client
|
||||
@ -2448,23 +2443,17 @@ Sent from client to the server to receive the full suggestions database.
|
||||
- **Visibility:** Public
|
||||
|
||||
#### Parameters
|
||||
``` idl
|
||||
namespace org.enso.languageserver.protocol.binary;
|
||||
|
||||
table GetSuggestionsDatabaseCommand {
|
||||
contextId: EnsoUUID (required);
|
||||
}
|
||||
```typescript
|
||||
null
|
||||
```
|
||||
|
||||
#### Result
|
||||
``` idl
|
||||
namespace org.enso.languageserver.protocol.binary;
|
||||
|
||||
table GetSuggestionsDatabaseReply {
|
||||
```typescript
|
||||
{
|
||||
// The list of suggestions database entries
|
||||
entries: [SuggestionsDatabaseEntry] (required);
|
||||
entries: [SuggestionsDatabaseEntry];
|
||||
// The version of received suggestions database
|
||||
currentVersion: int64 (required);
|
||||
currentVersion: number;
|
||||
}
|
||||
```
|
||||
|
||||
@ -2481,21 +2470,15 @@ database.
|
||||
- **Visibility:** Public
|
||||
|
||||
#### Parameters
|
||||
``` idl
|
||||
namespace org.enso.languageserver.protocol.binary;
|
||||
|
||||
table GetSuggestionsDatabaseVersionCommand {
|
||||
contextId: EnsoUUID (required);
|
||||
}
|
||||
```typescript
|
||||
null
|
||||
```
|
||||
|
||||
#### Result
|
||||
``` idl
|
||||
namespace org.enso.languageserver.protocol.binary;
|
||||
|
||||
table GetSuggestionsDatabaseVersionReply {
|
||||
```typescript
|
||||
{
|
||||
// The version of the suggestions database
|
||||
currentVersion: int64 (required);
|
||||
currentVersion: number;
|
||||
}
|
||||
```
|
||||
|
||||
@ -2513,16 +2496,10 @@ database.
|
||||
|
||||
#### Parameters
|
||||
|
||||
``` idl
|
||||
namespace org.enso.languageserver.protocol.binary;
|
||||
|
||||
table SuggestionsDatabaseUpdate {
|
||||
// The context id
|
||||
contextId: EnsoUUID (required);
|
||||
// The list of database updates to apply
|
||||
updates: [SuggestionsDatabaseUpdate] (required);
|
||||
// The version of suggestions database after applying the updates
|
||||
currentVersion: int64 (required);
|
||||
```typescript
|
||||
{
|
||||
updates: [SuggestionsDatabaseUpdate];
|
||||
currentVersion: number;
|
||||
}
|
||||
```
|
||||
|
||||
@ -2539,32 +2516,26 @@ Sent from client to the server to receive the autocomplete suggestion.
|
||||
|
||||
#### Parameters
|
||||
|
||||
``` idl
|
||||
namespace org.enso.languageserver.protocol.binary;
|
||||
|
||||
table SearchCompletionCommand {
|
||||
// The context id
|
||||
contextId: EnsoUUID (required);
|
||||
```typescript
|
||||
{
|
||||
// The edited file
|
||||
file: Path (required);
|
||||
file: Path;
|
||||
// The cursor position
|
||||
position: Position (required);
|
||||
position: Position;
|
||||
// Filter by methods with the provided self type
|
||||
selfType: string;
|
||||
selfType?: string;
|
||||
// Filter by the return type
|
||||
returnType: string;
|
||||
returnType?: string;
|
||||
// Filter by the suggestion types
|
||||
tags: [SuggestionEntryType];
|
||||
tags?: [SuggestionEntryType];
|
||||
}
|
||||
```
|
||||
|
||||
#### Result
|
||||
``` idl
|
||||
namespace org.enso.languageserver.protocol.binary;
|
||||
|
||||
table SearchCompletionReply {
|
||||
results: [SuggestionEntryId] (required);
|
||||
currentVersion: int64 (required);
|
||||
```typescript
|
||||
{
|
||||
results: [SuggestionEntryId];
|
||||
currentVersion: number;
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -27,7 +27,8 @@ import org.enso.languageserver.protocol.json.{
|
||||
import org.enso.languageserver.runtime.{
|
||||
ContextRegistry,
|
||||
RuntimeConnector,
|
||||
RuntimeKiller
|
||||
RuntimeKiller,
|
||||
SuggestionsDatabaseEventsListener
|
||||
}
|
||||
import org.enso.languageserver.session.SessionRouter
|
||||
import org.enso.languageserver.text.BufferRegistry
|
||||
@ -93,9 +94,16 @@ class MainModule(serverConfig: LanguageServerConfig) {
|
||||
"file-event-registry"
|
||||
)
|
||||
|
||||
lazy val suggestionsDatabaseEventsListener =
|
||||
system.actorOf(SuggestionsDatabaseEventsListener.props(sessionRouter))
|
||||
|
||||
lazy val capabilityRouter =
|
||||
system.actorOf(
|
||||
CapabilityRouter.props(bufferRegistry, receivesTreeUpdatesHandler),
|
||||
CapabilityRouter.props(
|
||||
bufferRegistry,
|
||||
receivesTreeUpdatesHandler,
|
||||
suggestionsDatabaseEventsListener
|
||||
),
|
||||
"capability-router"
|
||||
)
|
||||
|
||||
|
@ -8,6 +8,7 @@ import org.enso.languageserver.capability.CapabilityProtocol.{
|
||||
import org.enso.languageserver.data.{
|
||||
CanEdit,
|
||||
CapabilityRegistration,
|
||||
ReceivesSuggestionsDatabaseUpdates,
|
||||
ReceivesTreeUpdates
|
||||
}
|
||||
import org.enso.languageserver.monitoring.MonitoringProtocol.{Ping, Pong}
|
||||
@ -20,10 +21,13 @@ import org.enso.languageserver.util.UnhandledLogging
|
||||
* @param bufferRegistry the recipient of buffer capability requests
|
||||
* @param receivesTreeUpdatesHandler the recipient of
|
||||
* `receivesTreeUpdates` capability requests
|
||||
* @param suggestionsDatabaseEventsListener the recipient of
|
||||
* `receivesSuggestionsDatabaseUpdates` capability requests
|
||||
*/
|
||||
class CapabilityRouter(
|
||||
bufferRegistry: ActorRef,
|
||||
receivesTreeUpdatesHandler: ActorRef
|
||||
receivesTreeUpdatesHandler: ActorRef,
|
||||
suggestionsDatabaseEventsListener: ActorRef
|
||||
) extends Actor
|
||||
with ActorLogging
|
||||
with UnhandledLogging {
|
||||
@ -49,6 +53,18 @@ class CapabilityRouter(
|
||||
CapabilityRegistration(ReceivesTreeUpdates(_))
|
||||
) =>
|
||||
receivesTreeUpdatesHandler.forward(msg)
|
||||
|
||||
case msg @ AcquireCapability(
|
||||
_,
|
||||
CapabilityRegistration(ReceivesSuggestionsDatabaseUpdates())
|
||||
) =>
|
||||
suggestionsDatabaseEventsListener.forward(msg)
|
||||
|
||||
case msg @ ReleaseCapability(
|
||||
_,
|
||||
CapabilityRegistration(ReceivesSuggestionsDatabaseUpdates())
|
||||
) =>
|
||||
suggestionsDatabaseEventsListener.forward(msg)
|
||||
}
|
||||
|
||||
}
|
||||
@ -59,12 +75,23 @@ object CapabilityRouter {
|
||||
* Creates a configuration object used to create a [[CapabilityRouter]]
|
||||
*
|
||||
* @param bufferRegistry a buffer registry ref
|
||||
* @param receivesTreeUpdatesHandler the recipient of `receivesTreeUpdates`
|
||||
* capability requests
|
||||
* @param suggestionsDatabaseEventsListener the recipient of
|
||||
* `receivesSuggestionsDatabaseUpdates` capability requests
|
||||
* @return a configuration object
|
||||
*/
|
||||
def props(
|
||||
bufferRegistry: ActorRef,
|
||||
receivesTreeUpdatesHandler: ActorRef
|
||||
receivesTreeUpdatesHandler: ActorRef,
|
||||
suggestionsDatabaseEventsListener: ActorRef
|
||||
): Props =
|
||||
Props(new CapabilityRouter(bufferRegistry, receivesTreeUpdatesHandler))
|
||||
Props(
|
||||
new CapabilityRouter(
|
||||
bufferRegistry,
|
||||
receivesTreeUpdatesHandler,
|
||||
suggestionsDatabaseEventsListener
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
|
@ -63,14 +63,22 @@ object Capability {
|
||||
import io.circe.syntax._
|
||||
|
||||
implicit val encoder: Encoder[Capability] = {
|
||||
case cap: CanEdit => cap.asJson
|
||||
case cap: ReceivesTreeUpdates => cap.asJson
|
||||
case cap: CanModify => cap.asJson
|
||||
case cap: ReceivesUpdates => cap.asJson
|
||||
case cap: CanEdit => cap.asJson
|
||||
case cap: ReceivesTreeUpdates => cap.asJson
|
||||
case cap: CanModify => cap.asJson
|
||||
case cap: ReceivesUpdates => cap.asJson
|
||||
case cap: ReceivesSuggestionsDatabaseUpdates => cap.asJson
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case class ReceivesSuggestionsDatabaseUpdates()
|
||||
extends Capability(ReceivesSuggestionsDatabaseUpdates.methodName)
|
||||
|
||||
object ReceivesSuggestionsDatabaseUpdates {
|
||||
val methodName = "search/receivesSuggestionsDatabaseUpdates"
|
||||
}
|
||||
|
||||
/**
|
||||
* A capability registration object, used to identify acquired capabilities.
|
||||
*
|
||||
@ -99,14 +107,17 @@ object CapabilityRegistration {
|
||||
def resolveOptions(
|
||||
method: String,
|
||||
json: Json
|
||||
): Decoder.Result[Capability] = method match {
|
||||
case CanEdit.methodName => json.as[CanEdit]
|
||||
case ReceivesTreeUpdates.methodName => json.as[ReceivesTreeUpdates]
|
||||
case CanModify.methodName => json.as[CanModify]
|
||||
case ReceivesUpdates.methodName => json.as[ReceivesUpdates]
|
||||
case _ =>
|
||||
Left(DecodingFailure("Unrecognized capability method.", List()))
|
||||
}
|
||||
): Decoder.Result[Capability] =
|
||||
method match {
|
||||
case CanEdit.methodName => json.as[CanEdit]
|
||||
case ReceivesTreeUpdates.methodName => json.as[ReceivesTreeUpdates]
|
||||
case CanModify.methodName => json.as[CanModify]
|
||||
case ReceivesUpdates.methodName => json.as[ReceivesUpdates]
|
||||
case ReceivesSuggestionsDatabaseUpdates.methodName =>
|
||||
json.as[ReceivesSuggestionsDatabaseUpdates]
|
||||
case _ =>
|
||||
Left(DecodingFailure("Unrecognized capability method.", List()))
|
||||
}
|
||||
|
||||
for {
|
||||
method <- json.downField(methodField).as[String]
|
||||
|
@ -39,7 +39,11 @@ import org.enso.languageserver.requesthandler.visualisation.{
|
||||
DetachVisualisationHandler,
|
||||
ModifyVisualisationHandler
|
||||
}
|
||||
import org.enso.languageserver.runtime.ContextRegistryProtocol
|
||||
import org.enso.languageserver.runtime.{
|
||||
ContextRegistryProtocol,
|
||||
SearchApi,
|
||||
SearchProtocol
|
||||
}
|
||||
import org.enso.languageserver.runtime.ExecutionApi._
|
||||
import org.enso.languageserver.runtime.VisualisationApi.{
|
||||
AttachVisualisation,
|
||||
@ -170,6 +174,14 @@ class JsonConnectionController(
|
||||
ExecutionContextExecutionFailed.Params(contextId, msg)
|
||||
)
|
||||
|
||||
case SearchProtocol.SuggestionsDatabaseUpdateNotification(
|
||||
updates,
|
||||
version
|
||||
) =>
|
||||
webActor ! Notification(
|
||||
SearchApi.SuggestionsDatabaseUpdates,
|
||||
SearchApi.SuggestionsDatabaseUpdates.Params(updates, version)
|
||||
)
|
||||
case InputOutputProtocol.OutputAppended(output, outputKind) =>
|
||||
outputKind match {
|
||||
case StandardOutput =>
|
||||
@ -189,7 +201,7 @@ class JsonConnectionController(
|
||||
case InputOutputProtocol.WaitingForStandardInput =>
|
||||
webActor ! Notification(InputOutputApi.WaitingForStandardInput, Unused)
|
||||
|
||||
case req @ Request(method, _, _) if (requestHandlers.contains(method)) =>
|
||||
case req @ Request(method, _, _) if requestHandlers.contains(method) =>
|
||||
val handler = context.actorOf(
|
||||
requestHandlers(method),
|
||||
s"request-handler-$method-${UUID.randomUUID()}"
|
||||
|
@ -21,6 +21,7 @@ import org.enso.languageserver.io.InputOutputApi.{
|
||||
}
|
||||
import org.enso.languageserver.monitoring.MonitoringApi.Ping
|
||||
import org.enso.languageserver.runtime.ExecutionApi._
|
||||
import org.enso.languageserver.runtime.SearchApi._
|
||||
import org.enso.languageserver.runtime.VisualisationApi._
|
||||
import org.enso.languageserver.session.SessionApi.InitProtocolConnection
|
||||
import org.enso.languageserver.text.TextApi._
|
||||
@ -71,5 +72,6 @@ object JsonRpc {
|
||||
.registerNotification(StandardOutputAppended)
|
||||
.registerNotification(StandardErrorAppended)
|
||||
.registerNotification(WaitingForStandardInput)
|
||||
.registerNotification(SuggestionsDatabaseUpdates)
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
package org.enso.languageserver.runtime
|
||||
|
||||
import org.enso.jsonrpc.{HasParams, Method}
|
||||
import org.enso.languageserver.runtime.SearchProtocol.SuggestionsDatabaseUpdate
|
||||
|
||||
/**
|
||||
* The execution JSON RPC API provided by the language server.
|
||||
*
|
||||
* @see `docs/language-server/protocol-language-server.md`
|
||||
*/
|
||||
object SearchApi {
|
||||
|
||||
case object SuggestionsDatabaseUpdates
|
||||
extends Method("search/suggestionsDatabaseUpdates") {
|
||||
|
||||
case class Params(
|
||||
updates: Seq[SuggestionsDatabaseUpdate],
|
||||
currentVersion: Long
|
||||
)
|
||||
|
||||
implicit val hasParams = new HasParams[this.type] {
|
||||
type Params = SuggestionsDatabaseUpdates.Params
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,160 @@
|
||||
package org.enso.languageserver.runtime
|
||||
|
||||
import io.circe.generic.auto._
|
||||
import io.circe.syntax._
|
||||
import io.circe.{Decoder, Encoder, Json}
|
||||
import org.enso.searcher.Suggestion
|
||||
|
||||
object SearchProtocol {
|
||||
|
||||
sealed trait SuggestionsDatabaseUpdate
|
||||
object SuggestionsDatabaseUpdate {
|
||||
|
||||
/** Create or replace the database entry.
|
||||
*
|
||||
* @param id suggestion id
|
||||
* @param suggestion the new suggestion
|
||||
*/
|
||||
case class Add(id: Long, suggestion: Suggestion)
|
||||
extends SuggestionsDatabaseUpdate
|
||||
|
||||
/** Remove the database entry.
|
||||
*
|
||||
* @param id the suggestion id
|
||||
*/
|
||||
case class Remove(id: Long) extends SuggestionsDatabaseUpdate
|
||||
|
||||
/** Modify the database entry.
|
||||
*
|
||||
* @param id the suggestion id
|
||||
* @param name the new suggestion name
|
||||
* @param arguments the new suggestion arguments
|
||||
* @param selfType the new self type of the suggestion
|
||||
* @param returnType the new return type of the suggestion
|
||||
* @param documentation the new documentation string
|
||||
* @param scope the suggestion scope
|
||||
*/
|
||||
case class Modify(
|
||||
id: Long,
|
||||
name: Option[String],
|
||||
arguments: Option[Seq[Suggestion.Argument]],
|
||||
selfType: Option[String],
|
||||
returnType: Option[String],
|
||||
documentation: Option[String],
|
||||
scope: Option[Suggestion.Scope]
|
||||
) extends SuggestionsDatabaseUpdate
|
||||
|
||||
private object CodecField {
|
||||
|
||||
val Type = "type"
|
||||
}
|
||||
|
||||
private object CodecType {
|
||||
|
||||
val Add = "Add"
|
||||
|
||||
val Delete = "Delete"
|
||||
|
||||
val Update = "Update"
|
||||
}
|
||||
|
||||
implicit val decoder: Decoder[SuggestionsDatabaseUpdate] =
|
||||
Decoder.instance { cursor =>
|
||||
cursor.downField(CodecField.Type).as[String].flatMap {
|
||||
case CodecType.Add =>
|
||||
Decoder[SuggestionsDatabaseUpdate.Add].tryDecode(cursor)
|
||||
|
||||
case CodecType.Update =>
|
||||
Decoder[SuggestionsDatabaseUpdate.Modify].tryDecode(cursor)
|
||||
|
||||
case CodecType.Delete =>
|
||||
Decoder[SuggestionsDatabaseUpdate.Remove].tryDecode(cursor)
|
||||
}
|
||||
}
|
||||
|
||||
implicit val encoder: Encoder[SuggestionsDatabaseUpdate] =
|
||||
Encoder.instance[SuggestionsDatabaseUpdate] {
|
||||
case add: SuggestionsDatabaseUpdate.Add =>
|
||||
Encoder[SuggestionsDatabaseUpdate.Add]
|
||||
.apply(add)
|
||||
.deepMerge(Json.obj(CodecField.Type -> CodecType.Add.asJson))
|
||||
.dropNullValues
|
||||
|
||||
case modify: SuggestionsDatabaseUpdate.Modify =>
|
||||
Encoder[SuggestionsDatabaseUpdate.Modify]
|
||||
.apply(modify)
|
||||
.deepMerge(Json.obj(CodecField.Type -> CodecType.Update.asJson))
|
||||
.dropNullValues
|
||||
|
||||
case remove: SuggestionsDatabaseUpdate.Remove =>
|
||||
Encoder[SuggestionsDatabaseUpdate.Remove]
|
||||
.apply(remove)
|
||||
.deepMerge(Json.obj(CodecField.Type -> CodecType.Delete.asJson))
|
||||
}
|
||||
|
||||
private object SuggestionType {
|
||||
|
||||
val Atom = "atom"
|
||||
|
||||
val Method = "method"
|
||||
|
||||
val Function = "function"
|
||||
|
||||
val Local = "local"
|
||||
}
|
||||
|
||||
implicit val suggestionEncoder: Encoder[Suggestion] =
|
||||
Encoder.instance[Suggestion] {
|
||||
case atom: Suggestion.Atom =>
|
||||
Encoder[Suggestion.Atom]
|
||||
.apply(atom)
|
||||
.deepMerge(Json.obj(CodecField.Type -> SuggestionType.Atom.asJson))
|
||||
.dropNullValues
|
||||
|
||||
case method: Suggestion.Method =>
|
||||
Encoder[Suggestion.Method]
|
||||
.apply(method)
|
||||
.deepMerge(
|
||||
Json.obj(CodecField.Type -> SuggestionType.Method.asJson)
|
||||
)
|
||||
.dropNullValues
|
||||
|
||||
case function: Suggestion.Function =>
|
||||
Encoder[Suggestion.Function]
|
||||
.apply(function)
|
||||
.deepMerge(
|
||||
Json.obj(CodecField.Type -> SuggestionType.Function.asJson)
|
||||
)
|
||||
.dropNullValues
|
||||
|
||||
case local: Suggestion.Local =>
|
||||
Encoder[Suggestion.Local]
|
||||
.apply(local)
|
||||
.deepMerge(Json.obj(CodecField.Type -> SuggestionType.Local.asJson))
|
||||
.dropNullValues
|
||||
}
|
||||
|
||||
implicit val suggestionDecoder: Decoder[Suggestion] =
|
||||
Decoder.instance { cursor =>
|
||||
cursor.downField(CodecField.Type).as[String].flatMap {
|
||||
case SuggestionType.Atom =>
|
||||
Decoder[Suggestion.Atom].tryDecode(cursor)
|
||||
|
||||
case SuggestionType.Method =>
|
||||
Decoder[Suggestion.Method].tryDecode(cursor)
|
||||
|
||||
case SuggestionType.Function =>
|
||||
Decoder[Suggestion.Function].tryDecode(cursor)
|
||||
|
||||
case SuggestionType.Local =>
|
||||
Decoder[Suggestion.Local].tryDecode(cursor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class SuggestionsDatabaseUpdateNotification(
|
||||
updates: Seq[SuggestionsDatabaseUpdate],
|
||||
currentVersion: Long
|
||||
)
|
||||
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
package org.enso.languageserver.runtime
|
||||
|
||||
import akka.actor.{Actor, ActorLogging, ActorRef, Props}
|
||||
import org.enso.languageserver.capability.CapabilityProtocol.{
|
||||
AcquireCapability,
|
||||
CapabilityAcquired,
|
||||
CapabilityReleased,
|
||||
ReleaseCapability
|
||||
}
|
||||
import org.enso.languageserver.data.{
|
||||
CapabilityRegistration,
|
||||
ClientId,
|
||||
ReceivesSuggestionsDatabaseUpdates
|
||||
}
|
||||
import org.enso.languageserver.runtime.SearchProtocol.{
|
||||
SuggestionsDatabaseUpdate,
|
||||
SuggestionsDatabaseUpdateNotification
|
||||
}
|
||||
import org.enso.languageserver.session.SessionRouter.DeliverToJsonController
|
||||
import org.enso.languageserver.util.UnhandledLogging
|
||||
import org.enso.polyglot.runtime.Runtime.Api
|
||||
|
||||
/**
|
||||
* Event listener listens event stream for the suggestion database
|
||||
* notifications from the runtime and sends updates to the client. The listener
|
||||
* is a singleton and created per context registry.
|
||||
*
|
||||
* @param sessionRouter the session router
|
||||
*/
|
||||
final class SuggestionsDatabaseEventsListener(
|
||||
sessionRouter: ActorRef
|
||||
) extends Actor
|
||||
with ActorLogging
|
||||
with UnhandledLogging {
|
||||
|
||||
override def preStart(): Unit = {
|
||||
context.system.eventStream
|
||||
.subscribe(self, classOf[Api.SuggestionsDatabaseUpdateNotification])
|
||||
}
|
||||
|
||||
override def receive: Receive = withClients(Set())
|
||||
|
||||
private def withClients(clients: Set[ClientId]): Receive = {
|
||||
case AcquireCapability(
|
||||
client,
|
||||
CapabilityRegistration(ReceivesSuggestionsDatabaseUpdates())
|
||||
) =>
|
||||
sender() ! CapabilityAcquired
|
||||
context.become(withClients(clients + client.clientId))
|
||||
|
||||
case ReleaseCapability(
|
||||
client,
|
||||
CapabilityRegistration(ReceivesSuggestionsDatabaseUpdates())
|
||||
) =>
|
||||
sender() ! CapabilityReleased
|
||||
context.become(withClients(clients - client.clientId))
|
||||
|
||||
case msg: Api.SuggestionsDatabaseUpdateNotification =>
|
||||
clients.foreach { clientId =>
|
||||
sessionRouter ! DeliverToJsonController(
|
||||
clientId,
|
||||
SuggestionsDatabaseUpdateNotification(msg.updates.map(toUpdate), 0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private def toUpdate(
|
||||
update: Api.SuggestionsDatabaseUpdate
|
||||
): SuggestionsDatabaseUpdate =
|
||||
update match {
|
||||
case Api.SuggestionsDatabaseUpdate.Add(id, suggestion) =>
|
||||
SuggestionsDatabaseUpdate.Add(id, suggestion)
|
||||
case Api.SuggestionsDatabaseUpdate.Modify(
|
||||
id,
|
||||
name,
|
||||
arguments,
|
||||
selfType,
|
||||
returnType,
|
||||
doc,
|
||||
scope
|
||||
) =>
|
||||
SuggestionsDatabaseUpdate.Modify(
|
||||
id,
|
||||
name,
|
||||
arguments,
|
||||
selfType,
|
||||
returnType,
|
||||
doc,
|
||||
scope
|
||||
)
|
||||
case Api.SuggestionsDatabaseUpdate.Remove(id) =>
|
||||
SuggestionsDatabaseUpdate.Remove(id)
|
||||
}
|
||||
}
|
||||
|
||||
object SuggestionsDatabaseEventsListener {
|
||||
|
||||
/**
|
||||
* Creates a configuration object used to create a
|
||||
* [[SuggestionsDatabaseEventsListener]].
|
||||
*
|
||||
* @param sessionRouter the session router
|
||||
*/
|
||||
def props(sessionRouter: ActorRef): Props =
|
||||
Props(new SuggestionsDatabaseEventsListener(sessionRouter))
|
||||
|
||||
}
|
@ -141,4 +141,4 @@ table FileContentsReply {
|
||||
|
||||
}
|
||||
|
||||
//todo Split up the schema once Rust bugs will be resolved.
|
||||
//todo Split up the schema once Rust bugs will be resolved.
|
||||
|
@ -26,7 +26,10 @@ import org.enso.languageserver.protocol.json.{
|
||||
JsonConnectionControllerFactory,
|
||||
JsonRpc
|
||||
}
|
||||
import org.enso.languageserver.runtime.ContextRegistry
|
||||
import org.enso.languageserver.runtime.{
|
||||
ContextRegistry,
|
||||
SuggestionsDatabaseEventsListener
|
||||
}
|
||||
import org.enso.languageserver.session.SessionRouter
|
||||
import org.enso.languageserver.text.BufferRegistry
|
||||
|
||||
@ -92,8 +95,18 @@ class BaseServerTest extends JsonRpcServerTestKit {
|
||||
system.actorOf(
|
||||
ContextRegistry.props(config, runtimeConnectorProbe.ref, sessionRouter)
|
||||
)
|
||||
lazy val capabilityRouter =
|
||||
system.actorOf(CapabilityRouter.props(bufferRegistry, fileEventRegistry))
|
||||
|
||||
val suggestionsDatabaseEventsListener =
|
||||
system.actorOf(SuggestionsDatabaseEventsListener.props(sessionRouter))
|
||||
|
||||
val capabilityRouter =
|
||||
system.actorOf(
|
||||
CapabilityRouter.props(
|
||||
bufferRegistry,
|
||||
fileEventRegistry,
|
||||
suggestionsDatabaseEventsListener
|
||||
)
|
||||
)
|
||||
|
||||
new JsonConnectionControllerFactory(
|
||||
bufferRegistry,
|
||||
|
@ -0,0 +1,352 @@
|
||||
package org.enso.languageserver.websocket.json
|
||||
|
||||
import io.circe.literal._
|
||||
import org.enso.polyglot.runtime.Runtime.Api
|
||||
import org.enso.searcher.Suggestion
|
||||
|
||||
class SuggestionsDatabaseEventsListenerTest extends BaseServerTest {
|
||||
|
||||
"SuggestionsDatabaseEventListener" must {
|
||||
|
||||
"acquire and release capabilities" in {
|
||||
val client = getInitialisedWsClient()
|
||||
|
||||
client.send(json.acquireSuggestionsDatabaseUpdatesCapability(0))
|
||||
client.expectJson(json.ok(0))
|
||||
|
||||
client.send(json.releaseSuggestionsDatabaseUpdatesCapability(1))
|
||||
client.expectJson(json.ok(1))
|
||||
}
|
||||
|
||||
"send suggestions database add atom notifications" in {
|
||||
val client = getInitialisedWsClient()
|
||||
|
||||
client.send(json.acquireSuggestionsDatabaseUpdatesCapability(0))
|
||||
client.expectJson(json.ok(0))
|
||||
|
||||
system.eventStream.publish(
|
||||
Api.SuggestionsDatabaseUpdateNotification(
|
||||
Seq(Api.SuggestionsDatabaseUpdate.Add(0, suggestion.atom))
|
||||
)
|
||||
)
|
||||
client.expectJson(json"""
|
||||
{ "jsonrpc" : "2.0",
|
||||
"method" : "search/suggestionsDatabaseUpdates",
|
||||
"params" : {
|
||||
"updates" : [
|
||||
{
|
||||
"type" : "Add",
|
||||
"id" : 0,
|
||||
"suggestion" : {
|
||||
"type" : "atom",
|
||||
"name" : "MyType",
|
||||
"arguments" : [
|
||||
{
|
||||
"name" : "a",
|
||||
"reprType" : "Any",
|
||||
"isSuspended" : false,
|
||||
"hasDefault" : false,
|
||||
"defaultValue" : null
|
||||
}
|
||||
],
|
||||
"returnType" : "MyAtom"
|
||||
}
|
||||
}
|
||||
],
|
||||
"currentVersion" : 0
|
||||
}
|
||||
}
|
||||
""")
|
||||
}
|
||||
|
||||
"send suggestions database add method notifications" in {
|
||||
val client = getInitialisedWsClient()
|
||||
|
||||
client.send(json.acquireSuggestionsDatabaseUpdatesCapability(0))
|
||||
client.expectJson(json.ok(0))
|
||||
|
||||
system.eventStream.publish(
|
||||
Api.SuggestionsDatabaseUpdateNotification(
|
||||
Seq(Api.SuggestionsDatabaseUpdate.Add(0, suggestion.method))
|
||||
)
|
||||
)
|
||||
client.expectJson(json"""
|
||||
{ "jsonrpc" : "2.0",
|
||||
"method" : "search/suggestionsDatabaseUpdates",
|
||||
"params" : {
|
||||
"updates" : [
|
||||
{
|
||||
"type" : "Add",
|
||||
"id" : 0,
|
||||
"suggestion" : {
|
||||
"type" : "method",
|
||||
"name" : "foo",
|
||||
"arguments" : [
|
||||
{
|
||||
"name" : "this",
|
||||
"reprType" : "MyType",
|
||||
"isSuspended" : false,
|
||||
"hasDefault" : false,
|
||||
"defaultValue" : null
|
||||
},
|
||||
{
|
||||
"name" : "foo",
|
||||
"reprType" : "Number",
|
||||
"isSuspended" : false,
|
||||
"hasDefault" : true,
|
||||
"defaultValue" : "42"
|
||||
}
|
||||
],
|
||||
"selfType" : "MyType",
|
||||
"returnType" : "Number",
|
||||
"documentation" : "My doc"
|
||||
}
|
||||
}
|
||||
],
|
||||
"currentVersion" : 0
|
||||
}
|
||||
}
|
||||
""")
|
||||
}
|
||||
|
||||
"send suggestions database add function notifications" in {
|
||||
val client = getInitialisedWsClient()
|
||||
|
||||
client.send(json.acquireSuggestionsDatabaseUpdatesCapability(0))
|
||||
client.expectJson(json.ok(0))
|
||||
|
||||
system.eventStream.publish(
|
||||
Api.SuggestionsDatabaseUpdateNotification(
|
||||
Seq(Api.SuggestionsDatabaseUpdate.Add(0, suggestion.function))
|
||||
)
|
||||
)
|
||||
client.expectJson(json"""
|
||||
{ "jsonrpc" : "2.0",
|
||||
"method" : "search/suggestionsDatabaseUpdates",
|
||||
"params" : {
|
||||
"updates" : [
|
||||
{
|
||||
"type" : "Add",
|
||||
"id" : 0,
|
||||
"suggestion" : {
|
||||
"type" : "function",
|
||||
"name" : "print",
|
||||
"arguments" : [
|
||||
],
|
||||
"returnType" : "IO",
|
||||
"scope" : {
|
||||
"start" : 7,
|
||||
"end" : 10
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"currentVersion" : 0
|
||||
}
|
||||
}
|
||||
""")
|
||||
}
|
||||
|
||||
"send suggestions database add local notifications" in {
|
||||
val client = getInitialisedWsClient()
|
||||
|
||||
client.send(json.acquireSuggestionsDatabaseUpdatesCapability(0))
|
||||
client.expectJson(json.ok(0))
|
||||
|
||||
system.eventStream.publish(
|
||||
Api.SuggestionsDatabaseUpdateNotification(
|
||||
Seq(Api.SuggestionsDatabaseUpdate.Add(0, suggestion.local))
|
||||
)
|
||||
)
|
||||
client.expectJson(json"""
|
||||
{ "jsonrpc" : "2.0",
|
||||
"method" : "search/suggestionsDatabaseUpdates",
|
||||
"params" : {
|
||||
"updates" : [
|
||||
{
|
||||
"type" : "Add",
|
||||
"id" : 0,
|
||||
"suggestion" : {
|
||||
"type" : "local",
|
||||
"name" : "x",
|
||||
"returnType" : "Number",
|
||||
"scope" : {
|
||||
"start" : 15,
|
||||
"end" : 17
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"currentVersion" : 0
|
||||
}
|
||||
}
|
||||
""")
|
||||
}
|
||||
|
||||
"send suggestions database modify notifications" in {
|
||||
val client = getInitialisedWsClient()
|
||||
|
||||
client.send(json.acquireSuggestionsDatabaseUpdatesCapability(0))
|
||||
client.expectJson(json.ok(0))
|
||||
|
||||
system.eventStream.publish(
|
||||
Api.SuggestionsDatabaseUpdateNotification(
|
||||
Seq(
|
||||
Api.SuggestionsDatabaseUpdate.Modify(
|
||||
id = 0,
|
||||
name = Some("foo"),
|
||||
arguments = Some(
|
||||
Seq(
|
||||
Suggestion.Argument("a", "Any", true, false, None),
|
||||
Suggestion.Argument("b", "Any", false, true, Some("77"))
|
||||
)
|
||||
),
|
||||
selfType = Some("MyType"),
|
||||
returnType = Some("IO"),
|
||||
documentation = None,
|
||||
scope = Some(Suggestion.Scope(12, 24))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
client.expectJson(json"""
|
||||
{ "jsonrpc" : "2.0",
|
||||
"method" : "search/suggestionsDatabaseUpdates",
|
||||
"params" : {
|
||||
"updates" : [
|
||||
{
|
||||
"type" : "Update",
|
||||
"id" : 0,
|
||||
"name" : "foo",
|
||||
"arguments" : [
|
||||
{
|
||||
"name" : "a",
|
||||
"reprType" : "Any",
|
||||
"isSuspended" : true,
|
||||
"hasDefault" : false,
|
||||
"defaultValue" : null
|
||||
},
|
||||
{
|
||||
"name" : "b",
|
||||
"reprType" : "Any",
|
||||
"isSuspended" : false,
|
||||
"hasDefault" : true,
|
||||
"defaultValue" : "77"
|
||||
}
|
||||
],
|
||||
"selfType" : "MyType",
|
||||
"returnType" : "IO",
|
||||
"scope" : {
|
||||
"start" : 12,
|
||||
"end" : 24
|
||||
}
|
||||
}
|
||||
],
|
||||
"currentVersion" : 0
|
||||
}
|
||||
}
|
||||
""")
|
||||
}
|
||||
|
||||
"send suggestions database remove notifications" in {
|
||||
val client = getInitialisedWsClient()
|
||||
|
||||
client.send(json.acquireSuggestionsDatabaseUpdatesCapability(0))
|
||||
client.expectJson(json.ok(0))
|
||||
|
||||
system.eventStream.publish(
|
||||
Api.SuggestionsDatabaseUpdateNotification(
|
||||
Seq(Api.SuggestionsDatabaseUpdate.Remove(101))
|
||||
)
|
||||
)
|
||||
client.expectJson(json"""
|
||||
{ "jsonrpc" : "2.0",
|
||||
"method" : "search/suggestionsDatabaseUpdates",
|
||||
"params" : {
|
||||
"updates" : [
|
||||
{
|
||||
"type" : "Delete",
|
||||
"id" : 101
|
||||
}
|
||||
],
|
||||
"currentVersion" : 0
|
||||
}
|
||||
}
|
||||
""")
|
||||
}
|
||||
}
|
||||
|
||||
object suggestion {
|
||||
|
||||
val atom: Suggestion.Atom =
|
||||
Suggestion.Atom(
|
||||
name = "MyType",
|
||||
arguments = Seq(Suggestion.Argument("a", "Any", false, false, None)),
|
||||
returnType = "MyAtom",
|
||||
documentation = None
|
||||
)
|
||||
|
||||
val method: Suggestion.Method =
|
||||
Suggestion.Method(
|
||||
name = "foo",
|
||||
arguments = Seq(
|
||||
Suggestion.Argument("this", "MyType", false, false, None),
|
||||
Suggestion.Argument("foo", "Number", false, true, Some("42"))
|
||||
),
|
||||
selfType = "MyType",
|
||||
returnType = "Number",
|
||||
documentation = Some("My doc")
|
||||
)
|
||||
|
||||
val function: Suggestion.Function =
|
||||
Suggestion.Function(
|
||||
name = "print",
|
||||
arguments = Seq(),
|
||||
returnType = "IO",
|
||||
scope = Suggestion.Scope(7, 10)
|
||||
)
|
||||
|
||||
val local: Suggestion.Local =
|
||||
Suggestion.Local(
|
||||
name = "x",
|
||||
returnType = "Number",
|
||||
scope = Suggestion.Scope(15, 17)
|
||||
)
|
||||
}
|
||||
|
||||
object json {
|
||||
|
||||
def acquireSuggestionsDatabaseUpdatesCapability(reqId: Long) =
|
||||
json"""
|
||||
{ "jsonrpc": "2.0",
|
||||
"method": "capability/acquire",
|
||||
"id": $reqId,
|
||||
"params": {
|
||||
"method": "search/receivesSuggestionsDatabaseUpdates",
|
||||
"registerOptions": {}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
def releaseSuggestionsDatabaseUpdatesCapability(reqId: Long) =
|
||||
json"""
|
||||
{ "jsonrpc": "2.0",
|
||||
"method": "capability/release",
|
||||
"id": $reqId,
|
||||
"params": {
|
||||
"method": "search/receivesSuggestionsDatabaseUpdates",
|
||||
"registerOptions": {}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
def ok(reqId: Long) =
|
||||
json"""
|
||||
{ "jsonrpc": "2.0",
|
||||
"id": $reqId,
|
||||
"result": null
|
||||
}
|
||||
"""
|
||||
}
|
||||
|
||||
}
|
@ -11,6 +11,7 @@ import com.fasterxml.jackson.module.scala.{
|
||||
DefaultScalaModule,
|
||||
ScalaObjectMapper
|
||||
}
|
||||
import org.enso.searcher.Suggestion
|
||||
import org.enso.text.editing.model.TextEdit
|
||||
|
||||
import scala.util.Try
|
||||
@ -150,6 +151,10 @@ object Runtime {
|
||||
new JsonSubTypes.Type(
|
||||
value = classOf[Api.RuntimeServerShutDown],
|
||||
name = "runtimeServerShutDown"
|
||||
),
|
||||
new JsonSubTypes.Type(
|
||||
value = classOf[Api.SuggestionsDatabaseUpdateNotification],
|
||||
name = "suggestionsDatabaseUpdateNotification"
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -297,6 +302,62 @@ object Runtime {
|
||||
expression: String
|
||||
)
|
||||
|
||||
/** A change in the suggestions database. */
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
||||
@JsonSubTypes(
|
||||
Array(
|
||||
new JsonSubTypes.Type(
|
||||
value = classOf[SuggestionsDatabaseUpdate.Add],
|
||||
name = "suggestionsDatabaseUpdateAdd"
|
||||
),
|
||||
new JsonSubTypes.Type(
|
||||
value = classOf[SuggestionsDatabaseUpdate.Remove],
|
||||
name = "suggestionsDatabaseUpdateRemove"
|
||||
),
|
||||
new JsonSubTypes.Type(
|
||||
value = classOf[SuggestionsDatabaseUpdate.Modify],
|
||||
name = "suggestionsDatabaseUpdateModify"
|
||||
)
|
||||
)
|
||||
)
|
||||
sealed trait SuggestionsDatabaseUpdate
|
||||
object SuggestionsDatabaseUpdate {
|
||||
|
||||
/** Create or replace the database entry.
|
||||
*
|
||||
* @param id suggestion id
|
||||
* @param suggestion the new suggestion
|
||||
*/
|
||||
case class Add(id: Long, suggestion: Suggestion)
|
||||
extends SuggestionsDatabaseUpdate
|
||||
|
||||
/** Remove the database entry.
|
||||
*
|
||||
* @param id the suggestion id
|
||||
*/
|
||||
case class Remove(id: Long) extends SuggestionsDatabaseUpdate
|
||||
|
||||
/** Modify the database entry.
|
||||
*
|
||||
* @param id the suggestion id
|
||||
* @param name the new suggestion name
|
||||
* @param arguments the new suggestion arguments
|
||||
* @param selfType the new self type of the suggestion
|
||||
* @param returnType the new return type of the suggestion
|
||||
* @param documentation the new documentation string
|
||||
* @param scope the suggestion scope
|
||||
*/
|
||||
case class Modify(
|
||||
id: Long,
|
||||
name: Option[String],
|
||||
arguments: Option[Seq[Suggestion.Argument]],
|
||||
selfType: Option[String],
|
||||
returnType: Option[String],
|
||||
documentation: Option[String],
|
||||
scope: Option[Suggestion.Scope]
|
||||
) extends SuggestionsDatabaseUpdate
|
||||
}
|
||||
|
||||
/**
|
||||
* An event signaling a visualisation update.
|
||||
*
|
||||
@ -617,6 +678,15 @@ object Runtime {
|
||||
*/
|
||||
case class RuntimeServerShutDown() extends ApiResponse
|
||||
|
||||
/**
|
||||
* A notification about the change in the suggestions database.
|
||||
*
|
||||
* @param updates the list of database updates
|
||||
*/
|
||||
case class SuggestionsDatabaseUpdateNotification(
|
||||
updates: Seq[SuggestionsDatabaseUpdate]
|
||||
) extends ApiNotification
|
||||
|
||||
private lazy val mapper = {
|
||||
val factory = new CBORFactory()
|
||||
val mapper = new ObjectMapper(factory) with ScalaObjectMapper
|
||||
|
Loading…
Reference in New Issue
Block a user