]> granicus.if.org Git - vim/commitdiff
patch 7.4.1988 v7.4.1988
authorBram Moolenaar <Bram@vim.org>
Sun, 3 Jul 2016 15:47:26 +0000 (17:47 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 3 Jul 2016 15:47:26 +0000 (17:47 +0200)
Problem:    When updating viminfo with file marks there is no time order.
Solution:   Remember the time when a buffer was last used, store marks for
            the most recently used buffers.

src/buffer.c
src/ex_cmds.c
src/main.c
src/mark.c
src/proto/mark.pro
src/structs.h
src/testdir/test_viminfo.vim
src/version.c

index 39a5bcb4d13f57aba05e7f598cf408cb1b76f16d..058e4d785ba5dee86a95a902bd095d49aaf701c6 100644 (file)
@@ -1619,6 +1619,9 @@ enter_buffer(buf_T *buf)
     if (!curbuf->b_help && curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
        (void)did_set_spelllang(curwin);
 #endif
+#ifdef FEAT_VIMINFO
+    curbuf->b_last_used = vim_time();
+#endif
 
     redraw_later(NOT_VALID);
 }
index 72603d1bd2aab90a85894b5a31450e0499e804c5..5900c86d31bfee1ab6d96d525898e4fe402e59e5 100644 (file)
@@ -2148,10 +2148,11 @@ viminfo_filename(char_u *file)
     static void
 do_viminfo(FILE *fp_in, FILE *fp_out, int flags)
 {
-    int                count = 0;
     int                eof = FALSE;
     vir_T      vir;
     int                merge = FALSE;
+    int                do_copy_marks = FALSE;
+    garray_T   buflist;
 
     if ((vir.vir_line = alloc(LSIZE)) == NULL)
        return;
@@ -2183,7 +2184,11 @@ do_viminfo(FILE *fp_in, FILE *fp_out, int flags)
            while (!(eof = viminfo_readline(&vir))
                    && vir.vir_line[0] != '>')
                ;
+
+       do_copy_marks = (flags &
+                          (VIF_WANT_MARKS | VIF_GET_OLDFILES | VIF_FORCEIT));
     }
+
     if (fp_out != NULL)
     {
        /* Write the info: */
@@ -2209,11 +2214,18 @@ do_viminfo(FILE *fp_in, FILE *fp_out, int flags)
        finish_viminfo_marks();
        write_viminfo_bufferlist(fp_out);
        write_viminfo_barlines(&vir, fp_out);
-       count = write_viminfo_marks(fp_out);
+
+       if (do_copy_marks)
+           ga_init2(&buflist, sizeof(buf_T *), 50);
+       write_viminfo_marks(fp_out, do_copy_marks ? &buflist : NULL);
+    }
+
+    if (do_copy_marks)
+    {
+       copy_viminfo_marks(&vir, fp_out, &buflist, eof, flags);
+       if (fp_out != NULL)
+           ga_clear(&buflist);
     }
-    if (fp_in != NULL
-           && (flags & (VIF_WANT_MARKS | VIF_GET_OLDFILES | VIF_FORCEIT)))
-       copy_viminfo_marks(&vir, fp_out, count, eof, flags);
 
     vim_free(vir.vir_line);
 #ifdef FEAT_MBYTE
@@ -4287,6 +4299,10 @@ do_ecmd(
        msg_scrolled_ign = FALSE;
     }
 
+#ifdef FEAT_VIMINFO
+    curbuf->b_last_used = vim_time();
+#endif
+
     if (command != NULL)
        do_cmdline(command, NULL, NULL, DOCMD_VERBOSE);
 
index dcede31e45c62856583214e8abe96641a4cedad0..42638e4485fbf8801932481abec891d2de540655 100644 (file)
@@ -1272,6 +1272,9 @@ main_loop(
 #ifdef FEAT_TITLE
            if (need_maketitle)
                maketitle();
+#endif
+#ifdef FEAT_VIMINFO
+           curbuf->b_last_used = vim_time();
 #endif
            /* display message after redraw */
            if (keep_msg != NULL)
index 2e8fdd63f97d7f4f2cdcf1068059b7a6971b5c75..1e6b26a7ac76e2b8187068ee191a567159febeb7 100644 (file)
@@ -1799,16 +1799,54 @@ removable(char_u *name)
     return retval;
 }
 
-static void write_one_mark(FILE *fp_out, int c, pos_T *pos);
+    static void
+write_one_mark(FILE *fp_out, int c, pos_T *pos)
+{
+    if (pos->lnum != 0)
+       fprintf(fp_out, "\t%c\t%ld\t%d\n", c, (long)pos->lnum, (int)pos->col);
+}
+
+
+    static void
+write_buffer_marks(buf_T *buf, FILE *fp_out)
+{
+    int                i;
+    pos_T      pos;
+
+    home_replace(NULL, buf->b_ffname, IObuff, IOSIZE, TRUE);
+    fprintf(fp_out, "\n> ");
+    viminfo_writestring(fp_out, IObuff);
+
+    /* Write the last used timestamp as the lnum of the non-existing mark '*'.
+     * Older Vims will ignore it and/or copy it. */
+    pos.lnum = (linenr_T)buf->b_last_used;
+    pos.col = 0;
+    write_one_mark(fp_out, '*', &pos);
+
+    write_one_mark(fp_out, '"', &buf->b_last_cursor);
+    write_one_mark(fp_out, '^', &buf->b_last_insert);
+    write_one_mark(fp_out, '.', &buf->b_last_change);
+#ifdef FEAT_JUMPLIST
+    /* changelist positions are stored oldest first */
+    for (i = 0; i < buf->b_changelistlen; ++i)
+    {
+       /* skip duplicates */
+       if (i == 0 || !equalpos(buf->b_changelist[i - 1], buf->b_changelist[i]))
+           write_one_mark(fp_out, '+', &buf->b_changelist[i]);
+    }
+#endif
+    for (i = 0; i < NMARKS; i++)
+       write_one_mark(fp_out, 'a' + i, &buf->b_namedm[i]);
+}
 
 /*
  * Write all the named marks for all buffers.
- * Return the number of buffers for which marks have been written.
+ * When "buflist" is not NULL fill it with the buffers for which marks are to
+ * be written.
  */
-    int
-write_viminfo_marks(FILE *fp_out)
+    void
+write_viminfo_marks(FILE *fp_out, garray_T *buflist)
 {
-    int                count;
     buf_T      *buf;
     int                is_mark_set;
     int                i;
@@ -1826,7 +1864,6 @@ write_viminfo_marks(FILE *fp_out)
 #endif
 
     fputs(_("\n# History of marks within files (newest to oldest):\n"), fp_out);
-    count = 0;
     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
     {
        /*
@@ -1850,42 +1887,35 @@ write_viminfo_marks(FILE *fp_out)
            if (is_mark_set && buf->b_ffname != NULL
                      && buf->b_ffname[0] != NUL && !removable(buf->b_ffname))
            {
-               home_replace(NULL, buf->b_ffname, IObuff, IOSIZE, TRUE);
-               fprintf(fp_out, "\n> ");
-               viminfo_writestring(fp_out, IObuff);
-               write_one_mark(fp_out, '"', &buf->b_last_cursor);
-               write_one_mark(fp_out, '^', &buf->b_last_insert);
-               write_one_mark(fp_out, '.', &buf->b_last_change);
-#ifdef FEAT_JUMPLIST
-               /* changelist positions are stored oldest first */
-               for (i = 0; i < buf->b_changelistlen; ++i)
-               {
-                   /* skip duplicates */
-                   if (i == 0 || !equalpos(buf->b_changelist[i - 1],
-                                                       buf->b_changelist[i]))
-                       write_one_mark(fp_out, '+', &buf->b_changelist[i]);
-               }
-#endif
-               for (i = 0; i < NMARKS; i++)
-                   write_one_mark(fp_out, 'a' + i, &buf->b_namedm[i]);
-               count++;
+               if (buflist == NULL)
+                   write_buffer_marks(buf, fp_out);
+               else if (ga_grow(buflist, 1) == OK)
+                   ((buf_T **)buflist->ga_data)[buflist->ga_len++] = buf;
            }
        }
     }
