]> granicus.if.org Git - vim/commitdiff
updated for version 7.0224
authorBram Moolenaar <Bram@vim.org>
Tue, 14 Mar 2006 23:00:46 +0000 (23:00 +0000)
committerBram Moolenaar <Bram@vim.org>
Tue, 14 Mar 2006 23:00:46 +0000 (23:00 +0000)
runtime/autoload/netrw.vim
runtime/doc/diff.txt
runtime/doc/pi_netrw.txt
runtime/doc/tags
runtime/doc/undo.txt
src/os_unix.c
src/popupmenu.c
src/screen.c
src/undo.c

index 54613511ce4fea4fc24aa5eedcc04b4e84cc4200..124e6174895db3344fc1737cfab538411e2f8391 100644 (file)
@@ -1,7 +1,7 @@
 " netrw.vim: Handles file transfer and remote directory listing across a network
 "            AUTOLOAD PORTION
-" Date:                Mar 09, 2006
-" Version:     79
+" Date:                Mar 13, 2006
+" Version:     80
 " Maintainer:  Charles E Campbell, Jr <drchipNOSPAM at campbellfamily dot biz>
 " GetLatestVimScripts: 1075 1 :AutoInstall: netrw.vim
 " Copyright:    Copyright (C) 1999-2005 Charles E. Campbell, Jr. {{{1
@@ -23,7 +23,7 @@
 if &cp || exists("g:loaded_netrw")
   finish
 endif
-let g:loaded_netrw = "v79"
+let g:loaded_netrw = "v80"
 if v:version < 700
  echohl WarningMsg | echo "***netrw*** you need vim version 7.0 or later for version ".g:loaded_netrw." of netrw" | echohl None
  finish
@@ -2802,6 +2802,23 @@ fun! netrw#DirBrowse(dirname)
   endif
   let s:last_sort_by= g:netrw_sort_by
 
+  " set up ShellCmdPost handling.  Append current buffer to browselist
+  if !exists("s:netrw_browselist")
+   let s:netrw_browselist= []
+  endif
+  if g:netrw_fastbrowse <= 1 && (empty(s:netrw_browselist) || bufnr("%") > s:netrw_browselist[-1])
+   call add(s:netrw_browselist,bufnr("%"))
+"   call Decho("browselist=".string(s:netrw_browselist))
+  endif
+  if !exists("s:netrw_browser_shellcmd") && g:netrw_fastbrowse <= 1
+"   call Decho("setting up local-browser shell command refresh")
+   let s:netrw_browser_shellcmd= 1
+   augroup AuNetrwShellCmd
+    au!
+    au ShellCmdPost *  call s:LocalBrowseShellCmdRefresh()
+   augroup END
+  endif
+
   " get the new directory name
   if has("win32") || has("win95") || has("win64") || has("win16")
    let b:netrw_curdir= substitute(a:dirname,'\\','/','ge')
@@ -3161,6 +3178,36 @@ fun! s:LocalBrowseChgDir(dirname,newdir,...)
   return dirname
 endfun
 
+" ---------------------------------------------------------------------
+" LocalBrowseShellCmdRefresh: this function is called after a user has {{{2
+" performed any shell command.  The idea is to cause all local-browsing
+" buffers to be refreshed after a user has executed some shell command,
+" on the chance that s/he removed/created a file/directory with it.
+fun! s:LocalBrowseShellCmdRefresh()
+"  call Dfunc("LocalBrowseShellCmdRefresh() browselist=".string(s:netrw_browselist))
+  "  go through all buffers,
+  "  including unlisted (which is why I can't use bufdo)
+  let curwin = winnr()
+  let ibl    = 0
+  for ibuf in s:netrw_browselist
+   if bufwinnr(ibuf) == -1
+"    call Decho("wiping  buf#".ibuf)
+    exe "bw ".ibuf
+    call remove(s:netrw_browselist,ibl)
+"    call Decho("browselist=".string(s:netrw_browselist))
+    continue
+   else
+"    call Decho("refresh buf#".ibuf.'-> win#'.bufwinnr(ibuf))
+    exe bufwinnr(ibuf)."wincmd w"
+    call s:NetRefresh(s:LocalBrowseChgDir(b:netrw_curdir,'./'),1)
+   endif
+   let ibl= ibl + 1
+  endfor
+  exe curwin."wincmd w"
+
+"  call Dret("LocalBrowseShellCmdRefresh")
+endfun
+
 " ---------------------------------------------------------------------
 " LocalBrowseRm: {{{2
 fun! s:LocalBrowseRm(path) range
