Mercurial > vim
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; |