diff src/undo.c @ 772:aaaca5077255

updated for version 7.0226
author vimboss
date Thu, 16 Mar 2006 21:41:35 +0000
parents f0d0d3d3a1e2
children f664cc974a7a
line wrap: on
line diff
--- a/src/undo.c
+++ b/src/undo.c
@@ -89,6 +89,7 @@ static int u_savecommon __ARGS((linenr_T
 static void u_doit __ARGS((int count));
 static void u_undoredo __ARGS((void));
 static void u_undo_end __ARGS((void));
+static void u_add_time __ARGS((char_u *buf, size_t buflen, time_t tt));
 static void u_freeheader __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp));
 static void u_freebranch __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp));
 static void u_freeentries __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp));
@@ -637,11 +638,14 @@ static int lastmark = 0;
  * When "step" is negative go back in time, otherwise goes forward in time.
  * When "sec" is FALSE make "step" steps, when "sec" is TRUE use "step" as
  * seconds.
+ * When "absolute" is TRUE use "step" as the sequence number to jump to.
+ * "sec" must be FALSE then.
  */
     void
-undo_time(step, sec)
+undo_time(step, sec, absolute)
     long	step;
     int		sec;
+    int		absolute;
 {
     long	    target;
     long	    closest;
@@ -668,7 +672,12 @@ undo_time(step, sec)
 
     /* "target" is the node below which we want to be.  When going forward
      * the current one also counts, thus do one less. */
-    if (step < 0)
+    if (absolute)
+    {
+	target = step;
+	closest = -2;
+    }
+    else if (step < 0)
     {
 	if (sec)
 	    target = (long)curbuf->b_u_seq_time + step;
@@ -787,6 +796,13 @@ undo_time(step, sec)
 
 	if (uhp != NULL)    /* found it */
 	    break;
+
+	if (absolute)
+	{
+	    EMSGN(_("Undo number %ld not found"), step);
+	    return;
+	}
+
 	if (closest == closest_start)
 	{
 	    if (step < 0)
@@ -1152,8 +1168,9 @@ u_undoredo()
     static void
 u_undo_end()
 {
-    long	sec;
     char	*msg;
+    u_header_T	*uhp;
+    char_u	msgbuf[80];
 
 #ifdef FEAT_FOLDING
     if ((fdo_flags & FDO_UNDO) && KeyTyped)
@@ -1185,12 +1202,18 @@ u_undo_end()
 	    msg = N_("changes");
     }
 
-    if (curbuf->b_u_curhead == 0)
-	sec = 0;
+    if (curbuf->b_u_curhead != NULL)
+	uhp = curbuf->b_u_curhead;
     else
-	sec = time(NULL) - curbuf->b_u_curhead->uh_time;
+	uhp = curbuf->b_u_newhead;
 
-    smsg((char_u *)_("%ld %s; %ld seconds ago"), u_oldcount, _(msg), sec);
+    if (uhp == NULL)
+	*msgbuf = NUL;
+    else
+	u_add_time(msgbuf, sizeof(msgbuf), uhp->uh_time);
+
+    smsg((char_u *)_("%ld %s; #%ld  %s"), u_oldcount, _(msg),
+				      uhp == NULL ? 0L : uhp->uh_seq, msgbuf);
 }
 
 /*
@@ -1215,6 +1238,128 @@ u_sync()
 }
 
 /*
+ * ":undolist": List the leafs of the undo tree
+ */
+/*ARGSUSED*/
+    void
+ex_undolist(eap)
+    exarg_T *eap;
+{
+    garray_T	ga;
+    u_header_T	*uhp;
+    int		mark;
+    int		nomark;
+    int		changes = 1;
+    int		i;
+
+    /*
+     * 1: walk the tree to find all leafs, put the info in "ga".
+     * 2: sort the lines
+     * 3: display the list
+     */
+    mark = ++lastmark;
+    nomark = ++lastmark;
+    ga_init2(&ga, (int)sizeof(char *), 20);
+
+    uhp = curbuf->b_u_oldhead;
+    while (uhp != NULL)
+    {
+	if (uhp->uh_prev == NULL)
+	{
+	    if (ga_grow(&ga, 1) == FAIL)
+		break;
+	    vim_snprintf((char *)IObuff, IOSIZE, "%6ld %7ld  ",
+							uhp->uh_seq, changes);
+	    u_add_time(IObuff + STRLEN(IObuff), IOSIZE - STRLEN(IObuff),
+								uhp->uh_time);
+	    ((char_u **)(ga.ga_data))[ga.ga_len++] = vim_strsave(IObuff);
+	}
+
+	uhp->uh_walk = mark;
+
+	/* go down in the tree if we haven't been there */
+	if (uhp->uh_prev != NULL && uhp->uh_prev->uh_walk != nomark
+					 && uhp->uh_prev->uh_walk != mark)
+	{
+	    uhp = uhp->uh_prev;
+	    ++changes;
+	}
+
+	/* go to alternate branch if we haven't been there */
+	else if (uhp->uh_alt_next != NULL
+		&& uhp->uh_alt_next->uh_walk != nomark
+		&& uhp->uh_alt_next->uh_walk != mark)
+	    uhp = uhp->uh_alt_next;
+
+	/* go up in the tree if we haven't been there and we are at the
+	 * start of alternate branches */
+	else if (uhp->uh_next != NULL && uhp->uh_alt_prev == NULL
+		&& uhp->uh_next->uh_walk != nomark
+		&& uhp->uh_next->uh_walk != mark)
+	{
+	    uhp = uhp->uh_next;
+	    --changes;
+	}
+
+	else
+	{
+	    /* need to backtrack; mark this node as done */
+	    uhp->uh_walk = nomark;
+	    if (uhp->uh_alt_prev != NULL)
+		uhp = uhp->uh_alt_prev;
+	    else
+	    {
+		uhp = uhp->uh_next;
+		--changes;
+	    }
+	}
+    }
+
+    if (ga.ga_len == 0)
+	MSG(_("Nothing to undo"));
+    else
+    {
+	sort_strings((char_u **)ga.ga_data, ga.ga_len);
+
+	msg_start();
+	msg_puts_attr((char_u *)_("number changes  time"), hl_attr(HLF_T));
+	for (i = 0; i < ga.ga_len && !got_int; ++i)
+	{
+	    msg_putchar('\n');
+	    if (got_int)
+		break;
+	    msg_puts(((char_u **)ga.ga_data)[i]);
+	}
+	msg_end();
+
+	ga_clear_strings(&ga);
+    }
+}
+
+/*
+ * Put the timestamp of an undo header in "buf[buflen]" in a nice format.
+ */
+    static void
+u_add_time(buf, buflen, tt)
+    char_u	*buf;
+    size_t	buflen;
+    time_t	tt;
+{
+#ifdef HAVE_STRFTIME
+    struct tm	*curtime;
+
+    if (time(NULL) - tt >= 100)
+    {
+	curtime = localtime(&tt);
+	(void)strftime((char *)buf, buflen, "%T", curtime);
+    }
+    else
+#endif
+	vim_snprintf((char *)buf, buflen, "%ld seconds ago",
+						     (long)(time(NULL) - tt));
+}
+
+/*
  * ":undojoin": continue adding to the last entry list
  */
 /*ARGSUSED*/