comparison src/undo.c @ 18025:d19caa851682 v8.1.2008

patch 8.1.2008: error for invalid range when using listener and undo Commit: https://github.com/vim/vim/commit/4544bd2f247425c9dd743c76618dd70f53c72538 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Sep 8 15:27:21 2019 +0200 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 #4908)
author Bram Moolenaar <Bram@vim.org>
date Sun, 08 Sep 2019 15:30:04 +0200
parents 684a15da9929
children d1e77015f60b
comparison
equal deleted inserted replaced
18024:5b68c0bb3101 18025:d19caa851682
2622 linenr_T oldsize; 2622 linenr_T oldsize;
2623 linenr_T newsize; 2623 linenr_T newsize;
2624 linenr_T top, bot; 2624 linenr_T top, bot;
2625 linenr_T lnum; 2625 linenr_T lnum;
2626 linenr_T newlnum = MAXLNUM; 2626 linenr_T newlnum = MAXLNUM;
2627 pos_T new_curpos = curwin->w_cursor;
2627 long i; 2628 long i;
2628 u_entry_T *uep, *nuep; 2629 u_entry_T *uep, *nuep;
2629 u_entry_T *newlist = NULL; 2630 u_entry_T *newlist = NULL;
2630 int old_flags; 2631 int old_flags;
2631 int new_flags; 2632 int new_flags;
2665 if (top > curbuf->b_ml.ml_line_count || top >= bot 2666 if (top > curbuf->b_ml.ml_line_count || top >= bot
2666 || bot > curbuf->b_ml.ml_line_count + 1) 2667 || bot > curbuf->b_ml.ml_line_count + 1)
2667 { 2668 {
2668 unblock_autocmds(); 2669 unblock_autocmds();
2669 iemsg(_("E438: u_undo: line numbers wrong")); 2670 iemsg(_("E438: u_undo: line numbers wrong"));
2670 changed(); /* don't want UNCHANGED now */ 2671 changed(); // don't want UNCHANGED now
2671 return; 2672 return;
2672 } 2673 }
2673 2674
2674 oldsize = bot - top - 1; /* number of lines before undo */ 2675 oldsize = bot - top - 1; // number of lines before undo
2675 newsize = uep->ue_size; /* number of lines after undo */ 2676 newsize = uep->ue_size; // number of lines after undo
2676 2677
2678 // Decide about the cursor position, depending on what text changed.
2679 // Don't set it yet, it may be invalid if lines are going to be added.
2677 if (top < newlnum) 2680 if (top < newlnum)
2678 { 2681 {
2679 /* If the saved cursor is somewhere in this undo block, move it to 2682 // If the saved cursor is somewhere in this undo block, move it to
2680 * the remembered position. Makes "gwap" put the cursor back 2683 // the remembered position. Makes "gwap" put the cursor back
2681 * where it was. */ 2684 // where it was.
2682 lnum = curhead->uh_cursor.lnum; 2685 lnum = curhead->uh_cursor.lnum;
2683 if (lnum >= top && lnum <= top + newsize + 1) 2686 if (lnum >= top && lnum <= top + newsize + 1)
2684 { 2687 {
2685 curwin->w_cursor = curhead->uh_cursor; 2688 new_curpos = curhead->uh_cursor;
2686 newlnum = curwin->w_cursor.lnum - 1; 2689 newlnum = new_curpos.lnum - 1;
2687 } 2690 }
2688 else 2691 else
2689 { 2692 {
2690 /* Use the first line that actually changed. Avoids that 2693 // Use the first line that actually changed. Avoids that
2691 * undoing auto-formatting puts the cursor in the previous 2694 // undoing auto-formatting puts the cursor in the previous
2692 * line. */ 2695 // line.
2693 for (i = 0; i < newsize && i < oldsize; ++i) 2696 for (i = 0; i < newsize && i < oldsize; ++i)
2694 { 2697 {
2695 char_u *p = ml_get(top + 1 + i); 2698 char_u *p = ml_get(top + 1 + i);
2696 2699
2697 if (curbuf->b_ml.ml_line_len != uep->ue_array[i].ul_len 2700 if (curbuf->b_ml.ml_line_len != uep->ue_array[i].ul_len
2700 break; 2703 break;
2701 } 2704 }
2702 if (i == newsize && newlnum == MAXLNUM && uep->ue_next == NULL) 2705 if (i == newsize && newlnum == MAXLNUM && uep->ue_next == NULL)
2703 { 2706 {
2704 newlnum = top; 2707 newlnum = top;
2705 curwin->w_cursor.lnum = newlnum + 1; 2708 new_curpos.lnum = newlnum + 1;
2706 } 2709 }
2707 else if (i < newsize) 2710 else if (i < newsize)
2708 { 2711 {
2709 newlnum = top + i; 2712 newlnum = top + i;
2710 curwin->w_cursor.lnum = newlnum + 1; 2713 new_curpos.lnum = newlnum + 1;
2711 } 2714 }
2712 } 2715 }
2713 } 2716 }
2714 2717
2715 empty_buffer = FALSE; 2718 empty_buffer = FALSE;
2716 2719
2717 /* delete the lines between top and bot and save them in newarray */ 2720 /*
2721 * Delete the lines between top and bot and save them in newarray.
2722 */
2718 if (oldsize > 0) 2723 if (oldsize > 0)
2719 { 2724 {
2720 if ((newarray = U_ALLOC_LINE(sizeof(undoline_T) * oldsize)) == NULL) 2725 if ((newarray = U_ALLOC_LINE(sizeof(undoline_T) * oldsize)) == NULL)
2721 { 2726 {
2722 do_outofmem_msg((long_u)(sizeof(undoline_T) * oldsize)); 2727 do_outofmem_msg((long_u)(sizeof(undoline_T) * oldsize));
2723 /* 2728
2724 * We have messed up the entry list, repair is impossible. 2729 // We have messed up the entry list, repair is impossible.
2725 * we have to free the rest of the list. 2730 // we have to free the rest of the list.
2726 */
2727 while (uep != NULL) 2731 while (uep != NULL)
2728 { 2732 {
2729 nuep = uep->ue_next; 2733 nuep = uep->ue_next;
2730 u_freeentry(uep, uep->ue_size); 2734 u_freeentry(uep, uep->ue_size);
2731 uep = nuep; 2735 uep = nuep;
2732 } 2736 }
2733 break; 2737 break;
2734 } 2738 }
2735 /* delete backwards, it goes faster in most cases */ 2739 // delete backwards, it goes faster in most cases
2736 for (lnum = bot - 1, i = oldsize; --i >= 0; --lnum) 2740 for (lnum = bot - 1, i = oldsize; --i >= 0; --lnum)
2737 { 2741 {
2738 /* what can we do when we run out of memory? */ 2742 // what can we do when we run out of memory?
2739 if (u_save_line(&newarray[i], lnum) == FAIL) 2743 if (u_save_line(&newarray[i], lnum) == FAIL)
2740 do_outofmem_msg((long_u)0); 2744 do_outofmem_msg((long_u)0);
2741 /* remember we deleted the last line in the buffer, and a 2745 // remember we deleted the last line in the buffer, and a
2742 * dummy empty line will be inserted */ 2746 // dummy empty line will be inserted
2743 if (curbuf->b_ml.ml_line_count == 1) 2747 if (curbuf->b_ml.ml_line_count == 1)
2744 empty_buffer = TRUE; 2748 empty_buffer = TRUE;
2745 ml_delete(lnum, FALSE); 2749 ml_delete(lnum, FALSE);
2746 } 2750 }
2747 } 2751 }
2748 else 2752 else
2749 newarray = NULL; 2753 newarray = NULL;
2750 2754
2751 /* insert the lines in u_array between top and bot */ 2755 // make sure the cursor is on a valid line after the deletions
2756 check_cursor_lnum();
2757
2758 /*
2759 * Insert the lines in u_array between top and bot.
2760 */
2752 if (newsize) 2761 if (newsize)
2753 { 2762 {
2754 for (lnum = top, i = 0; i < newsize; ++i, ++lnum) 2763 for (lnum = top, i = 0; i < newsize; ++i, ++lnum)
2755 { 2764 {
2756 // If the file is empty, there is an empty line 1 that we 2765 // If the file is empty, there is an empty line 1 that we
2764 vim_free(uep->ue_array[i].ul_line); 2773 vim_free(uep->ue_array[i].ul_line);
2765 } 2774 }
2766 vim_free((char_u *)uep->ue_array); 2775 vim_free((char_u *)uep->ue_array);
2767 } 2776 }
2768 2777
2769 /* adjust marks */ 2778 // adjust marks
2770 if (oldsize != newsize) 2779 if (oldsize != newsize)
2771 { 2780 {
2772 mark_adjust(top + 1, top + oldsize, (long)MAXLNUM, 2781 mark_adjust(top + 1, top + oldsize, (long)MAXLNUM,
2773 (long)newsize - (long)oldsize); 2782 (long)newsize - (long)oldsize);
2774 if (curbuf->b_op_start.lnum > top + oldsize) 2783 if (curbuf->b_op_start.lnum > top + oldsize)
2777 curbuf->b_op_end.lnum += newsize - oldsize; 2786 curbuf->b_op_end.lnum += newsize - oldsize;
2778 } 2787 }
2779 2788
2780 changed_lines(top + 1, 0, bot, newsize - oldsize); 2789 changed_lines(top + 1, 0, bot, newsize - oldsize);
2781 2790
2782 /* set '[ and '] mark */ 2791 // set '[ and '] mark
2783 if (top + 1 < curbuf->b_op_start.lnum) 2792 if (top + 1 < curbuf->b_op_start.lnum)
2784 curbuf->b_op_start.lnum = top + 1; 2793 curbuf->b_op_start.lnum = top + 1;
2785 if (newsize == 0 && top + 1 > curbuf->b_op_end.lnum) 2794 if (newsize == 0 && top + 1 > curbuf->b_op_end.lnum)
2786 curbuf->b_op_end.lnum = top + 1; 2795 curbuf->b_op_end.lnum = top + 1;
2787 else if (top + newsize > curbuf->b_op_end.lnum) 2796 else if (top + newsize > curbuf->b_op_end.lnum)
2798 */ 2807 */
2799 nuep = uep->ue_next; 2808 nuep = uep->ue_next;
2800 uep->ue_next = newlist; 2809 uep->ue_next = newlist;
2801 newlist = uep; 2810 newlist = uep;
2802 } 2811 }
2812
2813 // Set the cursor to the desired position. Check that the line is valid.
2814 curwin->w_cursor = new_curpos;
2815 check_cursor_lnum();
2803 2816
2804 curhead->uh_entry = newlist; 2817 curhead->uh_entry = newlist;
2805 curhead->uh_flags = new_flags; 2818 curhead->uh_flags = new_flags;
2806 if ((old_flags & UH_EMPTYBUF) && BUFEMPTY()) 2819 if ((old_flags & UH_EMPTYBUF) && BUFEMPTY())
2807 curbuf->b_ml.ml_flags |= ML_EMPTY; 2820 curbuf->b_ml.ml_flags |= ML_EMPTY;