mirror of
https://github.com/enso-org/enso.git
synced 2024-11-23 08:08:34 +03:00
Fix the search/getSuggestionsDatabase API (#1021)
This commit is contained in:
parent
27a322db26
commit
ded61865a4
@ -3,11 +3,12 @@ package org.enso.languageserver.runtime
|
||||
import org.enso.jsonrpc.{Error, HasParams, HasResult, Method, Unused}
|
||||
import org.enso.languageserver.filemanager.Path
|
||||
import org.enso.languageserver.runtime.SearchProtocol.{
|
||||
SuggestionDatabaseEntry,
|
||||
SuggestionId,
|
||||
SuggestionKind,
|
||||
SuggestionsDatabaseUpdate
|
||||
}
|
||||
import org.enso.searcher.SuggestionEntry
|
||||
|
||||
import org.enso.text.editing.model.Position
|
||||
|
||||
/**
|
||||
@ -34,7 +35,7 @@ object SearchApi {
|
||||
extends Method("search/getSuggestionsDatabase") {
|
||||
|
||||
case class Result(
|
||||
entries: Seq[SuggestionEntry],
|
||||
entries: Seq[SuggestionDatabaseEntry],
|
||||
currentVersion: Long
|
||||
)
|
||||
|
||||
|
@ -13,6 +13,79 @@ object SearchProtocol {
|
||||
|
||||
type SuggestionId = Long
|
||||
|
||||
private object CodecField {
|
||||
|
||||
val Type = "type"
|
||||
}
|
||||
|
||||
private object CodecType {
|
||||
|
||||
val Add = "Add"
|
||||
|
||||
val Remove = "Remove"
|
||||
|
||||
val Modify = "Modify"
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
sealed trait SuggestionsDatabaseUpdate
|
||||
object SuggestionsDatabaseUpdate {
|
||||
|
||||
@ -38,20 +111,6 @@ object SearchProtocol {
|
||||
case class Modify(id: SuggestionId, returnType: String)
|
||||
extends SuggestionsDatabaseUpdate
|
||||
|
||||
private object CodecField {
|
||||
|
||||
val Type = "type"
|
||||
}
|
||||
|
||||
private object CodecType {
|
||||
|
||||
val Add = "Add"
|
||||
|
||||
val Remove = "Remove"
|
||||
|
||||
val Modify = "Modify"
|
||||
}
|
||||
|
||||
implicit val decoder: Decoder[SuggestionsDatabaseUpdate] =
|
||||
Decoder.instance { cursor =>
|
||||
cursor.downField(CodecField.Type).as[String].flatMap {
|
||||
@ -85,65 +144,6 @@ object SearchProtocol {
|
||||
.deepMerge(Json.obj(CodecField.Type -> CodecType.Modify.asJson))
|
||||
.dropNullValues
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** The type of a suggestion. */
|
||||
@ -193,6 +193,49 @@ object SearchProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The entry in the suggestions database.
|
||||
*
|
||||
* @param id the suggestion id
|
||||
* @param suggestion the suggestion
|
||||
*/
|
||||
case class SuggestionDatabaseEntry(id: SuggestionId, suggestion: Suggestion)
|
||||
|
||||
object SuggestionDatabaseEntry {
|
||||
|
||||
/**
|
||||
* Create the database entry from the polyglot suggestion entry.
|
||||
*
|
||||
* @param entry the suggestion entry
|
||||
* @return the database entry
|
||||
*/
|
||||
def apply(entry: SuggestionEntry): SuggestionDatabaseEntry =
|
||||
new SuggestionDatabaseEntry(entry.id, entry.suggestion)
|
||||
|
||||
private object CodecField {
|
||||
|
||||
val Id = "id"
|
||||
|
||||
val Suggestion = "suggestion"
|
||||
}
|
||||
|
||||
implicit val encoder: Encoder[SuggestionDatabaseEntry] =
|
||||
Encoder.instance { entry =>
|
||||
Json.obj(
|
||||
CodecField.Id -> entry.id.asJson,
|
||||
CodecField.Suggestion -> Encoder[Suggestion].apply(entry.suggestion)
|
||||
)
|
||||
}
|
||||
|
||||
implicit val decoder: Decoder[SuggestionDatabaseEntry] =
|
||||
Decoder.instance { cursor =>
|
||||
for {
|
||||
id <- cursor.downField(CodecField.Id).as[SuggestionId]
|
||||
suggestion <- cursor.downField(CodecField.Suggestion).as[Suggestion]
|
||||
} yield SuggestionDatabaseEntry(id, suggestion)
|
||||
}
|
||||
}
|
||||
|
||||
/** A notification about changes in the suggestions database.
|
||||
*
|
||||
* @param currentVersion current version of the suggestions database
|
||||
@ -213,7 +256,7 @@ object SearchProtocol {
|
||||
*/
|
||||
case class GetSuggestionsDatabaseResult(
|
||||
currentVersion: Long,
|
||||
entries: Seq[SuggestionEntry]
|
||||
entries: Seq[SuggestionDatabaseEntry]
|
||||
)
|
||||
|
||||
/** The request to receive the current version of the suggestions database. */
|
||||
|
@ -173,7 +173,13 @@ final class SuggestionsHandler(
|
||||
|
||||
case GetSuggestionsDatabase =>
|
||||
repo.getAll
|
||||
.map(GetSuggestionsDatabaseResult.tupled)
|
||||
.map {
|
||||
case (version, entries) =>
|
||||
GetSuggestionsDatabaseResult(
|
||||
version,
|
||||
entries.map(SuggestionDatabaseEntry(_))
|
||||
)
|
||||
}
|
||||
.pipeTo(sender())
|
||||
|
||||
case Completion(path, pos, selfType, returnType, tags) =>
|
||||
|
@ -11,24 +11,17 @@ import org.enso.languageserver.capability.CapabilityProtocol.{
|
||||
AcquireCapability,
|
||||
CapabilityAcquired
|
||||
}
|
||||
import org.enso.languageserver.data.{
|
||||
CapabilityRegistration,
|
||||
Config,
|
||||
DirectoriesConfig,
|
||||
ExecutionContextConfig,
|
||||
FileManagerConfig,
|
||||
PathWatcherConfig,
|
||||
ReceivesSuggestionsDatabaseUpdates
|
||||
}
|
||||
import org.enso.languageserver.data._
|
||||
import org.enso.languageserver.filemanager.Path
|
||||
import org.enso.languageserver.refactoring.ProjectNameChangedEvent
|
||||
import org.enso.languageserver.runtime.SearchProtocol.SuggestionDatabaseEntry
|
||||
import org.enso.languageserver.session.JsonSession
|
||||
import org.enso.languageserver.session.SessionRouter.DeliverToJsonController
|
||||
import org.enso.polyglot.runtime.Runtime.Api
|
||||
import org.enso.searcher.{SuggestionEntry, SuggestionsRepo}
|
||||
import org.enso.searcher.SuggestionsRepo
|
||||
import org.enso.searcher.sql.SqlSuggestionsRepo
|
||||
import org.enso.text.editing.model.Position
|
||||
import org.enso.testkit.RetrySpec
|
||||
import org.enso.text.editing.model.Position
|
||||
import org.scalatest.BeforeAndAfterAll
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.wordspec.AnyWordSpecLike
|
||||
@ -162,7 +155,7 @@ class SuggestionsHandlerSpec
|
||||
expectMsg(
|
||||
SearchProtocol.GetSuggestionsDatabaseResult(
|
||||
1,
|
||||
Seq(SuggestionEntry(1L, Suggestions.atom))
|
||||
Seq(SuggestionDatabaseEntry(1L, Suggestions.atom))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -178,6 +178,107 @@ class SuggestionsHandlerEventsTest extends BaseServerTest with FlakySpec {
|
||||
}
|
||||
""")
|
||||
|
||||
// get suggestions database
|
||||
client.send(json.getSuggestionsDatabase(0))
|
||||
client.expectJson(json"""
|
||||
{ "jsonrpc" : "2.0",
|
||||
"id" : 0,
|
||||
"result" : {
|
||||
"entries" : [
|
||||
{
|
||||
"id" : 3,
|
||||
"suggestion" : {
|
||||
"type" : "function",
|
||||
"externalId" : ${Suggestions.function.externalId.get},
|
||||
"module" : "Test.Main",
|
||||
"name" : "print",
|
||||
"arguments" : [
|
||||
],
|
||||
"returnType" : "IO",
|
||||
"scope" : {
|
||||
"start" : {
|
||||
"line" : 1,
|
||||
"character" : 9
|
||||
},
|
||||
"end" : {
|
||||
"line" : 1,
|
||||
"character" : 22
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id" : 1,
|
||||
"suggestion" : {
|
||||
"type" : "atom",
|
||||
"module" : "Test.Main",
|
||||
"name" : "MyType",
|
||||
"arguments" : [
|
||||
{
|
||||
"name" : "a",
|
||||
"reprType" : "Any",
|
||||
"isSuspended" : false,
|
||||
"hasDefault" : false,
|
||||
"defaultValue" : null
|
||||
}
|
||||
],
|
||||
"returnType" : "MyAtom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id" : 2,
|
||||
"suggestion" : {
|
||||
"type" : "method",
|
||||
"externalId" : ${Suggestions.method.externalId.get},
|
||||
"module" : "Test.Main",
|
||||
"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" : "Lovely"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id" : 4,
|
||||
"suggestion" : {
|
||||
"type" : "local",
|
||||
"externalId" : ${Suggestions.local.externalId.get},
|
||||
"module" : "Test.Main",
|
||||
"name" : "x",
|
||||
"returnType" : "Number",
|
||||
"scope" : {
|
||||
"start" : {
|
||||
"line" : 21,
|
||||
"character" : 0
|
||||
},
|
||||
"end" : {
|
||||
"line" : 89,
|
||||
"character" : 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"currentVersion" : 4
|
||||
}
|
||||
}
|
||||
""")
|
||||
|
||||
// remove items
|
||||
system.eventStream.publish(
|
||||
Api.SuggestionsDatabaseUpdateNotification(
|
||||
|
@ -105,20 +105,21 @@ class RuntimeServerTest
|
||||
val idFooY = metadata.addItem(81, 8)
|
||||
val idFooZ = metadata.addItem(98, 5)
|
||||
|
||||
val code = metadata.appendToCode(
|
||||
"""
|
||||
|main =
|
||||
| x = 6
|
||||
| y = x.foo 5
|
||||
| z = y + 5
|
||||
| z
|
||||
|
|
||||
|Number.foo = x ->
|
||||
| y = this + 3
|
||||
| z = y * x
|
||||
| z
|
||||
|""".stripMargin
|
||||
)
|
||||
def code =
|
||||
metadata.appendToCode(
|
||||
"""
|
||||
|main =
|
||||
| x = 6
|
||||
| y = x.foo 5
|
||||
| z = y + 5
|
||||
| z
|
||||
|
|
||||
|Number.foo = x ->
|
||||
| y = this + 3
|
||||
| z = y * x
|
||||
| z
|
||||
|""".stripMargin.linesIterator.mkString("\n")
|
||||
)
|
||||
|
||||
object Update {
|
||||
|
||||
@ -459,6 +460,274 @@ class RuntimeServerTest
|
||||
context.consumeOut shouldEqual List()
|
||||
}
|
||||
|
||||
it should "support file modification operations with attached ids" in {
|
||||
val fooFile = new File(context.pkg.sourceDir, "Foo.enso")
|
||||
val contextId = UUID.randomUUID()
|
||||
val requestId = UUID.randomUUID()
|
||||
val metadata = new Metadata
|
||||
val idMain = metadata.addItem(7, 2)
|
||||
val code = metadata.appendToCode("main = 84")
|
||||
|
||||
context.send(Api.Request(requestId, Api.CreateContextRequest(contextId)))
|
||||
context.receive shouldEqual Some(
|
||||
Api.Response(requestId, Api.CreateContextResponse(contextId))
|
||||
)
|
||||
|
||||
// Create a new file
|
||||
context.writeFile(fooFile, code)
|
||||
|
||||
// Open the new file
|
||||
context.send(
|
||||
Api.Request(
|
||||
Api.OpenFileNotification(
|
||||
fooFile,
|
||||
code,
|
||||
false
|
||||
)
|
||||
)
|
||||
)
|
||||
context.receive shouldEqual None
|
||||
|
||||
// Push new item on the stack to trigger the re-execution
|
||||
context.send(
|
||||
Api.Request(
|
||||
requestId,
|
||||
Api.PushContextRequest(
|
||||
contextId,
|
||||
Api.StackItem
|
||||
.ExplicitCall(
|
||||
Api.MethodPointer(fooFile, "Foo", "main"),
|
||||
None,
|
||||
Vector()
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
context.receive(3) should contain theSameElementsAs Seq(
|
||||
Api.Response(requestId, Api.PushContextResponse(contextId)),
|
||||
Api.Response(
|
||||
Api.ExpressionValuesComputed(
|
||||
contextId,
|
||||
Vector(
|
||||
Api.ExpressionValueUpdate(idMain, Some("Number"), Some("84"), None)
|
||||
)
|
||||
)
|
||||
),
|
||||
Api.Response(
|
||||
Api.SuggestionsDatabaseReIndexNotification(
|
||||
"Test.Foo",
|
||||
Seq(
|
||||
Api.SuggestionsDatabaseUpdate.Add(
|
||||
Suggestion.Method(
|
||||
Some(idMain),
|
||||
"Test.Foo",
|
||||
"main",
|
||||
Seq(Suggestion.Argument("this", "Any", false, false, None)),
|
||||
"here",
|
||||
"Any",
|
||||
None
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// Modify the file
|
||||
context.send(
|
||||
Api.Request(
|
||||
Api.EditFileNotification(
|
||||
fooFile,
|
||||
Seq(
|
||||
TextEdit(
|
||||
model.Range(model.Position(0, 0), model.Position(0, 9)),
|
||||
"main = 42"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
context.receive(2) should contain theSameElementsAs Seq(
|
||||
Api.Response(
|
||||
Api.ExpressionValuesComputed(
|
||||
contextId,
|
||||
Vector(
|
||||
Api.ExpressionValueUpdate(idMain, Some("Number"), Some("42"), None)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
it should "send suggestion notifications when file executed" in {
|
||||
val contextId = UUID.randomUUID()
|
||||
val requestId = UUID.randomUUID()
|
||||
val idMain = context.Main.metadata.addItem(7, 47)
|
||||
val idMainUpdate =
|
||||
Api.Response(
|
||||
Api.ExpressionValuesComputed(
|
||||
contextId,
|
||||
Vector(
|
||||
Api.ExpressionValueUpdate(
|
||||
idMain,
|
||||
Some("Number"),
|
||||
Some("50"),
|
||||
None
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val mainFile = context.writeMain(context.Main.code)
|
||||
|
||||
// create context
|
||||
context.send(Api.Request(requestId, Api.CreateContextRequest(contextId)))
|
||||
context.receive shouldEqual Some(
|
||||
Api.Response(requestId, Api.CreateContextResponse(contextId))
|
||||
)
|
||||
|
||||
// Open the new file
|
||||
context.send(
|
||||
Api.Request(
|
||||
Api.OpenFileNotification(
|
||||
mainFile,
|
||||
context.Main.code,
|
||||
false
|
||||
)
|
||||
)
|
||||
)
|
||||
context.receive shouldEqual None
|
||||
|
||||
// push main
|
||||
val item1 = Api.StackItem.ExplicitCall(
|
||||
Api.MethodPointer(mainFile, "Main", "main"),
|
||||
None,
|
||||
Vector()
|
||||
)
|
||||
context.send(
|
||||
Api.Request(requestId, Api.PushContextRequest(contextId, item1))
|
||||
)
|
||||
context.receive(7) should contain theSameElementsAs Seq(
|
||||
Api.Response(requestId, Api.PushContextResponse(contextId)),
|
||||
context.Main.Update.mainX(contextId),
|
||||
context.Main.Update.mainY(contextId),
|
||||
context.Main.Update.mainZ(contextId),
|
||||
idMainUpdate,
|
||||
Api.Response(
|
||||
Api.SuggestionsDatabaseReIndexNotification(
|
||||
"Test.Main",
|
||||
List(
|
||||
Api.SuggestionsDatabaseUpdate.Add(
|
||||
Suggestion.Method(
|
||||
Some(idMain),
|
||||
"Test.Main",
|
||||
"main",
|
||||
List(Suggestion.Argument("this", "Any", false, false, None)),
|
||||
"here",
|
||||
"Any",
|
||||
None
|
||||
)
|
||||
),
|
||||
Api.SuggestionsDatabaseUpdate.Add(
|
||||
Suggestion.Method(
|
||||
None,
|
||||
"Test.Main",
|
||||
"foo",
|
||||
List(
|
||||
Suggestion.Argument("this", "Any", false, false, None),
|
||||
Suggestion.Argument("x", "Any", false, false, None)
|
||||
),
|
||||
"Number",
|
||||
"Any",
|
||||
None
|
||||
)
|
||||
),
|
||||
Api.SuggestionsDatabaseUpdate.Add(
|
||||
Suggestion.Local(
|
||||
Some(context.Main.idMainX),
|
||||
"Test.Main",
|
||||
"x",
|
||||
"Any",
|
||||
Suggestion
|
||||
.Scope(Suggestion.Position(1, 6), Suggestion.Position(6, 0))
|
||||
)
|
||||
),
|
||||
Api.SuggestionsDatabaseUpdate.Add(
|
||||
Suggestion.Local(
|
||||
Some(context.Main.idMainY),
|
||||
"Test.Main",
|
||||
"y",
|
||||
"Any",
|
||||
Suggestion
|
||||
.Scope(Suggestion.Position(1, 6), Suggestion.Position(6, 0))
|
||||
)
|
||||
),
|
||||
Api.SuggestionsDatabaseUpdate.Add(
|
||||
Suggestion.Local(
|
||||
Some(context.Main.idMainZ),
|
||||
"Test.Main",
|
||||
"z",
|
||||
"Any",
|
||||
Suggestion
|
||||
.Scope(Suggestion.Position(1, 6), Suggestion.Position(6, 0))
|
||||
)
|
||||
),
|
||||
Api.SuggestionsDatabaseUpdate.Add(
|
||||
Suggestion.Local(
|
||||
Some(context.Main.idFooY),
|
||||
"Test.Main",
|
||||
"y",
|
||||
"Any",
|
||||
Suggestion
|
||||
.Scope(Suggestion.Position(7, 17), Suggestion.Position(10, 5))
|
||||
)
|
||||
),
|
||||
Api.SuggestionsDatabaseUpdate.Add(
|
||||
Suggestion.Local(
|
||||
Some(context.Main.idFooZ),
|
||||
"Test.Main",
|
||||
"z",
|
||||
"Any",
|
||||
Suggestion
|
||||
.Scope(Suggestion.Position(7, 17), Suggestion.Position(10, 5))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// push foo call
|
||||
val item2 = Api.StackItem.LocalCall(context.Main.idMainY)
|
||||
context.send(
|
||||
Api.Request(requestId, Api.PushContextRequest(contextId, item2))
|
||||
)
|
||||
context.receive(4) should contain theSameElementsAs Seq(
|
||||
Api.Response(requestId, Api.PushContextResponse(contextId)),
|
||||
context.Main.Update.fooY(contextId),
|
||||
context.Main.Update.fooZ(contextId)
|
||||
)
|
||||
|
||||
// pop foo call
|
||||
context.send(Api.Request(requestId, Api.PopContextRequest(contextId)))
|
||||
context.receive(3) should contain theSameElementsAs Seq(
|
||||
Api.Response(requestId, Api.PopContextResponse(contextId)),
|
||||
idMainUpdate
|
||||
)
|
||||
|
||||
// pop main
|
||||
context.send(Api.Request(requestId, Api.PopContextRequest(contextId)))
|
||||
context.receive(2) should contain theSameElementsAs Seq(
|
||||
Api.Response(requestId, Api.PopContextResponse(contextId))
|
||||
)
|
||||
|
||||
// pop empty stack
|
||||
context.send(Api.Request(requestId, Api.PopContextRequest(contextId)))
|
||||
context.receive shouldEqual Some(
|
||||
Api.Response(requestId, Api.EmptyStackError(contextId))
|
||||
)
|
||||
}
|
||||
|
||||
it should "send suggestion notifications when file modified" in {
|
||||
val fooFile = new File(context.pkg.sourceDir, "Foo.enso")
|
||||
val contextId = UUID.randomUUID()
|
||||
|
Loading…
Reference in New Issue
Block a user