1
0
forked from aniani/vim

patch 7.4.1911

Problem:    Recent history lines may be lost when exiting Vim.
Solution:   Merge history using the timestamp.
This commit is contained in:
Bram Moolenaar 2016-06-09 20:24:28 +02:00
parent abc70bbf36
commit 1fd99c1ca8
6 changed files with 204 additions and 45 deletions

View 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. */

View 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;

View 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);

View 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

View File

@ -753,6 +753,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1911,
/**/
1910,
/**/

View File

@ -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,