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

LSP: Validate responses against client capabilities #144

Open
kjeremy opened this issue Oct 18, 2018 · 17 comments
Open

LSP: Validate responses against client capabilities #144

kjeremy opened this issue Oct 18, 2018 · 17 comments
Labels
A-lsp LSP conformance issues and missing features S-actionable Someone could pick this issue up and work on it right now

Comments

@kjeremy
Copy link
Contributor

kjeremy commented Oct 18, 2018

There are a number of places where responses from the LSP should be altered based on client and server support. Responses for things like textDocument/rename that return a WorkspaceEdit are a good example of this:

export interface WorkspaceEdit {
	/**
	 * Holds changes to existing resources.
	 */
	changes?: { [uri: string]: TextEdit[]; };
        /**
	 * Depending on the client capability `workspace.workspaceEdit.resourceOperations` document changes
	 * are either an array of `TextDocumentEdit`s to express changes to n different text documents
	 * where each text document edit addresses a specific version of a text document. Or it can contain
	 * above `TextDocumentEdit`s mixed with create, rename and delete file / folder operations.
	 *
	 * Whether a client supports versioned document edits is expressed via
	 * `workspace.workspaceEdit.documentChanges` client capability.
	 *
	 * If a client neither supports `documentChanges` nor `workspace.workspaceEdit.resourceOperations` then
	 * only plain `TextEdit`s using the `changes` property are supported.
	 */
	documentChanges?: (TextDocumentEdit[] | (TextDocumentEdit | CreateFile | RenameFile | DeleteFile)[]);
}
@matklad
Copy link
Member

matklad commented Oct 19, 2018

For the time being, I'd rather focus on supporting only the latest version of the LSP and fixing the clients :)

@kjeremy
Copy link
Contributor Author

kjeremy commented Oct 19, 2018

Sounds good. I just wanted to throw it out there.

@DJMcNab
Copy link
Contributor

DJMcNab commented Dec 31, 2018

When we do care about this, I think we can implement this in our ConvWith/TryConvWith impls, if we teach the ServerWorld about client capabilities.

@ZoeyR
Copy link

ZoeyR commented Mar 12, 2019

I don't think its as simple as supporting the latest version of the LSP. According to the official LSP spec if you don't support the capabilities then you are de-facto not supporting the latest version of the LSP. The LSP specification is designed to be backwards compatible and supporting client capabilities is part of all 3.0 versions of the specification.

This is also problematic for text editors with a slower release cycle than VSCode. Since VSCode defines the specification they will always have the latest features implemented. For other editors (such as VS) they will always be behind in the spec.

Edit: its also worth noting that some features cannot be implemented by some clients. And by not supporting capabilities you are unable to run on those clients ever.

@matklad
Copy link
Member

matklad commented Mar 12, 2019

That's true indeed! To elaborate a bit, we are in the explicitly experimental phase, so protocol conformance is a non-goal (at the moment). Instead, we want to try as may things as fast as possible, so we are cutting corners, and we do use custom extensions to the protocol.

For example, our syntax highgliting works only in VS Code (and is a horrible hack), assists are supported only in VS Code and Emacs (b/c we extended the protocol to position the cursor), and the same goes for extend selection (which we've up streamed to the protocol)

@ZoeyR
Copy link

ZoeyR commented Mar 12, 2019

Fair enough :) I only noticed this because I was attempting to get this working in Visual Studio and it doesn't have all the capabilities of VSCode.

@matklad
Copy link
Member

matklad commented Mar 12, 2019

Curious, what exactly is missing? Perhaps its easy enough to add?

@ZoeyR
Copy link

ZoeyR commented Mar 12, 2019

Well so the VS implementation of LSP is closed source and tied to the VS release cycle, which is quite slow compared to VSCode. Here are the list of things missing in VS I've noticed so far:

  • Code action literals, VS uses the old Command[] response type.
  • Completion snippets, VS does not support completion snippets (and possibly never will be able to)
  • Something is broken with workspace symbols, although this may just be a bug on us not expecting null in certain scenarios.

