diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/ex_cmds.lua | 29 | ||||
-rw-r--r-- | src/nvim/ex_cmds2.c | 44 | ||||
-rw-r--r-- | src/nvim/ex_cmds_defs.h | 1 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 48 | ||||
-rw-r--r-- | src/nvim/if_cscope.c | 16 | ||||
-rw-r--r-- | src/nvim/os/win_defs.h | 4 | ||||
-rw-r--r-- | src/nvim/quickfix.c | 220 | ||||
-rw-r--r-- | src/nvim/screen.c | 25 | ||||
-rw-r--r-- | src/nvim/shada.c | 107 | ||||
-rw-r--r-- | src/nvim/testdir/Makefile | 1 | ||||
-rw-r--r-- | src/nvim/testdir/test_breakindent.in | 2 | ||||
-rw-r--r-- | src/nvim/testdir/test_cdo.in | 107 | ||||
-rw-r--r-- | src/nvim/testdir/test_cdo.ok | 66 | ||||
-rw-r--r-- | src/nvim/testdir/test_eval.in | 33 | ||||
-rw-r--r-- | src/nvim/testdir/test_eval.ok | bin | 11106 -> 10814 bytes | |||
-rw-r--r-- | src/nvim/version.c | 14 |
16 files changed, 597 insertions, 120 deletions
diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index b7a3505c99..702abf3cf0 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -34,6 +34,7 @@ local ADDR_ARGUMENTS = 2 local ADDR_LOADED_BUFFERS = 3 local ADDR_BUFFERS = 4 local ADDR_TABS = 5 +local ADDR_QUICKFIX = 6 -- The following table is described in ex_cmds_defs.h file. return { @@ -374,6 +375,12 @@ return { func='ex_cd', }, { + command='cdo', + flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, NOTADR, DFLALL), + addr_type=ADDR_QUICKFIX, + func='ex_listdo', + }, + { command='center', flags=bit.bor(TRLBAR, RANGE, WHOLEFOLD, EXTRA, CMDWIN, MODIFY), addr_type=ADDR_LINES, @@ -391,6 +398,14 @@ return { addr_type=ADDR_LINES, func='ex_cfile', }, + -- Even though 'cfdo' is alphabetically lower than 'cfile', it is after + -- 'cfile' in this cmd list to support the existing ":cf" abbreviation. + { + command='cfdo', + flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, NOTADR, DFLALL), + addr_type=ADDR_QUICKFIX, + func='ex_listdo', + }, { command='cfirst', flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG), @@ -1286,6 +1301,12 @@ return { func='do_cscope', }, { + command='ldo', + flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, NOTADR, DFLALL), + addr_type=ADDR_QUICKFIX, + func='ex_listdo', + }, + { command='left', flags=bit.bor(TRLBAR, RANGE, WHOLEFOLD, EXTRA, CMDWIN, MODIFY), addr_type=ADDR_LINES, @@ -1315,6 +1336,14 @@ return { addr_type=ADDR_LINES, func='ex_cfile', }, + -- Even though 'lfdo' is alphabetically lower than 'lfile', it is after + -- 'lfile' in this cmd list to support the existing ":lf" abbreviation. + { + command='lfdo', + flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, NOTADR, DFLALL), + addr_type=ADDR_QUICKFIX, + func='ex_listdo', + }, { command='lfirst', flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG), diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 87a6283310..57153cf5a1 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -1868,7 +1868,7 @@ void ex_argdelete(exarg_T *eap) } /* - * ":argdo", ":windo", ":bufdo", ":tabdo" + * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo" */ void ex_listdo(exarg_T *eap) { @@ -1879,7 +1879,6 @@ void ex_listdo(exarg_T *eap) char_u *save_ei = NULL; char_u *p_shm_save; - if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo) /* Don't do syntax HL autocommands. Skipping the syntax file is a * great speed improvement. */ @@ -1914,7 +1913,10 @@ void ex_listdo(exarg_T *eap) default: break; } + buf_T *buf = curbuf; + size_t qf_size = 0; + /* set pcmark now */ if (eap->cmdidx == CMD_bufdo) { /* Advance to the first listed buffer after "eap->line1". */ @@ -1929,6 +1931,22 @@ void ex_listdo(exarg_T *eap) if (buf != NULL) { goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum); } + } else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo || + eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) { + qf_size = qf_get_size(eap); + assert(eap->line1 >= 0); + if (qf_size == 0 || (size_t)eap->line1 > qf_size) { + buf = NULL; + } else { + ex_cc(eap); + + buf = curbuf; + i = eap->line1 - 1; + if (eap->addr_count <= 0) { + // Default to all quickfix/location list entries. + eap->line2 = qf_size; + } + } } else { setpcmark(); } @@ -2009,9 +2027,27 @@ void ex_listdo(exarg_T *eap) set_option_value((char_u *)"shm", 0L, p_shm_save, 0); xfree(p_shm_save); - /* If autocommands took us elsewhere, quit here */ - if (curbuf->b_fnum != next_fnum) + // If autocommands took us elsewhere, quit here. + if (curbuf->b_fnum != next_fnum) { + break; + } + } + + if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo || + eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) { + assert(i >= 0); + if ((size_t)i >= qf_size || i >= eap->line2) { break; + } + + size_t qf_idx = qf_get_cur_idx(eap); + + ex_cnext(eap); + + // If jumping to the next quickfix entry fails, quit here. + if (qf_get_cur_idx(eap) == qf_idx) { + break; + } } if (eap->cmdidx == CMD_windo) { diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h index 10d2eb688e..f46d1e6d47 100644 --- a/src/nvim/ex_cmds_defs.h +++ b/src/nvim/ex_cmds_defs.h @@ -72,6 +72,7 @@ #define ADDR_LOADED_BUFFERS 3 #define ADDR_BUFFERS 4 #define ADDR_TABS 5 +#define ADDR_QUICKFIX 6 typedef struct exarg exarg_T; diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 59bda9345e..fad497928c 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1531,9 +1531,12 @@ static char_u * do_one_cmd(char_u **cmdlinep, lnum = CURRENT_TAB_NR; ea.line2 = lnum; break; + case ADDR_QUICKFIX: + ea.line2 = qf_get_cur_valid_idx(&ea); + break; } ea.cmd = skipwhite(ea.cmd); - lnum = get_address(&ea.cmd, ea.addr_type, ea.skip, ea.addr_count == 0); + lnum = get_address(&ea, &ea.cmd, ea.addr_type, ea.skip, ea.addr_count == 0); if (ea.cmd == NULL) /* error detected */ goto doend; if (lnum == MAXLNUM) { @@ -1582,6 +1585,13 @@ static char_u * do_one_cmd(char_u **cmdlinep, ea.line2 = ARGCOUNT; } break; + case ADDR_QUICKFIX: + ea.line1 = 1; + ea.line2 = qf_get_size(&ea); + if (ea.line2 == 0) { + ea.line2 = 1; + } + break; } ++ea.addr_count; } @@ -1962,6 +1972,12 @@ static char_u * do_one_cmd(char_u **cmdlinep, ea.line2 = ARGCOUNT; } break; + case ADDR_QUICKFIX: + ea.line2 = qf_get_size(&ea); + if (ea.line2 == 0) { + ea.line2 = 1; + } + break; } } @@ -2945,6 +2961,8 @@ set_one_cmd_context ( case CMD_botright: case CMD_browse: case CMD_bufdo: + case CMD_cdo: + case CMD_cfdo: case CMD_confirm: case CMD_debug: case CMD_folddoclosed: @@ -2954,7 +2972,9 @@ set_one_cmd_context ( case CMD_keepjumps: case CMD_keepmarks: case CMD_keeppatterns: + case CMD_ldo: case CMD_leftabove: + case CMD_lfdo: case CMD_lockmarks: case CMD_noautocmd: case CMD_noswapfile: @@ -3367,7 +3387,8 @@ skip_range ( * * Return MAXLNUM when no Ex address was found. */ -static linenr_T get_address(char_u **ptr, +static linenr_T get_address(exarg_T *eap, + char_u **ptr, int addr_type, // flag: one of ADDR_LINES, ... int skip, // only skip the address, don't use it int to_other_file // flag: may jump to other file @@ -3405,6 +3426,9 @@ static linenr_T get_address(char_u **ptr, case ADDR_TABS: lnum = CURRENT_TAB_NR; break; + case ADDR_QUICKFIX: + lnum = qf_get_cur_valid_idx(eap); + break; } break; @@ -3436,6 +3460,12 @@ static linenr_T get_address(char_u **ptr, case ADDR_TABS: lnum = LAST_TAB_NR; break; + case ADDR_QUICKFIX: + lnum = qf_get_size(eap); + if (lnum == 0) { + lnum = 1; + } + break; } break; @@ -3578,6 +3608,9 @@ static linenr_T get_address(char_u **ptr, case ADDR_TABS: lnum = CURRENT_TAB_NR; break; + case ADDR_QUICKFIX: + lnum = qf_get_cur_valid_idx(eap); + break; } } @@ -3702,6 +3735,12 @@ static char_u *invalid_range(exarg_T *eap) return (char_u *)_(e_invrange); } break; + case ADDR_QUICKFIX: + assert(eap->line2 >= 0); + if (eap->line2 != 1 && (size_t)eap->line2 > qf_get_size(eap)) { + return (char_u *)_(e_invrange); + } + break; } } return NULL; @@ -4589,6 +4628,7 @@ static struct { {ADDR_TABS, "tabs"}, {ADDR_BUFFERS, "buffers"}, {ADDR_WINDOWS, "windows"}, + {ADDR_QUICKFIX, "quickfix"}, {-1, NULL} }; @@ -7013,9 +7053,7 @@ static void ex_put(exarg_T *eap) */ static void ex_copymove(exarg_T *eap) { - long n; - - n = get_address(&eap->arg, eap->addr_type, FALSE, FALSE); + long n = get_address(eap, &eap->arg, eap->addr_type, false, false); if (eap->arg == NULL) { /* error detected */ eap->nextcmd = NULL; return; diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c index 3585c26ca2..b78dfdca11 100644 --- a/src/nvim/if_cscope.c +++ b/src/nvim/if_cscope.c @@ -1146,22 +1146,6 @@ static void clear_csinfo(size_t i) csinfo[i].to_fp = NULL; } -#ifndef UNIX -static char *GetWin32Error(void) -{ - char *msg = NULL; - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, - NULL, GetLastError(), 0, (LPSTR)&msg, 0, NULL); - if (msg != NULL) { - /* remove trailing \r\n */ - char *pcrlf = strstr(msg, "\r\n"); - if (pcrlf != NULL) - *pcrlf = '\0'; - } - return msg; -} -#endif - /* * PRIVATE: cs_insert_filelist * diff --git a/src/nvim/os/win_defs.h b/src/nvim/os/win_defs.h index 6003d46d96..aad9672ba7 100644 --- a/src/nvim/os/win_defs.h +++ b/src/nvim/os/win_defs.h @@ -2,6 +2,7 @@ #define NVIM_OS_WIN_DEFS_H #include <windows.h> +#include <sys/stat.h> #define TEMP_DIR_NAMES {"$TMP", "$TEMP", "$USERPROFILE", ""} #define TEMP_FILE_PATH_MAXLEN _MAX_PATH @@ -17,6 +18,9 @@ # ifndef restrict # define restrict __restrict # endif +# ifndef S_IXUSR +# define S_IXUSR S_IEXEC +# endif #endif #ifdef _MSC_VER diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 8e6ae46a3b..3abf43cb8c 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -1202,7 +1202,7 @@ static void qf_clean_dir_stack(struct dir_stack_T **stackptr) /* * Check in which directory of the directory stack the given file can be * found. - * Returns a pointer to the directory name or NULL if not found + * Returns a pointer to the directory name or NULL if not found. * Cleans up intermediate directory entries. * * TODO: How to solve the following problem? @@ -2571,9 +2571,159 @@ static char_u *get_mef_name(void) return name; } +/// Returns the number of valid entries in the current quickfix/location list. +size_t qf_get_size(exarg_T *eap) + FUNC_ATTR_NONNULL_ALL +{ + qf_info_T *qi = &ql_info; + if (eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo) { + // Location list. + qi = GET_LOC_LIST(curwin); + if (qi == NULL) { + return 0; + } + } + + int prev_fnum = 0; + size_t sz = 0; + qfline_T *qfp; + size_t i; + assert(qi->qf_lists[qi->qf_curlist].qf_count >= 0); + for (i = 0, qfp = qi->qf_lists[qi->qf_curlist].qf_start; + i < (size_t)qi->qf_lists[qi->qf_curlist].qf_count && qfp != NULL; + i++, qfp = qfp->qf_next) { + if (!qfp->qf_valid) { + continue; + } + + if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo) { + // Count all valid entries. + sz++; + } else if (qfp->qf_fnum > 0 && qfp->qf_fnum != prev_fnum) { + // Count the number of files. + sz++; + prev_fnum = qfp->qf_fnum; + } + } + + return sz; +} + +/// Returns the current index of the quickfix/location list. +/// Returns 0 if there is an error. +size_t qf_get_cur_idx(exarg_T *eap) + FUNC_ATTR_NONNULL_ALL +{ + qf_info_T *qi = &ql_info; + + if (eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo) { + // Location list. + qi = GET_LOC_LIST(curwin); + if (qi == NULL) { + return 0; + } + } + + assert(qi->qf_lists[qi->qf_curlist].qf_index >= 0); + return (size_t)qi->qf_lists[qi->qf_curlist].qf_index; +} + +/// Returns the current index in the quickfix/location list, +/// counting only valid entries. +/// Returns 1 if there are no valid entries. +int qf_get_cur_valid_idx(exarg_T *eap) + FUNC_ATTR_NONNULL_ALL +{ + qf_info_T *qi = &ql_info; + + if (eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo) { + // Location list. + qi = GET_LOC_LIST(curwin); + if (qi == NULL) { + return 1; + } + } + + qf_list_T *qfl = &qi->qf_lists[qi->qf_curlist]; + + // Check if the list has valid errors. + if (qfl->qf_count <= 0 || qfl->qf_nonevalid) { + return 1; + } + + int prev_fnum = 0; + int eidx = 0; + qfline_T *qfp; + size_t i; + assert(qfl->qf_index >= 0); + for (i = 1, qfp = qfl->qf_start; + i <= (size_t)qfl->qf_index && qfp != NULL; + i++, qfp = qfp->qf_next) { + if (!qfp->qf_valid) { + continue; + } + + if (eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) { + if (qfp->qf_fnum > 0 && qfp->qf_fnum != prev_fnum) { + // Count the number of files. + eidx++; + prev_fnum = qfp->qf_fnum; + } + } else { + eidx++; + } + } + + return eidx != 0 ? eidx : 1; +} + +/// Get the 'n'th valid error entry in the quickfix or location list. +/// +/// Used by :cdo, :ldo, :cfdo and :lfdo commands. +/// For :cdo and :ldo, returns the 'n'th valid error entry. +/// For :cfdo and :lfdo, returns the 'n'th valid file entry. +static size_t qf_get_nth_valid_entry(qf_info_T *qi, size_t n, bool fdo) + FUNC_ATTR_NONNULL_ALL +{ + qf_list_T *qfl = &qi->qf_lists[qi->qf_curlist]; + + // Check if the list has valid errors. + if (qfl->qf_count <= 0 || qfl->qf_nonevalid) { + return 1; + } + + int prev_fnum = 0; + size_t eidx = 0; + size_t i; + qfline_T *qfp; + assert(qfl->qf_count >= 0); + for (i = 1, qfp = qfl->qf_start; + i <= (size_t)qfl->qf_count && qfp != NULL; + i++, qfp = qfp->qf_next) { + if (qfp->qf_valid) { + if (fdo) { + if (qfp->qf_fnum > 0 && qfp->qf_fnum != prev_fnum) { + // Count the number of files. + eidx++; + prev_fnum = qfp->qf_fnum; + } + } else { + eidx++; + } + } + + if (eidx == n) { + break; + } + } + + return i <= (size_t)qfl->qf_count ? i : 1; +} + /* * ":cc", ":crewind", ":cfirst" and ":clast". * ":ll", ":lrewind", ":lfirst" and ":llast". + * ":cdo", ":ldo", ":cfdo" and ":lfdo". */ void ex_cc(exarg_T *eap) { @@ -2582,7 +2732,10 @@ void ex_cc(exarg_T *eap) if (eap->cmdidx == CMD_ll || eap->cmdidx == CMD_lrewind || eap->cmdidx == CMD_lfirst - || eap->cmdidx == CMD_llast) { + || eap->cmdidx == CMD_llast + || eap->cmdidx == CMD_llast + || eap->cmdidx == CMD_ldo + || eap->cmdidx == CMD_lfdo) { qi = GET_LOC_LIST(curwin); if (qi == NULL) { EMSG(_(e_loclist)); @@ -2590,21 +2743,42 @@ void ex_cc(exarg_T *eap) } } - qf_jump(qi, 0, - eap->addr_count > 0 - ? (int)eap->line2 - : (eap->cmdidx == CMD_cc || eap->cmdidx == CMD_ll) - ? 0 - : (eap->cmdidx == CMD_crewind || eap->cmdidx == CMD_lrewind - || eap->cmdidx == CMD_cfirst || eap->cmdidx == CMD_lfirst) - ? 1 - : 32767, - eap->forceit); + int errornr; + if (eap->addr_count > 0) { + errornr = (int)eap->line2; + } else if (eap->cmdidx == CMD_cc || eap->cmdidx == CMD_ll) { + errornr = 0; + } else if (eap->cmdidx == CMD_crewind || eap->cmdidx == CMD_lrewind + || eap->cmdidx == CMD_cfirst || eap->cmdidx == CMD_lfirst) { + errornr = 1; + } else { + errornr = 32767; + } + + // For cdo and ldo commands, jump to the nth valid error. + // For cfdo and lfdo commands, jump to the nth valid file entry. + if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo || + eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) { + size_t n; + if (eap->addr_count > 0) { + assert(eap->line1 >= 0); + n = (size_t)eap->line1; + } else { + n = 1; + } + size_t valid_entry = qf_get_nth_valid_entry(qi, n, + eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo); + assert(valid_entry <= INT_MAX); + errornr = (int)valid_entry; + } + + qf_jump(qi, 0, errornr, eap->forceit); } /* * ":cnext", ":cnfile", ":cNext" and ":cprevious". * ":lnext", ":lNext", ":lprevious", ":lnfile", ":lNfile" and ":lpfile". + * ":cdo", ":ldo", ":cfdo" and ":lfdo". */ void ex_cnext(exarg_T *eap) { @@ -2615,7 +2789,10 @@ void ex_cnext(exarg_T *eap) || eap->cmdidx == CMD_lprevious || eap->cmdidx == CMD_lnfile || eap->cmdidx == CMD_lNfile - || eap->cmdidx == CMD_lpfile) { + || eap->cmdidx == CMD_lpfile + || eap->cmdidx == CMD_lpfile + || eap->cmdidx == CMD_ldo + || eap->cmdidx == CMD_lfdo) { qi = GET_LOC_LIST(curwin); if (qi == NULL) { EMSG(_(e_loclist)); @@ -2623,15 +2800,26 @@ void ex_cnext(exarg_T *eap) } } - qf_jump(qi, (eap->cmdidx == CMD_cnext || eap->cmdidx == CMD_lnext) + int errornr; + if (eap->addr_count > 0 && + (eap->cmdidx != CMD_cdo && eap->cmdidx != CMD_ldo && + eap->cmdidx != CMD_cfdo && eap->cmdidx != CMD_lfdo)) { + errornr = (int)eap->line2; + } else { + errornr = 1; + } + + qf_jump(qi, (eap->cmdidx == CMD_cnext || eap->cmdidx == CMD_lnext + || eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo) ? FORWARD - : (eap->cmdidx == CMD_cnfile || eap->cmdidx == CMD_lnfile) + : (eap->cmdidx == CMD_cnfile || eap->cmdidx == CMD_lnfile + || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) ? FORWARD_FILE : (eap->cmdidx == CMD_cpfile || eap->cmdidx == CMD_lpfile || eap->cmdidx == CMD_cNfile || eap->cmdidx == CMD_lNfile) ? BACKWARD_FILE : BACKWARD, - eap->addr_count > 0 ? (int)eap->line2 : 1, eap->forceit); + errornr, eap->forceit); } /* diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 9fdb476748..c4264cbcee 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -2934,14 +2934,16 @@ win_line ( } } - /* Decide which of the highlight attributes to use. */ - attr_pri = TRUE; - if (area_attr != 0) - char_attr = area_attr; - else if (search_attr != 0) - char_attr = search_attr; - /* Use line_attr when not in the Visual or 'incsearch' area - * (area_attr may be 0 when "noinvcur" is set). */ + // Decide which of the highlight attributes to use. + attr_pri = true; + + if (area_attr != 0) { + char_attr = hl_combine_attr(line_attr, area_attr); + } else if (search_attr != 0) { + char_attr = hl_combine_attr(line_attr, search_attr); + } + // Use line_attr when not in the Visual or 'incsearch' area + // (area_attr may be 0 when "noinvcur" is set). else if (line_attr != 0 && ((fromcol == -10 && tocol == MAXCOL) || vcol < fromcol || vcol_prev < fromcol_prev || vcol >= tocol)) @@ -3323,16 +3325,15 @@ win_line ( * Found last space before word: check for line break. */ if (wp->w_p_lbr && vim_isbreak(c) && !vim_isbreak(*ptr)) { - char_u *p = ptr - ( - has_mbyte ? mb_l : - 1); + int mb_off = has_mbyte ? (*mb_head_off)(line, ptr - 1) : 0; + char_u *p = ptr - (mb_off + 1); // TODO: is passing p for start of the line OK? n_extra = win_lbr_chartabsize(wp, line, p, (colnr_T)vcol, NULL) - 1; if (c == TAB && n_extra + col > wp->w_width) { n_extra = (int)wp->w_buffer->b_p_ts - vcol % (int)wp->w_buffer->b_p_ts - 1; } - c_extra = ' '; + c_extra = mb_off > 0 ? MB_FILLER_CHAR : ' '; if (ascii_iswhite(c)) { if (c == TAB) /* See "Tab alignment" below. */ diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 340c14066a..42e514aa95 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -122,7 +122,7 @@ KHASH_SET_INIT_STR(strset) // E576: Missing '>' // E577: Illegal register name // E886: Can't rename viminfo file to %s! -// Now only five of them are used: +// Now only six of them are used: // E137: ShaDa file is not writeable (for pre-open checks) // E138: All %s.tmp.X files exist, cannot write ShaDa file! // RCERR (E576) for critical read errors. @@ -130,6 +130,7 @@ KHASH_SET_INIT_STR(strset) // RERR (E575) for various errors inside read ShaDa file. // SERR (E886) for various “system” errors (always contains output of // strerror) +// WERR (E574) for various ignorable write errors /// Common prefix for all errors inside ShaDa file /// @@ -148,6 +149,9 @@ KHASH_SET_INIT_STR(strset) /// Common prefix for all “rename” errors #define RNERR "E136: " +/// Common prefix for all ignorable “write” errors +#define WERR "E574: " + /// Flags for shada_read_file and children typedef enum { kShaDaWantInfo = 1, ///< Load non-mark information @@ -198,6 +202,9 @@ typedef enum { ///< a ShaDa file. kSDWriteFailed, ///< Writing was not successfull (e.g. because there ///< was no space left on device). + kSDWriteIgnError, ///< Writing resulted in a error which can be ignored + ///< (e.g. when trying to dump a function reference or + ///< self-referencing container in a variable). } ShaDaWriteResult; /// Flags for shada_read_next_item @@ -1666,11 +1673,14 @@ static char *shada_filename(const char *file) /// @param[in] entry Entry written. /// @param[in] max_kbyte Maximum size of an item in KiB. Zero means no /// restrictions. -static bool shada_pack_entry(msgpack_packer *const packer, - ShadaEntry entry, - const size_t max_kbyte) +/// +/// @return kSDWriteSuccessfull, kSDWriteFailed or kSDWriteIgnError. +static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer, + ShadaEntry entry, + const size_t max_kbyte) FUNC_ATTR_NONNULL_ALL { + ShaDaWriteResult ret = kSDWriteFailed; msgpack_sbuffer sbuf; msgpack_sbuffer_init(&sbuf); msgpack_packer *spacker = msgpack_packer_new(&sbuf, &msgpack_sbuffer_write); @@ -1742,6 +1752,9 @@ static bool shada_pack_entry(msgpack_packer *const packer, msgpack_pack_array(spacker, arr_size); PACK_BIN(cstr_as_string(entry.data.global_var.name)); if (vim_to_msgpack(spacker, &entry.data.global_var.value) == FAIL) { + ret = kSDWriteIgnError; + EMSG2(_(WERR "Failed to write variable %s"), + entry.data.global_var.name); goto shada_pack_entry_error; } DUMP_ADDITIONAL_ELEMENTS(entry.data.global_var.additional_elements); @@ -1946,11 +1959,11 @@ static bool shada_pack_entry(msgpack_packer *const packer, } msgpack_packer_free(spacker); msgpack_sbuffer_destroy(&sbuf); - return true; + return kSDWriteSuccessfull; shada_pack_entry_error: msgpack_packer_free(spacker); msgpack_sbuffer_destroy(&sbuf); - return false; + return ret; } #undef PACK_STRING @@ -1965,13 +1978,13 @@ shada_pack_entry_error: /// is assumed that entry was already converted. /// @param[in] max_kbyte Maximum size of an item in KiB. Zero means no /// restrictions. -static bool shada_pack_encoded_entry(msgpack_packer *const packer, - const vimconv_T *const sd_conv, - PossiblyFreedShadaEntry entry, - const size_t max_kbyte) +static ShaDaWriteResult shada_pack_encoded_entry(msgpack_packer *const packer, + const vimconv_T *const sd_conv, + PossiblyFreedShadaEntry entry, + const size_t max_kbyte) FUNC_ATTR_NONNULL_ALL { - bool ret = true; + ShaDaWriteResult ret = kSDWriteSuccessfull; if (entry.can_free_entry) { ret = shada_pack_entry(packer, entry.data, max_kbyte); shada_free_shada_entry(&entry.data); @@ -2244,9 +2257,7 @@ static inline ShaDaWriteResult shada_read_when_writing( assert(false); } case kSDItemUnknown: { - if (!shada_pack_entry(packer, entry, 0)) { - ret = kSDWriteFailed; - } + ret = shada_pack_entry(packer, entry, 0); shada_free_shada_entry(&entry); break; } @@ -2262,9 +2273,7 @@ static inline ShaDaWriteResult shada_read_when_writing( } case kSDItemHistoryEntry: { if (entry.data.history_item.histtype >= HIST_COUNT) { - if (!shada_pack_entry(packer, entry, 0)) { - ret = kSDWriteFailed; - } + ret = shada_pack_entry(packer, entry, 0); shada_free_shada_entry(&entry); break; } @@ -2275,9 +2284,7 @@ static inline ShaDaWriteResult shada_read_when_writing( case kSDItemRegister: { const int idx = op_reg_index(entry.data.reg.name); if (idx < 0) { - if (!shada_pack_entry(packer, entry, 0)) { - ret = kSDWriteFailed; - } + ret = shada_pack_entry(packer, entry, 0); shada_free_shada_entry(&entry); break; } @@ -2286,9 +2293,7 @@ static inline ShaDaWriteResult shada_read_when_writing( } case kSDItemVariable: { if (!in_strset(&wms->dumped_variables, entry.data.global_var.name)) { - if (!shada_pack_entry(packer, entry, 0)) { - ret = kSDWriteFailed; - } + ret = shada_pack_entry(packer, entry, 0); } shada_free_shada_entry(&entry); break; @@ -2296,9 +2301,7 @@ static inline ShaDaWriteResult shada_read_when_writing( case kSDItemGlobalMark: { const int idx = mark_global_index(entry.data.filemark.name); if (idx < 0) { - if (!shada_pack_entry(packer, entry, 0)) { - ret = kSDWriteFailed; - } + ret = shada_pack_entry(packer, entry, 0); shada_free_shada_entry(&entry); break; } @@ -2465,7 +2468,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, } // Write header - if (!shada_pack_entry(packer, (ShadaEntry) { + if (shada_pack_entry(packer, (ShadaEntry) { .type = kSDItemHeader, .timestamp = os_time(), .data = { @@ -2486,7 +2489,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, }), } } - }, 0)) { + }, 0) == kSDWriteFailed) { ret = kSDWriteFailed; goto shada_write_exit; } @@ -2526,7 +2529,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, }; i++; } - if (!shada_pack_entry(packer, buflist_entry, 0)) { + if (shada_pack_entry(packer, buflist_entry, 0) == kSDWriteFailed) { xfree(buflist_entry.data.buffer_list.buffers); ret = kSDWriteFailed; goto shada_write_exit; @@ -2552,7 +2555,8 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, } else { copy_tv(&vartv, &tgttv); } - if (!shada_pack_entry(packer, (ShadaEntry) { + ShaDaWriteResult spe_ret; + if ((spe_ret = shada_pack_entry(packer, (ShadaEntry) { .type = kSDItemVariable, .timestamp = cur_timestamp, .data = { @@ -2562,7 +2566,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, .additional_elements = NULL, } } - }, max_kbyte)) { + }, max_kbyte)) == kSDWriteFailed) { clear_tv(&vartv); clear_tv(&tgttv); ret = kSDWriteFailed; @@ -2570,8 +2574,10 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, } clear_tv(&vartv); clear_tv(&tgttv); - int kh_ret; - (void) kh_put(strset, &wms->dumped_variables, name, &kh_ret); + if (spe_ret == kSDWriteSuccessfull) { + int kh_ret; + (void) kh_put(strset, &wms->dumped_variables, name, &kh_ret); + } } while (var_iter != NULL); } @@ -2828,9 +2834,9 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, do { \ for (size_t i_ = 0; i_ < ARRAY_SIZE(wms_array); i_++) { \ if (wms_array[i_].data.type != kSDItemMissing) { \ - if (!shada_pack_encoded_entry(packer, &sd_writer->sd_conv, \ - wms_array[i_], \ - max_kbyte)) { \ + if (shada_pack_encoded_entry(packer, &sd_writer->sd_conv, \ + wms_array[i_], \ + max_kbyte) == kSDWriteFailed) { \ ret = kSDWriteFailed; \ goto shada_write_exit; \ } \ @@ -2840,8 +2846,8 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, PACK_WMS_ARRAY(wms->global_marks); PACK_WMS_ARRAY(wms->registers); for (size_t i = 0; i < wms->jumps_size; i++) { - if (!shada_pack_encoded_entry(packer, &sd_writer->sd_conv, wms->jumps[i], - max_kbyte)) { + if (shada_pack_encoded_entry(packer, &sd_writer->sd_conv, wms->jumps[i], + max_kbyte) == kSDWriteFailed) { ret = kSDWriteFailed; goto shada_write_exit; } @@ -2849,8 +2855,8 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, #define PACK_WMS_ENTRY(wms_entry) \ do { \ if (wms_entry.data.type != kSDItemMissing) { \ - if (!shada_pack_encoded_entry(packer, &sd_writer->sd_conv, wms_entry, \ - max_kbyte)) { \ + if (shada_pack_encoded_entry(packer, &sd_writer->sd_conv, wms_entry, \ + max_kbyte) == kSDWriteFailed) { \ ret = kSDWriteFailed; \ goto shada_write_exit; \ } \ @@ -2877,16 +2883,16 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, for (size_t i = 0; i < file_markss_to_dump; i++) { PACK_WMS_ARRAY(all_file_markss[i]->marks); for (size_t j = 0; j < all_file_markss[i]->changes_size; j++) { - if (!shada_pack_encoded_entry(packer, &sd_writer->sd_conv, - all_file_markss[i]->changes[j], - max_kbyte)) { + if (shada_pack_encoded_entry(packer, &sd_writer->sd_conv, + all_file_markss[i]->changes[j], + max_kbyte) == kSDWriteFailed) { ret = kSDWriteFailed; goto shada_write_exit; } } for (size_t j = 0; j < all_file_markss[i]->additional_marks_size; j++) { - if (!shada_pack_entry(packer, all_file_markss[i]->additional_marks[j], - 0)) { + if (shada_pack_entry(packer, all_file_markss[i]->additional_marks[j], + 0) == kSDWriteFailed) { shada_free_shada_entry(&all_file_markss[i]->additional_marks[j]); ret = kSDWriteFailed; goto shada_write_exit; @@ -2903,16 +2909,15 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, if (dump_one_history[i]) { hms_insert_whole_neovim_history(&wms->hms[i]); HMS_ITER(&wms->hms[i], cur_entry, { - if (!shada_pack_encoded_entry( + if (shada_pack_encoded_entry( packer, &sd_writer->sd_conv, (PossiblyFreedShadaEntry) { .data = cur_entry->data, .can_free_entry = cur_entry->can_free_entry, - }, max_kbyte)) { + }, max_kbyte) == kSDWriteFailed) { ret = kSDWriteFailed; break; } }) - hms_dealloc(&wms->hms[i]); if (ret == kSDWriteFailed) { goto shada_write_exit; } @@ -2921,6 +2926,11 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, } shada_write_exit: + for (size_t i = 0; i < HIST_COUNT; i++) { + if (dump_one_history[i]) { + hms_dealloc(&wms->hms[i]); + } + } kh_dealloc(file_marks, &wms->file_marks); kh_dealloc(bufset, &removable_bufs); msgpack_packer_free(packer); @@ -3043,6 +3053,7 @@ shada_write_file_nomerge: {} const ShaDaWriteResult sw_ret = shada_write(&sd_writer, (nomerge ? NULL : &sd_reader)); + assert(sw_ret != kSDWriteIgnError); #ifndef UNIX sd_writer.close(&sd_writer); #endif diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index 8c3e99c624..1a414a8847 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -29,6 +29,7 @@ SCRIPTS := test_eval.out \ test_charsearch.out \ test_close_count.out \ test_command_count.out \ + test_cdo.out \ SCRIPTS_GUI := test16.out diff --git a/src/nvim/testdir/test_breakindent.in b/src/nvim/testdir/test_breakindent.in index b05aef7f8d..5a8e580c4a 100644 --- a/src/nvim/testdir/test_breakindent.in +++ b/src/nvim/testdir/test_breakindent.in @@ -101,7 +101,7 @@ fygjyl:let line2 = @0 :$put =line2 :" :let g:test="Test 14: breakindent + visual blockwise delete #1" -:set all& breakindent +:set all& breakindent shada+=nX-test-breakindent.shada :30vnew :normal! 3a1234567890 :normal! a abcde diff --git a/src/nvim/testdir/test_cdo.in b/src/nvim/testdir/test_cdo.in new file mode 100644 index 0000000000..fb80ea1164 --- /dev/null +++ b/src/nvim/testdir/test_cdo.in @@ -0,0 +1,107 @@ +Tests for the :cdo, :cfdo, :ldo and :lfdo commands + +STARTTEST +:so small.vim +:if !has('quickfix') | e! test.ok | wq! test.out | endif + +:call writefile(["Line1", "Line2", "Line3"], 'Xtestfile1') +:call writefile(["Line1", "Line2", "Line3"], 'Xtestfile2') +:call writefile(["Line1", "Line2", "Line3"], 'Xtestfile3') + +:function RunTests(cchar) +: let nl="\n" + +: enew +: " Try with an empty list +: exe a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" + +: " Populate the list and then try +: exe a:cchar . "getexpr ['non-error 1', 'Xtestfile1:1:3:Line1', 'non-error 2', 'Xtestfile2:2:2:Line2', 'non-error 3', 'Xtestfile3:3:1:Line3']" +: exe a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" + +: " Run command only on selected error lines +: enew +: exe "2,3" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" +: " Boundary condition tests +: enew +: exe "1,1" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" +: enew +: exe "3" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" +: " Range test commands +: enew +: exe "%" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" +: enew +: exe "1,$" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" +: enew +: exe a:cchar . 'prev' +: exe "." . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" +: " Invalid error lines test +: enew +: exe "27" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" +: exe "4,5" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" + +: " Run commands from an unsaved buffer +: let v:errmsg='' +: enew +: setlocal modified +: exe "2,2" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" +: if v:errmsg =~# 'No write since last change' +: let g:result .= 'Unsaved file change test passed' . nl +: else +: let g:result .= 'Unsaved file change test failed' . nl +: endif + +: " If the executed command fails, then the operation should be aborted +: enew! +: let subst_count = 0 +: exe a:cchar . "do s/Line/xLine/ | let subst_count += 1" +: if subst_count == 1 && getline('.') == 'xLine1' +: let g:result .= 'Abort command on error test passed' . nl +: else +: let g:result .= 'Abort command on error test failed' . nl +: endif + +: exe "2,2" . a:cchar . "do! let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" + +: " List with no valid error entries +: edit! +2 Xtestfile1 +: exe a:cchar . "getexpr ['non-error 1', 'non-error 2', 'non-error 3']" +: exe a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" +: exe "2" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" +: let v:errmsg='' +: exe "%" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" +: exe "1,$" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" +: exe "." . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" +: let g:result .= v:errmsg + +: " List with only one valid entry +: exe a:cchar . "getexpr ['Xtestfile3:3:1:Line3']" +: exe a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" + +: " Tests for :cfdo and :lfdo commands +: exe a:cchar . "getexpr ['non-error 1', 'Xtestfile1:1:3:Line1', 'Xtestfile1:2:1:Line2', 'non-error 2', 'Xtestfile2:2:2:Line2', 'non-error 3', 'Xtestfile3:2:3:Line2', 'Xtestfile3:3:1:Line3']" +: exe a:cchar . "fdo let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" +: exe "3" . a:cchar . "fdo let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" +: exe "2,3" . a:cchar . "fdo let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" +: exe "%" . a:cchar . "fdo let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" +: exe "1,$" . a:cchar . "fdo let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" +: exe a:cchar . 'pfile' +: exe "." . a:cchar . "fdo let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" + +: " List with only one valid entry +: exe a:cchar . "getexpr ['Xtestfile2:2:5:Line2']" +: exe a:cchar . "fdo let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl" +:endfunction + +:let result='' +:" Tests for the :cdo quickfix list command +:call RunTests('c') +:let result .= "\n" +:" Tests for the :ldo location list command +:call RunTests('l') + +:edit! test.out +:0put =result +:wq! +ENDTEST + diff --git a/src/nvim/testdir/test_cdo.ok b/src/nvim/testdir/test_cdo.ok new file mode 100644 index 0000000000..ddcff4bbb8 --- /dev/null +++ b/src/nvim/testdir/test_cdo.ok @@ -0,0 +1,66 @@ +Xtestfile1 1L 3C +Xtestfile2 2L 2C +Xtestfile3 3L 1C +Xtestfile2 2L 2C +Xtestfile3 3L 1C +Xtestfile1 1L 3C +Xtestfile3 3L 1C +Xtestfile1 1L 3C +Xtestfile2 2L 2C +Xtestfile3 3L 1C +Xtestfile1 1L 3C +Xtestfile2 2L 2C +Xtestfile3 3L 1C +Xtestfile2 2L 2C +Unsaved file change test passed +Abort command on error test passed +Xtestfile2 2L 2C +Xtestfile3 3L 1C +Xtestfile1 1L 3C +Xtestfile2 2L 2C +Xtestfile3 2L 3C +Xtestfile3 2L 3C +Xtestfile2 2L 2C +Xtestfile3 2L 3C +Xtestfile1 1L 3C +Xtestfile2 2L 2C +Xtestfile3 2L 3C +Xtestfile1 1L 3C +Xtestfile2 2L 2C +Xtestfile3 2L 3C +Xtestfile2 2L 2C +Xtestfile2 2L 5C + +Xtestfile1 1L 3C +Xtestfile2 2L 2C +Xtestfile3 3L 1C +Xtestfile2 2L 2C +Xtestfile3 3L 1C +Xtestfile1 1L 3C +Xtestfile3 3L 1C +Xtestfile1 1L 3C +Xtestfile2 2L 2C +Xtestfile3 3L 1C +Xtestfile1 1L 3C +Xtestfile2 2L 2C +Xtestfile3 3L 1C +Xtestfile2 2L 2C +Unsaved file change test passed +Abort command on error test passed +Xtestfile2 2L 2C +Xtestfile3 3L 1C +Xtestfile1 1L 3C +Xtestfile2 2L 2C +Xtestfile3 2L 3C +Xtestfile3 2L 3C +Xtestfile2 2L 2C +Xtestfile3 2L 3C +Xtestfile1 1L 3C +Xtestfile2 2L 2C +Xtestfile3 2L 3C +Xtestfile1 1L 3C +Xtestfile2 2L 2C +Xtestfile3 2L 3C +Xtestfile2 2L 2C +Xtestfile2 2L 5C + diff --git a/src/nvim/testdir/test_eval.in b/src/nvim/testdir/test_eval.in index b2b982a434..54cdb03ba2 100644 --- a/src/nvim/testdir/test_eval.in +++ b/src/nvim/testdir/test_eval.in @@ -2,12 +2,18 @@ Test for various eval features. vim: set ft=vim : Note: system clipboard is saved, changed and restored. +clipboard contents +something else + STARTTEST :so small.vim :set noswapfile :lang C :fun AppendRegContents(reg) - call append('$', printf('%s: type %s; value: %s (%s), expr: %s (%s)', a:reg, getregtype(a:reg), getreg(a:reg), string(getreg(a:reg, 0, 1)), getreg(a:reg, 1), string(getreg(a:reg, 1, 1)))) + call AppendRegParts(a:reg, getregtype(a:reg), getreg(a:reg), string(getreg(a:reg, 0, 1)), getreg(a:reg, 1), string(getreg(a:reg, 1, 1))) +:endfun +:fun AppendRegParts(reg, type, cont, strcont, cont1, strcont1) + call append('$', printf('%s: type %s; value: %s (%s), expr: %s (%s)', a:reg, a:type, a:cont, a:strcont, a:cont1, a:strcont1)) endfun :command -nargs=? AR :call AppendRegContents(<q-args>) :fun SetReg(...) @@ -121,18 +127,23 @@ call SetReg('/', ["abc/\n"]) call SetReg('=', ['"abc/"']) call SetReg('=', ["\"abc/\n\""]) $put ='{{{1 System clipboard' +if has('clipboard') " Save and restore system clipboard. " If no connection to X-Server is possible, test should succeed. -:let _clipreg = ['+', getreg('+'), getregtype('+')] -:let _clipopt = &cb -:let &cb='unnamedplus' -:1y -:AR + -:tabdo :windo :echo "hi" -:3y -:AR + -:let &cb=_clipopt -:call call('setreg', _clipreg) +let _clipreg = ['*', getreg('*'), getregtype('*')] +let _clipopt = &cb +let &cb='unnamed' +5y +AR * +tabdo :windo :echo "hi" +6y +AR * +let &cb=_clipopt +call call('setreg', _clipreg) +else + call AppendRegParts('*', 'V', "clipboard contents\n", "['clipboard contents']", "clipboard contents\n", "['clipboard contents']") + call AppendRegParts('*', 'V', "something else\n", "['something else']", "something else\n", "['something else']") +endif $put ='{{{1 Errors' call ErrExe('call setreg()') call ErrExe('call setreg(1)') diff --git a/src/nvim/testdir/test_eval.ok b/src/nvim/testdir/test_eval.ok Binary files differindex 2cdb8f5da8..cf7a5cd418 100644 --- a/src/nvim/testdir/test_eval.ok +++ b/src/nvim/testdir/test_eval.ok diff --git a/src/nvim/version.c b/src/nvim/version.c index 3d26f643dc..b097ac4702 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -135,7 +135,7 @@ static int included_patches[] = { // 861 NA // 860, // 859, - // 858, + 858, // 857, // 856, // 855 NA @@ -311,7 +311,7 @@ static int included_patches[] = { // 685, // 684, // 683 NA - // 682, + 682, // 681 NA // 680, // 679 NA @@ -322,13 +322,13 @@ static int included_patches[] = { // 674 NA 673, // 672, - // 671, + 671, 670, // 669 NA 668, 667, // 666 NA - // 665, + 665, // 664 NA // 663 NA // 662, @@ -381,15 +381,15 @@ static int included_patches[] = { 615, // 614, // 613, - // 612, + 612, // 611 NA // 610 NA 609, - // 608, + 608, // 607, 606, // 605, - // 604, + 604, // 603, 602, 601, |