Mercurial > vim
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 } |