-
Notifications
You must be signed in to change notification settings - Fork 766
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
CompletionItem is underspecified: replacement text replaces *what* range? #264
Comments
The current version of the protocol also say that |
@mickaelistria what you wrote is exactly my Proposal1. Its downsides are (1) it doesn't work with multiple cursors, (2) it doesn't allow clients to offer users the choice of doing either replace or insert, as Eclipse and IntelliJ currently do. |
@ljw1004 in such case, dealing with replace vs insert would most likely be a language server setting. I don't think it should be part of the CompletionItem. On a side note, in Eclipse IDE the insert/replace setting is not available for most text editors, only JDT and a few others do support it, but usually users aren't given choice and take the completion as it; using LS is very similar, so it's not a major inconsistency. |
A couple of comments:
open code complete and select console. This will result in
I think the best solution will be proposal 3. I will provide a default range that is used as a replacement range if only a insertText is provided. Objections? |
May be a global flag is enough. Then server could use the text edit instead to ensure it behaves the same on all clients. |
My vote is for 'Proposal 1' (from @ljw1004). I.e. just deprecate the use of insertText. Personally, I found the potential confusion around what does the 'insertText' replace (if anything at all) enough of a reason that I already concluded we should use textEdit exclusively so we can be precise about what part of the document to replace when applying the completion. So our language servers never use the insertText precisely because I wasn't sure what it would do. Perhaps we should just make that official rather than pile more complexity in a place where its not needed (since textEdit mechanic is quite adequate already). |
@ljw1004 Mentions two downsides:
According to @jrieken, who should know, it can be made to work. So that objection is of the table.
Personally, I don't think that's really a problem. In my experience virtually nobody wants to change that preference, (because, essentially, changing it from its default value just makes the editor completions work incorrectly). |
@dbaeumer @jrieken Could you explain what you mean when you say "multi cursor works with text edits"? I still believe it doesn't. Let's look at your concrete example:
We send an autocomplete request for line 0 character 3. If it gives the suggestion "console" via a
But if it gives the suggestion "console" via a
That's why I say that |
@jrieken can you please clarify. We discussed this yesterday over slack. |
@jrieken let me hack a small example. May be I convert things wrongly :-) |
The API hides the fact that there are multiple cursors and makes this an editor responsibility. Otherwise the Now, how does VS Code actually implement this? In the editor we have the notion of an active/primary cursor and when making a completion request we use its position. The result might be an edit as outlined below (replace 'con' with 'console'). We then map that edit onto secondary cursors and use a simple rule: Compare the text-to-replace from the primary cursor ('con' in this sample) with the text-to-replace of the current cursor. If its the same value use a replace edit, otherwise fallback to an insert edit. Line 124 is the primary cursor, the others are secondary. The edit on line 123 will replace the same text which makes this a replace-edit, the other won't making them an insert-edit. Code reference: https://github.com/Microsoft/vscode/blob/master/src/vs/editor/contrib/snippet/snippetSession.ts#L281 @ljw1004 In case you actually tried this in VS Code and in case it didn't work, then please file a bug. Thanks |
I tried the following extension code and it works correctly in terms of multi cursor and text edit (note than in the VS Code API it is range and insertText)
@jrieken you are off the hook |
Will try a language server now. |
OK. I tried the LSP case as well and it works for me. I have the lsp-sample from here and exchanged the existing completion item handler with:
Running this correctly works with multi cursor: Given all this I will do the following: make it clear that the insertText might be subject to interpretation and deprecate it. I agree that using text edits is the right approach here anyways. I will also include a global capability to single if the insertText is subject to interpretation. |
Thanks for the explanation @jrieken, and thanks for your analysis and conclusions @dbaeumer. They sound good. Q1. TextEdit is used for multiple methods - Q2. I'm struggling to figure out how this would apply when multiple cursors overlap with the TextEdit. Imagine the string Q3. @jrieken, I get the gist of what you're describing, but not precisely enough to be able to implement it myself. For instance, I don't know the definition of a replace vs insert application of a TextEdit. Could you point me to some code so I can follow along? Q4. This is a real semantic thing. Prior to multiple cursors, if you had Q5. @dbaeumer do you expect all editors which support multiple cursors to also use the same algorithm when applying a completion response? Or is it up to them what to do? Q6. I'm still not sure what you mean by "is insertText subject to interpretation"... |
The |
Q1: as Joh said no. Q2: VS Code rejects this completion item. However other tools might do something different. Q3: @jrieken on the VS Code completion side this is a CompletionItem with an Q4: this is still true for the primary cursor. I am against saying anything about secondary cursors in the LSP. I think we should leave this up to the tool. I see that in VS Code there will be a semantic difference between a replace for Q5: no, only for the primary location. Q6: function foo() {
}
function foobar() {
}
function foobarbaz() {
}
foo<cursor>bar A tool when the completion item foobarbaz is selected and the So besides what I proposed I would add some sentences that a completion items is made for a primary cursor location and that it is up to the tool to decide what it does with the comletion item on secondary cursor locations. |
@ljw1004 Writes:
I don't understand that, if a insertext is 'console' and the text already there at the first cursor is 'con' then wouldn't the end result be
So that is not 'the desired result at all'. Actually, for the result to be 'console' then the server would probably return an insert text of 'sole' (because con is already there only 'sole' has to be inserted to complete it) and so, the result with multi-cursors would be
This is not the desired result either. So I'm a bit confused to be honest... it would seem to me insertText doesn't work with multicursor? |
@kdvolder this is why we deprecated insertText in favor of text edit. The tool might do some smartness with |
In my opinion not further action is needed. I added comments to the spec about the insert text and to favor the text edit. Please ping if you disagree. |
The LSP spec talks about the text that will be inserted. But VSCode only does insertion in some cases. More generally, VSCode autocomplete does replacement. Here's what VSCode does when you do an autocomplete when the caret is in this position
foo.ba|or
... [see also VSCode source code vs/workbench/api/node/extHostLanguageFeatures.ts and vs/workbench/api/node/extHostTypeConverters.ts.]LanguageConfiguration.wordPattern
regular expression.baor
.label || insertText
to replace that part of the current word that's to the left of the caret, in this caseba
.I think it's unsatisfactory that LSP's completion response should depend on the externally-provided
LanguageConfiguration.wordPattern
when it doesn't know what wordPattern was provided to VSCode, doesn't even know if it's being invoked by VSCode or some other client, doesn't know what that client does. I happened to stumble across the PHP wordpattern at https://github.com/Microsoft/vscode/blob/master/extensions/php/src/phpMain.ts#L29 but my LSP server shouldn't have to depend on that file!Concern 1: Some clients like IntelliJ, Eclipse and VisualStudio can actually have autocomplete replace the entire word
baor
, not just the bit to the leftba
. I think the language server needs to know what text it's going to replace, so it can offer up its insertText correctly.Concern 2: Some clients like IntelliJ, Eclipse have autocomplete insert the function-calls with snippets, e.g. at
this.f|
it will autocomplete tothis.foo($$i, $$j)
. This differs from VSCode which only autocompletes tothis.foo
. I think that in LSP it can be up to the language server whether or not to insert parentheses+arguments. But again I want my language server to know what span it will replace.Concern 3: I'm working in a language with a variety of separators --
a::b
,a->b
,a\b
,a.b
-- and I don't know if the LanguageConfiguration.wordPattern will accommodate all of these. The VSCode docs for wordPattern talk about the difference between "positive wordpatterns" (e.g. a word is the regex[a-zA-Z0-9_]+
) vs "negative wordpatterns" (e.g. a word is any string of characters surrounded by blanks or one of a finite list of punctuation characters). It says that the negative wordpattern is better if your language supports unicode. So honestly it's anyone's guess what the current wordpattern will be.PROPOSAL 1: Maybe we should say that
label / insertText
is actively bad practice because the language server can't know exactly what span this insertText will replace. And every language server should instead use textEdit to be sure to cover the correct range. (But this is a shame because it doesn't work with multiple cursors, and it wouldn't allow the client to offer the user a choice between replacing vs inserting behavior, like IntelliJ+Eclipse currently do).PROPOSAL 2: Maybe we should say that the LSP itself provides the autocomplete-wordpattern regex to the editor. (This would be tough because it would have to be a wordpattern regex that works across all the different language regex interpreters that clients might be written in).
PROPOSAL 3: Maybe the
textDocument/completion
request should include the characters that will be replaced ifinsertText
is used.ADDITIONAL PROPOSAL: Maybe we should stop calling it
insertText
in LSP, because it's a REPLACEMENT text not an insert text.The text was updated successfully, but these errors were encountered: