summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-06-09 20:24:28 +0200
committerBram Moolenaar <Bram@vim.org>2016-06-09 20:24:28 +0200
commit1fd99c1ca89a3d13bb53aff4a5a8f5ee740713e5 (patch)
tree756a88225b31fe0bef957aa4c262de47e241416f
parentabc70bbf363dbbe3f2bf714102f55648a512791e (diff)
patch 7.4.1911v7.4.1911
Problem: Recent history lines may be lost when exiting Vim. Solution: Merge history using the timestamp.
-rw-r--r--src/ex_cmds.c5
-rw-r--r--src/ex_getln.c174
-rw-r--r--src/proto/ex_getln.pro2
-rw-r--r--src/testdir/test_viminfo.vim63
-rw-r--r--src/version.c2
-rw-r--r--src/vim.h3
6 files changed, 204 insertions, 45 deletions
diff --git a/src/ex_cmds.c b/src/ex_cmds.c
index 62b39a2d89..2c7742eab8 100644
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -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. */
diff --git a/src/ex_getln.c b/src/ex_getln.c
index e0d5226b19..87aed90b06 100644
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -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;
diff --git a/src/proto/ex_getln.pro b/src/proto/ex_getln.pro
index 83a0c5f1c5..8737877819 100644
--- a/src/proto/ex_getln.pro
+++ b/src/proto/ex_getln.pro
@@ -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);
diff --git a/src/testdir/test_viminfo.vim b/src/testdir/test_viminfo.vim
index 9c2acf0c95..279b1c3d18 100644
--- a/src/testdir/test_viminfo.vim
+++ b/src/testdir/test_viminfo.vim
@@ -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
diff --git a/src/version.c b/src/version.c
index ad79efff1b..42e178713d 100644
--- a/src/version.c
+++ b/src/version.c
@@ -754,6 +754,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1911,
+/**/
1910,
/**/
1909,
diff --git a/src/vim.h b/src/vim.h
index 33ed941ca0..4615f070f2 100644
--- 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,