diff --git a/src/ex_cmds.c b/src/ex_cmds.c index 5e56489a31..b3b920939d 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -1750,7 +1750,7 @@ append_redir( #if defined(FEAT_VIMINFO) || defined(PROTO) static int no_viminfo(void); -static int read_viminfo_barline(vir_T *virp, int got_encoding, int writing); +static int read_viminfo_barline(vir_T *virp, int got_encoding, int force, int writing); static void write_viminfo_version(FILE *fp_out); static void write_viminfo_barlines(vir_T *virp, FILE *fp_out); static int viminfo_errcnt; @@ -2164,6 +2164,10 @@ do_viminfo(FILE *fp_in, FILE *fp_out, int flags) { if (flags & VIF_WANT_INFO) { + /* Registers are read and newer ones are used when writing. */ + if (fp_out != NULL) + prepare_viminfo_registers(); + eof = read_viminfo_up_to_marks(&vir, flags & VIF_FORCEIT, fp_out != NULL); merge = TRUE; @@ -2191,6 +2195,7 @@ do_viminfo(FILE *fp_in, FILE *fp_out, int flags) write_viminfo_history(fp_out, merge); #endif write_viminfo_registers(fp_out); + finish_viminfo_registers(); #ifdef FEAT_EVAL write_viminfo_varlist(fp_out); #endif @@ -2229,6 +2234,7 @@ read_viminfo_up_to_marks( #ifdef FEAT_CMDHIST prepare_viminfo_history(forceit ? 9999 : 0, writing); #endif + eof = viminfo_readline(virp); while (!eof && virp->vir_line[0] != '>') { @@ -2246,7 +2252,8 @@ read_viminfo_up_to_marks( eof = viminfo_readline(virp); break; case '|': - eof = read_viminfo_barline(virp, got_encoding, writing); + eof = read_viminfo_barline(virp, got_encoding, + forceit, writing); break; case '*': /* "*encoding=value" */ got_encoding = TRUE; @@ -2263,7 +2270,15 @@ read_viminfo_up_to_marks( eof = read_viminfo_bufferlist(virp, writing); break; case '"': - eof = read_viminfo_register(virp, forceit); + /* When registers are in bar lines skip the old style register + * lines. */ + if (virp->vir_version < VIMINFO_VERSION_WITH_REGISTERS) + eof = read_viminfo_register(virp, forceit); + else + do { + eof = viminfo_readline(virp); + } while (!eof && (virp->vir_line[0] == TAB + || virp->vir_line[0] == '<')); break; case '/': /* Search string */ case '&': /* Substitute search string */ @@ -2527,45 +2542,50 @@ barline_writestring(FILE *fd, char_u *s, int remaining_start) } } putc('"', fd); - return remaining; + return remaining - 2; } /* * Parse a viminfo line starting with '|'. - * Put each decoded value in "values" and return the number of values found. + * Add each decoded value to "values". */ - static int -barline_parse(vir_T *virp, char_u *text, bval_T *values) + static void +barline_parse(vir_T *virp, char_u *text, garray_T *values) { char_u *p = text; char_u *nextp = NULL; char_u *buf = NULL; - int count = 0; + bval_T *value; int i; int allocated = FALSE; +#ifdef FEAT_MBYTE + char_u *sconv; + int converted; +#endif while (*p == ',') { - if (count == BVAL_MAX) - { - EMSG2(e_intern2, "barline_parse()"); - break; - } ++p; + if (ga_grow(values, 1) == FAIL) + break; + value = (bval_T *)(values->ga_data) + values->ga_len; if (*p == '>') { - /* Need to read a continuation line. Need to put strings in - * allocated memory, because virp->vir_line is overwritten. */ + /* Need to read a continuation line. Put strings in allocated + * memory, because virp->vir_line is overwritten. */ if (!allocated) { - for (i = 0; i < count; ++i) - if (values[i].bv_type == BVAL_STRING) + for (i = 0; i < values->ga_len; ++i) + { + bval_T *vp = (bval_T *)(values->ga_data) + i; + + if (vp->bv_type == BVAL_STRING && !vp->bv_allocated) { - values[i].bv_string = vim_strnsave( - values[i].bv_string, values[i].bv_len); - values[i].bv_allocated = TRUE; + vp->bv_string = vim_strnsave(vp->bv_string, vp->bv_len); + vp->bv_allocated = TRUE; } + } allocated = TRUE; } @@ -2584,13 +2604,18 @@ barline_parse(vir_T *virp, char_u *text, bval_T *values) ++p; len = getdigits(&p); buf = alloc((int)(len + 1)); + if (buf == NULL) + return; p = buf; for (todo = len; todo > 0; todo -= n) { if (viminfo_readline(virp) || virp->vir_line[0] != '|' || virp->vir_line[1] != '<') + { /* file was truncated or garbled */ - return 0; + vim_free(buf); + return; + } /* Get length of text, excluding |< and NL chars. */ n = STRLEN(virp->vir_line); while (n > 0 && (virp->vir_line[n - 1] == NL @@ -2618,16 +2643,16 @@ barline_parse(vir_T *virp, char_u *text, bval_T *values) if (viminfo_readline(virp) || virp->vir_line[0] != '|' || virp->vir_line[1] != '<') /* file was truncated or garbled */ - return 0; + return; p = virp->vir_line + 2; } } if (isdigit(*p)) { - values[count].bv_type = BVAL_NR; - values[count].bv_nr = getdigits(&p); - ++count; + value->bv_type = BVAL_NR; + value->bv_nr = getdigits(&p); + ++values->ga_len; } else if (*p == '"') { @@ -2639,7 +2664,7 @@ barline_parse(vir_T *virp, char_u *text, bval_T *values) while (*p != '"') { if (*p == NL || *p == NUL) - return count; /* syntax error, drop the value */ + return; /* syntax error, drop the value */ if (*p == '\\') { ++p; @@ -2652,15 +2677,37 @@ barline_parse(vir_T *virp, char_u *text, bval_T *values) else s[len++] = *p++; } + ++p; s[len] = NUL; +#ifdef FEAT_MBYTE + converted = FALSE; + if (virp->vir_conv.vc_type != CONV_NONE && *s != NUL) + { + sconv = string_convert(&virp->vir_conv, s, NULL); + if (sconv != NULL) + { + if (s == buf) + vim_free(s); + s = sconv; + buf = s; + converted = TRUE; + } + } +#endif + /* Need to copy in allocated memory if the string wasn't allocated + * above and we did allocate before, thus vir_line may change. */ if (s != buf && allocated) s = vim_strsave(s); - values[count].bv_string = s; - values[count].bv_type = BVAL_STRING; - values[count].bv_len = len; - values[count].bv_allocated = allocated; - ++count; + value->bv_string = s; + value->bv_type = BVAL_STRING; + value->bv_len = len; + value->bv_allocated = allocated +#ifdef FEAT_MBYTE + || converted +#endif + ; + ++values->ga_len; if (nextp != NULL) { /* values following a long string */ @@ -2670,23 +2717,21 @@ barline_parse(vir_T *virp, char_u *text, bval_T *values) } else if (*p == ',') { - values[count].bv_type = BVAL_EMPTY; - ++count; + value->bv_type = BVAL_EMPTY; + ++values->ga_len; } else break; } - - return count; } static int -read_viminfo_barline(vir_T *virp, int got_encoding, int writing) +read_viminfo_barline(vir_T *virp, int got_encoding, int force, int writing) { char_u *p = virp->vir_line + 1; int bartype; - bval_T values[BVAL_MAX]; - int count = 0; + garray_T values; + bval_T *vp; int i; /* The format is: |{bartype},{value},... @@ -2706,6 +2751,7 @@ read_viminfo_barline(vir_T *virp, int got_encoding, int writing) } else { + ga_init2(&values, sizeof(bval_T), 20); bartype = getdigits(&p); switch (bartype) { @@ -2715,15 +2761,21 @@ read_viminfo_barline(vir_T *virp, int got_encoding, int writing) * doesn't understand the version. */ if (!got_encoding) { - count = barline_parse(virp, p, values); - if (count > 0 && values[0].bv_type == BVAL_NR) - virp->vir_version = values[0].bv_nr; + barline_parse(virp, p, &values); + vp = (bval_T *)values.ga_data; + if (values.ga_len > 0 && vp->bv_type == BVAL_NR) + virp->vir_version = vp->bv_nr; } break; case BARTYPE_HISTORY: - count = barline_parse(virp, p, values); - handle_viminfo_history(values, count, writing); + barline_parse(virp, p, &values); + handle_viminfo_history(&values, writing); + break; + + case BARTYPE_REGISTER: + barline_parse(virp, p, &values); + handle_viminfo_register(&values, force); break; default: @@ -2731,12 +2783,15 @@ read_viminfo_barline(vir_T *virp, int got_encoding, int writing) if (writing) ga_add_string(&virp->vir_barlines, virp->vir_line); } + for (i = 0; i < values.ga_len; ++i) + { + vp = (bval_T *)values.ga_data + i; + if (vp->bv_type == BVAL_STRING && vp->bv_allocated) + vim_free(vp->bv_string); + } + ga_clear(&values); } - for (i = 0; i < count; ++i) - if (values[i].bv_type == BVAL_STRING && values[i].bv_allocated) - vim_free(values[i].bv_string); - return viminfo_readline(virp); } @@ -2763,6 +2818,22 @@ write_viminfo_barlines(vir_T *virp, FILE *fp_out) } #endif /* FEAT_VIMINFO */ +#if defined(FEAT_CMDHIST) || defined(FEAT_VIMINFO) || defined(PROTO) +/* + * Return the current time in seconds. Calls time(), unless test_settime() + * was used. + */ + time_t +vim_time(void) +{ +# ifdef FEAT_EVAL + return time_for_testing == 0 ? time(NULL) : time_for_testing; +# else + return time(NULL); +# endif +} +#endif + /* * Implementation of ":fixdel", also used by get_stty(). * resulting diff --git a/src/ex_getln.c b/src/ex_getln.c index 4badaf6238..7f9e54f529 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -5422,20 +5422,6 @@ 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 @@ -6294,34 +6280,34 @@ read_viminfo_history(vir_T *virp, int writing) */ void handle_viminfo_history( - bval_T *values, - int count, - int writing) + garray_T *values, + int writing) { int type; long_u len; char_u *val; char_u *p; + bval_T *vp = (bval_T *)values->ga_data; /* 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) + if (values->ga_len < 4 + || vp[0].bv_type != BVAL_NR + || vp[1].bv_type != BVAL_NR + || (vp[2].bv_type != BVAL_NR && vp[2].bv_type != BVAL_EMPTY) + || vp[3].bv_type != BVAL_STRING) return; - type = values[0].bv_nr; + type = vp[0].bv_nr; if (type >= HIST_COUNT) return; if (viminfo_hisidx[type] < viminfo_hislen[type]) { - val = values[3].bv_string; + val = vp[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 sep = type == HIST_SEARCH && vp[2].bv_type == BVAL_NR + ? vp[2].bv_nr : NUL; int idx; int overwrite = FALSE; @@ -6343,12 +6329,12 @@ handle_viminfo_history( if (!overwrite) { /* Need to re-allocate to append the separator byte. */ - len = values[3].bv_len; + len = vp[3].bv_len; p = lalloc(len + 2, TRUE); } if (p != NULL) { - viminfo_history[type][idx].time_set = values[1].bv_nr; + viminfo_history[type][idx].time_set = vp[1].bv_nr; if (!overwrite) { mch_memmove(p, val, (size_t)len + 1); @@ -6485,6 +6471,7 @@ merge_history(int type) vim_free(history[type][i].hisstr); vim_free(history[type]); history[type] = new_hist; + vim_free(tot_hist); } /* diff --git a/src/if_ruby.c b/src/if_ruby.c index 0b384e834a..312017ea11 100644 --- a/src/if_ruby.c +++ b/src/if_ruby.c @@ -31,6 +31,10 @@ # define RUBYEXTERN extern #endif +# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 24 + # define USE_RUBY_Integer +#endif + #ifdef DYNAMIC_RUBY /* * This is tricky. In ruby.h there is (inline) function rb_class_of() @@ -39,6 +43,9 @@ */ # define rb_cFalseClass (*dll_rb_cFalseClass) # define rb_cFixnum (*dll_rb_cFixnum) +# if defined(USE_RUBY_Integer) +# define rb_cInteger (*dll_rb_cInteger) +# endif # if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 20 # define rb_cFloat (*dll_rb_cFloat) # endif @@ -326,6 +333,9 @@ static void ruby_vim_init(void); static VALUE (*dll_rb_assoc_new) (VALUE, VALUE); VALUE *dll_rb_cFalseClass; VALUE *dll_rb_cFixnum; +# if defined(USE_RUBY_Integer) +VALUE *dll_rb_cInteger; +# endif # if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 20 VALUE *dll_rb_cFloat; # endif @@ -513,6 +523,9 @@ static struct {"rb_assoc_new", (RUBY_PROC*)&dll_rb_assoc_new}, {"rb_cFalseClass", (RUBY_PROC*)&dll_rb_cFalseClass}, {"rb_cFixnum", (RUBY_PROC*)&dll_rb_cFixnum}, +# if defined(USE_RUBY_Integer) + {"rb_cInteger", (RUBY_PROC*)&dll_rb_cInteger}, +# endif # if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 20 {"rb_cFloat", (RUBY_PROC*)&dll_rb_cFloat}, # endif diff --git a/src/ops.c b/src/ops.c index 35f2d2e95f..ed291d06e9 100644 --- a/src/ops.c +++ b/src/ops.c @@ -50,19 +50,24 @@ #endif /* - * Each yank register is an array of pointers to lines. + * Each yank register has an array of pointers to lines. */ -static struct yankreg +typedef struct { char_u **y_array; /* pointer to array of line pointers */ linenr_T y_size; /* number of lines in y_array */ char_u y_type; /* MLINE, MCHAR or MBLOCK */ colnr_T y_width; /* only set if y_type == MBLOCK */ -} y_regs[NUM_REGISTERS]; +#ifdef FEAT_VIMINFO + time_t y_time_set; +#endif +} yankreg_T; -static struct yankreg *y_current; /* ptr to current yankreg */ +static yankreg_T y_regs[NUM_REGISTERS]; + +static yankreg_T *y_current; /* ptr to current yankreg */ static int y_append; /* TRUE when appending */ -static struct yankreg *y_previous = NULL; /* ptr to last written yankreg */ +static yankreg_T *y_previous = NULL; /* ptr to last written yankreg */ /* * structure used by block_prep, op_delete and op_yank for blockwise operators @@ -104,7 +109,7 @@ static void free_yank(long); static void free_yank_all(void); static int yank_copy_line(struct block_def *bd, long y_idx); #ifdef FEAT_CLIPBOARD -static void copy_yank_reg(struct yankreg *reg); +static void copy_yank_reg(yankreg_T *reg); static void may_set_selection(void); #endif static void dis_msg(char_u *p, int skip_esc); @@ -114,7 +119,7 @@ static char_u *skip_comment(char_u *line, int process, int include_space, int *i static void block_prep(oparg_T *oap, struct block_def *, linenr_T, int); static int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1); #if defined(FEAT_CLIPBOARD) || defined(FEAT_EVAL) -static void str_to_reg(struct yankreg *y_ptr, int yank_type, char_u *str, long len, long blocklen, int str_list); +static void str_to_reg(yankreg_T *y_ptr, int yank_type, char_u *str, long len, long blocklen, int str_list); #endif static int ends_in_white(linenr_T lnum); #ifdef FEAT_COMMENTS @@ -964,8 +969,8 @@ get_register( int name, int copy) /* make a copy, if FALSE make register empty. */ { - struct yankreg *reg; - int i; + yankreg_T *reg; + int i; #ifdef FEAT_CLIPBOARD /* When Visual area changed, may have to update selection. Obtain the @@ -985,7 +990,7 @@ get_register( #endif get_yank_register(name, 0); - reg = (struct yankreg *)alloc((unsigned)sizeof(struct yankreg)); + reg = (yankreg_T *)alloc((unsigned)sizeof(yankreg_T)); if (reg != NULL) { *reg = *y_current; @@ -1017,7 +1022,7 @@ put_register(int name, void *reg) { get_yank_register(name, 0); free_yank_all(); - *y_current = *(struct yankreg *)reg; + *y_current = *(yankreg_T *)reg; vim_free(reg); #ifdef FEAT_CLIPBOARD @@ -1029,10 +1034,10 @@ put_register(int name, void *reg) void free_register(void *reg) { - struct yankreg tmp; + yankreg_T tmp; tmp = *y_current; - *y_current = *(struct yankreg *)reg; + *y_current = *(yankreg_T *)reg; free_yank_all(); vim_free(reg); *y_current = tmp; @@ -1064,7 +1069,7 @@ do_record(int c) { char_u *p; static int regname; - struct yankreg *old_y_previous, *old_y_current; + yankreg_T *old_y_previous, *old_y_current; int retval; if (Recording == FALSE) /* start recording */ @@ -1164,6 +1169,9 @@ stuff_yank(int regname, char_u *p) y_current->y_array[0] = p; y_current->y_size = 1; y_current->y_type = MCHAR; /* used to be MLINE, why? */ +#ifdef FEAT_VIMINFO + y_current->y_time_set = vim_time(); +#endif } return OK; } @@ -2907,8 +2915,8 @@ free_yank_all(void) op_yank(oparg_T *oap, int deleting, int mess) { long y_idx; /* index in y_array[] */ - struct yankreg *curr; /* copy of y_current */ - struct yankreg newreg; /* new yank register when appending */ + yankreg_T *curr; /* copy of y_current */ + yankreg_T newreg; /* new yank register when appending */ char_u **new_ptr; linenr_T lnum; /* current line number */ long j; @@ -2970,12 +2978,14 @@ op_yank(oparg_T *oap, int deleting, int mess) y_current->y_width = 0; y_current->y_array = (char_u **)lalloc_clear((long_u)(sizeof(char_u *) * yanklines), TRUE); - if (y_current->y_array == NULL) { y_current = curr; return FAIL; } +#ifdef FEAT_VIMINFO + y_current->y_time_set = vim_time(); +#endif y_idx = 0; lnum = oap->start.lnum; @@ -3102,6 +3112,9 @@ op_yank(oparg_T *oap, int deleting, int mess) new_ptr[j] = curr->y_array[j]; vim_free(curr->y_array); curr->y_array = new_ptr; +#ifdef FEAT_VIMINFO + curr->y_time_set = vim_time(); +#endif if (yanktype == MLINE) /* MLINE overrides MCHAR and MBLOCK */ curr->y_type = MLINE; @@ -3252,10 +3265,10 @@ yank_copy_line(struct block_def *bd, long y_idx) * Make a copy of the y_current register to register "reg". */ static void -copy_yank_reg(struct yankreg *reg) +copy_yank_reg(yankreg_T *reg) { - struct yankreg *curr = y_current; - long j; + yankreg_T *curr = y_current; + long j; y_current = reg; free_yank_all(); @@ -4013,7 +4026,9 @@ preprocs_left(void) } #endif -/* Return the character name of the register with the given number */ +/* + * Return the character name of the register with the given number. + */ int get_register_name(int num) { @@ -4053,15 +4068,15 @@ get_register_name(int num) void ex_display(exarg_T *eap) { - int i, n; - long j; - char_u *p; - struct yankreg *yb; - int name; - int attr; - char_u *arg = eap->arg; + int i, n; + long j; + char_u *p; + yankreg_T *yb; + int name; + int attr; + char_u *arg = eap->arg; #ifdef FEAT_MBYTE - int clen; + int clen; #else # define clen 1 #endif @@ -5794,6 +5809,42 @@ theend: } #ifdef FEAT_VIMINFO + +static yankreg_T *y_read_regs = NULL; + +#define REG_PREVIOUS 1 +#define REG_EXEC 2 + +/* + * Prepare for reading viminfo registers when writing viminfo later. + */ + void +prepare_viminfo_registers() +{ + y_read_regs = (yankreg_T *)alloc_clear(NUM_REGISTERS + * (int)sizeof(yankreg_T)); +} + + void +finish_viminfo_registers() +{ + int i; + int j; + + if (y_read_regs != NULL) + { + for (i = 0; i < NUM_REGISTERS; ++i) + if (y_read_regs[i].y_array != NULL) + { + for (j = 0; j < y_read_regs[i].y_size; j++) + vim_free(y_read_regs[i].y_array[j]); + vim_free(y_read_regs[i].y_array); + } + vim_free(y_read_regs); + y_read_regs = NULL; + } +} + int read_viminfo_register(vir_T *virp, int force) { @@ -5900,6 +5951,7 @@ read_viminfo_register(vir_T *virp, int force) y_current->y_type = new_type; y_current->y_width = new_width; y_current->y_size = size; + y_current->y_time_set = 0; if (size == 0) { y_current->y_array = NULL; @@ -5929,16 +5981,106 @@ read_viminfo_register(vir_T *virp, int force) return eof; } +/* + * Accept a new style register line from the viminfo, store it when it's new. + */ + void +handle_viminfo_register(garray_T *values, int force) +{ + bval_T *vp = (bval_T *)values->ga_data; + int flags; + int name; + int type; + int linecount; + int width; + time_t timestamp; + yankreg_T *y_ptr; + int i; + + /* Check the format: + * |{bartype},{flags},{name},{type}, + * {linecount},{width},{timestamp},"line1","line2" + */ + if (values->ga_len < 6 + || vp[0].bv_type != BVAL_NR + || vp[1].bv_type != BVAL_NR + || vp[2].bv_type != BVAL_NR + || vp[3].bv_type != BVAL_NR + || vp[4].bv_type != BVAL_NR + || vp[5].bv_type != BVAL_NR) + return; + flags = vp[0].bv_nr; + name = vp[1].bv_nr; + if (name < 0 || name > NUM_REGISTERS) + return; + type = vp[2].bv_nr; + if (type != MCHAR && type != MLINE && type != MBLOCK) + return; + linecount = vp[3].bv_nr; + if (values->ga_len < 6 + linecount) + return; + width = vp[4].bv_nr; + if (width < 0) + return; + + if (y_read_regs != NULL) + /* Reading viminfo for merging and writing. Store the register + * content, don't update the current registers. */ + y_ptr = &y_read_regs[name]; + else + y_ptr = &y_regs[name]; + + /* Do not overwrite unless forced or the timestamp is newer. */ + timestamp = (time_t)vp[5].bv_nr; + if (y_ptr->y_array != NULL && !force + && (timestamp == 0 || y_ptr->y_time_set > timestamp)) + return; + + for (i = 0; i < y_ptr->y_size; i++) + vim_free(y_ptr->y_array[i]); + vim_free(y_ptr->y_array); + + if (y_read_regs == NULL) + { + if (flags & REG_PREVIOUS) + y_previous = y_ptr; + if ((flags & REG_EXEC) && (force || execreg_lastc == NUL)) + execreg_lastc = get_register_name(name); + } + y_ptr->y_type = type; + y_ptr->y_width = width; + y_ptr->y_size = linecount; + y_ptr->y_time_set = timestamp; + if (linecount == 0) + y_ptr->y_array = NULL; + else + { + y_ptr->y_array = + (char_u **)alloc((unsigned)(linecount * sizeof(char_u *))); + for (i = 0; i < linecount; i++) + { + if (vp[i + 6].bv_allocated) + { + y_ptr->y_array[i] = vp[i + 6].bv_string; + vp[i + 6].bv_string = NULL; + } + else + y_ptr->y_array[i] = vim_strsave(vp[i + 6].bv_string); + } + } +} + void write_viminfo_registers(FILE *fp) { - int i, j; - char_u *type; - char_u c; - int num_lines; - int max_num_lines; - int max_kbyte; - long len; + int i, j; + char_u *type; + char_u c; + int num_lines; + int max_num_lines; + int max_kbyte; + long len; + yankreg_T *y_ptr; fputs(_("\n# Registers:\n"), fp); @@ -5954,8 +6096,6 @@ write_viminfo_registers(FILE *fp) for (i = 0; i < NUM_REGISTERS; i++) { - if (y_regs[i].y_array == NULL) - continue; #ifdef FEAT_CLIPBOARD /* Skip '*'/'+' register, we don't want them back next time */ if (i == STAR_REGISTER || i == PLUS_REGISTER) @@ -5966,11 +6106,23 @@ write_viminfo_registers(FILE *fp) if (i == TILDE_REGISTER) continue; #endif + /* When reading viminfo for merging and writing: Use the register from + * viminfo if it's newer. */ + if (y_read_regs != NULL + && y_read_regs[i].y_array != NULL + && (y_regs[i].y_array == NULL || + y_read_regs[i].y_time_set > y_regs[i].y_time_set)) + y_ptr = &y_read_regs[i]; + else if (y_regs[i].y_array == NULL) + continue; + else + y_ptr = &y_regs[i]; + /* Skip empty registers. */ - num_lines = y_regs[i].y_size; + num_lines = y_ptr->y_size; if (num_lines == 0 - || (num_lines == 1 && y_regs[i].y_type == MCHAR - && *y_regs[i].y_array[0] == NUL)) + || (num_lines == 1 && y_ptr->y_type == MCHAR + && *y_ptr->y_array[0] == NUL)) continue; if (max_kbyte > 0) @@ -5978,12 +6130,12 @@ write_viminfo_registers(FILE *fp) /* Skip register if there is more text than the maximum size. */ len = 0; for (j = 0; j < num_lines; j++) - len += (long)STRLEN(y_regs[i].y_array[j]) + 1L; + len += (long)STRLEN(y_ptr->y_array[j]) + 1L; if (len > (long)max_kbyte * 1024L) continue; } - switch (y_regs[i].y_type) + switch (y_ptr->y_type) { case MLINE: type = (char_u *)"LINE"; @@ -5996,7 +6148,7 @@ write_viminfo_registers(FILE *fp) break; default: sprintf((char *)IObuff, _("E574: Unknown register type %d"), - y_regs[i].y_type); + y_ptr->y_type); emsg(IObuff); type = (char_u *)"LINE"; break; @@ -6007,7 +6159,7 @@ write_viminfo_registers(FILE *fp) fprintf(fp, "\"%c", c); if (c == execreg_lastc) fprintf(fp, "@"); - fprintf(fp, "\t%s\t%d\n", type, (int)y_regs[i].y_width); + fprintf(fp, "\t%s\t%d\n", type, (int)y_ptr->y_width); /* If max_num_lines < 0, then we save ALL the lines in the register */ if (max_num_lines > 0 && num_lines > max_num_lines) @@ -6015,7 +6167,36 @@ write_viminfo_registers(FILE *fp) for (j = 0; j < num_lines; j++) { putc('\t', fp); - viminfo_writestring(fp, y_regs[i].y_array[j]); + viminfo_writestring(fp, y_ptr->y_array[j]); + } + + { + int flags = 0; + int remaining; + + /* New style with a bar line. Format: + * |{bartype},{flags},{name},{type}, + * {linecount},{width},{timestamp},"line1","line2" + * flags: REG_PREVIOUS - register is y_previous + * REG_EXEC - used for @@ + */ + if (y_previous == &y_regs[i]) + flags |= REG_PREVIOUS; + if (c == execreg_lastc) + flags |= REG_EXEC; + fprintf(fp, "|%d,%d,%d,%d,%d,%d,%ld", BARTYPE_REGISTER, flags, + i, y_ptr->y_type, num_lines, (int)y_ptr->y_width, + (long)y_ptr->y_time_set); + /* 11 chars for type/flags/name/type, 3 * 20 for numbers */ + remaining = LSIZE - 71; + for (j = 0; j < num_lines; j++) + { + putc(',', fp); + --remaining; + remaining = barline_writestring(fp, y_ptr->y_array[j], + remaining); + } + putc('\n', fp); } } } @@ -6133,7 +6314,7 @@ x11_export_final_selection(void) void clip_free_selection(VimClipboard *cbd) { - struct yankreg *y_ptr = y_current; + yankreg_T *y_ptr = y_current; if (cbd == &clip_plus) y_current = &y_regs[PLUS_REGISTER]; @@ -6150,7 +6331,7 @@ clip_free_selection(VimClipboard *cbd) void clip_get_selection(VimClipboard *cbd) { - struct yankreg *old_y_previous, *old_y_current; + yankreg_T *old_y_previous, *old_y_current; pos_T old_cursor; pos_T old_visual; int old_visual_mode; @@ -6215,7 +6396,7 @@ clip_yank_selection( long len, VimClipboard *cbd) { - struct yankreg *y_ptr; + yankreg_T *y_ptr; if (cbd == &clip_plus) y_ptr = &y_regs[PLUS_REGISTER]; @@ -6239,7 +6420,7 @@ clip_convert_selection(char_u **str, long_u *len, VimClipboard *cbd) int lnum; int i, j; int_u eolsize; - struct yankreg *y_ptr; + yankreg_T *y_ptr; if (cbd == &clip_plus) y_ptr = &y_regs[PLUS_REGISTER]; @@ -6322,7 +6503,7 @@ may_set_selection(void) void dnd_yank_drag_data(char_u *str, long len) { - struct yankreg *curr; + yankreg_T *curr; curr = y_current; y_current = &y_regs[TILDE_REGISTER]; @@ -6518,11 +6699,11 @@ get_reg_contents(int regname, int flags) static int init_write_reg( - int name, - struct yankreg **old_y_previous, - struct yankreg **old_y_current, - int must_append, - int *yank_type UNUSED) + int name, + yankreg_T **old_y_previous, + yankreg_T **old_y_current, + int must_append, + int *yank_type UNUSED) { if (!valid_yank_reg(name, TRUE)) /* check for valid reg name */ { @@ -6542,9 +6723,9 @@ init_write_reg( static void finish_write_reg( - int name, - struct yankreg *old_y_previous, - struct yankreg *old_y_current) + int name, + yankreg_T *old_y_previous, + yankreg_T *old_y_current) { # ifdef FEAT_CLIPBOARD /* Send text of clipboard register to the clipboard. */ @@ -6585,7 +6766,7 @@ write_reg_contents_lst( int yank_type, long block_len) { - struct yankreg *old_y_previous, *old_y_current; + yankreg_T *old_y_previous, *old_y_current; if (name == '/' #ifdef FEAT_EVAL @@ -6630,8 +6811,8 @@ write_reg_contents_ex( int yank_type, long block_len) { - struct yankreg *old_y_previous, *old_y_current; - long len; + yankreg_T *old_y_previous, *old_y_current; + long len; if (maxlen >= 0) len = maxlen; @@ -6705,12 +6886,12 @@ write_reg_contents_ex( */ static void str_to_reg( - struct yankreg *y_ptr, /* pointer to yank register */ - int yank_type, /* MCHAR, MLINE, MBLOCK, MAUTO */ - char_u *str, /* string to put in register */ - long len, /* length of string */ - long blocklen, /* width of Visual block */ - int str_list) /* TRUE if str is char_u ** */ + yankreg_T *y_ptr, /* pointer to yank register */ + int yank_type, /* MCHAR, MLINE, MBLOCK, MAUTO */ + char_u *str, /* string to put in register */ + long len, /* length of string */ + long blocklen, /* width of Visual block */ + int str_list) /* TRUE if str is char_u ** */ { int type; /* MCHAR, MLINE or MBLOCK */ int lnum; @@ -6840,6 +7021,9 @@ str_to_reg( y_ptr->y_width = (blocklen < 0 ? maxlen - 1 : blocklen); else y_ptr->y_width = 0; +#ifdef FEAT_VIMINFO + y_ptr->y_time_set = vim_time(); +#endif } #endif /* FEAT_CLIPBOARD || FEAT_EVAL || PROTO */ diff --git a/src/proto/ex_cmds.pro b/src/proto/ex_cmds.pro index 3057a9310f..bc624bf2f1 100644 --- a/src/proto/ex_cmds.pro +++ b/src/proto/ex_cmds.pro @@ -17,6 +17,7 @@ int viminfo_readline(vir_T *virp); char_u *viminfo_readstring(vir_T *virp, int off, int convert); void viminfo_writestring(FILE *fd, char_u *p); int barline_writestring(FILE *fd, char_u *s, int remaining_start); +time_t vim_time(void); void do_fixdel(exarg_T *eap); void print_line_no_prefix(linenr_T lnum, int use_number, int list); void print_line(linenr_T lnum, int use_number, int list); diff --git a/src/proto/ex_getln.pro b/src/proto/ex_getln.pro index 8737877819..581bfcebb4 100644 --- a/src/proto/ex_getln.pro +++ b/src/proto/ex_getln.pro @@ -50,7 +50,7 @@ int get_list_range(char_u **str, int *num1, int *num2); void ex_history(exarg_T *eap); void prepare_viminfo_history(int asklen, int writing); int read_viminfo_history(vir_T *virp, int writing); -void handle_viminfo_history(bval_T *values, int count, int writing); +void handle_viminfo_history(garray_T *values, int writing); void finish_viminfo_history(vir_T *virp); void write_viminfo_history(FILE *fp, int merge); void cmd_pchar(int c, int offset); diff --git a/src/proto/ops.pro b/src/proto/ops.pro index 27cbea285b..5a603d004f 100644 --- a/src/proto/ops.pro +++ b/src/proto/ops.pro @@ -44,7 +44,10 @@ int fex_format(linenr_T lnum, long count, int c); void format_lines(linenr_T line_count, int avoid_fex); int paragraph_start(linenr_T lnum); void op_addsub(oparg_T *oap, linenr_T Prenum1, int g_cmd); +void prepare_viminfo_registers(void); +void finish_viminfo_registers(void); int read_viminfo_register(vir_T *virp, int force); +void handle_viminfo_register(garray_T *values, int writing); void write_viminfo_registers(FILE *fp); void x11_export_final_selection(void); void clip_free_selection(VimClipboard *cbd); diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak index 59fff145f0..57f8283f09 100644 --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -169,6 +169,7 @@ NEW_TESTS = test_arglist.res \ test_backspace_opt.res \ test_cdo.res \ test_channel.res \ + test_cmdline.res \ test_hardcopy.res \ test_history.res \ test_increment.res \ diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim new file mode 100644 index 0000000000..69dc9cdc05 --- /dev/null +++ b/src/testdir/test_cmdline.vim @@ -0,0 +1,26 @@ +" Tests for editing the command line. + +func Test_complete_tab() + call writefile(['testfile'], 'Xtestfile') + call feedkeys(":e Xtest\t\r", "tx") + call assert_equal('testfile', getline(1)) + call delete('Xtestfile') +endfunc + +func Test_complete_list() + " We can't see the output, but at least we check the code runs properly. + call feedkeys(":e test\\r", "tx") + call assert_equal('test', expand('%:t')) +endfunc + +func Test_complete_wildmenu() + call writefile(['testfile1'], 'Xtestfile1') + call writefile(['testfile2'], 'Xtestfile2') + set wildmenu + call feedkeys(":e Xtest\t\t\r", "tx") + call assert_equal('testfile2', getline(1)) + + call delete('Xtestfile1') + call delete('Xtestfile2') + set nowildmenu +endfunc diff --git a/src/testdir/test_viminfo.vim b/src/testdir/test_viminfo.vim index 279b1c3d18..b68b8ce586 100644 --- a/src/testdir/test_viminfo.vim +++ b/src/testdir/test_viminfo.vim @@ -17,9 +17,9 @@ function Test_read_and_write() let lines = readfile('Xviminfo') let done = 0 for line in lines - if line[0] == '|' + if line[0] == '|' && line !~ '^|3,' if done == 0 - call assert_equal('|1,2', line) + call assert_equal('|1,3', line) elseif done == 1 call assert_equal('|copied as-is', line) elseif done == 2 @@ -179,3 +179,81 @@ func Test_cmdline_history_order() call delete('Xviminfo') endfunc + +func Test_viminfo_registers() + call test_settime(8) + call setreg('a', "eight", 'c') + call test_settime(20) + call setreg('b', ["twenty", "again"], 'l') + call test_settime(40) + call setreg('c', ["four", "agai"], 'b4') + let l = [] + set viminfo='100,<600,s10,h,!,nviminfo + for i in range(500) + call add(l, 'something') + endfor + call setreg('d', l, 'l') + wviminfo Xviminfo + + call test_settime(10) + call setreg('a', '', 'b10') + call test_settime(15) + call setreg('b', 'drop') + call test_settime(50) + call setreg('c', 'keep', 'l') + call test_settime(30) + call setreg('d', 'drop', 'l') + rviminfo Xviminfo + + call assert_equal("", getreg('a')) + call assert_equal("\10", getregtype('a')) + call assert_equal("twenty\nagain\n", getreg('b')) + call assert_equal("V", getregtype('b')) + call assert_equal("keep\n", getreg('c')) + call assert_equal("V", getregtype('c')) + call assert_equal(l, getreg('d', 1, 1)) + call assert_equal("V", getregtype('d')) + + call delete('Xviminfo') +endfunc + +func Test_viminfo_encoding() + if !has('multi_byte') + return + endif + set enc=latin1 + call histdel(':') + call histadd(':', "echo '\xe9'") + wviminfo Xviminfo + + set fencs=utf-8,latin1 + set enc=utf-8 + sp Xviminfo + call assert_equal('latin1', &fenc) + close + + call histdel(':') + rviminfo Xviminfo + call assert_equal("echo 'é'", histget(':', -1)) + + call delete('Xviminfo') +endfunc + +func Test_viminfo_bad_syntax() + let lines = [] + call add(lines, '|<') " empty continuation line + call add(lines, '|234234234234234324,nothing') + call add(lines, '|1+"no comma"') + call add(lines, '|1,2,3,4,5,6,7') " too many items + call add(lines, '|1,"string version"') + call add(lines, '|1,>x') " bad continuation line + call add(lines, '|1,"x') " missing quote + call add(lines, '|1,"x\') " trailing backslash + call add(lines, '|1,,,,') "trailing comma + call add(lines, '|1,>234') " trailing continuation line + call writefile(lines, 'Xviminfo') + rviminfo Xviminfo + + call delete('Xviminfo') +endfunc + diff --git a/src/version.c b/src/version.c index 509a8ecfc3..dec9c2303c 100644 --- a/src/version.c +++ b/src/version.c @@ -768,6 +768,20 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1923, +/**/ + 1922, +/**/ + 1921, +/**/ + 1920, +/**/ + 1919, +/**/ + 1918, +/**/ + 1917, /**/ 1916, /**/ diff --git a/src/vim.h b/src/vim.h index 536e260a35..2969abf1b7 100644 --- a/src/vim.h +++ b/src/vim.h @@ -1078,9 +1078,11 @@ extern char *(*dyn_libintl_textdomain)(const char *domainname); /* The type numbers are fixed for backwards compatibility. */ #define BARTYPE_VERSION 1 #define BARTYPE_HISTORY 2 +#define BARTYPE_REGISTER 3 -#define VIMINFO_VERSION 2 +#define VIMINFO_VERSION 3 #define VIMINFO_VERSION_WITH_HISTORY 2 +#define VIMINFO_VERSION_WITH_REGISTERS 3 typedef enum { BVAL_NR, @@ -1088,8 +1090,6 @@ typedef enum { BVAL_EMPTY } btype_T; -#define BVAL_MAX 4 /* Maximum number of fields in a barline. */ - typedef struct { btype_T bv_type; long bv_nr;