mirror of
https://github.com/neovim/neovim.git
synced 2024-12-29 14:41:06 -07:00
fix(buffer_updates): save and restore current window cursor (#16732)
When a buffer update callback is called, textlock is active so buffer text cannot be changed, but cursor can still be moved. This can cause problems when the buffer update is in the middle of an operator, like the one mentioned in #16729. The solution is to save cursor position and restore it afterwards, like how cursor is saved and restored when evaluating an <expr> mapping.
This commit is contained in:
parent
eaccd0decd
commit
89a525de9f
@ -356,6 +356,7 @@ In-process Lua plugins can receive buffer updates in the form of Lua
|
||||
callbacks. These callbacks are called frequently in various contexts;
|
||||
|textlock| prevents changing buffer contents and window layout (use
|
||||
|vim.schedule()| to defer such operations to the main loop instead).
|
||||
Moving the cursor is allowed, but it is restored afterwards.
|
||||
|
||||
|nvim_buf_attach()| will take keyword args for the callbacks. "on_lines" will
|
||||
receive parameters ("lines", {buf}, {changedtick}, {firstline}, {lastline},
|
||||
|
@ -155,10 +155,20 @@ typedef struct {
|
||||
msglist_T *private_msg_list; \
|
||||
msg_list = &private_msg_list; \
|
||||
private_msg_list = NULL; \
|
||||
code \
|
||||
code; \
|
||||
msg_list = saved_msg_list; /* Restore the exception context. */ \
|
||||
} while (0)
|
||||
|
||||
// Execute code with cursor position saved and restored and textlock active.
|
||||
#define TEXTLOCK_WRAP(code) \
|
||||
do { \
|
||||
const pos_T save_cursor = curwin->w_cursor; \
|
||||
textlock++; \
|
||||
code; \
|
||||
textlock--; \
|
||||
curwin->w_cursor = save_cursor; \
|
||||
} while (0)
|
||||
|
||||
// Useful macro for executing some `code` for each item in an array.
|
||||
#define FOREACH_ITEM(a, __foreach_item, code) \
|
||||
for (size_t (__foreach_item##_index) = 0; (__foreach_item##_index) < (a).size; \
|
||||
|
@ -188,9 +188,9 @@ void buf_updates_unload(buf_T *buf, bool can_reload)
|
||||
// the first argument is always the buffer handle
|
||||
args.items[0] = BUFFER_OBJ(buf->handle);
|
||||
|
||||
textlock++;
|
||||
TEXTLOCK_WRAP({
|
||||
nlua_call_ref(thecb, keep ? "reload" : "detach", args, false, NULL);
|
||||
textlock--;
|
||||
});
|
||||
}
|
||||
|
||||
if (keep) {
|
||||
@ -305,9 +305,11 @@ void buf_updates_send_changes(buf_T *buf, linenr_T firstline, int64_t num_added,
|
||||
args.items[6] = INTEGER_OBJ((Integer)deleted_codepoints);
|
||||
args.items[7] = INTEGER_OBJ((Integer)deleted_codeunits);
|
||||
}
|
||||
textlock++;
|
||||
Object res = nlua_call_ref(cb.on_lines, "lines", args, false, NULL);
|
||||
textlock--;
|
||||
|
||||
Object res;
|
||||
TEXTLOCK_WRAP({
|
||||
res = nlua_call_ref(cb.on_lines, "lines", args, false, NULL);
|
||||
});
|
||||
|
||||
if (res.type == kObjectTypeBoolean && res.data.boolean == true) {
|
||||
buffer_update_callbacks_free(cb);
|
||||
@ -354,9 +356,10 @@ void buf_updates_send_splice(buf_T *buf, int start_row, colnr_T start_col, bcoun
|
||||
ADD_C(args, INTEGER_OBJ(new_col));
|
||||
ADD_C(args, INTEGER_OBJ(new_byte));
|
||||
|
||||
textlock++;
|
||||
Object res = nlua_call_ref(cb.on_bytes, "bytes", args, false, NULL);
|
||||
textlock--;
|
||||
Object res;
|
||||
TEXTLOCK_WRAP({
|
||||
res = nlua_call_ref(cb.on_bytes, "bytes", args, false, NULL);
|
||||
});
|
||||
|
||||
if (res.type == kObjectTypeBoolean && res.data.boolean == true) {
|
||||
buffer_update_callbacks_free(cb);
|
||||
@ -389,10 +392,10 @@ void buf_updates_changedtick(buf_T *buf)
|
||||
// next argument is b:changedtick
|
||||
ADD_C(args, INTEGER_OBJ(buf_get_changedtick(buf)));
|
||||
|
||||
textlock++;
|
||||
Object res = nlua_call_ref(cb.on_changedtick, "changedtick",
|
||||
args, false, NULL);
|
||||
textlock--;
|
||||
Object res;
|
||||
TEXTLOCK_WRAP({
|
||||
res = nlua_call_ref(cb.on_changedtick, "changedtick", args, false, NULL);
|
||||
});
|
||||
|
||||
if (res.type == kObjectTypeBoolean && res.data.boolean == true) {
|
||||
buffer_update_callbacks_free(cb);
|
||||
|
@ -317,7 +317,18 @@ describe('lua buffer event callbacks: on_lines', function()
|
||||
feed('1G0')
|
||||
feed('P')
|
||||
eq(meths.get_var('linesev'), { "lines", 1, 6, 0, 3, 3, 9 })
|
||||
end)
|
||||
|
||||
it('calling nvim_buf_call() from callback does not cause Normal mode CTRL-A to misbehave #16729', function()
|
||||
exec_lua([[
|
||||
vim.api.nvim_buf_attach(0, false, {
|
||||
on_lines = function(...)
|
||||
vim.api.nvim_buf_call(0, function() end)
|
||||
end,
|
||||
})
|
||||
]])
|
||||
feed('itest123<Esc><C-A>')
|
||||
eq('test124', meths.get_current_line())
|
||||
end)
|
||||
end)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user