@@ -3465,7 +3512,7 @@ fun! netrw#Explore(indx,dosplit,style,...)
      call search('\<'.substitute(dirfile,"^.*/","","").'\>',"w")
     endif
     let w:netrw_explore_mtchcnt = indx + 1
-    let w:netrw_explore_bufnr   = bufnr(".")
+    let w:netrw_explore_bufnr   = bufnr("%")
     let w:netrw_explore_line    = line(".")
     call s:SetupNetrwStatusLine('%f %h%m%r%=%9*%{NetrwStatusLine()}')
 "    call Decho("explore: mtchcnt=".w:netrw_explore_mtchcnt." bufnr=".w:netrw_explore_bufnr." line#".w:netrw_explore_line)
@@ -3537,8 +3584,8 @@ fun! NetrwStatusLine()
 "  let g:stlmsg=""
 "  if !exists("w:netrw_explore_bufnr")
 "   let g:stlmsg="!X<explore_bufnr>"
-"  elseif w:netrw_explore_bufnr != bufnr(".")
-"   let g:stlmsg="explore_bufnr!=".bufnr(".")
+"  elseif w:netrw_explore_bufnr != bufnr("%")
+"   let g:stlmsg="explore_bufnr!=".bufnr("%")
 "  endif
 "  if !exists("w:netrw_explore_line")
 "   let g:stlmsg=" !X<explore_line>"
@@ -3550,7 +3597,7 @@ fun! NetrwStatusLine()
 "  endif
   " ^^^ NetrwStatusLine() debugging ^^^
 
-  if !exists("w:netrw_explore_bufnr") || w:netrw_explore_bufnr != bufnr(".") || !exists("w:netrw_explore_line") || w:netrw_explore_line != line(".") || !exists("w:netrw_explore_list")
+  if !exists("w:netrw_explore_bufnr") || w:netrw_explore_bufnr != bufnr("%") || !exists("w:netrw_explore_line") || w:netrw_explore_line != line(".") || !exists("w:netrw_explore_list")
    " restore user's status line
    let &stl        = s:netrw_users_stl
    let &laststatus = s:netrw_users_ls
index aaf21b0f34f8b7586cda46978af64b700bb87681..8a6c7afde6c892028a7c6ca5f612b4444ff74c00 100644 (file)
@@ -1,4 +1,4 @@
-*diff.txt*      For Vim version 7.0aa.  Last change: 2006 Feb 18
+*diff.txt*      For Vim version 7.0aa.  Last change: 2006 Mar 14
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -378,7 +378,7 @@ will have the same effect.  These variables are set to the file names used:
 
 Example (this does the same as 'patchexpr' being empty): >
 
-       let patchexpr=MyPatch
+       let patchexpr=MyPatch()
        function MyPatch
           :call system("patch -o " . v:fname_out . " " . v:fname_in .
           \  " < " . v:fname_diff)
index ae39789d7d0324ff63175e72e82742172c31a57c..5d054e92469f588354644f398e2247867ccdcf77 100644 (file)
@@ -1,4 +1,4 @@
-*pi_netrw.txt*  For Vim version 7.0.  Last change: Mar 09, 2006
+*pi_netrw.txt*  For Vim version 7.0.  Last change: Mar 10, 2006
 
                VIM REFERENCE MANUAL    by Charles E. Campbell, Jr.
 
