Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jupyter/fix completion kind #2730

Merged
merged 3 commits into from
Feb 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using FluentAssertions;
using Microsoft.CodeAnalysis.Text;
using Microsoft.DotNet.Interactive.Commands;
using Microsoft.DotNet.Interactive.Events;
using Microsoft.DotNet.Interactive.Formatting;
Expand Down Expand Up @@ -573,4 +574,45 @@ public async Task can_fail_on_completions_status_error()
.Should()
.BeEmpty();
}

[Fact]
public async Task can_translate_completion_item_metadata_for_completions_produce()
{
var code = "test";
var metadata = new Dictionary<string, IReadOnlyList<CompletionResultMetadata>>
{
{
CompletionResultMetadata.Experimental, new[]
{
new CompletionResultMetadata(0, 1, "test1-test", "function", "TEST1TEST"),
new CompletionResultMetadata(0, 1, "test2-test", "class", null)
}
}
};
var options = new TestJupyterConnectionOptions(GenerateReplies(new[] {
Message.CreateReply(new CompleteReply(0, 1, new[] {"test1", "test2"}, metadata, StatusValues.Ok),
Message.Create(new CompleteRequest(code, 1))),
}));

var kernel = await CreateJupyterKernelAsync(options);

var command = new RequestCompletions(code, SourceUtilities.GetPositionFromCursorOffset(code, 1));
var result = await kernel.SendAsync(command);
var events = result.Events;

events
.Should()
.NotContainErrors();

events
.Should()
.ContainSingle<CompletionsProduced>()
.Which
.Completions
.Should()
.BeEquivalentToRespectingRuntimeTypes(new[] {
new CompletionItem("TEST1TEST", "Method", "test1-test", "test1-test", "test1-test"),
new CompletionItem("test2-test", "Class", "test2-test", "test2-test", "test2-test")
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,29 +94,56 @@ public async Task HandleAsync(RequestCompletions command, KernelInvocationContex
return;
}

bool metadataAvailable = results.MetaData.TryGetValue(CompletionResultMetadata.Entry, out IReadOnlyList<CompletionResultMetadata> resultsMetadata);
if (!metadataAvailable)
bool metadataAvailable = results.MetaData.TryGetValue(CompletionResultMetadata.Experimental, out IReadOnlyList<CompletionResultMetadata> resultsMetadata);

string GetCompletionKind(string type)
{
resultsMetadata = new List<CompletionResultMetadata>();
}
var kind = type switch
{
"keyword" => "Keyword",
"function" => "Method",
"class" => "Class",
"instance" => "Field",
"module" => "Module",
"type" => "Class",
"property" => "Property",
"field" => "Field",
"builtin" => "Method",
"builtinfunction" => "Method",
"builtinmodule" => "Module",
"builtintype" => "Class",
"value" => "Variable",
"constant" => "Constant",
"variable" => "Variable",
_ => string.Empty
};
return kind;
};

var completionItems = metadataAvailable ?
resultsMetadata.Select(m =>
new CompletionItem(
displayText: m.DisplayText ?? m.Text,
kind: GetCompletionKind(m.Type ?? string.Empty),
insertText: m.Text,
filterText: m.Text,
sortText: m.Text))
: results.Matches.Select(match =>
new CompletionItem(
displayText: match,
kind: string.Empty,
insertText: match,
filterText: match,
sortText: match));

var completionItems = from match in results.Matches
join metadata in resultsMetadata on match equals metadata.Text into ci
from itemMetadata in ci.DefaultIfEmpty()
select new CompletionItem(
displayText: itemMetadata?.DisplayText ?? match,
kind: itemMetadata?.Type ?? string.Empty,
insertText: match,
filterText: match,
sortText: match);

var completion = new CompletionsProduced(
completionItems, command,
SourceUtilities.GetLinePositionSpanFromStartAndEndIndices(command.Code, results.CursorStart, results.CursorEnd));

context.Publish(completion);
}

public async Task HandleAsync(SubmitCode command, KernelInvocationContext context)
{
CancelCommandOnKernelIfRequested(context);
Expand All @@ -126,7 +153,7 @@ public async Task HandleAsync(SubmitCode command, KernelInvocationContext contex

var executeRequest = Messaging.Message.Create(
new ExecuteRequest(
command.Code.NormalizeLineEndings(),
command.Code.NormalizeLineEndings(),
allowStdin: false, // TODO: ZMQ stdin channel is hanging. Disable until a consistent experience can be turned on.
stopOnError: true));
var processMessages = Receiver.Messages
Expand All @@ -148,7 +175,7 @@ public async Task HandleAsync(SubmitCode command, KernelInvocationContext contex
}
})
.TakeUntil(m => m.MessageType == JupyterMessageContentTypes.Error || (messagesProcessed && results is not null));
// run until kernel idle or until execution is done
// run until kernel idle or until execution is done

await Sender.SendAsync(executeRequest);
await processMessages.ToTask(context.CancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Microsoft.DotNet.Interactive.Jupyter.Protocol;
public class CompletionResultMetadata
{
[JsonIgnore]
public static string Entry = "_jupyter_types_experimental";
public static string Experimental = "_jupyter_types_experimental";

[JsonPropertyName("end")]
public int End { get; }
Expand Down