Hi Bram,
here are 3 patches that improve the undo-persistence.

Patch [1] sets the current save number to the last save number after 
loading a file (see how 'save_cur' in the undotree() function is set to 
zero after loading a file while it should probably be the same as 
'save_last'; compare this to how 'save_cur' changes after going back one 
step in the undotree and return to the original state [e.g. after g-g+ 
'save_cur' is the same as 'save_last'])

Patch [2] Lets changenr() return the current save_nr, if the optional 
argument save_nr is given and is one.
Currently, it is not possible to know after which save nr the buffer is, 
after moving around in the undo tree and :later <nr>f and :earlier <nr>f 
jump around only relative to the current save marks. So to decide what 
<nr> should be, one needs to know, after which save_nr the current 
buffer is.

Patch [3] :earlier <nr>f and :later <nr>f only move relative to the 
current save number of the buffer. I think it would be nice to jump 
right to the actual save number, as it is output with :undolist.
This patch implements :undo <nr>f to let you jump right after the 
specified save number. (Please verify, that the traversing the undo-tree 
structure works as it is supposed to be. I am not sure this is correct, 
though it seems to work)

[1]: /home/chrisbra/undo_save_nr_cur.patch
[2]: /home/chrisbra/changenr.patch
[3]: /home/chrisbra/undo_savenr.patch

regards,
Christian

-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
diff --git a/src/undo.c b/src/undo.c
--- a/src/undo.c
+++ b/src/undo.c
@@ -1861,6 +1861,7 @@
     curbuf->b_u_seq_cur = seq_cur;
     curbuf->b_u_time_cur = seq_time;
     curbuf->b_u_save_nr_last = last_save_nr;
+    curbuf->b_u_save_nr_cur  = last_save_nr;
 
     curbuf->b_u_synced = TRUE;
     vim_free(uhp_table);
diff --git a/runtime/doc/undo.txt b/runtime/doc/undo.txt
--- a/runtime/doc/undo.txt
+++ b/runtime/doc/undo.txt
@@ -27,6 +27,9 @@
 :u[ndo] {N}		Jump to after change number {N}.  See |undo-branches|
 			for the meaning of {N}.  {not in Vi}
 
+:u[ndo] {N}f		Jump to after save number {N}.  See |undo-branches|
+			for the meaning of {N}.  {not in Vi}
+
 							*CTRL-R*
 CTRL-R			Redo [count] changes which were undone.  {Vi: redraw
 			screen}