-
-    return count;
 }
 
-    static void
-write_one_mark(FILE *fp_out, int c, pos_T *pos)
+/*
+ * Compare functions for qsort() below, that compares b_last_used.
+ */
+    static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+buf_compare(const void *s1, const void *s2)
 {
-    if (pos->lnum != 0)
-       fprintf(fp_out, "\t%c\t%ld\t%d\n", c, (long)pos->lnum, (int)pos->col);
+    buf_T *buf1 = *(buf_T **)s1;
+    buf_T *buf2 = *(buf_T **)s2;
+
+    if (buf1->b_last_used == buf2->b_last_used)
+       return 0;
+    return buf1->b_last_used > buf2->b_last_used ? -1 : 1;
 }
 
 /*
  * Handle marks in the viminfo file:
- * fp_out != NULL: copy marks for buffers not in buffer list
+ * fp_out != NULL: copy marks, in time order with buffers in "buflist".
  * fp_out == NULL && (flags & VIF_WANT_MARKS): read marks for curbuf only
  * fp_out == NULL && (flags & VIF_GET_OLDFILES | VIF_FORCEIT): fill v:oldfiles
  */
@@ -1893,7 +1923,7 @@ write_one_mark(FILE *fp_out, int c, pos_T *pos)
 copy_viminfo_marks(
     vir_T      *virp,
     FILE       *fp_out,
-    int                count,
+    garray_T   *buflist,
     int                eof,
     int                flags)
 {
@@ -1910,11 +1940,22 @@ copy_viminfo_marks(
 #ifdef FEAT_EVAL
     list_T     *list = NULL;
 #endif
+    int                count = 0;
+    int                buflist_used = 0;
+    buf_T      *buflist_buf = NULL;
 
     if ((name_buf = alloc(LSIZE)) == NULL)
        return;
     *name_buf = NUL;
 
+    if (fp_out != NULL && buflist->ga_len > 0)
+    {
+       /* Sort the list of buffers on b_last_used. */
+       qsort(buflist->ga_data, (size_t)buflist->ga_len,
+                                               sizeof(buf_T *), buf_compare);
+       buflist_buf = ((buf_T **)buflist->ga_data)[0];
+    }
+
 #ifdef FEAT_EVAL
     if (fp_out == NULL && (flags & (VIF_GET_OLDFILES | VIF_FORCEIT)))
     {
@@ -1986,14 +2027,70 @@ copy_viminfo_marks(
                }
 
            /*
-            * copy marks if the buffer has not been loaded
+            * Copy marks if the buffer has not been loaded.
             */
            if (buf == NULL || !buf->b_marks_read)
            {
-               copy_marks_out = TRUE;
+               int     did_read_line = FALSE;
+
+               if (buflist_buf != NULL)
+               {
+                   /* Read the next line.  If it has the "*" mark compare the
+                    * time stamps.  Write entries from "buflist" that are
+                    * newer. */
+                   if (!(eof = viminfo_readline(virp)) && line[0] == TAB)
+                   {
+                       did_read_line = TRUE;
+                       if (line[1] == '*')
+                       {
+                           long        ltime;
+
+                           sscanf((char *)line + 2, "%ld ", &ltime);
+                           while ((time_T)ltime < buflist_buf->b_last_used)
+                           {
+                               write_buffer_marks(buflist_buf, fp_out);
+                               if (++count >= num_marked_files)
+                                   break;
+                               if (++buflist_used == buflist->ga_len)
+                               {
+                                   buflist_buf = NULL;
+                                   break;
+                               }
+                               buflist_buf =
+                                  ((buf_T **)buflist->ga_data)[buflist_used];
+                           }
+                       }
+                       else
+                       {
+                           /* No timestamp, must be written by an older Vim.
+                            * Assume all remaining buffers are older then
+                            * ours.  */
+                           while (count < num_marked_files
+                                           && buflist_used < buflist->ga_len)
+                           {
+                               buflist_buf = ((buf_T **)buflist->ga_data)
+                                                            [buflist_used++];
+                               write_buffer_marks(buflist_buf, fp_out);
+                               ++count;
+                           }
+                           buflist_buf = NULL;
+                       }
+
+                       if (count >= num_marked_files)
+                       {
+                           vim_free(str);
+                           break;
+                       }
+                   }
+               }
+
                fputs("\n> ", fp_out);
                viminfo_writestring(fp_out, str);
+               if (did_read_line)
+                   fputs((char *)line, fp_out);
+
                count++;
+               copy_marks_out = TRUE;
            }
        }
        vim_free(str);
@@ -2031,6 +2128,11 @@ copy_viminfo_marks(
                                           curbuf->b_changelistlen - 1] = pos;
 #endif
                                  break;
+
+                                 /* Using the line number for the last-used
+                                  * timestamp. */
+                       case '*': curbuf->b_last_used = pos.lnum; break;
+
                        default:  if ((i = line[1] - 'a') >= 0 && i < NMARKS)
                                      curbuf->b_namedm[i] = pos;
                    }
@@ -2039,6 +2141,7 @@ copy_viminfo_marks(
            else if (copy_marks_out)
                fputs((char *)line, fp_out);
        }
+
        if (load_marks)
        {
 #ifdef FEAT_JUMPLIST
@@ -2053,6 +2156,16 @@ copy_viminfo_marks(
            break;
        }
     }
+
+    if (fp_out != NULL)
+       /* Write any remaining entries from buflist. */
+       while (count < num_marked_files && buflist_used < buflist->ga_len)
+       {
+           buflist_buf = ((buf_T **)buflist->ga_data)[buflist_used++];
+           write_buffer_marks(buflist_buf, fp_out);
+           ++count;
+       }
+
     vim_free(name_buf);
 }
 #endif /* FEAT_VIMINFO */
