changeset 772:aaaca5077255

updated for version 7.0226
author vimboss
date Thu, 16 Mar 2006 21:41:35 +0000
parents c0f1b710ce07
children 8c9ef63b1ccc
files runtime/doc/change.txt runtime/doc/options.txt runtime/doc/tags runtime/doc/undo.txt src/auto/configure src/configure.in src/ex_getln.c src/misc2.c src/popupmenu.c src/regexp.c src/undo.c src/version.h
diffstat 12 files changed, 372 insertions(+), 119 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/change.txt
+++ b/runtime/doc/change.txt
@@ -1,4 +1,4 @@
-*change.txt*    For Vim version 7.0aa.  Last change: 2006 Mar 06
+*change.txt*    For Vim version 7.0aa.  Last change: 2006 Mar 16
 
 
 		  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -728,6 +728,7 @@ Examples: >
   :s/\([abc]\)\([efg]\)/\2\1/g	 modifies "af fa bg" to "fa fa gb"
   :s/abcde/abc^Mde/		 modifies "abcde"    to "abc", "de" (two lines)
   :s/$/\^M/			 modifies "abcde"    to "abcde^M"
+  :s/\w\+/\u\0/g		 modifies "bla bla"  to "Bla Bla"
 
 Note: In previous versions CTRL-V was handled in a special way.  Since this is
 not Vi compatible, this was removed.  Use a backslash instead.
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -1,4 +1,4 @@
-*options.txt*	For Vim version 7.0aa.  Last change: 2006 Mar 15
+*options.txt*	For Vim version 7.0aa.  Last change: 2006 Mar 16
 
 
 		  VIM REFERENCE MANUAL	  by Bram Moolenaar
@@ -3768,6 +3768,10 @@ A jump table for the options with a shor
 	cursor to the match.
 	The highlighting can be set with the 'i' flag in 'highlight'.
 	See also: 'hlsearch'.
+	CTRL-L can be used to add one character from after the current match
+	to the command line.
+	CTRL-R CTRL-W can be used to add the word at the end of the current
+	match, excluding the characters that were already typed.
 	NOTE: This option is reset when 'compatible' is set.
 
 						*'indentexpr'* *'inde'*
@@ -7182,10 +7186,19 @@ A jump table for the options with a shor
 	    block	Allow virtual editing in Visual block mode.
 	    insert	Allow virtual editing in Insert mode.
 	    all		Allow virtual editing in all modes.
+	    onemore	Allow the cursor to move just past the end of the line
 	Virtual editing means that the cursor can be positioned where there is
 	no actual character.  This can be halfway into a Tab or beyond the end
 	of the line.  Useful for selecting a rectangle in Visual mode and
 	editing a table.
