-
Notifications
You must be signed in to change notification settings - Fork 818
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
What's the expected behaviour of CompletionList.isIncomplete=false when the user presses backspace? #954
Comments
@dbaeumer do you know the answer to this? I don't mind sending a PR to clarify the docs as long as someone confirms the correct answer. |
I've always assumed that server is at least free to take the prefix into account. If not, then the number of completions could be 100s or even 1000s for some cases. So filtering based on prefix is almost mandatory for performance/practicality. However, I do agree with @DanTup, the spec is unclear about it. |
I assumed the opposite, on the assumption this really meant "the client never needs to ask the server again for this completion 'session'" 😄 I think for most cases, the completion opens with no prefix, so the saving is probably not for the majority of invocations, but it'd definitely be nice to save some bytes (especially for things like LiveShare, which sends the entire payload over the internet) if it can be confirmed that clients should re-request from the server when deleting the original prefix. |
All the more reason the spec really needs to be clarified. I agree either interpretation is possible with the current wording. I suspect the spec may even be deliberately vague to allow both types of server implemenations.
I think it realy depends a lot on the specifics of the language or even the context in which the completions are being invoked. In some contexts a complete 'no prefix' completion request is going to return unmanageable number of results. (E.g. all the classes on your project's classpath, or all the functions defined in all the code + libraries). Those kinds of things will tend to return 100s or 1000s of results unless they are somehow 'narrowed' down. I think a typical server implementation would have to be practical and just return a 'incomplete' list of result in such cases, and limit it to some small number of results. Then as user types more, the server takes the prefix into account to return a 'complete' list that is specific to that prefix. |
This won't work out though, as the client+server need to have the same understanding. For example if a server assumes the client will re-request on backspace and filters to the prefix, but an editor does not, the user will be missing completions if they backspace. I think it's likely just accidental, but I do believe it needs to be concrete. I've seen many inconsistencies across LSP clients because of vagueness in the spec, so I think it's in everyones interest to make everything absolutely concrete (though I don't think anyone disagrees with this 🙂)
That only works with IsIncomplete=true though, and that results in a lot of data being round-tripped multiple times and increased latency as the user types. That's why I'd prefer to filter to the prefix (if this can be clarified) than switch to IsIncomplete=true. (That said, I think this API is in real need of supporting partial results - I think the API does, but VS Code doesn't support it.. sending all the imported completions initially and then the huge list of unimported ones would be a big improvement). |
For coc.nvim implement, if |
This is the behaviour I somewhat expect (which unfortunately prevents the optimisation I was hoping to make), but it would be nice to have clarified (and made concrete in the spec to ensure all clients/servers assume the same). |
I just did some testing in VS Code, and I found:
Therefore I'm inclined to believe that it's always safe for a server to filter results based on the current prefix even if using isIncomplete=false. However it would be nice for the LSP spec (and the VS Code API docs) to be explicit about this so we don't have to hope all clients interpret it this way. |
In the case of Dart / Flutter v1.17 we have observed about 27,000 completions being sent from language server to client without server-side prefix filtering. Needless to say this results in noticeable editor pauses and stutter, at least in Vim + LSC. |
There have been a few bugs in the Dart LSP implementation that resulted in many more items being returned than there should (for example private and/or static members). However, the remaining list is still large when using auto-import completions. I'm working on a change that filters server-side based on the prefix (I am making the assumption that the behaviour I noted above from VS Code is what the spec intends, even though it's not clear) that should make things significantly better - however the spec really needs updating to be explicit here - clients/servers shouldn't need to make assumptions about what the other expects. |
@dbaeumer the related VS Code issue (microsoft/vscode#99355) was closed as not-enough-votes and then locked with outstanding questions. Could it be re-opened? It doesn't seem like spec ambiguities should require user votes to address - it's important the LSP spec is clear for servers/clients to know how the other will behave, and if LSP is based on VS Code functionality, it stands to reason that VS Code needs to be clear too. I've made assumptions about "current but unspecified behaviour" in the past, and then VS Code changed (I shouldn't rely on undocumented behaviour) and broke for users 😞 |
@dbaeumer slightly related to this, VS code's behaviour for isIncomplete=true when the list is empty is also unexpected. It also seems to different to the explanation described here. I've filed an issue at microsoft/vscode#155738 asking for empty lists to be supported, but if not, the behaviour clearly documenting. I think the same should be done here, because it's important that servers understand how the clients will behave. |
I disagree with that. For one, because Sublime Text doesn't work like that. Backspacing behind the point at which completions were requested doesn't re-request completions (in the case of But more importantly because it's not feasible. This is because the prefix typed in the editor doesn't necessarily have to match literally for the completion to match. The user can type the So this could only work if all editors and server implemented the same fuzzy algorithm for matching completions which is obviously not gonna happen. |
@rchl sorry, where I said "matches the prefix" above, I did mean a fuzzy match. The fuzzy matches don't need to match for things to work - the user just won't see things that are filtered by either server or client (for example if the client is allowing characters to be flipped around to cover typos but the server is just doing all the letters in order, ofc the user won't get the benefit of what the client is doing). It's a shame that VS Code and Sublime are behaving differently, but this just highlights why the spec needs to be explicit about these kinds of things. VS Code is not the only client and it's very difficult for both servers and other clients if the spec is vague. |
My understanding is that if IsIncomplete=true, the client will not cache results and must go back to the server whenever the user types a character (this allows the server to return a partial set of results).
Currently in Dart we use IsIncomplete=false - eg. we give the full list to VS Code and allow it to filter client side.
There has been an assumption that I don't think is well described in the spec, relating to whether the client should supply all possible completions given the current prefix or all possible completions for the current location regardless of prefix.
For example, let's say my completion list simple has:
If the user invokes completion where
^
is here:If the server is using
IsIncomplete=false
(eg. it's providing the full list), should it includetwo
andthree
here, on the assumption that the client will not call the server again even if the user hits backspace, or should it assume that the client-side filtering is only for typing forwards?The spec is a bit vague on this (it's not clear what "Further typing" covers, and "recomputing" is also a little vague - I presume it means "the client should re-request completions from the server").
If pressing backspace is intended to re-call the server even when IsIncomplete=false, then significant gains could be made for us by filtering based on the prefix on the server.
Thanks!
The text was updated successfully, but these errors were encountered: