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.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.