@matklad
Copy link
Member

matklad commented Mar 12, 2019

I meant easy to fix on our side :) Neither of those is trivial, but removing snippets should be easy enough (iirc vim doesn’t like snippets as well). Code actions are tricky, they are implemented with client-side commad. Workspace symbols should probably just work? We don’t do anything special there, and I think the protocol there hasn’t changed for a while?

For document symbols, we use new hierarchical format, which I think won’t work as well? Changing it to a flat one shouldn’t be too difficult, although less important than completions.

@kjeremy
Copy link
Contributor Author

kjeremy commented Mar 12, 2019

Originally my idea for solving this was be to hold onto the client capabilities sent during Initialize (or derive a configuration struct from that) and then use it as a Context in conv.rs to convert between analysis results and replies. I think that that could get us most of the way there.

@ZoeyR
Copy link

ZoeyR commented Mar 12, 2019

There are some code actions that get sent over when the client requests it. It shouldn't be too hard to fix this if we can get the client capabilities since the code action literals that are sent contain the command.

@kjeremy
Copy link
Contributor Author

kjeremy commented Mar 12, 2019

The InitializeParams come through here as params and you can get the ClientCapabilities from that.

From ClientCapabilities you can check for text_document (type TextDocumentClientCapabilities) which should cover the cases above I think.

From there you would need to maybe teach ServerWorld about those (maybe just hold onto the capabilities directly?) and then I think implement ConvWith for the return types from analysis with an Output type of the server reply and make the necessary changes in the handle_* functions.

@bstaletic
Copy link
Contributor

For the record, ycmd doesn't handle snippets and actually asserts so completion in ycmd with rust-analyzer is completely broken.

@joshtriplett
Copy link
Member

As an initial step, would it make sense to look at the client capabilities provided during initial connection, and error out if the capabilities don't include things that we assume the client supports?

