Patch 7.4.1903
Problem: When writing viminfo merging current history with history in
viminfo may drop recent history entries.
Solution: Add new format for viminfo lines, use it for history entries. Use
a timestamp for ordering the entries. Add test_settime().
Add the viminfo version. Does not do merging on timestamp yet.
Files: src/eval.c, src/ex_getln.c, src/ex_cmds.c, src/structs.h,
src/globals.h, src/proto/ex_cmds.pro, src/proto/ex_getln.pro,
src/testdir/test_viminfo.vim
*** ../vim-7.4.1902/src/eval.c 2016-06-04 18:49:15.382070039 +0200
--- src/eval.c 2016-06-06 20:06:23.415629375 +0200
***************
*** 820,825 ****
--- 820,826 ----
static void f_test_null_list(typval_T *argvars, typval_T *rettv);
static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
static void f_test_null_string(typval_T *argvars, typval_T *rettv);
+ static void f_test_settime(typval_T *argvars, typval_T *rettv);
#ifdef FEAT_FLOAT
static void f_tan(typval_T *argvars, typval_T *rettv);
static void f_tanh(typval_T *argvars, typval_T *rettv);
***************
*** 8809,8821 ****
#ifdef FEAT_JOB_CHANNEL
{"test_null_channel", 0, 0, f_test_null_channel},
#endif
! {"test_null_dict", 0, 0, f_test_null_dict},
#ifdef FEAT_JOB_CHANNEL
! {"test_null_job", 0, 0, f_test_null_job},
#endif
! {"test_null_list", 0, 0, f_test_null_list},
{"test_null_partial", 0, 0, f_test_null_partial},
{"test_null_string", 0, 0, f_test_null_string},
#ifdef FEAT_TIMERS
{"timer_start", 2, 3, f_timer_start},
{"timer_stop", 1, 1, f_timer_stop},
--- 8810,8823 ----
#ifdef FEAT_JOB_CHANNEL
{"test_null_channel", 0, 0, f_test_null_channel},
#endif
! {"test_null_dict", 0, 0, f_test_null_dict},
#ifdef FEAT_JOB_CHANNEL
! {"test_null_job", 0, 0, f_test_null_job},
#endif
! {"test_null_list", 0, 0, f_test_null_list},
{"test_null_partial", 0, 0, f_test_null_partial},
{"test_null_string", 0, 0, f_test_null_string},
+ {"test_settime", 1, 1, f_test_settime},
#ifdef FEAT_TIMERS
{"timer_start", 2, 3, f_timer_start},
{"timer_stop", 1, 1, f_timer_stop},
***************
*** 20849,20855 ****
#ifdef FEAT_JOB_CHANNEL
static void
! f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
{
rettv->v_type = VAR_CHANNEL;
rettv->vval.v_channel = NULL;
--- 20851,20857 ----
#ifdef FEAT_JOB_CHANNEL
static void
! f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
{
rettv->v_type = VAR_CHANNEL;
rettv->vval.v_channel = NULL;
***************
*** 20857,20863 ****
#endif
static void
! f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
{
rettv->v_type = VAR_DICT;
rettv->vval.v_dict = NULL;
--- 20859,20865 ----
#endif
static void
! f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
{
rettv->v_type = VAR_DICT;
rettv->vval.v_dict = NULL;
***************
*** 20865,20871 ****
#ifdef FEAT_JOB_CHANNEL
static void
! f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
{
rettv->v_type = VAR_JOB;
rettv->vval.v_job = NULL;
--- 20867,20873 ----
#ifdef FEAT_JOB_CHANNEL
static void
! f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
{
rettv->v_type = VAR_JOB;
rettv->vval.v_job = NULL;
***************
*** 20873,20898 ****
#endif
static void
! f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
{
rettv->v_type = VAR_LIST;
rettv->vval.v_list = NULL;
}
static void
! f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
{
rettv->v_type = VAR_PARTIAL;
rettv->vval.v_partial = NULL;
}
static void
! f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
{
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
}
#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
/*
* Get a callback from "arg". It can be a Funcref or a function name.
--- 20875,20906 ----
#endif
static void
! f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
{
rettv->v_type = VAR_LIST;
rettv->vval.v_list = NULL;
}
static void
! f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
{
rettv->v_type = VAR_PARTIAL;
rettv->vval.v_partial = NULL;
}
static void
! f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
{
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
}
+ static void
+ f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
+ {
+ time_for_testing = (time_t)get_tv_number(&argvars[0]);
+ }
+
#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
/*
* Get a callback from "arg". It can be a Funcref or a function name.
*** ../vim-7.4.1902/src/ex_getln.c 2016-05-07 18:36:44.244210666 +0200
--- src/ex_getln.c 2016-06-06 21:03:36.871582145 +0200
***************
*** 58,63 ****
--- 58,64 ----
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};
***************
*** 5407,5412 ****
--- 5408,5427 ----
NULL
};
+ /*
+ * Return the current time in seconds. Calls time(), unless test_settime()
+ * was used.
+ */
+ static time_t
+ vim_time(void)
+ {
+ #ifdef FEAT_EVAL
+ return time_for_testing == 0 ? time(NULL) : time_for_testing;
+ #else
+ return time(NULL);
+ #endif
+ }
+
#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
/*
* Function given to ExpandGeneric() to obtain the possible first
***************
*** 5576,5581 ****
--- 5591,5597 ----
history[type][i].hisnum = ++hisnum[type];
history[type][i].viminfo = FALSE;
history[type][i].hisstr = str;
+ history[type][i].time_set = vim_time();
return TRUE;
}
return FALSE;
***************
*** 5663,5668 ****
--- 5679,5685 ----
hisptr->hisnum = ++hisnum[histype];
hisptr->viminfo = FALSE;
+ hisptr->time_set = vim_time();
if (histype == HIST_SEARCH && in_map)
last_maptick = maptick;
}
***************
*** 6131,6139 ****
/*
* Buffers for history read from a viminfo file. Only valid while reading.
*/
! static char_u **viminfo_history[HIST_COUNT] = {NULL, NULL, NULL, NULL};
! static int viminfo_hisidx[HIST_COUNT] = {0, 0, 0, 0};
! static int viminfo_hislen[HIST_COUNT] = {0, 0, 0, 0};
static int viminfo_add_at_front = FALSE;
static int hist_type2char(int type, int use_question);
--- 6148,6157 ----
/*
* 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;
static int hist_type2char(int type, int use_question);
***************
*** 6191,6198 ****
if (len <= 0)
viminfo_history[type] = NULL;
else
! viminfo_history[type] =
! (char_u **)lalloc((long_u)(len * sizeof(char_u *)), FALSE);
if (viminfo_history[type] == NULL)
len = 0;
viminfo_hislen[type] = len;
--- 6209,6216 ----
if (len <= 0)
viminfo_history[type] = NULL;
else
! viminfo_history[type] = (histentry_T *)lalloc(
! (long_u)(len * sizeof(histentry_T)), FALSE);
if (viminfo_history[type] == NULL)
len = 0;
viminfo_hislen[type] = len;
***************
*** 6242,6248 ****
mch_memmove(p, val, (size_t)len + 1);
p[len + 1] = NUL;
}
! viminfo_history[type][viminfo_hisidx[type]++] = p;
}
}
}
--- 6260,6268 ----
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_hisidx[type]++;
}
}
}
***************
*** 6252,6257 ****
--- 6272,6352 ----
}
/*
+ * Accept a new style history line from the viminfo, store it in the history
+ * array when it's new.
+ */
+ void
+ handle_viminfo_history(
+ bval_T *values,
+ int count,
+ int writing)
+ {
+ int type;
+ long_u len;
+ char_u *val;
+ char_u *p;
+
+ /* Check the format:
+ * |{bartype},{histtype},{timestamp},{separator},"text" */
+ if (count < 4
+ || values[0].bv_type != BVAL_NR
+ || values[1].bv_type != BVAL_NR
+ || (values[2].bv_type != BVAL_NR && values[2].bv_type != BVAL_EMPTY)
+ || values[3].bv_type != BVAL_STRING)
+ return;
+
+ type = values[0].bv_nr;
+ if (type >= HIST_COUNT)
+ return;
+ if (viminfo_hisidx[type] < viminfo_hislen[type])
+ {
+ val = values[3].bv_string;
+ if (val != NULL && *val != NUL)
+ {
+ int sep = type == HIST_SEARCH && values[2].bv_type == BVAL_NR
+ ? values[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 = values[3].bv_len;
+ p = lalloc(len + 2, TRUE);
+ }
+ if (p != NULL)
+ {
+ viminfo_history[type][idx].time_set = values[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_hisidx[type]++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /*
* Finish reading history lines from viminfo. Not used when writing viminfo.
*/
void
***************
*** 6290,6297 ****
for (i = 0; i < viminfo_hisidx[type]; i++)
{
vim_free(history[type][idx].hisstr);
! history[type][idx].hisstr = viminfo_history[type][i];
history[type][idx].viminfo = TRUE;
if (--idx < 0)
idx = hislen - 1;
}
--- 6385,6393 ----
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;
}
***************
*** 6315,6329 ****
* 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;
- char_u *p;
- int c;
int round;
init_history();
--- 6411,6421 ----
* 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();
***************
*** 6339,6346 ****
fprintf(fp, _("\n# %s History (newest to oldest):\n"),
type == HIST_CMD ? _("Command Line") :
type == HIST_SEARCH ? _("Search String") :
! type == HIST_EXPR ? _("Expression") :
! _("Input Line"));
if (num_saved > hislen)
num_saved = hislen;
--- 6431,6439 ----
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;
***************
*** 6364,6372 ****
while (num_saved > 0
&& !(round == 2 && i >= viminfo_hisidx[type]))
{
! p = round == 1 ? history[type][i].hisstr
! : viminfo_history[type] == NULL ? NULL
! : viminfo_history[type][i];
if (p != NULL && (round == 2
|| !merge
|| !history[type][i].viminfo))
--- 6457,6479 ----
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))
***************
*** 6381,6386 ****
--- 6488,6508 ----
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)
{
***************
*** 6400,6406 ****
}
for (i = 0; i < viminfo_hisidx[type]; ++i)
if (viminfo_history[type] != NULL)
! vim_free(viminfo_history[type][i]);
vim_free(viminfo_history[type]);
viminfo_history[type] = NULL;
viminfo_hisidx[type] = 0;
--- 6522,6528 ----
}
for (i = 0; i < viminfo_hisidx[type]; ++i)
if (viminfo_history[type] != NULL)
! vim_free(viminfo_history[type][i].hisstr);
vim_free(viminfo_history[type]);
viminfo_history[type] = NULL;
viminfo_hisidx[type] = 0;
*** ../vim-7.4.1902/src/ex_cmds.c 2016-06-04 22:31:23.969886694 +0200
--- src/ex_cmds.c 2016-06-06 21:06:24.771579836 +0200
***************
*** 1750,1758 ****
--- 1750,1763 ----
#if defined(FEAT_VIMINFO) || defined(PROTO)
static int no_viminfo(void);
+ static int read_viminfo_barline(vir_T *virp, int got_encoding, int writing);
+ 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)
{
***************
*** 2156,2161 ****
--- 2161,2167 ----
vir.vir_conv.vc_type = CONV_NONE;
#endif
ga_init2(&vir.vir_barlines, (int)sizeof(char_u *), 100);
+ vir.vir_version = -1;
if (fp_in != NULL)
{
***************
*** 2177,2182 ****
--- 2183,2189 ----
fprintf(fp_out, _("# This viminfo file was generated by Vim %s.\n"),
VIM_VERSION_MEDIUM);
fputs(_("# You may edit it if you're careful!\n\n"), fp_out);
+ write_viminfo_version(fp_out);
#ifdef FEAT_MBYTE
fputs(_("# Value of 'encoding' when this file was written\n"), fp_out);
fprintf(fp_out, "*encoding=%s\n\n", p_enc);
***************
*** 2220,2225 ****
--- 2227,2233 ----
{
int eof;
buf_T *buf;
+ int got_encoding = FALSE;
#ifdef FEAT_CMDHIST
prepare_viminfo_history(forceit ? 9999 : 0, writing);
***************
*** 2240,2251 ****
case '#':
eof = viminfo_readline(virp);
break;
! case '|': /* copy line (for future use) */
! if (writing)
! ga_add_string(&virp->vir_barlines, virp->vir_line);
! eof = viminfo_readline(virp);
break;
case '*': /* "*encoding=value" */
eof = viminfo_encoding(virp);
break;
case '!': /* global variable */
--- 2248,2258 ----
case '#':
eof = viminfo_readline(virp);
break;
! case '|':
! eof = read_viminfo_barline(virp, got_encoding, writing);
break;
case '*': /* "*encoding=value" */
+ got_encoding = TRUE;
eof = viminfo_encoding(virp);
break;
case '!': /* global variable */
***************
*** 2274,2283 ****
case '=':
case '@':
#ifdef FEAT_CMDHIST
! eof = read_viminfo_history(virp, writing);
! #else
! eof = viminfo_readline(virp);
#endif
break;
case '-':
case '\'':
--- 2281,2293 ----
case '=':
case '@':
#ifdef FEAT_CMDHIST
! /* When history is in bar lines skip the old style history
! * lines. */
! if (virp->vir_version < VIMINFO_VERSION_WITH_HISTORY)
! eof = read_viminfo_history(virp, writing);
! else
#endif
+ eof = viminfo_readline(virp);
break;
case '-':
case '\'':
***************
*** 2347,2354 ****
}
/*
! * check string read from viminfo file
! * remove '\n' at the end of the line
* - replace CTRL-V CTRL-V with CTRL-V
* - replace CTRL-V 'n' with '\n'
*
--- 2357,2364 ----
}
/*
! * Check string read from viminfo file.
! * Remove '\n' at the end of the line.
* - replace CTRL-V CTRL-V with CTRL-V
* - replace CTRL-V 'n' with '\n'
*
***************
*** 2463,2468 ****
--- 2473,2755 ----
putc('\n', fd);
}
+ /*
+ * Write a string in quotes that barline_parse() can read back.
+ * Breaks the line in less than LSIZE pieces when needed.
+ * Returns remaining characters in the line.
+ */
+ int
+ barline_writestring(FILE *fd, char_u *s, int remaining_start)
+ {
+ char_u *p;
+ int remaining = remaining_start;
+ int len = 2;
+
+ /* Count the number of characters produced, including quotes. */
+ for (p = s; *p != NUL; ++p)
+ {
+ if (*p == NL)
+ len += 2;
+ else if (*p == '"' || *p == '\\')
+ len += 2;
+ else
+ ++len;
+ }
+ if (len > remaining)
+ {
+ fprintf(fd, ">%d\n|<", len);
+ remaining = LSIZE - 20;
+ }
+
+ putc('"', fd);
+ for (p = s; *p != NUL; ++p)
+ {
+ if (*p == NL)
+ {
+ putc('\\', fd);
+ putc('n', fd);
+ --remaining;
+ }
+ else if (*p == '"' || *p == '\\')
+ {
+ putc('\\', fd);
+ putc(*p, fd);
+ --remaining;
+ }
+ else
+ putc(*p, fd);
+ --remaining;
+
+ if (remaining < 3)
+ {
+ putc('\n', fd);
+ putc('|', fd);
+ putc('<', fd);
+ /* Leave enough space for another continuation. */
+ remaining = LSIZE - 20;
+ }
+ }
+ putc('"', fd);
+ return remaining;
+ }
+
+ /*
+ * Parse a viminfo line starting with '|'.
+ * Put each decoded value in "values" and return the number of values found.
+ */
+ static int
+ barline_parse(vir_T *virp, char_u *text, bval_T *values)
+ {
+ char_u *p = text;
+ char_u *nextp = NULL;
+ char_u *buf = NULL;;
+ int count = 0;
+ int i;
+ int allocated = FALSE;
+
+ while (*p == ',')
+ {
+ if (count == BVAL_MAX)
+ {
+ EMSG2(e_intern2, "barline_parse()");
+ break;
+ }
+ ++p;
+
+ if (*p == '>')
+ {
+ /* Need to read a continuation line. Need to put strings in
+ * allocated memory, because virp->vir_line is overwritten. */
+ if (!allocated)
+ {
+ for (i = 0; i < count; ++i)
+ if (values[i].bv_type == BVAL_STRING)
+ {
+ values[i].bv_string = vim_strnsave(
+ values[i].bv_string, values[i].bv_len);
+ values[i].bv_allocated = TRUE;
+ }
+ allocated = TRUE;
+ }
+
+ if (vim_isdigit(p[1]))
+ {
+ int len;
+ int todo;
+ int n;
+
+ /* String value was split into lines that are each shorter
+ * than LSIZE:
+ * |{bartype},>{length of "{text}{text2}"}
+ * |<"{text1}
+ * |<{text2}",{value}
+ */
+ ++p;
+ len = getdigits(&p);
+ buf = alloc(len + 1);
+ p = buf;
+ for (todo = len; todo > 0; todo -= n)
+ {
+ if (viminfo_readline(virp) || virp->vir_line[0] != '|'
+ || virp->vir_line[1] != '<')
+ /* file was truncated or garbled */
+ return 0;
+ /* Get length of text, excluding |< and NL chars. */
+ n = STRLEN(virp->vir_line);
+ while (n > 0 && (virp->vir_line[n - 1] == NL
+ || virp->vir_line[n - 1] == CAR))
+ --n;
+ n -= 2;
+ if (n > todo)
+ {
+ /* more values follow after the string */
+ nextp = virp->vir_line + 2 + todo;
+ n = todo;
+ }
+ mch_memmove(p, virp->vir_line + 2, n);
+ p += n;
+ }
+ *p = NUL;
+ p = buf;
+ }
+ else
+ {
+ /* Line ending in ">" continues in the next line:
+ * |{bartype},{lots of values},>
+ * |<{value},{value}
+ */
+ if (viminfo_readline(virp) || virp->vir_line[0] != '|'
+ || virp->vir_line[1] != '<')
+ /* file was truncated or garbled */
+ return 0;
+ p = virp->vir_line + 2;
+ }
+ }
+
+ if (isdigit(*p))
+ {
+ values[count].bv_type = BVAL_NR;
+ values[count].bv_nr = getdigits(&p);
+ ++count;
+ }
+ else if (*p == '"')
+ {
+ int len = 0;
+ char_u *s = p;
+
+ /* Unescape special characters in-place. */
+ ++p;
+ while (*p != '"')
+ {
+ if (*p == NL || *p == NUL)
+ return count; /* syntax error, drop the value */
+ if (*p == '\\')
+ {
+ ++p;
+ if (*p == 'n')
+ s[len++] = '\n';
+ else
+ s[len++] = *p;
+ ++p;
+ }
+ else
+ s[len++] = *p++;
+ }
+ s[len] = NUL;
+
+ if (s != buf && allocated)
+ s = vim_strsave(s);
+ values[count].bv_string = s;
+ values[count].bv_type = BVAL_STRING;
+ values[count].bv_len = len;
+ values[count].bv_allocated = allocated;
+ ++count;
+ if (nextp != NULL)
+ {
+ /* values following a long string */
+ p = nextp;
+ nextp = NULL;
+ }
+ }
+ else if (*p == ',')
+ {
+ values[count].bv_type = BVAL_EMPTY;
+ ++count;
+ }
+ else
+ break;
+ }
+
+ return count;
+ }
+
+ static int
+ read_viminfo_barline(vir_T *virp, int got_encoding, int writing)
+ {
+ char_u *p = virp->vir_line + 1;
+ int bartype;
+ bval_T values[BVAL_MAX];
+ int count = 0;
+ int i;
+
+ /* The format is: |{bartype},{value},...
+ * For a very long string:
+ * |{bartype},>{length of "{text}{text2}"}
+ * |<{text1}
+ * |<{text2},{value}
+ * For a long line not using a string
+ * |{bartype},{lots of values},>
+ * |<{value},{value}
+ */
+ if (*p == '<')
+ {
+ /* Continuation line of an unrecognized item. */
+ if (writing)
+ ga_add_string(&virp->vir_barlines, virp->vir_line);
+ }
+ else
+ {
+ bartype = getdigits(&p);
+ switch (bartype)
+ {
+ case BARTYPE_VERSION:
+ /* Only use the version when it comes before the encoding.
+ * If it comes later it was copied by a Vim version that
+ * doesn't understand the version. */
+ if (!got_encoding)
+ {
+ count = barline_parse(virp, p, values);
+ if (count > 0 && values[0].bv_type == BVAL_NR)
+ virp->vir_version = values[0].bv_nr;
+ }
+ break;
+
+ case BARTYPE_HISTORY:
+ count = barline_parse(virp, p, values);
+ handle_viminfo_history(values, count, writing);
+ break;
+
+ default:
+ /* copy unrecognized line (for future use) */
+ if (writing)
+ ga_add_string(&virp->vir_barlines, virp->vir_line);
+ }
+ }
+
+ for (i = 0; i < count; ++i)
+ if (values[i].bv_type == BVAL_STRING && values[i].bv_allocated)
+ vim_free(values[i].bv_string);
+
+ return viminfo_readline(virp);
+ }
+
+ static void
+ write_viminfo_version(FILE *fp_out)
+ {
+ fprintf(fp_out, "# Viminfo version\n|%d,%d\n\n",
+ BARTYPE_VERSION, VIMINFO_VERSION);
+ }
+
static void
write_viminfo_barlines(vir_T *virp, FILE *fp_out)
{
*** ../vim-7.4.1902/src/structs.h 2016-06-04 17:17:07.042146086 +0200
--- src/structs.h 2016-06-05 17:28:47.096947955 +0200
***************
*** 1014,1019 ****
--- 1014,1020 ----
#ifdef FEAT_MBYTE
vimconv_T vir_conv; /* encoding conversion */
#endif
+ int vir_version; /* viminfo version detected or -1 */
garray_T vir_barlines; /* lines starting with | */
} vir_T;
*** ../vim-7.4.1902/src/globals.h 2016-06-02 14:29:59.136661030 +0200
--- src/globals.h 2016-06-06 19:49:45.187643107 +0200
***************
*** 1639,1644 ****
--- 1639,1648 ----
EXTERN int did_add_timer INIT(= FALSE);
#endif
+ #ifdef FEAT_EVAL
+ EXTERN time_t time_for_testing INIT(= 0);
+ #endif
+
/*
* Optional Farsi support. Include it here, so EXTERN and INIT are defined.
*/
*** ../vim-7.4.1902/src/proto/ex_cmds.pro 2016-01-19 13:21:55.837334377
+0100
--- src/proto/ex_cmds.pro 2016-06-05 19:16:00.536859458 +0200
***************
*** 16,21 ****
--- 16,22 ----
int viminfo_readline(vir_T *virp);
char_u *viminfo_readstring(vir_T *virp, int off, int convert);
void viminfo_writestring(FILE *fd, char_u *p);
+ int barline_writestring(FILE *fd, char_u *s, int remaining_start);
void do_fixdel(exarg_T *eap);
void print_line_no_prefix(linenr_T lnum, int use_number, int list);
void print_line(linenr_T lnum, int use_number, int list);
*** ../vim-7.4.1902/src/proto/ex_getln.pro 2016-01-19 13:21:55.837334377
+0100
--- src/proto/ex_getln.pro 2016-06-05 23:10:08.664666215 +0200
***************
*** 37,55 ****
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);
- char_u *get_cmdline_str(void);
- int get_cmdline_pos(void);
- int set_cmdline_pos(int pos);
- int get_cmdline_type(void);
char_u *get_history_entry(int histype, int idx);
int clr_history(int histype);
int del_history_entry(int histype, char_u *str);
int del_history_idx(int histype, int idx);
void remove_key_from_history(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 finish_viminfo_history(void);
void write_viminfo_history(FILE *fp, int merge);
void cmd_pchar(int c, int offset);
--- 37,56 ----
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);
char_u *get_history_entry(int histype, int idx);
int clr_history(int histype);
int del_history_entry(int histype, char_u *str);
int del_history_idx(int histype, int idx);
void remove_key_from_history(void);
+ char_u *get_cmdline_str(void);
+ int get_cmdline_pos(void);
+ 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(bval_T *values, int count, int writing);
void finish_viminfo_history(void);
void write_viminfo_history(FILE *fp, int merge);
void cmd_pchar(int c, int offset);
*** ../vim-7.4.1902/src/testdir/test_viminfo.vim 2016-03-30
20:50:41.905696041 +0200
--- src/testdir/test_viminfo.vim 2016-06-06 20:50:52.899592654 +0200
***************
*** 1,6 ****
--- 1,7 ----
" Test for reading and writing .viminfo
function Test_read_and_write()
+ call histdel(':')
let lines = [
\ '# comment line',
\ '*encoding=utf-8',
***************
*** 18,31 ****
for line in lines
if line[0] == '|'
if done == 0
! call assert_equal('|copied as-is', line)
elseif done == 1
call assert_equal('|and one more', line)
endif
let done += 1
endif
endfor
! call assert_equal(2, done)
call delete('Xviminfo')
endfunc
--- 19,34 ----
for line in lines
if line[0] == '|'
if done == 0
! call assert_equal('|1,2', line)
elseif done == 1
+ call assert_equal('|copied as-is', line)
+ elseif done == 2
call assert_equal('|and one more', line)
endif
let done += 1
endif
endfor
! call assert_equal(3, done)
call delete('Xviminfo')
endfunc
***************
*** 48,50 ****
--- 51,118 ----
call delete('Xviminfo')
set viminfo-=!
endfunc
+
+ func Test_cmdline_history()
+ call histdel(':')
+ call test_settime(11)
+ call histadd(':', "echo 'one'")
+ call test_settime(12)
+ " split into two lines
+ let long800 = repeat(" 'eight'", 100)
+ call histadd(':', "echo " . long800)
+ call test_settime(13)
+ " split into three lines
+ let long1400 = repeat(" 'fourteeeeen'", 100)
+ call histadd(':', "echo " . long1400)
+ wviminfo Xviminfo
+ let lines = readfile('Xviminfo')
+ let done_colon = 0
+ let done_bar = 0
+ let lnum = 0
+ while lnum < len(lines)
+ let line = lines[lnum] | let lnum += 1
+ if line[0] == ':'
+ if done_colon == 0
+ call assert_equal(":\x161408", line)
+ let line = lines[lnum] | let lnum += 1
+ call assert_equal('<echo ' . long1400, line)
+ elseif done_colon == 1
+ call assert_equal(":\x16808", line)
+ let line = lines[lnum] | let lnum += 1
+ call assert_equal("<echo " . long800, line)
+ elseif done_colon == 2
+ call assert_equal(":echo 'one'", line)
+ endif
+ let done_colon += 1
+ elseif line[0:4] == '|2,0,'
+ if done_bar == 0
+ call assert_equal("|2,0,13,,>1407", line)
+ let line = lines[lnum] | let lnum += 1
+ call assert_equal('|<"echo ' . long1400[0:484], line)
+ let line = lines[lnum] | let lnum += 1
+ call assert_equal('|<' . long1400[485:974], line)
+ let line = lines[lnum] | let lnum += 1
+ call assert_equal('|<' . long1400[975:] . '"', line)
+ elseif done_bar == 1
+ call assert_equal('|2,0,12,,>807', line)
+ let line = lines[lnum] | let lnum += 1
+ call assert_equal('|<"echo ' . long800[0:484], line)
+ let line = lines[lnum] | let lnum += 1
+ call assert_equal('|<' . long800[485:] . '"', line)
+ elseif done_bar == 2
+ call assert_equal("|2,0,11,,\"echo 'one'\"", line)
+ endif
+ let done_bar += 1
+ endif
+ endwhile
+ call assert_equal(3, done_colon)
+ call assert_equal(3, done_bar)
+
+ call histdel(':')
+ rviminfo Xviminfo
+ call assert_equal("echo " . long1400, histget(':', -1))
+ call assert_equal("echo " . long800, histget(':', -2))
+ call assert_equal("echo 'one'", histget(':', -3))
+
+ call delete('Xviminfo')
+ endfunc
*** ../vim-7.4.1902/src/version.c 2016-06-05 16:10:49.537012299 +0200
--- src/version.c 2016-06-06 21:02:25.207583131 +0200
***************
*** 755,756 ****
--- 755,758 ----
{ /* Add new patch number below this line */
+ /**/
+ 1903,
/**/
--
"I simultaneously try to keep my head in the clouds and my feet on the
ground. Sometimes it's a stretch, though." -- Larry Wall
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.