]> granicus.if.org Git - vim/commitdiff
patch 7.4.1911 v7.4.1911
authorBram Moolenaar <Bram@vim.org>
Thu, 9 Jun 2016 18:24:28 +0000 (20:24 +0200)
committerBram Moolenaar <Bram@vim.org>
Thu, 9 Jun 2016 18:24:28 +0000 (20:24 +0200)
Problem:    Recent history lines may be lost when exiting Vim.
Solution:   Merge history using the timestamp.

src/ex_cmds.c
src/ex_getln.c
src/proto/ex_getln.pro
src/testdir/test_viminfo.vim
src/version.c
src/vim.h

index 62b39a2d898a95553caaa5ebcb581f198aa0aa08..2c7742eab88172c906b95446be8d703b8155fbcf 100644 (file)
@@ -1755,9 +1755,6 @@ static void write_viminfo_version(FILE *fp_out);
 static void write_viminfo_barlines(vir_T *virp, FILE *fp_out);
 static int  viminfo_errcnt;
 
-#define VIMINFO_VERSION 2
-#define VIMINFO_VERSION_WITH_HISTORY 2
-
     static int
 no_viminfo(void)
 {
@@ -2306,7 +2303,7 @@ read_viminfo_up_to_marks(
 #ifdef FEAT_CMDHIST
     /* Finish reading history items. */
     if (!writing)
-       finish_viminfo_history();
+       finish_viminfo_history(virp);
 #endif
 
     /* Change file names to buffer numbers for fmarks. */
index e0d5226b1956a74f3c99c84d02b0d56509fb3872..87aed90b06cffd88f7a5c399a0c149c5f88dc3ce 100644 (file)
@@ -5536,6 +5536,7 @@ clear_hist_entry(histentry_T *hisptr)
     hisptr->hisnum = 0;
     hisptr->viminfo = FALSE;
     hisptr->hisstr = NULL;
+    hisptr->time_set = 0;
 }
 
 /*
@@ -6262,6 +6263,8 @@ read_viminfo_history(vir_T *virp, int writing)
                    }
                    viminfo_history[type][viminfo_hisidx[type]].hisstr = p;
                    viminfo_history[type][viminfo_hisidx[type]].time_set = 0;
+                   viminfo_history[type][viminfo_hisidx[type]].viminfo = TRUE;
+                   viminfo_history[type][viminfo_hisidx[type]].hisnum = 0;
                    viminfo_hisidx[type]++;
                }
            }
@@ -6338,6 +6341,8 @@ handle_viminfo_history(
                        /* Put the separator after the NUL. */
                        p[len + 1] = sep;
                        viminfo_history[type][idx].hisstr = p;
+                       viminfo_history[type][idx].hisnum = 0;
+                       viminfo_history[type][idx].viminfo = TRUE;
                        viminfo_hisidx[type]++;
                    }
                }
@@ -6347,57 +6352,146 @@ handle_viminfo_history(
 }
 
 /*
- * Finish reading history lines from viminfo.  Not used when writing viminfo.
+ * Concatenate history lines from viminfo after the lines typed in this Vim.
  */