index a6b407a1935141e2fd025e12e7ec9d8bb2e235ac..d27b9118f2a24827615e580b8c102deeba384466 100644 (file)
@@ -1965,6 +1965,8 @@ $VIMRUNTIME       starting.txt    /*$VIMRUNTIME*
 :dsp   tagsrch.txt     /*:dsp*
 :dsplit        tagsrch.txt     /*:dsplit*
 :e     editing.txt     /*:e*
+:ea    undo.txt        /*:ea*
+:earlier       undo.txt        /*:earlier*
 :ec    eval.txt        /*:ec*
 :echo  eval.txt        /*:echo*
 :echoe eval.txt        /*:echoe*
@@ -2142,6 +2144,8 @@ $VIMRUNTIME       starting.txt    /*$VIMRUNTIME*
 :lang  mlang.txt       /*:lang*
 :language      mlang.txt       /*:language*
 :last  editing.txt     /*:last*
+:lat   undo.txt        /*:lat*
+:later undo.txt        /*:later*
 :lb    quickfix.txt    /*:lb*
 :lbuffer       quickfix.txt    /*:lbuffer*
 :lc    editing.txt     /*:lc*
@@ -5281,7 +5285,9 @@ g$        motion.txt      /*g$*
 g&     change.txt      /*g&*
 g'     motion.txt      /*g'*
 g'a    motion.txt      /*g'a*
+g+     undo.txt        /*g+*
 g,     motion.txt      /*g,*
+g-     undo.txt        /*g-*
 g0     motion.txt      /*g0*
 g8     various.txt     /*g8*
 g:DrChipTopLvlMenu     pi_netrw.txt    /*g:DrChipTopLvlMenu*
@@ -6254,6 +6260,7 @@ new-searchpat     version6.txt    /*new-searchpat*
 new-session-files      version5.txt    /*new-session-files*
 new-spell      version7.txt    /*new-spell*
 new-tab-pages  version7.txt    /*new-tab-pages*
+new-undo-branches      version7.txt    /*new-undo-branches*
 new-unlisted-buffers   version6.txt    /*new-unlisted-buffers*
 new-user-defined       version5.txt    /*new-user-defined*
 new-user-manual        version6.txt    /*new-user-manual*
@@ -7212,6 +7219,7 @@ undercurl syntax.txt      /*undercurl*
 underline      syntax.txt      /*underline*
 undo   undo.txt        /*undo*
 undo-blocks    undo.txt        /*undo-blocks*
+undo-branches  undo.txt        /*undo-branches*
 undo-commands  undo.txt        /*undo-commands*
 undo-redo      undo.txt        /*undo-redo*
 undo-remarks   undo.txt        /*undo-remarks*
index bdb7ffbf35d841b27ef14dc65cb23bad7a9fad90..fdfa71df60bb85839935bacd6da44f230e5bf1df 100644 (file)
@@ -1,4 +1,4 @@
-*undo.txt*      For Vim version 7.0aa.  Last change: 2006 Feb 28
+*undo.txt*      For Vim version 7.0aa.  Last change: 2006 Mar 14
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -11,7 +11,8 @@ The basics are explained in section |02.5| of the user manual.
 1. Undo and redo commands      |undo-commands|
 2. Two ways of undo            |undo-two-ways|
 3. Undo blocks                 |undo-blocks|
-4. Remarks about undo          |undo-remarks|
+4. Undo branches               |undo-branches|
+5. Remarks about undo          |undo-remarks|
 
 ==============================================================================
 1. Undo and redo commands                              *undo-commands*
@@ -102,7 +103,88 @@ After this an "u" command will undo the delete command and the previous
 change.
 
 ==============================================================================
-4. Remarks about undo                                  *undo-remarks*
+4. Undo branches                                       *undo-branches*
+
+Above we only discussed one line of undo.  But it is also possible to branch
+off.  This happens when you undo a few changes and then make a new change.
+The undone changes become a branch.  You can go to that branch with the
+following commands.
+
+What matters here is the order in which the changes are made.  Undo and redo
+are not considered changes in this context.  After each change you have a new
+state of the text.
+
+                                                       *g-*
+g-                     Go to older text state.  With a count repeat that many
+                       times.  {not in Vi}
+                                                       *:ea* *:earlier*
+:earlier {count}       Go to older text state {count} times.
+:earlier {N}s          Go to older text state about {N} seconds before.
+:earlier {N}m          Go to older text state about {N} minutes before.
+:earlier {N}h          Go to older text state about {N} hours before.
+
+                                                       *g+*
+g+                     Go to newer text state.  With a count repeat that many
+                       times.  {not in Vi}
+                                                       *:lat* *:later*
+:later {count}         Go to newer text state {count} times.
+:later {N}s            Go to newer text state about {N} seconds later.
+: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'.
+
+Don't be surprised when moving through time shows multiple changes to take
+place at a time.  This happens when moving through the undo tree and then
+making a new change.
+
+EXAMPLE
+
+Start with this text:
+       one two three ~
+
+Delete the first word by pressing "x" three times:
+       ne two three ~
+       e two three ~
+        two three ~
+
+Now undo that by pressing "u" three times:
+       e two three ~
+       ne two three ~
+       one two three ~
+
+Delete the second word by pressing "x" three times:
+       one wo three ~
+       one o three ~
+       one  three ~
+
+Now undo that by using "g-" three times:
+       one o three ~
+       one wo three ~
+       one two three ~
+
+Continue going back in time by pressing "g-" one more time:
+        two three ~
+
+You are now back in the first undo branch, after deleting "one".  Repeating
+"g-" will now bring you back to the original text:
+       e two three ~
+       ne two three ~
+       one two three ~
+
+Jump to the last change with ":later 1h":
+       one  three ~
+
+And back to the start again with ":earlier 1h":
+       one two three ~
+
+
+Note that using "u" and CTRL-R will not get you to all possible text states
+while repeating "g-" and "g+" does.
+
+==============================================================================
+5. Remarks about undo                                  *undo-remarks*
 
 The number of changes that are remembered is set with the 'undolevels' option.
 If it is zero, the Vi-compatible way is always used.  If it is negative no
index a80bd21807fcd6580edbc899e41fe08b15e0a840..3f9bd136a01bd2411394d0f4ceb51076059399af 100644 (file)
@@ -931,6 +931,29 @@ deathtrap SIGDEFARG(sigarg)
     get_stack_limit();
 #endif
 
+#if 0
+    /* This is for opening gdb the moment Vim crashes.
+     * You need to manually adjust the file name and Vim executable name.
+     * Suggested by SungHyun Nam. */
+    {
+# define VI_GDB_FILE "/tmp/vimgdb"
+# define VIM_NAME "/usr/bin/vim"
+       FILE *fp = fopen(VI_GDB_FILE, "w");
+       if (fp)
+       {
+           fprintf(fp,
+                   "file %s\n"
+                   "attach %d\n"
+                   "set height 1000\n"
+                   "bt full\n"
+                   , VIM_NAME, getpid());
+           fclose(fp);
+           system("xterm -e gdb -x "VI_GDB_FILE);
+           unlink(VI_GDB_FILE);
+       }
+    }
+#endif
+
 #ifdef SIGHASARG
     /* try to find the name of this signal */
     for (i = 0; signal_info[i].sig != -1; i++)
