-
Notifications
You must be signed in to change notification settings - Fork 320
Description
Per spec, textEdit is
An edit which is applied to a document when selecting this completion.
In vim's context, this is CompleteChanged rather than CompleteDone.
At this moment, the textEdit is applied on CompleteDone:
| autocmd CompleteDone * call s:on_complete_done() |
I'll try to illustrate the problem caused by this below.
Some language servers would send textEdit to make the completion text replace the word the cursor's at. This is pretty bad and annoying design IMO but seems to be the standard in the IDE world, JetBrains IDEs do this at least. rust-analyzer is a language server that does this. So, taking this Rust snippet as an example:
fn main() {
let mut a = 9;
let b = a;
}For some reason, I intend to change this into
fn main() {
let mut a = 9;
let b = std::mem::take(&mut a);
}In insert mode, I place my cursor at the a of let b = a;, and enter s. Completion popup tells me that I can complete into std. I use e.g. tab to select std. Here, the expected behavior is (once again, I don't think this should be the expected behavior, but looking at how e.g. JetBrains IDEA work they very much expect this), a textEdit happens, and the completion std replaces a, so we get
fn main() {
let mut a = 9;
let b = std;
}Cursor's between std and ;
However, since textEdit is handled on CompleteDone, but not CompleteChanged, at this moment, vim-lsp will lead us to
fn main() {
let mut a = 9;
let b = stda;
}Cursor's between std and a.
And, we continue to type, our input of :, a trigger character, which causes completion refresh, closes the completion popup and triggers CompleteDone. The textEdit fires, and removes the a now, leaving us to
fn main() {
let mut a = 9;
let b = std;
}So, our current behavior is a bit more annoying than the expected behavior, which is annoying enough: it wastes an extra keypress and is more surprising. A completion replacing the word under cursor is weird but is understandable and predictable, but that an input of :, which isn't even a completion and shouldn't lead to textEdit, deletes not only itself but also the word after cursor, really get a user caught off-guard.
Simply changing the autocmd used to CompleteChanged will solve this problem in vanilla vim-lsp. However, if snippet integration is used, the textEdit handling logic doesn't seem to be able to handle the much more complex edits, and won't update the snippet applied properly on change of completion options.