+	"onemore" is not the same, it will only allow moving the cursor just
+	after the last character of the line.  This makes some commands more
+	consistent.  Previously the cursor was always past the end of the line
+	if the line was empty.  But it is far from Vi compatible.  It may also
+	break some plugins or Vim scripts.  For example because |$| moves to a
+	different position.  Use with care!
+	It doesn't make sense to combine "all" with "onemore", but you will
+	not get a warning for it.
 
 			*'visualbell'* *'vb'* *'novisualbell'* *'novb'* *beep*
 'visualbell' 'vb'	boolean	(default off)
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -2740,6 +2740,8 @@ 90.5	usr_90.txt	/*90.5*
 :undo	undo.txt	/*:undo*
 :undoj	undo.txt	/*:undoj*
 :undojoin	undo.txt	/*:undojoin*
+:undol	undo.txt	/*:undol*
+:undolist	undo.txt	/*:undolist*
 :unh	windows.txt	/*:unh*
 :unhide	windows.txt	/*:unhide*
 :unl	eval.txt	/*:unl*
@@ -6247,6 +6249,7 @@ new-multi-lang	version6.txt	/*new-multi-
 new-netrw-explore	version7.txt	/*new-netrw-explore*
 new-network-files	version6.txt	/*new-network-files*
 new-omni-completion	version7.txt	/*new-omni-completion*
+new-onemore	version7.txt	/*new-onemore*
 new-operator-mod	version6.txt	/*new-operator-mod*
 new-options-5.2	version5.txt	/*new-options-5.2*
 new-options-5.4	version5.txt	/*new-options-5.4*
--- a/runtime/doc/undo.txt
+++ b/runtime/doc/undo.txt
@@ -1,4 +1,4 @@
-*undo.txt*      For Vim version 7.0aa.  Last change: 2006 Mar 14
+*undo.txt*      For Vim version 7.0aa.  Last change: 2006 Mar 16
 
 
 		  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -23,6 +23,9 @@ u			Undo [count] changes.  {Vi: only one
 							*:u* *:un* *:undo*
 :u[ndo]			Undo one change.  {Vi: only one level}
 
+:u[ndo] {N}		Jump to after change 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}
@@ -114,6 +117,19 @@ What matters here is the order in which 
 are not considered changes in this context.  After each change you have a new
 state of the text.
 
+							*:undol* *:undolist*
+:undol[ist]		List the leafs in the tree of changes.  Example:
+				number changes   time ~
+				4      10        10:34:11
+				18     4         11:01:46
+
+			The "number" column is the change number.  This number
+			continuously increases and can be used to identify a
+			specific undo-able change, see |:undo|.
+			The "changes" column is the number of changes to this
+			leaf from the root of the tree.
+			The "time" column is the time this change was made.
+
 							*g-*
 g-			Go to older text state.  With a count repeat that many
 			times.  {not in Vi}
@@ -132,6 +148,7 @@ g+			Go to newer text state.  With a cou
 :later {N}m		Go to newer text state about {N} minutes later.
 :later {N}h		Go to newer text state about {N} hours later.
 
+
 Note that text states will become unreachable when undo information is cleared
 for 'undolevels'.
 
--- a/src/auto/configure
+++ b/src/auto/configure
@@ -2838,10 +2838,6 @@ if test "`(uname) 2>/dev/null`" = Darwin
   echo "$as_me:$LINENO: result: yes" >&5
 echo "${ECHO_T}yes" >&6
 
-    if test x$prefix = xNONE; then
-    prefix=/Applications
-  fi
-
   echo "$as_me:$LINENO: checking --disable-darwin argument" >&5
 echo $ECHO_N "checking --disable-darwin argument... $ECHO_C" >&6
   # Check whether --enable-darwin or --disable-darwin was given.
@@ -3395,6 +3391,10 @@ fi
     if test "x$CARBON" = "xyes"; then
       if test -z "$with_x" -a "X$enable_gui" != Xmotif -a "X$enable_gui" != Xathena -a "X$enable_gui" != Xgtk -a "X$enable_gui" != Xgtk2; then
 	with_x=no
+
+		if test x$prefix = xNONE; then
+	  prefix=/Applications
+	fi
       fi
     fi
   fi
--- a/src/configure.in
+++ b/src/configure.in
@@ -85,11 +85,6 @@ AC_MSG_CHECKING([for Darwin (Mac OS X)])
 if test "`(uname) 2>/dev/null`" = Darwin; then
   AC_MSG_RESULT(yes)
 
-  dnl Default install directory is not /usr/local
-  if test x$prefix = xNONE; then
-    prefix=/Applications
-  fi
-
   AC_MSG_CHECKING(--disable-darwin argument)
   AC_ARG_ENABLE(darwin,
 	  [  --disable-darwin        Disable Darwin (Mac OS X) support.],
@@ -165,6 +160,11 @@ if test "`(uname) 2>/dev/null`" = Darwin
     if test "x$CARBON" = "xyes"; then
       if test -z "$with_x" -a "X$enable_gui" != Xmotif -a "X$enable_gui" != Xathena -a "X$enable_gui" != Xgtk -a "X$enable_gui" != Xgtk2; then
 	with_x=no
+
+	dnl Default install directory is not /usr/local
+	if test x$prefix = xNONE; then
+	  prefix=/Applications
+	fi
       fi
     fi
   fi
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -1377,7 +1377,23 @@ getcmdline(firstc, count, indent)
 		    break;
 		goto cmdline_changed;
 
-	case Ctrl_L:	    /* longest common part */
+	case Ctrl_L:
+#ifdef FEAT_SEARCH_EXTRA
+		if (p_is && !cmd_silent && (firstc == '/' || firstc == '?'))
+		{
+		    /* Add a character from under the cursor for 'incsearch' */
+		    if (did_incsearch
+				   && !equalpos(curwin->w_cursor, old_cursor))
+		    {
+			c = gchar_cursor();
+			if (c != NUL)
+			    break;
+		    }
+		    goto cmdline_not_changed;
+		}
+#endif
+
+		/* completion: longest common part */
 		if (nextwild(&xpc, WILD_LONGEST, 0) == FAIL)
 		    break;
 		goto cmdline_changed;