index 1ca03726dce10775b874858c562e84cb09e4fdff..5126e8647ba358fd182031f8f63994a717d55f28 100644 (file)
@@ -504,6 +504,7 @@ pum_undisplay()
 {
     pum_array = NULL;
     redraw_all_later(SOME_VALID);
+    status_redraw_all();
 }
 
 /*
index 44e5d171536b101b46c490ab42e73739d6928aae..64c2bb5bc67c265757a50ac23494c81a4257c04c 100644 (file)
@@ -4273,9 +4273,15 @@ win_line(wp, lnum, startrow, endrow, nochange)
 
 #ifdef FEAT_SYN_HL
            /* Highlight 'cursorcolumn' past end of the line. */
+           if (wp->w_p_wrap)
+               v = wp->w_skipcol;
+           else
+               v = wp->w_leftcol;
+           if (vcol < v)       /* line ends before left margin */
+               vcol = v;
            if (wp->w_p_cuc
                    && (int)wp->w_virtcol >= vcol
-                   && (int)wp->w_virtcol < W_WIDTH(wp)
+                   && (int)wp->w_virtcol < W_WIDTH(wp) + v
                    && lnum != wp->w_cursor.lnum
 # ifdef FEAT_RIGHTLEFT
                    && !wp->w_p_rl
index f693d144f9436f47ac554dca8546fec0891b1364..88f11a342a3443953e0495319fc084338083e9ea 100644 (file)
  *
  * Each u_entry list contains the information for one undo or redo.
  * curbuf->b_u_curhead points to the header of the last undo (the next redo),
- * or is NULL if nothing has been undone.
+ * or is NULL if nothing has been undone (end of the branch).
  *
  * For keeping alternate undo/redo branches the uh_alt field is used.  Thus at
  * each point in the list a branch may appear for an alternate to redo.  The
  * uh_seq field is numbered sequentially to be able to find a newer or older
  * branch.
  *
+ *                +---------------+    +---------------+
+ * b_u_oldhead --->| u_header     |    | u_header      |
+ *                |   uh_alt_next ---->|   uh_alt_next ----> NULL
+ *        NULL <----- uh_alt_prev |<------ uh_alt_prev |
+ *                |   uh_prev     |    |   uh_prev     |
+ *                +-----|---------+    +-----|---------+
+ *                      |                    |
+ *                      V                    V
+ *                +---------------+    +---------------+
+ *                | u_header      |    | u_header      |
+ *                |   uh_alt_next |    |   uh_alt_next |
+ * b_u_newhead --->|   uh_alt_prev |   |   uh_alt_prev |
+ *                |   uh_prev     |    |   uh_prev     |
+ *                +-----|---------+    +-----|---------+
+ *                      |                    |
+ *                      V                    V
+ *                    NULL             +---------------+    +---------------+
+ *                                     | u_header      |    | u_header      |
+ *                                     |   uh_alt_next ---->|   uh_alt_next |
+ *                                     |   uh_alt_prev |<------ uh_alt_prev |
+ *                                     |   uh_prev     |    |   uh_prev     |
+ *                                     +-----|---------+    +-----|---------+
+ *                                           |                    |
+ *                                          etc.                 etc.
+ *
+ *
  * All data is allocated with U_ALLOC_LINE(), it will be freed as soon as the
  * buffer is unloaded.
  */
@@ -55,6 +81,7 @@
 /* See below: use malloc()/free() for memory management. */
 #define U_USE_MALLOC 1
 
+static void u_unch_branch __ARGS((u_header_T *uhp));
 static u_entry_T *u_get_headentry __ARGS((void));
 static void u_getbot __ARGS((void));
 static int undo_allowed __ARGS((void));
@@ -62,7 +89,7 @@ static int u_savecommon __ARGS((linenr_T, linenr_T, 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_freelist __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp));
+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));
 static void u_freeentry __ARGS((u_entry_T *, long));
