Thanks very much for this. On Sun, 8 Sep 2019 at 14:28, Bram Moolenaar <[email protected]> wrote: > > > Patch 8.1.2008 > Problem: Error for invalid range when using listener and undo. (Paul Jolly) > Solution: Do not change the cursor before the lines are restored. > (closes #4908) > Files: src/undo.c, src/testdir/test_listener.vim > > > *** ../vim-8.1.2007/src/undo.c 2019-09-04 17:48:11.712877356 +0200 > --- src/undo.c 2019-09-08 15:20:23.437532804 +0200 > *************** > *** 2624,2629 **** > --- 2624,2630 ---- > linenr_T top, bot; > linenr_T lnum; > linenr_T newlnum = MAXLNUM; > + pos_T new_curpos = curwin->w_cursor; > long i; > u_entry_T *uep, *nuep; > u_entry_T *newlist = NULL; > *************** > *** 2667,2695 **** > { > unblock_autocmds(); > iemsg(_("E438: u_undo: line numbers wrong")); > ! changed(); /* don't want UNCHANGED now */ > return; > } > > ! oldsize = bot - top - 1; /* number of lines before undo */ > ! newsize = uep->ue_size; /* number of lines after undo */ > > 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. */ > lnum = curhead->uh_cursor.lnum; > if (lnum >= top && lnum <= top + newsize + 1) > { > ! curwin->w_cursor = curhead->uh_cursor; > ! newlnum = curwin->w_cursor.lnum - 1; > } > else > { > ! /* Use the first line that actually changed. Avoids that > ! * undoing auto-formatting puts the cursor in the previous > ! * line. */ > for (i = 0; i < newsize && i < oldsize; ++i) > { > char_u *p = ml_get(top + 1 + i); > --- 2668,2698 ---- > { > unblock_autocmds(); > iemsg(_("E438: u_undo: line numbers wrong")); > ! changed(); // don't want UNCHANGED now > return; > } > > ! oldsize = bot - top - 1; // number of lines before undo > ! 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. > lnum = curhead->uh_cursor.lnum; > if (lnum >= top && lnum <= top + newsize + 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 > ! // line. > for (i = 0; i < newsize && i < oldsize; ++i) > { > char_u *p = ml_get(top + 1 + i); > *************** > *** 2702,2729 **** > if (i == newsize && newlnum == MAXLNUM && uep->ue_next == > NULL) > { > newlnum = top; > ! curwin->w_cursor.lnum = newlnum + 1; > } > else if (i < newsize) > { > newlnum = top + i; > ! curwin->w_cursor.lnum = newlnum + 1; > } > } > } > > empty_buffer = FALSE; > > ! /* delete the lines between top and bot and save them in newarray */ > if (oldsize > 0) > { > if ((newarray = U_ALLOC_LINE(sizeof(undoline_T) * oldsize)) == > NULL) > { > do_outofmem_msg((long_u)(sizeof(undoline_T) * oldsize)); > ! /* > ! * We have messed up the entry list, repair is impossible. > ! * we have to free the rest of the list. > ! */ > while (uep != NULL) > { > nuep = uep->ue_next; > --- 2705,2733 ---- > if (i == newsize && newlnum == MAXLNUM && uep->ue_next == > NULL) > { > newlnum = top; > ! new_curpos.lnum = newlnum + 1; > } > else if (i < newsize) > { > newlnum = top + i; > ! new_curpos.lnum = newlnum + 1; > } > } > } > > empty_buffer = FALSE; > > ! /* > ! * Delete the lines between top and bot and save them in newarray. > ! */ > if (oldsize > 0) > { > if ((newarray = U_ALLOC_LINE(sizeof(undoline_T) * oldsize)) == > NULL) > { > do_outofmem_msg((long_u)(sizeof(undoline_T) * oldsize)); > ! > ! // We have messed up the entry list, repair is impossible. > ! // we have to free the rest of the list. > while (uep != NULL) > { > nuep = uep->ue_next; > *************** > *** 2732,2745 **** > } > break; > } > ! /* delete backwards, it goes faster in most cases */ > for (lnum = bot - 1, i = oldsize; --i >= 0; --lnum) > { > ! /* what can we do when we run out of memory? */ > if (u_save_line(&newarray[i], lnum) == FAIL) > do_outofmem_msg((long_u)0); > ! /* remember we deleted the last line in the buffer, and a > ! * dummy empty line will be inserted */ > if (curbuf->b_ml.ml_line_count == 1) > empty_buffer = TRUE; > ml_delete(lnum, FALSE); > --- 2736,2749 ---- > } > break; > } > ! // delete backwards, it goes faster in most cases > for (lnum = bot - 1, i = oldsize; --i >= 0; --lnum) > { > ! // what can we do when we run out of memory? > if (u_save_line(&newarray[i], lnum) == FAIL) > do_outofmem_msg((long_u)0); > ! // remember we deleted the last line in the buffer, and a > ! // dummy empty line will be inserted > if (curbuf->b_ml.ml_line_count == 1) > empty_buffer = TRUE; > ml_delete(lnum, FALSE); > *************** > *** 2748,2754 **** > else > newarray = NULL; > > ! /* insert the lines in u_array between top and bot */ > if (newsize) > { > for (lnum = top, i = 0; i < newsize; ++i, ++lnum) > --- 2752,2763 ---- > else > newarray = NULL; > > ! // make sure the cursor is on a valid line after the deletions > ! check_cursor_lnum(); > ! > ! /* > ! * Insert the lines in u_array between top and bot. > ! */ > if (newsize) > { > for (lnum = top, i = 0; i < newsize; ++i, ++lnum) > *************** > *** 2766,2772 **** > vim_free((char_u *)uep->ue_array); > } > > ! /* adjust marks */ > if (oldsize != newsize) > { > mark_adjust(top + 1, top + oldsize, (long)MAXLNUM, > --- 2775,2781 ---- > vim_free((char_u *)uep->ue_array); > } > > ! // adjust marks > if (oldsize != newsize) > { > mark_adjust(top + 1, top + oldsize, (long)MAXLNUM, > *************** > *** 2779,2785 **** > > changed_lines(top + 1, 0, bot, newsize - oldsize); > > ! /* set '[ and '] mark */ > if (top + 1 < curbuf->b_op_start.lnum) > curbuf->b_op_start.lnum = top + 1; > if (newsize == 0 && top + 1 > curbuf->b_op_end.lnum) > --- 2788,2794 ---- > > changed_lines(top + 1, 0, bot, newsize - oldsize); > > ! // set '[ and '] mark > if (top + 1 < curbuf->b_op_start.lnum) > curbuf->b_op_start.lnum = top + 1; > if (newsize == 0 && top + 1 > curbuf->b_op_end.lnum) > *************** > *** 2801,2806 **** > --- 2810,2819 ---- > newlist = uep; > } > > + // Set the cursor to the desired position. Check that the line is > valid. > + curwin->w_cursor = new_curpos; > + check_cursor_lnum(); > + > curhead->uh_entry = newlist; > curhead->uh_flags = new_flags; > if ((old_flags & UH_EMPTYBUF) && BUFEMPTY()) > *** ../vim-8.1.2007/src/testdir/test_listener.vim 2019-08-31 > 22:16:30.774127008 +0200 > --- src/testdir/test_listener.vim 2019-09-08 15:08:56.524062392 +0200 > *************** > *** 234,240 **** > new > let id = listener_add(function('MyListener', [{}]), bufnr('')) > call test_garbagecollect_now() > ! " must not crach caused by invalid memory access > normal ia > call assert_true(v:true) > > --- 234,240 ---- > new > let id = listener_add(function('MyListener', [{}]), bufnr('')) > call test_garbagecollect_now() > ! " must not crash caused by invalid memory access > normal ia > call assert_true(v:true) > > *************** > *** 268,270 **** > --- 268,292 ---- > iunmap <CR> > set nocindent > endfunc > + > + " Verify the fix for issue #4908 > + func Test_listener_undo_line_number() > + function DoIt() > + " NOP > + endfunction > + function EchoChanges(bufnr, start, end, added, changes) > + call DoIt() > + endfunction > + > + new > + let lid = listener_add("EchoChanges") > + call setline(1, ['a', 'b', 'c']) > + set undolevels& " start new undo block > + call feedkeys("ggcG\<Esc>", 'xt') > + undo > + > + bwipe! > + delfunc DoIt > + delfunc EchoChanges > + call listener_remove(lid) > + endfunc > *** ../vim-8.1.2007/src/version.c 2019-09-08 14:07:43.104866704 +0200 > --- src/version.c 2019-09-08 15:25:54.516311353 +0200 > *************** > *** 759,760 **** > --- 759,762 ---- > { /* Add new patch number below this line */ > + /**/ > + 2008, > /**/ > > -- > Don't be humble ... you're not that great. > -- Golda Meir > > /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\ > /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ > \\\ an exciting new programming language -- http://www.Zimbu.org /// > \\\ help me help AIDS victims -- http://ICCF-Holland.org /// > > -- > -- > You received this message from the "vim_dev" maillist. > Do not top-post! Type your reply below the text you are replying to. > For more information, visit http://www.vim.org/maillist.php > > --- > You received this message because you are subscribed to the Google Groups > "vim_dev" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > To view this discussion on the web visit > https://groups.google.com/d/msgid/vim_dev/201909081328.x88DS5nX006278%40masaka.moolenaar.net.
-- -- You received this message from the "vim_dev" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php --- You received this message because you are subscribed to the Google Groups "vim_dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/vim_dev/CACoUkn7sOo7oe1cugBqs9mz1_mM5QuHUC4Rj9UY4rMXXJPJkuQ%40mail.gmail.com.