We can then incrementally reduce that set of "required capabilities" as rust-analyzer starts to take them into account (for instance, not providing snippets if the client doesn't advertise support for them).

@kjeremy
Copy link
Contributor Author

kjeremy commented Apr 23, 2020 via email

@matklad
Copy link
Member

matklad commented Apr 23, 2020

As an initial step, would it make sense to look at the client capabilities provided during initial connection, and error out if the capabilities don't include things that we assume the client supports?

I strongly believe that "erroring out" is wrong behavior for an IDE most of the times. It should function on best-effort basis and never die and thus the best language for IDE development is Erlang.

I don't think we need any incremental steps here -- we just (and here I think the word just is actually justtified) need to go through all methods in handlers.rs and make sure to simplify our responses according to client's capabilities.

The good start would be the completion snippets issue.

kjeremy added a commit to kjeremy/rust-analyzer that referenced this issue Apr 23, 2020
If `hierarchicalDocumentSymbolSupport` is not true in the client capabilites
then it does not support the `DocumentSymbol[]` return type from the
`textDocument/documentSymbol` request and we must fall back to `SymbolInformation[]`.

This is one of the few requests that use the client capabilities to
differentiate between return types and could cause problems for clients.

See microsoft/language-server-protocol#538 (comment) for more context.

Found while looking at rust-lang#144
kjeremy added a commit to kjeremy/rust-analyzer that referenced this issue Apr 23, 2020
If `hierarchicalDocumentSymbolSupport` is not true in the client capabilites
then it does not support the `DocumentSymbol[]` return type from the
`textDocument/documentSymbol` request and we must fall back to `SymbolInformation[]`.

This is one of the few requests that use the client capabilities to
differentiate between return types and could cause problems for clients.

See microsoft/language-server-protocol#538 (comment) for more context.

Found while looking at rust-lang#144
kjeremy added a commit to kjeremy/rust-analyzer that referenced this issue Apr 24, 2020
If `hierarchicalDocumentSymbolSupport` is not true in the client capabilites
then it does not support the `DocumentSymbol[]` return type from the
`textDocument/documentSymbol` request and we must fall back to `SymbolInformation[]`.

This is one of the few requests that use the client capabilities to
differentiate between return types and could cause problems for clients.

See microsoft/language-server-protocol#538 (comment) for more context.

Found while looking at rust-lang#144
bors bot added a commit that referenced this issue Apr 25, 2020
4113: Support returning non-hierarchical symbols r=matklad a=kjeremy

If `hierarchicalDocumentSymbolSupport` is not true in the client capabilites
then it does not support the `DocumentSymbol[]` return type from the
`textDocument/documentSymbol` request and we must fall back to `SymbolInformation[]`.

This is one of the few requests that use the client capabilities to
differentiate between return types and could cause problems for clients.

See microsoft/language-server-protocol#538 (comment) for more context.

Found while looking at #144

4136: add support for cfg feature attributes on expression #4063 r=matklad a=bnjjj

close issue #4063

4141: Fix typo r=matklad a=Veetaha



4142: Remove unnecessary async from vscode language client creation r=matklad a=Veetaha



4145: Remove dead code r=matklad a=matklad



bors r+
🤖

Co-authored-by: kjeremy <[email protected]>
Co-authored-by: Benjamin Coenen <[email protected]>
Co-authored-by: veetaha <[email protected]>
Co-authored-by: Aleksey Kladov <[email protected]>
bors bot added a commit that referenced this issue Apr 25, 2020
4113: Support returning non-hierarchical symbols r=matklad a=kjeremy

If `hierarchicalDocumentSymbolSupport` is not true in the client capabilites
then it does not support the `DocumentSymbol[]` return type from the
`textDocument/documentSymbol` request and we must fall back to `SymbolInformation[]`.

This is one of the few requests that use the client capabilities to
differentiate between return types and could cause problems for clients.

See microsoft/language-server-protocol#538 (comment) for more context.

Found while looking at #144

4136: add support for cfg feature attributes on expression #4063 r=matklad a=bnjjj

close issue #4063

4141: Fix typo r=matklad a=Veetaha



4142: Remove unnecessary async from vscode language client creation r=matklad a=Veetaha



Co-authored-by: kjeremy <[email protected]>
Co-authored-by: Benjamin Coenen <[email protected]>
Co-authored-by: veetaha <[email protected]>
bors bot added a commit that referenced this issue May 1, 2020
4167: Filter out code actions if unsupported by the client and advertise our capabilities r=matklad a=kjeremy

This PR does three things:
1. If the client does not support `CodeActionKind` this will filter the results and only send `Command[]` back.
2. Correctly advertises to the client that the server supports `CodeActionKind`. This may cause clients to not request code actions if they are checking for the provider to be `true` (or implement LSP < 3.8) in the caps but I will fix that in a followup PR.
3. Marks most CodeActions as <strike>"refactor" so that they show up in the menu in vscode.</strike>`""`.

Part of #144
#4147 
#2833  

Co-authored-by: kjeremy <[email protected]>
bors bot added a commit that referenced this issue May 22, 2020
4516: LSP: Two stage initialization r=kjeremy a=kjeremy

Fills in server information.

Derives CodeAction capabilities from the client. If code action literals
are unsupported we fall back to the "simple support" which just sends back
commands (this is already supported in our config). The difference being
that we did not adjust our server capabilities so that if the client was
checking for `CodeActionProvider: "true"` in the response that would have failed.

Part of #144
Fixes #4130 (the specific case called out in that issue)

Co-authored-by: kjeremy <[email protected]>
@lnicola lnicola added the S-actionable Someone could pick this issue up and work on it right now label Jan 25, 2021
@Veykril Veykril added the A-lsp LSP conformance issues and missing features label May 25, 2022
@mishazharov
Copy link

It appears that this also affect Emacs' Eglot LSP client: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=63433

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lsp LSP conformance issues and missing features S-actionable Someone could pick this issue up and work on it right now
Projects
None yet
Development

No branches or pull requests

9 participants