index f24c0355ebd91536badae6c03295ebff6ac33bad..90be1a566ee5d99523f4028bfaa1381182cfae95 100644 (file)
@@ -30,6 +30,6 @@ void finish_viminfo_marks(void);
 void handle_viminfo_mark(garray_T *values, int force);
 void write_viminfo_filemarks(FILE *fp);
 int removable(char_u *name);
-int write_viminfo_marks(FILE *fp_out);
-void copy_viminfo_marks(vir_T *virp, FILE *fp_out, int count, int eof, int flags);
+void write_viminfo_marks(FILE *fp_out, garray_T *buflist);
+void copy_viminfo_marks(vir_T *virp, FILE *fp_out, garray_T *buflist, int eof, int flags);
 /* vim: set ft=c : */
index 9d19c3c89f856164053f2ca88d02f3d72db92f71..05f4617059efeecab39d359c527f1694dd05f5e6 100644 (file)
@@ -1771,6 +1771,10 @@ struct file_buffer
     long       b_mtime_read;   /* last change time when reading */
     off_T      b_orig_size;    /* size of original file in bytes */
     int                b_orig_mode;    /* mode of original file */
+#ifdef FEAT_VIMINFO
+    time_T     b_last_used;    /* time when the buffer was last used; used
+                                * for viminfo */
+#endif
 
     pos_T      b_namedm[NMARKS]; /* current named marks (mark.c) */
 
