diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/eval.c | 317 | ||||
-rw-r--r-- | src/nvim/eval.lua | 1 | ||||
-rw-r--r-- | src/nvim/ex_cmds.lua | 6 | ||||
-rw-r--r-- | src/nvim/generators/gen_options.lua | 1 | ||||
-rw-r--r-- | src/nvim/getchar.c | 12 | ||||
-rw-r--r-- | src/nvim/option.c | 6 | ||||
-rw-r--r-- | src/nvim/option_defs.h | 1 | ||||
-rw-r--r-- | src/nvim/options.lua | 21 | ||||
-rw-r--r-- | src/nvim/os/dl.c | 1 | ||||
-rw-r--r-- | src/nvim/testdir/shared.vim | 14 | ||||
-rw-r--r-- | src/nvim/testdir/test49.vim | 3 | ||||
-rw-r--r-- | src/nvim/testdir/test_bufline.vim | 67 | ||||
-rw-r--r-- | src/nvim/testdir/test_const.vim | 237 | ||||
-rw-r--r-- | src/nvim/testdir/test_functions.vim | 48 | ||||
-rw-r--r-- | src/nvim/testdir/test_modeline.vim | 95 | ||||
-rw-r--r-- | src/nvim/testdir/test_source.vim | 10 | ||||
-rw-r--r-- | src/nvim/testdir/test_vimscript.vim | 1 | ||||
-rw-r--r-- | src/nvim/testdir/test_writefile.vim | 2 |
18 files changed, 733 insertions, 110 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index f19fbe112f..cd2888883b 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -176,6 +176,7 @@ static char *e_funcref = N_("E718: Funcref required"); static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary"); static char *e_nofunc = N_("E130: Unknown function: %s"); static char *e_illvar = N_("E461: Illegal variable name: %s"); +static char *e_cannot_mod = N_("E995: Cannot modify existing variable"); static const char *e_readonlyvar = N_( "E46: Cannot change read-only variable \"%.*s\""); @@ -776,10 +777,11 @@ var_redir_start( did_emsg = FALSE; tv.v_type = VAR_STRING; tv.vval.v_string = (char_u *)""; - if (append) - set_var_lval(redir_lval, redir_endp, &tv, TRUE, (char_u *)"."); - else - set_var_lval(redir_lval, redir_endp, &tv, TRUE, (char_u *)"="); + if (append) { + set_var_lval(redir_lval, redir_endp, &tv, true, false, (char_u *)"."); + } else { + set_var_lval(redir_lval, redir_endp, &tv, true, false, (char_u *)"="); + } clear_lval(redir_lval); err = did_emsg; did_emsg |= save_emsg; @@ -837,7 +839,7 @@ void var_redir_stop(void) redir_endp = (char_u *)get_lval(redir_varname, NULL, redir_lval, false, false, 0, FNE_CHECK_START); if (redir_endp != NULL && redir_lval->ll_name != NULL) { - set_var_lval(redir_lval, redir_endp, &tv, false, (char_u *)"."); + set_var_lval(redir_lval, redir_endp, &tv, false, false, (char_u *)"."); } clear_lval(redir_lval); } @@ -1518,21 +1520,33 @@ int eval_foldexpr(char_u *arg, int *cp) return (int)retval; } -/* - * ":let" list all variable values - * ":let var1 var2" list variable values - * ":let var = expr" assignment command. - * ":let var += expr" assignment command. - * ":let var -= expr" assignment command. - * ":let var *= expr" assignment command. - * ":let var /= expr" assignment command. - * ":let var %= expr" assignment command. - * ":let var .= expr" assignment command. - * ":let var ..= expr" assignment command. - * ":let [var1, var2] = expr" unpack list. - */ +// ":cons[t] var = expr1" define constant +// ":cons[t] [name1, name2, ...] = expr1" define constants unpacking list +// ":cons[t] [name, ..., ; lastname] = expr" define constants unpacking list +void ex_const(exarg_T *eap) +{ + ex_let_const(eap, true); +} + +// ":let" list all variable values +// ":let var1 var2" list variable values +// ":let var = expr" assignment command. +// ":let var += expr" assignment command. +// ":let var -= expr" assignment command. +// ":let var *= expr" assignment command. +// ":let var /= expr" assignment command. +// ":let var %= expr" assignment command. +// ":let var .= expr" assignment command. +// ":let var ..= expr" assignment command. +// ":let [var1, var2] = expr" unpack list. +// ":let [name, ..., ; lastname] = expr" unpack list. void ex_let(exarg_T *eap) { + ex_let_const(eap, false); +} + +static void ex_let_const(exarg_T *eap, const bool is_const) +{ char_u *arg = eap->arg; char_u *expr = NULL; typval_T rettv; @@ -1594,7 +1608,8 @@ void ex_let(exarg_T *eap) } emsg_skip--; } else if (i != FAIL) { - (void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, op); + (void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, + is_const, op); tv_clear(&rettv); } } @@ -1612,9 +1627,10 @@ static int ex_let_vars( char_u *arg_start, typval_T *tv, - int copy, /* copy values from "tv", don't move */ - int semicolon, /* from skip_var_list() */ - int var_count, /* from skip_var_list() */ + int copy, // copy values from "tv", don't move + int semicolon, // from skip_var_list() + int var_count, // from skip_var_list() + int is_const, // lock variables for :const char_u *nextchars ) { @@ -1625,8 +1641,9 @@ ex_let_vars( /* * ":let var = expr" or ":for var in list" */ - if (ex_let_one(arg, tv, copy, nextchars, nextchars) == NULL) + if (ex_let_one(arg, tv, copy, is_const, nextchars, nextchars) == NULL) { return FAIL; + } return OK; } @@ -1654,8 +1671,8 @@ ex_let_vars( size_t rest_len = tv_list_len(l); while (*arg != ']') { arg = skipwhite(arg + 1); - arg = ex_let_one(arg, TV_LIST_ITEM_TV(item), true, (const char_u *)",;]", - nextchars); + arg = ex_let_one(arg, TV_LIST_ITEM_TV(item), true, is_const, + (const char_u *)",;]", nextchars); if (arg == NULL) { return FAIL; } @@ -1677,7 +1694,7 @@ ex_let_vars( ltv.vval.v_list = rest_list; tv_list_ref(rest_list); - arg = ex_let_one(skipwhite(arg + 1), <v, false, + arg = ex_let_one(skipwhite(arg + 1), <v, false, is_const, (char_u *)"]", nextchars); tv_clear(<v); if (arg == NULL) { @@ -1933,8 +1950,8 @@ static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first) /// @return a pointer to the char just after the var name or NULL in case of /// error. static char_u *ex_let_one(char_u *arg, typval_T *const tv, - const bool copy, const char_u *const endchars, - const char_u *const op) + const bool copy, const bool is_const, + const char_u *const endchars, const char_u *const op) FUNC_ATTR_NONNULL_ARG(1, 2) FUNC_ATTR_WARN_UNUSED_RESULT { char_u *arg_end = NULL; @@ -1946,6 +1963,10 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv, * ":let $VAR = expr": Set environment variable. */ if (*arg == '$') { + if (is_const) { + EMSG(_("E996: Cannot lock an environment variable")); + return NULL; + } // Find the end of the name. arg++; char *name = (char *)arg; @@ -1991,6 +2012,10 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv, // ":let &l:option = expr": Set local option value. // ":let &g:option = expr": Set global option value. } else if (*arg == '&') { + if (is_const) { + EMSG(_("E996: Cannot lock an option")); + return NULL; + } // Find the end of the name. char *const p = (char *)find_option_end((const char **)&arg, &opt_flags); if (p == NULL @@ -2041,6 +2066,10 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv, } // ":let @r = expr": Set register contents. } else if (*arg == '@') { + if (is_const) { + EMSG(_("E996: Cannot lock a register")); + return NULL; + } arg++; if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL) { emsgf(_(e_letwrong), op); @@ -2080,7 +2109,7 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv, if (endchars != NULL && vim_strchr(endchars, *skipwhite(p)) == NULL) { EMSG(_(e_letunexp)); } else { - set_var_lval(&lv, p, tv, copy, op); + set_var_lval(&lv, p, tv, copy, is_const, op); arg_end = p; } } @@ -2445,7 +2474,7 @@ static void clear_lval(lval_T *lp) * "%" for "%=", "." for ".=" or "=" for "=". */ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, - int copy, const char_u *op) + int copy, const bool is_const, const char_u *op) { int cc; listitem_T *ri; @@ -2457,6 +2486,12 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, if (op != NULL && *op != '=') { typval_T tv; + if (is_const) { + EMSG(_(e_cannot_mod)); + *endp = cc; + return; + } + // handle +=, -=, *=, /=, %= and .= di = NULL; if (get_var_tv((const char *)lp->ll_name, (int)STRLEN(lp->ll_name), @@ -2472,7 +2507,7 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, tv_clear(&tv); } } else { - set_var(lp->ll_name, lp->ll_name_len, rettv, copy); + set_var_const(lp->ll_name, lp->ll_name_len, rettv, copy, is_const); } *endp = cc; } else if (tv_check_lock(lp->ll_newkey == NULL @@ -2483,6 +2518,11 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, listitem_T *ll_li = lp->ll_li; int ll_n1 = lp->ll_n1; + if (is_const) { + EMSG(_("E996: Cannot lock a range")); + return; + } + // Check whether any of the list items is locked for (ri = tv_list_first(rettv->vval.v_list); ri != NULL && ll_li != NULL; ) { @@ -2538,6 +2578,11 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, dict_T *dict = lp->ll_dict; bool watched = tv_dict_is_watched(dict); + if (is_const) { + EMSG(_("E996: Cannot lock a list or dict")); + return; + } + // Assign to a List or Dictionary item. if (lp->ll_newkey != NULL) { if (op != NULL && *op != '=') { @@ -2661,7 +2706,7 @@ bool next_for_item(void *fi_void, char_u *arg) } else { fi->fi_lw.lw_item = TV_LIST_ITEM_NEXT(fi->fi_list, item); return (ex_let_vars(arg, TV_LIST_ITEM_TV(item), true, - fi->fi_semicolon, fi->fi_varcount, NULL) == OK); + fi->fi_semicolon, fi->fi_varcount, false, NULL) == OK); } } @@ -14912,6 +14957,123 @@ static void f_serverstop(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } +/// Set line or list of lines in buffer "buf". +static void set_buffer_lines(buf_T *buf, linenr_T lnum, typval_T *lines, + typval_T *rettv) +{ + list_T *l = NULL; + listitem_T *li = NULL; + long added = 0; + linenr_T lcount; + buf_T *curbuf_save = NULL; + win_T *curwin_save = NULL; + int is_curbuf = buf == curbuf; + + // When using the current buffer ml_mfp will be set if needed. Useful when + // setline() is used on startup. For other buffers the buffer must be + // loaded. + if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1) { + rettv->vval.v_number = 1; // FAIL + return; + } + + if (!is_curbuf) { + wininfo_T *wip; + + curbuf_save = curbuf; + curwin_save = curwin; + curbuf = buf; + for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next) { + if (wip->wi_win != NULL) { + curwin = wip->wi_win; + break; + } + } + } + + lcount = curbuf->b_ml.ml_line_count; + + const char *line = NULL; + + if (lines->v_type == VAR_LIST) { + l = lines->vval.v_list; + li = tv_list_first(l); + } else { + line = tv_get_string_chk(lines); + } + + // Default result is zero == OK. + for (;; ) { + if (lines->v_type == VAR_LIST) { + // List argument, get next string. + if (li == NULL) { + break; + } + line = tv_get_string_chk(TV_LIST_ITEM_TV(li)); + li = TV_LIST_ITEM_NEXT(l, li); + } + + rettv->vval.v_number = 1; // FAIL + if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1) { + break; + } + + /* When coming here from Insert mode, sync undo, so that this can be + * undone separately from what was previously inserted. */ + if (u_sync_once == 2) { + u_sync_once = 1; /* notify that u_sync() was called */ + u_sync(TRUE); + } + + if (lnum <= curbuf->b_ml.ml_line_count) { + // Existing line, replace it. + if (u_savesub(lnum) == OK + && ml_replace(lnum, (char_u *)line, true) == OK) { + changed_bytes(lnum, 0); + if (is_curbuf && lnum == curwin->w_cursor.lnum) { + check_cursor_col(); + } + rettv->vval.v_number = 0; // OK + } + } else if (added > 0 || u_save(lnum - 1, lnum) == OK) { + // lnum is one past the last line, append the line. + added++; + if (ml_append(lnum - 1, (char_u *)line, 0, false) == OK) { + rettv->vval.v_number = 0; // OK + } + } + + if (l == NULL) /* only one string argument */ + break; + ++lnum; + } + + if (added > 0) { + appended_lines_mark(lcount, added); + } + + if (!is_curbuf) { + curbuf = curbuf_save; + curwin = curwin_save; + } +} + +/// "setbufline()" function +static void f_setbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + linenr_T lnum; + buf_T *buf; + + buf = tv_get_buf(&argvars[0], false); + if (buf == NULL) { + rettv->vval.v_number = 1; // FAIL + } else { + lnum = tv_get_lnum_buf(&argvars[1], buf); + + set_buffer_lines(buf, lnum, &argvars[2], rettv); + } +} + /* * "setbufvar()" function */ @@ -15044,67 +15206,8 @@ static void f_setfperm(typval_T *argvars, typval_T *rettv, FunPtr fptr) */ static void f_setline(typval_T *argvars, typval_T *rettv, FunPtr fptr) { - list_T *l = NULL; - listitem_T *li = NULL; - long added = 0; - linenr_T lcount = curbuf->b_ml.ml_line_count; - linenr_T lnum = tv_get_lnum(&argvars[0]); - const char *line = NULL; - if (argvars[1].v_type == VAR_LIST) { - l = argvars[1].vval.v_list; - li = tv_list_first(l); - } else { - line = tv_get_string_chk(&argvars[1]); - } - - // Default result is zero == OK. - for (;; ) { - if (argvars[1].v_type == VAR_LIST) { - // List argument, get next string. - if (li == NULL) { - break; - } - line = tv_get_string_chk(TV_LIST_ITEM_TV(li)); - li = TV_LIST_ITEM_NEXT(l, li); - } - - rettv->vval.v_number = 1; // FAIL - if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1) { - break; - } - - /* When coming here from Insert mode, sync undo, so that this can be - * undone separately from what was previously inserted. */ - if (u_sync_once == 2) { - u_sync_once = 1; /* notify that u_sync() was called */ - u_sync(TRUE); - } - - if (lnum <= curbuf->b_ml.ml_line_count) { - // Existing line, replace it. - if (u_savesub(lnum) == OK - && ml_replace(lnum, (char_u *)line, true) == OK) { - changed_bytes(lnum, 0); - if (lnum == curwin->w_cursor.lnum) - check_cursor_col(); - rettv->vval.v_number = 0; /* OK */ - } - } else if (added > 0 || u_save(lnum - 1, lnum) == OK) { - // lnum is one past the last line, append the line. - added++; - if (ml_append(lnum - 1, (char_u *)line, 0, false) == OK) { - rettv->vval.v_number = 0; // OK - } - } - - if (l == NULL) /* only one string argument */ - break; - ++lnum; - } - - if (added > 0) - appended_lines_mark(lcount, added); + set_buffer_lines(curbuf, lnum, &argvars[1], rettv); } /// Create quickfix/location list from VimL values @@ -20112,6 +20215,24 @@ static void set_var(const char *name, const size_t name_len, typval_T *const tv, const bool copy) FUNC_ATTR_NONNULL_ALL { + set_var_const(name, name_len, tv, copy, false); +} + +/// Set variable to the given value +/// +/// If the variable already exists, the value is updated. Otherwise the variable +/// is created. +/// +/// @param[in] name Variable name to set. +/// @param[in] name_len Length of the variable name. +/// @param tv Variable value. +/// @param[in] copy True if value in tv is to be copied. +/// @param[in] is_const True if value in tv is to be locked. +static void set_var_const(const char *name, const size_t name_len, + typval_T *const tv, const bool copy, + const bool is_const) + FUNC_ATTR_NONNULL_ALL +{ dictitem_T *v; hashtab_T *ht; dict_T *dict; @@ -20137,6 +20258,11 @@ static void set_var(const char *name, const size_t name_len, typval_T *const tv, typval_T oldtv = TV_INITIAL_VALUE; if (v != NULL) { + if (is_const) { + EMSG(_(e_cannot_mod)); + return; + } + // existing variable, need to clear the value if (var_check_ro(v->di_flags, name, name_len) || tv_check_lock(v->di_tv.v_lock, name, name_len)) { @@ -20203,6 +20329,9 @@ static void set_var(const char *name, const size_t name_len, typval_T *const tv, return; } v->di_flags = DI_FLAGS_ALLOC; + if (is_const) { + v->di_flags |= DI_FLAGS_LOCK; + } } if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT) { @@ -20221,6 +20350,10 @@ static void set_var(const char *name, const size_t name_len, typval_T *const tv, tv_clear(&oldtv); } } + + if (is_const) { + v->di_tv.v_lock |= VAR_LOCKED; + } } /// Check whether variable is read-only (DI_FLAGS_RO, DI_FLAGS_RO_SBX) diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 6159103767..9deee69f32 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -263,6 +263,7 @@ return { serverlist={}, serverstart={args={0, 1}}, serverstop={args=1}, + setbufline={args=3}, setbufvar={args=3}, setcharsearch={args=1}, setcmdpos={args=1}, diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index 0f69d476f9..58dc62e953 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -601,6 +601,12 @@ return { func='ex_wrongmodifier', }, { + command='const', + flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM, CMDWIN), + addr_type=ADDR_LINES, + func='ex_const', + }, + { command='copen', flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR), addr_type=ADDR_LINES, diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua index fdc00d5dc0..d9c65e17c5 100644 --- a/src/nvim/generators/gen_options.lua +++ b/src/nvim/generators/gen_options.lua @@ -79,6 +79,7 @@ local get_flags = function(o) {'pri_mkrc'}, {'deny_in_modelines', 'P_NO_ML'}, {'deny_duplicates', 'P_NODUP'}, + {'modelineexpr', 'P_MLE'}, }) do local key_name = flag_desc[1] local def_name = flag_desc[2] or ('P_' .. key_name:upper()) diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 27ad6bb86c..7efae1e637 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1253,9 +1253,17 @@ openscript ( EMSG(_(e_nesting)); return; } - if (ignore_script) - /* Not reading from script, also don't open one. Warning message? */ + + // Disallow sourcing a file in the sandbox, the commands would be executed + // later, possibly outside of the sandbox. + if (check_secure()) { return; + } + + if (ignore_script) { + // Not reading from script, also don't open one. Warning message? + return; + } if (scriptin[curscript] != NULL) /* already reading script */ ++curscript; diff --git a/src/nvim/option.c b/src/nvim/option.c index a39be0fe96..8dadf926b9 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -253,6 +253,7 @@ typedef struct vimoption { #define P_RWINONLY 0x10000000U ///< only redraw current window #define P_NDNAME 0x20000000U ///< only normal dir name chars allowed #define P_UI_OPTION 0x40000000U ///< send option to remote ui +#define P_MLE 0x80000000U ///< under control of 'modelineexpr' #define HIGHLIGHT_INIT \ "8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText," \ @@ -1327,6 +1328,11 @@ int do_set( errmsg = (char_u *)_("E520: Not allowed in a modeline"); goto skip; } + if ((flags & P_MLE) && !p_mle) { + errmsg = (char_u *)_( + "E992: Not allowed in a modeline when 'modelineexpr' is off"); + goto skip; + } // In diff mode some options are overruled. This avoids that // 'foldmethod' becomes "marker" instead of "diff" and that // "wrap" gets set. diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index f9f2a7d5dc..8df5039037 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -496,6 +496,7 @@ EXTERN long p_mmd; // 'maxmapdepth' EXTERN long p_mmp; // 'maxmempattern' EXTERN long p_mis; // 'menuitems' EXTERN char_u *p_msm; // 'mkspellmem' +EXTERN long p_mle; // 'modelineexpr' EXTERN long p_mls; // 'modelines' EXTERN char_u *p_mouse; // 'mouse' EXTERN char_u *p_mousem; // 'mousemodel' diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 96e098778c..e892e59ba6 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -8,6 +8,7 @@ -- defaults={condition=nil, if_true={vi=224, vim=0}, if_false=nil}, -- secure=nil, gettext=nil, noglob=nil, normal_fname_chars=nil, -- pri_mkrc=nil, deny_in_modelines=nil, normal_dname_chars=nil, +-- modelineexpr=nil, -- expand=nil, nodefault=nil, no_mkrc=nil, vi_def=true, vim=true, -- alloced=nil, -- save_pv_indir=nil, @@ -283,6 +284,7 @@ return { deny_duplicates=true, vi_def=true, expand=true, + secure=true, varname='p_cdpath', defaults={if_true={vi=",,"}} }, @@ -847,6 +849,7 @@ return { type='string', scope={'window'}, vi_def=true, vim=true, + modelineexpr=true, alloced=true, redraw={'current_window'}, defaults={if_true={vi="0"}} @@ -922,6 +925,7 @@ return { type='string', scope={'window'}, vi_def=true, vim=true, + modelineexpr=true, alloced=true, redraw={'current_window'}, defaults={if_true={vi="foldtext()"}} @@ -931,6 +935,7 @@ return { type='string', scope={'buffer'}, vi_def=true, vim=true, + modelineexpr=true, alloced=true, varname='p_fex', defaults={if_true={vi=""}} @@ -1045,6 +1050,7 @@ return { full_name='guitablabel', abbreviation='gtl', type='string', scope={'global'}, vi_def=true, + modelineexpr=true, redraw={'current_window'}, enable_if=false, }, @@ -1136,6 +1142,7 @@ return { full_name='iconstring', type='string', scope={'global'}, vi_def=true, + modelineexpr=true, varname='p_iconstring', defaults={if_true={vi=""}} }, @@ -1198,6 +1205,7 @@ return { full_name='includeexpr', abbreviation='inex', type='string', scope={'buffer'}, vi_def=true, + modelineexpr=true, alloced=true, varname='p_inex', defaults={if_true={vi=""}} @@ -1214,6 +1222,7 @@ return { type='string', scope={'buffer'}, vi_def=true, vim=true, + modelineexpr=true, alloced=true, varname='p_inde', defaults={if_true={vi=""}} @@ -1528,6 +1537,14 @@ return { defaults={if_true={vi=false, vim=true}} }, { + full_name='modelineexpr', abbreviation='mle', + type='bool', scope={'global'}, + vi_def=true, + secure=true, + varname='p_mle', + defaults={if_true={vi=false}} + }, + { full_name='modelines', abbreviation='mls', type='number', scope={'global'}, vi_def=true, @@ -1903,6 +1920,7 @@ return { type='string', scope={'global'}, vi_def=true, alloced=true, + modelineexpr=true, redraw={'statuslines'}, varname='p_ruf', defaults={if_true={vi=""}} @@ -2310,6 +2328,7 @@ return { type='string', scope={'global', 'window'}, vi_def=true, alloced=true, + modelineexpr=true, redraw={'statuslines'}, varname='p_stl', defaults={if_true={vi=""}} @@ -2369,6 +2388,7 @@ return { full_name='tabline', abbreviation='tal', type='string', scope={'global'}, vi_def=true, + modelineexpr=true, redraw={'all_windows'}, varname='p_tal', defaults={if_true={vi=""}} @@ -2528,6 +2548,7 @@ return { full_name='titlestring', type='string', scope={'global'}, vi_def=true, + modelineexpr=true, varname='p_titlestring', defaults={if_true={vi=""}} }, diff --git a/src/nvim/os/dl.c b/src/nvim/os/dl.c index bbd0424a82..f0fadb16f2 100644 --- a/src/nvim/os/dl.c +++ b/src/nvim/os/dl.c @@ -54,6 +54,7 @@ bool os_libcall(const char *libname, // open the dynamic loadable library if (uv_dlopen(libname, &lib)) { EMSG2(_("dlerror = \"%s\""), uv_dlerror(&lib)); + uv_dlclose(&lib); return false; } diff --git a/src/nvim/testdir/shared.vim b/src/nvim/testdir/shared.vim index ac34dec569..a5cf4def4f 100644 --- a/src/nvim/testdir/shared.vim +++ b/src/nvim/testdir/shared.vim @@ -190,12 +190,18 @@ func s:feedkeys(timer) endfunc " Get the command to run Vim, with -u NONE and --headless arguments. +" If there is an argument use it instead of "NONE". " Returns an empty string on error. -func GetVimCommand() +func GetVimCommand(...) + if a:0 == 0 + let name = 'NONE' + else + let name = a:1 + endif let cmd = v:progpath - let cmd = substitute(cmd, '-u \f\+', '-u NONE', '') - if cmd !~ '-u NONE' - let cmd = cmd . ' -u NONE' + let cmd = substitute(cmd, '-u \f\+', '-u ' . name, '') + if cmd !~ '-u '. name + let cmd = cmd . ' -u ' . name endif let cmd .= ' --headless -i NONE' let cmd = substitute(cmd, 'VIMRUNTIME=.*VIMRUNTIME;', '', '') diff --git a/src/nvim/testdir/test49.vim b/src/nvim/testdir/test49.vim index 467abcd9b9..837e55ebca 100644 --- a/src/nvim/testdir/test49.vim +++ b/src/nvim/testdir/test49.vim @@ -1,6 +1,6 @@ " Vim script language tests " Author: Servatius Brandt <Servatius.Brandt@fujitsu-siemens.com> -" Last Change: 2016 Feb 07 +" Last Change: 2019 May 24 "------------------------------------------------------------------------------- " Test environment {{{1 @@ -9005,5 +9005,4 @@ Xcheck 50443995 "------------------------------------------------------------------------------- " Modelines {{{1 " vim: ts=8 sw=4 tw=80 fdm=marker -" vim: fdt=substitute(substitute(foldtext(),\ '\\%(^+--\\)\\@<=\\(\\s*\\)\\(.\\{-}\\)\:\ \\%(\"\ \\)\\=\\(Test\ \\d*\\)\:\\s*',\ '\\3\ (\\2)\:\ \\1',\ \"\"),\ '\\(Test\\s*\\)\\(\\d\\)\\D\\@=',\ '\\1\ \\2',\ "") "------------------------------------------------------------------------------- diff --git a/src/nvim/testdir/test_bufline.vim b/src/nvim/testdir/test_bufline.vim new file mode 100644 index 0000000000..b886e99506 --- /dev/null +++ b/src/nvim/testdir/test_bufline.vim @@ -0,0 +1,67 @@ +" Tests for setbufline() and getbufline() + +source shared.vim + +func Test_setbufline_getbufline() + new + let b = bufnr('%') + hide + call assert_equal(0, setbufline(b, 1, ['foo', 'bar'])) + call assert_equal(['foo'], getbufline(b, 1)) + call assert_equal(['bar'], getbufline(b, 2)) + call assert_equal(['foo', 'bar'], getbufline(b, 1, 2)) + exe "bd!" b + call assert_equal([], getbufline(b, 1, 2)) + + split Xtest + call setline(1, ['a', 'b', 'c']) + let b = bufnr('%') + wincmd w + call assert_equal(1, setbufline(b, 5, ['x'])) + call assert_equal(1, setbufline(1234, 1, ['x'])) + call assert_equal(0, setbufline(b, 4, ['d', 'e'])) + call assert_equal(['c'], getbufline(b, 3)) + call assert_equal(['d'], getbufline(b, 4)) + call assert_equal(['e'], getbufline(b, 5)) + call assert_equal([], getbufline(b, 6)) + exe "bwipe! " . b +endfunc + +func Test_setbufline_getbufline_fold() + split Xtest + setlocal foldmethod=expr foldexpr=0 + let b = bufnr('%') + new + call assert_equal(0, setbufline(b, 1, ['foo', 'bar'])) + call assert_equal(['foo'], getbufline(b, 1)) + call assert_equal(['bar'], getbufline(b, 2)) + call assert_equal(['foo', 'bar'], getbufline(b, 1, 2)) + exe "bwipe!" b + bwipe! +endfunc + +func Test_setbufline_getbufline_fold_tab() + split Xtest + setlocal foldmethod=expr foldexpr=0 + let b = bufnr('%') + tab new + call assert_equal(0, setbufline(b, 1, ['foo', 'bar'])) + call assert_equal(['foo'], getbufline(b, 1)) + call assert_equal(['bar'], getbufline(b, 2)) + call assert_equal(['foo', 'bar'], getbufline(b, 1, 2)) + exe "bwipe!" b + bwipe! +endfunc + +func Test_setline_startup() + let cmd = GetVimCommand('Xscript') + if cmd == '' + return + endif + call writefile(['call setline(1, "Hello")', 'silent w Xtest', 'q!'], 'Xscript') + call system(cmd) + call assert_equal(['Hello'], readfile('Xtest')) + + call delete('Xscript') + call delete('Xtest') +endfunc diff --git a/src/nvim/testdir/test_const.vim b/src/nvim/testdir/test_const.vim new file mode 100644 index 0000000000..06062c5e58 --- /dev/null +++ b/src/nvim/testdir/test_const.vim @@ -0,0 +1,237 @@ + +" Test for :const + +func s:noop() +endfunc + +func Test_define_var_with_lock() + const i = 1 + const f = 1.1 + const s = 'vim' + const F = funcref('s:noop') + const l = [1, 2, 3] + const d = {'foo': 10} + if has('channel') + const j = test_null_job() + const c = test_null_channel() + endif + const b = v:true + const n = v:null + + call assert_true(exists('i')) + call assert_true(exists('f')) + call assert_true(exists('s')) + call assert_true(exists('F')) + call assert_true(exists('l')) + call assert_true(exists('d')) + if has('channel') + call assert_true(exists('j')) + call assert_true(exists('c')) + endif + call assert_true(exists('b')) + call assert_true(exists('n')) + + call assert_fails('let i = 1', 'E741:') + call assert_fails('let f = 1.1', 'E741:') + call assert_fails('let s = "vim"', 'E741:') + call assert_fails('let F = funcref("s:noop")', 'E741:') + call assert_fails('let l = [1, 2, 3]', 'E741:') + call assert_fails('let d = {"foo": 10}', 'E741:') + if has('channel') + call assert_fails('let j = test_null_job()', 'E741:') + call assert_fails('let c = test_null_channel()', 'E741:') + endif + call assert_fails('let b = v:true', 'E741:') + call assert_fails('let n = v:null', 'E741:') + + " Unlet + unlet i + unlet f + unlet s + unlet F + unlet l + unlet d + if has('channel') + unlet j + unlet c + endif + unlet b + unlet n +endfunc + +func Test_define_l_var_with_lock() + " With l: prefix + const l:i = 1 + const l:f = 1.1 + const l:s = 'vim' + const l:F = funcref('s:noop') + const l:l = [1, 2, 3] + const l:d = {'foo': 10} + if has('channel') + const l:j = test_null_job() + const l:c = test_null_channel() + endif + const l:b = v:true + const l:n = v:null + + call assert_fails('let l:i = 1', 'E741:') + call assert_fails('let l:f = 1.1', 'E741:') + call assert_fails('let l:s = "vim"', 'E741:') + call assert_fails('let l:F = funcref("s:noop")', 'E741:') + call assert_fails('let l:l = [1, 2, 3]', 'E741:') + call assert_fails('let l:d = {"foo": 10}', 'E741:') + if has('channel') + call assert_fails('let l:j = test_null_job()', 'E741:') + call assert_fails('let l:c = test_null_channel()', 'E741:') + endif + call assert_fails('let l:b = v:true', 'E741:') + call assert_fails('let l:n = v:null', 'E741:') + + " Unlet + unlet l:i + unlet l:f + unlet l:s + unlet l:F + unlet l:l + unlet l:d + if has('channel') + unlet l:j + unlet l:c + endif + unlet l:b + unlet l:n +endfunc + +func Test_define_script_var_with_lock() + const s:x = 0 + call assert_fails('let s:x = 1', 'E741:') + unlet s:x +endfunc + +func Test_descructuring_with_lock() + const [a, b, c] = [1, 1.1, 'vim'] + + call assert_fails('let a = 1', 'E741:') + call assert_fails('let b = 1.1', 'E741:') + call assert_fails('let c = "vim"', 'E741:') + + const [d; e] = [1, 1.1, 'vim'] + call assert_fails('let d = 1', 'E741:') + call assert_fails('let e = [2.2, "a"]', 'E741:') +endfunc + +func Test_cannot_modify_existing_variable() + let i = 1 + let f = 1.1 + let s = 'vim' + let F = funcref('s:noop') + let l = [1, 2, 3] + let d = {'foo': 10} + if has('channel') + let j = test_null_job() + let c = test_null_channel() + endif + let b = v:true + let n = v:null + + call assert_fails('const i = 1', 'E995:') + call assert_fails('const f = 1.1', 'E995:') + call assert_fails('const s = "vim"', 'E995:') + call assert_fails('const F = funcref("s:noop")', 'E995:') + call assert_fails('const l = [1, 2, 3]', 'E995:') + call assert_fails('const d = {"foo": 10}', 'E995:') + if has('channel') + call assert_fails('const j = test_null_job()', 'E995:') + call assert_fails('const c = test_null_channel()', 'E995:') + endif + call assert_fails('const b = v:true', 'E995:') + call assert_fails('const n = v:null', 'E995:') + call assert_fails('const [i, f, s] = [1, 1.1, "vim"]', 'E995:') + + const i2 = 1 + const f2 = 1.1 + const s2 = 'vim' + const F2 = funcref('s:noop') + const l2 = [1, 2, 3] + const d2 = {'foo': 10} + if has('channel') + const j2 = test_null_job() + const c2 = test_null_channel() + endif + const b2 = v:true + const n2 = v:null + + call assert_fails('const i2 = 1', 'E995:') + call assert_fails('const f2 = 1.1', 'E995:') + call assert_fails('const s2 = "vim"', 'E995:') + call assert_fails('const F2 = funcref("s:noop")', 'E995:') + call assert_fails('const l2 = [1, 2, 3]', 'E995:') + call assert_fails('const d2 = {"foo": 10}', 'E995:') + if has('channel') + call assert_fails('const j2 = test_null_job()', 'E995:') + call assert_fails('const c2 = test_null_channel()', 'E995:') + endif + call assert_fails('const b2 = v:true', 'E995:') + call assert_fails('const n2 = v:null', 'E995:') + call assert_fails('const [i2, f2, s2] = [1, 1.1, "vim"]', 'E995:') +endfunc + +func Test_const_with_index_access() + let l = [1, 2, 3] + call assert_fails('const l[0] = 4', 'E996:') + call assert_fails('const l[0:1] = [1, 2]', 'E996:') + + let d = {'aaa': 0} + call assert_fails("const d['aaa'] = 4", 'E996:') + call assert_fails("const d.aaa = 4", 'E996:') +endfunc + +func Test_const_with_compound_assign() + let i = 0 + call assert_fails('const i += 4', 'E995:') + call assert_fails('const i -= 4', 'E995:') + call assert_fails('const i *= 4', 'E995:') + call assert_fails('const i /= 4', 'E995:') + call assert_fails('const i %= 4', 'E995:') + + let s = 'a' + call assert_fails('const s .= "b"', 'E995:') + + let [a, b, c] = [1, 2, 3] + call assert_fails('const [a, b, c] += [4, 5, 6]', 'E995:') + + let [d; e] = [1, 2, 3] + call assert_fails('const [d; e] += [4, 5, 6]', 'E995:') +endfunc + +func Test_const_with_special_variables() + call assert_fails('const $FOO = "hello"', 'E996:') + call assert_fails('const @a = "hello"', 'E996:') + call assert_fails('const &filetype = "vim"', 'E996:') + call assert_fails('const &l:filetype = "vim"', 'E996:') + call assert_fails('const &g:encoding = "utf-8"', 'E996:') +endfunc + +func Test_const_with_eval_name() + let s = 'foo' + + " eval name with :const should work + const abc_{s} = 1 + const {s}{s} = 1 + + let s2 = 'abc_foo' + call assert_fails('const {s2} = "bar"', 'E995:') +endfunc + +func Test_lock_depth_is_1() + const l = [1, 2, 3] + const d = {'foo': 10} + + " Modify list + call add(l, 4) + let l[0] = 42 + + " Modify dict + let d['bar'] = 'hello' + let d.foo = 44 +endfunc diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim index ed9c70403e..0c3c356622 100644 --- a/src/nvim/testdir/test_functions.vim +++ b/src/nvim/testdir/test_functions.vim @@ -1,4 +1,5 @@ " Tests for various functions. +source shared.vim " Must be done first, since the alternate buffer must be unset. func Test_00_bufexists() @@ -1140,3 +1141,50 @@ func Test_reg_executing_and_recording() delfunc s:save_reg_stat unlet s:reg_stat endfunc + +func Test_libcall_libcallnr() + if !has('libcall') + return + endif + + if has('win32') + let libc = 'msvcrt.dll' + elseif has('mac') + let libc = 'libSystem.B.dylib' + elseif system('uname -s') =~ 'SunOS' + " Set the path to libc.so according to the architecture. + let test_bits = system('file ' . GetVimProg()) + let test_arch = system('uname -p') + if test_bits =~ '64-bit' && test_arch =~ 'sparc' + let libc = '/usr/lib/sparcv9/libc.so' + elseif test_bits =~ '64-bit' && test_arch =~ 'i386' + let libc = '/usr/lib/amd64/libc.so' + else + let libc = '/usr/lib/libc.so' + endif + else + " On Unix, libc.so can be in various places. + " Interestingly, using an empty string for the 1st argument of libcall + " allows to call functions from libc which is not documented. + let libc = '' + endif + + if has('win32') + call assert_equal($USERPROFILE, libcall(libc, 'getenv', 'USERPROFILE')) + else + call assert_equal($HOME, libcall(libc, 'getenv', 'HOME')) + endif + + " If function returns NULL, libcall() should return an empty string. + call assert_equal('', libcall(libc, 'getenv', 'X_ENV_DOES_NOT_EXIT')) + + " Test libcallnr() with string and integer argument. + call assert_equal(4, libcallnr(libc, 'strlen', 'abcd')) + call assert_equal(char2nr('A'), libcallnr(libc, 'toupper', char2nr('a'))) + + call assert_fails("call libcall(libc, 'Xdoesnotexist_', '')", 'E364:') + call assert_fails("call libcallnr(libc, 'Xdoesnotexist_', '')", 'E364:') + + call assert_fails("call libcall('Xdoesnotexist_', 'getenv', 'HOME')", 'E364:') + call assert_fails("call libcallnr('Xdoesnotexist_', 'strlen', 'abcd')", 'E364:') +endfunc diff --git a/src/nvim/testdir/test_modeline.vim b/src/nvim/testdir/test_modeline.vim index 091a833774..1e196e07f0 100644 --- a/src/nvim/testdir/test_modeline.vim +++ b/src/nvim/testdir/test_modeline.vim @@ -60,14 +60,17 @@ func Test_modeline_keymap() set keymap= iminsert=0 imsearch=-1 endfunc -func s:modeline_fails(what, text) +func s:modeline_fails(what, text, error) + if !exists('+' . a:what) + return + endif let fname = "Xmodeline_fails_" . a:what call writefile(['vim: set ' . a:text . ' :', 'nothing'], fname) let modeline = &modeline set modeline filetype plugin on syntax enable - call assert_fails('split ' . fname, 'E474:') + call assert_fails('split ' . fname, a:error) call assert_equal("", &filetype) call assert_equal("", &syntax) @@ -79,16 +82,92 @@ func s:modeline_fails(what, text) endfunc func Test_modeline_filetype_fails() - call s:modeline_fails('filetype', 'ft=evil$CMD') + call s:modeline_fails('filetype', 'ft=evil$CMD', 'E474:') endfunc func Test_modeline_syntax_fails() - call s:modeline_fails('syntax', 'syn=evil$CMD') + call s:modeline_fails('syntax', 'syn=evil$CMD', 'E474:') endfunc func Test_modeline_keymap_fails() - if !has('keymap') - return - endif - call s:modeline_fails('keymap', 'keymap=evil$CMD') + call s:modeline_fails('keymap', 'keymap=evil$CMD', 'E474:') +endfunc + +func Test_modeline_fails_always() + call s:modeline_fails('backupdir', 'backupdir=Something()', 'E520:') + call s:modeline_fails('cdpath', 'cdpath=Something()', 'E520:') + call s:modeline_fails('charconvert', 'charconvert=Something()', 'E520:') + call s:modeline_fails('completefunc', 'completefunc=Something()', 'E520:') + call s:modeline_fails('cscopeprg', 'cscopeprg=Something()', 'E520:') + call s:modeline_fails('diffexpr', 'diffexpr=Something()', 'E520:') + call s:modeline_fails('directory', 'directory=Something()', 'E520:') + call s:modeline_fails('equalprg', 'equalprg=Something()', 'E520:') + call s:modeline_fails('errorfile', 'errorfile=Something()', 'E520:') + call s:modeline_fails('exrc', 'exrc=Something()', 'E520:') + call s:modeline_fails('formatprg', 'formatprg=Something()', 'E520:') + call s:modeline_fails('fsync', 'fsync=Something()', 'E520:') + call s:modeline_fails('grepprg', 'grepprg=Something()', 'E520:') + call s:modeline_fails('helpfile', 'helpfile=Something()', 'E520:') + call s:modeline_fails('imactivatefunc', 'imactivatefunc=Something()', 'E520:') + call s:modeline_fails('imstatusfunc', 'imstatusfunc=Something()', 'E520:') + call s:modeline_fails('imstyle', 'imstyle=Something()', 'E520:') + call s:modeline_fails('keywordprg', 'keywordprg=Something()', 'E520:') + call s:modeline_fails('langmap', 'langmap=Something()', 'E520:') + call s:modeline_fails('luadll', 'luadll=Something()', 'E520:') + call s:modeline_fails('makeef', 'makeef=Something()', 'E520:') + call s:modeline_fails('makeprg', 'makeprg=Something()', 'E520:') + call s:modeline_fails('mkspellmem', 'mkspellmem=Something()', 'E520:') + call s:modeline_fails('mzschemedll', 'mzschemedll=Something()', 'E520:') + call s:modeline_fails('mzschemegcdll', 'mzschemegcdll=Something()', 'E520:') + call s:modeline_fails('modelineexpr', 'modelineexpr=Something()', 'E520:') + call s:modeline_fails('omnifunc', 'omnifunc=Something()', 'E520:') + call s:modeline_fails('operatorfunc', 'operatorfunc=Something()', 'E520:') + call s:modeline_fails('perldll', 'perldll=Something()', 'E520:') + call s:modeline_fails('printdevice', 'printdevice=Something()', 'E520:') + call s:modeline_fails('patchexpr', 'patchexpr=Something()', 'E520:') + call s:modeline_fails('printexpr', 'printexpr=Something()', 'E520:') + call s:modeline_fails('pythondll', 'pythondll=Something()', 'E520:') + call s:modeline_fails('pythonhome', 'pythonhome=Something()', 'E520:') + call s:modeline_fails('pythonthreedll', 'pythonthreedll=Something()', 'E520:') + call s:modeline_fails('pythonthreehome', 'pythonthreehome=Something()', 'E520:') + call s:modeline_fails('pyxversion', 'pyxversion=Something()', 'E520:') + call s:modeline_fails('rubydll', 'rubydll=Something()', 'E520:') + call s:modeline_fails('runtimepath', 'runtimepath=Something()', 'E520:') + call s:modeline_fails('secure', 'secure=Something()', 'E520:') + call s:modeline_fails('shell', 'shell=Something()', 'E520:') + call s:modeline_fails('shellcmdflag', 'shellcmdflag=Something()', 'E520:') + call s:modeline_fails('shellpipe', 'shellpipe=Something()', 'E520:') + call s:modeline_fails('shellquote', 'shellquote=Something()', 'E520:') + call s:modeline_fails('shellredir', 'shellredir=Something()', 'E520:') + call s:modeline_fails('shellxquote', 'shellxquote=Something()', 'E520:') + call s:modeline_fails('spellfile', 'spellfile=Something()', 'E520:') + call s:modeline_fails('spellsuggest', 'spellsuggest=Something()', 'E520:') + call s:modeline_fails('tcldll', 'tcldll=Something()', 'E520:') + call s:modeline_fails('titleold', 'titleold=Something()', 'E520:') + call s:modeline_fails('viewdir', 'viewdir=Something()', 'E520:') + call s:modeline_fails('viminfo', 'viminfo=Something()', 'E520:') + call s:modeline_fails('viminfofile', 'viminfofile=Something()', 'E520:') + call s:modeline_fails('winptydll', 'winptydll=Something()', 'E520:') + call s:modeline_fails('undodir', 'undodir=Something()', 'E520:') + " only check a few terminal options + " Skip these since nvim doesn't support termcodes as options + "call s:modeline_fails('t_AB', 't_AB=Something()', 'E520:') + "call s:modeline_fails('t_ce', 't_ce=Something()', 'E520:') + "call s:modeline_fails('t_sr', 't_sr=Something()', 'E520:') + "call s:modeline_fails('t_8b', 't_8b=Something()', 'E520:') +endfunc + +func Test_modeline_fails_modelineexpr() + call s:modeline_fails('balloonexpr', 'balloonexpr=Something()', 'E992:') + call s:modeline_fails('foldexpr', 'foldexpr=Something()', 'E992:') + call s:modeline_fails('foldtext', 'foldtext=Something()', 'E992:') + call s:modeline_fails('formatexpr', 'formatexpr=Something()', 'E992:') + call s:modeline_fails('guitablabel', 'guitablabel=Something()', 'E992:') + call s:modeline_fails('iconstring', 'iconstring=Something()', 'E992:') + call s:modeline_fails('includeexpr', 'includeexpr=Something()', 'E992:') + call s:modeline_fails('indentexpr', 'indentexpr=Something()', 'E992:') + call s:modeline_fails('rulerformat', 'rulerformat=Something()', 'E992:') + call s:modeline_fails('statusline', 'statusline=Something()', 'E992:') + call s:modeline_fails('tabline', 'tabline=Something()', 'E992:') + call s:modeline_fails('titlestring', 'titlestring=Something()', 'E992:') endfunc diff --git a/src/nvim/testdir/test_source.vim b/src/nvim/testdir/test_source.vim new file mode 100644 index 0000000000..42ac0c4d0f --- /dev/null +++ b/src/nvim/testdir/test_source.vim @@ -0,0 +1,10 @@ +" Tests for the :source command. + +func Test_source_sandbox() + new + call writefile(["Ohello\<Esc>"], 'Xsourcehello') + source! Xsourcehello | echo + call assert_equal('hello', getline(1)) + call assert_fails('sandbox source! Xsourcehello', 'E48:') + bwipe! +endfunc diff --git a/src/nvim/testdir/test_vimscript.vim b/src/nvim/testdir/test_vimscript.vim index d0ecbef7e1..f3e40e1210 100644 --- a/src/nvim/testdir/test_vimscript.vim +++ b/src/nvim/testdir/test_vimscript.vim @@ -1375,5 +1375,4 @@ endfunc "------------------------------------------------------------------------------- " Modelines {{{1 " vim: ts=8 sw=4 tw=80 fdm=marker -" vim: fdt=substitute(substitute(foldtext(),\ '\\%(^+--\\)\\@<=\\(\\s*\\)\\(.\\{-}\\)\:\ \\%(\"\ \\)\\=\\(Test\ \\d*\\)\:\\s*',\ '\\3\ (\\2)\:\ \\1',\ \"\"),\ '\\(Test\\s*\\)\\(\\d\\)\\D\\@=',\ '\\1\ \\2',\ "") "------------------------------------------------------------------------------- diff --git a/src/nvim/testdir/test_writefile.vim b/src/nvim/testdir/test_writefile.vim index 9da9df2150..6d88c0d8cd 100644 --- a/src/nvim/testdir/test_writefile.vim +++ b/src/nvim/testdir/test_writefile.vim @@ -33,7 +33,7 @@ func Test_writefile_fails_gently() endfunc func Test_writefile_fails_conversion() - if !has('multi_byte') || !has('iconv') + if !has('multi_byte') || !has('iconv') || system('uname -s') =~ 'SunOS' return endif " Without a backup file the write won't happen if there is a conversion |