@@ -1665,6 +1681,8 @@ cmdline_changed:
 	 */
 	if (p_is && !cmd_silent && (firstc == '/' || firstc == '?'))
 	{
+	    pos_T	end_pos;
+
 	    /* if there is a character waiting, search and redraw later */
 	    if (char_avail())
 	    {
@@ -1696,7 +1714,7 @@ cmdline_changed:
 		    /* cancelled searching because a char was typed */
 		    incsearch_postponed = TRUE;
 	    }
-	    if (i)
+	    if (i != 0)
 		highlight_match = TRUE;		/* highlight position */
 	    else
 		highlight_match = FALSE;	/* remove highlight */
@@ -1717,7 +1735,7 @@ cmdline_changed:
 		pos_T	    save_pos = curwin->w_cursor;
 
 		/*
-		 * First move cursor to end of match, then to start.  This
+		 * First move cursor to end of match, then to the start.  This
 		 * moves the whole match onto the screen when 'nowrap' is set.
 		 */
 		curwin->w_cursor.lnum += search_match_lines;
@@ -1728,14 +1746,20 @@ cmdline_changed:
 		    coladvance((colnr_T)MAXCOL);
 		}
 		validate_cursor();
+		end_pos = curwin->w_cursor;
 		curwin->w_cursor = save_pos;
 	    }
+
 	    validate_cursor();
 
 	    save_cmdline(&save_ccline);
 	    update_screen(SOME_VALID);
 	    restore_cmdline(&save_ccline);
 
+	    /* Leave it at the end to make CTRL-R CTRL-W work. */
+	    if (i != 0)
+		curwin->w_cursor = end_pos;
+
 	    msg_starthere();
 	    redrawcmdline();
 	    did_incsearch = TRUE;
