vim-patch:8.0.1441: using ":undo 0" leaves undo in wrong state

Problem:    Using ":undo 0" leaves undo in wrong state.
Solution:   Instead of searching for state 1 and go above, just use the start.
            (Ozaki Kiichi, closes vim/vim#2595)
ce46d934af
This commit is contained in:
Jan Edmund Lazo 2018-08-20 21:24:30 -04:00
parent 0839c44257
commit 66ed6297b0
2 changed files with 126 additions and 70 deletions

View File

@ -390,3 +390,47 @@ funct Test_undofile()
set undodir& set undodir&
endfunc endfunc
func Test_undo_0()
new
set ul=100
normal i1
undo
normal i2
undo
normal i3
undo 0
let d = undotree()
call assert_equal('', getline(1))
call assert_equal(0, d.seq_cur)
redo
let d = undotree()
call assert_equal('3', getline(1))
call assert_equal(3, d.seq_cur)
undo 2
undo 0
let d = undotree()
call assert_equal('', getline(1))
call assert_equal(0, d.seq_cur)
redo
let d = undotree()
call assert_equal('2', getline(1))
call assert_equal(2, d.seq_cur)
undo 1
undo 0
let d = undotree()
call assert_equal('', getline(1))
call assert_equal(0, d.seq_cur)
redo
let d = undotree()
call assert_equal('1', getline(1))
call assert_equal(1, d.seq_cur)
bwipe!
endfunc

View File

@ -1820,7 +1820,7 @@ void undo_time(long step, int sec, int file, int absolute)
long closest_start; long closest_start;
long closest_seq = 0; long closest_seq = 0;
long val; long val;
u_header_T *uhp; u_header_T *uhp = NULL;
u_header_T *last; u_header_T *last;
int mark; int mark;
int nomark; int nomark;
@ -1842,13 +1842,7 @@ void undo_time(long step, int sec, int file, int absolute)
/* "target" is the node below which we want to be. /* "target" is the node below which we want to be.
* Init "closest" to a value we can't reach. */ * Init "closest" to a value we can't reach. */
if (absolute) { if (absolute) {
if (step == 0) {
// target 0 does not exist, got to 1 and above it.
target = 1;
above = true;
} else {
target = step; target = step;
}
closest = -1; closest = -1;
} else { } else {
if (dosec) { if (dosec) {
@ -1906,6 +1900,11 @@ void undo_time(long step, int sec, int file, int absolute)
closest_start = closest; closest_start = closest;
closest_seq = curbuf->b_u_seq_cur; closest_seq = curbuf->b_u_seq_cur;
// When "target" is 0; Back to origin.
if (target == 0) {
goto found;
}
/* /*
* May do this twice: * May do this twice:
* 1. Search for "target", update "closest" to the best match found. * 1. Search for "target", update "closest" to the best match found.
@ -2021,8 +2020,9 @@ void undo_time(long step, int sec, int file, int absolute)
above = TRUE; /* stop above the header */ above = TRUE; /* stop above the header */
} }
found:
/* If we found it: Follow the path to go to where we want to be. */ /* If we found it: Follow the path to go to where we want to be. */
if (uhp != NULL) { if (uhp != NULL || target == 0) {
/* /*
* First go up the tree as much as needed. * First go up the tree as much as needed.
*/ */
@ -2035,61 +2035,70 @@ void undo_time(long step, int sec, int file, int absolute)
uhp = curbuf->b_u_newhead; uhp = curbuf->b_u_newhead;
else else
uhp = uhp->uh_next.ptr; uhp = uhp->uh_next.ptr;
if (uhp == NULL || uhp->uh_walk != mark if (uhp == NULL || (target > 0 && uhp->uh_walk != mark)
|| (uhp->uh_seq == target && !above)) || (uhp->uh_seq == target && !above))
break; break;
curbuf->b_u_curhead = uhp; curbuf->b_u_curhead = uhp;
u_undoredo(true, true); u_undoredo(true, true);
if (target > 0) {
uhp->uh_walk = nomark; // don't go back down here uhp->uh_walk = nomark; // don't go back down here
} }
}
/* // When back to origin, redo is not needed.
* And now go down the tree (redo), branching off where needed. if (target > 0) {
*/ // And now go down the tree (redo), branching off where needed.
while (!got_int) { while (!got_int) {
/* Do the change warning now, for the same reason as above. */ // Do the change warning now, for the same reason as above.
change_warning(0); change_warning(0);
uhp = curbuf->b_u_curhead; uhp = curbuf->b_u_curhead;
if (uhp == NULL) if (uhp == NULL) {
break; break;
}
/* Go back to the first branch with a mark. */ // Go back to the first branch with a mark.
while (uhp->uh_alt_prev.ptr != NULL while (uhp->uh_alt_prev.ptr != NULL
&& uhp->uh_alt_prev.ptr->uh_walk == mark) && uhp->uh_alt_prev.ptr->uh_walk == mark) {
uhp = uhp->uh_alt_prev.ptr; uhp = uhp->uh_alt_prev.ptr;
}
/* Find the last branch with a mark, that's the one. */ // Find the last branch with a mark, that's the one.
last = uhp; last = uhp;
while (last->uh_alt_next.ptr != NULL while (last->uh_alt_next.ptr != NULL
&& last->uh_alt_next.ptr->uh_walk == mark) && last->uh_alt_next.ptr->uh_walk == mark) {
last = last->uh_alt_next.ptr; last = last->uh_alt_next.ptr;
}
if (last != uhp) { if (last != uhp) {
/* Make the used branch the first entry in the list of // Make the used branch the first entry in the list of
* alternatives to make "u" and CTRL-R take this branch. */ // alternatives to make "u" and CTRL-R take this branch.
while (uhp->uh_alt_prev.ptr != NULL) while (uhp->uh_alt_prev.ptr != NULL) {
uhp = uhp->uh_alt_prev.ptr; uhp = uhp->uh_alt_prev.ptr;
if (last->uh_alt_next.ptr != NULL) }
last->uh_alt_next.ptr->uh_alt_prev.ptr = if (last->uh_alt_next.ptr != NULL) {
last->uh_alt_prev.ptr; last->uh_alt_next.ptr->uh_alt_prev.ptr = last->uh_alt_prev.ptr;
}
last->uh_alt_prev.ptr->uh_alt_next.ptr = last->uh_alt_next.ptr; last->uh_alt_prev.ptr->uh_alt_next.ptr = last->uh_alt_next.ptr;
last->uh_alt_prev.ptr = NULL; last->uh_alt_prev.ptr = NULL;
last->uh_alt_next.ptr = uhp; last->uh_alt_next.ptr = uhp;
uhp->uh_alt_prev.ptr = last; uhp->uh_alt_prev.ptr = last;
if (curbuf->b_u_oldhead == uhp) if (curbuf->b_u_oldhead == uhp) {
curbuf->b_u_oldhead = last; curbuf->b_u_oldhead = last;
}
uhp = last; uhp = last;
if (uhp->uh_next.ptr != NULL) if (uhp->uh_next.ptr != NULL) {
uhp->uh_next.ptr->uh_prev.ptr = uhp; uhp->uh_next.ptr->uh_prev.ptr = uhp;
} }
}
curbuf->b_u_curhead = uhp; curbuf->b_u_curhead = uhp;
if (uhp->uh_walk != mark) if (uhp->uh_walk != mark) {
break; /* must have reached the target */ break; // must have reached the target
}
/* Stop when going backwards in time and didn't find the exact // Stop when going backwards in time and didn't find the exact
* header we were looking for. */ // header we were looking for.
if (uhp->uh_seq == target && above) { if (uhp->uh_seq == target && above) {
curbuf->b_u_seq_cur = target - 1; curbuf->b_u_seq_cur = target - 1;
break; break;
@ -2097,15 +2106,17 @@ void undo_time(long step, int sec, int file, int absolute)
u_undoredo(false, true); u_undoredo(false, true);
/* Advance "curhead" to below the header we last used. If it // Advance "curhead" to below the header we last used. If it
* becomes NULL then we need to set "newhead" to this leaf. */ // becomes NULL then we need to set "newhead" to this leaf.
if (uhp->uh_prev.ptr == NULL) if (uhp->uh_prev.ptr == NULL) {
curbuf->b_u_newhead = uhp; curbuf->b_u_newhead = uhp;
}
curbuf->b_u_curhead = uhp->uh_prev.ptr; curbuf->b_u_curhead = uhp->uh_prev.ptr;
did_undo = FALSE; did_undo = false;
if (uhp->uh_seq == target) /* found it! */ if (uhp->uh_seq == target) { // found it!
break; break;
}
uhp = uhp->uh_prev.ptr; uhp = uhp->uh_prev.ptr;
if (uhp == NULL || uhp->uh_walk != mark) { if (uhp == NULL || uhp->uh_walk != mark) {
@ -2115,6 +2126,7 @@ void undo_time(long step, int sec, int file, int absolute)
} }
} }
} }
}
u_undo_end(did_undo, absolute, false); u_undo_end(did_undo, absolute, false);
} }