@@ -270,8 +297,8 @@ u_savecommon(top, bot, newbot)
        }
 
        /*
-        * If we undid more than we redid, remove the entry lists before and
-        * including curbuf->b_u_curhead to the alternate branch.
+        * If we undid more than we redid, move the entry lists before and
+        * including curbuf->b_u_curhead to an alternate branch.
         */
        old_curhead = curbuf->b_u_curhead;
        if (old_curhead != NULL)
@@ -285,17 +312,17 @@ u_savecommon(top, bot, newbot)
         */
        while (curbuf->b_u_numhead > p_ul && curbuf->b_u_oldhead != NULL)
        {
-           u_header_T      *upfree = curbuf->b_u_oldhead;
+           u_header_T      *uhfree = curbuf->b_u_oldhead;
 
            /* If there is no branch only free one header. */
-           if (upfree->uh_alt_next == NULL)
-               u_freelist(curbuf, upfree, &old_curhead);
+           if (uhfree->uh_alt_next == NULL)
+               u_freeheader(curbuf, uhfree, &old_curhead);
            else
            {
                /* Free the oldest alternate branch as a whole. */
-               while (upfree->uh_alt_next != NULL)
-                   upfree = upfree->uh_alt_next;
-               u_freebranch(curbuf, upfree, &old_curhead);
+               while (uhfree->uh_alt_next != NULL)
+                   uhfree = uhfree->uh_alt_next;
+               u_freebranch(curbuf, uhfree, &old_curhead);
            }
        }
 
@@ -317,10 +344,14 @@ u_savecommon(top, bot, newbot)
                curbuf->b_u_oldhead = uhp;
        }
        uhp->uh_alt_prev = NULL;
-       uhp->uh_seq = curbuf->b_u_seq_last++;
-       curbuf->b_u_seq_cur = curbuf->b_u_seq_last;
        if (curbuf->b_u_newhead != NULL)
            curbuf->b_u_newhead->uh_prev = uhp;
+
+       uhp->uh_seq = curbuf->b_u_seq_last++;
+       curbuf->b_u_seq_cur = curbuf->b_u_seq_last;
+       uhp->uh_time = time(NULL);
+       curbuf->b_u_seq_time = uhp->uh_time + 1;
+
        uhp->uh_walk = 0;
        uhp->uh_entry = NULL;
        uhp->uh_getbot_entry = NULL;
@@ -331,7 +362,6 @@ u_savecommon(top, bot, newbot)
        else
            uhp->uh_cursor_vcol = -1;
 #endif
-       uhp->uh_time = time(NULL);
 
        /* save changed and buffer empty flag for undo */
        uhp->uh_flags = (curbuf->b_changed ? UH_CHANGED : 0) +
@@ -575,7 +605,6 @@ u_doit(count)
            }
 
            u_undoredo();
-           curbuf->b_u_seq_cur = curbuf->b_u_curhead->uh_seq;
        }
        else
        {
@@ -586,7 +615,8 @@ u_doit(count)
            }
 
            u_undoredo();