-    void
-finish_viminfo_history(void)
+    static void
+concat_history(int type)
 {
     int idx;
     int i;
+
+    idx = hisidx[type] + viminfo_hisidx[type];
+    if (idx >= hislen)
+       idx -= hislen;
+    else if (idx < 0)
+       idx = hislen - 1;
+    if (viminfo_add_at_front)
+       hisidx[type] = idx;
+    else
+    {
+       if (hisidx[type] == -1)
+           hisidx[type] = hislen - 1;
+       do
+       {
+           if (history[type][idx].hisstr != NULL
+                                           || history[type][idx].viminfo)
+               break;
+           if (++idx == hislen)
+               idx = 0;
+       } while (idx != hisidx[type]);
+       if (idx != hisidx[type] && --idx < 0)
+           idx = hislen - 1;
+    }
+    for (i = 0; i < viminfo_hisidx[type]; i++)
+    {
+       vim_free(history[type][idx].hisstr);
+       history[type][idx].hisstr = viminfo_history[type][i].hisstr;
+       history[type][idx].viminfo = TRUE;
+       history[type][idx].time_set = viminfo_history[type][i].time_set;
+       if (--idx < 0)
+           idx = hislen - 1;
+    }
+    idx += 1;
+    idx %= hislen;
+    for (i = 0; i < viminfo_hisidx[type]; i++)
+    {
+       history[type][idx++].hisnum = ++hisnum[type];
+       idx %= hislen;
+    }
+}
+
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+    static int
+#ifdef __BORLANDC__
+_RTLENTRYF
+#endif
+sort_hist(const void *s1, const void *s2)
+{
+    histentry_T *p1 = *(histentry_T **)s1;
+    histentry_T *p2 = *(histentry_T **)s2;
+
+    if (p1->time_set < p2->time_set) return -1;
+    if (p1->time_set > p2->time_set) return 1;
+    return 0;
+}
+#endif
+
+/*
+ * Merge history lines from viminfo and lines typed in this Vim based on the
+ * timestamp;
+ */
+    static void
+merge_history(int type)
+{
+    int                max_len;
+    histentry_T **tot_hist;
+    histentry_T *new_hist;
+    int                i;
+    int                len;
+
+    /* Make one long list with all entries. */
+    max_len = hislen + viminfo_hisidx[type];
+    tot_hist = (histentry_T **)alloc(max_len * (int)sizeof(histentry_T *));
+    new_hist = (histentry_T *)alloc(hislen * (int)sizeof(histentry_T));
+    if (tot_hist == NULL || new_hist == NULL)
+    {
+       vim_free(tot_hist);
+       vim_free(new_hist);
+       return;
+    }
+    for (i = 0; i < viminfo_hisidx[type]; i++)
+       tot_hist[i] = &viminfo_history[type][i];
+    len = i;
+    for (i = 0; i < hislen; i++)
+       if (history[type][i].hisstr != NULL)
+           tot_hist[len++] = &history[type][i];
+
+    /* Sort the list on timestamp. */
+    qsort((void *)tot_hist, (size_t)len, sizeof(histentry_T *), sort_hist);
+
+    /* Keep the newest ones. */
+    for (i = 0; i < hislen; i++)
+    {
+       if (i < len)
+       {
+           new_hist[i] = *tot_hist[i];
+           tot_hist[i]->hisstr = NULL;
+           if (new_hist[i].hisnum == 0)
+               new_hist[i].hisnum = ++hisnum[type];
+       }
+       else
+           clear_hist_entry(&new_hist[i]);
+    }
+    hisidx[type] = len - 1;
+
+    /* Free what is not kept. */
+    for (i = 0; i < viminfo_hisidx[type]; i++)
+       vim_free(viminfo_history[type][i].hisstr);
+    for (i = 0; i < hislen; i++)
+       vim_free(history[type][i].hisstr);
+    vim_free(history[type]);
+    history[type] = new_hist;
+}
+
+/*
+ * Finish reading history lines from viminfo.  Not used when writing viminfo.
+ */
+    void
+finish_viminfo_history(vir_T *virp)
+{
     int        type;
+    int merge = virp->vir_version >= VIMINFO_VERSION_WITH_HISTORY;
 
     for (type = 0; type < HIST_COUNT; ++type)
     {
        if (history[type] == NULL)
            continue;
-       idx = hisidx[type] + viminfo_hisidx[type];
-       if (idx >= hislen)
-           idx -= hislen;
-       else if (idx < 0)
-           idx = hislen - 1;
-       if (viminfo_add_at_front)
-           hisidx[type] = idx;
+
+       if (merge)
+           merge_history(type);
        else
-       {
-           if (hisidx[type] == -1)
-               hisidx[type] = hislen - 1;
-           do
-           {
-               if (history[type][idx].hisstr != NULL
-                                               || history[type][idx].viminfo)
-                   break;
-               if (++idx == hislen)
-                   idx = 0;
-           } while (idx != hisidx[type]);
-           if (idx != hisidx[type] && --idx < 0)
-               idx = hislen - 1;
-       }
-       for (i = 0; i < viminfo_hisidx[type]; i++)
-       {
-           vim_free(history[type][idx].hisstr);
-           history[type][idx].hisstr = viminfo_history[type][i].hisstr;
-           history[type][idx].viminfo = TRUE;
-           history[type][idx].time_set = viminfo_history[type][i].time_set;
-           if (--idx < 0)
-               idx = hislen - 1;
-       }
-       idx += 1;
-       idx %= hislen;
-       for (i = 0; i < viminfo_hisidx[type]; i++)
-       {
-           history[type][idx++].hisnum = ++hisnum[type];
-           idx %= hislen;
-       }
+           concat_history(type);
+
        vim_free(viminfo_history[type]);
        viminfo_history[type] = NULL;
        viminfo_hisidx[type] = 0;
index 83a0c5f1c5ac23548ff70242e85c85bd5e77e79a..873787781975a8986c767a5aaddb77cd8ddb9e3c 100644 (file)
@@ -51,7 +51,7 @@ void ex_history(exarg_T *eap);
 void prepare_viminfo_history(int asklen, int writing);
 int read_viminfo_history(vir_T *virp, int writing);
 void handle_viminfo_history(bval_T *values, int count, int writing);
-void finish_viminfo_history(void);
+void finish_viminfo_history(vir_T *virp);
 void write_viminfo_history(FILE *fp, int merge);
 void cmd_pchar(int c, int offset);
 int cmd_gchar(int offset);
index 9c2acf0c953267f6c622e3ef7bd368d7fb6055db..279b1c3d18ff0629e9daea0c6a217614e599c1aa 100644 (file)
@@ -116,3 +116,66 @@ func Test_cmdline_history()
 
   call delete('Xviminfo')
 endfunc
+
+func Test_cmdline_history_order()
+  call histdel(':')
+  call test_settime(11)
+  call histadd(':', "echo '11'")
+  call test_settime(22)
+  call histadd(':', "echo '22'")
+  call test_settime(33)
+  call histadd(':', "echo '33'")
+  wviminfo Xviminfo
+
+  call histdel(':')
+  " items go in between
+  call test_settime(15)
+  call histadd(':', "echo '15'")
+  call test_settime(27)
+  call histadd(':', "echo '27'")
+
+  rviminfo Xviminfo
+  call assert_equal("echo '33'", histget(':', -1))
+  call assert_equal("echo '27'", histget(':', -2))
+  call assert_equal("echo '22'", histget(':', -3))
+  call assert_equal("echo '15'", histget(':', -4))
+  call assert_equal("echo '11'", histget(':', -5))
+
+  call histdel(':')
+  " items go before and after
+  call test_settime(8)
+  call histadd(':', "echo '8'")
+  call test_settime(39)
+  call histadd(':', "echo '39'")
+
+  rviminfo Xviminfo
+  call assert_equal("echo '39'", histget(':', -1))
+  call assert_equal("echo '33'", histget(':', -2))
+  call assert_equal("echo '22'", histget(':', -3))
+  call assert_equal("echo '11'", histget(':', -4))
+  call assert_equal("echo '8'", histget(':', -5))
+
+  " Check sorting works when writing with merge.
+  call histdel(':')
+  call test_settime(8)
+  call histadd(':', "echo '8'")
+  call test_settime(15)
+  call histadd(':', "echo '15'")
+  call test_settime(27)
+  call histadd(':', "echo '27'")
+  call test_settime(39)
+  call histadd(':', "echo '39'")
+  wviminfo Xviminfo
+  
+  call histdel(':')
+  rviminfo Xviminfo
+  call assert_equal("echo '39'", histget(':', -1))
+  call assert_equal("echo '33'", histget(':', -2))
+  call assert_equal("echo '27'", histget(':', -3))
+  call assert_equal("echo '22'", histget(':', -4))
+  call assert_equal("echo '15'", histget(':', -5))
+  call assert_equal("echo '11'", histget(':', -6))
+  call assert_equal("echo '8'", histget(':', -7))
+
+  call delete('Xviminfo')
+endfunc
index ad79efff1bea084e363363215e133c78fa82f0f1..42e178713da2b6982421a89b9dd48672bb09b6c9 100644 (file)
@@ -753,6 +753,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1911,
 /**/
     1910,
 /**/
index 33ed941ca049686c0c7b1dd1fde49e60f5d29c01..4615f070f2d02c45ec486f4a23fed13b14555009 100644 (file)
--- a/src/vim.h
+++ b/src/vim.h
@@ -1076,6 +1076,9 @@ extern char *(*dyn_libintl_textdomain)(const char *domainname);
 #define BARTYPE_VERSION 1
 #define BARTYPE_HISTORY 2
 
+#define VIMINFO_VERSION 2
+#define VIMINFO_VERSION_WITH_HISTORY 2
+
 typedef enum {
     BVAL_NR,
     BVAL_STRING,