changeset 13134:c4b5ad2b3596 v8.0.1441

patch 8.0.1441: using ":undo 0" leaves undo in wrong state commit https://github.com/vim/vim/commit/ce46d934af35d0f774be7f996001db03cf0b894a Author: Bram Moolenaar <Bram@vim.org> Date: Tue Jan 30 22:46:06 2018 +0100 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)
author Christian Brabandt <cb@256bit.org>
date Tue, 30 Jan 2018 23:00:06 +0100
parents 31a78144e47f
children f57fb2393fd0
files src/testdir/test_undo.vim src/undo.c src/version.c
diffstat 3 files changed, 131 insertions(+), 81 deletions(-) [+]
line wrap: on
line diff
--- a/src/testdir/test_undo.vim
+++ b/src/testdir/test_undo.vim
@@ -359,3 +359,47 @@ func Test_undo_append()
   norm o
   quit
 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
--- a/src/undo.c
+++ b/src/undo.c
@@ -2272,7 +2272,7 @@ undo_time(
     long	    closest_start;
     long	    closest_seq = 0;
     long	    val;
-    u_header_T	    *uhp;
+    u_header_T	    *uhp = NULL;
     u_header_T	    *last;
     int		    mark;
     int		    nomark;
@@ -2295,14 +2295,7 @@ undo_time(
      * Init "closest" to a value we can't reach. */
     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;
     }
     else
@@ -2369,6 +2362,10 @@ undo_time(
     closest_start = closest;
     closest_seq = curbuf->b_u_seq_cur;
 
+    /* When "target" is 0; Back to origin. */
+    if (target == 0)
+	goto found;
+
     /*
      * May do this twice:
      * 1. Search for "target", update "closest" to the best match found.
@@ -2494,8 +2491,9 @@ undo_time(
 	    above = TRUE;	/* stop above the header */
     }
 
+found:
     /* 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.
@@ -2510,87 +2508,93 @@ undo_time(
 		uhp = curbuf->b_u_newhead;
 	    else
 		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))
 		break;
 	    curbuf->b_u_curhead = uhp;
 	    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 */
 	}
 
-	/*
-	 * And now go down the tree (redo), branching off where needed.
-	 */
-	while (!got_int)
+	/* When back to origin, redo is not needed. */
+	if (target > 0)
 	{
-	    /* Do the change warning now, for the same reason as above. */
-	    change_warning(0);
-
-	    uhp = curbuf->b_u_curhead;
-	    if (uhp == NULL)
-		break;
-
-	    /* Go back to the first branch with a mark. */
-	    while (uhp->uh_alt_prev.ptr != NULL
+	    /*
+	     * 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;
+		if (uhp == NULL)
+		    break;
+
+		/* Go back to the first branch with a mark. */
+		while (uhp->uh_alt_prev.ptr != NULL
 				     && 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
+		    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;
-		if (last->uh_alt_next.ptr != NULL)
-		    last->uh_alt_next.ptr->uh_alt_prev.ptr =
+		    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->uh_alt_next.ptr = last->uh_alt_next.ptr;
-		last->uh_alt_prev.ptr = NULL;
-		last->uh_alt_next.ptr = uhp;
-		uhp->uh_alt_prev.ptr = last;
-
-		if (curbuf->b_u_oldhead == uhp)
-		    curbuf->b_u_oldhead = last;
-		uhp = last;
-		if (uhp->uh_next.ptr != NULL)
-		    uhp->uh_next.ptr->uh_prev.ptr = uhp;
-	    }
-	    curbuf->b_u_curhead = uhp;
-
-	    if (uhp->uh_walk != mark)
-		break;	    /* must have reached the target */
-
-	    /* Stop when going backwards in time and didn't find the exact
-	     * header we were looking for. */
-	    if (uhp->uh_seq == target && above)
-	    {
-		curbuf->b_u_seq_cur = target - 1;
-		break;
-	    }
-
-	    u_undoredo(FALSE);
-
-	    /* Advance "curhead" to below the header we last used.  If it
-	     * becomes NULL then we need to set "newhead" to this leaf. */
-	    if (uhp->uh_prev.ptr == NULL)
-		curbuf->b_u_newhead = uhp;
-	    curbuf->b_u_curhead = uhp->uh_prev.ptr;
-	    did_undo = FALSE;
-
-	    if (uhp->uh_seq == target)	/* found it! */
-		break;
-
-	    uhp = uhp->uh_prev.ptr;
-	    if (uhp == NULL || uhp->uh_walk != mark)
-	    {
-		/* Need to redo more but can't find it... */
-		internal_error("undo_time()");
-		break;
+		    last->uh_alt_prev.ptr->uh_alt_next.ptr =
+							last->uh_alt_next.ptr;
+		    last->uh_alt_prev.ptr = NULL;
+		    last->uh_alt_next.ptr = uhp;
+		    uhp->uh_alt_prev.ptr = last;
+
+		    if (curbuf->b_u_oldhead == uhp)
+			curbuf->b_u_oldhead = last;
+		    uhp = last;
+		    if (uhp->uh_next.ptr != NULL)
+			uhp->uh_next.ptr->uh_prev.ptr = uhp;
+		}
+		curbuf->b_u_curhead = uhp;
+
+		if (uhp->uh_walk != mark)
+		    break;	    /* must have reached the target */
+
+		/* Stop when going backwards in time and didn't find the exact
+		 * header we were looking for. */
+		if (uhp->uh_seq == target && above)
+		{
+		    curbuf->b_u_seq_cur = target - 1;
+		    break;
+		}
+
+		u_undoredo(FALSE);
+
+		/* Advance "curhead" to below the header we last used.  If it
+		 * becomes NULL then we need to set "newhead" to this leaf. */
+		if (uhp->uh_prev.ptr == NULL)
+		    curbuf->b_u_newhead = uhp;
+		curbuf->b_u_curhead = uhp->uh_prev.ptr;
+		did_undo = FALSE;
+
+		if (uhp->uh_seq == target)	/* found it! */
+		    break;
+
+		uhp = uhp->uh_prev.ptr;
+		if (uhp == NULL || uhp->uh_walk != mark)
+		{
+		    /* Need to redo more but can't find it... */
+		    internal_error("undo_time()");
+		    break;
+		}
 	    }
 	}
     }
--- a/src/version.c
+++ b/src/version.c
@@ -772,6 +772,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1441,
+/**/
     1440,
 /**/
     1439,