-           curbuf->b_u_seq_cur = curbuf->b_u_curhead->uh_seq + 1;
+           ++curbuf->b_u_seq_cur;
+           ++curbuf->b_u_seq_time;
 
            /* Advance for next redo.  Set "newhead" when at the end of the
             * redoable changes. */
@@ -603,18 +633,27 @@ static int lastmark = 0;
 /*
  * Undo or redo over the timeline.
  * 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.
  */
     void
-undo_time(step)
-    int            step;
+undo_time(step, sec)
+    long       step;
+    int                sec;
 {
     long           target;
     long           closest;
+    long           closest_start;
+    long           closest_seq = 0;
+    long           val;
+    long           limit;
     u_header_T     *uhp;
     u_header_T     *last;
     int                    mark;
     int                    nomark;
     int                    round;
+    int                    dosec = sec;
+    int                    above = FALSE;
 
     u_newcount = 0;
     u_oldcount = 0;
@@ -625,18 +664,43 @@ undo_time(step)
      * the current one also counts, thus do one less. */
     if (step < 0)
     {
-       target = curbuf->b_u_seq_cur + step;
-       closest = -1;
+       if (sec)
+           target = (long)curbuf->b_u_seq_time + step;
+       else
+           target = curbuf->b_u_seq_cur + step;
+       if (target < 0)
+           target = -1;
+       closest = -2;
     }
     else
     {
-       target = curbuf->b_u_seq_cur + step - 1;
-       closest = curbuf->b_u_seq_last + 1;
+       if (sec)
+       {
+           target = curbuf->b_u_seq_time + step - 1;
+           closest = time(NULL) + 1;
+       }
+       else
+       {
+           target = curbuf->b_u_seq_cur + step - 1;
+           closest = curbuf->b_u_seq_last + 1;
+       }
+       if (target >= closest)
+           target = closest - 1;
     }
+    closest_start = closest;
+    if (sec)
+       limit = curbuf->b_u_seq_time + (step > 0 ? -1 : 1);
+    else
+       limit = curbuf->b_u_seq_cur;
 
-    /* May do this twice:
+    /*
+     * May do this twice:
      * 1. Search for "target", update "closest" to the best match found.
-     * 2. If "target" not found search for "closest".  */
+     * 2. If "target" not found search for "closest".
+     *
+     * When using the closest time we use the sequence number in the second
+     * round, because there may be several entries with the same time.
+     */
     for (round = 1; round <= 2; ++round)
     {
        /* Find the path from the current state to where we want to go.  The
@@ -654,13 +718,37 @@ undo_time(step)
        while (uhp != NULL)
        {
            uhp->uh_walk = mark;
-           if (uhp->uh_seq == target)  /* found it! */
-               break;
+           val = (dosec ? uhp->uh_time : uhp->uh_seq);
 
-           if (round == 1 && (step < 0
-                       ? (uhp->uh_seq < target && uhp->uh_seq > closest)
-                       : (uhp->uh_seq > target && uhp->uh_seq < closest)))
-               closest = uhp->uh_seq;
+           if (round == 1)
+           {
+               /* Remember the header that is closest to the target.
+                * It must be at least in the right direction (checked with
+                * "limit").  When the timestamp is equal find the
+                * highest/lowest sequence number. */
+               if ((dosec && val == closest)
+                       ? (step < 0
+                           ? uhp->uh_seq < closest_seq
+                           : uhp->uh_seq > closest_seq)
+                       : (step < 0
+                           ? (val < limit
+                               && (closest > target
+                                   ? (val <= closest)
+                                   : (val >= closest)))
+                           : (val > limit
+                               && (closest < target
+                                   ? val >= closest
+                                   : val <= closest))))
+               {
+                   closest = val;
+                   closest_seq = uhp->uh_seq;
+               }
+           }
+
+           /* Quit searching when we found a match.  But when searching for a
+            * time we need to continue looking for the best uh_seq. */
+           if (target == val && !dosec)
+               break;
 
            /* go down in the tree if we haven't been there */
            if (uhp->uh_prev != NULL && uhp->uh_prev->uh_walk != nomark
@@ -693,18 +781,19 @@ undo_time(step)
 
        if (uhp != NULL)    /* found it */
            break;
-       if (step < 0 && closest == -1)
-       {
-           MSG(_("Already at oldest change"));
-           return;
-       }
-       if (step > 0 && closest == curbuf->b_u_seq_last + 1)
+       if (closest == closest_start)
        {
-           MSG(_("Already at newest change"));
+           if (step < 0)
+               MSG(_("Already at oldest change"));
+           else
+               MSG(_("Already at newest change"));
            return;
        }
 
-       target = closest;
+       target = closest_seq;
+       dosec = FALSE;
+       if (step < 0)
+           above = TRUE;       /* stop above the header */
     }
 
     /* If we found it: Follow the path to go to where we want to be. */
@@ -720,7 +809,8 @@ undo_time(step)
                uhp = curbuf->b_u_newhead;
            else
            {
-               while (uhp->uh_alt_prev != NULL)
+               while (uhp->uh_alt_prev != NULL
+                                        && uhp->uh_alt_prev->uh_walk == mark)
                {
                    uhp->uh_walk = nomark;
                    uhp = uhp->uh_alt_prev;
@@ -732,11 +822,10 @@ undo_time(step)
            curbuf->b_u_curhead = uhp;
            u_undoredo();
            uhp->uh_walk = nomark;      /* don't go back down here */
-           curbuf->b_u_seq_cur = uhp->uh_seq;
        }
 
        /*
-        * And now go down the tree, branching off where needed.
+        * And now go down the tree (redo), branching off where needed.
         */
        uhp = curbuf->b_u_curhead;
        for (;;)
@@ -759,13 +848,21 @@ undo_time(step)
 
                uhp = last;
            }
+           curbuf->b_u_curhead = uhp;
+           curbuf->b_u_seq_cur = uhp->uh_seq;
+           curbuf->b_u_seq_time = uhp->uh_time;
 
            if (uhp->uh_walk != mark)
                break;      /* must have reached the target */
 
-           curbuf->b_u_curhead = uhp;
+           /* Stop when going backwards in time and didn't find the exact
+            * header we were looking for. */
+           if (uhp->uh_seq == target && above)
+               break;
+
            u_undoredo();
-           curbuf->b_u_seq_cur = uhp->uh_seq + 1;
+           ++curbuf->b_u_seq_cur;
+           ++curbuf->b_u_seq_time;
 
            /* Advance "curhead" to below the header we last used.  If it
             * becomes NULL then we need to set "newhead" to this leaf. */
@@ -813,8 +910,9 @@ u_undoredo()
     visualinfo_T visualinfo;
 #endif
     int                empty_buffer;               /* buffer became empty */
+    u_header_T *curhead = curbuf->b_u_curhead;
 
-    old_flags = curbuf->b_u_curhead->uh_flags;
+    old_flags = curhead->uh_flags;
     new_flags = (curbuf->b_changed ? UH_CHANGED : 0) +
               ((curbuf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0);
     setpcmark();
@@ -831,7 +929,7 @@ u_undoredo()
     curbuf->b_op_end.lnum = 0;
     curbuf->b_op_end.col = 0;
 
-    for (uep = curbuf->b_u_curhead->uh_entry; uep != NULL; uep = nuep)
+    for (uep = curhead->uh_entry; uep != NULL; uep = nuep)
     {
        top = uep->ue_top;
        bot = uep->ue_bot;
@@ -853,10 +951,10 @@ u_undoredo()
            /* If the saved cursor is somewhere in this undo block, move it to
             * the remembered position.  Makes "gwap" put the cursor back
             * where it was. */
-           lnum = curbuf->b_u_curhead->uh_cursor.lnum;
+           lnum = curhead->uh_cursor.lnum;
            if (lnum >= top && lnum <= top + newsize + 1)
            {
-               curwin->w_cursor = curbuf->b_u_curhead->uh_cursor;
+               curwin->w_cursor = curhead->uh_cursor;
                newlnum = curwin->w_cursor.lnum - 1;
            }
            else
@@ -970,8 +1068,8 @@ u_undoredo()
        newlist = uep;
     }
 
-    curbuf->b_u_curhead->uh_entry = newlist;
-    curbuf->b_u_curhead->uh_flags = new_flags;
+    curhead->uh_entry = newlist;
+    curhead->uh_flags = new_flags;
     if ((old_flags & UH_EMPTYBUF) && bufempty())
        curbuf->b_ml.ml_flags |= ML_EMPTY;
     if (old_flags & UH_CHANGED)
@@ -987,16 +1085,16 @@ u_undoredo()
      * restore marks from before undo/redo
      */
     for (i = 0; i < NMARKS; ++i)
-       if (curbuf->b_u_curhead->uh_namedm[i].lnum != 0)
+       if (curhead->uh_namedm[i].lnum != 0)
        {
-           curbuf->b_namedm[i] = curbuf->b_u_curhead->uh_namedm[i];
-           curbuf->b_u_curhead->uh_namedm[i] = namedm[i];
+           curbuf->b_namedm[i] = curhead->uh_namedm[i];
+           curhead->uh_namedm[i] = namedm[i];
        }
 #ifdef FEAT_VISUAL
-    if (curbuf->b_u_curhead->uh_visual.vi_start.lnum != 0)
+    if (curhead->uh_visual.vi_start.lnum != 0)
     {
-       curbuf->b_visual = curbuf->b_u_curhead->uh_visual;
-       curbuf->b_u_curhead->uh_visual = visualinfo;
+       curbuf->b_visual = curhead->uh_visual;
+       curhead->uh_visual = visualinfo;
     }
 #endif
 
@@ -1005,15 +1103,15 @@ u_undoredo()
      * before starting the change (for the "o" command).
      * Otherwise the cursor should go to the first undone line.
      */
-    if (curbuf->b_u_curhead->uh_cursor.lnum + 1 == curwin->w_cursor.lnum
+    if (curhead->uh_cursor.lnum + 1 == curwin->w_cursor.lnum
                                                 && curwin->w_cursor.lnum > 1)
        --curwin->w_cursor.lnum;
-    if (curbuf->b_u_curhead->uh_cursor.lnum == curwin->w_cursor.lnum)
+    if (curhead->uh_cursor.lnum == curwin->w_cursor.lnum)
     {
-       curwin->w_cursor.col = curbuf->b_u_curhead->uh_cursor.col;
+       curwin->w_cursor.col = curhead->uh_cursor.col;
 #ifdef FEAT_VIRTUALEDIT
-       if (virtual_active() && curbuf->b_u_curhead->uh_cursor_vcol >= 0)
-           coladvance((colnr_T)curbuf->b_u_curhead->uh_cursor_vcol);
+       if (virtual_active() && curhead->uh_cursor_vcol >= 0)
+           coladvance((colnr_T)curhead->uh_cursor_vcol);
        else
            curwin->w_cursor.coladd = 0;
 #endif
@@ -1034,6 +1132,10 @@ u_undoredo()
 
     /* Make sure the cursor is on an existing line and column. */
     check_cursor();
+
+    /* Remember where we are for "g-" and ":earlier 10s". */
+    curbuf->b_u_seq_cur = curhead->uh_seq;
+    curbuf->b_u_seq_time = curhead->uh_time;
 }
 
 /*
@@ -1135,12 +1237,23 @@ ex_undojoin(eap)
     void
 u_unchanged(buf)
     buf_T      *buf;
+{
+    u_unch_branch(buf->b_u_oldhead);
+    buf->b_did_warn = FALSE;
+}
+
+    static void
+u_unch_branch(uhp)
+    u_header_T *uhp;
 {
     u_header_T *uh;
 
-    for (uh = buf->b_u_newhead; uh; uh = uh->uh_next)
+    for (uh = uhp; uh != NULL; uh = uh->uh_prev)
+    {
        uh->uh_flags |= UH_CHANGED;
-    buf->b_did_warn = FALSE;
+       if (uh->uh_alt_next != NULL)
+           u_unch_branch(uh->uh_alt_next);         /* recursive */
+    }
 }
 
 /*
@@ -1201,7 +1314,7 @@ u_getbot()
  * Free one header and its entry list and adjust the pointers.
  */
     static void
-u_freelist(buf, uhp, uhpp)
+u_freeheader(buf, uhp, uhpp)
     buf_T          *buf;
     u_header_T     *uhp;
     u_header_T     **uhpp;     /* if not NULL reset when freeing this header */
@@ -1229,7 +1342,7 @@ u_freelist(buf, uhp, uhpp)
 }
 
 /*
- * Free an alternate branch and all following alternate branches.
+ * Free an alternate branch and any following alternate branches.
  */
     static void
 u_freebranch(buf, uhp, uhpp)
@@ -1415,7 +1528,7 @@ u_blockfree(buf)
     buf_T      *buf;
 {
     while (buf->b_u_oldhead != NULL)
-       u_freelist(buf, buf->b_u_oldhead, NULL);
+       u_freeheader(buf, buf->b_u_oldhead, NULL);
     U_FREE_LINE(buf->b_u_line_ptr);
 }