diff options
author | Bram Moolenaar <Bram@vim.org> | 2016-06-06 21:07:52 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2016-06-06 21:07:52 +0200 |
commit | 45d2eeaad66939348893b9254171067b0457cd9d (patch) | |
tree | 9259906f02afa0de6c6752982ad0c936e08033e5 /src/ex_getln.c | |
parent | bbe8d91e695184771d7e45315258fab8eb3e6b07 (diff) | |
download | vim-git-45d2eeaad66939348893b9254171067b0457cd9d.tar.gz |
patch 7.4.1903v7.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.
Diffstat (limited to 'src/ex_getln.c')
-rw-r--r-- | src/ex_getln.c | 158 |
1 files changed, 140 insertions, 18 deletions
diff --git a/src/ex_getln.c b/src/ex_getln.c index ed9707a26..e0d5226b1 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -58,6 +58,7 @@ 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}; @@ -5407,6 +5408,20 @@ static char *(history_names[]) = 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,6 +5591,7 @@ in_history( 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,6 +5679,7 @@ add_to_history( hisptr->hisnum = ++hisnum[histype]; hisptr->viminfo = FALSE; + hisptr->time_set = vim_time(); if (histype == HIST_SEARCH && in_map) last_maptick = maptick; } @@ -6131,9 +6148,10 @@ ex_history(exarg_T *eap) /* * 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 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,8 +6209,8 @@ prepare_viminfo_history(int asklen, int writing) if (len <= 0) viminfo_history[type] = NULL; else - viminfo_history[type] = - (char_u **)lalloc((long_u)(len * sizeof(char_u *)), FALSE); + 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,7 +6260,9 @@ read_viminfo_history(vir_T *virp, int writing) mch_memmove(p, val, (size_t)len + 1); p[len + 1] = NUL; } - viminfo_history[type][viminfo_hisidx[type]++] = p; + viminfo_history[type][viminfo_hisidx[type]].hisstr = p; + viminfo_history[type][viminfo_hisidx[type]].time_set = 0; + viminfo_hisidx[type]++; } } } @@ -6252,6 +6272,81 @@ read_viminfo_history(vir_T *virp, int writing) } /* + * 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,8 +6385,9 @@ finish_viminfo_history(void) 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].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,15 +6411,11 @@ finish_viminfo_history(void) * When "merge" is FALSE just write all history lines. Used for ":wviminfo!". */ void -write_viminfo_history( - FILE *fp, - int merge) +write_viminfo_history(FILE *fp, int merge) { int i; int type; int num_saved; - char_u *p; - int c; int round; init_history(); @@ -6339,8 +6431,9 @@ write_viminfo_history( 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")); + type == HIST_EXPR ? _("Expression") : + type == HIST_INPUT ? _("Input Line") : + _("Debug Line")); if (num_saved > hislen) num_saved = hislen; @@ -6364,9 +6457,23 @@ write_viminfo_history( 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]; + 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,6 +6488,21 @@ write_viminfo_history( 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,7 +6522,7 @@ write_viminfo_history( } for (i = 0; i < viminfo_hisidx[type]; ++i) if (viminfo_history[type] != NULL) - vim_free(viminfo_history[type][i]); + vim_free(viminfo_history[type][i].hisstr); vim_free(viminfo_history[type]); viminfo_history[type] = NULL; viminfo_hisidx[type] = 0; |