comparison src/ex_cmds.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 6e80397a592c
children 931bbf7b6ee3
comparison
equal deleted inserted replaced
9239:a744b63c4ed0 9240:636cfa97200e
1748 } 1748 }
1749 1749
1750 #if defined(FEAT_VIMINFO) || defined(PROTO) 1750 #if defined(FEAT_VIMINFO) || defined(PROTO)
1751 1751
1752 static int no_viminfo(void); 1752 static int no_viminfo(void);
1753 static int read_viminfo_barline(vir_T *virp, int got_encoding, int writing);
1754 static void write_viminfo_version(FILE *fp_out);
1753 static void write_viminfo_barlines(vir_T *virp, FILE *fp_out); 1755 static void write_viminfo_barlines(vir_T *virp, FILE *fp_out);
1754 static int viminfo_errcnt; 1756 static int viminfo_errcnt;
1757
1758 #define VIMINFO_VERSION 2
1759 #define VIMINFO_VERSION_WITH_HISTORY 2
1755 1760
1756 static int 1761 static int
1757 no_viminfo(void) 1762 no_viminfo(void)
1758 { 1763 {
1759 /* "vim -i NONE" does not read or write a viminfo file */ 1764 /* "vim -i NONE" does not read or write a viminfo file */
2154 vir.vir_fd = fp_in; 2159 vir.vir_fd = fp_in;
2155 #ifdef FEAT_MBYTE 2160 #ifdef FEAT_MBYTE
2156 vir.vir_conv.vc_type = CONV_NONE; 2161 vir.vir_conv.vc_type = CONV_NONE;
2157 #endif 2162 #endif
2158 ga_init2(&vir.vir_barlines, (int)sizeof(char_u *), 100); 2163 ga_init2(&vir.vir_barlines, (int)sizeof(char_u *), 100);
2164 vir.vir_version = -1;
2159 2165
2160 if (fp_in != NULL) 2166 if (fp_in != NULL)
2161 { 2167 {
2162 if (flags & VIF_WANT_INFO) 2168 if (flags & VIF_WANT_INFO)
2163 { 2169 {
2175 { 2181 {
2176 /* Write the info: */ 2182 /* Write the info: */
2177 fprintf(fp_out, _("# This viminfo file was generated by Vim %s.\n"), 2183 fprintf(fp_out, _("# This viminfo file was generated by Vim %s.\n"),
2178 VIM_VERSION_MEDIUM); 2184 VIM_VERSION_MEDIUM);
2179 fputs(_("# You may edit it if you're careful!\n\n"), fp_out); 2185 fputs(_("# You may edit it if you're careful!\n\n"), fp_out);
2186 write_viminfo_version(fp_out);
2180 #ifdef FEAT_MBYTE 2187 #ifdef FEAT_MBYTE
2181 fputs(_("# Value of 'encoding' when this file was written\n"), fp_out); 2188 fputs(_("# Value of 'encoding' when this file was written\n"), fp_out);
2182 fprintf(fp_out, "*encoding=%s\n\n", p_enc); 2189 fprintf(fp_out, "*encoding=%s\n\n", p_enc);
2183 #endif 2190 #endif
2184 write_viminfo_search_pattern(fp_out); 2191 write_viminfo_search_pattern(fp_out);
2218 int forceit, 2225 int forceit,
2219 int writing) 2226 int writing)
2220 { 2227 {
2221 int eof; 2228 int eof;
2222 buf_T *buf; 2229 buf_T *buf;
2230 int got_encoding = FALSE;
2223 2231
2224 #ifdef FEAT_CMDHIST 2232 #ifdef FEAT_CMDHIST
2225 prepare_viminfo_history(forceit ? 9999 : 0, writing); 2233 prepare_viminfo_history(forceit ? 9999 : 0, writing);
2226 #endif 2234 #endif
2227 eof = viminfo_readline(virp); 2235 eof = viminfo_readline(virp);
2238 case '\r': 2246 case '\r':
2239 case '\n': 2247 case '\n':
2240 case '#': 2248 case '#':
2241 eof = viminfo_readline(virp); 2249 eof = viminfo_readline(virp);
2242 break; 2250 break;
2243 case '|': /* copy line (for future use) */ 2251 case '|':
2244 if (writing) 2252 eof = read_viminfo_barline(virp, got_encoding, writing);
2245 ga_add_string(&virp->vir_barlines, virp->vir_line);
2246 eof = viminfo_readline(virp);
2247 break; 2253 break;
2248 case '*': /* "*encoding=value" */ 2254 case '*': /* "*encoding=value" */
2255 got_encoding = TRUE;
2249 eof = viminfo_encoding(virp); 2256 eof = viminfo_encoding(virp);
2250 break; 2257 break;
2251 case '!': /* global variable */ 2258 case '!': /* global variable */
2252 #ifdef FEAT_EVAL 2259 #ifdef FEAT_EVAL
2253 eof = read_viminfo_varlist(virp, writing); 2260 eof = read_viminfo_varlist(virp, writing);
2272 case ':': 2279 case ':':
2273 case '?': 2280 case '?':
2274 case '=': 2281 case '=':
2275 case '@': 2282 case '@':
2276 #ifdef FEAT_CMDHIST 2283 #ifdef FEAT_CMDHIST
2277 eof = read_viminfo_history(virp, writing); 2284 /* When history is in bar lines skip the old style history
2278 #else 2285 * lines. */
2279 eof = viminfo_readline(virp); 2286 if (virp->vir_version < VIMINFO_VERSION_WITH_HISTORY)
2280 #endif 2287 eof = read_viminfo_history(virp, writing);
2288 else
2289 #endif
2290 eof = viminfo_readline(virp);
2281 break; 2291 break;
2282 case '-': 2292 case '-':
2283 case '\'': 2293 case '\'':
2284 eof = read_viminfo_filemark(virp, forceit); 2294 eof = read_viminfo_filemark(virp, forceit);
2285 break; 2295 break;
2345 { 2355 {
2346 return vim_fgets(virp->vir_line, LSIZE, virp->vir_fd); 2356 return vim_fgets(virp->vir_line, LSIZE, virp->vir_fd);
2347 } 2357 }
2348 2358
2349 /* 2359 /*
2350 * check string read from viminfo file 2360 * Check string read from viminfo file.
2351 * remove '\n' at the end of the line 2361 * Remove '\n' at the end of the line.
2352 * - replace CTRL-V CTRL-V with CTRL-V 2362 * - replace CTRL-V CTRL-V with CTRL-V
2353 * - replace CTRL-V 'n' with '\n' 2363 * - replace CTRL-V 'n' with '\n'
2354 * 2364 *
2355 * Check for a long line as written by viminfo_writestring(). 2365 * Check for a long line as written by viminfo_writestring().
2356 * 2366 *
2459 c = 'n'; 2469 c = 'n';
2460 } 2470 }
2461 putc(c, fd); 2471 putc(c, fd);
2462 } 2472 }
2463 putc('\n', fd); 2473 putc('\n', fd);
2474 }
2475
2476 /*
2477 * Write a string in quotes that barline_parse() can read back.
2478 * Breaks the line in less than LSIZE pieces when needed.
2479 * Returns remaining characters in the line.
2480 */
2481 int
2482 barline_writestring(FILE *fd, char_u *s, int remaining_start)
2483 {
2484 char_u *p;
2485 int remaining = remaining_start;
2486 int len = 2;
2487
2488 /* Count the number of characters produced, including quotes. */
2489 for (p = s; *p != NUL; ++p)
2490 {
2491 if (*p == NL)
2492 len += 2;
2493 else if (*p == '"' || *p == '\\')
2494 len += 2;
2495 else
2496 ++len;
2497 }
2498 if (len > remaining)
2499 {
2500 fprintf(fd, ">%d\n|<", len);
2501 remaining = LSIZE - 20;
2502 }
2503
2504 putc('"', fd);
2505 for (p = s; *p != NUL; ++p)
2506 {
2507 if (*p == NL)
2508 {
2509 putc('\\', fd);
2510 putc('n', fd);
2511 --remaining;
2512 }
2513 else if (*p == '"' || *p == '\\')
2514 {
2515 putc('\\', fd);
2516 putc(*p, fd);
2517 --remaining;
2518 }
2519 else
2520 putc(*p, fd);
2521 --remaining;
2522
2523 if (remaining < 3)
2524 {
2525 putc('\n', fd);
2526 putc('|', fd);
2527 putc('<', fd);
2528 /* Leave enough space for another continuation. */
2529 remaining = LSIZE - 20;
2530 }
2531 }
2532 putc('"', fd);
2533 return remaining;
2534 }
2535
2536 /*
2537 * Parse a viminfo line starting with '|'.
2538 * Put each decoded value in "values" and return the number of values found.
2539 */
2540 static int
2541 barline_parse(vir_T *virp, char_u *text, bval_T *values)
2542 {
2543 char_u *p = text;
2544 char_u *nextp = NULL;
2545 char_u *buf = NULL;;
2546 int count = 0;
2547 int i;
2548 int allocated = FALSE;
2549
2550 while (*p == ',')
2551 {
2552 if (count == BVAL_MAX)
2553 {
2554 EMSG2(e_intern2, "barline_parse()");
2555 break;
2556 }
2557 ++p;
2558
2559 if (*p == '>')
2560 {
2561 /* Need to read a continuation line. Need to put strings in
2562 * allocated memory, because virp->vir_line is overwritten. */
2563 if (!allocated)
2564 {
2565 for (i = 0; i < count; ++i)
2566 if (values[i].bv_type == BVAL_STRING)
2567 {
2568 values[i].bv_string = vim_strnsave(
2569 values[i].bv_string, values[i].bv_len);
2570 values[i].bv_allocated = TRUE;
2571 }
2572 allocated = TRUE;
2573 }
2574
2575 if (vim_isdigit(p[1]))
2576 {
2577 int len;
2578 int todo;
2579 int n;
2580
2581 /* String value was split into lines that are each shorter
2582 * than LSIZE:
2583 * |{bartype},>{length of "{text}{text2}"}
2584 * |<"{text1}
2585 * |<{text2}",{value}
2586 */
2587 ++p;
2588 len = getdigits(&p);
2589 buf = alloc(len + 1);
2590 p = buf;
2591 for (todo = len; todo > 0; todo -= n)
2592 {
2593 if (viminfo_readline(virp) || virp->vir_line[0] != '|'
2594 || virp->vir_line[1] != '<')
2595 /* file was truncated or garbled */
2596 return 0;
2597 /* Get length of text, excluding |< and NL chars. */
2598 n = STRLEN(virp->vir_line);
2599 while (n > 0 && (virp->vir_line[n - 1] == NL
2600 || virp->vir_line[n - 1] == CAR))
2601 --n;
2602 n -= 2;
2603 if (n > todo)
2604 {
2605 /* more values follow after the string */
2606 nextp = virp->vir_line + 2 + todo;
2607 n = todo;
2608 }
2609 mch_memmove(p, virp->vir_line + 2, n);
2610 p += n;
2611 }
2612 *p = NUL;
2613 p = buf;
2614 }
2615 else
2616 {
2617 /* Line ending in ">" continues in the next line:
2618 * |{bartype},{lots of values},>
2619 * |<{value},{value}
2620 */
2621 if (viminfo_readline(virp) || virp->vir_line[0] != '|'
2622 || virp->vir_line[1] != '<')
2623 /* file was truncated or garbled */
2624 return 0;
2625 p = virp->vir_line + 2;
2626 }
2627 }
2628
2629 if (isdigit(*p))
2630 {
2631 values[count].bv_type = BVAL_NR;
2632 values[count].bv_nr = getdigits(&p);
2633 ++count;
2634 }
2635 else if (*p == '"')
2636 {
2637 int len = 0;
2638 char_u *s = p;
2639
2640 /* Unescape special characters in-place. */
2641 ++p;
2642 while (*p != '"')
2643 {
2644 if (*p == NL || *p == NUL)
2645 return count; /* syntax error, drop the value */
2646 if (*p == '\\')
2647 {
2648 ++p;
2649 if (*p == 'n')
2650 s[len++] = '\n';
2651 else
2652 s[len++] = *p;
2653 ++p;
2654 }
2655 else
2656 s[len++] = *p++;
2657 }
2658 s[len] = NUL;
2659
2660 if (s != buf && allocated)
2661 s = vim_strsave(s);
2662 values[count].bv_string = s;
2663 values[count].bv_type = BVAL_STRING;
2664 values[count].bv_len = len;
2665 values[count].bv_allocated = allocated;
2666 ++count;
2667 if (nextp != NULL)
2668 {
2669 /* values following a long string */
2670 p = nextp;
2671 nextp = NULL;
2672 }
2673 }
2674 else if (*p == ',')
2675 {
2676 values[count].bv_type = BVAL_EMPTY;
2677 ++count;
2678 }
2679 else
2680 break;
2681 }
2682
2683 return count;
2684 }
2685
2686 static int
2687 read_viminfo_barline(vir_T *virp, int got_encoding, int writing)
2688 {
2689 char_u *p = virp->vir_line + 1;
2690 int bartype;
2691 bval_T values[BVAL_MAX];
2692 int count = 0;
2693 int i;
2694
2695 /* The format is: |{bartype},{value},...
2696 * For a very long string:
2697 * |{bartype},>{length of "{text}{text2}"}
2698 * |<{text1}
2699 * |<{text2},{value}
2700 * For a long line not using a string
2701 * |{bartype},{lots of values},>
2702 * |<{value},{value}
2703 */
2704 if (*p == '<')
2705 {
2706 /* Continuation line of an unrecognized item. */
2707 if (writing)
2708 ga_add_string(&virp->vir_barlines, virp->vir_line);
2709 }
2710 else
2711 {
2712 bartype = getdigits(&p);
2713 switch (bartype)
2714 {
2715 case BARTYPE_VERSION:
2716 /* Only use the version when it comes before the encoding.
2717 * If it comes later it was copied by a Vim version that
2718 * doesn't understand the version. */
2719 if (!got_encoding)
2720 {
2721 count = barline_parse(virp, p, values);
2722 if (count > 0 && values[0].bv_type == BVAL_NR)
2723 virp->vir_version = values[0].bv_nr;
2724 }
2725 break;
2726
2727 case BARTYPE_HISTORY:
2728 count = barline_parse(virp, p, values);
2729 handle_viminfo_history(values, count, writing);
2730 break;
2731
2732 default:
2733 /* copy unrecognized line (for future use) */
2734 if (writing)
2735 ga_add_string(&virp->vir_barlines, virp->vir_line);
2736 }
2737 }
2738
2739 for (i = 0; i < count; ++i)
2740 if (values[i].bv_type == BVAL_STRING && values[i].bv_allocated)
2741 vim_free(values[i].bv_string);
2742
2743 return viminfo_readline(virp);
2744 }
2745
2746 static void
2747 write_viminfo_version(FILE *fp_out)
2748 {
2749 fprintf(fp_out, "# Viminfo version\n|%d,%d\n\n",
2750 BARTYPE_VERSION, VIMINFO_VERSION);
2464 } 2751 }
2465 2752
2466 static void 2753 static void
2467 write_viminfo_barlines(vir_T *virp, FILE *fp_out) 2754 write_viminfo_barlines(vir_T *virp, FILE *fp_out)
2468 { 2755 {