index 76b24403b34be76f9934dbd25e444dcb5f696fdb..4c4935b92e52b0bfed53f5a9a930494d7de7846c 100644 (file)
@@ -395,3 +395,33 @@ func Test_viminfo_bad_syntax()
   call delete('Xviminfo')
 endfunc
 
+func Test_viminfo_file_marks()
+  silent! bwipe test_viminfo.vim
+  silent! bwipe Xviminfo
+
+  call test_settime(10)
+  edit ten
+  call test_settime(25)
+  edit again
+  call test_settime(30)
+  edit thirty
+  wviminfo Xviminfo
+
+  call test_settime(20)
+  edit twenty
+  call test_settime(35)
+  edit again
+  call test_settime(40)
+  edit fourty
+  wviminfo Xviminfo
+
+  sp Xviminfo
+  1
+  for name in ['fourty', 'again', 'thirty', 'twenty', 'ten']
+    /^>
+    call assert_equal(name, substitute(getline('.'), '.*/', '', ''))
+  endfor
+  close
+
+  call delete('Xviminfo')
+endfunc
index 0a720cd1efb6174838a7ae1a66e2d3b0cd8f336c..a89b83e1c556bd7311dcf574218e306f02a6541a 100644 (file)
@@ -758,6 +758,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1988,
 /**/
     1987,
 /**/