diff options
31 files changed, 561 insertions, 115 deletions
diff --git a/runtime/compiler/xo.vim b/runtime/compiler/xo.vim new file mode 100644 index 0000000000..525657d4bb --- /dev/null +++ b/runtime/compiler/xo.vim @@ -0,0 +1,26 @@ +" Vim compiler file +" Compiler: XO +" Maintainer: Doug Kearns <dougkearns@gmail.com> +" Last Change: 2019 Jul 10 + +if exists("current_compiler") + finish +endif +let current_compiler = "xo" + +if exists(":CompilerSet") != 2 " older Vim always used :setlocal + command -nargs=* CompilerSet setlocal <args> +endif + +let s:cpo_save = &cpo +set cpo&vim + +" CompilerSet makeprg=npx\ xo\ --reporter\ compact + +CompilerSet makeprg=xo\ --reporter\ compact +CompilerSet errorformat=%f:\ line\ %l\\,\ col\ %c\\,\ %trror\ %m, + \%f:\ line\ %l\\,\ col\ %c\\,\ %tarning\ %m, + \%-G%.%# + +let &cpo = s:cpo_save +unlet s:cpo_save diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index efb6272e58..448885296d 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2224,6 +2224,7 @@ inputsecret({prompt} [, {text}]) String like input() but hiding the text insert({list}, {item} [, {idx}]) List insert {item} in {list} [before {idx}] +interrupt() none interrupt script execution invert({expr}) Number bitwise invert isdirectory({directory}) Number |TRUE| if {directory} is a directory isinf({expr}) Number determine if {expr} is infinity value @@ -5412,6 +5413,19 @@ insert({list}, {item} [, {idx}]) *insert()* Note that when {item} is a |List| it is inserted as a single item. Use |extend()| to concatenate |Lists|. +interrupt() *interrupt()* + Interrupt script execution. It works more or less like the + user typing CTRL-C, most commands won't execute and control + returns to the user. This is useful to abort execution + from lower down, e.g. in an autocommand. Example: > + :function s:check_typoname(file) + : if fnamemodify(a:file, ':t') == '[' + : echomsg 'Maybe typo' + : call interrupt() + : endif + :endfunction + :au BufWritePre * call s:check_typoname(expand('<amatch>')) + invert({expr}) *invert()* Bitwise invert. The argument is converted to a number. A List, Dict or Float argument causes an error. Example: > diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt index ed31ecc42e..1514f03c55 100644 --- a/runtime/doc/map.txt +++ b/runtime/doc/map.txt @@ -1078,6 +1078,10 @@ When executing an autocommand or a user command, it will run in the context of the script it was defined in. This makes it possible that the command calls a local function or uses a local mapping. +In case the value is used in a context where <SID> cannot be correctly +expanded, use the expand() function: > + let &includexpr = expand('<SID>') .. 'My_includeexpr()' + Otherwise, using "<SID>" outside of a script context is an error. If you need to get the script number to use in a complicated script, you can @@ -1162,6 +1166,10 @@ See |:verbose-cmd| for more information. attributes (see below) are {attr}. If the command already exists, an error is reported, unless a ! is specified, in which case the command is redefined. + There is one exception: When sourcing a script again, + a command that was previously defined in that script + will be silently replaced. + :delc[ommand] {cmd} *:delc* *:delcommand* *E184* Delete the user-defined command {cmd}. @@ -1169,7 +1177,8 @@ See |:verbose-cmd| for more information. :comc[lear] *:comc* *:comclear* Delete all user-defined commands. -Command attributes + +Command attributes ~ User-defined commands are treated by Vim just like any other Ex commands. They can have arguments, or have a range specified. Arguments are subject to @@ -1180,8 +1189,9 @@ There are a number of attributes, split into four categories: argument handling, completion behavior, range handling, and special cases. The attributes are described below, by category. -Argument handling *E175* *E176* *:command-nargs* +Argument handling ~ + *E175* *E176* *:command-nargs* By default, a user defined command will take no arguments (and an error is reported if any are supplied). However, it is possible to specify that the command can take arguments, using the -nargs attribute. Valid cases are: @@ -1257,9 +1267,9 @@ completion can be enabled: Note: That some completion methods might expand environment variables. -Custom completion *:command-completion-custom* - *:command-completion-customlist* - *E467* *E468* +Custom completion ~ + *:command-completion-custom* + *:command-completion-customlist* *E467* *E468* It is possible to define customized completion schemes via the "custom,{func}" or the "customlist,{func}" completion argument. The {func} part should be a function with the following signature: > @@ -1304,8 +1314,8 @@ the 'path' option: > This example does not work for file names with spaces! -Range handling *E177* *E178* *:command-range* - *:command-count* +Range handling ~ + *E177* *E178* *:command-range* *:command-count* By default, user-defined commands do not accept a line number range. However, it is possible to specify that the command does take a range (the -range attribute), or that it takes an arbitrary count value, either in the line @@ -1342,7 +1352,8 @@ Possible values are: -addr=other other kind of range -Special cases *:command-bang* *:command-bar* +Special cases ~ + *:command-bang* *:command-bar* *:command-register* *:command-buffer* There are some special cases as well: @@ -1360,7 +1371,8 @@ replacement text separately. Note that these arguments can be abbreviated, but that is a deprecated feature. Use the full name for new scripts. -Replacement text + +Replacement text ~ The replacement text for a user defined command is scanned for special escape sequences, using <...> notation. Escape sequences are replaced with values diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 29f4abf250..8efd876d76 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -5043,9 +5043,7 @@ A jump table for the options with a short description can be found at |Q_op|. Don't include both "curdir" and "sesdir". When neither "curdir" nor "sesdir" is included, file names are stored with absolute paths. - "slash" and "unix" are useful on Windows when sharing session files - with Unix. The Unix version of Vim cannot source dos format scripts, - but the Windows version of Vim can source unix format scripts. + "slash" and "unix" are always enabled. *'shada'* *'sd'* *E526* *E527* *E528* 'shada' 'sd' string (Vim default for diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt index 24b562543e..0ba2711090 100644 --- a/runtime/doc/vim_diff.txt +++ b/runtime/doc/vim_diff.txt @@ -50,7 +50,7 @@ the differences. - 'listchars' defaults to "tab:> ,trail:-,nbsp:+" - 'nrformats' defaults to "bin,hex" - 'ruler' is enabled -- 'sessionoptions' excludes "options" +- 'sessionoptions' enables "slash,unix", excludes "options" - 'shortmess' includes "F", excludes "S" - 'showcmd' is enabled - 'sidescroll' defaults to 1 diff --git a/runtime/filetype.vim b/runtime/filetype.vim index c0d656107c..41a9188905 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -180,7 +180,7 @@ au BufNewFile,BufRead *.at setf m4 au BufNewFile,BufRead *.ave setf ave " Awk -au BufNewFile,BufRead *.awk setf awk +au BufNewFile,BufRead *.awk,*.gawk setf awk " B au BufNewFile,BufRead *.mch,*.ref,*.imp setf b @@ -1089,6 +1089,9 @@ au BufNewFile,BufRead .netrc setf netrc " Ninja file au BufNewFile,BufRead *.ninja setf ninja +" NPM RC file +au BufNewFile,BufRead npmrc,.npmrc setf dosini + " Novell netware batch files au BufNewFile,BufRead *.ncf setf ncf @@ -1195,6 +1198,9 @@ au BufNewFile,BufRead *.pod6 setf pod6 " Also .ctp for Cake template file au BufNewFile,BufRead *.php,*.php\d,*.phtml,*.ctp setf php +" PHP config +au BufNewFile,BufRead php.ini,php.ini-* setf dosini + " Pike and Cmod au BufNewFile,BufRead *.pike,*.pmod setf pike au BufNewFile,BufRead *.cmod setf cmod diff --git a/runtime/tools/check_colors.vim b/runtime/tools/check_colors.vim index 57b71b19db..e4acbc33ec 100644 --- a/runtime/tools/check_colors.vim +++ b/runtime/tools/check_colors.vim @@ -1,6 +1,6 @@ " This script tests a color scheme for some errors and lists potential errors. " Load the scheme and source this script, like this: -" :edit colors/desert.vim | :so colors/tools/check_colors.vim +" :edit colors/desert.vim | :so tools/check_colors.vim let s:save_cpo= &cpo set cpo&vim @@ -8,7 +8,7 @@ set cpo&vim func! Test_check_colors() let l:savedview = winsaveview() call cursor(1,1) - let err={} + let err = {} " 1) Check g:colors_name is existing if !search('\<\%(g:\)\?colors_name\>', 'cnW') @@ -81,36 +81,39 @@ func! Test_check_colors() \ 'WarningMsg', \ 'WildMenu', \ ] - let groups={} + let groups = {} for group in hi_groups - if search('\c@suppress\s\+'.group, 'cnW') + if search('\c@suppress\s\+\<' .. group .. '\>', 'cnW') " skip check, if the script contains a line like " @suppress Visual: - let groups[group] = 'Ignoring '.group continue endif - if search('hi\%[ghlight]!\= \+link \+'.group, 'cnW') " Linked group + if search('hi\%[ghlight]!\= \+link \+' .. group, 'cnW') " Linked group continue endif - if !search('hi\%[ghlight] \+'.group, 'cnW') - let groups[group] = 'No highlight definition for '.group + if !search('hi\%[ghlight] \+\<' .. group .. '\>', 'cnW') + let groups[group] = 'No highlight definition for ' .. group continue endif - if !search('hi\%[ghlight] \+'.group. '.*fg=', 'cnW') - let groups[group] = 'Missing foreground color for '.group + if !search('hi\%[ghlight] \+\<' .. group .. '\>.*[bf]g=', 'cnW') + let groups[group] = 'Missing foreground or background color for ' .. group continue endif - if search('hi\%[ghlight] \+'.group. '.*guibg=', 'cnW') && - \ !search('hi\%[ghlight] \+'.group. '.*ctermbg=', 'cnW') - let groups[group] = 'Missing bg terminal color for '.group + if search('hi\%[ghlight] \+\<' .. group .. '\>.*guibg=', 'cnW') && + \ !search('hi\%[ghlight] \+\<' .. group .. '\>.*ctermbg=', 'cnW') + \ && group != 'Cursor' + let groups[group] = 'Missing bg terminal color for ' .. group continue endif - if !search('hi\%[ghlight] \+'.group. '.*guifg=', 'cnW') - let groups[group] = 'Missing guifg definition for '.group + if !search('hi\%[ghlight] \+\<' .. group .. '\>.*guifg=', 'cnW') + \ && group !~ '^Diff' + let groups[group] = 'Missing guifg definition for ' .. group continue endif - if !search('hi\%[ghlight] \+'.group. '.*ctermfg=', 'cnW') - let groups[group] = 'Missing ctermfg definition for '.group + if !search('hi\%[ghlight] \+\<' .. group .. '\>.*ctermfg=', 'cnW') + \ && group !~ '^Diff' + \ && group != 'Cursor' + let groups[group] = 'Missing ctermfg definition for ' .. group continue endif " do not check for background colors, they could be intentionally left out @@ -120,10 +123,10 @@ func! Test_check_colors() " 3) Check, that it does not set background highlighting " Doesn't ':hi Normal ctermfg=253 ctermfg=233' also set the background sometimes? - let bg_set='\(set\?\|setl\(ocal\)\?\) .*\(background\|bg\)=\(dark\|light\)' - let bg_let='let \%([&]\%([lg]:\)\?\)\%(background\|bg\)\s*=\s*\([''"]\?\)\w\+\1' - let bg_pat='\%('.bg_set. '\|'.bg_let.'\)' - let line=search(bg_pat, 'cnW') + let bg_set = '\(set\?\|setl\(ocal\)\?\) .*\(background\|bg\)=\(dark\|light\)' + let bg_let = 'let \%([&]\%([lg]:\)\?\)\%(background\|bg\)\s*=\s*\([''"]\?\)\w\+\1' + let bg_pat = '\%(' .. bg_set .. '\|' .. bg_let .. '\)' + let line = search(bg_pat, 'cnW') if search(bg_pat, 'cnW') exe line if search('hi \U\w\+\s\+\S', 'cbnW') @@ -145,7 +148,7 @@ func! Test_check_colors() " if exists("syntax_on") " syntax reset " endif - let pat='hi\%[ghlight]\s*clear\n\s*if\s*exists(\([''"]\)syntax_on\1)\n\s*syn\%[tax]\s*reset\n\s*endif' + let pat = 'hi\%[ghlight]\s*clear\n\s*if\s*exists(\([''"]\)syntax_on\1)\n\s*syn\%[tax]\s*reset\n\s*endif' if !search(pat, 'cnW') let err['init'] = 'No initialization' endif @@ -160,7 +163,7 @@ func! Test_check_colors() let ft_groups = [] " let group = '\%('.join(hi_groups, '\|').'\)' " More efficient than a for loop, but less informative for group in hi_groups - let pat='\Chi\%[ghlight]!\= *\%[link] \+\zs'.group.'\w\+\>\ze \+.' " Skips `hi clear` + let pat = '\Chi\%[ghlight]!\= *\%[link] \+\zs' .. group .. '\w\+\>\ze \+.' " Skips `hi clear` if search(pat, 'cW') call add(ft_groups, matchstr(getline('.'), pat)) endif @@ -172,7 +175,7 @@ func! Test_check_colors() " 8) Were debugPC and debugBreakpoint defined? for group in ['debugPC', 'debugBreakpoint'] - let pat='\Chi\%[ghlight]!\= *\%[link] \+\zs'.group.'\>' + let pat = '\Chi\%[ghlight]!\= *\%[link] \+\zs' .. group .. '\>' if search(pat, 'cnW') let line = search(pat, 'cW') let err['filetype'] = get(err, 'filetype', 'Should not define: ') . matchstr(getline('.'), pat). ' ' diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 0cad5fd6c1..b37fd85659 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -760,7 +760,7 @@ int eval_expr_typval(const typval_T *expr, typval_T *argv, if (eval1_emsg(&s, rettv, true) == FAIL) { return FAIL; } - if (*s != NUL) { // check for trailing chars after expr + if (*skipwhite(s) != NUL) { // check for trailing chars after expr tv_clear(rettv); emsgf(_(e_invexpr2), s); return FAIL; @@ -2086,6 +2086,7 @@ char_u *get_lval(char_u *const name, typval_T *const rettv, tv_clear(&var1); return NULL; } + p = skipwhite(p); } // Optionally get the second index [ :expr]. @@ -5364,7 +5365,7 @@ static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate) if (eval1(&start, &tv, false) == FAIL) { // recursive! return FAIL; } - if (*start == '}') { + if (*skipwhite(start) == '}') { return NOTDONE; } } diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 023c60f118..a5544435d2 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -191,6 +191,7 @@ return { inputsave={}, inputsecret={args={1, 2}}, insert={args={2, 3}}, + interrupt={args=0}, invert={args=1}, isdirectory={args=1}, isinf={args=1}, diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 1a80d4d4bd..a81f789f0f 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -4717,6 +4717,14 @@ static void f_insert(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } +// "interrupt()" function +static void f_interrupt(typval_T *argvars FUNC_ATTR_UNUSED, + typval_T *rettv FUNC_ATTR_UNUSED, + FunPtr fptr FUNC_ATTR_UNUSED) +{ + got_int = true; +} + /* * "invert(expr)" function */ diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 229f0e8dde..46eccd5181 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -3457,12 +3457,7 @@ bool set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID) char_u *register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state) { char_u *name = get_lambda_name(); - ufunc_T *fp = NULL; - - fp = xcalloc(1, offsetof(ufunc_T, uf_name) + STRLEN(name) + 1); - if (fp == NULL) { - return NULL; - } + ufunc_T *fp = xcalloc(1, offsetof(ufunc_T, uf_name) + STRLEN(name) + 1); fp->uf_refcount = 1; fp->uf_varargs = true; diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 5bf6aa73c6..064cebe016 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5026,8 +5026,13 @@ static int uc_add_command(char_u *name, size_t name_len, char_u *rep, } if (cmp == 0) { - if (!force) { - EMSG(_("E174: Command already exists: add ! to replace it")); + // Command can be replaced with "command!" and when sourcing the + // same script again, but only once. + if (!force + && (cmd->uc_script_ctx.sc_sid != current_sctx.sc_sid + || cmd->uc_script_ctx.sc_seq == current_sctx.sc_seq)) { + EMSG2(_("E174: Command already exists: add ! to replace it: %s"), + name); goto fail; } @@ -8586,6 +8591,24 @@ static void ex_tag_cmd(exarg_T *eap, char_u *name) eap->forceit, TRUE); } +enum { + SPEC_PERC = 0, + SPEC_HASH, + SPEC_CWORD, + SPEC_CCWORD, + SPEC_CEXPR, + SPEC_CFILE, + SPEC_SFILE, + SPEC_SLNUM, + SPEC_STACK, + SPEC_AFILE, + SPEC_ABUF, + SPEC_AMATCH, + SPEC_SFLNUM, + SPEC_SID, + // SPEC_CLIENT, +}; + /* * Check "str" for starting with a special cmdline variable. * If found return one of the SPEC_ values and set "*usedlen" to the length of @@ -8596,30 +8619,21 @@ ssize_t find_cmdline_var(const char_u *src, size_t *usedlen) { size_t len; static char *(spec_str[]) = { - "%", -#define SPEC_PERC 0 - "#", -#define SPEC_HASH (SPEC_PERC + 1) - "<cword>", // cursor word -#define SPEC_CWORD (SPEC_HASH + 1) - "<cWORD>", // cursor WORD -#define SPEC_CCWORD (SPEC_CWORD + 1) - "<cexpr>", // expr under cursor -#define SPEC_CEXPR (SPEC_CCWORD + 1) - "<cfile>", // cursor path name -#define SPEC_CFILE (SPEC_CEXPR + 1) - "<sfile>", // ":so" file name -#define SPEC_SFILE (SPEC_CFILE + 1) - "<slnum>", // ":so" file line number -#define SPEC_SLNUM (SPEC_SFILE + 1) - "<afile>", // autocommand file name -#define SPEC_AFILE (SPEC_SLNUM + 1) - "<abuf>", // autocommand buffer number -#define SPEC_ABUF (SPEC_AFILE + 1) - "<amatch>", // autocommand match name -#define SPEC_AMATCH (SPEC_ABUF + 1) - "<sflnum>", // script file line number -#define SPEC_SFLNUM (SPEC_AMATCH + 1) + [SPEC_PERC] = "%", + [SPEC_HASH] = "#", + [SPEC_CWORD] = "<cword>", // cursor word + [SPEC_CCWORD] = "<cWORD>", // cursor WORD + [SPEC_CEXPR] = "<cexpr>", // expr under cursor + [SPEC_CFILE] = "<cfile>", // cursor path name + [SPEC_SFILE] = "<sfile>", // ":so" file name + [SPEC_SLNUM] = "<slnum>", // ":so" file line number + [SPEC_STACK] = "<stack>", // call stack + [SPEC_AFILE] = "<afile>", // autocommand file name + [SPEC_ABUF] = "<abuf>", // autocommand buffer number + [SPEC_AMATCH] = "<amatch>", // autocommand match name + [SPEC_SFLNUM] = "<sflnum>", // script file line number + [SPEC_SID] = "<SID>", // script ID: <SNR>123_ + // [SPEC_CLIENT] = "<client>", }; for (size_t i = 0; i < ARRAY_SIZE(spec_str); ++i) { @@ -8866,6 +8880,16 @@ eval_vars ( result = (char_u *)strbuf; break; + case SPEC_SID: + if (current_sctx.sc_sid <= 0) { + *errormsg = (char_u *)_(e_usingsid); + return NULL; + } + snprintf(strbuf, sizeof(strbuf), "<SNR>%" PRIdSCID "_", + current_sctx.sc_sid); + result = (char_u *)strbuf; + break; + default: // should not happen *errormsg = (char_u *)""; diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index 81274fcf2a..e99e5b01cd 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -87,17 +87,16 @@ */ static int cause_abort = FALSE; -/* - * Return TRUE when immediately aborting on error, or when an interrupt - * occurred or an exception was thrown but not caught. Use for ":{range}call" - * to check whether an aborted function that does not handle a range itself - * should be called again for the next line in the range. Also used for - * cancelling expression evaluation after a function call caused an immediate - * abort. Note that the first emsg() call temporarily resets "force_abort" - * until the throw point for error messages has been reached. That is, during - * cancellation of an expression evaluation after an aborting function call or - * due to a parsing error, aborting() always returns the same value. - */ +// Return true when immediately aborting on error, or when an interrupt +// occurred or an exception was thrown but not caught. Use for ":{range}call" +// to check whether an aborted function that does not handle a range itself +// should be called again for the next line in the range. Also used for +// cancelling expression evaluation after a function call caused an immediate +// abort. Note that the first emsg() call temporarily resets "force_abort" +// until the throw point for error messages has been reached. That is, during +// cancellation of an expression evaluation after an aborting function call or +// due to a parsing error, aborting() always returns the same value. +// "got_int" is also set by calling interrupt(). int aborting(void) { return (did_emsg && force_abort) || got_int || current_exception; diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index dc11e4a232..c35398cd8d 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -456,6 +456,9 @@ void flush_buffers(flush_buffers_T flush_typeahead) typebuf.tb_silent = 0; cmd_silent = false; typebuf.tb_no_abbr_cnt = 0; + if (++typebuf.tb_change_cnt == 0) { + typebuf.tb_change_cnt = 1; + } } /* diff --git a/src/nvim/option.c b/src/nvim/option.c index 168160834b..a70a634966 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1355,11 +1355,11 @@ int do_set( // Disallow changing some options from modelines. if (opt_flags & OPT_MODELINE) { if (flags & (P_SECURE | P_NO_ML)) { - errmsg = (char_u *)_("E520: Not allowed in a modeline"); + errmsg = (char_u *)N_("E520: Not allowed in a modeline"); goto skip; } if ((flags & P_MLE) && !p_mle) { - errmsg = (char_u *)_( + errmsg = (char_u *)N_( "E992: Not allowed in a modeline when 'modelineexpr' is off"); goto skip; } @@ -1376,7 +1376,7 @@ int do_set( // Disallow changing some options in the sandbox if (sandbox != 0 && (flags & P_SECURE)) { - errmsg = (char_u *)_(e_sandbox); + errmsg = e_sandbox; goto skip; } @@ -1712,6 +1712,7 @@ int do_set( #ifdef BACKSLASH_IN_FILENAME && !((flags & P_EXPAND) && vim_isfilec(arg[1]) + && !ascii_iswhite(arg[1]) && (arg[1] != '\\' || (s == newval && arg[2] != '\\'))) diff --git a/src/nvim/search.c b/src/nvim/search.c index b105d99d7c..fc82e81472 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -1612,8 +1612,9 @@ static bool find_rawstring_end(char_u *linep, pos_T *startpos, pos_T *endpos) if (lnum == endpos->lnum && (colnr_T)(p - line) >= endpos->col) { break; } - if (*p == ')' && p[delim_len + 1] == '"' - && STRNCMP(delim_copy, p + 1, delim_len) == 0) { + if (*p == ')' + && STRNCMP(delim_copy, p + 1, delim_len) == 0 + && p[delim_len + 1] == '"') { found = true; break; } diff --git a/src/nvim/shada.c b/src/nvim/shada.c index aa19d1db1f..2444910bb3 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -4148,7 +4148,7 @@ static inline size_t shada_init_jumps( } const char *const fname = (char *) (fm.fmark.fnum == 0 ? (fm.fname == NULL ? NULL : fm.fname) - : buf->b_ffname); + : buf ? buf->b_ffname : NULL); if (fname == NULL) { continue; } diff --git a/src/nvim/testdir/summarize.vim b/src/nvim/testdir/summarize.vim index 7f8f758a71..da5856a2e7 100644 --- a/src/nvim/testdir/summarize.vim +++ b/src/nvim/testdir/summarize.vim @@ -1,3 +1,4 @@ +set cpo&vim if 1 " This is executed only with the eval feature set nocompatible diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index d116246ef3..3dd68873d4 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -1125,7 +1125,7 @@ func Test_change_mark_in_autocmds() write au! BufWritePre - if executable('cat') + if has('unix') write XtestFilter write >> XtestFilter diff --git a/src/nvim/testdir/test_compiler.vim b/src/nvim/testdir/test_compiler.vim index 6bb602717f..9101f8cfa0 100644 --- a/src/nvim/testdir/test_compiler.vim +++ b/src/nvim/testdir/test_compiler.vim @@ -42,12 +42,12 @@ func Test_compiler_without_arg() let a = split(execute('compiler')) call assert_match(runtime .. '/compiler/ant.vim$', a[0]) call assert_match(runtime .. '/compiler/bcc.vim$', a[1]) - call assert_match(runtime .. '/compiler/xmlwf.vim$', a[-1]) + call assert_match(runtime .. '/compiler/xo.vim$', a[-1]) endfunc func Test_compiler_completion() call feedkeys(":compiler \<C-A>\<C-B>\"\<CR>", 'tx') - call assert_match('^"compiler ant bcc .* xmlwf$', @:) + call assert_match('^"compiler ant bcc .* xmlwf xo$', @:) call feedkeys(":compiler p\<C-A>\<C-B>\"\<CR>", 'tx') call assert_equal('"compiler pbx perl php pylint pyunit', @:) diff --git a/src/nvim/testdir/test_debugger.vim b/src/nvim/testdir/test_debugger.vim index 811717208e..59d51b855b 100644 --- a/src/nvim/testdir/test_debugger.vim +++ b/src/nvim/testdir/test_debugger.vim @@ -316,3 +316,128 @@ func Test_Debugger() call delete('Xtest.vim') endfunc + +" Test for setting a breakpoint on a :endif where the :if condition is false +" and then quit the script. This should generate an interrupt. +func Test_breakpt_endif_intr() + func F() + let g:Xpath ..= 'a' + if v:false + let g:Xpath ..= 'b' + endif + invalid_command + endfunc + + let g:Xpath = '' + breakadd func 4 F + try + let caught_intr = 0 + debuggreedy + call feedkeys(":call F()\<CR>quit\<CR>", "xt") + call F() + catch /^Vim:Interrupt$/ + call assert_match('\.F, line 4', v:throwpoint) + let caught_intr = 1 + endtry + 0debuggreedy + call assert_equal(1, caught_intr) + call assert_equal('a', g:Xpath) + breakdel * + delfunc F +endfunc + +" Test for setting a breakpoint on a :else where the :if condition is false +" and then quit the script. This should generate an interrupt. +func Test_breakpt_else_intr() + func F() + let g:Xpath ..= 'a' + if v:false + let g:Xpath ..= 'b' + else + invalid_command + endif + invalid_command + endfunc + + let g:Xpath = '' + breakadd func 4 F + try + let caught_intr = 0 + debuggreedy + call feedkeys(":call F()\<CR>quit\<CR>", "xt") + call F() + catch /^Vim:Interrupt$/ + call assert_match('\.F, line 4', v:throwpoint) + let caught_intr = 1 + endtry + 0debuggreedy + call assert_equal(1, caught_intr) + call assert_equal('a', g:Xpath) + breakdel * + delfunc F +endfunc + +" Test for setting a breakpoint on a :endwhile where the :while condition is +" false and then quit the script. This should generate an interrupt. +func Test_breakpt_endwhile_intr() + func F() + let g:Xpath ..= 'a' + while v:false + let g:Xpath ..= 'b' + endwhile + invalid_command + endfunc + + let g:Xpath = '' + breakadd func 4 F + try + let caught_intr = 0 + debuggreedy + call feedkeys(":call F()\<CR>quit\<CR>", "xt") + call F() + catch /^Vim:Interrupt$/ + call assert_match('\.F, line 4', v:throwpoint) + let caught_intr = 1 + endtry + 0debuggreedy + call assert_equal(1, caught_intr) + call assert_equal('a', g:Xpath) + breakdel * + delfunc F +endfunc + +" Test for setting a breakpoint on an :endtry where an exception is pending to +" be processed and then quit the script. This should generate an interrupt and +" the thrown exception should be ignored. +func Test_breakpt_endtry_intr() + func F() + try + let g:Xpath ..= 'a' + throw "abc" + endtry + invalid_command + endfunc + + let g:Xpath = '' + breakadd func 4 F + try + let caught_intr = 0 + let caught_abc = 0 + debuggreedy + call feedkeys(":call F()\<CR>quit\<CR>", "xt") + call F() + catch /abc/ + let caught_abc = 1 + catch /^Vim:Interrupt$/ + call assert_match('\.F, line 4', v:throwpoint) + let caught_intr = 1 + endtry + 0debuggreedy + call assert_equal(1, caught_intr) + call assert_equal(0, caught_abc) + call assert_equal('a', g:Xpath) + breakdel * + delfunc F +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_eval_stuff.vim b/src/nvim/testdir/test_eval_stuff.vim index 4b54a0d39f..061364fb73 100644 --- a/src/nvim/testdir/test_eval_stuff.vim +++ b/src/nvim/testdir/test_eval_stuff.vim @@ -108,3 +108,27 @@ func Test_skip_after_throw() catch /something/ endtry endfunc + +func Test_curly_assignment() + let s:svar = 'svar' + let g:gvar = 'gvar' + let lname = 'gvar' + let gname = 'gvar' + let {'s:'.lname} = {'g:'.gname} + call assert_equal('gvar', s:gvar) + let s:gvar = '' + let { 's:'.lname } = { 'g:'.gname } + call assert_equal('gvar', s:gvar) + let s:gvar = '' + let { 's:' . lname } = { 'g:' . gname } + call assert_equal('gvar', s:gvar) + let s:gvar = '' + let { 's:' .. lname } = { 'g:' .. gname } + call assert_equal('gvar', s:gvar) + + unlet s:svar + unlet s:gvar + unlet g:gvar +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_expand_func.vim b/src/nvim/testdir/test_expand_func.vim index fb29c3eb7a..9588d3b89d 100644 --- a/src/nvim/testdir/test_expand_func.vim +++ b/src/nvim/testdir/test_expand_func.vim @@ -1,5 +1,7 @@ " Tests for expand() +source shared.vim + let s:sfile = expand('<sfile>') let s:slnum = str2nr(expand('<slnum>')) let s:sflnum = str2nr(expand('<sflnum>')) @@ -16,6 +18,25 @@ func s:expand_sflnum() return str2nr(expand('<sflnum>')) endfunc +" This test depends on the location in the test file, put it first. +func Test_expand_sflnum() + call assert_equal(7, s:sflnum) + call assert_equal(24, str2nr(expand('<sflnum>'))) + + " Line-continuation + call assert_equal( + \ 27, + \ str2nr(expand('<sflnum>'))) + + " Call in script-local function + call assert_equal(18, s:expand_sflnum()) + + " Call in command + command Flnum echo expand('<sflnum>') + call assert_equal(36, str2nr(trim(execute('Flnum')))) + delcommand Flnum +endfunc + func Test_expand_sfile() call assert_match('test_expand_func\.vim$', s:sfile) call assert_match('^function .*\.\.Test_expand_sfile$', expand('<sfile>')) @@ -30,7 +51,7 @@ func Test_expand_sfile() endfunc func Test_expand_slnum() - call assert_equal(4, s:slnum) + call assert_equal(6, s:slnum) call assert_equal(2, str2nr(expand('<slnum>'))) " Line-continuation @@ -47,20 +68,14 @@ func Test_expand_slnum() delcommand Slnum endfunc -func Test_expand_sflnum() - call assert_equal(5, s:sflnum) - call assert_equal(52, str2nr(expand('<sflnum>'))) - - " Line-continuation - call assert_equal( - \ 55, - \ str2nr(expand('<sflnum>'))) - - " Call in script-local function - call assert_equal(16, s:expand_sflnum()) +func s:sid_test() + return 'works' +endfunc - " Call in command - command Flnum echo expand('<sflnum>') - call assert_equal(64, str2nr(trim(execute('Flnum')))) - delcommand Flnum +func Test_expand_SID() + let sid = expand('<SID>') + execute 'let g:sid_result = ' .. sid .. 'sid_test()' + call assert_equal('works', g:sid_result) endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_expr.vim b/src/nvim/testdir/test_expr.vim index 264d8b000f..b8d6f5aa7d 100644 --- a/src/nvim/testdir/test_expr.vim +++ b/src/nvim/testdir/test_expr.vim @@ -49,6 +49,9 @@ func Test_dict() let d['a'] = 'aaa' call assert_equal('none', d['']) call assert_equal('aaa', d['a']) + + let d[ 'b' ] = 'bbb' + call assert_equal('bbb', d[ 'b' ]) endfunc func Test_strgetchar() diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index 2e280417ae..8cf7400f7a 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -73,7 +73,7 @@ let s:filename_checks = { \ 'autoit': ['file.au3'], \ 'automake': ['GNUmakefile.am'], \ 'ave': ['file.ave'], - \ 'awk': ['file.awk'], + \ 'awk': ['file.awk', 'file.gawk'], \ 'b': ['file.mch', 'file.ref', 'file.imp'], \ 'bc': ['file.bc'], \ 'bdf': ['file.bdf'], @@ -140,7 +140,7 @@ let s:filename_checks = { \ 'dnsmasq': ['/etc/dnsmasq.conf'], \ 'dockerfile': ['Dockerfile', 'file.Dockerfile'], \ 'dosbatch': ['file.bat', 'file.sys'], - \ 'dosini': ['.editorconfig', '/etc/pacman.conf', '/etc/yum.conf', 'file.ini'], + \ 'dosini': ['.editorconfig', '/etc/pacman.conf', '/etc/yum.conf', 'file.ini', 'npmrc', '.npmrc', 'php.ini', 'php.ini-5'], \ 'dot': ['file.dot', 'file.gv'], \ 'dracula': ['file.drac', 'file.drc', 'filelvs', 'filelpe'], \ 'dsl': ['file.dsl'], @@ -596,7 +596,8 @@ let s:script_checks = { \ 'bc': [['#!/path/bc']], \ 'sed': [['#!/path/sed']], \ 'ocaml': [['#!/path/ocaml']], - \ 'awk': [['#!/path/awk']], + \ 'awk': [['#!/path/awk'], + \ ['#!/path/gawk']], \ 'wml': [['#!/path/wml']], \ 'scheme': [['#!/path/scheme']], \ 'cfengine': [['#!/path/cfengine']], diff --git a/src/nvim/testdir/test_filter_map.vim b/src/nvim/testdir/test_filter_map.vim index 1dd3a5b29f..a15567bcf2 100644 --- a/src/nvim/testdir/test_filter_map.vim +++ b/src/nvim/testdir/test_filter_map.vim @@ -11,6 +11,7 @@ func Test_filter_map_list_expr_string() call assert_equal([2, 4, 6, 8], map([1, 2, 3, 4], 'v:val * 2')) call assert_equal([0, 2, 4, 6], map([1, 2, 3, 4], 'v:key * 2')) call assert_equal([9, 9, 9, 9], map([1, 2, 3, 4], 9)) + call assert_equal([7, 7, 7], map([1, 2, 3], ' 7 ')) endfunc " dict with expression string diff --git a/src/nvim/testdir/test_interrupt.vim b/src/nvim/testdir/test_interrupt.vim new file mode 100644 index 0000000000..111752d16a --- /dev/null +++ b/src/nvim/testdir/test_interrupt.vim @@ -0,0 +1,27 @@ +" Test behavior of interrupt() + +let s:bufwritepre_called = 0 +let s:bufwritepost_called = 0 + +func s:bufwritepre() + let s:bufwritepre_called = 1 + call interrupt() +endfunction + +func s:bufwritepost() + let s:bufwritepost_called = 1 +endfunction + +func Test_interrupt() + new Xfile + let n = 0 + try + au BufWritePre Xfile call s:bufwritepre() + au BufWritePost Xfile call s:bufwritepost() + w! + catch /^Vim:Interrupt$/ + endtry + call assert_equal(1, s:bufwritepre_called) + call assert_equal(0, s:bufwritepost_called) + call assert_equal(0, filereadable('Xfile')) +endfunc diff --git a/src/nvim/testdir/test_mksession.vim b/src/nvim/testdir/test_mksession.vim index 9c9e04be07..1e22f7e9c9 100644 --- a/src/nvim/testdir/test_mksession.vim +++ b/src/nvim/testdir/test_mksession.vim @@ -155,7 +155,7 @@ endfunc " Verify that arglist is stored correctly to the session file. func Test_mksession_arglist() - argdel * + %argdel next file1 file2 file3 file4 mksession! Xtest_mks.out source Xtest_mks.out @@ -307,6 +307,126 @@ func Test_mksession_quote_in_filename() call delete('Xtest_mks_quoted.out') endfunc +" Test for storing global variables in a session file +func Test_mksession_globals() + set sessionoptions+=globals + + " create different global variables + let g:Global_string = "Sun is shining" + let g:Global_count = 100 + let g:Global_pi = 3.14 + + mksession! Xtest_mks.out + + unlet g:Global_string + unlet g:Global_count + unlet g:Global_pi + + source Xtest_mks.out + call assert_equal("Sun is shining", g:Global_string) + call assert_equal(100, g:Global_count) + call assert_equal(3.14, g:Global_pi) + + unlet g:Global_string + unlet g:Global_count + unlet g:Global_pi + call delete('Xtest_mks.out') + set sessionoptions& +endfunc + +" Test for changing backslash to forward slash in filenames +func Test_mksession_slash() + if exists('+shellslash') + throw 'Skipped: cannot use backslash in file name' + endif + enew + %bwipe! + e a\\b\\c + mksession! Xtest_mks1.out + set sessionoptions+=slash + mksession! Xtest_mks2.out + + %bwipe! + source Xtest_mks1.out + call assert_equal('a/b/c', bufname('')) + %bwipe! + source Xtest_mks2.out + call assert_equal('a/b/c', bufname('')) + + %bwipe! + call delete('Xtest_mks1.out') + call delete('Xtest_mks2.out') + set sessionoptions& +endfunc + +" Test for storing global and local argument list in a session file +func Test_mkseesion_arglocal() + enew | only + n a b c + new + arglocal + mksession! Xtest_mks.out + + %bwipe! + %argdelete + argglobal + source Xtest_mks.out + call assert_equal(2, winnr('$')) + call assert_equal(2, arglistid(1)) + call assert_equal(0, arglistid(2)) + + %bwipe! + %argdelete + argglobal + call delete('Xtest_mks.out') +endfunc + +" Test for changing directory to the session file directory +func Test_mksession_sesdir() + call mkdir('Xproj') + mksession! Xproj/Xtest_mks1.out + set sessionoptions-=curdir + set sessionoptions+=sesdir + mksession! Xproj/Xtest_mks2.out + + source Xproj/Xtest_mks1.out + call assert_equal('testdir', fnamemodify(getcwd(), ':t')) + source Xproj/Xtest_mks2.out + call assert_equal('Xproj', fnamemodify(getcwd(), ':t')) + cd .. + + set sessionoptions& + call delete('Xproj', 'rf') +endfunc + +" Test for storing the 'lines' and 'columns' settings +func Test_mksession_resize() + mksession! Xtest_mks1.out + set sessionoptions+=resize + mksession! Xtest_mks2.out + + let lines = readfile('Xtest_mks1.out') + let found_resize = v:false + for line in lines + if line =~ '^set lines=' + let found_resize = v:true + endif + endfor + call assert_equal(v:false, found_resize) + let lines = readfile('Xtest_mks2.out') + let found_resize = v:false + for line in lines + if line =~ '^set lines=' + let found_resize = v:true + endif + endfor + call assert_equal(v:true, found_resize) + + call delete('Xtest_mks1.out') + call delete('Xtest_mks2.out') + set sessionoptions& +endfunc + func s:ClearMappings() mapclear omapclear diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim index 04a5c62f66..9e8da74db7 100644 --- a/src/nvim/testdir/test_options.vim +++ b/src/nvim/testdir/test_options.vim @@ -576,3 +576,13 @@ func Test_opt_boolean() set number& endfunc +" Test for setting option value containing spaces with isfname+=32 +func Test_isfname_with_options() + set isfname+=32 + setlocal keywordprg=:term\ help.exe + call assert_equal(':term help.exe', &keywordprg) + set isfname& + setlocal keywordprg& +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_usercommands.vim b/src/nvim/testdir/test_usercommands.vim index 2c7cb7bab7..fdd3a9abeb 100644 --- a/src/nvim/testdir/test_usercommands.vim +++ b/src/nvim/testdir/test_usercommands.vim @@ -184,6 +184,34 @@ func Test_Ambiguous() call assert_fails("\x4ei\041", 'E492: Not an editor command: Ni!') endfunc +func Test_redefine_on_reload() + call writefile(['command ExistingCommand echo "yes"'], 'Xcommandexists') + call assert_equal(0, exists(':ExistingCommand')) + source Xcommandexists + call assert_equal(2, exists(':ExistingCommand')) + " Redefining a command when reloading a script is OK. + source Xcommandexists + call assert_equal(2, exists(':ExistingCommand')) + + " But redefining in another script is not OK. + call writefile(['command ExistingCommand echo "yes"'], 'Xcommandexists2') + call assert_fails('source Xcommandexists2', 'E174:') + call delete('Xcommandexists2') + + " And defining twice in one script is not OK. + delcommand ExistingCommand + call assert_equal(0, exists(':ExistingCommand')) + call writefile([ + \ 'command ExistingCommand echo "yes"', + \ 'command ExistingCommand echo "no"', + \ ], 'Xcommandexists') + call assert_fails('source Xcommandexists', 'E174:') + call assert_equal(2, exists(':ExistingCommand')) + + call delete('Xcommandexists') + delcommand ExistingCommand +endfunc + func Test_CmdUndefined() call assert_fails('Doit', 'E492:') au CmdUndefined Doit :command Doit let g:didit = 'yes' diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index bfd9435c49..860271d209 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1817,9 +1817,8 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, || tmux // per tmux manual page // https://lists.gnu.org/archive/html/screen-devel/2013-03/msg00000.html || (true_screen - && (!screen_host_linuxvt - || (screen_host_linuxvt - && (xterm_version || (vte_version > 0) || colorterm)))) + && (screen_host_linuxvt + && (xterm_version || (vte_version > 0) || colorterm))) // Since GNU Screen does not support DECSCUSR, DECSCUSR is wrapped // in DCS and output to the host terminal. || st // #7641 |