diff options
43 files changed, 590 insertions, 335 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 94a78f85c8..f4ff4d5ac3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -250,13 +250,14 @@ if(HAS_DIAG_COLOR_FLAG) endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.8.5") - # Array-bounds testing is broken in some GCC versions before 4.8.5. - # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56273 - check_c_compiler_flag(-Wno-array-bounds HAS_NO_ARRAY_BOUNDS_FLAG) - if(HAS_NO_ARRAY_BOUNDS_FLAG) - add_definitions(-Wno-array-bounds) - endif() + # 1. Array-bounds testing is broken in some GCC versions before 4.8.5. + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56273 + # 2. But _Pragma("...ignored") is broken (unresolved) in GCC 5+: + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66099 + # So we must disable -Warray-bounds globally for GCC (for kbtree.h, #7083). + check_c_compiler_flag(-Wno-array-bounds HAS_NO_ARRAY_BOUNDS_FLAG) + if(HAS_NO_ARRAY_BOUNDS_FLAG) + add_definitions(-Wno-array-bounds) endif() endif() diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 0172f630cd..b3907fdf37 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -71,7 +71,7 @@ foreach(DF ${DOCFILES}) endforeach() add_custom_target(helptags - COMMAND ${CMAKE_COMMAND} -E remove_directory ${GENERATED_RUNTIME_DIR}/doc + COMMAND ${CMAKE_COMMAND} -E remove ${GENERATED_RUNTIME_DIR}/doc/* COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/runtime/doc ${GENERATED_RUNTIME_DIR}/doc COMMAND "${PROJECT_BINARY_DIR}/bin/nvim" diff --git a/runtime/autoload/provider.vim b/runtime/autoload/provider.vim new file mode 100644 index 0000000000..dc24e801d0 --- /dev/null +++ b/runtime/autoload/provider.vim @@ -0,0 +1,21 @@ +" Common functions for providers + +" Start the provider and perform a 'poll' request +" +" Returns a valid channel on success +function! provider#Poll(argv, orig_name, log_env) abort + let job = {'rpc': v:true, 'stderr_buffered': v:true} + try + let channel_id = jobstart(a:argv, job) + if channel_id > 0 && rpcrequest(channel_id, 'poll') ==# 'ok' + return channel_id + endif + catch + echomsg v:throwpoint + echomsg v:exception + for row in get(job, 'stderr', []) + echomsg row + endfor + endtry + throw remote#host#LoadErrorForHost(a:orig_name, a:log_env) +endfunction diff --git a/runtime/autoload/provider/node.vim b/runtime/autoload/provider/node.vim index 3dde18022e..ae6f84de72 100644 --- a/runtime/autoload/provider/node.vim +++ b/runtime/autoload/provider/node.vim @@ -3,8 +3,6 @@ if exists('g:loaded_node_provider') endif let g:loaded_node_provider = 1 -let s:job_opts = {'rpc': v:true, 'stderr_buffered': v:true} - function! s:is_minimum_version(version, min_major, min_minor) abort if empty(a:version) let nodejs_version = get(split(system(['node', '-v']), "\n"), 0, '') @@ -72,21 +70,7 @@ function! provider#node#Require(host) abort call add(args, provider#node#Prog()) - try - let job = copy(s:job_opts) - let channel_id = jobstart(args, job) - if rpcrequest(channel_id, 'poll') ==# 'ok' - return channel_id - endif - catch - echomsg v:throwpoint - echomsg v:exception - for row in job.stderr - echomsg row - endfor - endtry - endtry - throw remote#host#LoadErrorForHost(a:host.orig_name, '$NVIM_NODE_LOG_FILE') + return provider#Poll(args, a:host.orig_name, '$NVIM_NODE_LOG_FILE') endfunction function! provider#node#Call(method, args) abort diff --git a/runtime/autoload/provider/pythonx.vim b/runtime/autoload/provider/pythonx.vim index 1c77eabe23..b51c398410 100644 --- a/runtime/autoload/provider/pythonx.vim +++ b/runtime/autoload/provider/pythonx.vim @@ -5,8 +5,6 @@ endif let s:loaded_pythonx_provider = 1 -let s:job_opts = {'rpc': v:true, 'stderr_buffered': v:true} - function! provider#pythonx#Require(host) abort let ver = (a:host.orig_name ==# 'python') ? 2 : 3 @@ -20,21 +18,7 @@ function! provider#pythonx#Require(host) abort call add(args, plugin.path) endfor - try - let job = copy(s:job_opts) - let channel_id = jobstart(args, job) - if rpcrequest(channel_id, 'poll') ==# 'ok' - return channel_id - endif - catch - echomsg v:throwpoint - echomsg v:exception - for row in job.stderr - echomsg row - endfor - endtry - throw remote#host#LoadErrorForHost(a:host.orig_name, - \ '$NVIM_PYTHON_LOG_FILE') + return provider#Poll(args, a:host.orig_name, '$NVIM_PYTHON_LOG_FILE') endfunction function! provider#pythonx#Detect(major_ver) abort diff --git a/runtime/autoload/provider/ruby.vim b/runtime/autoload/provider/ruby.vim index 3fb65fecdf..2fe3817512 100644 --- a/runtime/autoload/provider/ruby.vim +++ b/runtime/autoload/provider/ruby.vim @@ -4,17 +4,6 @@ if exists('g:loaded_ruby_provider') endif let g:loaded_ruby_provider = 1 -let s:stderr = {} -let s:job_opts = {'rpc': v:true} - -function! s:job_opts.on_stderr(chan_id, data, event) abort - let stderr = get(s:stderr, a:chan_id, ['']) - let last = remove(stderr, -1) - let a:data[0] = last.a:data[0] - call extend(stderr, a:data) - let s:stderr[a:chan_id] = stderr -endfunction - function! provider#ruby#Detect() abort if exists("g:ruby_host_prog") return g:ruby_host_prog @@ -35,19 +24,7 @@ function! provider#ruby#Require(host) abort let prog .= " " . shellescape(plugin.path) endfor - try - let channel_id = jobstart(prog, s:job_opts) - if rpcrequest(channel_id, 'poll') ==# 'ok' - return channel_id - endif - catch - echomsg v:throwpoint - echomsg v:exception - for row in get(s:stderr, channel_id, []) - echomsg row - endfor - endtry - throw remote#host#LoadErrorForHost(a:host.orig_name, '$NVIM_RUBY_LOG_FILE') + return provider#Poll(prog, a:host.orig_name, '$NVIM_RUBY_LOG_FILE') endfunction function! provider#ruby#Call(method, args) abort diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt index b6cc18ab1b..9ae35bea52 100644 --- a/runtime/doc/insert.txt +++ b/runtime/doc/insert.txt @@ -1077,6 +1077,8 @@ items: item with the same word is already present. empty when non-zero this match will be added even when it is an empty string + user_data custom data which is associated with the item and + available in |v:completed_item| All of these except "icase", "dup" and "empty" must be a string. If an item does not meet these requirements then an error message is given and further @@ -1170,6 +1172,8 @@ The menu is used when: The 'pumheight' option can be used to set a maximum height. The default is to use all space available. +The 'pumwidth' option can be used to set a minimum width. The default is 15 +characters. There are three states: 1. A complete match has been inserted, e.g., after using CTRL-N or CTRL-P. diff --git a/runtime/doc/msgpack_rpc.txt b/runtime/doc/msgpack_rpc.txt index 2d8f5af6d2..11fad105b5 100644 --- a/runtime/doc/msgpack_rpc.txt +++ b/runtime/doc/msgpack_rpc.txt @@ -242,4 +242,4 @@ Even for statically compiled clients it is good practice to avoid hardcoding the type codes, because a client may be built against one Nvim version but connect to another with different type codes. - + vim:tw=78:ts=8:ft=help:norl: diff --git a/runtime/filetype.vim b/runtime/filetype.vim index a2e1f23bf1..4e0f145c18 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -1,7 +1,7 @@ " Vim support file to detect file types " " Maintainer: Bram Moolenaar <Bram@vim.org> -" Last Change: 2017 Nov 02 +" Last Change: 2018 Feb 14 " Listen very carefully, I will say this only once if exists("did_load_filetypes") @@ -48,6 +48,9 @@ func! s:StarSetf(ft) endif endfunc +" Vim help file +au BufNewFile,BufRead $VIMRUNTIME/doc/*.txt setf help + " Abaqus or Trasys au BufNewFile,BufRead *.inp call s:Check_inp() @@ -2804,8 +2807,13 @@ au BufNewFile,BufRead zsh*,zlog* call s:StarSetf('zsh') " Plain text files, needs to be far down to not override others. This avoids " the "conf" type being used if there is a line starting with '#'. -au BufNewFile,BufRead *.txt,*.text,README setf text +au BufNewFile,BufRead *.text,README setf text +" Help files match *.txt but should have a last line that is a modeline. +au BufNewFile,BufRead *.txt + \ if getline('$') !~ 'vim:.*ft=help' + \| setf text + \| endif " Use the filetype detect plugins. They may overrule any of the previously " detected filetypes. diff --git a/src/nvim/edit.c b/src/nvim/edit.c index e67ac7d49f..35bbe04ff0 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -3600,6 +3600,8 @@ int ins_compl_add_tv(typval_T *const tv, const Direction dir) cptext[CPT_MENU] = tv_dict_get_string(tv->vval.v_dict, "menu", true); cptext[CPT_KIND] = tv_dict_get_string(tv->vval.v_dict, "kind", true); cptext[CPT_INFO] = tv_dict_get_string(tv->vval.v_dict, "info", true); + cptext[CPT_USER_DATA] = tv_dict_get_string(tv->vval.v_dict, + "user_data", true); icase = (bool)tv_dict_get_number(tv->vval.v_dict, "icase"); adup = (bool)tv_dict_get_number(tv->vval.v_dict, "dup"); @@ -4043,8 +4045,9 @@ static void ins_compl_insert(int in_compl_func) // Set completed item. // { word, abbr, menu, kind, info } dict_T *dict = tv_dict_alloc(); - tv_dict_add_str(dict, S_LEN("word"), - (const char *)EMPTY_IF_NULL(compl_shown_match->cp_str)); + tv_dict_add_str( + dict, S_LEN("word"), + (const char *)EMPTY_IF_NULL(compl_shown_match->cp_str)); tv_dict_add_str( dict, S_LEN("abbr"), (const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_ABBR])); @@ -4057,6 +4060,9 @@ static void ins_compl_insert(int in_compl_func) tv_dict_add_str( dict, S_LEN("info"), (const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_INFO])); + tv_dict_add_str( + dict, S_LEN("user_data"), + (const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_USER_DATA])); set_vim_var_dict(VV_COMPLETED_ITEM, dict); if (!in_compl_func) { compl_curr_match = compl_shown_match; diff --git a/src/nvim/edit.h b/src/nvim/edit.h index 0d61f26bcc..433a941295 100644 --- a/src/nvim/edit.h +++ b/src/nvim/edit.h @@ -6,11 +6,12 @@ /* * Array indexes used for cptext argument of ins_compl_add(). */ -#define CPT_ABBR 0 /* "abbr" */ -#define CPT_MENU 1 /* "menu" */ -#define CPT_KIND 2 /* "kind" */ -#define CPT_INFO 3 /* "info" */ -#define CPT_COUNT 4 /* Number of entries */ +#define CPT_ABBR 0 // "abbr" +#define CPT_MENU 1 // "menu" +#define CPT_KIND 2 // "kind" +#define CPT_INFO 3 // "info" +#define CPT_USER_DATA 4 // "user data" +#define CPT_COUNT 5 // Number of entries typedef int (*IndentGetter)(void); diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 2873f76ce0..48d1d42e2e 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -4864,7 +4864,9 @@ void fix_help_buffer(void) char_u *rt; // Set filetype to "help". - set_option_value("ft", 0L, "help", OPT_LOCAL); + if (STRCMP(curbuf->b_p_ft, "help") != 0) { + set_option_value("ft", 0L, "help", OPT_LOCAL); + } if (!syntax_present(curwin)) { for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum) { diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c index eb0653c432..5e56e5f41b 100644 --- a/src/nvim/keymap.c +++ b/src/nvim/keymap.c @@ -40,6 +40,7 @@ static const struct modmasktable { // 'A' must be the last one { MOD_MASK_ALT, MOD_MASK_ALT, (char_u)'A' }, { 0, 0, NUL } + // NOTE: when adding an entry, update MAX_KEY_NAME_LEN! }; /* @@ -285,6 +286,7 @@ static const struct key_name_entry { { K_PLUG, "Plug" }, { K_PASTE, "Paste" }, { 0, NULL } + // NOTE: When adding a long name update MAX_KEY_NAME_LEN. }; static struct mousetable { @@ -472,9 +474,13 @@ char_u *get_special_key_name(int c, int modifiers) string[idx++] = *s++; } } - } else { /* use name of special key */ - STRCPY(string + idx, key_names_table[table_idx].name); - idx = (int)STRLEN(string); + } else { // use name of special key + size_t len = STRLEN(key_names_table[table_idx].name); + + if ((int)len + idx + 2 <= MAX_KEY_NAME_LEN) { + STRCPY(string + idx, key_names_table[table_idx].name); + idx += (int)len; + } } string[idx++] = '>'; string[idx] = NUL; diff --git a/src/nvim/keymap.h b/src/nvim/keymap.h index ee64854c98..04fc93e29e 100644 --- a/src/nvim/keymap.h +++ b/src/nvim/keymap.h @@ -448,9 +448,10 @@ enum key_extra { /* * The length of the longest special key name, including modifiers. - * Current longest is <M-C-S-T-4-MiddleRelease> (length includes '<' and '>'). + * Current longest is <M-C-S-T-D-A-4-ScrollWheelRight> (length includes '<' and + * '>'). */ -#define MAX_KEY_NAME_LEN 25 +#define MAX_KEY_NAME_LEN 32 // Maximum length of a special key event as tokens. This includes modifiers. // The longest event is something like <M-C-S-T-4-LeftDrag> which would be the diff --git a/src/nvim/lib/kbtree.h b/src/nvim/lib/kbtree.h index a3943054e6..e2688064a8 100644 --- a/src/nvim/lib/kbtree.h +++ b/src/nvim/lib/kbtree.h @@ -390,34 +390,14 @@ #define KBTREE_INIT(name, key_t, __cmp, T) \ KBTREE_INIT_IMPL(name, key_t, kbnode_##name##_t, __cmp, T, (sizeof(kbnode_##name##_t)+(2*T)*sizeof(void *))) -#if (!defined(__clang__) && !defined(__INTEL_COMPILER)) && (__GNUC__ > 4 ) - -// The index trickery shouldn't be UB anymore, -// still it is to much for gcc:s -Werror=array-bounds -# define __KB_PRAGMA_START \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Warray-bounds\"") - -# define __KB_PRAGMA_END \ - _Pragma("GCC diagnostic pop") \ - -#else - -# define __KB_PRAGMA_START -# define __KB_PRAGMA_END - -#endif - #define KBTREE_INIT_IMPL(name, key_t, kbnode_t, __cmp, T, ILEN) \ - __KB_PRAGMA_START \ __KB_TREE_T(name, key_t, T) \ __KB_GET_AUX1(name, key_t, kbnode_t, __cmp) \ __KB_GET(name, key_t, kbnode_t) \ __KB_INTERVAL(name, key_t, kbnode_t) \ __KB_PUT(name, key_t, kbnode_t, __cmp, T, ILEN) \ __KB_DEL(name, key_t, kbnode_t, T) \ - __KB_ITR(name, key_t, kbnode_t) \ - __KB_PRAGMA_END + __KB_ITR(name, key_t, kbnode_t) #define KB_DEFAULT_SIZE 512 diff --git a/src/nvim/option.c b/src/nvim/option.c index c805e41ec5..2341371f65 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -2455,6 +2455,7 @@ did_set_string_option ( int did_chartab = FALSE; char_u **gvarp; bool free_oldval = (options[opt_idx].flags & P_ALLOCED); + int ft_changed = false; /* Get the global option to compare with, otherwise we would have to check * two values for all local options. */ @@ -3174,6 +3175,8 @@ did_set_string_option ( } else if (gvarp == &p_ft) { if (!valid_filetype(*varp)) { errmsg = e_invarg; + } else { + ft_changed = STRCMP(oldval, *varp) != 0; } } else if (gvarp == &p_syn) { if (!valid_filetype(*varp)) { @@ -3256,10 +3259,12 @@ did_set_string_option ( apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn, curbuf->b_fname, TRUE, curbuf); } else if (varp == &(curbuf->b_p_ft)) { - /* 'filetype' is set, trigger the FileType autocommand */ - did_filetype = TRUE; - apply_autocmds(EVENT_FILETYPE, curbuf->b_p_ft, - curbuf->b_fname, TRUE, curbuf); + // 'filetype' is set, trigger the FileType autocommand + if (!(opt_flags & OPT_MODELINE) || ft_changed) { + did_filetype = true; + apply_autocmds(EVENT_FILETYPE, curbuf->b_p_ft, + curbuf->b_fname, true, curbuf); + } } if (varp == &(curwin->w_s->b_p_spl)) { char_u fname[200]; diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 0a7f703461..c3bc009f6a 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -4968,6 +4968,8 @@ static void syn_cmd_cluster(exarg_T *eap, int syncing) if (scl_id >= 0) { syn_combine_list(&SYN_CLSTR(curwin->w_s)[scl_id].scl_list, &clstr_list, list_op); + } else { + xfree(clstr_list); } got_clstr = true; } @@ -5276,8 +5278,9 @@ get_id_list ( break; } if (count != 0) { - EMSG2(_("E408: %s must be first in contains list"), name + 1); - failed = TRUE; + EMSG2(_("E408: %s must be first in contains list"), + name + 1); + failed = true; xfree(name); break; } diff --git a/src/nvim/testdir/test_ins_complete.vim b/src/nvim/testdir/test_ins_complete.vim index 8707438ede..c307e33cbf 100644 --- a/src/nvim/testdir/test_ins_complete.vim +++ b/src/nvim/testdir/test_ins_complete.vim @@ -97,3 +97,123 @@ func Test_ins_complete() cd .. call delete('Xdir', 'rf') endfunc + +function! s:CompleteDone_CompleteFuncDict( findstart, base ) + if a:findstart + return 0 + endif + + return { + \ 'words': [ + \ { + \ 'word': 'aword', + \ 'abbr': 'wrd', + \ 'menu': 'extra text', + \ 'info': 'words are cool', + \ 'kind': 'W', + \ 'user_data': 'test' + \ } + \ ] + \ } +endfunction + +function! s:CompleteDone_CheckCompletedItemDict() + call assert_equal( 'aword', v:completed_item[ 'word' ] ) + call assert_equal( 'wrd', v:completed_item[ 'abbr' ] ) + call assert_equal( 'extra text', v:completed_item[ 'menu' ] ) + call assert_equal( 'words are cool', v:completed_item[ 'info' ] ) + call assert_equal( 'W', v:completed_item[ 'kind' ] ) + call assert_equal( 'test', v:completed_item[ 'user_data' ] ) + + let s:called_completedone = 1 +endfunction + +function Test_CompleteDoneDict() + au CompleteDone * :call <SID>CompleteDone_CheckCompletedItemDict() + + set completefunc=<SID>CompleteDone_CompleteFuncDict + execute "normal a\<C-X>\<C-U>\<C-Y>" + set completefunc& + + call assert_equal( 'test', v:completed_item[ 'user_data' ] ) + call assert_true( s:called_completedone ) + + let s:called_completedone = 0 + au! CompleteDone +endfunc + +function! s:CompleteDone_CompleteFuncDictNoUserData( findstart, base ) + if a:findstart + return 0 + endif + + return { + \ 'words': [ + \ { + \ 'word': 'aword', + \ 'abbr': 'wrd', + \ 'menu': 'extra text', + \ 'info': 'words are cool', + \ 'kind': 'W' + \ } + \ ] + \ } +endfunction + +function! s:CompleteDone_CheckCompletedItemDictNoUserData() + call assert_equal( 'aword', v:completed_item[ 'word' ] ) + call assert_equal( 'wrd', v:completed_item[ 'abbr' ] ) + call assert_equal( 'extra text', v:completed_item[ 'menu' ] ) + call assert_equal( 'words are cool', v:completed_item[ 'info' ] ) + call assert_equal( 'W', v:completed_item[ 'kind' ] ) + call assert_equal( '', v:completed_item[ 'user_data' ] ) + + let s:called_completedone = 1 +endfunction + +function Test_CompleteDoneDictNoUserData() + au CompleteDone * :call <SID>CompleteDone_CheckCompletedItemDictNoUserData() + + set completefunc=<SID>CompleteDone_CompleteFuncDictNoUserData + execute "normal a\<C-X>\<C-U>\<C-Y>" + set completefunc& + + call assert_equal( '', v:completed_item[ 'user_data' ] ) + call assert_true( s:called_completedone ) + + let s:called_completedone = 0 + au! CompleteDone +endfunc + +function! s:CompleteDone_CompleteFuncList( findstart, base ) + if a:findstart + return 0 + endif + + return [ 'aword' ] +endfunction + +function! s:CompleteDone_CheckCompletedItemList() + call assert_equal( 'aword', v:completed_item[ 'word' ] ) + call assert_equal( '', v:completed_item[ 'abbr' ] ) + call assert_equal( '', v:completed_item[ 'menu' ] ) + call assert_equal( '', v:completed_item[ 'info' ] ) + call assert_equal( '', v:completed_item[ 'kind' ] ) + call assert_equal( '', v:completed_item[ 'user_data' ] ) + + let s:called_completedone = 1 +endfunction + +function Test_CompleteDoneList() + au CompleteDone * :call <SID>CompleteDone_CheckCompletedItemList() + + set completefunc=<SID>CompleteDone_CompleteFuncList + execute "normal a\<C-X>\<C-U>\<C-Y>" + set completefunc& + + call assert_equal( '', v:completed_item[ 'user_data' ] ) + call assert_true( s:called_completedone ) + + let s:called_completedone = 0 + au! CompleteDone +endfunc diff --git a/test/functional/autocmd/filetype_spec.lua b/test/functional/autocmd/filetype_spec.lua new file mode 100644 index 0000000000..e6fa7ab6bb --- /dev/null +++ b/test/functional/autocmd/filetype_spec.lua @@ -0,0 +1,16 @@ +local helpers = require('test.functional.helpers')(after_each) + +local eval = helpers.eval +local clear = helpers.clear +local command = helpers.command + +describe('autocmd FileType', function() + before_each(clear) + + it("is triggered by :help only once", function() + command("let g:foo = 0") + command("autocmd FileType help let g:foo = g:foo + 1") + command("help help") + assert.same(1, eval('g:foo')) + end) +end) diff --git a/test/functional/autocmd/termclose_spec.lua b/test/functional/autocmd/termclose_spec.lua index e64df502a6..9918cbe4fa 100644 --- a/test/functional/autocmd/termclose_spec.lua +++ b/test/functional/autocmd/termclose_spec.lua @@ -5,8 +5,8 @@ local clear, command, nvim, nvim_dir = local eval, eq, retry = helpers.eval, helpers.eq, helpers.retry local ok = helpers.ok +local iswin = helpers.iswin -if helpers.pending_win32(pending) then return end describe('TermClose event', function() before_each(function() @@ -23,7 +23,7 @@ describe('TermClose event', function() end) it('triggers when long-running terminal job gets stopped', function() - nvim('set_option', 'shell', 'sh') + nvim('set_option', 'shell', iswin() and 'cmd.exe' or 'sh') command('autocmd TermClose * let g:test_termclose = 23') command('terminal') command('call jobstop(b:terminal_job_id)') @@ -31,6 +31,7 @@ describe('TermClose event', function() end) it('kills job trapping SIGTERM', function() + if helpers.pending_win32(pending) then return end nvim('set_option', 'shell', 'sh') nvim('set_option', 'shellcmdflag', '-c') command([[ let g:test_job = jobstart('trap "" TERM && echo 1 && sleep 60', { ]] @@ -48,6 +49,7 @@ describe('TermClose event', function() end) it('kills pty job trapping SIGHUP and SIGTERM', function() + if helpers.pending_win32(pending) then return end nvim('set_option', 'shell', 'sh') nvim('set_option', 'shellcmdflag', '-c') command([[ let g:test_job = jobstart('trap "" HUP TERM && echo 1 && sleep 60', { ]] diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index 65ec198a08..e3c93d4b5a 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -12,6 +12,7 @@ local get_pathsep = helpers.get_pathsep local pathroot = helpers.pathroot local nvim_set = helpers.nvim_set local expect_twostreams = helpers.expect_twostreams +local expect_msg_seq = helpers.expect_msg_seq local Screen = require('test.functional.ui.screen') describe('jobs', function() @@ -59,7 +60,7 @@ describe('jobs', function() it('changes to given / directory', function() nvim('command', "let g:job_opts.cwd = '/'") if iswin() then - nvim('command', "let j = jobstart('pwd|%{$_.Path}', g:job_opts)") + nvim('command', "let j = jobstart('(Get-Location).Path', g:job_opts)") else nvim('command', "let j = jobstart('pwd', g:job_opts)") end @@ -74,13 +75,22 @@ describe('jobs', function() mkdir(dir) nvim('command', "let g:job_opts.cwd = '" .. dir .. "'") if iswin() then - nvim('command', "let j = jobstart('pwd|%{$_.Path}', g:job_opts)") + nvim('command', "let j = jobstart('(Get-Location).Path', g:job_opts)") else nvim('command', "let j = jobstart('pwd', g:job_opts)") end - eq({'notification', 'stdout', {0, {dir, ''}}}, next_msg()) - eq({'notification', 'stdout', {0, {''}}}, next_msg()) - eq({'notification', 'exit', {0, 0}}, next_msg()) + expect_msg_seq( + { {'notification', 'stdout', {0, {dir, ''} } }, + {'notification', 'stdout', {0, {''} } }, + {'notification', 'exit', {0, 0} } + }, + -- Alternative sequence: + { {'notification', 'stdout', {0, {dir} } }, + {'notification', 'stdout', {0, {'', ''} } }, + {'notification', 'stdout', {0, {''} } }, + {'notification', 'exit', {0, 0} } + } + ) rmdir(dir) end) @@ -105,13 +115,13 @@ describe('jobs', function() end) it('returns -1 when target is not executable #5465', function() - if helpers.pending_win32(pending) then return end local function new_job() return eval([[jobstart('')]]) end local executable_jobid = new_job() - local nonexecutable_jobid = eval( - "jobstart(['./test/functional/fixtures/non_executable.txt'])") + local nonexecutable_jobid = eval("jobstart(['"..(iswin() + and './test/functional/fixtures' + or './test/functional/fixtures/non_executable.txt').."'])") eq(-1, nonexecutable_jobid) -- Should _not_ throw an error. eq("", eval("v:errmsg")) @@ -123,11 +133,10 @@ describe('jobs', function() -- TODO: hangs on Windows if helpers.pending_win32(pending) then return end nvim('command', "let g:job_opts.on_stderr = function('OnEvent')") - nvim('command', "call jobstart('echo', g:job_opts)") + nvim('command', [[call jobstart('echo ""', g:job_opts)]]) expect_twostreams({{'notification', 'stdout', {0, {'', ''}}}, {'notification', 'stdout', {0, {''}}}}, {{'notification', 'stderr', {0, {''}}}}) - eq({'notification', 'exit', {0, 0}}, next_msg()) end) @@ -243,7 +252,6 @@ describe('jobs', function() end) it('will not leak memory if we leave a job running', function() - if helpers.pending_win32(pending) then return end -- TODO: Need `cat`. nvim('command', "call jobstart(['cat', '-'], g:job_opts)") end) @@ -289,14 +297,6 @@ describe('jobs', function() eq({'notification', 'exit', {data, 0}}, next_msg()) end) - it('can omit options', function() - if helpers.pending_win32(pending) then return end - neq(0, nvim('eval', 'delete(".Xtestjob")')) - nvim('command', "call jobstart(['touch', '.Xtestjob'])") - nvim('command', "sleep 100m") - eq(0, nvim('eval', 'delete(".Xtestjob")')) - end) - it('can omit data callbacks', function() nvim('command', 'unlet g:job_opts.on_stdout') nvim('command', 'let g:job_opts.user = 5') @@ -308,8 +308,15 @@ describe('jobs', function() nvim('command', 'unlet g:job_opts.on_exit') nvim('command', 'let g:job_opts.user = 5') nvim('command', [[call jobstart('echo "foo"', g:job_opts)]]) - eq({'notification', 'stdout', {5, {'foo', ''}}}, next_msg()) - eq({'notification', 'stdout', {5, {''}}}, next_msg()) + expect_msg_seq( + { {'notification', 'stdout', {5, {'foo', ''} } }, + {'notification', 'stdout', {5, {''} } } + }, + -- Alternative sequence: + { {'notification', 'stdout', {5, {'foo'} } }, + {'notification', 'stdout', {5, {'', ''} } } + } + ) end) it('will pass return code with the exit event', function() @@ -331,7 +338,6 @@ describe('jobs', function() end) it('can redefine callbacks being used by a job', function() - if helpers.pending_win32(pending) then return end -- TODO: Need `cat`. local screen = Screen.new() screen:attach() screen:set_default_attr_ids({ @@ -346,7 +352,7 @@ describe('jobs', function() \ 'on_stderr': function('g:JobHandler'), \ 'on_exit': function('g:JobHandler') \ } - let job = jobstart('cat -', g:callbacks) + let job = jobstart(['cat', '-'], g:callbacks) ]]) wait() source([[ diff --git a/test/functional/eval/system_spec.lua b/test/functional/eval/system_spec.lua index 7fe79d4351..446afefb59 100644 --- a/test/functional/eval/system_spec.lua +++ b/test/functional/eval/system_spec.lua @@ -188,8 +188,9 @@ describe('system()', function() end) it('`yes` and is interrupted with CTRL-C', function() - if helpers.pending_win32(pending) then return end - feed(':call system("yes")<cr>') + feed(':call system("' .. (iswin() + and 'for /L %I in (1,0,2) do @echo y' + or 'yes') .. '")<cr>') screen:expect([[ | ~ | @@ -204,8 +205,11 @@ describe('system()', function() ~ | ~ | ~ | - :call system("yes") | - ]]) +]] .. (iswin() + and [[ + :call system("for /L %I in (1,0,2) do @echo y") |]] + or [[ + :call system("yes") |]])) feed('<c-c>') screen:expect([[ ^ | diff --git a/test/functional/ex_cmds/cd_spec.lua b/test/functional/ex_cmds/cd_spec.lua index 059cb26d5d..bc2b365b30 100644 --- a/test/functional/ex_cmds/cd_spec.lua +++ b/test/functional/ex_cmds/cd_spec.lua @@ -8,8 +8,7 @@ local call = helpers.call local clear = helpers.clear local command = helpers.command local exc_exec = helpers.exc_exec - -if helpers.pending_win32(pending) then return end +local pathsep = helpers.get_pathsep() -- These directories will be created for testing local directories = { @@ -75,8 +74,8 @@ for _, cmd in ipairs {'cd', 'chdir'} do eq(0, lwd(globalwin, tabnr)) -- Window with local dir reports as such - eq(globalDir .. '/' .. directories.window, cwd(localwin)) - eq(globalDir .. '/' .. directories.window, cwd(localwin, tabnr)) + eq(globalDir .. pathsep .. directories.window, cwd(localwin)) + eq(globalDir .. pathsep .. directories.window, cwd(localwin, tabnr)) eq(1, lwd(localwin)) eq(1, lwd(localwin, tabnr)) @@ -86,7 +85,7 @@ for _, cmd in ipairs {'cd', 'chdir'} do eq(0, lwd(globalwin, tabnr)) -- From new tab page, local window reports as such - eq(globalDir .. '/' .. directories.window, cwd(localwin, tabnr)) + eq(globalDir .. pathsep .. directories.window, cwd(localwin, tabnr)) eq(1, lwd(localwin, tabnr)) end) @@ -109,14 +108,14 @@ for _, cmd in ipairs {'cd', 'chdir'} do eq(0, lwd(-1, globaltab)) -- new tab reports local - eq(globalDir .. '/' .. directories.tab, cwd(-1, 0)) - eq(globalDir .. '/' .. directories.tab, cwd(-1, localtab)) + eq(globalDir .. pathsep .. directories.tab, cwd(-1, 0)) + eq(globalDir .. pathsep .. directories.tab, cwd(-1, localtab)) eq(1, lwd(-1, 0)) eq(1, lwd(-1, localtab)) command('tabnext') -- From original tab page, local reports as such - eq(globalDir .. '/' .. directories.tab, cwd(-1, localtab)) + eq(globalDir .. pathsep .. directories.tab, cwd(-1, localtab)) eq(1, lwd(-1, localtab)) end) end) @@ -147,17 +146,17 @@ for _, cmd in ipairs {'cd', 'chdir'} do -- Create a new tab and change directory command('tabnew') command('silent t' .. cmd .. ' ' .. directories.tab) - eq(globalDir .. '/' .. directories.tab, tcwd()) + eq(globalDir .. pathsep .. directories.tab, tcwd()) -- Create a new tab and verify it has inherited the directory command('tabnew') - eq(globalDir .. '/' .. directories.tab, tcwd()) + eq(globalDir .. pathsep .. directories.tab, tcwd()) -- Change tab and change back, verify that directories are correct command('tabnext') eq(globalDir, tcwd()) command('tabprevious') - eq(globalDir .. '/' .. directories.tab, tcwd()) + eq(globalDir .. pathsep .. directories.tab, tcwd()) end) end) @@ -173,7 +172,7 @@ for _, cmd in ipairs {'cd', 'chdir'} do -- Change tab-local working directory and verify it is different command('silent t' .. cmd .. ' ' .. directories.tab) - eq(globalDir .. '/' .. directories.tab, cwd()) + eq(globalDir .. pathsep .. directories.tab, cwd()) eq(cwd(), tcwd()) -- working directory maches tab directory eq(1, tlwd()) eq(cwd(), wcwd()) -- still no window-directory @@ -183,16 +182,16 @@ for _, cmd in ipairs {'cd', 'chdir'} do command('new') eq(1, tlwd()) -- Still tab-local working directory eq(0, wlwd()) -- Still no window-local working directory - eq(globalDir .. '/' .. directories.tab, cwd()) + eq(globalDir .. pathsep .. directories.tab, cwd()) command('silent l' .. cmd .. ' ../' .. directories.window) - eq(globalDir .. '/' .. directories.window, cwd()) - eq(globalDir .. '/' .. directories.tab, tcwd()) + eq(globalDir .. pathsep .. directories.window, cwd()) + eq(globalDir .. pathsep .. directories.tab, tcwd()) eq(1, wlwd()) -- Verify the first window still has the tab local directory command('wincmd w') - eq(globalDir .. '/' .. directories.tab, cwd()) - eq(globalDir .. '/' .. directories.tab, tcwd()) + eq(globalDir .. pathsep .. directories.tab, cwd()) + eq(globalDir .. pathsep .. directories.tab, tcwd()) eq(0, wlwd()) -- No window-local directory -- Change back to initial tab and verify working directory has stayed @@ -203,10 +202,10 @@ for _, cmd in ipairs {'cd', 'chdir'} do -- Verify global changes don't affect local ones command('silent ' .. cmd .. ' ' .. directories.global) - eq(globalDir .. '/' .. directories.global, cwd()) + eq(globalDir .. pathsep .. directories.global, cwd()) command('tabnext') - eq(globalDir .. '/' .. directories.tab, cwd()) - eq(globalDir .. '/' .. directories.tab, tcwd()) + eq(globalDir .. pathsep .. directories.tab, cwd()) + eq(globalDir .. pathsep .. directories.tab, tcwd()) eq(0, wlwd()) -- Still no window-local directory in this window -- Unless the global change happened in a tab with local directory @@ -220,9 +219,9 @@ for _, cmd in ipairs {'cd', 'chdir'} do -- But not in a window with its own local directory command('tabnext | wincmd w') - eq(globalDir .. '/' .. directories.window, cwd() ) + eq(globalDir .. pathsep .. directories.window, cwd() ) eq(0 , tlwd()) - eq(globalDir .. '/' .. directories.window, wcwd()) + eq(globalDir .. pathsep .. directories.window, wcwd()) end) end) end @@ -280,6 +279,9 @@ describe("getcwd()", function () end) it("returns empty string if working directory does not exist", function() + if helpers.iswin() then + return + end command("cd "..directories.global) command("call delete('../"..directories.global.."', 'd')") eq("", helpers.eval("getcwd()")) diff --git a/test/functional/ex_cmds/write_spec.lua b/test/functional/ex_cmds/write_spec.lua index 863d439080..bcf83698bb 100644 --- a/test/functional/ex_cmds/write_spec.lua +++ b/test/functional/ex_cmds/write_spec.lua @@ -10,8 +10,6 @@ local feed_command = helpers.feed_command local funcs = helpers.funcs local meths = helpers.meths -if helpers.pending_win32(pending) then return end - local fname = 'Xtest-functional-ex_cmds-write' local fname_bak = fname .. '~' local fname_broken = fname_bak .. 'broken' @@ -36,7 +34,11 @@ describe(':write', function() it('&backupcopy=auto preserves symlinks', function() command('set backupcopy=auto') write_file('test_bkc_file.txt', 'content0') - command("silent !ln -s test_bkc_file.txt test_bkc_link.txt") + if helpers.iswin() then + command("silent !mklink test_bkc_link.txt test_bkc_file.txt") + else + command("silent !ln -s test_bkc_file.txt test_bkc_link.txt") + end source([[ edit test_bkc_link.txt call setline(1, ['content1']) @@ -49,7 +51,11 @@ describe(':write', function() it('&backupcopy=no replaces symlink with new file', function() command('set backupcopy=no') write_file('test_bkc_file.txt', 'content0') - command("silent !ln -s test_bkc_file.txt test_bkc_link.txt") + if helpers.iswin() then + command("silent !mklink test_bkc_link.txt test_bkc_file.txt") + else + command("silent !ln -s test_bkc_file.txt test_bkc_link.txt") + end source([[ edit test_bkc_link.txt call setline(1, ['content1']) @@ -82,8 +88,10 @@ describe(':write', function() command('let $HOME=""') eq(funcs.fnamemodify('.', ':p:h'), funcs.fnamemodify('.', ':p:h:~')) -- Message from check_overwrite - eq(('\nE17: "'..funcs.fnamemodify('.', ':p:h')..'" is a directory'), - redir_exec('write .')) + if not helpers.iswin() then + eq(('\nE17: "'..funcs.fnamemodify('.', ':p:h')..'" is a directory'), + redir_exec('write .')) + end meths.set_option('writeany', true) -- Message from buf_write eq(('\nE502: "." is a directory'), @@ -100,9 +108,16 @@ describe(':write', function() funcs.setfperm(fname, 'r--------') eq('Vim(write):E505: "Xtest-functional-ex_cmds-write" is read-only (add ! to override)', exc_exec('write')) - os.remove(fname) - os.remove(fname_bak) + if helpers.iswin() then + eq(0, os.execute('del /q/f ' .. fname)) + eq(0, os.execute('rd /q/s ' .. fname_bak)) + else + eq(true, os.remove(fname)) + eq(true, os.remove(fname_bak)) + end write_file(fname_bak, 'TTYX') + -- FIXME: exc_exec('write!') outputs 0 in Windows + if helpers.iswin() then return end lfs.link(fname_bak .. ('/xxxxx'):rep(20), fname, true) eq('Vim(write):E166: Can\'t open linked file for writing', exc_exec('write!')) diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index f0e47481da..1f53200dd8 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -18,6 +18,7 @@ local ok = global_helpers.ok local map = global_helpers.map local filter = global_helpers.filter local dedent = global_helpers.dedent +local table_flatten = global_helpers.table_flatten local start_dir = lfs.currentdir() -- XXX: NVIM_PROG takes precedence, QuickBuild sets it. @@ -96,8 +97,8 @@ local function request(method, ...) return rv end -local function next_message() - return session:next_message() +local function next_message(timeout) + return session:next_message(timeout) end local function expect_twostreams(msgs1, msgs2) @@ -116,6 +117,46 @@ local function expect_twostreams(msgs1, msgs2) end end +-- Expects a sequence of next_message() results. If multiple sequences are +-- passed they are tried until one succeeds, in order of shortest to longest. +local function expect_msg_seq(...) + if select('#', ...) < 1 then + error('need at least 1 argument') + end + local seqs = {...} + table.sort(seqs, function(a, b) -- Sort ascending, by (shallow) length. + return #a < #b + end) + + local actual_seq = {} + local final_error = '' + local function cat_err(err1, err2) + if err1 == nil then + return err2 + end + return string.format('%s\n%s\n%s', err1, string.rep('=', 78), err2) + end + for anum = 1, #seqs do + local expected_seq = seqs[anum] + -- Collect enough messages to compare the next expected sequence. + while #actual_seq < #expected_seq do + local msg = next_message(10000) -- Big timeout for ASAN/valgrind. + if msg == nil then + error(cat_err(final_error, + string.format('got %d messages, expected %d', + #actual_seq, #expected_seq))) + end + table.insert(actual_seq, msg) + end + local status, result = pcall(eq, expected_seq, actual_seq) + if status then + return result + end + final_error = cat_err(final_error, result) + end + error(final_error) +end + local function call_and_stop_on_error(...) local status, result = copcall(...) -- luacheck: ignore if not status then @@ -600,7 +641,7 @@ local function redir_exec(cmd) end local function get_pathsep() - return funcs.fnamemodify('.', ':p'):sub(-1) + return iswin() and '\\' or '/' end local function pathroot() @@ -674,78 +715,80 @@ local function hexdump(str) end local module = { - prepend_argv = prepend_argv, + NIL = mpack.NIL, + alter_slashes = alter_slashes, + buffer = buffer, + bufmeths = bufmeths, + call = nvim_call, clear = clear, + command = nvim_command, connect = connect, - retry = retry, - spawn = spawn, + curbuf = curbuf, + curbuf_contents = curbuf_contents, + curbufmeths = curbufmeths, + curtab = curtab, + curtabmeths = curtabmeths, + curwin = curwin, + curwinmeths = curwinmeths, dedent = dedent, - source = source, - rawfeed = rawfeed, - insert = insert, - iswin = iswin, - feed = feed, - feed_command = feed_command, - eval = nvim_eval, - call = nvim_call, - command = nvim_command, - request = request, - next_message = next_message, - expect_twostreams = expect_twostreams, - run = run, - stop = stop, eq = eq, - neq = neq, + eval = nvim_eval, + exc_exec = exc_exec, expect = expect, expect_any = expect_any, - ok = ok, - map = map, + expect_msg_seq = expect_msg_seq, + expect_twostreams = expect_twostreams, + feed = feed, + feed_command = feed_command, filter = filter, + funcs = funcs, + get_pathsep = get_pathsep, + hexdump = hexdump, + insert = insert, + iswin = iswin, + map = map, + merge_args = merge_args, + meth_pcall = meth_pcall, + meths = meths, + missing_provider = missing_provider, + mkdir = lfs.mkdir, + neq = neq, + new_pipename = new_pipename, + next_message = next_message, nvim = nvim, + nvim_argv = nvim_argv, nvim_async = nvim_async, + nvim_dir = nvim_dir, nvim_prog = nvim_prog, - nvim_argv = nvim_argv, nvim_set = nvim_set, - nvim_dir = nvim_dir, - buffer = buffer, - window = window, - tabpage = tabpage, - curbuf = curbuf, - curwin = curwin, - curtab = curtab, - curbuf_contents = curbuf_contents, - wait = wait, - sleep = sleep, - set_session = set_session, - write_file = write_file, - read_file = read_file, + ok = ok, os_name = os_name, - rmdir = rmdir, - mkdir = lfs.mkdir, - exc_exec = exc_exec, - redir_exec = redir_exec, - merge_args = merge_args, - funcs = funcs, - meths = meths, - bufmeths = bufmeths, - winmeths = winmeths, - tabmeths = tabmeths, - uimeths = uimeths, - curbufmeths = curbufmeths, - curwinmeths = curwinmeths, - curtabmeths = curtabmeths, + pathroot = pathroot, pending_win32 = pending_win32, - skip_fragile = skip_fragile, + prepend_argv = prepend_argv, + rawfeed = rawfeed, + read_file = read_file, + redir_exec = redir_exec, + request = request, + retry = retry, + rmdir = rmdir, + run = run, + set_session = set_session, set_shell_powershell = set_shell_powershell, + skip_fragile = skip_fragile, + sleep = sleep, + source = source, + spawn = spawn, + stop = stop, + table_flatten = table_flatten, + tabmeths = tabmeths, + tabpage = tabpage, tmpname = tmpname, - meth_pcall = meth_pcall, - NIL = mpack.NIL, - get_pathsep = get_pathsep, - pathroot = pathroot, - missing_provider = missing_provider, - alter_slashes = alter_slashes, - hexdump = hexdump, - new_pipename = new_pipename, + uimeths = uimeths, + wait = wait, + window = window, + winmeths = winmeths, + write_file = write_file, } return function(after_each) diff --git a/test/functional/legacy/011_autocommands_spec.lua b/test/functional/legacy/011_autocommands_spec.lua index d969a8bd37..c2667d28d2 100644 --- a/test/functional/legacy/011_autocommands_spec.lua +++ b/test/functional/legacy/011_autocommands_spec.lua @@ -18,10 +18,9 @@ local clear, feed_command, expect, eq, neq, dedent, write_file, feed = helpers.clear, helpers.feed_command, helpers.expect, helpers.eq, helpers.neq, helpers.dedent, helpers.write_file, helpers.feed -if helpers.pending_win32(pending) then return end - local function has_gzip() - return os.execute('gzip --help >/dev/null 2>&1') == 0 + local null = helpers.iswin() and 'nul' or '/dev/null' + return os.execute('gzip --help >' .. null .. ' 2>&1') == 0 end local function prepare_gz_file(name, text) @@ -142,6 +141,7 @@ describe('file reading, writing and bufnew and filter autocommands', function() end) it('FilterReadPre, FilterReadPost', function() + if helpers.pending_win32(pending) then return end -- Write a special input file for this test block. write_file('test.out', dedent([[ startstart diff --git a/test/functional/legacy/025_jump_tag_hidden_spec.lua b/test/functional/legacy/025_jump_tag_hidden_spec.lua index 0d51b4da26..dd89a3680e 100644 --- a/test/functional/legacy/025_jump_tag_hidden_spec.lua +++ b/test/functional/legacy/025_jump_tag_hidden_spec.lua @@ -5,8 +5,6 @@ local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local feed_command, expect = helpers.feed_command, helpers.expect -if helpers.pending_win32(pending) then return end - describe('jump to a tag with hidden set', function() setup(clear) @@ -25,12 +23,17 @@ describe('jump to a tag with hidden set', function() feed_command('set hidden') -- Create a link from test25.dir to the current directory. - feed_command('!rm -f test25.dir') - feed_command('!ln -s . test25.dir') + if helpers.iswin() then + feed_command('!rd /q/s test25.dir') + feed_command('!mklink /j test25.dir .') + else + feed_command('!rm -f test25.dir') + feed_command('!ln -s . test25.dir') + end -- Create tags.text, with the current directory name inserted. feed_command('/tags line') - feed_command('r !pwd') + feed_command('r !' .. (helpers.iswin() and 'cd' or 'pwd')) feed('d$/test<cr>') feed('hP:.w! tags.test<cr>') @@ -39,7 +42,13 @@ describe('jump to a tag with hidden set', function() -- space will then be eaten by hit-return, instead of moving the cursor to 'd'. feed_command('set tags=tags.test') feed('G<C-]> x:yank a<cr>') - feed_command('!rm -f Xxx test25.dir tags.test') + feed_command("call delete('tags.test')") + feed_command("call delete('Xxx')") + if helpers.iswin() then + feed_command('!rd /q test25.dir') + else + feed_command('!rm -f test25.dir') + end -- Put @a and remove empty line feed_command('%d') diff --git a/test/functional/legacy/030_fileformats_spec.lua b/test/functional/legacy/030_fileformats_spec.lua index 7384fdf847..2fd51602d8 100644 --- a/test/functional/legacy/030_fileformats_spec.lua +++ b/test/functional/legacy/030_fileformats_spec.lua @@ -5,8 +5,6 @@ local feed, clear, command = helpers.feed, helpers.clear, helpers.command local eq, write_file = helpers.eq, helpers.write_file local wait = helpers.wait -if helpers.pending_win32(pending) then return end - describe('fileformats option', function() setup(function() clear() diff --git a/test/functional/legacy/051_highlight_spec.lua b/test/functional/legacy/051_highlight_spec.lua index 2ef74196ee..40f70de2ec 100644 --- a/test/functional/legacy/051_highlight_spec.lua +++ b/test/functional/legacy/051_highlight_spec.lua @@ -8,8 +8,6 @@ local eq = helpers.eq local wait = helpers.wait local exc_exec = helpers.exc_exec -if helpers.pending_win32(pending) then return end - describe(':highlight', function() setup(clear) diff --git a/test/functional/legacy/059_utf8_spell_checking_spec.lua b/test/functional/legacy/059_utf8_spell_checking_spec.lua index 120e469ab2..8630ac58ef 100644 --- a/test/functional/legacy/059_utf8_spell_checking_spec.lua +++ b/test/functional/legacy/059_utf8_spell_checking_spec.lua @@ -5,8 +5,6 @@ local feed, insert, source = helpers.feed, helpers.insert, helpers.source local clear, feed_command, expect = helpers.clear, helpers.feed_command, helpers.expect local write_file, call = helpers.write_file, helpers.call -if helpers.pending_win32(pending) then return end - local function write_latin1(name, text) text = call('iconv', text, 'utf-8', 'latin-1') write_file(name, text) @@ -507,8 +505,13 @@ describe("spell checking with 'encoding' set to utf-8", function() -- Vim function in the original legacy test. local function test_one(aff, dic) -- Generate a .spl file from a .dic and .aff file. - os.execute('cp -f Xtest'..aff..'.aff Xtest.aff') - os.execute('cp -f Xtest'..dic..'.dic Xtest.dic') + if helpers.iswin() then + os.execute('copy /y Xtest'..aff..'.aff Xtest.aff') + os.execute('copy /y Xtest'..dic..'.dic Xtest.dic') + else + os.execute('cp -f Xtest'..aff..'.aff Xtest.aff') + os.execute('cp -f Xtest'..dic..'.dic Xtest.dic') + end source([[ set spellfile= function! SpellDumpNoShow() @@ -559,7 +562,11 @@ describe("spell checking with 'encoding' set to utf-8", function() feed_command([[$put =soundfold('kóopërÿnôven')]]) feed_command([[$put =soundfold('oeverloos gezwets edale')]]) -- And now with SAL instead of SOFO items; test automatic reloading. - os.execute('cp -f Xtest-sal.aff Xtest.aff') + if helpers.iswin() then + os.execute('copy /y Xtest-sal.aff Xtest.aff') + else + os.execute('cp -f Xtest-sal.aff Xtest.aff') + end feed_command('mkspell! Xtest Xtest') feed_command([[$put =soundfold('goobledygoook')]]) feed_command([[$put =soundfold('kóopërÿnôven')]]) diff --git a/test/functional/legacy/093_mksession_cursor_cols_latin1_spec.lua b/test/functional/legacy/093_mksession_cursor_cols_latin1_spec.lua index b1221ff8b6..f09fd9a6e5 100644 --- a/test/functional/legacy/093_mksession_cursor_cols_latin1_spec.lua +++ b/test/functional/legacy/093_mksession_cursor_cols_latin1_spec.lua @@ -7,8 +7,6 @@ local helpers = require('test.functional.helpers')(after_each) local feed, insert = helpers.feed, helpers.insert local clear, feed_command, expect = helpers.clear, helpers.feed_command, helpers.expect -if helpers.pending_win32(pending) then return end - describe('store cursor position in session file in Latin-1', function() setup(clear) diff --git a/test/functional/legacy/097_glob_path_spec.lua b/test/functional/legacy/097_glob_path_spec.lua index 6b63a317f1..907f0665ae 100644 --- a/test/functional/legacy/097_glob_path_spec.lua +++ b/test/functional/legacy/097_glob_path_spec.lua @@ -6,15 +6,19 @@ local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local command, expect = helpers.command, helpers.expect -if helpers.pending_win32(pending) then return end - describe('glob() and globpath()', function() setup(clear) setup(function() - os.execute("mkdir -p sautest/autoload") - os.execute("touch sautest/autoload/Test104.vim") - os.execute("touch sautest/autoload/footest.vim") + if helpers.iswin() then + os.execute("md sautest\\autoload") + os.execute(".>sautest\\autoload\\Test104.vim 2>nul") + os.execute(".>sautest\\autoload\\footest.vim 2>nul") + else + os.execute("mkdir -p sautest/autoload") + os.execute("touch sautest/autoload/Test104.vim") + os.execute("touch sautest/autoload/footest.vim") + end end) it('is working', function() @@ -24,29 +28,55 @@ describe('glob() and globpath()', function() -- Consistent sorting of file names command('set nofileignorecase') - command([[$put =glob('Xxx\{')]]) - command([[$put =glob('Xxx\$')]]) + if helpers.iswin() then + command([[$put =glob('Xxx{')]]) + command([[$put =glob('Xxx$')]]) + + command('silent w! Xxx{') + command([[w! Xxx$]]) + command([[$put =glob('Xxx{')]]) + command([[$put =glob('Xxx$')]]) + + command([[$put =string(globpath('sautest\autoload', '*.vim'))]]) + command([[$put =string(globpath('sautest\autoload', '*.vim', 0, 1))]]) + expect([=[ + + - command('silent w! Xxx{') - command([[w! Xxx\$]]) - command([[$put =glob('Xxx\{')]]) - command([[$put =glob('Xxx\$')]]) + Xxx{ + Xxx$ + 'sautest\autoload\Test104.vim + sautest\autoload\footest.vim' + ['sautest\autoload\Test104.vim', 'sautest\autoload\footest.vim']]=]) + else + command([[$put =glob('Xxx\{')]]) + command([[$put =glob('Xxx\$')]]) - command("$put =string(globpath('sautest/autoload', '*.vim'))") - command("$put =string(globpath('sautest/autoload', '*.vim', 0, 1))") + command('silent w! Xxx{') + command([[w! Xxx\$]]) + command([[$put =glob('Xxx\{')]]) + command([[$put =glob('Xxx\$')]]) - expect([=[ + command("$put =string(globpath('sautest/autoload', '*.vim'))") + command("$put =string(globpath('sautest/autoload', '*.vim', 0, 1))") + expect([=[ - Xxx{ - Xxx$ - 'sautest/autoload/Test104.vim - sautest/autoload/footest.vim' - ['sautest/autoload/Test104.vim', 'sautest/autoload/footest.vim']]=]) + Xxx{ + Xxx$ + 'sautest/autoload/Test104.vim + sautest/autoload/footest.vim' + ['sautest/autoload/Test104.vim', 'sautest/autoload/footest.vim']]=]) + end end) teardown(function() - os.execute("rm -rf sautest Xxx{ Xxx$") + if helpers.iswin() then + os.execute('del /q/f Xxx{ Xxx$') + os.execute('rd /q sautest') + else + os.execute("rm -rf sautest Xxx{ Xxx$") + end end) end) diff --git a/test/functional/legacy/107_adjust_window_and_contents_spec.lua b/test/functional/legacy/107_adjust_window_and_contents_spec.lua index 836a0f8f24..239f60341a 100644 --- a/test/functional/legacy/107_adjust_window_and_contents_spec.lua +++ b/test/functional/legacy/107_adjust_window_and_contents_spec.lua @@ -8,8 +8,6 @@ local clear = helpers.clear local insert = helpers.insert local command = helpers.command -if helpers.pending_win32(pending) then return end - describe('107', function() setup(clear) diff --git a/test/functional/legacy/arglist_spec.lua b/test/functional/legacy/arglist_spec.lua index ec754a533b..bd65e549ef 100644 --- a/test/functional/legacy/arglist_spec.lua +++ b/test/functional/legacy/arglist_spec.lua @@ -4,8 +4,6 @@ local helpers = require('test.functional.helpers')(after_each) local clear, command, eq = helpers.clear, helpers.command, helpers.eq local eval, exc_exec, neq = helpers.eval, helpers.exc_exec, helpers.neq -if helpers.pending_win32(pending) then return end - describe('argument list commands', function() before_each(clear) diff --git a/test/functional/legacy/delete_spec.lua b/test/functional/legacy/delete_spec.lua index aeaab335e8..5ef456bfe3 100644 --- a/test/functional/legacy/delete_spec.lua +++ b/test/functional/legacy/delete_spec.lua @@ -2,8 +2,6 @@ local helpers = require('test.functional.helpers')(after_each) local clear, source = helpers.clear, helpers.source local eq, eval, command = helpers.eq, helpers.eval, helpers.command -if helpers.pending_win32(pending) then return end - describe('Test for delete()', function() before_each(clear) @@ -48,7 +46,11 @@ describe('Test for delete()', function() split Xfile call setline(1, ['a', 'b']) wq - silent !ln -s Xfile Xlink + if has('win32') + silent !mklink Xlink Xfile + else + silent !ln -s Xfile Xlink + endif ]]) -- Delete the link, not the file eq(0, eval("delete('Xlink')")) @@ -58,7 +60,11 @@ describe('Test for delete()', function() it('symlink directory delete', function() command("call mkdir('Xdir1')") - command("silent !ln -s Xdir1 Xlink") + if helpers.iswin() then + command("silent !mklink /j Xlink Xdir1") + else + command("silent !ln -s Xdir1 Xlink") + end eq(1, eval("isdirectory('Xdir1')")) eq(1, eval("isdirectory('Xlink')")) -- Delete the link, not the directory @@ -78,7 +84,11 @@ describe('Test for delete()', function() w Xdir3/subdir/Xfile w Xdir4/Xfile close - silent !ln -s ../Xdir4 Xdir3/Xlink + if has('win32') + silent !mklink /j Xdir3\Xlink Xdir4 + else + silent !ln -s ../Xdir4 Xdir3/Xlink + endif ]]) eq(1, eval("isdirectory('Xdir3')")) diff --git a/test/functional/legacy/fixeol_spec.lua b/test/functional/legacy/fixeol_spec.lua index 801451b300..50236e8617 100644 --- a/test/functional/legacy/fixeol_spec.lua +++ b/test/functional/legacy/fixeol_spec.lua @@ -4,15 +4,14 @@ local helpers = require('test.functional.helpers')(after_each) local feed = helpers.feed local clear, feed_command, expect = helpers.clear, helpers.feed_command, helpers.expect -if helpers.pending_win32(pending) then return end - describe('fixeol', function() local function rmtestfiles() - os.remove('test.out') - os.remove('XXEol') - os.remove('XXNoEol') - os.remove('XXTestEol') - os.remove('XXTestNoEol') + feed_command('%bwipeout!') + feed_command('call delete("test.out")') + feed_command('call delete("XXEol")') + feed_command('call delete("XXNoEol")') + feed_command('call delete("XXTestEol")') + feed_command('call delete("XXTestNoEol")') end setup(function() clear() diff --git a/test/functional/legacy/getcwd_spec.lua b/test/functional/legacy/getcwd_spec.lua index 8fb31ccd22..eae13da528 100644 --- a/test/functional/legacy/getcwd_spec.lua +++ b/test/functional/legacy/getcwd_spec.lua @@ -4,8 +4,6 @@ local helpers = require('test.functional.helpers')(after_each) local eq, eval, source = helpers.eq, helpers.eval, helpers.source local call, clear, command = helpers.call, helpers.clear, helpers.command -if helpers.pending_win32(pending) then return end - describe('getcwd', function() before_each(clear) diff --git a/test/functional/legacy/packadd_spec.lua b/test/functional/legacy/packadd_spec.lua index 2dfd36142b..fb308475c0 100644 --- a/test/functional/legacy/packadd_spec.lua +++ b/test/functional/legacy/packadd_spec.lua @@ -9,17 +9,15 @@ local function expected_empty() eq({}, nvim.get_vvar('errors')) end -if helpers.pending_win32(pending) then return end - describe('packadd', function() before_each(function() clear() source([=[ func SetUp() - let s:topdir = expand('%:p:h') . '/Xdir' + let s:topdir = expand(expand('%:p:h') . '/Xdir') exe 'set packpath=' . s:topdir - let s:plugdir = s:topdir . '/pack/mine/opt/mytest' + let s:plugdir = expand(s:topdir . '/pack/mine/opt/mytest') endfunc func TearDown() @@ -52,8 +50,8 @@ describe('packadd', function() call assert_equal(77, g:plugin_also_works) call assert_true(17, g:ftdetect_works) call assert_true(len(&rtp) > len(rtp)) - call assert_true(&rtp =~ (s:plugdir . '\($\|,\)')) - call assert_true(&rtp =~ (s:plugdir . '/after$')) + call assert_true(&rtp =~ (escape(s:plugdir, '\') . '\($\|,\)')) + call assert_true(&rtp =~ escape(expand(s:plugdir . '/after$'), '\')) " Check exception call assert_fails("packadd directorynotfound", 'E919:') @@ -74,7 +72,7 @@ describe('packadd', function() packadd! mytest call assert_true(len(&rtp) > len(rtp)) - call assert_true(&rtp =~ (s:plugdir . '\($\|,\)')) + call assert_true(&rtp =~ (escape(s:plugdir, '\') . '\($\|,\)')) call assert_equal(0, g:plugin_works) " check the path is not added twice @@ -84,17 +82,18 @@ describe('packadd', function() endfunc func Test_packadd_symlink_dir() - if !has('unix') - return - endif - let top2_dir = s:topdir . '/Xdir2' - let real_dir = s:topdir . '/Xsym' + let top2_dir = expand(s:topdir . '/Xdir2') + let real_dir = expand(s:topdir . '/Xsym') call mkdir(real_dir, 'p') - exec "silent! !ln -s Xsym" top2_dir - let &rtp = top2_dir . ',' . top2_dir . '/after' + if has('win32') + exec "silent! !mklink /d" top2_dir "Xsym" + else + exec "silent! !ln -s Xsym" top2_dir + endif + let &rtp = top2_dir . ',' . expand(top2_dir . '/after') let &packpath = &rtp - let s:plugdir = top2_dir . '/pack/mine/opt/mytest' + let s:plugdir = expand(top2_dir . '/pack/mine/opt/mytest') call mkdir(s:plugdir . '/plugin', 'p') exe 'split ' . s:plugdir . '/plugin/test.vim' @@ -105,7 +104,7 @@ describe('packadd', function() packadd mytest " Must have been inserted in the middle, not at the end - call assert_true(&rtp =~ '/pack/mine/opt/mytest,') + call assert_true(&rtp =~ escape(expand('/pack/mine/opt/mytest').',', '\')) call assert_equal(44, g:plugin_works) " No change when doing it again. @@ -115,7 +114,7 @@ describe('packadd', function() set rtp& let rtp = &rtp - exec "silent !rm" top2_dir + exec "silent !" (has('win32') ? "rd /q/s" : "rm") top2_dir endfunc func Test_packloadall() diff --git a/test/functional/legacy/wordcount_spec.lua b/test/functional/legacy/wordcount_spec.lua index 5412903866..0c8bd2cdcc 100644 --- a/test/functional/legacy/wordcount_spec.lua +++ b/test/functional/legacy/wordcount_spec.lua @@ -6,8 +6,6 @@ local clear, command = helpers.clear, helpers.command local eq, eval = helpers.eq, helpers.eval local wait = helpers.wait -if helpers.pending_win32(pending) then return end - describe('wordcount', function() before_each(clear) diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua index 042969357e..c6ddc78618 100644 --- a/test/functional/ui/wildmode_spec.lua +++ b/test/functional/ui/wildmode_spec.lua @@ -60,8 +60,7 @@ describe("'wildmenu'", function() command('set wildmenu wildmode=full') command('set scrollback=4') if iswin() then - if helpers.pending_win32(pending) then return end - -- feed([[:terminal 1,2,3,4,5 | foreach-object -process {echo $_; sleep 0.1}]]) + feed([[:terminal for /L \%I in (1,1,5000) do @(echo foo & echo foo & echo foo)<cr>]]) else feed([[:terminal for i in $(seq 1 5000); do printf 'foo\nfoo\nfoo\n'; sleep 0.1; done<cr>]]) end diff --git a/test/functional/viml/completion_spec.lua b/test/functional/viml/completion_spec.lua index fbc7a527f8..216ccb3744 100644 --- a/test/functional/viml/completion_spec.lua +++ b/test/functional/viml/completion_spec.lua @@ -59,7 +59,8 @@ describe('completion', function() it('returns expected dict in normal completion', function() feed('ifoo<ESC>o<C-x><C-n>') eq('foo', eval('getline(2)')) - eq({word = 'foo', abbr = '', menu = '', info = '', kind = ''}, + eq({word = 'foo', abbr = '', menu = '', + info = '', kind = '', user_data = ''}, eval('v:completed_item')) end) it('is readonly', function() @@ -84,13 +85,18 @@ describe('completion', function() feed_command('let v:completed_item.kind = "bar"') neq(nil, string.find(eval('v:errmsg'), '^E46: ')) feed_command('let v:errmsg = ""') + + feed_command('let v:completed_item.user_data = "bar"') + neq(nil, string.find(eval('v:errmsg'), '^E46: ')) + feed_command('let v:errmsg = ""') end) it('returns expected dict in omni completion', function() source([[ function! TestOmni(findstart, base) abort return a:findstart ? 0 : [{'word': 'foo', 'abbr': 'bar', \ 'menu': 'baz', 'info': 'foobar', 'kind': 'foobaz'}, - \ {'word': 'word', 'abbr': 'abbr', 'menu': 'menu', 'info': 'info', 'kind': 'kind'}] + \ {'word': 'word', 'abbr': 'abbr', 'menu': 'menu', + \ 'info': 'info', 'kind': 'kind'}] endfunction setlocal omnifunc=TestOmni ]]) @@ -107,7 +113,7 @@ describe('completion', function() {3:-- Omni completion (^O^N^P) }{4:match 1 of 2} | ]]) eq({word = 'foo', abbr = 'bar', menu = 'baz', - info = 'foobar', kind = 'foobaz'}, + info = 'foobar', kind = 'foobaz', user_data = ''}, eval('v:completed_item')) end) end) diff --git a/test/helpers.lua b/test/helpers.lua index 1c64f41b65..91ceed4df1 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -7,13 +7,13 @@ local check_logs_useless_lines = { ['See README_MISSING_SYSCALL_OR_IOCTL for guidance']=3, } -local eq = function(exp, act) - return assert.are.same(exp, act) +local function eq(expected, actual) + return assert.are.same(expected, actual) end -local neq = function(exp, act) - return assert.are_not.same(exp, act) +local function neq(expected, actual) + return assert.are_not.same(expected, actual) end -local ok = function(res) +local function ok(res) return assert.is_true(res) end @@ -534,30 +534,49 @@ local function fixtbl_rec(tbl) return fixtbl(tbl) end +-- From https://github.com/premake/premake-core/blob/master/src/base/table.lua +local function table_flatten(arr) + local result = {} + local function _table_flatten(_arr) + local n = #_arr + for i = 1, n do + local v = _arr[i] + if type(v) == "table" then + _table_flatten(v) + elseif v then + table.insert(result, v) + end + end + end + _table_flatten(arr) + return result +end + return { - eq = eq, - neq = neq, - ok = ok, - check_logs = check_logs, - uname = uname, - tmpname = tmpname, - map = map, - filter = filter, - glob = glob, - check_cores = check_cores, - hasenv = hasenv, - which = which, - shallowcopy = shallowcopy, - deepcopy = deepcopy, - mergedicts_copy = mergedicts_copy, - dictdiff = dictdiff, REMOVE_THIS = REMOVE_THIS, + check_cores = check_cores, + check_logs = check_logs, concat_tables = concat_tables, dedent = dedent, + deepcopy = deepcopy, + dictdiff = dictdiff, + eq = eq, + filter = filter, + fixtbl = fixtbl, + fixtbl_rec = fixtbl_rec, format_luav = format_luav, format_string = format_string, + glob = glob, + hasenv = hasenv, intchar2lua = intchar2lua, + map = map, + mergedicts_copy = mergedicts_copy, + neq = neq, + ok = ok, + shallowcopy = shallowcopy, + table_flatten = table_flatten, + tmpname = tmpname, + uname = uname, updated = updated, - fixtbl = fixtbl, - fixtbl_rec = fixtbl_rec, + which = which, } diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt index 537059afdd..ceebb4cf1d 100644 --- a/third-party/CMakeLists.txt +++ b/third-party/CMakeLists.txt @@ -103,8 +103,8 @@ set(LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333) set(LUAROCKS_URL https://github.com/luarocks/luarocks/archive/v2.4.3.tar.gz) set(LUAROCKS_SHA256 ea1881d6954f2a98c34f93674571c8f0cbdbc28dedb3fa3cb56b6a91886d1a99) -set(UNIBILIUM_URL https://github.com/mauke/unibilium/archive/v1.2.1.tar.gz) -set(UNIBILIUM_SHA256 6045b4f6adca7b1123284007675ca71f718f70942d3a93d8b9fa5bd442006ec1) +set(UNIBILIUM_URL https://github.com/mauke/unibilium/archive/v2.0.0.tar.gz) +set(UNIBILIUM_SHA256 78997d38d4c8177c60d3d0c1aa8c53fd0806eb21825b7b335b1768d7116bc1c1) if(WIN32) set(LIBTERMKEY_URL https://github.com/equalsraf/libtermkey/archive/tb-windows.zip) |