mirror of
https://github.com/vim/vim.git
synced 2025-09-23 03:43:49 -04:00
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.
This commit is contained in:
305
src/ex_cmds.c
305
src/ex_cmds.c
@@ -1750,9 +1750,14 @@ append_redir(
|
||||
#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,6 +2161,7 @@ do_viminfo(FILE *fp_in, FILE *fp_out, int flags)
|
||||
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,6 +2183,7 @@ do_viminfo(FILE *fp_in, FILE *fp_out, int flags)
|
||||
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,6 +2227,7 @@ read_viminfo_up_to_marks(
|
||||
{
|
||||
int eof;
|
||||
buf_T *buf;
|
||||
int got_encoding = FALSE;
|
||||
|
||||
#ifdef FEAT_CMDHIST
|
||||
prepare_viminfo_history(forceit ? 9999 : 0, writing);
|
||||
@@ -2240,12 +2248,11 @@ read_viminfo_up_to_marks(
|
||||
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);
|
||||
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,10 +2281,13 @@ read_viminfo_up_to_marks(
|
||||
case '=':
|
||||
case '@':
|
||||
#ifdef FEAT_CMDHIST
|
||||
eof = read_viminfo_history(virp, writing);
|
||||
#else
|
||||
eof = viminfo_readline(virp);
|
||||
/* 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,8 +2357,8 @@ viminfo_readline(vir_T *virp)
|
||||
}
|
||||
|
||||
/*
|
||||
* check string read from viminfo file
|
||||
* remove '\n' at the end of the line
|
||||
* 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,6 +2473,283 @@ viminfo_writestring(FILE *fd, char_u *p)
|
||||
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)
|
||||
{
|
||||
|
Reference in New Issue
Block a user