0
0
mirror of https://github.com/vim/vim.git synced 2025-07-26 11:04:33 -04:00

patch 8.1.1728: wrong place for command line history viminfo support

Problem:    Wrong place for command line history viminfo support.
Solution:   Move it to viminfo.c.
This commit is contained in:
Bram Moolenaar 2019-07-21 21:51:59 +02:00
parent defa067c54
commit 5f32ece459
5 changed files with 527 additions and 479 deletions

View File

@ -60,21 +60,11 @@ static int extra_char = NUL; /* extra character to display when redrawing
static int extra_char_shift;
#ifdef FEAT_CMDHIST
typedef struct hist_entry
{
int hisnum; /* identifying number */
int viminfo; /* when TRUE hisstr comes from viminfo */
char_u *hisstr; /* actual entry, separator char after the NUL */
time_t time_set; /* when it was typed, zero if unknown */
} histentry_T;
static histentry_T *(history[HIST_COUNT]) = {NULL, NULL, NULL, NULL, NULL};
static int hisidx[HIST_COUNT] = {-1, -1, -1, -1, -1}; /* lastused entry */
static int hisnum[HIST_COUNT] = {0, 0, 0, 0, 0};
/* identifying (unique) number of newest history entry */
static int hislen = 0; /* actual length of history tables */
static int hist_char2type(int c);
#endif
#ifdef FEAT_RIGHTLEFT
@ -116,9 +106,6 @@ static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file,
static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file);
# endif
#endif
#ifdef FEAT_CMDHIST
static void clear_hist_entry(histentry_T *hisptr);
#endif
#ifdef FEAT_CMDWIN
static int open_cmdwin(void);
@ -5873,7 +5860,7 @@ globpath(
/*
* Translate a history character to the associated type number.
*/
static int
int
hist_char2type(int c)
{
if (c == ':')
@ -6010,7 +5997,7 @@ init_history(void)
}
}
static void
void
clear_hist_entry(histentry_T *hisptr)
{
hisptr->hisnum = 0;
@ -6023,7 +6010,7 @@ clear_hist_entry(histentry_T *hisptr)
* Check if command line 'str' is already in history.
* If 'move_to_front' is TRUE, matching entry is moved to end of history.
*/
static int
int
in_history(
int type,
char_u *str,
@ -6629,479 +6616,37 @@ ex_history(exarg_T *eap)
#endif
#if (defined(FEAT_VIMINFO) && defined(FEAT_CMDHIST)) || defined(PROTO)
/*
* Buffers for history read from a viminfo file. Only valid while reading.
*/
static histentry_T *viminfo_history[HIST_COUNT] =
{NULL, NULL, NULL, NULL, NULL};
static int viminfo_hisidx[HIST_COUNT] = {0, 0, 0, 0, 0};
static int viminfo_hislen[HIST_COUNT] = {0, 0, 0, 0, 0};
static int viminfo_add_at_front = FALSE;
/*
* Translate a history type number to the associated character.
*/
static int
hist_type2char(
int type,
int use_question) /* use '?' instead of '/' */
{
if (type == HIST_CMD)
return ':';
if (type == HIST_SEARCH)
{
if (use_question)
return '?';
else
return '/';
}
if (type == HIST_EXPR)
return '=';
return '@';
}
/*
* Prepare for reading the history from the viminfo file.
* This allocates history arrays to store the read history lines.
*/
void
prepare_viminfo_history(int asklen, int writing)
{
int i;
int num;
int type;
int len;
init_history();
viminfo_add_at_front = (asklen != 0 && !writing);
if (asklen > hislen)
asklen = hislen;
for (type = 0; type < HIST_COUNT; ++type)
{
/* Count the number of empty spaces in the history list. Entries read
* from viminfo previously are also considered empty. If there are
* more spaces available than we request, then fill them up. */
for (i = 0, num = 0; i < hislen; i++)
if (history[type][i].hisstr == NULL || history[type][i].viminfo)
num++;
len = asklen;
if (num > len)
len = num;
if (len <= 0)
viminfo_history[type] = NULL;
else
viminfo_history[type] = LALLOC_MULT(histentry_T, len);
if (viminfo_history[type] == NULL)
len = 0;
viminfo_hislen[type] = len;
viminfo_hisidx[type] = 0;
}
}
/*
* Accept a line from the viminfo, store it in the history array when it's
* new.
*/
int
read_viminfo_history(vir_T *virp, int writing)
get_hislen(void)
{
int type;
long_u len;
char_u *val;
char_u *p;
type = hist_char2type(virp->vir_line[0]);
if (viminfo_hisidx[type] < viminfo_hislen[type])
{
val = viminfo_readstring(virp, 1, TRUE);
if (val != NULL && *val != NUL)
{
int sep = (*val == ' ' ? NUL : *val);
if (!in_history(type, val + (type == HIST_SEARCH),
viminfo_add_at_front, sep, writing))
{
/* Need to re-allocate to append the separator byte. */
len = STRLEN(val);
p = alloc(len + 2);
if (p != NULL)
{
if (type == HIST_SEARCH)
{
/* Search entry: Move the separator from the first
* column to after the NUL. */
mch_memmove(p, val + 1, (size_t)len);
p[len] = sep;
}
else
{
/* Not a search entry: No separator in the viminfo
* file, add a NUL separator. */
mch_memmove(p, val, (size_t)len + 1);
p[len + 1] = NUL;
}
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]++;
}
}
}
vim_free(val);
}
return viminfo_readline(virp);
return hislen;
}
histentry_T *
get_histentry(int hist_type)
{
return history[hist_type];
}
/*
* Accept a new style history line from the viminfo, store it in the history
* array when it's new.
*/
void
handle_viminfo_history(
garray_T *values,
int writing)
set_histentry(int hist_type, histentry_T *entry)
{
int type;
long_u len;
char_u *val;
char_u *p;
bval_T *vp = (bval_T *)values->ga_data;
/* Check the format:
* |{bartype},{histtype},{timestamp},{separator},"text" */
if (values->ga_len < 4
|| vp[0].bv_type != BVAL_NR
|| vp[1].bv_type != BVAL_NR
|| (vp[2].bv_type != BVAL_NR && vp[2].bv_type != BVAL_EMPTY)
|| vp[3].bv_type != BVAL_STRING)
return;
type = vp[0].bv_nr;
if (type >= HIST_COUNT)
return;
if (viminfo_hisidx[type] < viminfo_hislen[type])
{
val = vp[3].bv_string;
if (val != NULL && *val != NUL)
{
int sep = type == HIST_SEARCH && vp[2].bv_type == BVAL_NR
? vp[2].bv_nr : NUL;
int idx;
int overwrite = FALSE;
if (!in_history(type, val, viminfo_add_at_front, sep, writing))
{
/* If lines were written by an older Vim we need to avoid
* getting duplicates. See if the entry already exists. */
for (idx = 0; idx < viminfo_hisidx[type]; ++idx)
{
p = viminfo_history[type][idx].hisstr;
if (STRCMP(val, p) == 0
&& (type != HIST_SEARCH || sep == p[STRLEN(p) + 1]))
{
overwrite = TRUE;
break;
}
}
if (!overwrite)
{
/* Need to re-allocate to append the separator byte. */
len = vp[3].bv_len;
p = alloc(len + 2);
}
else
len = 0; /* for picky compilers */
if (p != NULL)
{
viminfo_history[type][idx].time_set = vp[1].bv_nr;
if (!overwrite)
{
mch_memmove(p, val, (size_t)len + 1);
/* 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]++;
}
}
}
}
}
history[hist_type] = entry;
}
/*
* Concatenate history lines from viminfo after the lines typed in this Vim.
*/
static void
concat_history(int type)
int *
get_hisidx(int hist_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;
}
return &hisidx[hist_type];
}
#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
static int
sort_hist(const void *s1, const void *s2)
int *
get_hisnum(int hist_type)
{
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;
return &hisnum[hist_type];
}
#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 = ALLOC_MULT(histentry_T *, max_len);
new_hist = ALLOC_MULT(histentry_T, hislen );
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] = (i < len ? i : 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;
vim_free(tot_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;
if (merge)
merge_history(type);
else
concat_history(type);
VIM_CLEAR(viminfo_history[type]);
viminfo_hisidx[type] = 0;
}
}
/*
* Write history to viminfo file in "fp".
* When "merge" is TRUE merge history lines with a previously read viminfo
* file, data is in viminfo_history[].
* When "merge" is FALSE just write all history lines. Used for ":wviminfo!".
*/
void
write_viminfo_history(FILE *fp, int merge)
{
int i;
int type;
int num_saved;
int round;
init_history();
if (hislen == 0)
return;
for (type = 0; type < HIST_COUNT; ++type)
{
num_saved = get_viminfo_parameter(hist_type2char(type, FALSE));
if (num_saved == 0)
continue;
if (num_saved < 0) /* Use default */
num_saved = hislen;
fprintf(fp, _("\n# %s History (newest to oldest):\n"),
type == HIST_CMD ? _("Command Line") :
type == HIST_SEARCH ? _("Search String") :
type == HIST_EXPR ? _("Expression") :
type == HIST_INPUT ? _("Input Line") :
_("Debug Line"));
if (num_saved > hislen)
num_saved = hislen;
/*
* Merge typed and viminfo history:
* round 1: history of typed commands.
* round 2: history from recently read viminfo.
*/
for (round = 1; round <= 2; ++round)
{
if (round == 1)
/* start at newest entry, somewhere in the list */
i = hisidx[type];
else if (viminfo_hisidx[type] > 0)
/* start at newest entry, first in the list */
i = 0;
else
/* empty list */
i = -1;
if (i >= 0)
while (num_saved > 0
&& !(round == 2 && i >= viminfo_hisidx[type]))
{
char_u *p;
time_t timestamp;
int c = NUL;
if (round == 1)
{
p = history[type][i].hisstr;
timestamp = history[type][i].time_set;
}
else
{
p = viminfo_history[type] == NULL ? NULL
: viminfo_history[type][i].hisstr;
timestamp = viminfo_history[type] == NULL ? 0
: viminfo_history[type][i].time_set;
}
if (p != NULL && (round == 2
|| !merge
|| !history[type][i].viminfo))
{
--num_saved;
fputc(hist_type2char(type, TRUE), fp);
/* For the search history: put the separator in the
* second column; use a space if there isn't one. */
if (type == HIST_SEARCH)
{
c = p[STRLEN(p) + 1];
putc(c == NUL ? ' ' : c, fp);
}
viminfo_writestring(fp, p);
{
char cbuf[NUMBUFLEN];
/* New style history with a bar line. Format:
* |{bartype},{histtype},{timestamp},{separator},"text" */
if (c == NUL)
cbuf[0] = NUL;
else
sprintf(cbuf, "%d", c);
fprintf(fp, "|%d,%d,%ld,%s,", BARTYPE_HISTORY,
type, (long)timestamp, cbuf);
barline_writestring(fp, p, LSIZE - 20);
putc('\n', fp);
}
}
if (round == 1)
{
/* Decrement index, loop around and stop when back at
* the start. */
if (--i < 0)
i = hislen - 1;
if (i == hisidx[type])
break;
}
else
{
/* Increment index. Stop at the end in the while. */
++i;
}
}
}
for (i = 0; i < viminfo_hisidx[type]; ++i)
if (viminfo_history[type] != NULL)
vim_free(viminfo_history[type][i].hisstr);
VIM_CLEAR(viminfo_history[type]);
viminfo_hisidx[type] = 0;
}
}
#endif /* FEAT_VIMINFO */
#if defined(FEAT_CMDWIN) || defined(PROTO)
/*
* Open a window on the current command line and history. Allow editing in

View File

@ -34,7 +34,10 @@ void set_cmd_context(expand_T *xp, char_u *str, int len, int col, int use_ccline
int expand_cmdline(expand_T *xp, char_u *str, int col, int *matchcount, char_u ***matches);
int ExpandGeneric(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file, char_u *((*func)(expand_T *, int)), int escaped);
void globpath(char_u *path, char_u *file, garray_T *ga, int expand_options);
int hist_char2type(int c);
void init_history(void);
void clear_hist_entry(histentry_T *hisptr);
int in_history(int type, char_u *str, int move_to_front, int sep, int writing);
int get_histtype(char_u *name);
void add_to_history(int histype, char_u *new_entry, int in_map, int sep);
int get_history_idx(int histype);
@ -49,10 +52,10 @@ int set_cmdline_pos(int pos);
int get_cmdline_type(void);
int get_list_range(char_u **str, int *num1, int *num2);
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(garray_T *values, int writing);
void finish_viminfo_history(vir_T *virp);
void write_viminfo_history(FILE *fp, int merge);
int get_hislen(void);
histentry_T *get_histentry(int hist_type);
void set_histentry(int hist_type, histentry_T *entry);
int *get_hisidx(int hist_type);
int *get_hisnum(int hist_type);
char_u *script_get(exarg_T *eap, char_u *cmd);
/* vim: set ft=c : */

View File

@ -1115,6 +1115,17 @@ typedef struct
garray_T vir_barlines; // lines starting with |
} vir_T;
/*
* Structure used for the command line history.
*/
typedef struct hist_entry
{
int hisnum; /* identifying number */
int viminfo; /* when TRUE hisstr comes from viminfo */
char_u *hisstr; /* actual entry, separator char after the NUL */
time_t time_set; /* when it was typed, zero if unknown */
} histentry_T;
#define CONV_NONE 0
#define CONV_TO_UTF8 1
#define CONV_9_TO_UTF8 2

View File

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

View File

@ -169,6 +169,493 @@ write_viminfo_bufferlist(FILE *fp)
vim_free(line);
}
#if defined(FEAT_CMDHIST) || defined(PROTO)
/*
* Buffers for history read from a viminfo file. Only valid while reading.
*/
static histentry_T *viminfo_history[HIST_COUNT] =
{NULL, NULL, NULL, NULL, NULL};
static int viminfo_hisidx[HIST_COUNT] = {0, 0, 0, 0, 0};
static int viminfo_hislen[HIST_COUNT] = {0, 0, 0, 0, 0};
static int viminfo_add_at_front = FALSE;
/*
* Translate a history type number to the associated character.
*/
static int
hist_type2char(
int type,
int use_question) // use '?' instead of '/'
{
if (type == HIST_CMD)
return ':';
if (type == HIST_SEARCH)
{
if (use_question)
return '?';
else
return '/';
}
if (type == HIST_EXPR)
return '=';
return '@';
}
/*
* Prepare for reading the history from the viminfo file.
* This allocates history arrays to store the read history lines.
*/
static void
prepare_viminfo_history(int asklen, int writing)
{
int i;
int num;
int type;
int len;
int hislen = get_hislen();
init_history();
viminfo_add_at_front = (asklen != 0 && !writing);
if (asklen > hislen)
asklen = hislen;
for (type = 0; type < HIST_COUNT; ++type)
{
histentry_T *histentry = get_histentry(type);
// Count the number of empty spaces in the history list. Entries read
// from viminfo previously are also considered empty. If there are
// more spaces available than we request, then fill them up.
for (i = 0, num = 0; i < hislen; i++)
if (histentry[i].hisstr == NULL || histentry[i].viminfo)
num++;
len = asklen;
if (num > len)
len = num;
if (len <= 0)
viminfo_history[type] = NULL;
else
viminfo_history[type] = LALLOC_MULT(histentry_T, len);
if (viminfo_history[type] == NULL)
len = 0;
viminfo_hislen[type] = len;
viminfo_hisidx[type] = 0;
}
}
/*
* Accept a line from the viminfo, store it in the history array when it's
* new.
*/
static int
read_viminfo_history(vir_T *virp, int writing)
{
int type;
long_u len;
char_u *val;
char_u *p;
type = hist_char2type(virp->vir_line[0]);
if (viminfo_hisidx[type] < viminfo_hislen[type])
{
val = viminfo_readstring(virp, 1, TRUE);
if (val != NULL && *val != NUL)
{
int sep = (*val == ' ' ? NUL : *val);
if (!in_history(type, val + (type == HIST_SEARCH),
viminfo_add_at_front, sep, writing))
{
// Need to re-allocate to append the separator byte.
len = STRLEN(val);
p = alloc(len + 2);
if (p != NULL)
{
if (type == HIST_SEARCH)
{
// Search entry: Move the separator from the first
// column to after the NUL.
mch_memmove(p, val + 1, (size_t)len);
p[len] = sep;
}
else
{
// Not a search entry: No separator in the viminfo
// file, add a NUL separator.
mch_memmove(p, val, (size_t)len + 1);
p[len + 1] = NUL;
}
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]++;
}
}
}
vim_free(val);
}
return viminfo_readline(virp);
}
/*
* Accept a new style history line from the viminfo, store it in the history
* array when it's new.
*/
static void
handle_viminfo_history(
garray_T *values,
int writing)
{
int type;
long_u len;
char_u *val;
char_u *p;
bval_T *vp = (bval_T *)values->ga_data;
// Check the format:
// |{bartype},{histtype},{timestamp},{separator},"text"
if (values->ga_len < 4
|| vp[0].bv_type != BVAL_NR
|| vp[1].bv_type != BVAL_NR
|| (vp[2].bv_type != BVAL_NR && vp[2].bv_type != BVAL_EMPTY)
|| vp[3].bv_type != BVAL_STRING)
return;
type = vp[0].bv_nr;
if (type >= HIST_COUNT)
return;
if (viminfo_hisidx[type] < viminfo_hislen[type])
{
val = vp[3].bv_string;
if (val != NULL && *val != NUL)
{
int sep = type == HIST_SEARCH && vp[2].bv_type == BVAL_NR
? vp[2].bv_nr : NUL;
int idx;
int overwrite = FALSE;
if (!in_history(type, val, viminfo_add_at_front, sep, writing))
{
// If lines were written by an older Vim we need to avoid
// getting duplicates. See if the entry already exists.
for (idx = 0; idx < viminfo_hisidx[type]; ++idx)
{
p = viminfo_history[type][idx].hisstr;
if (STRCMP(val, p) == 0
&& (type != HIST_SEARCH || sep == p[STRLEN(p) + 1]))
{
overwrite = TRUE;
break;
}
}
if (!overwrite)
{
// Need to re-allocate to append the separator byte.
len = vp[3].bv_len;
p = alloc(len + 2);
}
else
len = 0; // for picky compilers
if (p != NULL)
{
viminfo_history[type][idx].time_set = vp[1].bv_nr;
if (!overwrite)
{
mch_memmove(p, val, (size_t)len + 1);
// 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]++;
}
}
}
}
}
}
/*
* Concatenate history lines from viminfo after the lines typed in this Vim.
*/
static void
concat_history(int type)
{
int idx;
int i;
int hislen = get_hislen();
histentry_T *histentry = get_histentry(type);
int *hisidx = get_hisidx(type);
int *hisnum = get_hisnum(type);
idx = *hisidx + viminfo_hisidx[type];
if (idx >= hislen)
idx -= hislen;
else if (idx < 0)
idx = hislen - 1;
if (viminfo_add_at_front)
*hisidx = idx;
else
{
if (*hisidx == -1)
*hisidx = hislen - 1;
do
{
if (histentry[idx].hisstr != NULL || histentry[idx].viminfo)
break;
if (++idx == hislen)
idx = 0;
} while (idx != *hisidx);
if (idx != *hisidx && --idx < 0)
idx = hislen - 1;
}
for (i = 0; i < viminfo_hisidx[type]; i++)
{
vim_free(histentry[idx].hisstr);
histentry[idx].hisstr = viminfo_history[type][i].hisstr;
histentry[idx].viminfo = TRUE;
histentry[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++)
{
histentry[idx++].hisnum = ++*hisnum;
idx %= hislen;
}
}
static int
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;
}
/*
* 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;
int hislen = get_hislen();
histentry_T *histentry = get_histentry(type);
int *hisidx = get_hisidx(type);
int *hisnum = get_hisnum(type);
// Make one long list with all entries.
max_len = hislen + viminfo_hisidx[type];
tot_hist = ALLOC_MULT(histentry_T *, max_len);
new_hist = ALLOC_MULT(histentry_T, hislen );
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 (histentry[i].hisstr != NULL)
tot_hist[len++] = &histentry[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;
}
else
clear_hist_entry(&new_hist[i]);
}
*hisidx = (i < len ? i : 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(histentry[i].hisstr);
vim_free(histentry);
set_histentry(type, new_hist);
vim_free(tot_hist);
}
/*
* Finish reading history lines from viminfo. Not used when writing viminfo.
*/
static 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 (get_histentry(type) == NULL)
continue;
if (merge)
merge_history(type);
else
concat_history(type);
VIM_CLEAR(viminfo_history[type]);
viminfo_hisidx[type] = 0;
}
}
/*
* Write history to viminfo file in "fp".
* When "merge" is TRUE merge history lines with a previously read viminfo
* file, data is in viminfo_history[].
* When "merge" is FALSE just write all history lines. Used for ":wviminfo!".
*/
static void
write_viminfo_history(FILE *fp, int merge)
{
int i;
int type;
int num_saved;
int round;
int hislen;
init_history();
hislen = get_hislen();
if (hislen == 0)
return;
for (type = 0; type < HIST_COUNT; ++type)
{
histentry_T *histentry = get_histentry(type);
int *hisidx = get_hisidx(type);
num_saved = get_viminfo_parameter(hist_type2char(type, FALSE));
if (num_saved == 0)
continue;
if (num_saved < 0) // Use default
num_saved = hislen;
fprintf(fp, _("\n# %s History (newest to oldest):\n"),
type == HIST_CMD ? _("Command Line") :
type == HIST_SEARCH ? _("Search String") :
type == HIST_EXPR ? _("Expression") :
type == HIST_INPUT ? _("Input Line") :
_("Debug Line"));
if (num_saved > hislen)
num_saved = hislen;
/*
* Merge typed and viminfo history:
* round 1: history of typed commands.
* round 2: history from recently read viminfo.
*/
for (round = 1; round <= 2; ++round)
{
if (round == 1)
// start at newest entry, somewhere in the list
i = *hisidx;
else if (viminfo_hisidx[type] > 0)
// start at newest entry, first in the list
i = 0;
else
// empty list
i = -1;
if (i >= 0)
while (num_saved > 0
&& !(round == 2 && i >= viminfo_hisidx[type]))
{
char_u *p;
time_t timestamp;
int c = NUL;
if (round == 1)
{
p = histentry[i].hisstr;
timestamp = histentry[i].time_set;
}
else
{
p = viminfo_history[type] == NULL ? NULL
: viminfo_history[type][i].hisstr;
timestamp = viminfo_history[type] == NULL ? 0
: viminfo_history[type][i].time_set;
}
if (p != NULL && (round == 2
|| !merge
|| !histentry[i].viminfo))
{
--num_saved;
fputc(hist_type2char(type, TRUE), fp);
// For the search history: put the separator in the
// second column; use a space if there isn't one.
if (type == HIST_SEARCH)
{
c = p[STRLEN(p) + 1];
putc(c == NUL ? ' ' : c, fp);
}
viminfo_writestring(fp, p);
{
char cbuf[NUMBUFLEN];
// New style history with a bar line. Format:
// |{bartype},{histtype},{timestamp},{separator},"text"
if (c == NUL)
cbuf[0] = NUL;
else
sprintf(cbuf, "%d", c);
fprintf(fp, "|%d,%d,%ld,%s,", BARTYPE_HISTORY,
type, (long)timestamp, cbuf);
barline_writestring(fp, p, LSIZE - 20);
putc('\n', fp);
}
}
if (round == 1)
{
// Decrement index, loop around and stop when back at
// the start.
if (--i < 0)
i = hislen - 1;
if (i == *hisidx)
break;
}
else
{
// Increment index. Stop at the end in the while.
++i;
}
}
}
for (i = 0; i < viminfo_hisidx[type]; ++i)
if (viminfo_history[type] != NULL)
vim_free(viminfo_history[type][i].hisstr);
VIM_CLEAR(viminfo_history[type]);
viminfo_hisidx[type] = 0;
}
}
#endif // FEAT_VIMINFO
static void
write_viminfo_barlines(vir_T *virp, FILE *fp_out)
{