aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/api.txt1
-rw-r--r--src/nvim/api/private/helpers.h14
-rw-r--r--src/nvim/buffer_updates.c29
-rw-r--r--test/functional/lua/buffer_updates_spec.lua11
4 files changed, 40 insertions, 15 deletions
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index 3ca50dda15..2930f2314b 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -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},
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h
index b70452d7cb..1b82aeac34 100644
--- a/src/nvim/api/private/helpers.h
+++ b/src/nvim/api/private/helpers.h
@@ -155,8 +155,18 @@ typedef struct {
msglist_T *private_msg_list; \
msg_list = &private_msg_list; \
private_msg_list = NULL; \
- code \
- msg_list = saved_msg_list; /* Restore the exception context. */ \
+ 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.
diff --git a/src/nvim/buffer_updates.c b/src/nvim/buffer_updates.c
index 075ac2adbf..9543731c9b 100644
--- a/src/nvim/buffer_updates.c
+++ b/src/nvim/buffer_updates.c
@@ -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++;
- nlua_call_ref(thecb, keep ? "reload" : "detach", args, false, NULL);
- textlock--;
+ TEXTLOCK_WRAP({
+ nlua_call_ref(thecb, keep ? "reload" : "detach", args, false, NULL);
+ });
}
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);
diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua
index 2fd44b8b5f..b1b39501f7 100644
--- a/test/functional/lua/buffer_updates_spec.lua
+++ b/test/functional/lua/buffer_updates_spec.lua
@@ -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)