@@ -2813,6 +2837,7 @@ cmdline_paste(regname, literally)
 {
     long		i;
     char_u		*arg;
+    char_u		*p;
     int			allocated;
     struct cmdline_info	save_ccline;
 
@@ -2845,7 +2870,40 @@ cmdline_paste(regname, literally)
 	/* Got the value of a special register in "arg". */
 	if (arg == NULL)
 	    return FAIL;
-	cmdline_paste_str(arg, literally);
+
+	/* When 'incsearch' is set and CTRL-R CTRL-W used: skip the duplicate
+	 * part of the word. */
+	p = arg;
+	if (p_is && regname == Ctrl_W)
+	{
+	    char_u  *w;
+	    int	    len;
+
+	    /* Locate start of last word in the cmd buffer. */
+	    for (w = ccline.cmdbuff + ccline.cmdlen; w > ccline.cmdbuff; )
+	    {
+#ifdef FEAT_MBYTE
+		if (has_mbyte)
+		{
+		    len = (*mb_head_off)(ccline.cmdbuff, w - 1) + 1;
+		    if (!vim_iswordc(mb_ptr2char(w - len)))
+			break;
+		    w -= len;
+		}
+		else
+#endif
+		{
+		    if (!vim_iswordc(w[-1]))
+			break;
+		    --w;
+		}
+	    }
+	    len = (ccline.cmdbuff + ccline.cmdlen) - w;
+	    if (p_ic ? STRNICMP(w, arg, len) == 0 : STRNCMP(w, arg, len) == 0)
+		p += len;
+	}
+
+	cmdline_paste_str(p, literally);
 	if (allocated)
 	    vim_free(arg);
 	return OK;
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -151,11 +151,15 @@ coladvance2(pos, addspaces, finetune, wc
     int		head = 0;
 #endif
 
-    one_more = (State & INSERT) || restart_edit != NUL
+    one_more = (State & INSERT)
+		    || restart_edit != NUL
 #ifdef FEAT_VISUAL
-					  || (VIsual_active && *p_sel != 'o')
-#endif
-					  ;
+		    || (VIsual_active && *p_sel != 'o')
+#endif
+#ifdef FEAT_VIRTUALEDIT
+		    || (ve_flags & VE_ONEMORE)
+#endif
+		    ;
     line = ml_get_curline();
 
     if (wcol >= MAXCOL)
@@ -5486,8 +5490,6 @@ qsort(base, elm_count, elm_size, cmp)
 }
 #endif
 
-#if defined(FEAT_EX_EXTRA) || defined(FEAT_CMDL_COMPL) \
-    || (defined(FEAT_SYN_HL) && defined(FEAT_MBYTE)) || defined(PROTO)
 /*
  * Sort an array of strings.
  */
@@ -5515,7 +5517,6 @@ sort_strings(files, count)
 {
     qsort((void *)files, (size_t)count, sizeof(char_u *), sort_compare);
 }
-#endif
 
 #if !defined(NO_EXPANDPATH) || defined(PROTO)
 /*
--- a/src/popupmenu.c
+++ b/src/popupmenu.c
@@ -58,6 +58,7 @@ pum_display(array, size, selected)
     int		row;
     int		height;
     int		col;
+    int		above_row = cmdline_row;
 
 redo:
     def_width = PUM_DEF_WIDTH;
@@ -80,6 +81,12 @@ redo:
     else
 	top_clear = 0;
 
+    /* When the preview window is at the bottom stop just above it.  Also
+     * avoid drawing over the status line so that it's clear there is a window
+     * boundary. */
+    if (lastwin->w_p_pvw)
+	above_row -= lastwin->w_height + lastwin->w_status_height + 1;
+
     /*
      * Figure out the size and position of the pum.
      */
@@ -92,8 +99,8 @@ redo:
 
     /* Put the pum below "row" if possible.  If there are few lines decide on
      * where there is more room. */
-    if (row >= cmdline_row - pum_height
-			      && row > (cmdline_row - top_clear - height) / 2)
+    if (row >= above_row - pum_height
+			      && row > (above_row - top_clear - height) / 2)
     {
 	/* pum above "row" */
 	if (row >= size)
@@ -116,8 +123,8 @@ redo:
     {
 	/* pum below "row" */
 	pum_row = row + height;
-	if (size > cmdline_row - pum_row)
-	    pum_height = cmdline_row - pum_row;
+	if (size > above_row - pum_row)
+	    pum_height = above_row - pum_row;
 	else
 	    pum_height = size;
 	if (p_ph > 0 && pum_height > p_ph)
--- a/src/regexp.c
+++ b/src/regexp.c
@@ -6531,53 +6531,53 @@ cstrchr(s, c)
  * This is impossible, so we declare a pointer to a function returning a
  * pointer to a function returning void. This should work for all compilers.
  */
-typedef void (*(*fptr) __ARGS((char_u *, int)))();
-
-static fptr do_upper __ARGS((char_u *, int));
-static fptr do_Upper __ARGS((char_u *, int));
-static fptr do_lower __ARGS((char_u *, int));
-static fptr do_Lower __ARGS((char_u *, int));
+typedef void (*(*fptr_T) __ARGS((int *, int)))();
+
+static fptr_T do_upper __ARGS((int *, int));
+static fptr_T do_Upper __ARGS((int *, int));
+static fptr_T do_lower __ARGS((int *, int));
+static fptr_T do_Lower __ARGS((int *, int));
 
 static int vim_regsub_both __ARGS((char_u *source, char_u *dest, int copy, int magic, int backslash));
 
-    static fptr
+    static fptr_T
 do_upper(d, c)
-    char_u *d;
-    int c;
-{
-    *d = TOUPPER_LOC(c);
-
-    return (fptr)NULL;
-}
-
-    static fptr
-do_Upper(d, c)
-    char_u *d;
-    int c;
+    int		*d;
+    int		c;
 {
-    *d = TOUPPER_LOC(c);
-
-    return (fptr)do_Upper;
+    *d = MB_TOUPPER(c);
+
+    return (fptr_T)NULL;
 }
 
-    static fptr
-do_lower(d, c)
-    char_u *d;
-    int c;
-{
-    *d = TOLOWER_LOC(c);
-
-    return (fptr)NULL;
-}
-
-    static fptr
-do_Lower(d, c)
-    char_u	*d;
+    static fptr_T
+do_Upper(d, c)
+    int		*d;
     int		c;
 {
-    *d = TOLOWER_LOC(c);
-
-    return (fptr)do_Lower;
+    *d = MB_TOUPPER(c);
+
+    return (fptr_T)do_Upper;
+}
+
+    static fptr_T
+do_lower(d, c)
+    int		*d;
+    int		c;
+{
+    *d = MB_TOLOWER(c);
+
+    return (fptr_T)NULL;
+}
+
+    static fptr_T
+do_Lower(d, c)
+    int		*d;
+    int		c;
+{
+    *d = MB_TOLOWER(c);
+
+    return (fptr_T)do_Lower;
 }
 
 /*
@@ -6587,7 +6587,8 @@ do_Lower(d, c)
  * pattern.  If that previous pattern also contains a ~ we should go back a
  * step further...  But we insert the previous pattern into the current one
  * and remember that.
- * This still does not handle the case where "magic" changes. TODO?
+ * This still does not handle the case where "magic" changes.  So require the
+ * user to keep his hands off of "magic".
  *
  * The tildes are parsed once before the first call to vim_regsub().
  */
@@ -6729,17 +6730,14 @@ vim_regsub_both(source, dest, copy, magi
     char_u	*dst;
     char_u	*s;
     int		c;
+    int		cc;
     int		no = -1;
-    fptr	func = (fptr)NULL;
+    fptr_T	func = (fptr_T)NULL;
     linenr_T	clnum = 0;	/* init for GCC */
     int		len = 0;	/* init for GCC */
 #ifdef FEAT_EVAL
     static char_u *eval_result = NULL;
 #endif
-#ifdef FEAT_MBYTE
-    int		l;
-#endif
-
 
     /* Be paranoid... */
     if (source == NULL || dest == NULL)
@@ -6840,16 +6838,16 @@ vim_regsub_both(source, dest, copy, magi
 	    {
 		switch (*src++)
 		{
-		case 'u':   func = (fptr)do_upper;
+		case 'u':   func = (fptr_T)do_upper;
 			    continue;
-		case 'U':   func = (fptr)do_Upper;
+		case 'U':   func = (fptr_T)do_Upper;
 			    continue;
-		case 'l':   func = (fptr)do_lower;
+		case 'l':   func = (fptr_T)do_lower;
 			    continue;
-		case 'L':   func = (fptr)do_Lower;
+		case 'L':   func = (fptr_T)do_Lower;
 			    continue;
 		case 'e':
-		case 'E':   func = (fptr)NULL;
+		case 'E':   func = (fptr_T)NULL;
 			    continue;
 		}
 	    }
@@ -6882,28 +6880,28 @@ vim_regsub_both(source, dest, copy, magi
 
 	    /* Write to buffer, if copy is set. */
 #ifdef FEAT_MBYTE
-	    if (has_mbyte && (l = (*mb_ptr2len)(src - 1)) > 1)
+	    if (has_mbyte)
+		c = mb_ptr2char(src - 1);
+#endif
+
+	    if (func == (fptr_T)NULL)	/* just copy */
+		cc = c;
+	    else
+		/* Turbo C complains without the typecast */
+		func = (fptr_T)(func(&cc, c));
+
+#ifdef FEAT_MBYTE
+	    if (has_mbyte)
 	    {
-		/* TODO: should use "func" here. */
+		src += mb_ptr2len(src - 1) - 1;
 		if (copy)
-		    mch_memmove(dst, src - 1, l);
-		dst += l - 1;
-		src += l - 1;
+		    mb_char2bytes(cc, dst);
+		dst += mb_char2len(cc) - 1;
 	    }
 	    else
-	    {
 #endif
 		if (copy)
-		{
-		    if (func == (fptr)NULL)	/* just copy */
-			*dst = c;
-		    else			/* change case */
-			func = (fptr)(func(dst, c));
-		    /* Turbo C complains without the typecast */
-		}
-#ifdef FEAT_MBYTE
-	    }
-#endif
+		    *dst = cc;
 	    dst++;
 	}
 	else
@@ -6976,29 +6974,39 @@ vim_regsub_both(source, dest, copy, magi
 			    }
 			    dst += 2;
 			}
-#ifdef FEAT_MBYTE
-			else if (has_mbyte && (l = (*mb_ptr2len)(s)) > 1)
-			{
-			    /* TODO: should use "func" here. */
-			    if (copy)
-				mch_memmove(dst, s, l);
-			    dst	+= l;
-			    s += l - 1;
-			    len	-= l - 1;
-			}
-#endif
 			else
 			{
-			    if (copy)
+#ifdef FEAT_MBYTE
+			    if (has_mbyte)
+				c = mb_ptr2char(s);
+			    else
+#endif
+				c = *s;
+
+			    if (func == (fptr_T)NULL)	/* just copy */
+				cc = c;
+			    else
+				/* Turbo C complains without the typecast */
+				func = (fptr_T)(func(&cc, c));
+
+#ifdef FEAT_MBYTE
+			    if (has_mbyte)
 			    {
-				if (func == (fptr)NULL)	    /* just copy */
-				    *dst = *s;
-				else			    /* change case */
-				    func = (fptr)(func(dst, *s));
-				/* Turbo C complains without the typecast */
+				int l = mb_ptr2len(s) - 1;
+
+				s += l;
+				len -= l;
+				if (copy)
+				    mb_char2bytes(cc, dst);
+				dst += mb_char2len(cc) - 1;
 			    }
-			    ++dst;
+			    else
+#endif
+				if (copy)
+				    *dst = cc;
+			    dst++;
 			}
+
 			++s;
 			--len;
 		    }
--- 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*/
--- a/src/version.h
+++ b/src/version.h
@@ -36,5 +36,5 @@
 #define VIM_VERSION_NODOT	"vim70aa"
 #define VIM_VERSION_SHORT	"7.0aa"
 #define VIM_VERSION_MEDIUM	"7.0aa ALPHA"
-#define VIM_VERSION_LONG	"VIM - Vi IMproved 7.0aa ALPHA (2006 Mar 15)"
-#define VIM_VERSION_LONG_DATE	"VIM - Vi IMproved 7.0aa ALPHA (2006 Mar 15, compiled "
+#define VIM_VERSION_LONG	"VIM - Vi IMproved 7.0aa ALPHA (2006 Mar 16)"
+#define VIM_VERSION_LONG_DATE	"VIM - Vi IMproved 7.0aa ALPHA (2006 Mar 16, compiled "