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)

4544bd2f24

Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
Jan Edmund Lazo
2025-08-15 20:12:39 -04:00
parent fbaead249b
commit d06fdecb97

View File

@@ -2250,6 +2250,7 @@ static void u_undoredo(bool undo, bool do_buf_event)
{ {
char **newarray = NULL; char **newarray = NULL;
linenr_T newlnum = MAXLNUM; linenr_T newlnum = MAXLNUM;
pos_T new_curpos = curwin->w_cursor;
u_entry_T *nuep; u_entry_T *nuep;
u_entry_T *newlist = NULL; u_entry_T *newlist = NULL;
fmark_T namedm[NMARKS]; 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 oldsize = bot - top - 1; // number of lines before undo
linenr_T newsize = uep->ue_size; // number of lines after 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 (top < newlnum) {
// If the saved cursor is somewhere in this undo block, move it to // If the saved cursor is somewhere in this undo block, move it to
// the remembered position. Makes "gwap" put the cursor back // the remembered position. Makes "gwap" put the cursor back
// where it was. // where it was.
linenr_T lnum = curhead->uh_cursor.lnum; linenr_T lnum = curhead->uh_cursor.lnum;
if (lnum >= top && lnum <= top + newsize + 1) { if (lnum >= top && lnum <= top + newsize + 1) {
curwin->w_cursor = curhead->uh_cursor; new_curpos = curhead->uh_cursor;
newlnum = curwin->w_cursor.lnum - 1; newlnum = new_curpos.lnum - 1;
} else { } else {
// Use the first line that actually changed. Avoids that // Use the first line that actually changed. Avoids that
// undoing auto-formatting puts the cursor in the previous // 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) { if (i == newsize && newlnum == MAXLNUM && uep->ue_next == NULL) {
newlnum = top; newlnum = top;
curwin->w_cursor.lnum = newlnum + 1; new_curpos.lnum = newlnum + 1;
} else if (i < newsize) { } else if (i < newsize) {
newlnum = top + (linenr_T)i; newlnum = top + (linenr_T)i;
curwin->w_cursor.lnum = newlnum + 1; new_curpos.lnum = newlnum + 1;
} }
} }
} }
bool empty_buffer = false; 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) { if (oldsize > 0) {
newarray = xmalloc(sizeof(char *) * (size_t)oldsize); newarray = xmalloc(sizeof(char *) * (size_t)oldsize);
// delete backwards, it goes faster in most cases // delete backwards, it goes faster in most cases
@@ -2344,7 +2347,10 @@ static void u_undoredo(bool undo, bool do_buf_event)
newarray = NULL; 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) { if (newsize) {
int i; int i;
linenr_T lnum; linenr_T lnum;
@@ -2423,6 +2429,10 @@ static void u_undoredo(bool undo, bool do_buf_event)
} }
// Finish adjusting extmarks // 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_entry = newlist;
curhead->uh_flags = new_flags; curhead->uh_flags = new_flags;
if ((old_flags & UH_EMPTYBUF) && buf_is_empty(curbuf)) { if ((old_flags & UH_EMPTYBUF) && buf_is_empty(curbuf)) {