comparison src/undo.c @ 777:f664cc974a7a

updated for version 7.0227
author vimboss
date Fri, 17 Mar 2006 23:19:38 +0000
parents aaaca5077255
children f19994020dad
comparison
equal deleted inserted replaced
776:5a5a080c2776 777:f664cc974a7a
85 static u_entry_T *u_get_headentry __ARGS((void)); 85 static u_entry_T *u_get_headentry __ARGS((void));
86 static void u_getbot __ARGS((void)); 86 static void u_getbot __ARGS((void));
87 static int undo_allowed __ARGS((void)); 87 static int undo_allowed __ARGS((void));
88 static int u_savecommon __ARGS((linenr_T, linenr_T, linenr_T)); 88 static int u_savecommon __ARGS((linenr_T, linenr_T, linenr_T));
89 static void u_doit __ARGS((int count)); 89 static void u_doit __ARGS((int count));
90 static void u_undoredo __ARGS((void)); 90 static void u_undoredo __ARGS((int undo));
91 static void u_undo_end __ARGS((void)); 91 static void u_undo_end __ARGS((void));
92 static void u_add_time __ARGS((char_u *buf, size_t buflen, time_t tt)); 92 static void u_add_time __ARGS((char_u *buf, size_t buflen, time_t tt));
93 static void u_freeheader __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp)); 93 static void u_freeheader __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp));
94 static void u_freebranch __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp)); 94 static void u_freebranch __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp));
95 static void u_freeentries __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp)); 95 static void u_freeentries __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp));
348 } 348 }
349 uhp->uh_alt_prev = NULL; 349 uhp->uh_alt_prev = NULL;
350 if (curbuf->b_u_newhead != NULL) 350 if (curbuf->b_u_newhead != NULL)
351 curbuf->b_u_newhead->uh_prev = uhp; 351 curbuf->b_u_newhead->uh_prev = uhp;
352 352
353 uhp->uh_seq = curbuf->b_u_seq_last++; 353 uhp->uh_seq = ++curbuf->b_u_seq_last;
354 curbuf->b_u_seq_cur = curbuf->b_u_seq_last; 354 curbuf->b_u_seq_cur = uhp->uh_seq;
355 uhp->uh_time = time(NULL); 355 uhp->uh_time = time(NULL);
356 curbuf->b_u_seq_time = uhp->uh_time + 1; 356 curbuf->b_u_seq_time = uhp->uh_time + 1;
357 357
358 uhp->uh_walk = 0; 358 uhp->uh_walk = 0;
359 uhp->uh_entry = NULL; 359 uhp->uh_entry = NULL;
577 577
578 /* 578 /*
579 * Undo or redo, depending on 'undo_undoes', 'count' times. 579 * Undo or redo, depending on 'undo_undoes', 'count' times.
580 */ 580 */
581 static void 581 static void
582 u_doit(count) 582 u_doit(startcount)
583 int count; 583 int startcount;
584 { 584 {
585 int count = startcount;
586
585 if (!undo_allowed()) 587 if (!undo_allowed())
586 return; 588 return;
587 589
588 u_newcount = 0; 590 u_newcount = 0;
589 u_oldcount = 0; 591 u_oldcount = 0;
602 if (curbuf->b_u_numhead == 0 || curbuf->b_u_curhead == NULL) 604 if (curbuf->b_u_numhead == 0 || curbuf->b_u_curhead == NULL)
603 { 605 {
604 /* stick curbuf->b_u_curhead at end */ 606 /* stick curbuf->b_u_curhead at end */
605 curbuf->b_u_curhead = curbuf->b_u_oldhead; 607 curbuf->b_u_curhead = curbuf->b_u_oldhead;
606 beep_flush(); 608 beep_flush();
609 if (count == startcount - 1)
610 {
611 MSG(_("Already at oldest change"));
612 return;
613 }
607 break; 614 break;
608 } 615 }
609 616
610 u_undoredo(); 617 u_undoredo(TRUE);
611 } 618 }
612 else 619 else
613 { 620 {
614 if (curbuf->b_u_curhead == NULL || p_ul <= 0) 621 if (curbuf->b_u_curhead == NULL || p_ul <= 0)
615 { 622 {
616 beep_flush(); /* nothing to redo */ 623 beep_flush(); /* nothing to redo */
624 if (count == startcount - 1)
625 {
626 MSG(_("Already at newest change"));
627 return;
628 }
617 break; 629 break;
618 } 630 }
619 631
620 u_undoredo(); 632 u_undoredo(FALSE);
621 ++curbuf->b_u_seq_cur;
622 ++curbuf->b_u_seq_time;
623 633
624 /* Advance for next redo. Set "newhead" when at the end of the 634 /* Advance for next redo. Set "newhead" when at the end of the
625 * redoable changes. */ 635 * redoable changes. */
626 if (curbuf->b_u_curhead->uh_prev == NULL) 636 if (curbuf->b_u_curhead->uh_prev == NULL)
627 curbuf->b_u_newhead = curbuf->b_u_curhead; 637 curbuf->b_u_newhead = curbuf->b_u_curhead;
650 long target; 660 long target;
651 long closest; 661 long closest;
652 long closest_start; 662 long closest_start;
653 long closest_seq = 0; 663 long closest_seq = 0;
654 long val; 664 long val;
655 long limit;
656 u_header_T *uhp; 665 u_header_T *uhp;
657 u_header_T *last; 666 u_header_T *last;
658 int mark; 667 int mark;
659 int nomark; 668 int nomark;
660 int round; 669 int round;
668 u_newcount = 0; 677 u_newcount = 0;
669 u_oldcount = 0; 678 u_oldcount = 0;
670 if (curbuf->b_ml.ml_flags & ML_EMPTY) 679 if (curbuf->b_ml.ml_flags & ML_EMPTY)
671 u_oldcount = -1; 680 u_oldcount = -1;
672 681
673 /* "target" is the node below which we want to be. When going forward 682 /* "target" is the node below which we want to be.
674 * the current one also counts, thus do one less. */ 683 * Init "closest" to a value we can't reach. */
675 if (absolute) 684 if (absolute)
676 { 685 {
677 target = step; 686 target = step;
678 closest = -2; 687 closest = -1;
679 } 688 }
680 else if (step < 0) 689 else
681 { 690 {
691 /* When doing computations with time_t subtract starttime, because
692 * time_t converted to a long may result in a wrong number. */
682 if (sec) 693 if (sec)
683 target = (long)curbuf->b_u_seq_time + step; 694 target = (long)(curbuf->b_u_seq_time - starttime) + step;
684 else 695 else
685 target = curbuf->b_u_seq_cur + step; 696 target = curbuf->b_u_seq_cur + step;
686 if (target < 0) 697 if (step < 0)
687 target = -1; 698 {
688 closest = -2; 699 if (target < 0)
689 } 700 target = 0;
690 else 701 closest = -1;
691 {
692 if (sec)
693 {
694 target = curbuf->b_u_seq_time + step - 1;
695 closest = time(NULL) + 1;
696 } 702 }
697 else 703 else
698 { 704 {
699 target = curbuf->b_u_seq_cur + step - 1; 705 if (sec)
700 closest = curbuf->b_u_seq_last + 1; 706 closest = time(NULL) - starttime + 1;
701 } 707 else
702 if (target >= closest) 708 closest = curbuf->b_u_seq_last + 2;
703 target = closest - 1; 709 if (target >= closest)
710 target = closest - 1;
711 }
704 } 712 }
705 closest_start = closest; 713 closest_start = closest;
706 if (sec) 714 closest_seq = curbuf->b_u_seq_cur;
707 limit = curbuf->b_u_seq_time + (step > 0 ? -1 : 1);
708 else
709 limit = curbuf->b_u_seq_cur;
710 715
711 /* 716 /*
712 * May do this twice: 717 * May do this twice:
713 * 1. Search for "target", update "closest" to the best match found. 718 * 1. Search for "target", update "closest" to the best match found.
714 * 2. If "target" not found search for "closest". 719 * 2. If "target" not found search for "closest".
731 uhp = curbuf->b_u_curhead; 736 uhp = curbuf->b_u_curhead;
732 737
733 while (uhp != NULL) 738 while (uhp != NULL)
734 { 739 {
735 uhp->uh_walk = mark; 740 uhp->uh_walk = mark;
736 val = (dosec ? uhp->uh_time : uhp->uh_seq); 741 val = (dosec ? (uhp->uh_time - starttime) : uhp->uh_seq);
737 742
738 if (round == 1) 743 if (round == 1)
739 { 744 {
740 /* Remember the header that is closest to the target. 745 /* Remember the header that is closest to the target.
741 * It must be at least in the right direction (checked with 746 * It must be at least in the right direction (checked with
742 * "limit"). When the timestamp is equal find the 747 * "b_u_seq_cur"). When the timestamp is equal find the
743 * highest/lowest sequence number. */ 748 * highest/lowest sequence number. */
744 if ((dosec && val == closest) 749 if ((step < 0 ? uhp->uh_seq <= curbuf->b_u_seq_cur
745 ? (step < 0 750 : uhp->uh_seq > curbuf->b_u_seq_cur)
746 ? uhp->uh_seq < closest_seq 751 && ((dosec && val == closest)
747 : uhp->uh_seq > closest_seq) 752 ? (step < 0
748 : (step < 0 753 ? uhp->uh_seq < closest_seq
749 ? (val < limit 754 : uhp->uh_seq > closest_seq)
750 && (closest > target 755 : closest == closest_start
751 ? (val <= closest) 756 || (val > target
752 : (val >= closest))) 757 ? (closest > target
753 : (val > limit 758 ? val - target <= closest - target
754 && (closest < target 759 : val - target <= target - closest)
755 ? val >= closest 760 : (closest > target
756 : val <= closest)))) 761 ? target - val <= closest - target
762 : target - val <= target - closest))))
757 { 763 {
758 closest = val; 764 closest = val;
759 closest_seq = uhp->uh_seq; 765 closest_seq = uhp->uh_seq;
760 } 766 }
761 } 767 }
828 { 834 {
829 uhp = curbuf->b_u_curhead; 835 uhp = curbuf->b_u_curhead;
830 if (uhp == NULL) 836 if (uhp == NULL)
831 uhp = curbuf->b_u_newhead; 837 uhp = curbuf->b_u_newhead;
832 else 838 else
833 {
834 while (uhp->uh_alt_prev != NULL
835 && uhp->uh_alt_prev->uh_walk == mark)
836 {
837 uhp->uh_walk = nomark;
838 uhp = uhp->uh_alt_prev;
839 }
840 uhp = uhp->uh_next; 839 uhp = uhp->uh_next;
841 } 840 if (uhp == NULL || uhp->uh_walk != mark
842 if (uhp == NULL || uhp->uh_walk != mark) 841 || (uhp->uh_seq == target && !above))
843 break; 842 break;
844 curbuf->b_u_curhead = uhp; 843 curbuf->b_u_curhead = uhp;
845 u_undoredo(); 844 u_undoredo(TRUE);
846 uhp->uh_walk = nomark; /* don't go back down here */ 845 uhp->uh_walk = nomark; /* don't go back down here */
847 } 846 }
848 847
849 /* 848 /*
850 * And now go down the tree (redo), branching off where needed. 849 * And now go down the tree (redo), branching off where needed.
851 */ 850 */
852 uhp = curbuf->b_u_curhead; 851 uhp = curbuf->b_u_curhead;
853 for (;;) 852 while (uhp != NULL)
854 { 853 {
855 /* Find the last branch with a mark, that's the one. */ 854 /* Find the last branch with a mark, that's the one. */
856 last = uhp; 855 last = uhp;
857 while (last->uh_alt_next != NULL 856 while (last->uh_alt_next != NULL
858 && last->uh_alt_next->uh_walk == mark) 857 && last->uh_alt_next->uh_walk == mark)
867 last->uh_alt_prev = NULL; 866 last->uh_alt_prev = NULL;
868 last->uh_alt_next = uhp; 867 last->uh_alt_next = uhp;
869 uhp->uh_alt_prev = last; 868 uhp->uh_alt_prev = last;
870 869
871 uhp = last; 870 uhp = last;
871 if (uhp->uh_next != NULL)
872 uhp->uh_next->uh_prev = uhp;
872 } 873 }
873 curbuf->b_u_curhead = uhp; 874 curbuf->b_u_curhead = uhp;
874 curbuf->b_u_seq_cur = uhp->uh_seq;
875 curbuf->b_u_seq_time = uhp->uh_time;
876 875
877 if (uhp->uh_walk != mark) 876 if (uhp->uh_walk != mark)
878 break; /* must have reached the target */ 877 break; /* must have reached the target */
879 878
880 /* Stop when going backwards in time and didn't find the exact 879 /* Stop when going backwards in time and didn't find the exact
881 * header we were looking for. */ 880 * header we were looking for. */
882 if (uhp->uh_seq == target && above) 881 if (uhp->uh_seq == target && above)
883 break; 882 break;
884 883
885 u_undoredo(); 884 u_undoredo(FALSE);
886 ++curbuf->b_u_seq_cur;
887 ++curbuf->b_u_seq_time;
888 885
889 /* Advance "curhead" to below the header we last used. If it 886 /* Advance "curhead" to below the header we last used. If it
890 * becomes NULL then we need to set "newhead" to this leaf. */ 887 * becomes NULL then we need to set "newhead" to this leaf. */
891 if (uhp->uh_prev == NULL) 888 if (uhp->uh_prev == NULL)
892 curbuf->b_u_newhead = uhp; 889 curbuf->b_u_newhead = uhp;
896 break; 893 break;
897 894
898 uhp = uhp->uh_prev; 895 uhp = uhp->uh_prev;
899 if (uhp == NULL || uhp->uh_walk != mark) 896 if (uhp == NULL || uhp->uh_walk != mark)
900 { 897 {
898 /* Need to redo more but can't find it... */
901 EMSG2(_(e_intern2), "undo_time()"); 899 EMSG2(_(e_intern2), "undo_time()");
902 break; 900 break;
903 } 901 }
904 } 902 }
905 } 903 }
910 * u_undoredo: common code for undo and redo 908 * u_undoredo: common code for undo and redo
911 * 909 *
912 * The lines in the file are replaced by the lines in the entry list at 910 * The lines in the file are replaced by the lines in the entry list at
913 * curbuf->b_u_curhead. The replaced lines in the file are saved in the entry 911 * curbuf->b_u_curhead. The replaced lines in the file are saved in the entry
914 * list for the next undo/redo. 912 * list for the next undo/redo.
913 *
914 * When "undo" is TRUE we go up in the tree, when FALSE we go down.
915 */ 915 */
916 static void 916 static void
917 u_undoredo() 917 u_undoredo(undo)
918 int undo;
918 { 919 {
919 char_u **newarray = NULL; 920 char_u **newarray = NULL;
920 linenr_T oldsize; 921 linenr_T oldsize;
921 linenr_T newsize; 922 linenr_T newsize;
922 linenr_T top, bot; 923 linenr_T top, bot;
1155 /* Make sure the cursor is on an existing line and column. */ 1156 /* Make sure the cursor is on an existing line and column. */
1156 check_cursor(); 1157 check_cursor();
1157 1158
1158 /* Remember where we are for "g-" and ":earlier 10s". */ 1159 /* Remember where we are for "g-" and ":earlier 10s". */
1159 curbuf->b_u_seq_cur = curhead->uh_seq; 1160 curbuf->b_u_seq_cur = curhead->uh_seq;
1161 if (undo)
1162 /* We are below the previous undo. However, to make ":earlier 1s"
1163 * work we compute this as being just above the just undone change. */
1164 --curbuf->b_u_seq_cur;
1165
1166 /* The timestamp can be the same for multiple changes, just use the one of
1167 * the undone/redone change. */
1160 curbuf->b_u_seq_time = curhead->uh_time; 1168 curbuf->b_u_seq_time = curhead->uh_time;
1161 } 1169 }
1162 1170
1163 /* 1171 /*
1164 * If we deleted or added lines, report the number of less/more lines. 1172 * If we deleted or added lines, report the number of less/more lines.
1210 if (uhp == NULL) 1218 if (uhp == NULL)
1211 *msgbuf = NUL; 1219 *msgbuf = NUL;
1212 else 1220 else
1213 u_add_time(msgbuf, sizeof(msgbuf), uhp->uh_time); 1221 u_add_time(msgbuf, sizeof(msgbuf), uhp->uh_time);
1214 1222
1215 smsg((char_u *)_("%ld %s; #%ld %s"), u_oldcount, _(msg), 1223 smsg((char_u *)_("%ld %s; #%ld %s"),
1216 uhp == NULL ? 0L : uhp->uh_seq, msgbuf); 1224 u_oldcount < 0 ? -u_oldcount : u_oldcount,
1225 _(msg), uhp == NULL ? 0L : uhp->uh_seq, msgbuf);
1217 } 1226 }
1218 1227
1219 /* 1228 /*
1220 * u_sync: stop adding to the current entry list 1229 * u_sync: stop adding to the current entry list
1221 */ 1230 */
1262 ga_init2(&ga, (int)sizeof(char *), 20); 1271 ga_init2(&ga, (int)sizeof(char *), 20);
1263 1272
1264 uhp = curbuf->b_u_oldhead; 1273 uhp = curbuf->b_u_oldhead;
1265 while (uhp != NULL) 1274 while (uhp != NULL)
1266 { 1275 {
1267 if (uhp->uh_prev == NULL) 1276 if (uhp->uh_prev == NULL && uhp->uh_walk != nomark
1277 && uhp->uh_walk != mark)
1268 { 1278 {
1269 if (ga_grow(&ga, 1) == FAIL) 1279 if (ga_grow(&ga, 1) == FAIL)
1270 break; 1280 break;
1271 vim_snprintf((char *)IObuff, IOSIZE, "%6ld %7ld ", 1281 vim_snprintf((char *)IObuff, IOSIZE, "%6ld %7ld ",
1272 uhp->uh_seq, changes); 1282 uhp->uh_seq, changes);