Re: [vim/vim] listener_add() callback receives errronious information for 'undo' operations (Issue #19947)
h_east (Vim Github Repository) <[email protected]>
| Newsgroups | gmane.editors.vim.devel |
|---|---|
| Message-ID | <vim/vim/issues/19947/[email protected]> |
h-east left a comment (vim/vim#19947)
I reproduced this and looked at the code. The values reported to the callback
are correct; `listener_add()` is not returning erroneous information.
With a three line buffer, `dd` on line 1 followed by `u`, the callback is
invoked twice and each change is delivered exactly once:
```
dd -> {'lnum': 1, 'col': 1, 'added': -1, 'end': 2}
u -> {'lnum': 1, 'col': 1, 'added': 1, 'end': 1}
```
The net line count change is 0, which matches the buffer going from 3 lines to
2 and back to 3.
The reason the second dictionary appears to arrive at the wrong time is
buffering. With a buffered listener and no flush between the two commands, the
change recorded for `dd` is delivered *while* the `u` command is running, not
after `dd`. Vim flushes pending changes before it modifies the text, in
`ml_append_flags()` and `ml_delete_flags()`:
```c
// When inserting above recorded changes: flush the changes before changing
// the text.
may_invoke_listeners(curbuf, lnum, lnum + 1, -1);
```
This is deliberate, so that the callback can still read a buffer state that
matches the line numbers it was given. The consequence is that the payload a
callback receives does not necessarily belong to the command you just typed.
Attributing it to that command is what makes the undo look like it reported a
deletion.
Registering the listener as unbuffered gives one callback per change, in step
with the operations:
```vim
let id = listener_add(funcref, bufnr(), v:true)
```
The unbuffered mode was added in 9.1.1782.
I suggest closing this. If anything is worth changing it is the documentation
of `listener_add()`, which explains that line numbers may become invalid in
buffered mode but does not say that a callback may be invoked in the middle of
another command carrying an earlier change.
There is a separate limitation you will run into when building an LSP client,
which is not the problem reported here. A change that does not alter the line
count never causes a flush, so two edits to the same line are reported
together and `getbufline()` can then only return the result of the second one.
The text of the first one is gone. #21071 adds a "text" option to
`listener_add()` that puts the resulting text in each change entry, copied at
the moment the change is recorded.
--
Reply to this email directly or view it on GitHub:
https://github.com/vim/vim/issues/19947#issuecomment-5314388746
You are receiving this because you are subscribed to this thread.
Message ID: <vim/vim/issues/19947/[email protected]>
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups "vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To view this discussion visit https://groups.google.com/d/msgid/vim_dev/vim/vim/issues/19947/5314388746%40github.com.