commit d06fdecb974ecbe76d2224500cd2e82de83b3d76
parent fbaead249b15b2ad408eae689c2407924bc52225
Author: Jan Edmund Lazo <jan.lazo@mail.utoronto.ca>
Date: Fri, 15 Aug 2025 20:12:39 -0400
vim-patch:8.1.2008: error for invalid range when using listener and undo
Problem: Error for invalid range when using listener and undo. (Paul Jolly)
Solution: Do not change the cursor before the lines are restored.
(closes vim/vim#4908)
https://github.com/vim/vim/commit/4544bd2f247425c9dd743c76618dd70f53c72538
Co-authored-by: Bram Moolenaar <Bram@vim.org>
Diffstat:
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
@@ -2250,6 +2250,7 @@ static void u_undoredo(bool undo, bool do_buf_event)
{
char **newarray = NULL;
linenr_T newlnum = MAXLNUM;
+ pos_T new_curpos = curwin->w_cursor;
u_entry_T *nuep;
u_entry_T *newlist = NULL;
fmark_T namedm[NMARKS];
@@ -2294,14 +2295,16 @@ static void u_undoredo(bool undo, bool do_buf_event)
linenr_T oldsize = bot - top - 1; // number of lines before undo
linenr_T newsize = uep->ue_size; // number of lines after undo
+ // Decide about the cursor position, depending on what text changed.
+ // Don't set it yet, it may be invalid if lines are going to be added.
if (top < newlnum) {
// If the saved cursor is somewhere in this undo block, move it to
// the remembered position. Makes "gwap" put the cursor back
// where it was.
linenr_T lnum = curhead->uh_cursor.lnum;
if (lnum >= top && lnum <= top + newsize + 1) {
- curwin->w_cursor = curhead->uh_cursor;
- newlnum = curwin->w_cursor.lnum - 1;
+ new_curpos = curhead->uh_cursor;
+ newlnum = new_curpos.lnum - 1;
} else {
// Use the first line that actually changed. Avoids that
// undoing auto-formatting puts the cursor in the previous
@@ -2314,17 +2317,17 @@ static void u_undoredo(bool undo, bool do_buf_event)
}
if (i == newsize && newlnum == MAXLNUM && uep->ue_next == NULL) {
newlnum = top;
- curwin->w_cursor.lnum = newlnum + 1;
+ new_curpos.lnum = newlnum + 1;
} else if (i < newsize) {
newlnum = top + (linenr_T)i;
- curwin->w_cursor.lnum = newlnum + 1;
+ new_curpos.lnum = newlnum + 1;
}
}
}
bool empty_buffer = false;
- // delete the lines between top and bot and save them in newarray
+ // Delete the lines between top and bot and save them in newarray.
if (oldsize > 0) {
newarray = xmalloc(sizeof(char *) * (size_t)oldsize);
// delete backwards, it goes faster in most cases
@@ -2344,7 +2347,10 @@ static void u_undoredo(bool undo, bool do_buf_event)
newarray = NULL;
}
- // insert the lines in u_array between top and bot
+ // make sure the cursor is on a valid line after the deletions
+ check_cursor_lnum(curwin);
+
+ // Insert the lines in u_array between top and bot.
if (newsize) {
int i;
linenr_T lnum;
@@ -2423,6 +2429,10 @@ static void u_undoredo(bool undo, bool do_buf_event)
}
// Finish adjusting extmarks
+ // Set the cursor to the desired position. Check that the line is valid.
+ curwin->w_cursor = new_curpos;
+ check_cursor_lnum(curwin);
+
curhead->uh_entry = newlist;
curhead->uh_flags = new_flags;
if ((old_flags & UH_EMPTYBUF) && buf_is_empty(curbuf)) {