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