diff options
-rw-r--r-- | runtime/ftplugin/man.vim | 2 | ||||
-rw-r--r-- | scripts/gendispatch.lua | 102 | ||||
-rw-r--r-- | src/nvim/CMakeLists.txt | 10 | ||||
-rw-r--r-- | src/nvim/api/private/dispatch.c | 45 | ||||
-rw-r--r-- | src/nvim/api/private/dispatch.h | 1 | ||||
-rw-r--r-- | src/nvim/api/private/helpers.c | 21 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 1 | ||||
-rw-r--r-- | src/nvim/os/fs.c | 8 | ||||
-rw-r--r-- | src/nvim/testdir/Makefile | 1 | ||||
-rw-r--r-- | src/nvim/testdir/test_history.vim | 65 | ||||
-rw-r--r-- | src/nvim/version.c | 8 | ||||
-rw-r--r-- | src/nvim/window.c | 14 | ||||
-rw-r--r-- | test/functional/core/job_spec.lua | 8 | ||||
-rw-r--r-- | test/functional/ex_cmds/write_spec.lua | 41 | ||||
-rw-r--r-- | test/functional/legacy/assert_spec.lua | 15 | ||||
-rw-r--r-- | test/functional/legacy/quickfix_spec.lua | 117 | ||||
-rw-r--r-- | test/functional/terminal/api_spec.lua | 12 | ||||
-rw-r--r-- | test/functional/terminal/ex_terminal_spec.lua | 48 |
18 files changed, 400 insertions, 119 deletions
diff --git a/runtime/ftplugin/man.vim b/runtime/ftplugin/man.vim index 02d2b4e557..f6fefd0155 100644 --- a/runtime/ftplugin/man.vim +++ b/runtime/ftplugin/man.vim @@ -21,7 +21,7 @@ if has('vim_starting') " all caps it is impossible to tell what the original capitilization was. let ref = tolower(matchstr(getline(1), '^\S\+')) let b:man_sect = man#extract_sect_and_name_ref(ref)[0] - execute 'file man://'.ref + execute 'silent file man://'.ref endif setlocal buftype=nofile diff --git a/scripts/gendispatch.lua b/scripts/gendispatch.lua index 96cf2d3a11..94789e1ef0 100644 --- a/scripts/gendispatch.lua +++ b/scripts/gendispatch.lua @@ -52,16 +52,18 @@ package.path = nvimsrcdir .. '/?.lua;' .. package.path -- names of all headers relative to the source root (for inclusion in the -- generated file) headers = {} --- output c file(dispatch function + metadata serialized with msgpack) -outputf = arg[#arg-1] --- output mpack file (metadata) +-- output h file with generated dispatch functions +dispatch_outputf = arg[#arg-2] +-- output h file with packed metadata +funcs_metadata_outputf = arg[#arg-1] +-- output metadata mpack file, for use by other build scripts mpack_outputf = arg[#arg] -- set of function names, used to detect duplicates function_names = {} -- read each input file, parse and append to the api metadata -for i = 2, #arg - 2 do +for i = 2, #arg - 3 do local full_path = arg[i] local parts = {} for part in string.gmatch(full_path, '[^/]+') do @@ -165,66 +167,27 @@ for _,f in ipairs(functions) do end --- start building the output -output = io.open(outputf, 'wb') - -output:write([[ -#include <inttypes.h> -#include <stdbool.h> -#include <stdint.h> -#include <assert.h> -#include <msgpack.h> - -#include "nvim/map.h" -#include "nvim/log.h" -#include "nvim/vim.h" -#include "nvim/msgpack_rpc/helpers.h" -#include "nvim/api/private/dispatch.h" -#include "nvim/api/private/helpers.h" -#include "nvim/api/private/defs.h" +funcs_metadata_output = io.open(funcs_metadata_outputf, 'wb') +funcs_metadata_output:write([[ +static const uint8_t funcs_metadata[] = { ]]) -for i = 1, #headers do - if headers[i]:sub(-12) ~= '.generated.h' then - output:write('\n#include "nvim/'..headers[i]..'"') - end -end - -output:write([[ - - -static const uint8_t msgpack_metadata[] = { - -]]) -- serialize the API metadata using msgpack and embed into the resulting -- binary for easy querying by clients packed_exported_functions = mpack.pack(exported_functions) for i = 1, #packed_exported_functions do - output:write(string.byte(packed_exported_functions, i)..', ') + funcs_metadata_output:write(string.byte(packed_exported_functions, i)..', ') if i % 10 == 0 then - output:write('\n ') + funcs_metadata_output:write('\n ') end end -output:write([[ +funcs_metadata_output:write([[ }; - -void msgpack_rpc_init_function_metadata(Dictionary *metadata) -{ - msgpack_unpacked unpacked; - msgpack_unpacked_init(&unpacked); - if (msgpack_unpack_next(&unpacked, - (const char *)msgpack_metadata, - sizeof(msgpack_metadata), - NULL) != MSGPACK_UNPACK_SUCCESS) { - abort(); - } - Object functions; - msgpack_rpc_to_object(&unpacked.data, &functions); - msgpack_unpacked_destroy(&unpacked); - PUT(*metadata, "functions", functions); -} - ]]) +funcs_metadata_output:close() + +-- start building the dispatch wrapper output +output = io.open(dispatch_outputf, 'wb') local function real_type(type) local rv = type @@ -336,22 +299,12 @@ end -- Generate a function that initializes method names with handler functions output:write([[ -static Map(String, MsgpackRpcRequestHandler) *methods = NULL; - -void msgpack_rpc_add_method_handler(String method, MsgpackRpcRequestHandler handler) -{ - map_put(String, MsgpackRpcRequestHandler)(methods, method, handler); -} - void msgpack_rpc_init_method_table(void) { methods = map_new(String, MsgpackRpcRequestHandler)(); ]]) --- Keep track of the maximum method name length in order to avoid walking --- strings longer than that when searching for a method handler -local max_fname_len = 0 for i = 1, #functions do local fn = functions[i] output:write(' msgpack_rpc_add_method_handler('.. @@ -360,32 +313,9 @@ for i = 1, #functions do '(MsgpackRpcRequestHandler) {.fn = handle_'.. (fn.impl_name or fn.name).. ', .async = '..tostring(fn.async)..'});\n') - if #fn.name > max_fname_len then - max_fname_len = #fn.name - end end output:write('\n}\n\n') - -output:write([[ -MsgpackRpcRequestHandler msgpack_rpc_get_handler_for(const char *name, - size_t name_len) -{ - String m = { - .data=(char *)name, - .size=MIN(name_len, ]]..max_fname_len..[[) - }; - MsgpackRpcRequestHandler rv = - map_get(String, MsgpackRpcRequestHandler)(methods, m); - - if (!rv.fn) { - rv.fn = msgpack_rpc_handle_missing_method; - } - - return rv; -} -]]) - output:close() mpack_output = io.open(mpack_outputf, 'wb') diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index cbea6a05c9..49edfda838 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -18,7 +18,8 @@ set(API_METADATA ${PROJECT_BINARY_DIR}/api_metadata.mpack) set(FUNCS_DATA ${PROJECT_BINARY_DIR}/funcs_data.mpack) set(HEADER_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/gendeclarations.lua) set(GENERATED_INCLUDES_DIR ${PROJECT_BINARY_DIR}/include) -set(GENERATED_API_DISPATCH ${GENERATED_DIR}/api/private/dispatch.c) +set(GENERATED_API_DISPATCH ${GENERATED_DIR}/api/private/dispatch_wrappers.generated.h) +set(GENERATED_FUNCS_METADATA ${GENERATED_DIR}/api/private/funcs_metadata.generated.h) set(GENERATED_EX_CMDS_ENUM ${GENERATED_INCLUDES_DIR}/ex_cmds_enum.generated.h) set(GENERATED_EX_CMDS_DEFS ${GENERATED_DIR}/ex_cmds_defs.generated.h) set(GENERATED_FUNCS_HASH_INPUT ${GENERATED_DIR}/funcs.generated.h.gperf) @@ -197,8 +198,11 @@ add_custom_command(OUTPUT ${GENERATED_UNICODE_TABLES} ${UNICODE_FILES} ) -add_custom_command(OUTPUT ${GENERATED_API_DISPATCH} ${API_METADATA} - COMMAND ${LUA_PRG} ${DISPATCH_GENERATOR} ${CMAKE_CURRENT_LIST_DIR} ${API_HEADERS} ${GENERATED_API_DISPATCH} ${API_METADATA} +add_custom_command(OUTPUT ${GENERATED_API_DISPATCH} ${GENERATED_FUNCS_METADATA} + ${API_METADATA} + COMMAND ${LUA_PRG} ${DISPATCH_GENERATOR} ${CMAKE_CURRENT_LIST_DIR} + ${API_HEADERS} ${GENERATED_API_DISPATCH} + ${GENERATED_FUNCS_METADATA} ${API_METADATA} DEPENDS ${API_HEADERS} ${MSGPACK_RPC_HEADERS} diff --git a/src/nvim/api/private/dispatch.c b/src/nvim/api/private/dispatch.c new file mode 100644 index 0000000000..9b3bcc380a --- /dev/null +++ b/src/nvim/api/private/dispatch.c @@ -0,0 +1,45 @@ +#include <inttypes.h> +#include <stdbool.h> +#include <stdint.h> +#include <assert.h> +#include <msgpack.h> + +#include "nvim/map.h" +#include "nvim/log.h" +#include "nvim/vim.h" +#include "nvim/msgpack_rpc/helpers.h" +#include "nvim/api/private/dispatch.h" +#include "nvim/api/private/helpers.h" +#include "nvim/api/private/defs.h" + +#include "nvim/api/buffer.h" +#include "nvim/api/tabpage.h" +#include "nvim/api/ui.h" +#include "nvim/api/vim.h" +#include "nvim/api/window.h" + +static Map(String, MsgpackRpcRequestHandler) *methods = NULL; + +static void msgpack_rpc_add_method_handler(String method, + MsgpackRpcRequestHandler handler) +{ + map_put(String, MsgpackRpcRequestHandler)(methods, method, handler); +} + +MsgpackRpcRequestHandler msgpack_rpc_get_handler_for(const char *name, + size_t name_len) +{ + String m = { .data = (char *)name, .size = name_len }; + MsgpackRpcRequestHandler rv = + map_get(String, MsgpackRpcRequestHandler)(methods, m); + + if (!rv.fn) { + rv.fn = msgpack_rpc_handle_missing_method; + } + + return rv; +} + +#ifdef INCLUDE_GENERATED_DECLARATIONS +#include "api/private/dispatch_wrappers.generated.h" +#endif diff --git a/src/nvim/api/private/dispatch.h b/src/nvim/api/private/dispatch.h index a4840c1e46..39aabd708a 100644 --- a/src/nvim/api/private/dispatch.h +++ b/src/nvim/api/private/dispatch.h @@ -17,6 +17,7 @@ typedef struct { #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/private/dispatch.h.generated.h" +# include "api/private/dispatch_wrappers.h.generated.h" #endif #endif // NVIM_API_PRIVATE_DISPATCH_H diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index d80ee7dc67..c0ee735d1a 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -7,6 +7,7 @@ #include "nvim/api/private/helpers.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/handle.h" +#include "nvim/msgpack_rpc/helpers.h" #include "nvim/ascii.h" #include "nvim/vim.h" #include "nvim/buffer.h" @@ -27,6 +28,7 @@ typedef struct { #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/private/helpers.c.generated.h" +# include "api/private/funcs_metadata.generated.h" #endif /// Start block that may cause vimscript exceptions @@ -761,7 +763,7 @@ Dictionary api_metadata(void) static Dictionary metadata = ARRAY_DICT_INIT; if (!metadata.size) { - msgpack_rpc_init_function_metadata(&metadata); + init_function_metadata(&metadata); init_error_type_metadata(&metadata); init_type_metadata(&metadata); } @@ -769,6 +771,22 @@ Dictionary api_metadata(void) return copy_object(DICTIONARY_OBJ(metadata)).data.dictionary; } +static void init_function_metadata(Dictionary *metadata) +{ + msgpack_unpacked unpacked; + msgpack_unpacked_init(&unpacked); + if (msgpack_unpack_next(&unpacked, + (const char *)funcs_metadata, + sizeof(funcs_metadata), + NULL) != MSGPACK_UNPACK_SUCCESS) { + abort(); + } + Object functions; + msgpack_rpc_to_object(&unpacked.data, &functions); + msgpack_unpacked_destroy(&unpacked); + PUT(*metadata, "functions", functions); +} + static void init_error_type_metadata(Dictionary *metadata) { Dictionary types = ARRAY_DICT_INIT; @@ -784,6 +802,7 @@ static void init_error_type_metadata(Dictionary *metadata) PUT(*metadata, "error_types", DICTIONARY_OBJ(types)); } + static void init_type_metadata(Dictionary *metadata) { Dictionary types = ARRAY_DICT_INIT; diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 4254697241..7444eb8a38 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -4396,6 +4396,7 @@ static HistoryType hist_char2type(const int c) case '>': { return HIST_DEBUG; } + case NUL: case '/': case '?': { return HIST_SEARCH; diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 008952fa97..3c821936e9 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -163,8 +163,12 @@ int os_nodetype(const char *name) // saves us the hassle. int nodetype = NODE_WRITABLE; - int fd = os_open(name, O_RDONLY, 0); - switch(uv_guess_handle(fd)) { + int fd = os_open(name, O_RDONLY +#ifdef O_NONBLOCK + | O_NONBLOCK +#endif + , 0); + switch (uv_guess_handle(fd)) { case UV_TTY: // FILE_TYPE_CHAR nodetype = NODE_WRITABLE; break; diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index 4d21887240..67e7c97905 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -34,6 +34,7 @@ NEW_TESTS = \ test_cscope.res \ test_hardcopy.res \ test_help_tagjump.res \ + test_history.res \ test_langmap.res \ test_syntax.res \ test_usercommands.res \ diff --git a/src/nvim/testdir/test_history.vim b/src/nvim/testdir/test_history.vim new file mode 100644 index 0000000000..ee6acfffc3 --- /dev/null +++ b/src/nvim/testdir/test_history.vim @@ -0,0 +1,65 @@ +" Tests for the history functions + +if !has('cmdline_hist') + finish +endif + +set history=7 + +function History_Tests(hist) + " First clear the history + call histadd(a:hist, 'dummy') + call assert_true(histdel(a:hist)) + call assert_equal(-1, histnr(a:hist)) + call assert_equal('', histget(a:hist)) + + call assert_true(histadd(a:hist, 'ls')) + call assert_true(histadd(a:hist, 'buffers')) + call assert_equal('buffers', histget(a:hist)) + call assert_equal('ls', histget(a:hist, -2)) + call assert_equal('ls', histget(a:hist, 1)) + call assert_equal('', histget(a:hist, 5)) + call assert_equal('', histget(a:hist, -5)) + call assert_equal(2, histnr(a:hist)) + call assert_true(histdel(a:hist, 2)) + call assert_false(histdel(a:hist, 7)) + call assert_equal(1, histnr(a:hist)) + call assert_equal('ls', histget(a:hist, -1)) + + call assert_true(histadd(a:hist, 'buffers')) + call assert_true(histadd(a:hist, 'ls')) + call assert_equal('ls', histget(a:hist, -1)) + call assert_equal(4, histnr(a:hist)) + + " Test for removing entries matching a pattern + for i in range(1, 3) + call histadd(a:hist, 'text_' . i) + endfor + call assert_true(histdel(a:hist, 'text_\d\+')) + call assert_equal('ls', histget(a:hist, -1)) + + " Test for freeing the entire history list + for i in range(1, 7) + call histadd(a:hist, 'text_' . i) + endfor + call histdel(a:hist) + for i in range(1, 7) + call assert_equal('', histget(a:hist, i)) + call assert_equal('', histget(a:hist, i - 7 - 1)) + endfor +endfunction + +function Test_History() + for h in ['cmd', ':', '', 'search', '/', '?', 'expr', '=', 'input', '@', 'debug', '>'] + call History_Tests(h) + endfor + + " Negative tests + call assert_false(histdel('abc')) + call assert_equal('', histget('abc')) + call assert_fails('call histdel([])', 'E730:') + call assert_equal('', histget(10)) + call assert_fails('call histget([])', 'E730:') + call assert_equal(-1, histnr('abc')) + call assert_fails('call histnr([])', 'E730:') +endfunction diff --git a/src/nvim/version.c b/src/nvim/version.c index 0bc55df585..b8dd2c2a47 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -739,7 +739,7 @@ static int included_patches[] = { // 1707, // 1706 NA // 1705 NA - // 1704, + 1704, 1703, // 1702, // 1701, @@ -855,7 +855,7 @@ static int included_patches[] = { // 1591, // 1590, // 1589, - // 1588, + 1588, // 1587 NA // 1586, // 1585, @@ -878,7 +878,7 @@ static int included_patches[] = { 1568, 1567, // 1566 NA - // 1565, + 1565, // 1564, // 1563, // 1562 NA @@ -949,7 +949,7 @@ static int included_patches[] = { // 1497 NA // 1496 NA // 1495 NA - // 1494, + 1494, // 1493 NA 1492, 1491, diff --git a/src/nvim/window.c b/src/nvim/window.c index 29c670322a..03a2e9a842 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -278,10 +278,11 @@ newwindow: /* cursor to last accessed (previous) window */ case 'p': case Ctrl_P: - if (prevwin == NULL) + if (!win_valid(prevwin)) { beep_flush(); - else + } else { win_goto(prevwin); + } break; /* exchange current and next window */ @@ -3768,8 +3769,15 @@ win_free ( hash_init(&wp->w_vars->dv_hashtab); unref_var_dict(wp->w_vars); - if (prevwin == wp) + if (prevwin == wp) { prevwin = NULL; + } + FOR_ALL_TABS(ttp) { + if (ttp->tp_prevwin == wp) { + ttp->tp_prevwin = NULL; + } + } + win_free_lsize(wp); for (i = 0; i < wp->w_tagstacklen; ++i) diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index adbe17d4b5..5872ebe8ee 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -121,14 +121,14 @@ describe('jobs', function() eq({'notification', 'exit', {0, 0}}, next_msg()) end) - it('can preserve newlines', function() + it('preserves newlines', function() nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)") nvim('command', 'call jobsend(j, "a\\n\\nc\\n\\n\\n\\nb\\n\\n")') eq({'notification', 'stdout', {0, {'a', '', 'c', '', '', '', 'b', '', ''}}}, next_msg()) end) - it('can preserve NULs', function() + it('preserves NULs', function() nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)") nvim('command', 'call jobsend(j, ["\n123\n", "abc\\nxyz\n", ""])') eq({'notification', 'stdout', {0, {'\n123\n', 'abc\nxyz\n', ''}}}, @@ -137,7 +137,7 @@ describe('jobs', function() eq({'notification', 'exit', {0, 0}}, next_msg()) end) - it('can avoid sending final newline', function() + it('avoids sending final newline', function() nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)") nvim('command', 'call jobsend(j, ["some data", "without\nfinal nl"])') eq({'notification', 'stdout', {0, {'some data', 'without\nfinal nl'}}}, @@ -146,7 +146,7 @@ describe('jobs', function() eq({'notification', 'exit', {0, 0}}, next_msg()) end) - it('can close the job streams with jobclose', function() + it('closes the job streams with jobclose', function() nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)") nvim('command', 'call jobclose(j, "stdin")') eq({'notification', 'exit', {0, 0}}, next_msg()) diff --git a/test/functional/ex_cmds/write_spec.lua b/test/functional/ex_cmds/write_spec.lua index c1bc5d3140..4ac9f312ef 100644 --- a/test/functional/ex_cmds/write_spec.lua +++ b/test/functional/ex_cmds/write_spec.lua @@ -1,20 +1,26 @@ --- Specs for :write - local helpers = require('test.functional.helpers')(after_each) -local eq, eval, clear, write_file, execute, source = - helpers.eq, helpers.eval, helpers.clear, helpers.write_file, - helpers.execute, helpers.source +local eq, eval, clear, write_file, execute, source, insert = + helpers.eq, helpers.eval, helpers.clear, helpers.write_file, + helpers.execute, helpers.source, helpers.insert if helpers.pending_win32(pending) then return end describe(':write', function() - after_each(function() + local function cleanup() os.remove('test_bkc_file.txt') os.remove('test_bkc_link.txt') + os.remove('test_fifo') + end + before_each(function() + clear() + cleanup() + end) + after_each(function() + cleanup() end) it('&backupcopy=auto preserves symlinks', function() - clear('--cmd', 'set backupcopy=auto') + execute('set backupcopy=auto') write_file('test_bkc_file.txt', 'content0') execute("silent !ln -s test_bkc_file.txt test_bkc_link.txt") source([[ @@ -27,7 +33,7 @@ describe(':write', function() end) it('&backupcopy=no replaces symlink with new file', function() - clear('--cmd', 'set backupcopy=no') + execute('set backupcopy=no') write_file('test_bkc_file.txt', 'content0') execute("silent !ln -s test_bkc_file.txt test_bkc_link.txt") source([[ @@ -38,4 +44,23 @@ describe(':write', function() eq(eval("['content0']"), eval("readfile('test_bkc_file.txt')")) eq(eval("['content1']"), eval("readfile('test_bkc_link.txt')")) end) + + it("appends FIFO file", function() + if eval("executable('mkfifo')") == 0 then + pending('missing "mkfifo" command', function()end) + return + end + + local text = "some fifo text from write_spec" + assert(os.execute("mkfifo test_fifo")) + insert(text) + + -- Blocks until a consumer reads the FIFO. + execute("write >> test_fifo") + + -- Read the FIFO, this will unblock the :write above. + local fifo = assert(io.open("test_fifo")) + eq(text.."\n", fifo:read("*all")) + fifo:close() + end) end) diff --git a/test/functional/legacy/assert_spec.lua b/test/functional/legacy/assert_spec.lua index 42dd25023a..8a042be7f7 100644 --- a/test/functional/legacy/assert_spec.lua +++ b/test/functional/legacy/assert_spec.lua @@ -2,6 +2,7 @@ local helpers = require('test.functional.helpers')(after_each) local nvim, call = helpers.meths, helpers.call local clear, eq = helpers.clear, helpers.eq local source, execute = helpers.source, helpers.execute +local exc_exec = helpers.exc_exec local function expected_errors(errors) eq(errors, nvim.get_vvar('errors')) @@ -62,6 +63,20 @@ describe('assert function:', function() call('assert_equal', 'true', 'false') expected_errors({"Expected 'true' but got 'false'"}) end) + + it('should change v:errors when expected is not equal to actual', function() + source([[ + function CheckAssert() + let s:v = {} + let s:x = {"a": s:v} + let s:v["b"] = s:x + let s:w = {"c": s:x, "d": ''} + call assert_equal(s:w, '') + endfunction + ]]) + eq('Vim(call):E724: unable to correctly dump variable with self-referencing container', + exc_exec('call CheckAssert()')) + end) end) -- assert_notequal({expected}, {actual}[, {msg}]) diff --git a/test/functional/legacy/quickfix_spec.lua b/test/functional/legacy/quickfix_spec.lua index df8f2625db..7657b8641b 100644 --- a/test/functional/legacy/quickfix_spec.lua +++ b/test/functional/legacy/quickfix_spec.lua @@ -277,6 +277,118 @@ describe('helpgrep', function() augroup! testgroup endfunction + + " This will test for problems in quickfix: + " A. incorrectly copying location lists which caused the location list to show + " a different name than the file that was actually being displayed. + " B. not reusing the window for which the location list window is opened but + " instead creating new windows. + " C. make sure that the location list window is not reused instead of the + " window it belongs to. + " + " Set up the test environment: + function! ReadTestProtocol(name) + let base = substitute(a:name, '\v^test://(.*)%(\.[^.]+)?', '\1', '') + let word = substitute(base, '\v(.*)\..*', '\1', '') + + setl modifiable + setl noreadonly + setl noswapfile + setl bufhidden=delete + %del _ + " For problem 2: + " 'buftype' has to be set to reproduce the constant opening of new windows + setl buftype=nofile + + call setline(1, word) + + setl nomodified + setl nomodifiable + setl readonly + exe 'doautocmd BufRead ' . substitute(a:name, '\v^test://(.*)', '\1', '') + endfunction + + function Test_locationlist() + enew + + augroup testgroup + au! + autocmd BufReadCmd test://* call ReadTestProtocol(expand("<amatch>")) + augroup END + + let words = [ "foo", "bar", "baz", "quux", "shmoo", "spam", "eggs" ] + + let qflist = [] + for word in words + call add(qflist, {'filename': 'test://' . word . '.txt', 'text': 'file ' . word . '.txt', }) + " NOTE: problem 1: + " intentionally not setting 'lnum' so that the quickfix entries are not + " valid + call setloclist(0, qflist, ' ') + endfor + + " Test A + lrewind + enew + lopen + lnext + lnext + lnext + lnext + vert split + wincmd L + lopen + wincmd p + lnext + let fileName = expand("%") + wincmd p + let locationListFileName = substitute(getline(line('.')), '\([^|]*\)|.*', '\1', '') + let fileName = substitute(fileName, '\\', '/', 'g') + let locationListFileName = substitute(locationListFileName, '\\', '/', 'g') + call assert_equal("test://bar.txt", fileName) + call assert_equal("test://bar.txt", locationListFileName) + + wincmd n | only + + " Test B: + lrewind + lopen + 2 + exe "normal \<CR>" + wincmd p + 3 + exe "normal \<CR>" + wincmd p + 4 + exe "normal \<CR>" + call assert_equal(2, winnr('$')) + wincmd n | only + + " Test C: + lrewind + lopen + " Let's move the location list window to the top to check whether it (the + " first window found) will be reused when we try to open new windows: + wincmd K + 2 + exe "normal \<CR>" + wincmd p + 3 + exe "normal \<CR>" + wincmd p + 4 + exe "normal \<CR>" + 1wincmd w + call assert_equal('quickfix', &buftype) + 2wincmd w + let bufferName = expand("%") + let bufferName = substitute(bufferName, '\\', '/', 'g') + call assert_equal('test://quux.txt', bufferName) + + wincmd n | only + + augroup! testgroup + endfunction ]]) end) @@ -339,4 +451,9 @@ describe('helpgrep', function() call('Test_locationlist_curwin_was_closed') expected_empty() end) + + it('checks locationlist protocol read', function() + call('Test_locationlist') + expected_empty() + end) end) diff --git a/test/functional/terminal/api_spec.lua b/test/functional/terminal/api_spec.lua index 58d6c75940..045bdb0749 100644 --- a/test/functional/terminal/api_spec.lua +++ b/test/functional/terminal/api_spec.lua @@ -22,7 +22,7 @@ describe('api', function() -- Start the socket from the child nvim. child_session.feed_data(":echo serverstart('"..socket_name.."')\n") - -- Wait for socket creation by abusing expect(). + -- Wait for socket creation. screen:expect([[ {1: } | {4:~ }| @@ -37,6 +37,16 @@ describe('api', function() local socket_session2 = helpers.connect(socket_name) child_session.feed_data("i[tui] insert-mode") + -- Wait for stdin to be processed. + screen:expect([[ + [tui] insert-mode{1: } | + {4:~ }| + {4:~ }| + {4:~ }| + {5:[No Name] [+] }| + {3:-- INSERT --} | + {3:-- TERMINAL --} | + ]]) ok(socket_session1:request("nvim_ui_attach", 42, 6, {rgb=true})) ok(socket_session2:request("nvim_ui_attach", 25, 30, {rgb=true})) diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua index 09b4eaa8d5..4247be0417 100644 --- a/test/functional/terminal/ex_terminal_spec.lua +++ b/test/functional/terminal/ex_terminal_spec.lua @@ -13,6 +13,42 @@ describe(':terminal', function() clear() screen = Screen.new(50, 4) screen:attach({rgb=false}) + end) + + it("does not interrupt Press-ENTER prompt #2748", function() + -- Ensure that :messages shows Press-ENTER. + source([[ + echomsg "msg1" + echomsg "msg2" + ]]) + -- Invoke a command that emits frequent terminal activity. + execute([[terminal while true; do echo X; done]]) + helpers.feed([[<C-\><C-N>]]) + screen:expect([[ + X | + X | + ^X | + | + ]]) + helpers.sleep(10) -- Let some terminal activity happen. + execute("messages") + screen:expect([[ + X | + msg1 | + msg2 | + Press ENTER or type command to continue^ | + ]]) + end) + +end) + +describe(':terminal (with fake shell)', function() + local screen + + before_each(function() + clear() + screen = Screen.new(50, 4) + screen:attach({rgb=false}) -- shell-test.c is a fake shell that prints its arguments and exits. nvim('set_option', 'shell', nvim_dir..'/shell-test') nvim('set_option', 'shellcmdflag', 'EXE') @@ -20,12 +56,12 @@ describe(':terminal', function() -- Invokes `:terminal {cmd}` using a fake shell (shell-test.c) which prints -- the {cmd} and exits immediately . - local function terminal_run_fake_shell_cmd(cmd) + local function terminal_with_fake_shell(cmd) execute("terminal "..(cmd and cmd or "")) end it('with no argument, acts like termopen()', function() - terminal_run_fake_shell_cmd() + terminal_with_fake_shell() wait() screen:expect([[ ready $ | @@ -36,7 +72,7 @@ describe(':terminal', function() end) it('executes a given command through the shell', function() - terminal_run_fake_shell_cmd('echo hi') + terminal_with_fake_shell('echo hi') wait() screen:expect([[ ready $ echo hi | @@ -47,7 +83,7 @@ describe(':terminal', function() end) it('allows quotes and slashes', function() - terminal_run_fake_shell_cmd([[echo 'hello' \ "world"]]) + terminal_with_fake_shell([[echo 'hello' \ "world"]]) wait() screen:expect([[ ready $ echo 'hello' \ "world" | @@ -66,14 +102,14 @@ describe(':terminal', function() end) it('ignores writes if the backing stream closes', function() - terminal_run_fake_shell_cmd() + terminal_with_fake_shell() helpers.feed('iiXXXXXXX') wait() -- Race: Though the shell exited (and streams were closed by SIGCHLD -- handler), :terminal cleanup is pending on the main-loop. -- This write should be ignored (not crash, #5445). helpers.feed('iiYYYYYYY') - wait() + eq(2, eval("1+1")) -- Still alive? end) end) |