From b6dd8bbca0c61e5b4935011c3fd89db55ce3927c Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Fri, 15 Aug 2025 20:12:39 -0400 Subject: [PATCH] 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 --- src/nvim/undo.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/nvim/undo.c b/src/nvim/undo.c index 8d791a4c38..826e42beec 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -2252,6 +2252,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]; @@ -2296,14 +2297,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 @@ -2316,17 +2319,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 @@ -2346,7 +2349,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; @@ -2425,6 +2431,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)) {