Hi,
Here is another update, that allows to 'undo' the undorecover command 
and should work better in case of errors.

Best,
Christian
-- 
Ich mache mir immer Vorwürfe, daß meine Malerei nicht wert ist, was
sie kostet.
                -- Vincent Willem van Gogh

-- 
-- 
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

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.
diff --git a/runtime/doc/undo.txt b/runtime/doc/undo.txt
--- a/runtime/doc/undo.txt
+++ b/runtime/doc/undo.txt
@@ -14,6 +14,7 @@ 3. Undo blocks			|undo-blocks|
 4. Undo branches		|undo-branches|
 5. Undo persistence		|undo-persistence|
 6. Remarks about undo		|undo-remarks|
+7. Undo recovery		|undo-recovery|
 
 ==============================================================================
 1. Undo and redo commands				*undo-commands*
@@ -403,4 +404,25 @@ if it is not what you want do 'u.'.  Thi
 first put, and repeat the put command for the second register.  Repeat the
 'u.' until you got what you want.
 
+==============================================================================
+7. Undo recovery                                        *undo-recovery*
+
+:undorecovery {file}
+
+		Read undo history from {file} and try to recover the buffer
+		contents. In case you have lost your buffer, you can try to
+		recover from the undofile.
+
+		This works by checking the undo history and for each line
+		restore it to the last known state.
+
+		If you have previously stored the complete buffer in the undo
+		tree (e.g. by means of the 'undoreload' setting) all lines can
+		be recovered (but possibly not into a consistent state), else
+		you possibly end up with a file containing a lot of white
+		space (e.g. because those empty lines were not stored in the
+		undo tree).
+
+		Note: In any case you need to check each line carefully.
+
  vim:tw=78:ts=8:ft=help:norl:
diff --git a/src/eval.c b/src/eval.c
--- a/src/eval.c
+++ b/src/eval.c
@@ -19317,6 +19317,7 @@ f_undotree(argvars, rettv)
 	dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL);
 	dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL);
 	dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL);
+	dict_add_nr_str(dict, "whole_buf", (long)curbuf->b_u_save_buf, NULL);
 
 	list = list_alloc();
 	if (list != NULL)
