aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2023-03-09 10:19:00 +0800
committerGitHub <noreply@github.com>2023-03-09 10:19:00 +0800
commit89a525de9f2551e460cc91d40fd7afbb7e07622f (patch)
tree2e9bd543d89b693c7a6382fa66ec82488f8a0c61 /src
parenteaccd0decd707ff7cec318e06914f963daa9574c (diff)
downloadrneovim-89a525de9f2551e460cc91d40fd7afbb7e07622f.tar.gz
rneovim-89a525de9f2551e460cc91d40fd7afbb7e07622f.tar.bz2
rneovim-89a525de9f2551e460cc91d40fd7afbb7e07622f.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/private/helpers.h14
-rw-r--r--src/nvim/buffer_updates.c29
2 files changed, 28 insertions, 15 deletions
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);