Mercurial > vim
comparison src/undo.c @ 758:d591d4ceeaee
updated for version 7.0224
author | vimboss |
---|---|
date | Tue, 14 Mar 2006 23:00:46 +0000 |
parents | ac005a544e24 |
children | f0d0d3d3a1e2 |
comparison
equal
deleted
inserted
replaced
757:8b0484fd9119 | 758:d591d4ceeaee |
---|---|
37 * V | 37 * V |
38 * etc. | 38 * etc. |
39 * | 39 * |
40 * Each u_entry list contains the information for one undo or redo. | 40 * Each u_entry list contains the information for one undo or redo. |
41 * curbuf->b_u_curhead points to the header of the last undo (the next redo), | 41 * curbuf->b_u_curhead points to the header of the last undo (the next redo), |
42 * or is NULL if nothing has been undone. | 42 * or is NULL if nothing has been undone (end of the branch). |
43 * | 43 * |
44 * For keeping alternate undo/redo branches the uh_alt field is used. Thus at | 44 * For keeping alternate undo/redo branches the uh_alt field is used. Thus at |
45 * each point in the list a branch may appear for an alternate to redo. The | 45 * each point in the list a branch may appear for an alternate to redo. The |
46 * uh_seq field is numbered sequentially to be able to find a newer or older | 46 * uh_seq field is numbered sequentially to be able to find a newer or older |
47 * branch. | 47 * branch. |
48 * | 48 * |
49 * +---------------+ +---------------+ | |
50 * b_u_oldhead --->| u_header | | u_header | | |
51 * | uh_alt_next ---->| uh_alt_next ----> NULL | |
52 * NULL <----- uh_alt_prev |<------ uh_alt_prev | | |
53 * | uh_prev | | uh_prev | | |
54 * +-----|---------+ +-----|---------+ | |
55 * | | | |
56 * V V | |
57 * +---------------+ +---------------+ | |
58 * | u_header | | u_header | | |
59 * | uh_alt_next | | uh_alt_next | | |
60 * b_u_newhead --->| uh_alt_prev | | uh_alt_prev | | |
61 * | uh_prev | | uh_prev | | |
62 * +-----|---------+ +-----|---------+ | |
63 * | | | |
64 * V V | |
65 * NULL +---------------+ +---------------+ | |
66 * | u_header | | u_header | | |
67 * | uh_alt_next ---->| uh_alt_next | | |
68 * | uh_alt_prev |<------ uh_alt_prev | | |
69 * | uh_prev | | uh_prev | | |
70 * +-----|---------+ +-----|---------+ | |
71 * | | | |
72 * etc. etc. | |
73 * | |
74 * | |
49 * All data is allocated with U_ALLOC_LINE(), it will be freed as soon as the | 75 * All data is allocated with U_ALLOC_LINE(), it will be freed as soon as the |
50 * buffer is unloaded. | 76 * buffer is unloaded. |
51 */ | 77 */ |
52 | 78 |
53 #include "vim.h" | 79 #include "vim.h" |
54 | 80 |
55 /* See below: use malloc()/free() for memory management. */ | 81 /* See below: use malloc()/free() for memory management. */ |
56 #define U_USE_MALLOC 1 | 82 #define U_USE_MALLOC 1 |
57 | 83 |
84 static void u_unch_branch __ARGS((u_header_T *uhp)); | |
58 static u_entry_T *u_get_headentry __ARGS((void)); | 85 static u_entry_T *u_get_headentry __ARGS((void)); |
59 static void u_getbot __ARGS((void)); | 86 static void u_getbot __ARGS((void)); |
60 static int undo_allowed __ARGS((void)); | 87 static int undo_allowed __ARGS((void)); |
61 static int u_savecommon __ARGS((linenr_T, linenr_T, linenr_T)); | 88 static int u_savecommon __ARGS((linenr_T, linenr_T, linenr_T)); |
62 static void u_doit __ARGS((int count)); | 89 static void u_doit __ARGS((int count)); |
63 static void u_undoredo __ARGS((void)); | 90 static void u_undoredo __ARGS((void)); |
64 static void u_undo_end __ARGS((void)); | 91 static void u_undo_end __ARGS((void)); |
65 static void u_freelist __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp)); | 92 static void u_freeheader __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp)); |
66 static void u_freebranch __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp)); | 93 static void u_freebranch __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp)); |
67 static void u_freeentries __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp)); | 94 static void u_freeentries __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp)); |
68 static void u_freeentry __ARGS((u_entry_T *, long)); | 95 static void u_freeentry __ARGS((u_entry_T *, long)); |
69 | 96 |
70 #ifdef U_USE_MALLOC | 97 #ifdef U_USE_MALLOC |
268 if (uhp == NULL) | 295 if (uhp == NULL) |
269 goto nomem; | 296 goto nomem; |
270 } | 297 } |
271 | 298 |
272 /* | 299 /* |
273 * If we undid more than we redid, remove the entry lists before and | 300 * If we undid more than we redid, move the entry lists before and |
274 * including curbuf->b_u_curhead to the alternate branch. | 301 * including curbuf->b_u_curhead to an alternate branch. |
275 */ | 302 */ |
276 old_curhead = curbuf->b_u_curhead; | 303 old_curhead = curbuf->b_u_curhead; |
277 if (old_curhead != NULL) | 304 if (old_curhead != NULL) |
278 { | 305 { |
279 curbuf->b_u_newhead = old_curhead->uh_next; | 306 curbuf->b_u_newhead = old_curhead->uh_next; |
283 /* | 310 /* |
284 * free headers to keep the size right | 311 * free headers to keep the size right |
285 */ | 312 */ |
286 while (curbuf->b_u_numhead > p_ul && curbuf->b_u_oldhead != NULL) | 313 while (curbuf->b_u_numhead > p_ul && curbuf->b_u_oldhead != NULL) |
287 { | 314 { |
288 u_header_T *upfree = curbuf->b_u_oldhead; | 315 u_header_T *uhfree = curbuf->b_u_oldhead; |
289 | 316 |
290 /* If there is no branch only free one header. */ | 317 /* If there is no branch only free one header. */ |
291 if (upfree->uh_alt_next == NULL) | 318 if (uhfree->uh_alt_next == NULL) |
292 u_freelist(curbuf, upfree, &old_curhead); | 319 u_freeheader(curbuf, uhfree, &old_curhead); |
293 else | 320 else |
294 { | 321 { |
295 /* Free the oldest alternate branch as a whole. */ | 322 /* Free the oldest alternate branch as a whole. */ |
296 while (upfree->uh_alt_next != NULL) | 323 while (uhfree->uh_alt_next != NULL) |
297 upfree = upfree->uh_alt_next; | 324 uhfree = uhfree->uh_alt_next; |
298 u_freebranch(curbuf, upfree, &old_curhead); | 325 u_freebranch(curbuf, uhfree, &old_curhead); |
299 } | 326 } |
300 } | 327 } |
301 | 328 |
302 if (p_ul < 0) /* no undo at all */ | 329 if (p_ul < 0) /* no undo at all */ |
303 { | 330 { |
315 old_curhead->uh_alt_prev = uhp; | 342 old_curhead->uh_alt_prev = uhp; |
316 if (curbuf->b_u_oldhead == old_curhead) | 343 if (curbuf->b_u_oldhead == old_curhead) |
317 curbuf->b_u_oldhead = uhp; | 344 curbuf->b_u_oldhead = uhp; |
318 } | 345 } |
319 uhp->uh_alt_prev = NULL; | 346 uhp->uh_alt_prev = NULL; |
347 if (curbuf->b_u_newhead != NULL) | |
348 curbuf->b_u_newhead->uh_prev = uhp; | |
349 | |
320 uhp->uh_seq = curbuf->b_u_seq_last++; | 350 uhp->uh_seq = curbuf->b_u_seq_last++; |
321 curbuf->b_u_seq_cur = curbuf->b_u_seq_last; | 351 curbuf->b_u_seq_cur = curbuf->b_u_seq_last; |
322 if (curbuf->b_u_newhead != NULL) | 352 uhp->uh_time = time(NULL); |
323 curbuf->b_u_newhead->uh_prev = uhp; | 353 curbuf->b_u_seq_time = uhp->uh_time + 1; |
354 | |
324 uhp->uh_walk = 0; | 355 uhp->uh_walk = 0; |
325 uhp->uh_entry = NULL; | 356 uhp->uh_entry = NULL; |
326 uhp->uh_getbot_entry = NULL; | 357 uhp->uh_getbot_entry = NULL; |
327 uhp->uh_cursor = curwin->w_cursor; /* save cursor pos. for undo */ | 358 uhp->uh_cursor = curwin->w_cursor; /* save cursor pos. for undo */ |
328 #ifdef FEAT_VIRTUALEDIT | 359 #ifdef FEAT_VIRTUALEDIT |
329 if (virtual_active() && curwin->w_cursor.coladd > 0) | 360 if (virtual_active() && curwin->w_cursor.coladd > 0) |
330 uhp->uh_cursor_vcol = getviscol(); | 361 uhp->uh_cursor_vcol = getviscol(); |
331 else | 362 else |
332 uhp->uh_cursor_vcol = -1; | 363 uhp->uh_cursor_vcol = -1; |
333 #endif | 364 #endif |
334 uhp->uh_time = time(NULL); | |
335 | 365 |
336 /* save changed and buffer empty flag for undo */ | 366 /* save changed and buffer empty flag for undo */ |
337 uhp->uh_flags = (curbuf->b_changed ? UH_CHANGED : 0) + | 367 uhp->uh_flags = (curbuf->b_changed ? UH_CHANGED : 0) + |
338 ((curbuf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0); | 368 ((curbuf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0); |
339 | 369 |
573 beep_flush(); | 603 beep_flush(); |
574 break; | 604 break; |
575 } | 605 } |
576 | 606 |
577 u_undoredo(); | 607 u_undoredo(); |
578 curbuf->b_u_seq_cur = curbuf->b_u_curhead->uh_seq; | |
579 } | 608 } |
580 else | 609 else |
581 { | 610 { |
582 if (curbuf->b_u_curhead == NULL || p_ul <= 0) | 611 if (curbuf->b_u_curhead == NULL || p_ul <= 0) |
583 { | 612 { |
584 beep_flush(); /* nothing to redo */ | 613 beep_flush(); /* nothing to redo */ |
585 break; | 614 break; |
586 } | 615 } |
587 | 616 |
588 u_undoredo(); | 617 u_undoredo(); |
589 curbuf->b_u_seq_cur = curbuf->b_u_curhead->uh_seq + 1; | 618 ++curbuf->b_u_seq_cur; |
619 ++curbuf->b_u_seq_time; | |
590 | 620 |
591 /* Advance for next redo. Set "newhead" when at the end of the | 621 /* Advance for next redo. Set "newhead" when at the end of the |
592 * redoable changes. */ | 622 * redoable changes. */ |
593 if (curbuf->b_u_curhead->uh_prev == NULL) | 623 if (curbuf->b_u_curhead->uh_prev == NULL) |
594 curbuf->b_u_newhead = curbuf->b_u_curhead; | 624 curbuf->b_u_newhead = curbuf->b_u_curhead; |
601 static int lastmark = 0; | 631 static int lastmark = 0; |
602 | 632 |
603 /* | 633 /* |
604 * Undo or redo over the timeline. | 634 * Undo or redo over the timeline. |
605 * When "step" is negative go back in time, otherwise goes forward in time. | 635 * When "step" is negative go back in time, otherwise goes forward in time. |
636 * When "sec" is FALSE make "step" steps, when "sec" is TRUE use "step" as | |
637 * seconds. | |
606 */ | 638 */ |
607 void | 639 void |
608 undo_time(step) | 640 undo_time(step, sec) |
609 int step; | 641 long step; |
642 int sec; | |
610 { | 643 { |
611 long target; | 644 long target; |
612 long closest; | 645 long closest; |
646 long closest_start; | |
647 long closest_seq = 0; | |
648 long val; | |
649 long limit; | |
613 u_header_T *uhp; | 650 u_header_T *uhp; |
614 u_header_T *last; | 651 u_header_T *last; |
615 int mark; | 652 int mark; |
616 int nomark; | 653 int nomark; |
617 int round; | 654 int round; |
655 int dosec = sec; | |
656 int above = FALSE; | |
618 | 657 |
619 u_newcount = 0; | 658 u_newcount = 0; |
620 u_oldcount = 0; | 659 u_oldcount = 0; |
621 if (curbuf->b_ml.ml_flags & ML_EMPTY) | 660 if (curbuf->b_ml.ml_flags & ML_EMPTY) |
622 u_oldcount = -1; | 661 u_oldcount = -1; |
623 | 662 |
624 /* "target" is the node below which we want to be. When going forward | 663 /* "target" is the node below which we want to be. When going forward |
625 * the current one also counts, thus do one less. */ | 664 * the current one also counts, thus do one less. */ |
626 if (step < 0) | 665 if (step < 0) |
627 { | 666 { |
628 target = curbuf->b_u_seq_cur + step; | 667 if (sec) |
629 closest = -1; | 668 target = (long)curbuf->b_u_seq_time + step; |
669 else | |
670 target = curbuf->b_u_seq_cur + step; | |
671 if (target < 0) | |
672 target = -1; | |
673 closest = -2; | |
630 } | 674 } |
631 else | 675 else |
632 { | 676 { |
633 target = curbuf->b_u_seq_cur + step - 1; | 677 if (sec) |
634 closest = curbuf->b_u_seq_last + 1; | 678 { |
635 } | 679 target = curbuf->b_u_seq_time + step - 1; |
636 | 680 closest = time(NULL) + 1; |
637 /* May do this twice: | 681 } |
682 else | |
683 { | |
684 target = curbuf->b_u_seq_cur + step - 1; | |
685 closest = curbuf->b_u_seq_last + 1; | |
686 } | |
687 if (target >= closest) | |
688 target = closest - 1; | |
689 } | |
690 closest_start = closest; | |
691 if (sec) | |
692 limit = curbuf->b_u_seq_time + (step > 0 ? -1 : 1); | |
693 else | |
694 limit = curbuf->b_u_seq_cur; | |
695 | |
696 /* | |
697 * May do this twice: | |
638 * 1. Search for "target", update "closest" to the best match found. | 698 * 1. Search for "target", update "closest" to the best match found. |
639 * 2. If "target" not found search for "closest". */ | 699 * 2. If "target" not found search for "closest". |
700 * | |
701 * When using the closest time we use the sequence number in the second | |
702 * round, because there may be several entries with the same time. | |
703 */ | |
640 for (round = 1; round <= 2; ++round) | 704 for (round = 1; round <= 2; ++round) |
641 { | 705 { |
642 /* Find the path from the current state to where we want to go. The | 706 /* Find the path from the current state to where we want to go. The |
643 * desired state can be anywhere in the undo tree, need to go all over | 707 * desired state can be anywhere in the undo tree, need to go all over |
644 * it. We put "nomark" in uh_walk where we have been without success, | 708 * it. We put "nomark" in uh_walk where we have been without success, |
652 uhp = curbuf->b_u_curhead; | 716 uhp = curbuf->b_u_curhead; |
653 | 717 |
654 while (uhp != NULL) | 718 while (uhp != NULL) |
655 { | 719 { |
656 uhp->uh_walk = mark; | 720 uhp->uh_walk = mark; |
657 if (uhp->uh_seq == target) /* found it! */ | 721 val = (dosec ? uhp->uh_time : uhp->uh_seq); |
722 | |
723 if (round == 1) | |
724 { | |
725 /* Remember the header that is closest to the target. | |
726 * It must be at least in the right direction (checked with | |
727 * "limit"). When the timestamp is equal find the | |
728 * highest/lowest sequence number. */ | |
729 if ((dosec && val == closest) | |
730 ? (step < 0 | |
731 ? uhp->uh_seq < closest_seq | |
732 : uhp->uh_seq > closest_seq) | |
733 : (step < 0 | |
734 ? (val < limit | |
735 && (closest > target | |
736 ? (val <= closest) | |
737 : (val >= closest))) | |
738 : (val > limit | |
739 && (closest < target | |
740 ? val >= closest | |
741 : val <= closest)))) | |
742 { | |
743 closest = val; | |
744 closest_seq = uhp->uh_seq; | |
745 } | |
746 } | |
747 | |
748 /* Quit searching when we found a match. But when searching for a | |
749 * time we need to continue looking for the best uh_seq. */ | |
750 if (target == val && !dosec) | |
658 break; | 751 break; |
659 | |
660 if (round == 1 && (step < 0 | |
661 ? (uhp->uh_seq < target && uhp->uh_seq > closest) | |
662 : (uhp->uh_seq > target && uhp->uh_seq < closest))) | |
663 closest = uhp->uh_seq; | |
664 | 752 |
665 /* go down in the tree if we haven't been there */ | 753 /* go down in the tree if we haven't been there */ |
666 if (uhp->uh_prev != NULL && uhp->uh_prev->uh_walk != nomark | 754 if (uhp->uh_prev != NULL && uhp->uh_prev->uh_walk != nomark |
667 && uhp->uh_prev->uh_walk != mark) | 755 && uhp->uh_prev->uh_walk != mark) |
668 uhp = uhp->uh_prev; | 756 uhp = uhp->uh_prev; |
691 } | 779 } |
692 } | 780 } |
693 | 781 |
694 if (uhp != NULL) /* found it */ | 782 if (uhp != NULL) /* found it */ |
695 break; | 783 break; |
696 if (step < 0 && closest == -1) | 784 if (closest == closest_start) |
697 { | 785 { |
698 MSG(_("Already at oldest change")); | 786 if (step < 0) |
787 MSG(_("Already at oldest change")); | |
788 else | |
789 MSG(_("Already at newest change")); | |
699 return; | 790 return; |
700 } | 791 } |
701 if (step > 0 && closest == curbuf->b_u_seq_last + 1) | 792 |
702 { | 793 target = closest_seq; |
703 MSG(_("Already at newest change")); | 794 dosec = FALSE; |
704 return; | 795 if (step < 0) |
705 } | 796 above = TRUE; /* stop above the header */ |
706 | |
707 target = closest; | |
708 } | 797 } |
709 | 798 |
710 /* If we found it: Follow the path to go to where we want to be. */ | 799 /* If we found it: Follow the path to go to where we want to be. */ |
711 if (uhp != NULL) | 800 if (uhp != NULL) |
712 { | 801 { |
718 uhp = curbuf->b_u_curhead; | 807 uhp = curbuf->b_u_curhead; |
719 if (uhp == NULL) | 808 if (uhp == NULL) |
720 uhp = curbuf->b_u_newhead; | 809 uhp = curbuf->b_u_newhead; |
721 else | 810 else |
722 { | 811 { |
723 while (uhp->uh_alt_prev != NULL) | 812 while (uhp->uh_alt_prev != NULL |
813 && uhp->uh_alt_prev->uh_walk == mark) | |
724 { | 814 { |
725 uhp->uh_walk = nomark; | 815 uhp->uh_walk = nomark; |
726 uhp = uhp->uh_alt_prev; | 816 uhp = uhp->uh_alt_prev; |
727 } | 817 } |
728 uhp = uhp->uh_next; | 818 uhp = uhp->uh_next; |
730 if (uhp == NULL || uhp->uh_walk != mark) | 820 if (uhp == NULL || uhp->uh_walk != mark) |
731 break; | 821 break; |
732 curbuf->b_u_curhead = uhp; | 822 curbuf->b_u_curhead = uhp; |
733 u_undoredo(); | 823 u_undoredo(); |
734 uhp->uh_walk = nomark; /* don't go back down here */ | 824 uhp->uh_walk = nomark; /* don't go back down here */ |
735 curbuf->b_u_seq_cur = uhp->uh_seq; | |
736 } | 825 } |
737 | 826 |
738 /* | 827 /* |
739 * And now go down the tree, branching off where needed. | 828 * And now go down the tree (redo), branching off where needed. |
740 */ | 829 */ |
741 uhp = curbuf->b_u_curhead; | 830 uhp = curbuf->b_u_curhead; |
742 for (;;) | 831 for (;;) |
743 { | 832 { |
744 /* Find the last branch with a mark, that's the one. */ | 833 /* Find the last branch with a mark, that's the one. */ |
757 last->uh_alt_next = uhp; | 846 last->uh_alt_next = uhp; |
758 uhp->uh_alt_prev = last; | 847 uhp->uh_alt_prev = last; |
759 | 848 |
760 uhp = last; | 849 uhp = last; |
761 } | 850 } |
851 curbuf->b_u_curhead = uhp; | |
852 curbuf->b_u_seq_cur = uhp->uh_seq; | |
853 curbuf->b_u_seq_time = uhp->uh_time; | |
762 | 854 |
763 if (uhp->uh_walk != mark) | 855 if (uhp->uh_walk != mark) |
764 break; /* must have reached the target */ | 856 break; /* must have reached the target */ |
765 | 857 |
766 curbuf->b_u_curhead = uhp; | 858 /* Stop when going backwards in time and didn't find the exact |
859 * header we were looking for. */ | |
860 if (uhp->uh_seq == target && above) | |
861 break; | |
862 | |
767 u_undoredo(); | 863 u_undoredo(); |
768 curbuf->b_u_seq_cur = uhp->uh_seq + 1; | 864 ++curbuf->b_u_seq_cur; |
865 ++curbuf->b_u_seq_time; | |
769 | 866 |
770 /* Advance "curhead" to below the header we last used. If it | 867 /* Advance "curhead" to below the header we last used. If it |
771 * becomes NULL then we need to set "newhead" to this leaf. */ | 868 * becomes NULL then we need to set "newhead" to this leaf. */ |
772 if (uhp->uh_prev == NULL) | 869 if (uhp->uh_prev == NULL) |
773 curbuf->b_u_newhead = uhp; | 870 curbuf->b_u_newhead = uhp; |
811 pos_T namedm[NMARKS]; | 908 pos_T namedm[NMARKS]; |
812 #ifdef FEAT_VISUAL | 909 #ifdef FEAT_VISUAL |
813 visualinfo_T visualinfo; | 910 visualinfo_T visualinfo; |
814 #endif | 911 #endif |
815 int empty_buffer; /* buffer became empty */ | 912 int empty_buffer; /* buffer became empty */ |
816 | 913 u_header_T *curhead = curbuf->b_u_curhead; |
817 old_flags = curbuf->b_u_curhead->uh_flags; | 914 |
915 old_flags = curhead->uh_flags; | |
818 new_flags = (curbuf->b_changed ? UH_CHANGED : 0) + | 916 new_flags = (curbuf->b_changed ? UH_CHANGED : 0) + |
819 ((curbuf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0); | 917 ((curbuf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0); |
820 setpcmark(); | 918 setpcmark(); |
821 | 919 |
822 /* | 920 /* |
829 curbuf->b_op_start.lnum = curbuf->b_ml.ml_line_count; | 927 curbuf->b_op_start.lnum = curbuf->b_ml.ml_line_count; |
830 curbuf->b_op_start.col = 0; | 928 curbuf->b_op_start.col = 0; |
831 curbuf->b_op_end.lnum = 0; | 929 curbuf->b_op_end.lnum = 0; |
832 curbuf->b_op_end.col = 0; | 930 curbuf->b_op_end.col = 0; |
833 | 931 |
834 for (uep = curbuf->b_u_curhead->uh_entry; uep != NULL; uep = nuep) | 932 for (uep = curhead->uh_entry; uep != NULL; uep = nuep) |
835 { | 933 { |
836 top = uep->ue_top; | 934 top = uep->ue_top; |
837 bot = uep->ue_bot; | 935 bot = uep->ue_bot; |
838 if (bot == 0) | 936 if (bot == 0) |
839 bot = curbuf->b_ml.ml_line_count + 1; | 937 bot = curbuf->b_ml.ml_line_count + 1; |
851 if (top < newlnum) | 949 if (top < newlnum) |
852 { | 950 { |
853 /* If the saved cursor is somewhere in this undo block, move it to | 951 /* If the saved cursor is somewhere in this undo block, move it to |
854 * the remembered position. Makes "gwap" put the cursor back | 952 * the remembered position. Makes "gwap" put the cursor back |
855 * where it was. */ | 953 * where it was. */ |
856 lnum = curbuf->b_u_curhead->uh_cursor.lnum; | 954 lnum = curhead->uh_cursor.lnum; |
857 if (lnum >= top && lnum <= top + newsize + 1) | 955 if (lnum >= top && lnum <= top + newsize + 1) |
858 { | 956 { |
859 curwin->w_cursor = curbuf->b_u_curhead->uh_cursor; | 957 curwin->w_cursor = curhead->uh_cursor; |
860 newlnum = curwin->w_cursor.lnum - 1; | 958 newlnum = curwin->w_cursor.lnum - 1; |
861 } | 959 } |
862 else | 960 else |
863 { | 961 { |
864 /* Use the first line that actually changed. Avoids that | 962 /* Use the first line that actually changed. Avoids that |
968 nuep = uep->ue_next; | 1066 nuep = uep->ue_next; |
969 uep->ue_next = newlist; | 1067 uep->ue_next = newlist; |
970 newlist = uep; | 1068 newlist = uep; |
971 } | 1069 } |
972 | 1070 |
973 curbuf->b_u_curhead->uh_entry = newlist; | 1071 curhead->uh_entry = newlist; |
974 curbuf->b_u_curhead->uh_flags = new_flags; | 1072 curhead->uh_flags = new_flags; |
975 if ((old_flags & UH_EMPTYBUF) && bufempty()) | 1073 if ((old_flags & UH_EMPTYBUF) && bufempty()) |
976 curbuf->b_ml.ml_flags |= ML_EMPTY; | 1074 curbuf->b_ml.ml_flags |= ML_EMPTY; |
977 if (old_flags & UH_CHANGED) | 1075 if (old_flags & UH_CHANGED) |
978 changed(); | 1076 changed(); |
979 else | 1077 else |
985 | 1083 |
986 /* | 1084 /* |
987 * restore marks from before undo/redo | 1085 * restore marks from before undo/redo |
988 */ | 1086 */ |
989 for (i = 0; i < NMARKS; ++i) | 1087 for (i = 0; i < NMARKS; ++i) |
990 if (curbuf->b_u_curhead->uh_namedm[i].lnum != 0) | 1088 if (curhead->uh_namedm[i].lnum != 0) |
991 { | 1089 { |
992 curbuf->b_namedm[i] = curbuf->b_u_curhead->uh_namedm[i]; | 1090 curbuf->b_namedm[i] = curhead->uh_namedm[i]; |
993 curbuf->b_u_curhead->uh_namedm[i] = namedm[i]; | 1091 curhead->uh_namedm[i] = namedm[i]; |
994 } | 1092 } |
995 #ifdef FEAT_VISUAL | 1093 #ifdef FEAT_VISUAL |
996 if (curbuf->b_u_curhead->uh_visual.vi_start.lnum != 0) | 1094 if (curhead->uh_visual.vi_start.lnum != 0) |
997 { | 1095 { |
998 curbuf->b_visual = curbuf->b_u_curhead->uh_visual; | 1096 curbuf->b_visual = curhead->uh_visual; |
999 curbuf->b_u_curhead->uh_visual = visualinfo; | 1097 curhead->uh_visual = visualinfo; |
1000 } | 1098 } |
1001 #endif | 1099 #endif |
1002 | 1100 |
1003 /* | 1101 /* |
1004 * If the cursor is only off by one line, put it at the same position as | 1102 * If the cursor is only off by one line, put it at the same position as |
1005 * before starting the change (for the "o" command). | 1103 * before starting the change (for the "o" command). |
1006 * Otherwise the cursor should go to the first undone line. | 1104 * Otherwise the cursor should go to the first undone line. |
1007 */ | 1105 */ |
1008 if (curbuf->b_u_curhead->uh_cursor.lnum + 1 == curwin->w_cursor.lnum | 1106 if (curhead->uh_cursor.lnum + 1 == curwin->w_cursor.lnum |
1009 && curwin->w_cursor.lnum > 1) | 1107 && curwin->w_cursor.lnum > 1) |
1010 --curwin->w_cursor.lnum; | 1108 --curwin->w_cursor.lnum; |
1011 if (curbuf->b_u_curhead->uh_cursor.lnum == curwin->w_cursor.lnum) | 1109 if (curhead->uh_cursor.lnum == curwin->w_cursor.lnum) |
1012 { | 1110 { |
1013 curwin->w_cursor.col = curbuf->b_u_curhead->uh_cursor.col; | 1111 curwin->w_cursor.col = curhead->uh_cursor.col; |
1014 #ifdef FEAT_VIRTUALEDIT | 1112 #ifdef FEAT_VIRTUALEDIT |
1015 if (virtual_active() && curbuf->b_u_curhead->uh_cursor_vcol >= 0) | 1113 if (virtual_active() && curhead->uh_cursor_vcol >= 0) |
1016 coladvance((colnr_T)curbuf->b_u_curhead->uh_cursor_vcol); | 1114 coladvance((colnr_T)curhead->uh_cursor_vcol); |
1017 else | 1115 else |
1018 curwin->w_cursor.coladd = 0; | 1116 curwin->w_cursor.coladd = 0; |
1019 #endif | 1117 #endif |
1020 } | 1118 } |
1021 else if (curwin->w_cursor.lnum <= curbuf->b_ml.ml_line_count) | 1119 else if (curwin->w_cursor.lnum <= curbuf->b_ml.ml_line_count) |
1032 #endif | 1130 #endif |
1033 } | 1131 } |
1034 | 1132 |
1035 /* Make sure the cursor is on an existing line and column. */ | 1133 /* Make sure the cursor is on an existing line and column. */ |
1036 check_cursor(); | 1134 check_cursor(); |
1135 | |
1136 /* Remember where we are for "g-" and ":earlier 10s". */ | |
1137 curbuf->b_u_seq_cur = curhead->uh_seq; | |
1138 curbuf->b_u_seq_time = curhead->uh_time; | |
1037 } | 1139 } |
1038 | 1140 |
1039 /* | 1141 /* |
1040 * If we deleted or added lines, report the number of less/more lines. | 1142 * If we deleted or added lines, report the number of less/more lines. |
1041 * Otherwise, report the number of changes (this may be incorrect | 1143 * Otherwise, report the number of changes (this may be incorrect |
1134 */ | 1236 */ |
1135 void | 1237 void |
1136 u_unchanged(buf) | 1238 u_unchanged(buf) |
1137 buf_T *buf; | 1239 buf_T *buf; |
1138 { | 1240 { |
1241 u_unch_branch(buf->b_u_oldhead); | |
1242 buf->b_did_warn = FALSE; | |
1243 } | |
1244 | |
1245 static void | |
1246 u_unch_branch(uhp) | |
1247 u_header_T *uhp; | |
1248 { | |
1139 u_header_T *uh; | 1249 u_header_T *uh; |
1140 | 1250 |
1141 for (uh = buf->b_u_newhead; uh; uh = uh->uh_next) | 1251 for (uh = uhp; uh != NULL; uh = uh->uh_prev) |
1252 { | |
1142 uh->uh_flags |= UH_CHANGED; | 1253 uh->uh_flags |= UH_CHANGED; |
1143 buf->b_did_warn = FALSE; | 1254 if (uh->uh_alt_next != NULL) |
1255 u_unch_branch(uh->uh_alt_next); /* recursive */ | |
1256 } | |
1144 } | 1257 } |
1145 | 1258 |
1146 /* | 1259 /* |
1147 * Get pointer to last added entry. | 1260 * Get pointer to last added entry. |
1148 * If it's not valid, give an error message and return NULL. | 1261 * If it's not valid, give an error message and return NULL. |
1199 | 1312 |
1200 /* | 1313 /* |
1201 * Free one header and its entry list and adjust the pointers. | 1314 * Free one header and its entry list and adjust the pointers. |
1202 */ | 1315 */ |
1203 static void | 1316 static void |
1204 u_freelist(buf, uhp, uhpp) | 1317 u_freeheader(buf, uhp, uhpp) |
1205 buf_T *buf; | 1318 buf_T *buf; |
1206 u_header_T *uhp; | 1319 u_header_T *uhp; |
1207 u_header_T **uhpp; /* if not NULL reset when freeing this header */ | 1320 u_header_T **uhpp; /* if not NULL reset when freeing this header */ |
1208 { | 1321 { |
1209 /* When there is an alternate redo list free that branch completely, | 1322 /* When there is an alternate redo list free that branch completely, |
1227 | 1340 |
1228 u_freeentries(buf, uhp, uhpp); | 1341 u_freeentries(buf, uhp, uhpp); |
1229 } | 1342 } |
1230 | 1343 |
1231 /* | 1344 /* |
1232 * Free an alternate branch and all following alternate branches. | 1345 * Free an alternate branch and any following alternate branches. |
1233 */ | 1346 */ |
1234 static void | 1347 static void |
1235 u_freebranch(buf, uhp, uhpp) | 1348 u_freebranch(buf, uhp, uhpp) |
1236 buf_T *buf; | 1349 buf_T *buf; |
1237 u_header_T *uhp; | 1350 u_header_T *uhp; |
1413 void | 1526 void |
1414 u_blockfree(buf) | 1527 u_blockfree(buf) |
1415 buf_T *buf; | 1528 buf_T *buf; |
1416 { | 1529 { |
1417 while (buf->b_u_oldhead != NULL) | 1530 while (buf->b_u_oldhead != NULL) |
1418 u_freelist(buf, buf->b_u_oldhead, NULL); | 1531 u_freeheader(buf, buf->b_u_oldhead, NULL); |
1419 U_FREE_LINE(buf->b_u_line_ptr); | 1532 U_FREE_LINE(buf->b_u_line_ptr); |
1420 } | 1533 } |
1421 | 1534 |
1422 #else | 1535 #else |
1423 /* | 1536 /* |