diff --git a/src/ex_cmds.c b/src/ex_cmds.c
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -3743,6 +3743,7 @@ do_ecmd(fnum, ffname, sfname, eap, newln
 	    if (u_savecommon(0, curbuf->b_ml.ml_line_count + 1, 0, TRUE)
 								     == FAIL)
 		goto theend;
+	    curbuf->b_u_save_buf = curbuf->b_u_seq_cur;
 	    u_unchanged(curbuf);
 	    buf_freeall(curbuf, BFA_KEEP_UNDO);
 
diff --git a/src/ex_cmds.h b/src/ex_cmds.h
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -1009,6 +1009,8 @@ EX(CMD_undojoin,	"undojoin",	ex_undojoin
 			TRLBAR|CMDWIN),
 EX(CMD_undolist,	"undolist",	ex_undolist,
 			TRLBAR|CMDWIN),
+EX(CMD_undorecover,	"undorecover",	ex_undorecover,
+			NEEDARG|FILE1),
 EX(CMD_unabbreviate,	"unabbreviate",	ex_abbreviate,
 			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
 EX(CMD_unhide,		"unhide",	ex_buffer_all,
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -254,6 +254,7 @@ static void	ex_popup __ARGS((exarg_T *ea
 #endif
 #ifndef FEAT_PERSISTENT_UNDO
 # define ex_rundo		ex_ni
+# define ex_undorecover		ex_ni
 # define ex_wundo		ex_ni
 #endif
 #ifndef FEAT_LUA
@@ -324,6 +325,7 @@ static void	ex_undo __ARGS((exarg_T *eap
 #ifdef FEAT_PERSISTENT_UNDO
 static void	ex_wundo __ARGS((exarg_T *eap));
 static void	ex_rundo __ARGS((exarg_T *eap));
+static void	ex_undorecover __ARGS((exarg_T *eap));
 #endif
 static void	ex_redo __ARGS((exarg_T *eap));
 static void	ex_later __ARGS((exarg_T *eap));
@@ -8808,7 +8810,17 @@ ex_rundo(eap)
     char_u hash[UNDO_HASH_SIZE];
 
     u_compute_hash(hash);
-    u_read_undo(eap->arg, hash, NULL);
+    u_read_undo(eap->arg, hash, NULL, FALSE);
+}
+
+    static void
+ex_undorecover(eap)
+    exarg_T *eap;
+{
+    if (!(curbuf->b_ml.ml_flags & ML_EMPTY))
+	EMSG(_("E__: undorecovery: buffer not empty!"));
+    else
+	u_read_undo(eap->arg, NULL, NULL, TRUE);
 }
 #endif
 
diff --git a/src/fileio.c b/src/fileio.c
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -2634,7 +2634,7 @@ failed:
 	char_u	hash[UNDO_HASH_SIZE];
 
 	sha256_finish(&sha_ctx, hash);
-	u_read_undo(NULL, hash, fname);
+	u_read_undo(NULL, hash, fname, FALSE);
     }
 #endif
 
diff --git a/src/option.c b/src/option.c
--- a/src/option.c
+++ b/src/option.c
@@ -7805,7 +7805,7 @@ set_bool_option(opt_idx, varp, value, op
 			&& !curbufIsChanged() && curbuf->b_ml.ml_mfp != NULL)
 		{
 		    u_compute_hash(hash);
-		    u_read_undo(NULL, hash, curbuf->b_fname);
+		    u_read_undo(NULL, hash, curbuf->b_fname, FALSE);
 		}
 	    }
 	    curbuf = save_curbuf;
diff --git a/src/proto/undo.pro b/src/proto/undo.pro
--- a/src/proto/undo.pro
+++ b/src/proto/undo.pro
@@ -9,7 +9,7 @@ int u_savecommon __ARGS((linenr_T top, l
 void u_compute_hash __ARGS((char_u *hash));
 char_u *u_get_undo_file_name __ARGS((char_u *buf_ffname, int reading));
 void u_write_undo __ARGS((char_u *name, int forceit, buf_T *buf, char_u *hash));
-void u_read_undo __ARGS((char_u *name, char_u *hash, char_u *orig_name));
+void u_read_undo __ARGS((char_u *name, char_u *hash, char_u *orig_name, int force));
 void u_undo __ARGS((int count));
 void u_redo __ARGS((int count));
 void undo_time __ARGS((long step, int sec, int file, int absolute));
diff --git a/src/structs.h b/src/structs.h
--- a/src/structs.h
+++ b/src/structs.h
@@ -1489,6 +1489,7 @@ struct file_buffer
     int		b_u_synced;	/* entry lists are synced */
     long	b_u_seq_last;	/* last used undo sequence number */
     long	b_u_save_nr_last; /* counter for last file write */
+    long	b_u_save_buf;   /* counter for when buffer was completly saved in undo tree */
     long	b_u_seq_cur;	/* hu_seq of header below which we are now */
     time_t	b_u_time_cur;	/* uh_time of header below which we are now */
     long	b_u_save_nr_cur; /* file write nr after which we are now */
diff --git a/src/undo.c b/src/undo.c
--- a/src/undo.c
+++ b/src/undo.c
@@ -120,6 +120,8 @@ static int undo_flush __ARGS((bufinfo_T 
 static int fwrite_crypt __ARGS((bufinfo_T *bi, char_u *ptr, size_t len));
 static int undo_write_bytes __ARGS((bufinfo_T *bi, long_u nr, int len));
 static void put_header_ptr __ARGS((bufinfo_T *bi, u_header_T *uhp));
+static void u_undorecover __ARGS((long size));
+static void u_undorecover_entry __ARGS((u_header_T *uhp, linenr_T **line));
 static int undo_read_4c __ARGS((bufinfo_T *bi));
 static int undo_read_2c __ARGS((bufinfo_T *bi));
 static int undo_read_byte __ARGS((bufinfo_T *bi));
@@ -739,6 +741,7 @@ nomem:
 
 /* extra fields for header */
 # define UF_LAST_SAVE_NR	1
+# define UF_SAVE_WHOLE_BUF	2
 
 /* extra fields for uhp */
 # define UHP_SAVE_NR		1
@@ -1245,6 +1248,9 @@ serialize_header(bi, hash)
     undo_write_bytes(bi, 4, 1);
     undo_write_bytes(bi, UF_LAST_SAVE_NR, 1);
     undo_write_bytes(bi, (long_u)buf->b_u_save_nr_last, 4);
+    undo_write_bytes(bi, 4, 1);
+    undo_write_bytes(bi, UF_SAVE_WHOLE_BUF, 1);
+    undo_write_bytes(bi, (long_u)buf->b_u_save_buf, 4);
 
     undo_write_bytes(bi, 0, 1);  /* end marker */
 
@@ -1540,6 +1546,71 @@ unserialize_visualinfo(bi, info)
     info->vi_curswant = undo_read_4c(bi);
 }
 
+/* Try to recover from the undotree. This works by running through all u_entry
+ * entries and recovering the line to the last known state of the line */
+    static void
+u_undorecover(size)
+    long    size;
+{
+    u_header_T	*uhp;
+    linenr_T	*lines = NULL;
+
+    uhp = curbuf->b_u_oldhead;
+    if (uhp != NULL)
+    {
+	lines = (linenr_T *)lalloc_clear((unsigned)(size * sizeof(linenr_T)), FALSE);
+	if (lines == NULL)
+	{
+	    EMSG(_("EXXX: Undorecovery not possible!"));
+	    return;
+	}
+	u_undorecover_entry(uhp, &lines);
+
+	vim_free(lines);
+    }
+}
+
+    static void
+u_undorecover_entry(uhp, l_array)
+    u_header_T	*uhp;
+    linenr_T	**l_array; /* array holding the last sequence number for each line */
+{
+    u_entry_T	*uep;
+    linenr_T	i;
+
+    if (uhp == NULL)
+	return;
+    uep = uhp->uh_entry;
+    while (uep != NULL)
+    {
+	for (i = 0; i < uep->ue_size; i++)
+	{
+	    /* safety check: add empty lines */
+	    if (i + uep->ue_top >= curbuf->b_ml.ml_line_count)
+	    {
+		/* adding empty lines at the end of the buffer,
+		 * prevents partly recovered lines to move downwards */
+		while (curbuf->b_ml.ml_line_count <= i + uep->ue_top)
+		    ml_append(curbuf->b_ml.ml_line_count, (char_u *)"", 0, TRUE);
+	    }
+
+	    if ((*l_array)[uep->ue_top + i] < uhp->uh_seq
+		    && *uep->ue_array[i] != NUL)
+	    {
+		ml_replace((long)uep->ue_top + i + 1, uep->ue_array[i], TRUE);
+		(*l_array)[uep->ue_top + i] = uhp->uh_seq;
+	    }
+	}
+	uep = uep->ue_next;
+    }
+
+    /* Check next alt tree */
+    u_undorecover_entry(uhp->uh_alt_next.ptr, l_array);
+
+    /* Check next branch */
+    u_undorecover_entry(uhp->uh_prev.ptr, l_array);
+}
+
 /*
  * Write the undo tree in an undo file.
  * When "name" is not NULL, use it as the name of the undo file.
@@ -1675,6 +1746,17 @@ u_write_undo(name, forceit, buf, hash)
 	goto theend;
     }
 
+    if (buf->b_u_save_buf == 0 && (p_ur < 0
+		|| buf->b_ml.ml_line_count <= p_ur))
+    {
+	/* store buffer content in the undo header in the current change */
+	if (buf->b_u_curhead == NULL && buf->b_u_newhead != NULL)
+	    buf->b_u_curhead = buf->b_u_newhead;
+	buf->b_u_synced = FALSE;
+	u_savecommon(0, buf->b_ml.ml_line_count + 1, 0, TRUE);
+	buf->b_u_save_buf = buf->b_u_seq_cur;
+    }
+
     fd = mch_open((char *)file_name,
 			    O_CREAT|O_EXTRA|O_WRONLY|O_EXCL|O_NOFOLLOW, perm);
     if (fd < 0)
@@ -1824,10 +1906,11 @@ theend:
  * "hash[UNDO_HASH_SIZE]" must be the hash value of the buffer text.
  */
     void
-u_read_undo(name, hash, orig_name)
+u_read_undo(name, hash, orig_name, recover)
     char_u *name;
     char_u *hash;
     char_u *orig_name;
+    int	    recover;	/* :undorecover */
 {
     char_u	*file_name;
     FILE	*fp;
@@ -1840,6 +1923,7 @@ u_read_undo(name, hash, orig_name)
     long	old_header_seq, new_header_seq, cur_header_seq;
     long	seq_last, seq_cur;
     long	last_save_nr = 0;
+    long	last_save_buf = 0;
     short	old_idx = -1, new_idx = -1, cur_idx = -1;
     long	num_read_uhps = 0;
     time_t	seq_time;
@@ -1857,6 +1941,11 @@ u_read_undo(name, hash, orig_name)
     struct stat	st_undo;
 #endif
     bufinfo_T	bi;
+    /* structures needed for undorecovery */
+    u_header_T  *uh_newhead = NULL;
+    u_entry_T   *uep_dummy  = NULL;
+    char_u	**newarray = NULL;
+
 
     vim_memset(&bi, 0, sizeof(bi));
     if (name == NULL)
@@ -1958,8 +2047,8 @@ u_read_undo(name, hash, orig_name)
 	goto error;
     }
     line_count = (linenr_T)undo_read_4c(&bi);
-    if (memcmp(hash, read_hash, UNDO_HASH_SIZE) != 0
-				  || line_count != curbuf->b_ml.ml_line_count)
+    if (!recover && (memcmp(hash, read_hash, UNDO_HASH_SIZE) != 0
+				  || line_count != curbuf->b_ml.ml_line_count))
     {
 	if (p_verbose > 0 || name != NULL)
 	{
@@ -2010,6 +2099,9 @@ u_read_undo(name, hash, orig_name)
 	    case UF_LAST_SAVE_NR:
 		last_save_nr = undo_read_4c(&bi);
 		break;
+	    case UF_SAVE_WHOLE_BUF:
+		last_save_buf = undo_read_4c(&bi);
+		break;
 	    default:
 		/* field not supported, skip */
 		while (--len >= 0)
@@ -2141,9 +2233,11 @@ u_read_undo(name, hash, orig_name)
     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_save_buf = last_save_buf;
 
     curbuf->b_u_synced = TRUE;
     vim_free(uhp_table);
+    uhp_table = NULL;
 
 #ifdef U_DEBUG
     for (i = 0; i < num_head; ++i)
@@ -2153,6 +2247,61 @@ u_read_undo(name, hash, orig_name)
     u_check(TRUE);
 #endif
 
+    if (recover)
+    {
+	if (!undo_allowed())
+	{
+	    EMSG(_("EXXX: Undorecovery not allowed!"));
+	    goto theend;
+	}
+
+	u_undorecover(line_count); /* adds many lines */
+#ifdef U_DEBUG
+	u_check(TRUE);
+#endif
+	appended_lines(0, curbuf->b_ml.ml_line_count);
+	u_blockfree(curbuf);	    /* free the memory allocated for undo */
+	u_clearall(curbuf);	    /* reset all undo information */
+	line_ptr = NULL;
+	curbuf->b_u_line_colnr = (colnr_T)0;
+	curbuf->b_u_save_nr_last = 0;
+	curbuf->b_u_save_nr_cur = 0;
+	curbuf->b_u_save_buf = 0;
+	curbuf->b_u_seq_last = 1;
+	curbuf->b_u_seq_cur = 1;
+	curbuf->b_u_numhead = 1;
+	/* Make a dummy entry for the first empty buffer,
+	 * so that the recovery is undoable */
+	uh_newhead = (u_header_T *)U_ALLOC_LINE(sizeof(u_header_T));
+	if (uh_newhead == NULL)
+	    goto error;
+	vim_memset(uh_newhead, 0, sizeof(u_header_T));
+	uep_dummy =  (u_entry_T  *)U_ALLOC_LINE(sizeof(u_entry_T));
+	if (uep_dummy == NULL)
+	    goto error;
+	vim_memset(uep_dummy,  0, sizeof(u_entry_T));
+	newarray =   (char_u **)U_ALLOC_LINE(sizeof(char_u *));
+	if (newarray == NULL)
+	    goto error;
+#ifdef U_DEBUG
+	uh_newhead->uh_magic = UH_MAGIC;
+	uep_dummy->ue_magic  = UE_MAGIC;
+#endif
+	uep_dummy->ue_size = 1;
+	uep_dummy->ue_array = newarray;
+	uep_dummy->ue_array[0] = vim_strsave((char_u *)"");
+	uh_newhead->uh_entry = uep_dummy;
+	uh_newhead->uh_seq   = 1;
+	uh_newhead->uh_time  = time(NULL);
+	uh_newhead->uh_cursor = curwin->w_cursor;
+	curbuf->b_u_newhead = curbuf->b_u_oldhead = uh_newhead;
+#ifdef U_DEBUG
+	u_check(TRUE);
+#endif
+	update_screen(NOT_VALID);
+	MSG(_("Undorecovery completed."));
+    }
+
     if (name != NULL)
 	smsg((char_u *)_("Finished reading undo file %s"), file_name);
     goto theend;
@@ -2166,6 +2315,13 @@ error:
 		u_free_uhp(uhp_table[i]);
 	vim_free(uhp_table);
     }
+    if (recover)
+    {
+	if (uh_newhead != NULL)
+	    u_free_uhp(uh_newhead);
+	vim_free(uh_newhead);
+	vim_free(newarray);
+    }
 
 theend:
 #ifdef FEAT_CRYPT
@@ -3362,6 +3518,9 @@ u_freeheader(buf, uhp, uhpp)
 						 uhap = uhap->uh_alt_next.ptr)
 	    uhap->uh_next.ptr = uhp->uh_next.ptr;
 
+    if (buf->b_u_save_buf == uhp->uh_seq)
+	buf->b_u_save_buf = 0;
+
     u_freeentries(buf, uhp, uhpp);
 }
 

Raspunde prin e-mail lui