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

Add signatureHelp and hover to Python autocomplete #3607

Merged
merged 19 commits into from
Mar 31, 2023

Conversation

mattrunyon
Copy link
Contributor

@mattrunyon mattrunyon commented Mar 27, 2023

Corresponds with deephaven/web-client-ui#1178

This addresses the first 3 items in #3453 except deprecation tags.

Adds signatureHelp and hover requests to the Python autocomplete server

Requires you build and force reinstall the Python server locally unless you are using pip -e flag for your local Python server.

Put the plumbing in place for autocomplete cancellation and diagnostic requests

You can either use the web-client-ui main branch dev server or change web/client-ui/Dockerfile to WEB_VERSION=0.32.1-lsp.3 locally to test the web UI.

@mattrunyon mattrunyon added the ReleaseNotesNeeded Release notes are needed label Mar 28, 2023
@mattrunyon mattrunyon requested a review from niloc132 March 28, 2023 22:55
mattrunyon added a commit to deephaven/web-client-ui that referenced this pull request Mar 29, 2023
Corresponds with deephaven/deephaven-core#3607

This adds signatureHelp and hover providers if the JS API supports the
corresponding requests

SignatureHelp is provided when you type a method and then type the `(`
character. There's also probably a keybinding in monaco to trigger it,
but I'm not sure what it is.

Hover provided when you hover anything

Needs to use [my core
branch](https://github.com/mattrunyon/deephaven-core/tree/lsp-improvements)
to test. After pulling that branch, will need to build/install the
Python server using the following commands

```
./gradlew :py-server:assemble :py-embedded-server:assemble
pip install --force-reinstall py/server/build/wheel/deephaven_core-0.23.0-py3-none-any.whl py/embedded-server/build/wheel/deephaven_server-0.23.0-py3-none-any.whl
```

Then start using one of these commands. Groovy provided just to show it
doesn't break anything in Groovy. There is no autocomplete in Python
notebooks if you are using a Groovy worker.

```
./gradlew server-jetty-app:run # Python
START_OPTS="-Ddeephaven.console.type=groovy" ./gradlew server-jetty-app:run # Groovy
```
@mattrunyon mattrunyon requested a review from niloc132 March 31, 2023 16:34
niloc132
niloc132 previously approved these changes Mar 31, 2023
@devinrsmith
Copy link
Member

Filed deephaven/web-client-ui#1191

Copy link
Contributor

@jmao-denver jmao-denver left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small quibbles

Copy link
Contributor

@jmao-denver jmao-denver left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Python changes LGTM

@devinrsmith
Copy link
Member

I could have swore we didn't throw any huge errors when jedi is not installed, but it looks like that is not the case. This is not this PRs fault, but definitely something we should cleanup. Will create follow-up ticket. Should also plan to either close #3174 or re-do.

@devinrsmith
Copy link
Member

Follow up #3640

Copy link
Member

@devinrsmith devinrsmith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not get deep into the LSP side of things. My main concerns are about server/client semantics.

Comment on lines +113 to +133
switch (request.getRequestCase()) {
case GET_COMPLETION_ITEMS: {
response.setCompletionItems(getCompletionItems(request.getGetCompletionItems(), exportedConsole,
parser, responseObserver));
break;
}
case GET_SIGNATURE_HELP: {
// Not implemented. Return empty signature list
response.setSignatures(GetSignatureHelpResponse.getDefaultInstance());
break;
}
case GET_HOVER: {
// Not implemented. Return empty hover help
response.setHover(
GetHoverResponse.newBuilder().setContents(MarkupContent.getDefaultInstance()).build());
break;
}
case GET_DIAGNOSTIC: {
// Not implemented. Return empty diagnostics
response.setDiagnostic(GetPullDiagnosticResponse.getDefaultInstance());
break;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the pattern here is to return success if the server knows about the type, but doesn't implement it. That said, I wonder if it's better to not set any response on the GET_SIGNATURE_HELP / GET_HOVER / GET_DIAGNOSTIC cases.

The way the implementation works now, for example, on a GET_DIAGNOSTIC request, the client needs to know that an empty kind field means it's not implemented?

message GetPullDiagnosticResponse {
    string kind = 1;
    optional string result_id = 2;
    repeated Diagnostic items = 3;
}

Note: as the server is previously implemented, and implemented now, a newer client won't be able to talk to an older server (REQUEST_NOT_SET will throw an exception, which seems acceptable as long as the client knows how to properly handle it).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if we ever see the default case (in the way the code is currently structured), we should throw an illegal argument exception.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The LSP spec is to first negotiate what the client and server support. Then the client should not send requests or expect results if the server does not support the request type in that negotiation. The client can also tell the server what it supports (like markdown or plaintext only). For now we are just assuming the web IDE which supports markdown

We could instead add a NOT_SUPPORTED response type to be more explicit in these cases. In that case we probably wouldn't throw in the default and instead just return a NOT_SUPPORTED response

On the web client I'm checking if the JS API has either of the new requests before registering the provider, so the web IDE won't try to send requests unless the JS API has the method we expect.

Comment on lines +87 to +91
// Maintain compatibility with older clients
// The only autocomplete type supported before the consoleId was moved to the parent request was
// GetCompletionItems
final io.deephaven.proto.backplane.grpc.Ticket consoleId =
value.hasConsoleId() ? value.getConsoleId() : value.getGetCompletionItems().getConsoleId();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have a safer version of this? If console_id is not set, ensure that request type is get_completion_items? (Could extract code and use on the java side too)

.append("\tbuild_response_time=").append(toMillis(totalResponseBuildNanos))
.append("\ttotal_complete_time=").append(toMillis(totalCompletionNanos))
.endl();
switch (request.getRequestCase()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if we ever see the default case (in the way the code is currently structured), we should throw an illegal argument exception.

}
}

message BrowserNextResponse {
}

message OpenDocumentRequest {
io.deephaven.proto.backplane.grpc.Ticket console_id = 1;
io.deephaven.proto.backplane.grpc.Ticket console_id = 1 [deprecated=true];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have a server safety layer that ensures if the deprecated fields and new fields are set, they are equal; otherwise blowup? Alternatively, we could say either the new fields must be set, or the deprecated fields must be set, but not both.

Copy link
Contributor Author

@mattrunyon mattrunyon Mar 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the only reason for deprecation here (as opposed to just ripping out these fields) is if a user had an older web client but newer engine version. Realistically I think the only place that may happen right now is with web developers, so I would be fine just removing these fields instead of deprecating, but I know @niloc132 had other thoughts on that

Although one main reason to not rip this out would be in DnD where at the moment we might have the enterprise JS API talking to the community engine still

@devinrsmith devinrsmith merged commit 05fcdad into deephaven:main Mar 31, 2023
@github-actions github-actions bot locked and limited conversation to collaborators Mar 31, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants