0
0
mirror of https://github.com/vim/vim.git synced 2025-09-23 03:43:49 -04:00

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 #2595)
This commit is contained in:
Bram Moolenaar
2018-01-30 22:46:06 +01:00
parent b50773c6df
commit ce46d934af
3 changed files with 122 additions and 72 deletions

View File

@@ -359,3 +359,47 @@ func Test_undo_append()
norm o norm o
quit quit
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

@@ -2272,7 +2272,7 @@ undo_time(
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;
@@ -2295,14 +2295,7 @@ undo_time(
* 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 = step;
{
/* target 0 does not exist, got to 1 and above it. */
target = 1;
above = TRUE;
}
else
target = step;
closest = -1; closest = -1;
} }
else else
@@ -2369,6 +2362,10 @@ undo_time(
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.
@@ -2494,8 +2491,9 @@ undo_time(
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.
@@ -2510,87 +2508,93 @@ undo_time(
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); u_undoredo(TRUE);
uhp->uh_walk = nomark; /* don't go back down here */ if (target > 0)
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)
*/
while (!got_int)
{ {
/* Do the change warning now, for the same reason as above. */ /*
change_warning(0); * And now go down the tree (redo), branching off where needed.
*/
while (!got_int)
{
/* Do the change warning now, for the same reason as above. */
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;
/* Find the last branch with a mark, that's the one. */
last = uhp;
while (last->uh_alt_next.ptr != NULL
&& last->uh_alt_next.ptr->uh_walk == mark)
last = last->uh_alt_next.ptr;
if (last != uhp)
{
/* Make the used branch the first entry in the list of
* alternatives to make "u" and CTRL-R take this branch. */
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 = /* Find the last branch with a mark, that's the one. */
last = uhp;
while (last->uh_alt_next.ptr != NULL
&& last->uh_alt_next.ptr->uh_walk == mark)
last = last->uh_alt_next.ptr;
if (last != uhp)
{
/* Make the used branch the first entry in the list of
* alternatives to make "u" and CTRL-R take this branch. */
while (uhp->uh_alt_prev.ptr != NULL)
uhp = uhp->uh_alt_prev.ptr;
if (last->uh_alt_next.ptr != NULL)
last->uh_alt_next.ptr->uh_alt_prev.ptr =
last->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_prev.ptr = NULL; last->uh_alt_next.ptr;
last->uh_alt_next.ptr = uhp; last->uh_alt_prev.ptr = NULL;
uhp->uh_alt_prev.ptr = last; last->uh_alt_next.ptr = uhp;
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;
} }
u_undoredo(FALSE); u_undoredo(FALSE);
/* 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)
{ {
/* Need to redo more but can't find it... */ /* Need to redo more but can't find it... */
internal_error("undo_time()"); internal_error("undo_time()");
break; break;
}
} }
} }
} }

View File

@@ -771,6 +771,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1441,
/**/ /**/
1440, 1440,
/**/ /**/