comparison src/ex_getln.c @ 9240:636cfa97200e v7.4.1903

commit https://github.com/vim/vim/commit/45d2eeaad66939348893b9254171067b0457cd9d Author: Bram Moolenaar <Bram@vim.org> Date: Mon Jun 6 21:07:52 2016 +0200 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.
author Christian Brabandt <cb@256bit.org>
date Mon, 06 Jun 2016 21:15:07 +0200
parents 0bb25b026fc9
children 26c7bf23ec1d
comparison
equal deleted inserted replaced
9239:a744b63c4ed0 9240:636cfa97200e
56 typedef struct hist_entry 56 typedef struct hist_entry
57 { 57 {
58 int hisnum; /* identifying number */ 58 int hisnum; /* identifying number */
59 int viminfo; /* when TRUE hisstr comes from viminfo */ 59 int viminfo; /* when TRUE hisstr comes from viminfo */
60 char_u *hisstr; /* actual entry, separator char after the NUL */ 60 char_u *hisstr; /* actual entry, separator char after the NUL */
61 time_t time_set; /* when it was typed, zero if unknown */
61 } histentry_T; 62 } histentry_T;
62 63
63 static histentry_T *(history[HIST_COUNT]) = {NULL, NULL, NULL, NULL, NULL}; 64 static histentry_T *(history[HIST_COUNT]) = {NULL, NULL, NULL, NULL, NULL};
64 static int hisidx[HIST_COUNT] = {-1, -1, -1, -1, -1}; /* lastused entry */ 65 static int hisidx[HIST_COUNT] = {-1, -1, -1, -1, -1}; /* lastused entry */
65 static int hisnum[HIST_COUNT] = {0, 0, 0, 0, 0}; 66 static int hisnum[HIST_COUNT] = {0, 0, 0, 0, 0};
5405 "input", 5406 "input",
5406 "debug", 5407 "debug",
5407 NULL 5408 NULL
5408 }; 5409 };
5409 5410
5411 /*
5412 * Return the current time in seconds. Calls time(), unless test_settime()
5413 * was used.
5414 */
5415 static time_t
5416 vim_time(void)
5417 {
5418 #ifdef FEAT_EVAL
5419 return time_for_testing == 0 ? time(NULL) : time_for_testing;
5420 #else
5421 return time(NULL);
5422 #endif
5423 }
5424
5410 #if defined(FEAT_CMDL_COMPL) || defined(PROTO) 5425 #if defined(FEAT_CMDL_COMPL) || defined(PROTO)
5411 /* 5426 /*
5412 * Function given to ExpandGeneric() to obtain the possible first 5427 * Function given to ExpandGeneric() to obtain the possible first
5413 * arguments of the ":history command. 5428 * arguments of the ":history command.
5414 */ 5429 */
5574 last_i = i; 5589 last_i = i;
5575 } 5590 }
5576 history[type][i].hisnum = ++hisnum[type]; 5591 history[type][i].hisnum = ++hisnum[type];
5577 history[type][i].viminfo = FALSE; 5592 history[type][i].viminfo = FALSE;
5578 history[type][i].hisstr = str; 5593 history[type][i].hisstr = str;
5594 history[type][i].time_set = vim_time();
5579 return TRUE; 5595 return TRUE;
5580 } 5596 }
5581 return FALSE; 5597 return FALSE;
5582 } 5598 }
5583 5599
5661 if (hisptr->hisstr != NULL) 5677 if (hisptr->hisstr != NULL)
5662 hisptr->hisstr[len + 1] = sep; 5678 hisptr->hisstr[len + 1] = sep;
5663 5679
5664 hisptr->hisnum = ++hisnum[histype]; 5680 hisptr->hisnum = ++hisnum[histype];
5665 hisptr->viminfo = FALSE; 5681 hisptr->viminfo = FALSE;
5682 hisptr->time_set = vim_time();
5666 if (histype == HIST_SEARCH && in_map) 5683 if (histype == HIST_SEARCH && in_map)
5667 last_maptick = maptick; 5684 last_maptick = maptick;
5668 } 5685 }
5669 } 5686 }
5670 5687
6129 6146
6130 #if (defined(FEAT_VIMINFO) && defined(FEAT_CMDHIST)) || defined(PROTO) 6147 #if (defined(FEAT_VIMINFO) && defined(FEAT_CMDHIST)) || defined(PROTO)
6131 /* 6148 /*
6132 * Buffers for history read from a viminfo file. Only valid while reading. 6149 * Buffers for history read from a viminfo file. Only valid while reading.
6133 */ 6150 */
6134 static char_u **viminfo_history[HIST_COUNT] = {NULL, NULL, NULL, NULL}; 6151 static histentry_T *viminfo_history[HIST_COUNT] =
6135 static int viminfo_hisidx[HIST_COUNT] = {0, 0, 0, 0}; 6152 {NULL, NULL, NULL, NULL, NULL};
6136 static int viminfo_hislen[HIST_COUNT] = {0, 0, 0, 0}; 6153 static int viminfo_hisidx[HIST_COUNT] = {0, 0, 0, 0, 0};
6154 static int viminfo_hislen[HIST_COUNT] = {0, 0, 0, 0, 0};
6137 static int viminfo_add_at_front = FALSE; 6155 static int viminfo_add_at_front = FALSE;
6138 6156
6139 static int hist_type2char(int type, int use_question); 6157 static int hist_type2char(int type, int use_question);
6140 6158
6141 /* 6159 /*
6189 if (num > len) 6207 if (num > len)
6190 len = num; 6208 len = num;
6191 if (len <= 0) 6209 if (len <= 0)
6192 viminfo_history[type] = NULL; 6210 viminfo_history[type] = NULL;
6193 else 6211 else
6194 viminfo_history[type] = 6212 viminfo_history[type] = (histentry_T *)lalloc(
6195 (char_u **)lalloc((long_u)(len * sizeof(char_u *)), FALSE); 6213 (long_u)(len * sizeof(histentry_T)), FALSE);
6196 if (viminfo_history[type] == NULL) 6214 if (viminfo_history[type] == NULL)
6197 len = 0; 6215 len = 0;
6198 viminfo_hislen[type] = len; 6216 viminfo_hislen[type] = len;
6199 viminfo_hisidx[type] = 0; 6217 viminfo_hisidx[type] = 0;
6200 } 6218 }
6240 /* Not a search entry: No separator in the viminfo 6258 /* Not a search entry: No separator in the viminfo
6241 * file, add a NUL separator. */ 6259 * file, add a NUL separator. */
6242 mch_memmove(p, val, (size_t)len + 1); 6260 mch_memmove(p, val, (size_t)len + 1);
6243 p[len + 1] = NUL; 6261 p[len + 1] = NUL;
6244 } 6262 }
6245 viminfo_history[type][viminfo_hisidx[type]++] = p; 6263 viminfo_history[type][viminfo_hisidx[type]].hisstr = p;
6264 viminfo_history[type][viminfo_hisidx[type]].time_set = 0;
6265 viminfo_hisidx[type]++;
6246 } 6266 }
6247 } 6267 }
6248 } 6268 }
6249 vim_free(val); 6269 vim_free(val);
6250 } 6270 }
6251 return viminfo_readline(virp); 6271 return viminfo_readline(virp);
6272 }
6273
6274 /*
6275 * Accept a new style history line from the viminfo, store it in the history
6276 * array when it's new.
6277 */
6278 void
6279 handle_viminfo_history(
6280 bval_T *values,
6281 int count,
6282 int writing)
6283 {
6284 int type;
6285 long_u len;
6286 char_u *val;
6287 char_u *p;
6288
6289 /* Check the format:
6290 * |{bartype},{histtype},{timestamp},{separator},"text" */
6291 if (count < 4
6292 || values[0].bv_type != BVAL_NR
6293 || values[1].bv_type != BVAL_NR
6294 || (values[2].bv_type != BVAL_NR && values[2].bv_type != BVAL_EMPTY)
6295 || values[3].bv_type != BVAL_STRING)
6296 return;
6297
6298 type = values[0].bv_nr;
6299 if (type >= HIST_COUNT)
6300 return;
6301 if (viminfo_hisidx[type] < viminfo_hislen[type])
6302 {
6303 val = values[3].bv_string;
6304 if (val != NULL && *val != NUL)
6305 {
6306 int sep = type == HIST_SEARCH && values[2].bv_type == BVAL_NR
6307 ? values[2].bv_nr : NUL;
6308 int idx;
6309 int overwrite = FALSE;
6310
6311 if (!in_history(type, val, viminfo_add_at_front, sep, writing))
6312 {
6313 /* If lines were written by an older Vim we need to avoid
6314 * getting duplicates. See if the entry already exists. */
6315 for (idx = 0; idx < viminfo_hisidx[type]; ++idx)
6316 {
6317 p = viminfo_history[type][idx].hisstr;
6318 if (STRCMP(val, p) == 0
6319 && (type != HIST_SEARCH || sep == p[STRLEN(p) + 1]))
6320 {
6321 overwrite = TRUE;
6322 break;
6323 }
6324 }
6325
6326 if (!overwrite)
6327 {
6328 /* Need to re-allocate to append the separator byte. */
6329 len = values[3].bv_len;
6330 p = lalloc(len + 2, TRUE);
6331 }
6332 if (p != NULL)
6333 {
6334 viminfo_history[type][idx].time_set = values[1].bv_nr;
6335 if (!overwrite)
6336 {
6337 mch_memmove(p, val, (size_t)len + 1);
6338 /* Put the separator after the NUL. */
6339 p[len + 1] = sep;
6340 viminfo_history[type][idx].hisstr = p;
6341 viminfo_hisidx[type]++;
6342 }
6343 }
6344 }
6345 }
6346 }
6252 } 6347 }
6253 6348
6254 /* 6349 /*
6255 * Finish reading history lines from viminfo. Not used when writing viminfo. 6350 * Finish reading history lines from viminfo. Not used when writing viminfo.
6256 */ 6351 */
6288 idx = hislen - 1; 6383 idx = hislen - 1;
6289 } 6384 }
6290 for (i = 0; i < viminfo_hisidx[type]; i++) 6385 for (i = 0; i < viminfo_hisidx[type]; i++)
6291 { 6386 {
6292 vim_free(history[type][idx].hisstr); 6387 vim_free(history[type][idx].hisstr);
6293 history[type][idx].hisstr = viminfo_history[type][i]; 6388 history[type][idx].hisstr = viminfo_history[type][i].hisstr;
6294 history[type][idx].viminfo = TRUE; 6389 history[type][idx].viminfo = TRUE;
6390 history[type][idx].time_set = viminfo_history[type][i].time_set;
6295 if (--idx < 0) 6391 if (--idx < 0)
6296 idx = hislen - 1; 6392 idx = hislen - 1;
6297 } 6393 }
6298 idx += 1; 6394 idx += 1;
6299 idx %= hislen; 6395 idx %= hislen;
6313 * When "merge" is TRUE merge history lines with a previously read viminfo 6409 * When "merge" is TRUE merge history lines with a previously read viminfo
6314 * file, data is in viminfo_history[]. 6410 * file, data is in viminfo_history[].
6315 * When "merge" is FALSE just write all history lines. Used for ":wviminfo!". 6411 * When "merge" is FALSE just write all history lines. Used for ":wviminfo!".
6316 */ 6412 */
6317 void 6413 void
6318 write_viminfo_history( 6414 write_viminfo_history(FILE *fp, int merge)
6319 FILE *fp,
6320 int merge)
6321 { 6415 {
6322 int i; 6416 int i;
6323 int type; 6417 int type;
6324 int num_saved; 6418 int num_saved;
6325 char_u *p;
6326 int c;
6327 int round; 6419 int round;
6328 6420
6329 init_history(); 6421 init_history();
6330 if (hislen == 0) 6422 if (hislen == 0)
6331 return; 6423 return;
6337 if (num_saved < 0) /* Use default */ 6429 if (num_saved < 0) /* Use default */
6338 num_saved = hislen; 6430 num_saved = hislen;
6339 fprintf(fp, _("\n# %s History (newest to oldest):\n"), 6431 fprintf(fp, _("\n# %s History (newest to oldest):\n"),
6340 type == HIST_CMD ? _("Command Line") : 6432 type == HIST_CMD ? _("Command Line") :
6341 type == HIST_SEARCH ? _("Search String") : 6433 type == HIST_SEARCH ? _("Search String") :
6342 type == HIST_EXPR ? _("Expression") : 6434 type == HIST_EXPR ? _("Expression") :
6343 _("Input Line")); 6435 type == HIST_INPUT ? _("Input Line") :
6436 _("Debug Line"));
6344 if (num_saved > hislen) 6437 if (num_saved > hislen)
6345 num_saved = hislen; 6438 num_saved = hislen;
6346 6439
6347 /* 6440 /*
6348 * Merge typed and viminfo history: 6441 * Merge typed and viminfo history:
6362 i = -1; 6455 i = -1;
6363 if (i >= 0) 6456 if (i >= 0)
6364 while (num_saved > 0 6457 while (num_saved > 0
6365 && !(round == 2 && i >= viminfo_hisidx[type])) 6458 && !(round == 2 && i >= viminfo_hisidx[type]))
6366 { 6459 {
6367 p = round == 1 ? history[type][i].hisstr 6460 char_u *p;
6368 : viminfo_history[type] == NULL ? NULL 6461 time_t timestamp;
6369 : viminfo_history[type][i]; 6462 int c = NUL;
6463
6464 if (round == 1)
6465 {
6466 p = history[type][i].hisstr;
6467 timestamp = history[type][i].time_set;
6468 }
6469 else
6470 {
6471 p = viminfo_history[type] == NULL ? NULL
6472 : viminfo_history[type][i].hisstr;
6473 timestamp = viminfo_history[type] == NULL ? 0
6474 : viminfo_history[type][i].time_set;
6475 }
6476
6370 if (p != NULL && (round == 2 6477 if (p != NULL && (round == 2
6371 || !merge 6478 || !merge
6372 || !history[type][i].viminfo)) 6479 || !history[type][i].viminfo))
6373 { 6480 {
6374 --num_saved; 6481 --num_saved;
6379 { 6486 {
6380 c = p[STRLEN(p) + 1]; 6487 c = p[STRLEN(p) + 1];
6381 putc(c == NUL ? ' ' : c, fp); 6488 putc(c == NUL ? ' ' : c, fp);
6382 } 6489 }
6383 viminfo_writestring(fp, p); 6490 viminfo_writestring(fp, p);
6491
6492 {
6493 char cbuf[NUMBUFLEN];
6494
6495 /* New style history with a bar line. Format:
6496 * |{bartype},{histtype},{timestamp},{separator},"text" */
6497 if (c == NUL)
6498 cbuf[0] = NUL;
6499 else
6500 sprintf(cbuf, "%d", c);
6501 fprintf(fp, "|%d,%d,%ld,%s,", BARTYPE_HISTORY,
6502 type, (long)timestamp, cbuf);
6503 barline_writestring(fp, p, LSIZE - 20);
6504 putc('\n', fp);
6505 }
6384 } 6506 }
6385 if (round == 1) 6507 if (round == 1)
6386 { 6508 {
6387 /* Decrement index, loop around and stop when back at 6509 /* Decrement index, loop around and stop when back at
6388 * the start. */ 6510 * the start. */
6398 } 6520 }
6399 } 6521 }
6400 } 6522 }
6401 for (i = 0; i < viminfo_hisidx[type]; ++i) 6523 for (i = 0; i < viminfo_hisidx[type]; ++i)
6402 if (viminfo_history[type] != NULL) 6524 if (viminfo_history[type] != NULL)
6403 vim_free(viminfo_history[type][i]); 6525 vim_free(viminfo_history[type][i].hisstr);
6404 vim_free(viminfo_history[type]); 6526 vim_free(viminfo_history[type]);
6405 viminfo_history[type] = NULL; 6527 viminfo_history[type] = NULL;
6406 viminfo_hisidx[type] = 0; 6528 viminfo_hisidx[type] = 0;
6407 } 6529 }
6408 } 6530 }