diff --git a/src/ex_cmds.h b/src/ex_cmds.h
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -994,7 +994,7 @@
 EX(CMD_tunmenu,		"tunmenu",	ex_menu,
 			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
 EX(CMD_undo,		"undo",		ex_undo,
-			RANGE|NOTADR|COUNT|ZEROR|TRLBAR|CMDWIN),
+			RANGE|NOTADR|COUNT|ZEROR|TRLBAR|CMDWIN|WORD1),
 EX(CMD_undojoin,	"undojoin",	ex_undojoin,
 			TRLBAR|CMDWIN),
 EX(CMD_undolist,	"undolist",	ex_undolist,
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -8493,9 +8493,34 @@
  */
     static void
 ex_undo(eap)
-    exarg_T	*eap UNUSED;
-{
-    if (eap->addr_count == 1)	    /* :undo 123 */
+    exarg_T	*eap;
+{
+    long	count = 0;
+    int         file  = FALSE;
+    char_u	*p = eap->arg;
+
+    if (*p == NUL)
+	count = 1;
+    else if (*p == 'f')
+    {
+	++p;
+	file = TRUE;
+    }
+
+    if (*p != NUL)
+	EMSG2(_(e_invarg2), eap->arg);
+    else if (file)
+    {
+        if (eap->line2 <= 0)
+	  count = 1;
+	else if (eap->line2 > curbuf->b_u_save_nr_last)
+	  count = curbuf->b_u_save_nr_last;
+	else
+	  count = eap->line2;
+        count = u_getChangenr(curbuf->b_u_oldhead, count);
+	undo_time(count, FALSE, FALSE, TRUE);
+    }
+    else if (eap->addr_count == 1)	    /* :undo 123 */
 	undo_time(eap->line2, FALSE, FALSE, TRUE);
     else
 	u_undo(1);
diff --git a/src/undo.c b/src/undo.c
--- a/src/undo.c
+++ b/src/undo.c
@@ -3311,6 +3312,43 @@
 #endif
 	(curbuf->b_changed || file_ff_differs(curbuf));
 }
+    long
+u_getChangenr(uh, savenr)
+    u_header_T *uh;
+    long savenr;
+{
+    u_header_T *uhp = uh;
+    int val=0;
+    int mark;
+    mark = ++lastmark;
+    while (uhp != NULL)
+    {
+	/* Serialize current UHP if we haven't seen it */
+	if (uhp->uh_walk != mark)
+	{
+	    uhp->uh_walk = mark;
+#ifdef U_DEBUG
+	    ++headers_written;
+#endif
+	}
+	if (uhp->uh_save_nr == savenr)
+	    val=uhp->uh_seq;
+	/* Now walk through the tree - algorithm from undo_time(). */
+	if (uhp->uh_prev.ptr != NULL && uhp->uh_prev.ptr->uh_walk != mark)
+	    uhp = uhp->uh_prev.ptr;
+	else if (uhp->uh_alt_next.ptr != NULL
+				     && uhp->uh_alt_next.ptr->uh_walk != mark)
+	    uhp = uhp->uh_alt_next.ptr;
+	else if (uhp->uh_next.ptr != NULL && uhp->uh_alt_prev.ptr == NULL
+					 && uhp->uh_next.ptr->uh_walk != mark)
+	    uhp = uhp->uh_next.ptr;
+	else if (uhp->uh_alt_prev.ptr != NULL)
+	    uhp = uhp->uh_alt_prev.ptr;
+	else
+	    uhp = uhp->uh_next.ptr;
+    }
+    return val;
+}
 
 #if defined(FEAT_EVAL) || defined(PROTO)
 /*
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1692,7 +1692,7 @@
 call( {func}, {arglist} [, {dict}])
 				any	call {func} with arguments {arglist}
 ceil( {expr})			Float	round {expr} up
-changenr()			Number	current change number
+changenr( [save_nr])		Number	current change number
 char2nr( {expr})		Number	ASCII value of first char in {expr}
 cindent( {lnum})		Number	C indent for line {lnum}
 clearmatches()			none	clear all matches
@@ -2242,13 +2242,16 @@
 <			4.0
 		{only available when compiled with the |+float| feature}
 
-changenr()						*changenr()*
+changenr([save_nr])						*changenr()*
 		Return the number of the most recent change.  This is the same
 		number as what is displayed with |:undolist| and can be used
 		with the |:undo| command.
 		When a change was made it is the number of that change.  After
 		redo it is the number of the redone change.  After undo it is
 		one less than the number of the undone change.
+		If the optional argument [save_nr] is one, this will output
+		the number of the last save count. This can be used together
+		with the |:later| and |:earlier| commands.
 
 char2nr({expr})						*char2nr()*
 		Return number value of the first char in {expr}.  Examples: >
diff --git a/src/eval.c b/src/eval.c
--- a/src/eval.c
+++ b/src/eval.c
@@ -7675,7 +7675,7 @@
 #ifdef FEAT_FLOAT
     {"ceil",		1, 1, f_ceil},
 #endif
-    {"changenr",	0, 0, f_changenr},
+    {"changenr",	0, 1, f_changenr},
     {"char2nr",		1, 1, f_char2nr},
     {"cindent",		1, 1, f_cindent},
     {"clearmatches",	0, 0, f_clearmatches},
@@ -9071,7 +9071,13 @@
     typval_T	*argvars UNUSED;
     typval_T	*rettv;
 {
-    rettv->vval.v_number = curbuf->b_u_seq_cur;
+    if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1)
+	rettv->vval.v_number = curbuf->b_u_save_nr_cur;
+    else 
+	rettv->vval.v_number = curbuf->b_u_seq_cur;
 }
 
 /*

Raspunde prin e-mail lui