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