mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 03:21:44 +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(pkg)
|
||||||
.dependsOn(`text-buffer`)
|
.dependsOn(`text-buffer`)
|
||||||
|
.dependsOn(`searcher`)
|
||||||
|
|
||||||
lazy val `language-server` = (project in file("engine/language-server"))
|
lazy val `language-server` = (project in file("engine/language-server"))
|
||||||
.settings(
|
.settings(
|
||||||
@ -663,6 +664,7 @@ lazy val `language-server` = (project in file("engine/language-server"))
|
|||||||
.dependsOn(`json-rpc-server`)
|
.dependsOn(`json-rpc-server`)
|
||||||
.dependsOn(`json-rpc-server-test` % Test)
|
.dependsOn(`json-rpc-server-test` % Test)
|
||||||
.dependsOn(`text-buffer`)
|
.dependsOn(`text-buffer`)
|
||||||
|
.dependsOn(`searcher`)
|
||||||
|
|
||||||
lazy val runtime = (project in file("engine/runtime"))
|
lazy val runtime = (project in file("engine/runtime"))
|
||||||
.configs(Benchmark)
|
.configs(Benchmark)
|
||||||
|
@ -55,7 +55,7 @@ transport formats, please look [here](./protocol-architecture).
|
|||||||
- [`file/receivesTreeUpdates`](#filereceivestreeupdates)
|
- [`file/receivesTreeUpdates`](#filereceivestreeupdates)
|
||||||
- [`executionContext/canModify`](#executioncontextcanmodify)
|
- [`executionContext/canModify`](#executioncontextcanmodify)
|
||||||
- [`executionContext/receivesUpdates`](#executioncontextreceivesupdates)
|
- [`executionContext/receivesUpdates`](#executioncontextreceivesupdates)
|
||||||
- [`search/receivesSuggestionsDatabaseUpdates`](#receivessuggestionsdatabaseupdates)
|
- [`search/receivesSuggestionsDatabaseUpdates`](#searchreceivessuggestionsdatabaseupdates)
|
||||||
- [File Management Operations](#file-management-operations)
|
- [File Management Operations](#file-management-operations)
|
||||||
- [`file/write`](#filewrite)
|
- [`file/write`](#filewrite)
|
||||||
- [`file/read`](#fileread)
|
- [`file/read`](#fileread)
|
||||||
@ -162,6 +162,10 @@ An identifier used for execution contexts.
|
|||||||
type ContextId = UUID;
|
type ContextId = UUID;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
type SuggestionEntryId = number;
|
||||||
|
```
|
||||||
|
|
||||||
### `StackItem`
|
### `StackItem`
|
||||||
A representation of an executable position in code, used by the execution APIs.
|
A representation of an executable position in code, used by the execution APIs.
|
||||||
|
|
||||||
@ -236,21 +240,19 @@ The argument of a [`SuggestionEntry`](#suggestionentry).
|
|||||||
|
|
||||||
#### Format
|
#### Format
|
||||||
|
|
||||||
``` idl
|
```typescript
|
||||||
namespace org.enso.languageserver.protocol.binary;
|
|
||||||
|
|
||||||
// The argument of an atom, method or function suggestion
|
// The argument of an atom, method or function suggestion
|
||||||
table SuggestionEntryArgument {
|
interface SuggestionEntryArgument {
|
||||||
// The argument name
|
// The argument name
|
||||||
name: string (required);
|
name: string;
|
||||||
// The arguement type. String 'Any' is used to specify genric types
|
// The arguement type. String 'Any' is used to specify genric types
|
||||||
type: string (required);
|
type: string;
|
||||||
// Indicates whether the argument is lazy
|
// Indicates whether the argument is lazy
|
||||||
isSuspended: bool (required);
|
isSuspended: bool;
|
||||||
// Indicates whether the argument has default value
|
// Indicates whether the argument has default value
|
||||||
hasDefault: bool (required);
|
hasDefault: bool;
|
||||||
// Optional default value
|
// Optional default value
|
||||||
defaultValue: string;
|
defaultValue?: string;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -259,46 +261,58 @@ The language construct that can be returned as a suggestion.
|
|||||||
|
|
||||||
#### Format
|
#### Format
|
||||||
|
|
||||||
``` idl
|
```typescript
|
||||||
namespace org.enso.languageserver.protocol.binary;
|
// 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.
|
// A type of suggestion entries.
|
||||||
union SuggestionEntry {
|
type SuggestionEntry
|
||||||
// A value constructor
|
// A value constructor
|
||||||
SuggestionEntryAtom,
|
= SuggestionEntryAtom
|
||||||
// A method defined on a type
|
// A method defined on a type
|
||||||
SuggestionEntryMethod,
|
| SuggestionEntryMethod
|
||||||
// A function
|
// A function
|
||||||
SuggestionEntryFunction,
|
| SuggestionEntryFunction
|
||||||
// A local value
|
// A local value
|
||||||
SuggestionEntryLocal
|
| SuggestionEntryLocal;
|
||||||
}
|
}
|
||||||
|
|
||||||
table SuggestionEntryAtom {
|
interface SuggestionEntryAtom {
|
||||||
name: string (required);
|
name: string;
|
||||||
arguments: [SuggestionEntryArgument] (required);
|
module: string;
|
||||||
returnType: string (required);
|
arguments: [SuggestionEntryArgument];
|
||||||
documentation: string;
|
returnType: string;
|
||||||
|
documentation?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
table SuggestionEntryMethod {
|
interface SuggestionEntryMethod {
|
||||||
name: string (required);
|
name: string;
|
||||||
arguments: [SuggestionEntryArgument] (required);
|
module: string;
|
||||||
selfType: string (required);
|
arguments: [SuggestionEntryArgument];
|
||||||
returnType: string (required);
|
selfType: string;
|
||||||
documentation: string;
|
returnType: string;
|
||||||
|
documentation?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
table SuggestionEntryFunction {
|
interface SuggestionEntryFunction {
|
||||||
name: string (required);
|
name: string;
|
||||||
arguments: [SuggestionEntryArgument] (required);
|
module: string;
|
||||||
returnType: string (required);
|
arguments: [SuggestionEntryArgument];
|
||||||
documentation: string;
|
returnType: string;
|
||||||
|
scope: SuggestionEntryScope;
|
||||||
}
|
}
|
||||||
|
|
||||||
table SuggestionEntryLocal {
|
interface SuggestionEntryLocal {
|
||||||
name: string (required);
|
name: string;
|
||||||
returnType: string (required);
|
module: string;
|
||||||
|
returnType: string;
|
||||||
|
scope: SuggestionEntryScope;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -307,16 +321,13 @@ The suggestion entry type that is used as a filter in search requests.
|
|||||||
|
|
||||||
#### Format
|
#### Format
|
||||||
|
|
||||||
``` idl
|
```typescript
|
||||||
namespace org.enso.languageserver.protocol.binary;
|
|
||||||
|
|
||||||
// The kind of a suggestion.
|
// The kind of a suggestion.
|
||||||
enum SuggestionEntryType : byte {
|
type SuggestionEntryType
|
||||||
Atom,
|
= Atom
|
||||||
Method,
|
| Method
|
||||||
Function,
|
| Function
|
||||||
Local
|
| Local;
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### `SuggestionsDatabaseEntry`
|
### `SuggestionsDatabaseEntry`
|
||||||
@ -324,14 +335,12 @@ The entry in the suggestions database.
|
|||||||
|
|
||||||
#### Format
|
#### Format
|
||||||
|
|
||||||
``` idl
|
```typescript
|
||||||
namespace org.enso.languageserver.protocol.binary;
|
|
||||||
|
|
||||||
// The suggestions database entry.
|
// The suggestions database entry.
|
||||||
table SuggestionsDatabaseEntry {
|
interface SuggestionsDatabaseEntry {
|
||||||
// suggestion entry id;
|
// suggestion entry id;
|
||||||
id: int64 (required);
|
id: number;
|
||||||
suggestion: Suggestion (required);
|
suggestion: Suggestion;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -340,38 +349,24 @@ The update of the suggestions database.
|
|||||||
|
|
||||||
#### Format
|
#### Format
|
||||||
|
|
||||||
``` idl
|
```typescript
|
||||||
namespace org.enso.languageserver.protocol.binary;
|
|
||||||
|
|
||||||
// The kind of the suggestions database update.
|
// The kind of the suggestions database update.
|
||||||
union SuggestionsDatabaseUpdate {
|
type SuggestionsDatabaseUpdateKind
|
||||||
// Create or replace the database entry
|
= Add
|
||||||
SuggestionsDatabaseUpdateInsert,
|
| Update
|
||||||
// Update the entry fields
|
| Delete
|
||||||
SuggestionsDatabaseUpdateModify,
|
|
||||||
// Remove the database Entry
|
|
||||||
SuggestionsDatabaseUpdateRemove
|
|
||||||
}
|
|
||||||
|
|
||||||
table SuggestionsDatabaseUpdateInsert {
|
interface SuggestionsDatabaseUpdate {
|
||||||
// suggestion entry id
|
// suggestion entry id
|
||||||
id: int64 (required);
|
id: number;
|
||||||
suggestion: SuggestionEntry (required);
|
kind: SuggestionsDatabaseUpdateKind;
|
||||||
}
|
name?: string;
|
||||||
|
module?: string;
|
||||||
table SuggestionsDatabaseUpdateModify {
|
arguments?: [SuggestionEntryArgument];
|
||||||
// suggestion entry id
|
selfType?: string;
|
||||||
id: int64 (required);
|
returnType?: string;
|
||||||
name: string;
|
documentation?: string;
|
||||||
arguments: [SuggestionEntryArgument];
|
scope?: SuggestionEntryScope;
|
||||||
selfType: string;
|
|
||||||
returnType: string;
|
|
||||||
documentation: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
table SuggestionsDatabaseUpdateRemove {
|
|
||||||
// suggestion entry id
|
|
||||||
id: int64 (required);
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -895,7 +890,7 @@ This capability states that the client receives the search database updates for
|
|||||||
a given execution context.
|
a given execution context.
|
||||||
|
|
||||||
- **method:** `search/receivesSuggestionsDatabaseUpdates`
|
- **method:** `search/receivesSuggestionsDatabaseUpdates`
|
||||||
- **registerOptions:** `{ contextId: ContextId; }`
|
- **registerOptions:** `{}`
|
||||||
|
|
||||||
### Enables
|
### Enables
|
||||||
- [`search/suggestionsDatabaseUpdate`](#suggestionsdatabaseupdate)
|
- [`search/suggestionsDatabaseUpdate`](#suggestionsdatabaseupdate)
|
||||||
@ -2131,7 +2126,7 @@ None
|
|||||||
|
|
||||||
### `executionContext/executionFailed`
|
### `executionContext/executionFailed`
|
||||||
Sent from the server to the client to inform about a failure during execution of
|
Sent from the server to the client to inform about a failure during execution of
|
||||||
an execution context.
|
an execution context.
|
||||||
|
|
||||||
- **Type:** Notification
|
- **Type:** Notification
|
||||||
- **Direction:** Server -> Client
|
- **Direction:** Server -> Client
|
||||||
@ -2448,23 +2443,17 @@ Sent from client to the server to receive the full suggestions database.
|
|||||||
- **Visibility:** Public
|
- **Visibility:** Public
|
||||||
|
|
||||||
#### Parameters
|
#### Parameters
|
||||||
``` idl
|
```typescript
|
||||||
namespace org.enso.languageserver.protocol.binary;
|
null
|
||||||
|
|
||||||
table GetSuggestionsDatabaseCommand {
|
|
||||||
contextId: EnsoUUID (required);
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Result
|
#### Result
|
||||||
``` idl
|
```typescript
|
||||||
namespace org.enso.languageserver.protocol.binary;
|
{
|
||||||
|
|
||||||
table GetSuggestionsDatabaseReply {
|
|
||||||
// The list of suggestions database entries
|
// The list of suggestions database entries
|
||||||
entries: [SuggestionsDatabaseEntry] (required);
|
entries: [SuggestionsDatabaseEntry];
|
||||||
// The version of received suggestions database
|
// The version of received suggestions database
|
||||||
currentVersion: int64 (required);
|
currentVersion: number;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -2481,21 +2470,15 @@ database.
|
|||||||
- **Visibility:** Public
|
- **Visibility:** Public
|
||||||
|
|
||||||
#### Parameters
|
#### Parameters
|
||||||
``` idl
|
```typescript
|
||||||
namespace org.enso.languageserver.protocol.binary;
|
null
|
||||||
|
|
||||||
table GetSuggestionsDatabaseVersionCommand {
|
|
||||||
contextId: EnsoUUID (required);
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Result
|
#### Result
|
||||||
``` idl
|
```typescript
|
||||||
namespace org.enso.languageserver.protocol.binary;
|
{
|
||||||
|
|
||||||
table GetSuggestionsDatabaseVersionReply {
|
|
||||||
// The version of the suggestions database
|
// The version of the suggestions database
|
||||||
currentVersion: int64 (required);
|
currentVersion: number;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -2513,16 +2496,10 @@ database.
|
|||||||
|
|
||||||
#### Parameters
|
#### Parameters
|
||||||
|
|
||||||
``` idl
|
```typescript
|
||||||
namespace org.enso.languageserver.protocol.binary;
|
{
|
||||||
|
updates: [SuggestionsDatabaseUpdate];
|
||||||
table SuggestionsDatabaseUpdate {
|
currentVersion: number;
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -2539,32 +2516,26 @@ Sent from client to the server to receive the autocomplete suggestion.
|
|||||||
|
|
||||||
#### Parameters
|
#### Parameters
|
||||||
|
|
||||||
``` idl
|
```typescript
|
||||||
namespace org.enso.languageserver.protocol.binary;
|
{
|
||||||
|
|
||||||
table SearchCompletionCommand {
|
|
||||||
// The context id
|
|
||||||
contextId: EnsoUUID (required);
|
|
||||||
// The edited file
|
// The edited file
|
||||||
file: Path (required);
|
file: Path;
|
||||||
// The cursor position
|
// The cursor position
|
||||||
position: Position (required);
|
position: Position;
|
||||||
// Filter by methods with the provided self type
|
// Filter by methods with the provided self type
|
||||||
selfType: string;
|
selfType?: string;
|
||||||
// Filter by the return type
|
// Filter by the return type
|
||||||
returnType: string;
|
returnType?: string;
|
||||||
// Filter by the suggestion types
|
// Filter by the suggestion types
|
||||||
tags: [SuggestionEntryType];
|
tags?: [SuggestionEntryType];
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Result
|
#### Result
|
||||||
``` idl
|
```typescript
|
||||||
namespace org.enso.languageserver.protocol.binary;
|
{
|
||||||
|
results: [SuggestionEntryId];
|
||||||
table SearchCompletionReply {
|
currentVersion: number;
|
||||||
results: [SuggestionEntryId] (required);
|
|
||||||
currentVersion: int64 (required);
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -27,7 +27,8 @@ import org.enso.languageserver.protocol.json.{
|
|||||||
import org.enso.languageserver.runtime.{
|
import org.enso.languageserver.runtime.{
|
||||||
ContextRegistry,
|
ContextRegistry,
|
||||||
RuntimeConnector,
|
RuntimeConnector,
|
||||||
RuntimeKiller
|
RuntimeKiller,
|
||||||
|
SuggestionsDatabaseEventsListener
|
||||||
}
|
}
|
||||||
import org.enso.languageserver.session.SessionRouter
|
import org.enso.languageserver.session.SessionRouter
|
||||||
import org.enso.languageserver.text.BufferRegistry
|
import org.enso.languageserver.text.BufferRegistry
|
||||||
@ -93,9 +94,16 @@ class MainModule(serverConfig: LanguageServerConfig) {
|
|||||||
"file-event-registry"
|
"file-event-registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
lazy val suggestionsDatabaseEventsListener =
|
||||||
|
system.actorOf(SuggestionsDatabaseEventsListener.props(sessionRouter))
|
||||||
|
|
||||||
lazy val capabilityRouter =
|
lazy val capabilityRouter =
|
||||||
system.actorOf(
|
system.actorOf(
|
||||||
CapabilityRouter.props(bufferRegistry, receivesTreeUpdatesHandler),
|
CapabilityRouter.props(
|
||||||
|
bufferRegistry,
|
||||||
|
receivesTreeUpdatesHandler,
|
||||||
|
suggestionsDatabaseEventsListener
|
||||||
|
),
|
||||||
"capability-router"
|
"capability-router"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import org.enso.languageserver.capability.CapabilityProtocol.{
|
|||||||
import org.enso.languageserver.data.{
|
import org.enso.languageserver.data.{
|
||||||
CanEdit,
|
CanEdit,
|
||||||
CapabilityRegistration,
|
CapabilityRegistration,
|
||||||
|
ReceivesSuggestionsDatabaseUpdates,
|
||||||
ReceivesTreeUpdates
|
ReceivesTreeUpdates
|
||||||
}
|
}
|
||||||
import org.enso.languageserver.monitoring.MonitoringProtocol.{Ping, Pong}
|
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 bufferRegistry the recipient of buffer capability requests
|
||||||
* @param receivesTreeUpdatesHandler the recipient of
|
* @param receivesTreeUpdatesHandler the recipient of
|
||||||
* `receivesTreeUpdates` capability requests
|
* `receivesTreeUpdates` capability requests
|
||||||
|
* @param suggestionsDatabaseEventsListener the recipient of
|
||||||
|
* `receivesSuggestionsDatabaseUpdates` capability requests
|
||||||
*/
|
*/
|
||||||
class CapabilityRouter(
|
class CapabilityRouter(
|
||||||
bufferRegistry: ActorRef,
|
bufferRegistry: ActorRef,
|
||||||
receivesTreeUpdatesHandler: ActorRef
|
receivesTreeUpdatesHandler: ActorRef,
|
||||||
|
suggestionsDatabaseEventsListener: ActorRef
|
||||||
) extends Actor
|
) extends Actor
|
||||||
with ActorLogging
|
with ActorLogging
|
||||||
with UnhandledLogging {
|
with UnhandledLogging {
|
||||||
@ -49,6 +53,18 @@ class CapabilityRouter(
|
|||||||
CapabilityRegistration(ReceivesTreeUpdates(_))
|
CapabilityRegistration(ReceivesTreeUpdates(_))
|
||||||
) =>
|
) =>
|
||||||
receivesTreeUpdatesHandler.forward(msg)
|
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]]
|
* Creates a configuration object used to create a [[CapabilityRouter]]
|
||||||
*
|
*
|
||||||
* @param bufferRegistry a buffer registry ref
|
* @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
|
* @return a configuration object
|
||||||
*/
|
*/
|
||||||
def props(
|
def props(
|
||||||
bufferRegistry: ActorRef,
|
bufferRegistry: ActorRef,
|
||||||
receivesTreeUpdatesHandler: ActorRef
|
receivesTreeUpdatesHandler: ActorRef,
|
||||||
|
suggestionsDatabaseEventsListener: ActorRef
|
||||||
): Props =
|
): Props =
|
||||||
Props(new CapabilityRouter(bufferRegistry, receivesTreeUpdatesHandler))
|
Props(
|
||||||
|
new CapabilityRouter(
|
||||||
|
bufferRegistry,
|
||||||
|
receivesTreeUpdatesHandler,
|
||||||
|
suggestionsDatabaseEventsListener
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -63,14 +63,22 @@ object Capability {
|
|||||||
import io.circe.syntax._
|
import io.circe.syntax._
|
||||||
|
|
||||||
implicit val encoder: Encoder[Capability] = {
|
implicit val encoder: Encoder[Capability] = {
|
||||||
case cap: CanEdit => cap.asJson
|
case cap: CanEdit => cap.asJson
|
||||||
case cap: ReceivesTreeUpdates => cap.asJson
|
case cap: ReceivesTreeUpdates => cap.asJson
|
||||||
case cap: CanModify => cap.asJson
|
case cap: CanModify => cap.asJson
|
||||||
case cap: ReceivesUpdates => 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.
|
* A capability registration object, used to identify acquired capabilities.
|
||||||
*
|
*
|
||||||
@ -99,14 +107,17 @@ object CapabilityRegistration {
|
|||||||
def resolveOptions(
|
def resolveOptions(
|
||||||
method: String,
|
method: String,
|
||||||
json: Json
|
json: Json
|
||||||
): Decoder.Result[Capability] = method match {
|
): Decoder.Result[Capability] =
|
||||||
case CanEdit.methodName => json.as[CanEdit]
|
method match {
|
||||||
case ReceivesTreeUpdates.methodName => json.as[ReceivesTreeUpdates]
|
case CanEdit.methodName => json.as[CanEdit]
|
||||||
case CanModify.methodName => json.as[CanModify]
|
case ReceivesTreeUpdates.methodName => json.as[ReceivesTreeUpdates]
|
||||||
case ReceivesUpdates.methodName => json.as[ReceivesUpdates]
|
case CanModify.methodName => json.as[CanModify]
|
||||||
case _ =>
|
case ReceivesUpdates.methodName => json.as[ReceivesUpdates]
|
||||||
Left(DecodingFailure("Unrecognized capability method.", List()))
|
case ReceivesSuggestionsDatabaseUpdates.methodName =>
|
||||||
}
|
json.as[ReceivesSuggestionsDatabaseUpdates]
|
||||||
|
case _ =>
|
||||||
|
Left(DecodingFailure("Unrecognized capability method.", List()))
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
method <- json.downField(methodField).as[String]
|
method <- json.downField(methodField).as[String]
|
||||||
|
@ -39,7 +39,11 @@ import org.enso.languageserver.requesthandler.visualisation.{
|
|||||||
DetachVisualisationHandler,
|
DetachVisualisationHandler,
|
||||||
ModifyVisualisationHandler
|
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.ExecutionApi._
|
||||||
import org.enso.languageserver.runtime.VisualisationApi.{
|
import org.enso.languageserver.runtime.VisualisationApi.{
|
||||||
AttachVisualisation,
|
AttachVisualisation,
|
||||||
@ -170,6 +174,14 @@ class JsonConnectionController(
|
|||||||
ExecutionContextExecutionFailed.Params(contextId, msg)
|
ExecutionContextExecutionFailed.Params(contextId, msg)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
case SearchProtocol.SuggestionsDatabaseUpdateNotification(
|
||||||
|
updates,
|
||||||
|
version
|
||||||
|
) =>
|
||||||
|
webActor ! Notification(
|
||||||
|
SearchApi.SuggestionsDatabaseUpdates,
|
||||||
|
SearchApi.SuggestionsDatabaseUpdates.Params(updates, version)
|
||||||
|
)
|
||||||
case InputOutputProtocol.OutputAppended(output, outputKind) =>
|
case InputOutputProtocol.OutputAppended(output, outputKind) =>
|
||||||
outputKind match {
|
outputKind match {
|
||||||
case StandardOutput =>
|
case StandardOutput =>
|
||||||
@ -189,7 +201,7 @@ class JsonConnectionController(
|
|||||||
case InputOutputProtocol.WaitingForStandardInput =>
|
case InputOutputProtocol.WaitingForStandardInput =>
|
||||||
webActor ! Notification(InputOutputApi.WaitingForStandardInput, Unused)
|
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(
|
val handler = context.actorOf(
|
||||||
requestHandlers(method),
|
requestHandlers(method),
|
||||||
s"request-handler-$method-${UUID.randomUUID()}"
|
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.monitoring.MonitoringApi.Ping
|
||||||
import org.enso.languageserver.runtime.ExecutionApi._
|
import org.enso.languageserver.runtime.ExecutionApi._
|
||||||
|
import org.enso.languageserver.runtime.SearchApi._
|
||||||
import org.enso.languageserver.runtime.VisualisationApi._
|
import org.enso.languageserver.runtime.VisualisationApi._
|
||||||
import org.enso.languageserver.session.SessionApi.InitProtocolConnection
|
import org.enso.languageserver.session.SessionApi.InitProtocolConnection
|
||||||
import org.enso.languageserver.text.TextApi._
|
import org.enso.languageserver.text.TextApi._
|
||||||
@ -71,5 +72,6 @@ object JsonRpc {
|
|||||||
.registerNotification(StandardOutputAppended)
|
.registerNotification(StandardOutputAppended)
|
||||||
.registerNotification(StandardErrorAppended)
|
.registerNotification(StandardErrorAppended)
|
||||||
.registerNotification(WaitingForStandardInput)
|
.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,
|
JsonConnectionControllerFactory,
|
||||||
JsonRpc
|
JsonRpc
|
||||||
}
|
}
|
||||||
import org.enso.languageserver.runtime.ContextRegistry
|
import org.enso.languageserver.runtime.{
|
||||||
|
ContextRegistry,
|
||||||
|
SuggestionsDatabaseEventsListener
|
||||||
|
}
|
||||||
import org.enso.languageserver.session.SessionRouter
|
import org.enso.languageserver.session.SessionRouter
|
||||||
import org.enso.languageserver.text.BufferRegistry
|
import org.enso.languageserver.text.BufferRegistry
|
||||||
|
|
||||||
@ -92,8 +95,18 @@ class BaseServerTest extends JsonRpcServerTestKit {
|
|||||||
system.actorOf(
|
system.actorOf(
|
||||||
ContextRegistry.props(config, runtimeConnectorProbe.ref, sessionRouter)
|
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(
|
new JsonConnectionControllerFactory(
|
||||||
bufferRegistry,
|
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,
|
DefaultScalaModule,
|
||||||
ScalaObjectMapper
|
ScalaObjectMapper
|
||||||
}
|
}
|
||||||
|
import org.enso.searcher.Suggestion
|
||||||
import org.enso.text.editing.model.TextEdit
|
import org.enso.text.editing.model.TextEdit
|
||||||
|
|
||||||
import scala.util.Try
|
import scala.util.Try
|
||||||
@ -150,6 +151,10 @@ object Runtime {
|
|||||||
new JsonSubTypes.Type(
|
new JsonSubTypes.Type(
|
||||||
value = classOf[Api.RuntimeServerShutDown],
|
value = classOf[Api.RuntimeServerShutDown],
|
||||||
name = "runtimeServerShutDown"
|
name = "runtimeServerShutDown"
|
||||||
|
),
|
||||||
|
new JsonSubTypes.Type(
|
||||||
|
value = classOf[Api.SuggestionsDatabaseUpdateNotification],
|
||||||
|
name = "suggestionsDatabaseUpdateNotification"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -297,6 +302,62 @@ object Runtime {
|
|||||||
expression: String
|
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.
|
* An event signaling a visualisation update.
|
||||||
*
|
*
|
||||||
@ -617,6 +678,15 @@ object Runtime {
|
|||||||
*/
|
*/
|
||||||
case class RuntimeServerShutDown() extends ApiResponse
|
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 = {
|
private lazy val mapper = {
|
||||||
val factory = new CBORFactory()
|
val factory = new CBORFactory()
|
||||||
val mapper = new ObjectMapper(factory) with ScalaObjectMapper
|
val mapper = new ObjectMapper(factory) with ScalaObjectMapper
|
||||||
|
Loading…
Reference in New Issue
Block a user