diff options
Diffstat (limited to 'test')
69 files changed, 3470 insertions, 789 deletions
diff --git a/test/README.md b/test/README.md index d3f421e8fc..c87f835f79 100644 --- a/test/README.md +++ b/test/README.md @@ -88,10 +88,25 @@ To run a *single* legacy test set `TEST_FILE`, for example: Debugging tests --------------- -You can set `$GDB` to [run tests under gdbserver](https://github.com/neovim/neovim/pull/1527). -And if `$VALGRIND` is set it will pass `--vgdb=yes` to valgrind instead of -starting gdbserver directly. - +- You can set `$GDB` to [run tests under gdbserver](https://github.com/neovim/neovim/pull/1527). + And if `$VALGRIND` is set it will pass `--vgdb=yes` to valgrind instead of + starting gdbserver directly. +- Hanging tests often happen due to unexpected `:h press-enter` prompts. The + default screen width is 50 columns. Commands that try to print lines longer + than 50 columns in the command-line, e.g. `:edit very...long...path`, will + trigger the prompt. In this case, a shorter path or `:silent edit` should be + used. +- If you can't figure out what is going on, try to visualize the screen. Put + this at the beginning of your test: + + ```lua + local Screen = require('test.functional.ui.screen') + local screen = Screen.new() + screen:attach() + ``` + + Afterwards, put `screen:snapshot_util()` at any position in your test. See the + comment at the top of `test/functional/ui/screen.lua` for more. Filtering Tests --------------- diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index 93599c04f1..9d6cfb99ab 100644 --- a/test/functional/api/buffer_spec.lua +++ b/test/functional/api/buffer_spec.lua @@ -24,8 +24,8 @@ describe('api/buf', function() end - describe('line_count, insert and del_line', function() - it('works', function() + describe('nvim_buf_set_lines, nvim_buf_line_count', function() + it('deprecated forms', function() eq(1, curbuf_depr('line_count')) curbuf_depr('insert', -1, {'line'}) eq(2, curbuf_depr('line_count')) @@ -39,6 +39,41 @@ describe('api/buf', function() eq(1, curbuf_depr('line_count')) end) + it('cursor position is maintained after lines are inserted #9961', function() + -- replace the buffer contents with these three lines. + request('nvim_buf_set_lines', 0, 0, -1, 1, {"line1", "line2", "line3", "line4"}) + -- Set the current cursor to {3, 2}. + curwin('set_cursor', {3, 2}) + + -- add 2 lines and delete 1 line above the current cursor position. + request('nvim_buf_set_lines', 0, 1, 2, 1, {"line5", "line6"}) + -- check the current set of lines in the buffer. + eq({"line1", "line5", "line6", "line3", "line4"}, buffer('get_lines', 0, 0, -1, 1)) + -- cursor should be moved below by 1 line. + eq({4, 2}, curwin('get_cursor')) + + -- add a line after the current cursor position. + request('nvim_buf_set_lines', 0, 5, 5, 1, {"line7"}) + -- check the current set of lines in the buffer. + eq({"line1", "line5", "line6", "line3", "line4", "line7"}, buffer('get_lines', 0, 0, -1, 1)) + -- cursor position is unchanged. + eq({4, 2}, curwin('get_cursor')) + + -- overwrite current cursor line. + request('nvim_buf_set_lines', 0, 3, 5, 1, {"line8", "line9"}) + -- check the current set of lines in the buffer. + eq({"line1", "line5", "line6", "line8", "line9", "line7"}, buffer('get_lines', 0, 0, -1, 1)) + -- cursor position is unchanged. + eq({4, 2}, curwin('get_cursor')) + + -- delete current cursor line. + request('nvim_buf_set_lines', 0, 3, 5, 1, {}) + -- check the current set of lines in the buffer. + eq({"line1", "line5", "line6", "line7"}, buffer('get_lines', 0, 0, -1, 1)) + -- cursor position is unchanged. + eq({4, 2}, curwin('get_cursor')) + end) + it('line_count has defined behaviour for unloaded buffers', function() -- we'll need to know our bufnr for when it gets unloaded local bufnr = curbuf('get_number') @@ -70,7 +105,7 @@ describe('api/buf', function() end) end) - describe('{get,set,del}_line', function() + describe('deprecated: {get,set,del}_line', function() it('works', function() eq('', curbuf_depr('get_line', 0)) curbuf_depr('set_line', 0, 'line1') @@ -102,7 +137,7 @@ describe('api/buf', function() end) end) - describe('{get,set}_line_slice', function() + describe('deprecated: {get,set}_line_slice', function() it('get_line_slice: out-of-bounds returns empty array', function() curbuf_depr('set_line_slice', 0, 0, true, true, {'a', 'b', 'c'}) eq({'a', 'b', 'c'}, curbuf_depr('get_line_slice', 0, 2, true, true)) --sanity @@ -149,7 +184,7 @@ describe('api/buf', function() end) end) - describe('{get,set}_lines', function() + describe('nvim_buf_get_lines, nvim_buf_set_lines', function() local get_lines, set_lines = curbufmeths.get_lines, curbufmeths.set_lines local line_count = curbufmeths.line_count @@ -272,7 +307,7 @@ describe('api/buf', function() eq({}, get_lines(-3, -4, true)) end) - it('set_line_slice: out-of-bounds can extend past end', function() + it('set_lines: out-of-bounds can extend past end', function() set_lines(0, -1, true, {'a', 'b', 'c'}) eq({'a', 'b', 'c'}, get_lines(0, -1, true)) --sanity @@ -286,7 +321,7 @@ describe('api/buf', function() eq({'e', 'a', 'b', 'c', 'd'}, get_lines(0, -1, true)) end) - it("set_line on alternate buffer does not access invalid line (E315)", function() + it("set_lines on alternate buffer does not access invalid line (E315)", function() feed_command('set hidden') insert('Initial file') command('enew') @@ -334,9 +369,27 @@ describe('api/buf', function() {2:-- INSERT --} | ]]) end) + + it('set_lines on hidden buffer preserves "previous window" #9741', function() + insert([[ + visible buffer line 1 + line 2 + ]]) + local hiddenbuf = meths.create_buf(false,true) + command('vsplit') + command('vsplit') + feed('<c-w>l<c-w>l<c-w>l') + eq(3, funcs.winnr()) + feed('<c-w>h') + eq(2, funcs.winnr()) + meths.buf_set_lines(hiddenbuf, 0, -1, true, + {'hidden buffer line 1', 'line 2'}) + feed('<c-w>p') + eq(3, funcs.winnr()) + end) end) - describe('get_offset', function() + describe('nvim_buf_get_offset', function() local get_offset = curbufmeths.get_offset it('works', function() curbufmeths.set_lines(0,-1,true,{'Some\r','exa\000mple', '', 'buf\rfer', 'text'}) @@ -373,7 +426,7 @@ describe('api/buf', function() end) end) - describe('{get,set,del}_var', function() + describe('nvim_buf_get_var, nvim_buf_set_var, nvim_buf_del_var', function() it('works', function() curbuf('set_var', 'lua', {1, 2, {['3'] = 1}}) eq({1, 2, {['3'] = 1}}, curbuf('get_var', 'lua')) @@ -393,7 +446,7 @@ describe('api/buf', function() end) end) - describe('get_changedtick', function() + describe('nvim_buf_get_changedtick', function() it('works', function() eq(2, curbufmeths.get_changedtick()) curbufmeths.set_lines(0, 1, false, {'abc\0', '\0def', 'ghi'}) @@ -417,7 +470,7 @@ describe('api/buf', function() end) end) - describe('{get,set}_option', function() + describe('nvim_buf_get_option, nvim_buf_set_option', function() it('works', function() eq(8, curbuf('get_option', 'shiftwidth')) curbuf('set_option', 'shiftwidth', 4) @@ -430,7 +483,7 @@ describe('api/buf', function() end) end) - describe('{get,set}_name', function() + describe('nvim_buf_get_name, nvim_buf_set_name', function() it('works', function() nvim('command', 'new') eq('', curbuf('get_name')) @@ -438,14 +491,12 @@ describe('api/buf', function() curbuf('set_name', new_name) eq(new_name, curbuf('get_name')) nvim('command', 'w!') - local f = io.open(new_name) - ok(f ~= nil) - f:close() + eq(1, funcs.filereadable(new_name)) os.remove(new_name) end) end) - describe('is_loaded', function() + describe('nvim_buf_is_loaded', function() it('works', function() -- record our buffer number for when we unload it local bufnr = curbuf('get_number') @@ -470,7 +521,7 @@ describe('api/buf', function() end) end) - describe('is_valid', function() + describe('nvim_buf_is_valid', function() it('works', function() nvim('command', 'new') local b = nvim('get_current_buf') @@ -480,12 +531,12 @@ describe('api/buf', function() end) end) - describe('get_mark', function() + describe('nvim_buf_get_mark', function() it('works', function() curbuf('set_lines', -1, -1, true, {'a', 'bit of', 'text'}) curwin('set_cursor', {3, 4}) - nvim('command', 'mark V') - eq({3, 0}, curbuf('get_mark', 'V')) + nvim('command', 'mark v') + eq({3, 0}, curbuf('get_mark', 'v')) end) end) end) diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua index f52372bee3..b3f6bb7895 100644 --- a/test/functional/api/keymap_spec.lua +++ b/test/functional/api/keymap_spec.lua @@ -1,15 +1,18 @@ local helpers = require('test.functional.helpers')(after_each) -local global_helpers = require('test.helpers') +local bufmeths = helpers.bufmeths local clear = helpers.clear local command = helpers.command local curbufmeths = helpers.curbufmeths -local eq = helpers.eq +local eq, neq = helpers.eq, helpers.neq +local expect_err = helpers.expect_err +local feed = helpers.feed local funcs = helpers.funcs local meths = helpers.meths local source = helpers.source -local shallowcopy = global_helpers.shallowcopy +local shallowcopy = helpers.shallowcopy +local sleep = helpers.sleep describe('nvim_get_keymap', function() before_each(clear) @@ -308,3 +311,502 @@ describe('nvim_get_keymap', function() eq({space_table}, meths.get_keymap('n')) end) end) + +describe('nvim_set_keymap, nvim_del_keymap', function() + before_each(clear) + + -- `generate_expected` is truthy: for generating an expected output for + -- maparg(), which does not accept "!" (though it returns "!" in its output + -- if getting a mapping set with |:map!|). + local function normalize_mapmode(mode, generate_expected) + if not generate_expected and mode == '!' then + -- Cannot retrieve mapmode-ic mappings with "!", but can with "i" or "c". + mode = 'i' + elseif mode == '' then + mode = generate_expected and ' ' or mode + end + return mode + end + + -- Generate a mapargs dict, for comparison against the mapping that was + -- actually set + local function generate_mapargs(mode, lhs, rhs, opts) + if not opts then + opts = {} + end + + local to_return = {} + to_return.mode = normalize_mapmode(mode, true) + to_return.noremap = not opts.noremap and 0 or 1 + to_return.lhs = lhs + to_return.rhs = rhs + to_return.silent = not opts.silent and 0 or 1 + to_return.nowait = not opts.nowait and 0 or 1 + to_return.expr = not opts.expr and 0 or 1 + to_return.sid = not opts.sid and 0 or opts.sid + to_return.buffer = not opts.buffer and 0 or opts.buffer + + -- mode 't' doesn't print when calling maparg + if mode == 't' then + to_return.mode = '' + end + + return to_return + end + + -- Gets a maparg() dict from Nvim, if one exists. + local function get_mapargs(mode, lhs) + return funcs.maparg(lhs, normalize_mapmode(mode), false, true) + end + + it('error on empty LHS', function() + -- escape parentheses in lua string, else comparison fails erroneously + expect_err('Invalid %(empty%) LHS', + meths.set_keymap, '', '', 'rhs', {}) + expect_err('Invalid %(empty%) LHS', + meths.set_keymap, '', '', '', {}) + + expect_err('Invalid %(empty%) LHS', meths.del_keymap, '', '') + end) + + it('error if LHS longer than MAXMAPLEN', function() + -- assume MAXMAPLEN of 50 chars, as declared in vim.h + local MAXMAPLEN = 50 + local lhs = '' + for i=1,MAXMAPLEN do + lhs = lhs..(i % 10) + end + + -- exactly 50 chars should be fine + meths.set_keymap('', lhs, 'rhs', {}) + + -- del_keymap should unmap successfully + meths.del_keymap('', lhs) + eq({}, get_mapargs('', lhs)) + + -- 51 chars should produce an error + lhs = lhs..'1' + expect_err('LHS exceeds maximum map length: '..lhs, + meths.set_keymap, '', lhs, 'rhs', {}) + expect_err('LHS exceeds maximum map length: '..lhs, + meths.del_keymap, '', lhs) + end) + + it('does not throw errors when rhs is longer than MAXMAPLEN', function() + local MAXMAPLEN = 50 + local rhs = '' + for i=1,MAXMAPLEN do + rhs = rhs..(i % 10) + end + rhs = rhs..'1' + meths.set_keymap('', 'lhs', rhs, {}) + eq(generate_mapargs('', 'lhs', rhs), + get_mapargs('', 'lhs')) + end) + + it('throws errors when given too-long mode shortnames', function() + expect_err('Shortname is too long: map', + meths.set_keymap, 'map', 'lhs', 'rhs', {}) + + expect_err('Shortname is too long: vmap', + meths.set_keymap, 'vmap', 'lhs', 'rhs', {}) + + expect_err('Shortname is too long: xnoremap', + meths.set_keymap, 'xnoremap', 'lhs', 'rhs', {}) + + expect_err('Shortname is too long: map', meths.del_keymap, 'map', 'lhs') + expect_err('Shortname is too long: vmap', meths.del_keymap, 'vmap', 'lhs') + expect_err('Shortname is too long: xnoremap', meths.del_keymap, 'xnoremap', 'lhs') + end) + + it('error on invalid mode shortname', function() + expect_err('Invalid mode shortname: " "', + meths.set_keymap, ' ', 'lhs', 'rhs', {}) + expect_err('Invalid mode shortname: "m"', + meths.set_keymap, 'm', 'lhs', 'rhs', {}) + expect_err('Invalid mode shortname: "?"', + meths.set_keymap, '?', 'lhs', 'rhs', {}) + expect_err('Invalid mode shortname: "y"', + meths.set_keymap, 'y', 'lhs', 'rhs', {}) + expect_err('Invalid mode shortname: "p"', + meths.set_keymap, 'p', 'lhs', 'rhs', {}) + expect_err('Invalid mode shortname: "?"', meths.del_keymap, '?', 'lhs') + expect_err('Invalid mode shortname: "y"', meths.del_keymap, 'y', 'lhs') + expect_err('Invalid mode shortname: "p"', meths.del_keymap, 'p', 'lhs') + end) + + it('error on invalid optnames', function() + expect_err('Invalid key: silentt', + meths.set_keymap, 'n', 'lhs', 'rhs', {silentt = true}) + expect_err('Invalid key: sidd', + meths.set_keymap, 'n', 'lhs', 'rhs', {sidd = false}) + expect_err('Invalid key: nowaiT', + meths.set_keymap, 'n', 'lhs', 'rhs', {nowaiT = false}) + end) + + it('error on <buffer> option key', function() + expect_err('Invalid key: buffer', + meths.set_keymap, 'n', 'lhs', 'rhs', {buffer = true}) + end) + + local optnames = {'nowait', 'silent', 'script', 'expr', 'unique'} + for _, opt in ipairs(optnames) do + -- note: need '%' to escape hyphens, which have special meaning in lua + it('throws an error when given non-boolean value for '..opt, function() + local opts = {} + opts[opt] = 2 + expect_err('Gave non%-boolean value for an opt: '..opt, + meths.set_keymap, 'n', 'lhs', 'rhs', opts) + end) + end + + -- Perform tests of basic functionality + it('sets ordinary mappings', function() + meths.set_keymap('n', 'lhs', 'rhs', {}) + eq(generate_mapargs('n', 'lhs', 'rhs'), get_mapargs('n', 'lhs')) + + meths.set_keymap('v', 'lhs', 'rhs', {}) + eq(generate_mapargs('v', 'lhs', 'rhs'), get_mapargs('v', 'lhs')) + end) + + it('does not throw when LHS or RHS have leading/trailing whitespace', function() + meths.set_keymap('n', ' lhs', 'rhs', {}) + eq(generate_mapargs('n', '<Space><Space><Space>lhs', 'rhs'), + get_mapargs('n', ' lhs')) + + meths.set_keymap('n', 'lhs ', 'rhs', {}) + eq(generate_mapargs('n', 'lhs<Space><Space><Space><Space>', 'rhs'), + get_mapargs('n', 'lhs ')) + + meths.set_keymap('v', ' lhs ', '\trhs\t\f', {}) + eq(generate_mapargs('v', '<Space>lhs<Space><Space>', '\trhs\t\f'), + get_mapargs('v', ' lhs ')) + end) + + it('can set noremap mappings', function() + meths.set_keymap('x', 'lhs', 'rhs', {noremap = true}) + eq(generate_mapargs('x', 'lhs', 'rhs', {noremap = true}), + get_mapargs('x', 'lhs')) + + meths.set_keymap('t', 'lhs', 'rhs', {noremap = true}) + eq(generate_mapargs('t', 'lhs', 'rhs', {noremap = true}), + get_mapargs('t', 'lhs')) + end) + + it('can unmap mappings', function() + meths.set_keymap('v', 'lhs', 'rhs', {}) + meths.del_keymap('v', 'lhs') + eq({}, get_mapargs('v', 'lhs')) + + meths.set_keymap('t', 'lhs', 'rhs', {noremap = true}) + meths.del_keymap('t', 'lhs') + eq({}, get_mapargs('t', 'lhs')) + end) + + -- Test some edge cases + it('"!" and empty string are synonyms for mapmode-nvo', function() + local nvo_shortnames = {'', '!'} + for _, name in ipairs(nvo_shortnames) do + meths.set_keymap(name, 'lhs', 'rhs', {}) + meths.del_keymap(name, 'lhs') + eq({}, get_mapargs(name, 'lhs')) + end + end) + + local special_chars = {'<C-U>', '<S-Left>', '<F12><F2><Tab>', '<Space><Tab>'} + for _, lhs in ipairs(special_chars) do + for _, rhs in ipairs(special_chars) do + local mapmode = '!' + it('can set mappings with special characters, lhs: '..lhs..', rhs: '..rhs, + function() + meths.set_keymap(mapmode, lhs, rhs, {}) + eq(generate_mapargs(mapmode, lhs, rhs), get_mapargs(mapmode, lhs)) + end) + end + end + + it('can set mappings containing literal keycodes', function() + meths.set_keymap('n', '\n\r\n', 'rhs', {}) + local expected = generate_mapargs('n', '<NL><CR><NL>', 'rhs') + eq(expected, get_mapargs('n', '<C-j><CR><C-j>')) + end) + + it('can set mappings whose RHS is a <Nop>', function() + meths.set_keymap('i', 'lhs', '<Nop>', {}) + command('normal ilhs') + eq({''}, curbufmeths.get_lines(0, -1, 0)) -- imap to <Nop> does nothing + eq(generate_mapargs('i', 'lhs', '<Nop>', {}), + get_mapargs('i', 'lhs')) + + -- also test for case insensitivity + meths.set_keymap('i', 'lhs', '<nOp>', {}) + command('normal ilhs') + eq({''}, curbufmeths.get_lines(0, -1, 0)) + -- note: RHS in returned mapargs() dict reflects the original RHS + -- provided by the user + eq(generate_mapargs('i', 'lhs', '<nOp>', {}), + get_mapargs('i', 'lhs')) + + meths.set_keymap('i', 'lhs', '<NOP>', {}) + command('normal ilhs') + eq({''}, curbufmeths.get_lines(0, -1, 0)) + eq(generate_mapargs('i', 'lhs', '<NOP>', {}), + get_mapargs('i', 'lhs')) + end) + + it('treats an empty RHS in a mapping like a <Nop>', function() + meths.set_keymap('i', 'lhs', '', {}) + command('normal ilhs') + eq({''}, curbufmeths.get_lines(0, -1, 0)) + eq(generate_mapargs('i', 'lhs', '', {}), + get_mapargs('i', 'lhs')) + end) + + it('can set and unset <M-">', function() + -- Taken from the legacy test: test_mapping.vim. Exposes a bug in which + -- replace_termcodes changes the length of the mapping's LHS, but + -- do_map continues to use the *old* length of LHS. + meths.set_keymap('i', '<M-">', 'foo', {}) + meths.del_keymap('i', '<M-">') + eq({}, get_mapargs('i', '<M-">')) + end) + + it('interprets control sequences in expr-quotes correctly when called ' + ..'inside vim', function() + command([[call nvim_set_keymap('i', "\<space>", "\<tab>", {})]]) + eq(generate_mapargs('i', '<Space>', '\t', {}), + get_mapargs('i', '<Space>')) + feed('i ') + eq({'\t'}, curbufmeths.get_lines(0, -1, 0)) + end) + + it('throws appropriate error messages when setting <unique> maps', function() + meths.set_keymap('l', 'lhs', 'rhs', {}) + expect_err('E227: mapping already exists for lhs', + meths.set_keymap, 'l', 'lhs', 'rhs', {unique = true}) + -- different mapmode, no error should be thrown + meths.set_keymap('t', 'lhs', 'rhs', {unique = true}) + end) + + it('can set <expr> mappings whose RHS change dynamically', function() + meths.command_output([[ + function! FlipFlop() abort + if !exists('g:flip') | let g:flip = 0 | endif + let g:flip = !g:flip + return g:flip + endfunction + ]]) + eq(1, meths.call_function('FlipFlop', {})) + eq(0, meths.call_function('FlipFlop', {})) + eq(1, meths.call_function('FlipFlop', {})) + eq(0, meths.call_function('FlipFlop', {})) + + meths.set_keymap('i', 'lhs', 'FlipFlop()', {expr = true}) + command('normal ilhs') + eq({'1'}, curbufmeths.get_lines(0, -1, 0)) + + command('normal! ggVGd') + + command('normal ilhs') + eq({'0'}, curbufmeths.get_lines(0, -1, 0)) + end) + + it('can set mappings that do trigger other mappings', function() + meths.set_keymap('i', 'mhs', 'rhs', {}) + meths.set_keymap('i', 'lhs', 'mhs', {}) + + command('normal imhs') + eq({'rhs'}, curbufmeths.get_lines(0, -1, 0)) + + command('normal! ggVGd') + + command('normal ilhs') + eq({'rhs'}, curbufmeths.get_lines(0, -1, 0)) + end) + + it("can set noremap mappings that don't trigger other mappings", function() + meths.set_keymap('i', 'mhs', 'rhs', {}) + meths.set_keymap('i', 'lhs', 'mhs', {noremap = true}) + + command('normal imhs') + eq({'rhs'}, curbufmeths.get_lines(0, -1, 0)) + + command('normal! ggVGd') + + command('normal ilhs') -- shouldn't trigger mhs-to-rhs mapping + eq({'mhs'}, curbufmeths.get_lines(0, -1, 0)) + end) + + it("can set nowait mappings that fire without waiting", function() + meths.set_keymap('i', '123456', 'longer', {}) + meths.set_keymap('i', '123', 'shorter', {nowait = true}) + + -- feed keys one at a time; if all keys arrive atomically, the longer + -- mapping will trigger + local keys = 'i123456' + for c in string.gmatch(keys, '.') do + feed(c) + sleep(5) + end + eq({'shorter456'}, curbufmeths.get_lines(0, -1, 0)) + end) + + -- Perform exhaustive tests of basic functionality + local mapmodes = {'n', 'v', 'x', 's', 'o', '!', 'i', 'l', 'c', 't', ''} + for _, mapmode in ipairs(mapmodes) do + it('can set/unset normal mappings in mapmode '..mapmode, function() + meths.set_keymap(mapmode, 'lhs', 'rhs', {}) + eq(generate_mapargs(mapmode, 'lhs', 'rhs'), + get_mapargs(mapmode, 'lhs')) + + -- some mapmodes (like 'o') will prevent other mapmodes (like '!') from + -- taking effect, so unmap after each mapping + meths.del_keymap(mapmode, 'lhs') + eq({}, get_mapargs(mapmode, 'lhs')) + end) + end + + for _, mapmode in ipairs(mapmodes) do + it('can set/unset noremap mappings using mapmode '..mapmode, function() + meths.set_keymap(mapmode, 'lhs', 'rhs', {noremap = true}) + eq(generate_mapargs(mapmode, 'lhs', 'rhs', {noremap = true}), + get_mapargs(mapmode, 'lhs')) + + meths.del_keymap(mapmode, 'lhs') + eq({}, get_mapargs(mapmode, 'lhs')) + end) + end + + -- Test map-arguments, using optnames from above + -- remove some map arguments that are harder to test, or were already tested + optnames = {'nowait', 'silent', 'expr', 'noremap'} + for _, mapmode in ipairs(mapmodes) do + local printable_mode = normalize_mapmode(mapmode) + + -- Test with single mappings + for _, maparg in ipairs(optnames) do + it('can set/unset '..printable_mode..'-mappings with maparg: '..maparg, + function() + meths.set_keymap(mapmode, 'lhs', 'rhs', {[maparg] = true}) + eq(generate_mapargs(mapmode, 'lhs', 'rhs', {[maparg] = true}), + get_mapargs(mapmode, 'lhs')) + meths.del_keymap(mapmode, 'lhs') + eq({}, get_mapargs(mapmode, 'lhs')) + end) + it ('can set/unset '..printable_mode..'-mode mappings with maparg '.. + maparg..', whose value is false', function() + meths.set_keymap(mapmode, 'lhs', 'rhs', {[maparg] = false}) + eq(generate_mapargs(mapmode, 'lhs', 'rhs'), + get_mapargs(mapmode, 'lhs')) + meths.del_keymap(mapmode, 'lhs') + eq({}, get_mapargs(mapmode, 'lhs')) + end) + end + + -- Test with triplets of mappings, one of which is false + for i = 1, (#optnames - 2) do + local opt1, opt2, opt3 = optnames[i], optnames[i + 1], optnames[i + 2] + it('can set/unset '..printable_mode..'-mode mappings with mapargs '.. + opt1..', '..opt2..', '..opt3, function() + local opts = {[opt1] = true, [opt2] = false, [opt3] = true} + meths.set_keymap(mapmode, 'lhs', 'rhs', opts) + eq(generate_mapargs(mapmode, 'lhs', 'rhs', opts), + get_mapargs(mapmode, 'lhs')) + meths.del_keymap(mapmode, 'lhs') + eq({}, get_mapargs(mapmode, 'lhs')) + end) + end + end +end) + +describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() + before_each(clear) + + -- nvim_set_keymap is implemented as a wrapped call to nvim_buf_set_keymap, + -- so its tests also effectively test nvim_buf_set_keymap + + -- here, we mainly test for buffer specificity and other special cases + + -- switch to the given buffer, abandoning any changes in the current buffer + local function switch_to_buf(bufnr) + command(bufnr..'buffer!') + end + + -- `set hidden`, then create two buffers and return their bufnr's + -- If start_from_first is truthy, the first buffer will be open when + -- the function returns; if falsy, the second buffer will be open. + local function make_two_buffers(start_from_first) + command('set hidden') + + local first_buf = meths.call_function('bufnr', {'%'}) + command('new') + local second_buf = meths.call_function('bufnr', {'%'}) + neq(second_buf, first_buf) -- sanity check + + if start_from_first then + switch_to_buf(first_buf) + end + + return first_buf, second_buf + end + + it('rejects negative bufnr values', function() + expect_err('Wrong type for argument 1, expecting Buffer', + bufmeths.set_keymap, -1, '', 'lhs', 'rhs', {}) + end) + + it('can set mappings active in the current buffer but not others', function() + local first, second = make_two_buffers(true) + + bufmeths.set_keymap(0, '', 'lhs', 'irhs<Esc>', {}) + command('normal lhs') + eq({'rhs'}, bufmeths.get_lines(0, 0, 1, 1)) + + -- mapping should have no effect in new buffer + switch_to_buf(second) + command('normal lhs') + eq({''}, bufmeths.get_lines(0, 0, 1, 1)) + + -- mapping should remain active in old buffer + switch_to_buf(first) + command('normal ^lhs') + eq({'rhsrhs'}, bufmeths.get_lines(0, 0, 1, 1)) + end) + + it('can set local mappings in buffer other than current', function() + local first = make_two_buffers(false) + bufmeths.set_keymap(first, '', 'lhs', 'irhs<Esc>', {}) + + -- shouldn't do anything + command('normal lhs') + eq({''}, bufmeths.get_lines(0, 0, 1, 1)) + + -- should take effect + switch_to_buf(first) + command('normal lhs') + eq({'rhs'}, bufmeths.get_lines(0, 0, 1, 1)) + end) + + it('can disable mappings made in another buffer, inside that buffer', function() + local first = make_two_buffers(false) + bufmeths.set_keymap(first, '', 'lhs', 'irhs<Esc>', {}) + bufmeths.del_keymap(first, '', 'lhs') + switch_to_buf(first) + + -- shouldn't do anything + command('normal lhs') + eq({''}, bufmeths.get_lines(0, 0, 1, 1)) + end) + + it("can't disable mappings given wrong buffer handle", function() + local first, second = make_two_buffers(false) + bufmeths.set_keymap(first, '', 'lhs', 'irhs<Esc>', {}) + expect_err('E31: No such mapping', + bufmeths.del_keymap, second, '', 'lhs') + + -- should still work + switch_to_buf(first) + command('normal lhs') + eq({'rhs'}, bufmeths.get_lines(0, 0, 1, 1)) + end) +end) diff --git a/test/functional/api/rpc_fixture.lua b/test/functional/api/rpc_fixture.lua index e885a525af..87f5a91115 100644 --- a/test/functional/api/rpc_fixture.lua +++ b/test/functional/api/rpc_fixture.lua @@ -1,7 +1,5 @@ -local deps_prefix = './.deps/usr' -if os.getenv('DEPS_PREFIX') then - deps_prefix = os.getenv('DEPS_PREFIX') -end +local deps_prefix = (os.getenv('DEPS_PREFIX') and os.getenv('DEPS_PREFIX') + or './.deps/usr') package.path = deps_prefix .. '/share/lua/5.1/?.lua;' .. deps_prefix .. '/share/lua/5.1/?/init.lua;' .. diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index 4d25ba0819..7d9a8269d9 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -1,7 +1,6 @@ -- Test server -> client RPC scenarios. Note: unlike `rpcnotify`, to evaluate -- `rpcrequest` calls we need the client event loop to be running. local helpers = require('test.functional.helpers')(after_each) -local Paths = require('test.config.paths') local clear, nvim, eval = helpers.clear, helpers.nvim, helpers.eval local eq, neq, run, stop = helpers.eq, helpers.neq, helpers.run, helpers.stop @@ -243,8 +242,8 @@ describe('server -> client', function() \ 'rpc': v:true \ } ]]) - local lua_prog = Paths.test_lua_prg - meths.set_var("args", {lua_prog, 'test/functional/api/rpc_fixture.lua'}) + meths.set_var("args", {helpers.test_lua_prg, + 'test/functional/api/rpc_fixture.lua'}) jobid = eval("jobstart(g:args, g:job_opts)") neq(0, 'jobid') end) diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 75b9fb71c9..a7d8dc59ec 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1,6 +1,5 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') -local global_helpers = require('test.helpers') local NIL = helpers.NIL local clear, nvim, eq, neq = helpers.clear, helpers.nvim, helpers.eq, helpers.neq @@ -16,10 +15,10 @@ local request = helpers.request local source = helpers.source local next_msg = helpers.next_msg -local expect_err = global_helpers.expect_err -local format_string = global_helpers.format_string -local intchar2lua = global_helpers.intchar2lua -local mergedicts_copy = global_helpers.mergedicts_copy +local expect_err = helpers.expect_err +local format_string = helpers.format_string +local intchar2lua = helpers.intchar2lua +local mergedicts_copy = helpers.mergedicts_copy describe('API', function() before_each(clear) @@ -49,13 +48,30 @@ describe('API', function() it('handles errors in async requests', function() local error_types = meths.get_api_info()[2].error_types - nvim_async("bogus") + nvim_async('bogus') eq({'notification', 'nvim_error_event', {error_types.Exception.id, 'Invalid method: nvim_bogus'}}, next_msg()) -- error didn't close channel. eq(2, eval('1+1')) end) + it('failed async request emits nvim_error_event', function() + local error_types = meths.get_api_info()[2].error_types + nvim_async('command', 'bogus') + eq({'notification', 'nvim_error_event', + {error_types.Exception.id, 'Vim:E492: Not an editor command: bogus'}}, + next_msg()) + -- error didn't close channel. + eq(2, eval('1+1')) + end) + + it('does not set CA_COMMAND_BUSY #7254', function() + nvim('command', 'split') + nvim('command', 'autocmd WinEnter * startinsert') + nvim('command', 'wincmd w') + eq({mode='i', blocking=false}, nvim("get_mode")) + end) + describe('nvim_command', function() it('works', function() local fname = helpers.tmpname() @@ -83,7 +99,7 @@ describe('API', function() end) it('VimL execution error: fails with specific error', function() - local status, rv = pcall(nvim, "command_output", "buffer 23487") + local status, rv = pcall(nvim, "command", "buffer 23487") eq(false, status) -- nvim_command() failed. eq("E86: Buffer 23487 does not exist", string.match(rv, "E%d*:.*")) eq('', eval('v:errmsg')) -- v:errmsg was not updated. @@ -1267,7 +1283,7 @@ describe('API', function() end) it('returns attached UIs', function() local screen = Screen.new(20, 4) - screen:attach() + screen:attach({override=true}) local expected = { { chan = 1, @@ -1282,6 +1298,7 @@ describe('API', function() ext_messages = false, height = 4, rgb = true, + override = true, width = 20, } } @@ -1291,6 +1308,7 @@ describe('API', function() screen = Screen.new(44, 99) screen:attach({ rgb = false }) expected[1].rgb = false + expected[1].override = false expected[1].width = 44 expected[1].height = 99 eq(expected, nvim("list_uis")) diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua index 42e5c46fa5..337c5442ef 100644 --- a/test/functional/autocmd/autocmd_spec.lua +++ b/test/functional/autocmd/autocmd_spec.lua @@ -1,4 +1,5 @@ local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') local dedent = helpers.dedent local eq = helpers.eq @@ -6,11 +7,13 @@ local eval = helpers.eval local feed = helpers.feed local clear = helpers.clear local meths = helpers.meths +local meth_pcall = helpers.meth_pcall local funcs = helpers.funcs local expect = helpers.expect local command = helpers.command local exc_exec = helpers.exc_exec local curbufmeths = helpers.curbufmeths +local source = helpers.source describe('autocmd', function() before_each(clear) @@ -59,9 +62,9 @@ describe('autocmd', function() end) end) - it('once', function() -- :help autocmd-once + it('++once', function() -- :help autocmd-once -- - -- ":autocmd ... once" executes its handler once, then removes the handler. + -- ":autocmd ... ++once" executes its handler once, then removes the handler. -- local expected = { 'Many1', @@ -76,10 +79,10 @@ describe('autocmd', function() } command('let g:foo = []') command('autocmd TabNew * :call add(g:foo, "Many1")') - command('autocmd TabNew * once :call add(g:foo, "Once1")') - command('autocmd TabNew * once :call add(g:foo, "Once2")') + command('autocmd TabNew * ++once :call add(g:foo, "Once1")') + command('autocmd TabNew * ++once :call add(g:foo, "Once2")') command('autocmd TabNew * :call add(g:foo, "Many2")') - command('autocmd TabNew * once :call add(g:foo, "Once3")') + command('autocmd TabNew * ++once :call add(g:foo, "Once3")') eq(dedent([[ --- Autocommands --- @@ -103,27 +106,158 @@ describe('autocmd', function() funcs.execute('autocmd Tabnew')) -- - -- ":autocmd ... once" handlers can be deleted. + -- ":autocmd ... ++once" handlers can be deleted. -- expected = {} command('let g:foo = []') - command('autocmd TabNew * once :call add(g:foo, "Once1")') + command('autocmd TabNew * ++once :call add(g:foo, "Once1")') command('autocmd! TabNew') command('tabnew') eq(expected, eval('g:foo')) -- - -- ":autocmd ... <buffer> once nested" + -- ":autocmd ... <buffer> ++once ++nested" -- expected = { 'OptionSet-Once', 'CursorMoved-Once', } command('let g:foo = []') - command('autocmd OptionSet binary once nested :call add(g:foo, "OptionSet-Once")') - command('autocmd CursorMoved <buffer> once nested setlocal binary|:call add(g:foo, "CursorMoved-Once")') + command('autocmd OptionSet binary ++nested ++once :call add(g:foo, "OptionSet-Once")') + command('autocmd CursorMoved <buffer> ++once ++nested setlocal binary|:call add(g:foo, "CursorMoved-Once")') command("put ='foo bar baz'") feed('0llhlh') eq(expected, eval('g:foo')) + + -- + -- :autocmd should not show empty section after ++once handlers expire. + -- + expected = { + 'Once1', + 'Once2', + } + command('let g:foo = []') + command('autocmd! TabNew') -- Clear all TabNew handlers. + command('autocmd TabNew * ++once :call add(g:foo, "Once1")') + command('autocmd TabNew * ++once :call add(g:foo, "Once2")') + command('tabnew') + eq(expected, eval('g:foo')) + eq(dedent([[ + + --- Autocommands ---]]), + funcs.execute('autocmd Tabnew')) + end) + + it('window works', function() + -- Nvim uses a special window to execute certain actions for an invisible buffer, + -- internally called autcmd_win and mentioned in the docs at :help E813 + -- Do some safety checks for redrawing and api accesses to this window. + + local screen = Screen.new(50, 10) + screen:attach() + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {background = Screen.colors.LightMagenta}, + [3] = {background = Screen.colors.LightMagenta, bold = true, foreground = Screen.colors.Blue1}, + }) + + source([[ + function! Doit() + let g:winid = nvim_get_current_win() + redraw! + echo getchar() + " API functions work when aucmd_win is in scope + let g:had_value = has_key(w:, "testvar") + call nvim_win_set_var(g:winid, "testvar", 7) + let g:test = w:testvar + endfunction + set hidden + " add dummy text to not discard the buffer + call setline(1,"bb") + autocmd User <buffer> call Doit() + ]]) + screen:expect([[ + ^bb | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + + feed(":enew | doautoall User<cr>") + screen:expect([[ + {2:bb }| + {3:~ }| + {3:~ }| + {3:~ }| + {3:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ^:enew | doautoall User | + ]]) + + feed('<cr>') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + 13 | + ]]) + eq(7, eval('g:test')) + + -- API calls are blocked when aucmd_win is not in scope + eq({false, 'Vim(call):Invalid window id'}, + meth_pcall(command, "call nvim_set_current_win(g:winid)")) + + -- second time aucmd_win is needed, a different code path is invoked + -- to reuse the same window, so check again + command("let g:test = v:null") + command("let g:had_value = v:null") + feed(":doautoall User<cr>") + screen:expect([[ + {2:bb }| + {3:~ }| + {3:~ }| + {3:~ }| + {3:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ^:doautoall User | + ]]) + + feed('<cr>') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + 13 | + ]]) + -- win vars in aucmd_win should have been reset + eq(0, eval('g:had_value')) + eq(7, eval('g:test')) + + eq({false, 'Vim(call):Invalid window id'}, + meth_pcall(command, "call nvim_set_current_win(g:winid)")) end) end) diff --git a/test/functional/autocmd/cursormoved_spec.lua b/test/functional/autocmd/cursormoved_spec.lua new file mode 100644 index 0000000000..d0f46e689b --- /dev/null +++ b/test/functional/autocmd/cursormoved_spec.lua @@ -0,0 +1,34 @@ +local helpers = require('test.functional.helpers')(after_each) + +local clear = helpers.clear +local eq = helpers.eq +local eval = helpers.eval +local funcs = helpers.funcs +local source = helpers.source + +describe('CursorMoved', function() + before_each(clear) + + it('is triggered by changing windows', function() + source([[ + let g:cursormoved = 0 + vsplit + autocmd CursorMoved * let g:cursormoved += 1 + wincmd w + wincmd w + ]]) + eq(2, eval('g:cursormoved')) + end) + + it("is not triggered by functions that don't change the window", function() + source([[ + let g:cursormoved = 0 + let g:buf = bufnr('%') + vsplit foo + autocmd CursorMoved * let g:cursormoved += 1 + call nvim_buf_set_lines(g:buf, 0, -1, v:true, ['aaa']) + ]]) + eq({'aaa'}, funcs.nvim_buf_get_lines(eval('g:buf'), 0, -1, true)) + eq(0, eval('g:cursormoved')) + end) +end) diff --git a/test/functional/autocmd/textyankpost_spec.lua b/test/functional/autocmd/textyankpost_spec.lua index 486a3346b1..5849679dd2 100644 --- a/test/functional/autocmd/textyankpost_spec.lua +++ b/test/functional/autocmd/textyankpost_spec.lua @@ -23,6 +23,7 @@ describe('TextYankPost', function() it('is executed after yank and handles register types', function() feed('yy') eq({ + inclusive = false, operator = 'y', regcontents = { 'foo\nbar' }, regname = '', @@ -35,6 +36,7 @@ describe('TextYankPost', function() feed('+yw') eq({ + inclusive = false, operator = 'y', regcontents = { 'baz ' }, regname = '', @@ -44,6 +46,7 @@ describe('TextYankPost', function() feed('<c-v>eky') eq({ + inclusive = true, operator = 'y', regcontents = { 'foo', 'baz' }, regname = '', @@ -55,6 +58,7 @@ describe('TextYankPost', function() it('makes v:event immutable', function() feed('yy') eq({ + inclusive = false, operator = 'y', regcontents = { 'foo\nbar' }, regname = '', @@ -84,6 +88,7 @@ describe('TextYankPost', function() command('autocmd TextYankPost * normal "+yy') feed('yy') eq({ + inclusive = false, operator = 'y', regcontents = { 'foo\nbar' }, regname = '', @@ -96,6 +101,7 @@ describe('TextYankPost', function() it('is executed after delete and change', function() feed('dw') eq({ + inclusive = false, operator = 'd', regcontents = { 'foo' }, regname = '', @@ -105,6 +111,7 @@ describe('TextYankPost', function() feed('dd') eq({ + inclusive = false, operator = 'd', regcontents = { '\nbar' }, regname = '', @@ -114,6 +121,7 @@ describe('TextYankPost', function() feed('cwspam<esc>') eq({ + inclusive = true, operator = 'c', regcontents = { 'baz' }, regname = '', @@ -141,6 +149,7 @@ describe('TextYankPost', function() it('gives the correct register name', function() feed('$"byiw') eq({ + inclusive = true, operator = 'y', regcontents = { 'bar' }, regname = 'b', @@ -149,6 +158,7 @@ describe('TextYankPost', function() feed('"*yy') eq({ + inclusive = true, operator = 'y', regcontents = { 'foo\nbar' }, regname = '*', @@ -160,6 +170,7 @@ describe('TextYankPost', function() -- regname still shows the name the user requested feed('yy') eq({ + inclusive = true, operator = 'y', regcontents = { 'foo\nbar' }, regname = '', @@ -168,6 +179,7 @@ describe('TextYankPost', function() feed('"*yy') eq({ + inclusive = true, operator = 'y', regcontents = { 'foo\nbar' }, regname = '*', @@ -178,6 +190,7 @@ describe('TextYankPost', function() it('works with Ex commands', function() command('1delete +') eq({ + inclusive = false, operator = 'd', regcontents = { 'foo\nbar' }, regname = '+', @@ -187,6 +200,7 @@ describe('TextYankPost', function() command('yank') eq({ + inclusive = false, operator = 'y', regcontents = { 'baz text' }, regname = '', @@ -196,6 +210,7 @@ describe('TextYankPost', function() command('normal yw') eq({ + inclusive = false, operator = 'y', regcontents = { 'baz ' }, regname = '', @@ -205,6 +220,7 @@ describe('TextYankPost', function() command('normal! dd') eq({ + inclusive = false, operator = 'd', regcontents = { 'baz text' }, regname = '', diff --git a/test/functional/core/channels_spec.lua b/test/functional/core/channels_spec.lua index 7b89172f92..ddaed1c448 100644 --- a/test/functional/core/channels_spec.lua +++ b/test/functional/core/channels_spec.lua @@ -1,5 +1,5 @@ - local helpers = require('test.functional.helpers')(after_each) +local uname = helpers.uname local clear, eq, eval, next_msg, ok, source = helpers.clear, helpers.eq, helpers.eval, helpers.next_msg, helpers.ok, helpers.source local command, funcs, meths = helpers.command, helpers.funcs, helpers.meths @@ -7,6 +7,7 @@ local sleep = helpers.sleep local spawn, nvim_argv = helpers.spawn, helpers.nvim_argv local set_session = helpers.set_session local nvim_prog = helpers.nvim_prog +local os_name = helpers.os_name local retry = helpers.retry local expect_twostreams = helpers.expect_twostreams @@ -138,9 +139,8 @@ describe('channels', function() command("call chansend(id, 'incomplet\004')") - local is_freebsd = eval("system('uname') =~? 'FreeBSD'") == 1 - local bsdlike = is_freebsd or (helpers.os_name() == "osx") - print("bsdlike:", bsdlike) + local is_freebsd = (string.lower(uname()) == 'freebsd') + local bsdlike = is_freebsd or (os_name() == "osx") local extra = bsdlike and "^D\008\008" or "" expect_twoline(id, "stdout", "incomplet"..extra, "[1, ['incomplet'], 'stdin']", true) diff --git a/test/functional/core/fileio_spec.lua b/test/functional/core/fileio_spec.lua index 6468aa9d0a..c74eb3bb02 100644 --- a/test/functional/core/fileio_spec.lua +++ b/test/functional/core/fileio_spec.lua @@ -68,7 +68,7 @@ describe('fileio', function() eq(4, request('nvim__stats').fsync) end) - it('creates a backup', function() + it('backup #9709', function() clear({ args={ '-i', 'Xtest_startup_shada', '--cmd', 'set directory=Xtest_startup_swapdir' } }) diff --git a/test/functional/core/main_spec.lua b/test/functional/core/main_spec.lua index a0981e9207..b793e531c9 100644 --- a/test/functional/core/main_spec.lua +++ b/test/functional/core/main_spec.lua @@ -7,19 +7,9 @@ local feed = helpers.feed local eval = helpers.eval local clear = helpers.clear local funcs = helpers.funcs -local nvim_prog = helpers.nvim_prog +local nvim_prog_abs = helpers.nvim_prog_abs local write_file = helpers.write_file -local function nvim_prog_abs() - -- system(['build/bin/nvim']) does not work for whatever reason. It needs to - -- either be executable searched in $PATH or something starting with / or ./. - if nvim_prog:match('[/\\]') then - return funcs.fnamemodify(nvim_prog, ':p') - else - return nvim_prog - end -end - describe('Command-line option', function() describe('-s', function() local fname = 'Xtest-functional-core-main-s' diff --git a/test/functional/spell/spellfile_spec.lua b/test/functional/core/spellfile_spec.lua index afd2c1bce4..afd2c1bce4 100644 --- a/test/functional/spell/spellfile_spec.lua +++ b/test/functional/core/spellfile_spec.lua diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua index 8edb8fc014..f77af836a6 100644 --- a/test/functional/core/startup_spec.lua +++ b/test/functional/core/startup_spec.lua @@ -13,9 +13,7 @@ local nvim_set = helpers.nvim_set local read_file = helpers.read_file local retry = helpers.retry local rmdir = helpers.rmdir -local set_session = helpers.set_session local sleep = helpers.sleep -local spawn = helpers.spawn local iswin = helpers.iswin local write_file = helpers.write_file @@ -203,6 +201,20 @@ describe('startup', function() { 'set encoding', '' })) end) + it('-es/-Es disables swapfile, user config #8540', function() + for _,arg in ipairs({'-es', '-Es'}) do + local out = funcs.system({nvim_prog, arg, + '+set swapfile? updatecount? shada?', + "+put =execute('scriptnames')", '+%print'}) + local line1 = string.match(out, '^.-\n') + -- updatecount=0 means swapfile was disabled. + eq(" swapfile updatecount=0 shada=!,'100,<50,s10,h\n", line1) + -- Standard plugins were loaded, but not user config. + eq('health.vim', string.match(out, 'health.vim')) + eq(nil, string.match(out, 'init.vim')) + end + end) + it('does not crash if --embed is given twice', function() clear{args={'--embed'}} eq(2, eval('1+1')) @@ -214,10 +226,6 @@ describe('sysinit', function() local vimdir = 'Xvim' local xhome = 'Xhome' local pathsep = helpers.get_pathsep() - local argv = { - nvim_prog, '--headless', '--embed', '-i', 'NONE', '-n', - '--cmd', 'set nomore undodir=. directory=. belloff=' - } before_each(function() rmdir(xdgdir) @@ -246,19 +254,21 @@ describe('sysinit', function() end) it('prefers XDG_CONFIG_DIRS over VIM', function() - set_session(spawn(argv, nil, - { 'HOME='..xhome, - 'XDG_CONFIG_DIRS='..xdgdir, - 'VIM='..vimdir })) + clear{args={'--cmd', 'set nomore undodir=. directory=. belloff='}, + args_rm={'-u', '--cmd'}, + env={ HOME=xhome, + XDG_CONFIG_DIRS=xdgdir, + VIM=vimdir }} eq('loaded 1 xdg 1 vim 0', eval('printf("loaded %d xdg %d vim %d", g:loaded, get(g:, "xdg", 0), get(g:, "vim", 0))')) end) it('uses VIM if XDG_CONFIG_DIRS unset', function() - set_session(spawn(argv, nil, - { 'HOME='..xhome, - 'XDG_CONFIG_DIRS=', - 'VIM='..vimdir })) + clear{args={'--cmd', 'set nomore undodir=. directory=. belloff='}, + args_rm={'-u', '--cmd'}, + env={ HOME=xhome, + XDG_CONFIG_DIRS='', + VIM=vimdir }} eq('loaded 1 xdg 0 vim 1', eval('printf("loaded %d xdg %d vim %d", g:loaded, get(g:, "xdg", 0), get(g:, "vim", 0))')) end) diff --git a/test/functional/eval/api_functions_spec.lua b/test/functional/eval/api_functions_spec.lua index 6f440c7d82..40d06b599f 100644 --- a/test/functional/eval/api_functions_spec.lua +++ b/test/functional/eval/api_functions_spec.lua @@ -6,7 +6,7 @@ local clear, curbufmeths = helpers.clear, helpers.curbufmeths local exc_exec, expect, eval = helpers.exc_exec, helpers.expect, helpers.eval local insert = helpers.insert -describe('api functions', function() +describe('eval-API', function() before_each(clear) it("work", function() diff --git a/test/functional/eval/executable_spec.lua b/test/functional/eval/executable_spec.lua index c931b47221..6a95128a4d 100644 --- a/test/functional/eval/executable_spec.lua +++ b/test/functional/eval/executable_spec.lua @@ -1,6 +1,7 @@ local helpers = require('test.functional.helpers')(after_each) -local eq, clear, call, iswin, write_file = - helpers.eq, helpers.clear, helpers.call, helpers.iswin, helpers.write_file +local eq, clear, call, iswin, write_file, command = + helpers.eq, helpers.clear, helpers.call, helpers.iswin, helpers.write_file, + helpers.command describe('executable()', function() before_each(clear) @@ -48,18 +49,17 @@ describe('executable()', function() end) it('not set', function() - local expected = iswin() and 1 or 0 - eq(expected, call('executable', 'Xtest_not_executable')) - eq(expected, call('executable', './Xtest_not_executable')) + eq(0, call('executable', 'Xtest_not_executable')) + eq(0, call('executable', './Xtest_not_executable')) end) it('set, unqualified and not in $PATH', function() - local expected = iswin() and 1 or 0 - eq(expected, call('executable', 'Xtest_executable')) + eq(0, call('executable', 'Xtest_executable')) end) it('set, qualified as a path', function() - eq(1, call('executable', './Xtest_executable')) + local expected = iswin() and 0 or 1 + eq(expected, call('executable', './Xtest_executable')) end) end) end) @@ -136,16 +136,48 @@ describe('executable() (Windows)', function() eq(1, call('executable', '.\\test_executable_zzz')) end) - it('returns 1 for any existing filename', function() + it("with weird $PATHEXT", function() + clear({env={PATHEXT=';'}}) + eq(0, call('executable', '.\\test_executable_zzz')) + clear({env={PATHEXT=';;;.zzz;;'}}) + eq(1, call('executable', '.\\test_executable_zzz')) + end) + + it("unqualified filename, Unix-style 'shell'", function() clear({env={PATHEXT=''}}) + command('set shell=sh') for _,ext in ipairs(exts) do eq(1, call('executable', 'test_executable_'..ext..'.'..ext)) end eq(1, call('executable', 'test_executable_zzz.zzz')) end) - it('returns 1 for any existing path (backslashes)', function() + it("relative path, Unix-style 'shell' (backslashes)", function() clear({env={PATHEXT=''}}) + command('set shell=bash.exe') + for _,ext in ipairs(exts) do + eq(1, call('executable', '.\\test_executable_'..ext..'.'..ext)) + eq(1, call('executable', './test_executable_'..ext..'.'..ext)) + end + eq(1, call('executable', '.\\test_executable_zzz.zzz')) + eq(1, call('executable', './test_executable_zzz.zzz')) + end) + + it('unqualified filename, $PATHEXT contains dot', function() + clear({env={PATHEXT='.;.zzz'}}) + for _,ext in ipairs(exts) do + eq(1, call('executable', 'test_executable_'..ext..'.'..ext)) + end + eq(1, call('executable', 'test_executable_zzz.zzz')) + clear({env={PATHEXT='.zzz;.'}}) + for _,ext in ipairs(exts) do + eq(1, call('executable', 'test_executable_'..ext..'.'..ext)) + end + eq(1, call('executable', 'test_executable_zzz.zzz')) + end) + + it('relative path, $PATHEXT contains dot (backslashes)', function() + clear({env={PATHEXT='.;.zzz'}}) for _,ext in ipairs(exts) do eq(1, call('executable', '.\\test_executable_'..ext..'.'..ext)) eq(1, call('executable', './test_executable_'..ext..'.'..ext)) @@ -153,4 +185,17 @@ describe('executable() (Windows)', function() eq(1, call('executable', '.\\test_executable_zzz.zzz')) eq(1, call('executable', './test_executable_zzz.zzz')) end) + + it('ignores case of extension', function() + clear({env={PATHEXT='.ZZZ'}}) + eq(1, call('executable', 'test_executable_zzz.zzz')) + end) + + it('relative path does not search $PATH', function() + clear({env={PATHEXT=''}}) + eq(0, call('executable', './System32/notepad.exe')) + eq(0, call('executable', '.\\System32\\notepad.exe')) + eq(0, call('executable', '../notepad.exe')) + eq(0, call('executable', '..\\notepad.exe')) + end) end) diff --git a/test/functional/eval/exepath_spec.lua b/test/functional/eval/exepath_spec.lua new file mode 100644 index 0000000000..10a11aeacc --- /dev/null +++ b/test/functional/eval/exepath_spec.lua @@ -0,0 +1,14 @@ +local helpers = require('test.functional.helpers')(after_each) +local eq, clear, call, iswin = + helpers.eq, helpers.clear, helpers.call, helpers.iswin + +describe('exepath() (Windows)', function() + if not iswin() then return end -- N/A for Unix. + + it('append extension if omitted', function() + local filename = 'cmd' + local pathext = '.exe' + clear({env={PATHEXT=pathext}}) + eq(call('exepath', filename..pathext), call('exepath', filename)) + end) +end) diff --git a/test/functional/eval/let_spec.lua b/test/functional/eval/let_spec.lua index 0cbf40137e..63e18f943f 100644 --- a/test/functional/eval/let_spec.lua +++ b/test/functional/eval/let_spec.lua @@ -59,7 +59,7 @@ describe(':let', function() end) it("multibyte env var to child process #8398 #9267", function() - if (not helpers.iswin()) and require('test.helpers').isCI() then + if (not helpers.iswin()) and helpers.isCI() then -- Fails on non-Windows CI. Buffering/timing issue? pending('fails on unix CI', function() end) end diff --git a/test/functional/ex_cmds/cd_spec.lua b/test/functional/ex_cmds/cd_spec.lua index bc2b365b30..283fcf9672 100644 --- a/test/functional/ex_cmds/cd_spec.lua +++ b/test/functional/ex_cmds/cd_spec.lua @@ -286,6 +286,15 @@ describe("getcwd()", function () command("call delete('../"..directories.global.."', 'd')") eq("", helpers.eval("getcwd()")) end) + + it("works with 'autochdir' after local directory was set (#9892)", function() + local curdir = cwd() + command('lcd ' .. directories.global) + command('lcd -') + command('set autochdir') + command('edit ' .. directories.global .. '/foo') + eq(curdir .. pathsep .. directories.global, cwd()) + end) end) diff --git a/test/functional/ex_cmds/dict_notifications_spec.lua b/test/functional/ex_cmds/dict_notifications_spec.lua index 3d550588e7..48e7e05e4c 100644 --- a/test/functional/ex_cmds/dict_notifications_spec.lua +++ b/test/functional/ex_cmds/dict_notifications_spec.lua @@ -1,12 +1,13 @@ local helpers = require('test.functional.helpers')(after_each) local clear, nvim, source = helpers.clear, helpers.nvim, helpers.source +local insert = helpers.insert local eq, next_msg = helpers.eq, helpers.next_msg local exc_exec = helpers.exc_exec local command = helpers.command local eval = helpers.eval -describe('dictionary change notifications', function() +describe('VimL dictionary notifications', function() local channel before_each(function() @@ -338,4 +339,22 @@ describe('dictionary change notifications', function() eq({'notification', '2', {'foo', {old = 'baz', new = 'bar'}}}, next_msg()) end) end) + + it('for b:changedtick', function() + source([[ + function! OnTickChanged(dict, key, value) + call rpcnotify(g:channel, 'SendChangeTick', a:key, a:value) + endfunction + call dictwatcheradd(b:, 'changedtick', 'OnTickChanged') + ]]) + + insert('t'); + eq({'notification', 'SendChangeTick', {'changedtick', {old = 2, new = 3}}}, + next_msg()) + + command([[call dictwatcherdel(b:, 'changedtick', 'OnTickChanged')]]) + insert('t'); + eq(2, eval('1+1')) -- Still alive? + end) + end) diff --git a/test/functional/ex_cmds/help_spec.lua b/test/functional/ex_cmds/help_spec.lua new file mode 100644 index 0000000000..66d7d7d89f --- /dev/null +++ b/test/functional/ex_cmds/help_spec.lua @@ -0,0 +1,27 @@ +local helpers = require('test.functional.helpers')(after_each) + +local clear = helpers.clear +local command = helpers.command +local eq = helpers.eq +local funcs = helpers.funcs + +describe(':help', function() + before_each(clear) + + it('window closed makes cursor return to a valid win/buf #9773', function() + command('help help') + eq(1001, funcs.win_getid()) + command('quit') + eq(1000, funcs.win_getid()) + + command('autocmd WinNew * wincmd p') + + command('help help') + -- Window 1002 is opened, but the autocmd switches back to 1000 and + -- creates the help buffer there instead. + eq(1000, funcs.win_getid()) + command('quit') + -- Before #9773, Nvim would crash on quitting the help window. + eq(1002, funcs.win_getid()) + end) +end) diff --git a/test/functional/ex_cmds/mksession_spec.lua b/test/functional/ex_cmds/mksession_spec.lua index a5b327095e..0f7860740e 100644 --- a/test/functional/ex_cmds/mksession_spec.lua +++ b/test/functional/ex_cmds/mksession_spec.lua @@ -47,4 +47,27 @@ describe(':mksession', function() command('tabnext 2') eq(cwd_dir .. get_pathsep() .. tab_dir, funcs.getcwd()) end) + + it('restores buffers when using tab-local working directories', function() + local tmpfile_base = file_prefix .. '-tmpfile' + local cwd_dir = funcs.getcwd() + local session_path = cwd_dir .. get_pathsep() .. session_file + + command('edit ' .. tmpfile_base .. '1') + command('tcd ' .. tab_dir) + command('tabnew') + command('edit ' .. cwd_dir .. get_pathsep() .. tmpfile_base .. '2') + command('tabfirst') + command('mksession ' .. session_path) + + -- Create a new test instance of Nvim. + clear() + + -- Use :silent to avoid press-enter prompt due to long path + command('silent source ' .. session_path) + command('tabnext 1') + eq(cwd_dir .. get_pathsep() .. tmpfile_base .. '1', funcs.expand('%:p')) + command('tabnext 2') + eq(cwd_dir .. get_pathsep() .. tmpfile_base .. '2', funcs.expand('%:p')) + end) end) diff --git a/test/functional/ex_cmds/oldfiles_spec.lua b/test/functional/ex_cmds/oldfiles_spec.lua index e2958c2924..802c3f68c6 100644 --- a/test/functional/ex_cmds/oldfiles_spec.lua +++ b/test/functional/ex_cmds/oldfiles_spec.lua @@ -1,18 +1,18 @@ local Screen = require('test.functional.ui.screen') local helpers = require('test.functional.helpers')(after_each) +local clear = helpers.clear local buf, eq, feed_command = helpers.curbufmeths, helpers.eq, helpers.feed_command -local feed, nvim_prog, wait = helpers.feed, helpers.nvim_prog, helpers.wait -local ok, set_session, spawn = helpers.ok, helpers.set_session, helpers.spawn +local feed, wait = helpers.feed, helpers.wait +local ok = helpers.ok local eval = helpers.eval local shada_file = 'Xtest.shada' local function _clear() - set_session(spawn({nvim_prog, '--embed', '--headless', '-u', 'NONE', - -- Need shada for these tests. - '-i', shada_file, - '--cmd', 'set noswapfile undodir=. directory=. viewdir=. backupdir=. belloff= noshowcmd noruler'})) + clear{args={'-i', shada_file, -- Need shada for these tests. + '--cmd', 'set noswapfile undodir=. directory=. viewdir=. backupdir=. belloff= noshowcmd noruler'}, + args_rm={'-i', '--cmd'}} end describe(':oldfiles', function() diff --git a/test/functional/ex_cmds/quickfix_commands_spec.lua b/test/functional/ex_cmds/quickfix_commands_spec.lua index bf10f80401..3392a90270 100644 --- a/test/functional/ex_cmds/quickfix_commands_spec.lua +++ b/test/functional/ex_cmds/quickfix_commands_spec.lua @@ -37,9 +37,9 @@ for _, c in ipairs({'l', 'c'}) do -- Second line of each entry (i.e. `nr=-1, …`) was obtained from actual -- results. First line (i.e. `{lnum=…`) was obtained from legacy test. local list = { - {lnum=700, col=10, text='Line 700', + {lnum=700, col=10, text='Line 700', module='', nr=-1, bufnr=2, valid=1, pattern='', vcol=0, ['type']=''}, - {lnum=800, col=15, text='Line 800', + {lnum=800, col=15, text='Line 800', module='', nr=-1, bufnr=3, valid=1, pattern='', vcol=0, ['type']=''}, } eq(list, getlist()) @@ -58,7 +58,7 @@ for _, c in ipairs({'l', 'c'}) do ]]):format(file)) command(('%s %s'):format(addfcmd, file)) list[#list + 1] = { - lnum=900, col=30, text='Line 900', + lnum=900, col=30, text='Line 900', module='', nr=-1, bufnr=5, valid=1, pattern='', vcol=0, ['type']='', } eq(list, getlist()) @@ -71,9 +71,9 @@ for _, c in ipairs({'l', 'c'}) do command('enew!') command(('%s %s'):format(getfcmd, file)) list = { - {lnum=222, col=77, text='Line 222', + {lnum=222, col=77, text='Line 222', module='', nr=-1, bufnr=2, valid=1, pattern='', vcol=0, ['type']=''}, - {lnum=333, col=88, text='Line 333', + {lnum=333, col=88, text='Line 333', module='', nr=-1, bufnr=3, valid=1, pattern='', vcol=0, ['type']=''}, } eq(list, getlist()) diff --git a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua index bbab1471f6..73cbb1d54e 100644 --- a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua +++ b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua @@ -13,6 +13,7 @@ local rmdir = helpers.rmdir local set_session = helpers.set_session local spawn = helpers.spawn local nvim_async = helpers.nvim_async +local expect_msg_seq = helpers.expect_msg_seq describe(':recover', function() before_each(clear) @@ -163,6 +164,13 @@ describe('swapfile detection', function() screen2:expect{any=[[Found a swap file by the name ".*]] ..[[Xtest_swapdialog_dir[/\].*]]..testfile..[[%.swp"]]} feed('e') -- Chose "Edit" at the swap dialog. - feed('<c-c>') + expect_msg_seq({ + ignore={'redraw'}, + seqs={ + { {'notification', 'nvim_error_event', {0, 'Vim(edit):E325: ATTENTION'}}, + } + } + }) + feed('<cr>') end) end) diff --git a/test/functional/ex_cmds/wviminfo_spec.lua b/test/functional/ex_cmds/wviminfo_spec.lua index df0b9df5dd..7c00daf1d7 100644 --- a/test/functional/ex_cmds/wviminfo_spec.lua +++ b/test/functional/ex_cmds/wviminfo_spec.lua @@ -1,23 +1,21 @@ local helpers = require('test.functional.helpers')(after_each) local lfs = require('lfs') -local command, eq, neq, spawn, nvim_prog, set_session, write_file = - helpers.command, helpers.eq, helpers.neq, helpers.spawn, - helpers.nvim_prog, helpers.set_session, helpers.write_file +local clear = helpers.clear +local command, eq, neq, write_file = + helpers.command, helpers.eq, helpers.neq, helpers.write_file local iswin = helpers.iswin local read_file = helpers.read_file describe(':wshada', function() local shada_file = 'wshada_test' - local session before_each(function() - -- Override the default session because we need 'swapfile' for these tests. - session = spawn({nvim_prog, '-u', 'NONE', '-i', iswin() and 'nul' or '/dev/null', '--embed', - '--cmd', 'set swapfile'}) - set_session(session) + clear{args={'-i', iswin() and 'nul' or '/dev/null', + -- Need 'swapfile' for these tests. + '--cmd', 'set swapfile undodir=. directory=. viewdir=. backupdir=. belloff= noshowcmd noruler'}, + args_rm={'-n', '-i', '--cmd'}} end) after_each(function () - session:close() os.remove(shada_file) end) diff --git a/test/functional/example_spec.lua b/test/functional/example_spec.lua new file mode 100644 index 0000000000..883fe4ba63 --- /dev/null +++ b/test/functional/example_spec.lua @@ -0,0 +1,36 @@ +-- To run this test: +-- TEST_FILE=test/functional/example_spec.lua make functionaltest + +local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') +local clear, feed = helpers.clear, helpers.feed + +describe('example', function() + local screen + before_each(function() + clear() + screen = Screen.new(20,5) + screen:attach() + screen:set_default_attr_ids( { + [0] = {bold=true, foreground=Screen.colors.Blue}, + [1] = {bold=true, foreground=Screen.colors.Brown} + } ) + end) + + it('screen test', function() + -- Do some stuff. + feed('iline1<cr>line2<esc>') + + -- For debugging only: prints the current screen. + -- screen:snapshot_util() + + -- Assert the expected state. + screen:expect([[ + line1 | + line^2 | + {0:~ }| + {0:~ }| + | + ]]) + end) +end) diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 9d82ce9c0d..35084f6cff 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -8,37 +8,28 @@ local Session = require('nvim.session') local TcpStream = require('nvim.tcp_stream') local SocketStream = require('nvim.socket_stream') local ChildProcessStream = require('nvim.child_process_stream') -local Paths = require('test.config.paths') local check_cores = global_helpers.check_cores local check_logs = global_helpers.check_logs local dedent = global_helpers.dedent local eq = global_helpers.eq -local expect_err = global_helpers.expect_err -local filter = global_helpers.filter -local map = global_helpers.map -local matches = global_helpers.matches -local near = global_helpers.near -local neq = global_helpers.neq local ok = global_helpers.ok -local read_file = global_helpers.read_file local sleep = global_helpers.sleep -local table_flatten = global_helpers.table_flatten +local tbl_contains = global_helpers.tbl_contains local write_file = global_helpers.write_file -local trim = global_helpers.trim local start_dir = lfs.currentdir() -- XXX: NVIM_PROG takes precedence, QuickBuild sets it. local nvim_prog = ( os.getenv('NVIM_PROG') or os.getenv('NVIM_PRG') - or Paths.test_build_dir .. '/bin/nvim' + or global_helpers.test_build_dir .. '/bin/nvim' ) -- Default settings for the test session. local nvim_set = 'set shortmess+=I background=light noswapfile noautoindent' ..' laststatus=1 undodir=. directory=. viewdir=. backupdir=.' ..' belloff= noshowcmd noruler nomore' -local nvim_argv = {nvim_prog, '-u', 'NONE', '-i', 'NONE', '-N', +local nvim_argv = {nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', nvim_set, '--embed'} -- Directory containing nvim. local nvim_dir = nvim_prog:gsub("[/\\][^/\\]+$", "") @@ -130,16 +121,33 @@ end -- Expects a sequence of next_msg() results. If multiple sequences are -- passed they are tried until one succeeds, in order of shortest to longest. +-- +-- Can be called with positional args (list of sequences only): +-- expect_msg_seq(seq1, seq2, ...) +-- or keyword args: +-- expect_msg_seq{ignore={...}, seqs={seq1, seq2, ...}} +-- +-- ignore: List of ignored event names. +-- seqs: List of one or more potential event sequences. local function expect_msg_seq(...) if select('#', ...) < 1 then error('need at least 1 argument') end - local seqs = {...} + local arg1 = select(1, ...) + if (arg1['seqs'] and select('#', ...) > 1) or type(arg1) ~= 'table' then + error('invalid args') + end + local ignore = arg1['ignore'] and arg1['ignore'] or {} + local seqs = arg1['seqs'] and arg1['seqs'] or {...} + if type(ignore) ~= 'table' then + error("'ignore' arg must be a list of strings") + end table.sort(seqs, function(a, b) -- Sort ascending, by (shallow) length. return #a < #b end) local actual_seq = {} + local nr_ignored = 0 local final_error = '' local function cat_err(err1, err2) if err1 == nil then @@ -152,12 +160,16 @@ local function expect_msg_seq(...) -- Collect enough messages to compare the next expected sequence. while #actual_seq < #expected_seq do local msg = next_msg(10000) -- Big timeout for ASAN/valgrind. + local msg_type = msg and msg[2] or nil if msg == nil then error(cat_err(final_error, - string.format('got %d messages, expected %d', - #actual_seq, #expected_seq))) + string.format('got %d messages (ignored %d), expected %d', + #actual_seq, nr_ignored, #expected_seq))) + elseif tbl_contains(ignore, msg_type) then + nr_ignored = nr_ignored + 1 + else + table.insert(actual_seq, msg) end - table.insert(actual_seq, msg) end local status, result = pcall(eq, expected_seq, actual_seq) if status then @@ -217,6 +229,16 @@ local function stop() session:stop() end +local function nvim_prog_abs() + -- system(['build/bin/nvim']) does not work for whatever reason. It must + -- be executable searched in $PATH or something starting with / or ./. + if nvim_prog:match('[/\\]') then + return request('nvim_call_function', 'fnamemodify', {nvim_prog, ':p'}) + else + return nvim_prog + end +end + -- Executes an ex-command. VimL errors manifest as client (lua) errors, but -- v:errmsg will not be updated. local function nvim_command(cmd) @@ -291,6 +313,43 @@ local function merge_args(...) return argv end +-- Removes Nvim startup args from `args` matching items in `args_rm`. +-- +-- "-u", "-i", "--cmd" are treated specially: their "values" are also removed. +-- Example: +-- args={'--headless', '-u', 'NONE'} +-- args_rm={'--cmd', '-u'} +-- Result: +-- {'--headless'} +-- +-- All cases are removed. +-- Example: +-- args={'--cmd', 'foo', '-N', '--cmd', 'bar'} +-- args_rm={'--cmd', '-u'} +-- Result: +-- {'-N'} +local function remove_args(args, args_rm) + local new_args = {} + local skip_following = {'-u', '-i', '-c', '--cmd', '-s', '--listen'} + if not args_rm or #args_rm == 0 then + return {unpack(args)} + end + for _, v in ipairs(args_rm) do + assert(type(v) == 'string') + end + local last = '' + for _, arg in ipairs(args) do + if tbl_contains(skip_following, last) then + last = '' + elseif tbl_contains(args_rm, arg) then + last = arg + else + table.insert(new_args, arg) + end + end + return new_args +end + local function spawn(argv, merge, env) local child_stream = ChildProcessStream.spawn( merge and merge_args(prepend_argv, argv) or argv, @@ -329,20 +388,25 @@ local function retry(max, max_ms, fn) end -- Starts a new global Nvim session. +-- -- Parameters are interpreted as startup args, OR a map with these keys: --- args: Merged with the default `nvim_argv` set. --- env : Defines the environment of the new session. +-- args: List: Args appended to the default `nvim_argv` set. +-- args_rm: List: Args removed from the default set. All cases are +-- removed, e.g. args_rm={'--cmd'} removes all cases of "--cmd" +-- (and its value) from the default set. +-- env: Map: Defines the environment of the new session. -- -- Example: -- clear('-e') --- clear({args={'-e'}, env={TERM=term}}) +-- clear{args={'-e'}, args_rm={'-i'}, env={TERM=term}} local function clear(...) local args = {unpack(nvim_argv)} + table.insert(args, '--headless') local new_args local env = nil local opts = select(1, ...) - local headless = true if type(opts) == 'table' then + args = remove_args(args, opts.args_rm) if opts.env then local env_tbl = {} for k, v in pairs(opts.env) do @@ -353,7 +417,8 @@ local function clear(...) for _, k in ipairs({ 'HOME', 'ASAN_OPTIONS', - 'LD_LIBRARY_PATH', 'PATH', + 'LD_LIBRARY_PATH', + 'PATH', 'NVIM_LOG_FILE', 'NVIM_RPLUGIN_MANIFEST', }) do @@ -367,15 +432,9 @@ local function clear(...) end end new_args = opts.args or {} - if opts.headless == false then - headless = false - end else new_args = {...} end - if headless then - table.insert(args, '--headless') - end for _, arg in ipairs(new_args) do table.insert(args, arg) end @@ -679,41 +738,14 @@ local function alter_slashes(obj) end end -local function compute_load_factor() - local timeout = 200 - local times = {} - - clear() - - for _ = 1, 5 do - source([[ - let g:val = 0 - call timer_start(200, {-> nvim_set_var('val', 1)}) - let start = reltime() - while 1 - sleep 10m - if g:val == 1 - let g:waited_in_ms = float2nr(reltimefloat(reltime(start)) * 1000) - break - endif - endwhile - ]]) - table.insert(times, nvim_eval('g:waited_in_ms')) - end - - session:close() - session = nil - - local longest = math.max(unpack(times)) - local factor = (longest + 50.0) / timeout - - return factor -end - --- Compute load factor only once. -local load_factor = compute_load_factor() +local load_factor = nil local function load_adjust(num) + if load_factor == nil then -- Compute load factor only once. + clear() + request('nvim_command', 'source src/nvim/testdir/load.vim') + load_factor = request('nvim_eval', 'g:test_load_factor') + end return math.ceil(num * load_factor) end @@ -734,33 +766,25 @@ local module = { curtabmeths = curtabmeths, curwin = curwin, curwinmeths = curwinmeths, - dedent = dedent, - eq = eq, eval = nvim_eval, exc_exec = exc_exec, expect = expect, expect_any = expect_any, - expect_err = expect_err, expect_msg_seq = expect_msg_seq, expect_twostreams = expect_twostreams, feed = feed, feed_command = feed_command, - filter = filter, funcs = funcs, get_pathsep = get_pathsep, get_session = get_session, insert = insert, iswin = iswin, - map = map, - matches = matches, merge_args = merge_args, meth_pcall = meth_pcall, meths = meths, missing_provider = missing_provider, mkdir = lfs.mkdir, load_adjust = load_adjust, - near = near, - neq = neq, new_pipename = new_pipename, next_msg = next_msg, nvim = nvim, @@ -768,14 +792,13 @@ local module = { nvim_async = nvim_async, nvim_dir = nvim_dir, nvim_prog = nvim_prog, + nvim_prog_abs = nvim_prog_abs, nvim_set = nvim_set, - ok = ok, os_name = os_name, pathroot = pathroot, pending_win32 = pending_win32, prepend_argv = prepend_argv, rawfeed = rawfeed, - read_file = read_file, redir_exec = redir_exec, request = request, retry = retry, @@ -785,21 +808,17 @@ local module = { 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, uimeths = uimeths, wait = wait, window = window, winmeths = winmeths, - write_file = write_file, - trim = trim, } +module = global_helpers.tbl_extend('error', module, global_helpers) return function(after_each) if after_each then diff --git a/test/functional/legacy/074_global_var_in_viminfo_spec.lua b/test/functional/legacy/074_global_var_in_viminfo_spec.lua index e17b463e30..f7f074c61a 100644 --- a/test/functional/legacy/074_global_var_in_viminfo_spec.lua +++ b/test/functional/legacy/074_global_var_in_viminfo_spec.lua @@ -2,9 +2,9 @@ local helpers = require('test.functional.helpers')(after_each) local lfs = require('lfs') -local clear, command, eq, neq, eval, wait, spawn = +local clear, command, eq, neq, eval, wait = helpers.clear, helpers.command, helpers.eq, helpers.neq, helpers.eval, - helpers.wait, helpers.spawn + helpers.wait describe('storing global variables in ShaDa files', function() local tempname = 'Xtest-functional-legacy-074' @@ -14,9 +14,7 @@ describe('storing global variables in ShaDa files', function() end) it('is working', function() - local nvim2 = spawn({helpers.nvim_prog, '-u', 'NONE', - '-i', 'Xviminfo', '--embed'}) - helpers.set_session(nvim2) + clear{args_rm={'-i'}, args={'-i', 'Xviminfo'}} local test_dict = {foo = 1, bar = 0, longvarible = 1000} local test_list = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, diff --git a/test/functional/legacy/assert_spec.lua b/test/functional/legacy/assert_spec.lua index 10703465aa..8df2d89b70 100644 --- a/test/functional/legacy/assert_spec.lua +++ b/test/functional/legacy/assert_spec.lua @@ -18,6 +18,15 @@ describe('assert function:', function() clear() end) + describe('assert_beeps', function() + it('works', function() + call('assert_beeps', 'normal h') + expected_empty() + call('assert_beeps', 'normal 0') + expected_errors({'command did not beep: normal 0'}) + end) + end) + -- assert_equal({expected}, {actual}, [, {msg}]) describe('assert_equal', function() it('should not change v:errors when expected is equal to actual', function() diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua index 007d40874f..8f318e3503 100644 --- a/test/functional/lua/overrides_spec.lua +++ b/test/functional/lua/overrides_spec.lua @@ -300,3 +300,19 @@ describe('package.path/package.cpath', function() eq(new_paths_str, eval_lua('package.path'):sub(1, #new_paths_str)) end) end) + +describe('os.getenv', function() + it('returns nothing for undefined env var', function() + eq(NIL, funcs.luaeval('os.getenv("XTEST_1")')) + end) + it('returns env var set by the parent process', function() + local value = 'foo' + clear({env = {['XTEST_1']=value}}) + eq(value, funcs.luaeval('os.getenv("XTEST_1")')) + end) + it('returns env var set by let', function() + local value = 'foo' + meths.command('let $XTEST_1 = "'..value..'"') + eq(value, funcs.luaeval('os.getenv("XTEST_1")')) + end) +end) diff --git a/test/functional/normal/jump_spec.lua b/test/functional/normal/jump_spec.lua new file mode 100644 index 0000000000..5bed541752 --- /dev/null +++ b/test/functional/normal/jump_spec.lua @@ -0,0 +1,48 @@ +local helpers = require('test.functional.helpers')(after_each) + +local clear = helpers.clear +local command = helpers.command +local eq = helpers.eq +local funcs = helpers.funcs +local feed = helpers.feed +local write_file = helpers.write_file + +describe('jumplist', function() + local fname1 = 'Xtest-functional-normal-jump' + local fname2 = fname1..'2' + before_each(clear) + after_each(function() + os.remove(fname1) + os.remove(fname2) + end) + + it('does not add a new entry on startup', function() + eq('\n jump line col file/text\n>', funcs.execute('jumps')) + end) + + it('does not require two <C-O> strokes to jump back', function() + write_file(fname1, 'first file contents') + write_file(fname2, 'second file contents') + + command('args '..fname1..' '..fname2) + local buf1 = funcs.bufnr(fname1) + local buf2 = funcs.bufnr(fname2) + + command('next') + feed('<C-O>') + eq(buf1, funcs.bufnr('%')) + + command('first') + command('snext') + feed('<C-O>') + eq(buf1, funcs.bufnr('%')) + feed('<C-I>') + eq(buf2, funcs.bufnr('%')) + feed('<C-O>') + eq(buf1, funcs.bufnr('%')) + + command('drop '..fname2) + feed('<C-O>') + eq(buf1, funcs.bufnr('%')) + end) +end) diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua index f6f3f02f45..415b526051 100644 --- a/test/functional/options/defaults_spec.lua +++ b/test/functional/options/defaults_spec.lua @@ -15,6 +15,7 @@ local neq = helpers.neq local mkdir = helpers.mkdir local rmdir = helpers.rmdir local alter_slashes = helpers.alter_slashes +local tbl_contains = helpers.tbl_contains describe('startup defaults', function() describe(':filetype', function() @@ -160,20 +161,39 @@ describe('startup defaults', function() end) end) - describe("'packpath'", function() - it('defaults to &runtimepath', function() - eq(meths.get_option('runtimepath'), meths.get_option('packpath')) - end) + it("'shadafile' ('viminfofile')", function() + local env = {XDG_DATA_HOME='Xtest-userdata', XDG_CONFIG_HOME='Xtest-userconfig'} + clear{args={}, args_rm={'-i'}, env=env} + -- Default 'shadafile' is empty. + -- This means use the default location. :help shada-file-name + eq('', meths.get_option('shadafile')) + eq('', meths.get_option('viminfofile')) + -- Check that shada data (such as v:oldfiles) is saved/restored. + command('edit Xtest-foo') + command('write') + local f = eval('fnamemodify(@%,":p")') + assert(string.len(f) > 3) + command('qall') + clear{args={}, args_rm={'-i'}, env=env} + eq({ f }, eval('v:oldfiles')) + os.remove('Xtest-foo') + rmdir('Xtest-userdata') + end) - it('does not follow modifications to runtimepath', function() - meths.command('set runtimepath+=foo') - neq(meths.get_option('runtimepath'), meths.get_option('packpath')) - meths.command('set packpath+=foo') - eq(meths.get_option('runtimepath'), meths.get_option('packpath')) - end) + it("'packpath'", function() + clear() + -- Defaults to &runtimepath. + eq(meths.get_option('runtimepath'), meths.get_option('packpath')) + + -- Does not follow modifications to runtimepath. + meths.command('set runtimepath+=foo') + neq(meths.get_option('runtimepath'), meths.get_option('packpath')) + meths.command('set packpath+=foo') + eq(meths.get_option('runtimepath'), meths.get_option('packpath')) end) it('v:progpath is set to the absolute path', function() + clear() eq(eval("fnamemodify(v:progpath, ':p')"), eval('v:progpath')) end) @@ -231,6 +251,23 @@ describe('XDG-based defaults', function() -- Need separate describe() blocks to not run clear() twice. -- Do not put before_each() here for the same reasons. + it("&runtimepath data-dir matches stdpath('data') #9910", function() + clear() + local rtp = eval('split(&runtimepath, ",")') + local rv = {} + local expected = (iswin() + and { [[\nvim-data\site]], [[\nvim-data\site\after]], } + or { '/nvim/site', '/nvim/site/after', }) + + for _,v in ipairs(rtp) do + local m = string.match(v, [=[[/\]nvim[^/\]*[/\]site.*$]=]) + if m and not tbl_contains(rv, m) then + table.insert(rv, m) + end + end + eq(expected, rv) + end) + describe('with empty/broken environment', function() it('sets correct defaults', function() clear({env={ diff --git a/test/functional/clipboard/clipboard_provider_spec.lua b/test/functional/provider/clipboard_spec.lua index 2bbc678a02..b2d75db745 100644 --- a/test/functional/clipboard/clipboard_provider_spec.lua +++ b/test/functional/provider/clipboard_spec.lua @@ -236,7 +236,7 @@ describe('clipboard', function() end) end) -describe('clipboard', function() +describe('clipboard (with fake clipboard.vim)', function() local function reset(...) clear('--cmd', 'let &rtp = "test/functional/fixtures,".&rtp', ...) end @@ -664,4 +664,20 @@ describe('clipboard', function() the a sourcetarget]]) end) + it('setreg("*") with clipboard=unnamed #5646', function() + source([=[ + function! Paste_without_yank(direction) range + let [reg_save,regtype_save] = [getreg('*'), getregtype('*')] + normal! gvp + call setreg('*', reg_save, regtype_save) + endfunction + xnoremap p :call Paste_without_yank('p')<CR> + set clipboard=unnamed + ]=]) + insert('some words') + feed('gg0yiw') + feed('wviwp') + expect('some some') + eq('some', eval('getreg("*")')) + end) end) diff --git a/test/functional/shada/marks_spec.lua b/test/functional/shada/marks_spec.lua index c2f6351e00..e6450e68b3 100644 --- a/test/functional/shada/marks_spec.lua +++ b/test/functional/shada/marks_spec.lua @@ -189,9 +189,6 @@ describe('ShaDa support code', function() eq(1, nvim_current_line()) nvim_command('execute "normal! \\<C-o>"') eq(testfilename, funcs.bufname('%')) - eq(1, nvim_current_line()) - nvim_command('execute "normal! \\<C-o>"') - eq(testfilename, funcs.bufname('%')) eq(2, nvim_current_line()) nvim_command('execute "normal! \\<C-o>"') eq(testfilename_2, funcs.bufname('%')) @@ -199,6 +196,9 @@ describe('ShaDa support code', function() nvim_command('execute "normal! \\<C-o>"') eq(testfilename_2, funcs.bufname('%')) eq(2, nvim_current_line()) + nvim_command('execute "normal! \\<C-o>"') + eq(testfilename_2, funcs.bufname('%')) + eq(2, nvim_current_line()) end) it('is able to dump and restore change list', function() diff --git a/test/functional/shada/merging_spec.lua b/test/functional/shada/merging_spec.lua index a628baff53..22f2b8348d 100644 --- a/test/functional/shada/merging_spec.lua +++ b/test/functional/shada/merging_spec.lua @@ -912,12 +912,11 @@ describe('ShaDa jumps support code', function() eq('', curbufmeths.get_name()) eq('\n' .. ' jump line col file/text\n' - .. ' 6 2 0 ' .. mock_file_path .. 'c\n' - .. ' 5 2 0 ' .. mock_file_path .. 'd\n' - .. ' 4 3 0 ' .. mock_file_path .. 'd\n' - .. ' 3 2 0 ' .. mock_file_path .. 'e\n' - .. ' 2 2 0 ' .. mock_file_path .. 'f\n' - .. ' 1 1 0 \n' + .. ' 5 2 0 ' .. mock_file_path .. 'c\n' + .. ' 4 2 0 ' .. mock_file_path .. 'd\n' + .. ' 3 3 0 ' .. mock_file_path .. 'd\n' + .. ' 2 2 0 ' .. mock_file_path .. 'e\n' + .. ' 1 2 0 ' .. mock_file_path .. 'f\n' .. '>', redir_exec('jumps')) end) diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua index dbee9bdb49..f3849709e3 100644 --- a/test/functional/terminal/ex_terminal_spec.lua +++ b/test/functional/terminal/ex_terminal_spec.lua @@ -99,6 +99,22 @@ describe(':terminal', function() eq(3, #jumps) end) + it(':stopinsert RPC request exits terminal-mode #7807', function() + command(':terminal') + feed('i[tui] insert-mode') + eq({ blocking=false, mode='t' }, nvim('get_mode')) + command('stopinsert') + eq({ blocking=false, mode='n' }, nvim('get_mode')) + end) + + it(':stopinsert in normal mode doesn\'t break insert mode #9889', function() + command(':terminal') + eq({ blocking=false, mode='n' }, nvim('get_mode')) + command(':stopinsert') + eq({ blocking=false, mode='n' }, nvim('get_mode')) + feed('a') + eq({ blocking=false, mode='t' }, nvim('get_mode')) + end) end) describe(':terminal (with fake shell)', function() diff --git a/test/functional/terminal/highlight_spec.lua b/test/functional/terminal/highlight_spec.lua index 9579e0ea0b..48fedd5927 100644 --- a/test/functional/terminal/highlight_spec.lua +++ b/test/functional/terminal/highlight_spec.lua @@ -3,9 +3,12 @@ local Screen = require('test.functional.ui.screen') local thelpers = require('test.functional.terminal.helpers') local feed, clear, nvim = helpers.feed, helpers.clear, helpers.nvim local nvim_dir, command = helpers.nvim_dir, helpers.command +local nvim_prog_abs = helpers.nvim_prog_abs local eq, eval = helpers.eq, helpers.eval +local funcs = helpers.funcs +local nvim_set = helpers.nvim_set -describe(':terminal window highlighting', function() +describe(':terminal highlight', function() local screen before_each(function() @@ -112,8 +115,51 @@ describe(':terminal window highlighting', function() end) end) +it(':terminal highlight has lower precedence than editor #9964', function() + clear() + local screen = Screen.new(30, 4) + screen:set_default_attr_ids({ + -- "Normal" highlight emitted by the child nvim process. + N_child = {foreground = tonumber('0x4040ff'), background = tonumber('0xffff40')}, + -- "Search" highlight emitted by the child nvim process. + S_child = {background = tonumber('0xffff40'), italic = true, foreground = tonumber('0x4040ff')}, + -- "Search" highlight in the parent nvim process. + S = {background = Screen.colors.Green, italic = true, foreground = Screen.colors.Red}, + -- "Question" highlight in the parent nvim process. + Q = {background = tonumber('0xffff40'), bold = true, foreground = Screen.colors.SeaGreen4}, + }) + screen:attach({rgb=true}) + -- Child nvim process in :terminal (with cterm colors). + funcs.termopen({ + nvim_prog_abs(), '-n', '-u', 'NORC', '-i', 'NONE', '--cmd', nvim_set, + '+hi Normal ctermfg=Blue ctermbg=Yellow', + '+norm! ichild nvim', + '+norm! oline 2', + }) + screen:expect([[ + {N_child:^child nvim }| + {N_child:line 2 }| + {N_child: }| + | + ]]) + command('hi Search gui=italic guifg=Red guibg=Green cterm=italic ctermfg=Red ctermbg=Green') + feed('/nvim<cr>') + screen:expect([[ + {N_child:child }{S:^nvim}{N_child: }| + {N_child:line 2 }| + {N_child: }| + /nvim | + ]]) + command('syntax keyword Question line') + screen:expect([[ + {N_child:child }{S:^nvim}{N_child: }| + {Q:line}{N_child: 2 }| + {N_child: }| + /nvim | + ]]) +end) -describe('terminal window highlighting with custom palette', function() +describe(':terminal highlight with custom palette', function() local screen before_each(function() diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua index 75bb89a1ab..544325e746 100644 --- a/test/functional/terminal/scrollback_spec.lua +++ b/test/functional/terminal/scrollback_spec.lua @@ -142,15 +142,15 @@ describe(':terminal scrollback', function() describe('and height decreased by 1', function() if helpers.pending_win32(pending) then return end local function will_hide_top_line() - feed([[<C-\><C-N>:]]) -- Go to cmdline-mode, so cursor is at bottom. + feed([[<C-\><C-N>]]) screen:try_resize(screen._width - 2, screen._height - 1) screen:expect([[ line2 | line3 | line4 | rows: 5, cols: 28 | - {2: } | - :^ | + {2:^ } | + | ]]) end @@ -166,11 +166,11 @@ describe(':terminal scrollback', function() screen:expect([[ rows: 5, cols: 28 | rows: 3, cols: 26 | - {2: } | - :^ | + {2:^ } | + | ]]) eq(8, curbuf('line_count')) - feed([[<C-\><C-N>3k]]) + feed([[3k]]) screen:expect([[ ^line4 | rows: 5, cols: 28 | diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index a0adb45630..56d6f68b7a 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -1,8 +1,7 @@ -- TUI acceptance tests. -- Uses :terminal as a way to send keys and assert screen state. -local global_helpers = require('test.helpers') -local uname = global_helpers.uname local helpers = require('test.functional.helpers')(after_each) +local uname = helpers.uname local thelpers = require('test.functional.terminal.helpers') local Screen = require('test.functional.ui.screen') local eq = helpers.eq @@ -255,14 +254,14 @@ describe('TUI', function() ]]) end) - it('shows up in nvim_list_uis', function() + it('is included in nvim_list_uis()', function() feed_data(':echo map(nvim_list_uis(), {k,v -> sort(items(filter(v, {k,v -> k[:3] !=# "ext_" })))})\013') screen:expect([=[ | {4:~ }| {5: }| - [[['height', 6], ['rgb', v:false], ['width', 50]]]| - | + [[['height', 6], ['override', v:false], ['rgb', v:| + false], ['width', 50]]] | {10:Press ENTER or type command to continue}{1: } | {3:-- TERMINAL --} | ]=]) @@ -839,8 +838,7 @@ describe('TUI background color', function() it("triggers OptionSet event on terminal-response", function() feed_data('\027:autocmd OptionSet background echo "did OptionSet, yay!"\n') - -- The child Nvim is running asynchronously; wait for it to register the - -- OptionSet handler. + -- Wait for the child Nvim to register the OptionSet handler. feed_data('\027:autocmd OptionSet\n') screen:expect({any='--- Autocommands ---'}) @@ -860,16 +858,23 @@ describe('TUI background color', function() local function assert_bg(color, bg) it('handles '..color..' as '..bg, function() - feed_data('\027]11;rgb:'..color..'\007:echo &background\n') - screen:expect(string.format([[ - {1: } | - {4:~ }| - {4:~ }| - {4:~ }| - {5:[No Name] 0,0-1 All}| - %-5s | - {3:-- TERMINAL --} | - ]], bg)) + feed_data('\027]11;rgb:'..color..'\007') + -- Retry until the terminal response is handled. + retry(100, nil, function() + feed_data(':echo &background\n') + screen:expect({ + timeout=40, + grid=string.format([[ + {1: } | + {4:~ }| + {4:~ }| + {4:~ }| + {5:[No Name] 0,0-1 All}| + %-5s | + {3:-- TERMINAL --} | + ]], bg) + }) + end) end) end diff --git a/test/functional/terminal/window_split_tab_spec.lua b/test/functional/terminal/window_split_tab_spec.lua index c0ce656bb1..ad70b3d14f 100644 --- a/test/functional/terminal/window_split_tab_spec.lua +++ b/test/functional/terminal/window_split_tab_spec.lua @@ -69,7 +69,7 @@ describe(':terminal', function() end) it('forwards resize request to the program', function() - feed([[<C-\><C-N>G:]]) -- Go to cmdline-mode, so cursor is at bottom. + feed([[<C-\><C-N>G]]) local w1, h1 = screen._width - 3, screen._height - 2 local w2, h2 = w1 - 6, h1 - 3 @@ -92,16 +92,16 @@ describe(':terminal', function() | | | + ^ | | - :^ | ]]) screen:try_resize(w2, h2) screen:expect([[ tty ready | rows: 7, cols: 47 | rows: 4, cols: 41 | - {2: } | - :^ | + {2:^ } | + | ]]) end) end) diff --git a/test/functional/ui/cmdline_highlight_spec.lua b/test/functional/ui/cmdline_highlight_spec.lua index 1568b7816e..45808b3b1b 100644 --- a/test/functional/ui/cmdline_highlight_spec.lua +++ b/test/functional/ui/cmdline_highlight_spec.lua @@ -975,8 +975,6 @@ describe('Expressions coloring support', function() ]]) funcs.setreg('a', {'\192'}) feed('<C-r>="<C-r><C-r>a"<C-r><C-r>a"foo"') - -- TODO(ZyX-I): Parser highlighting should not override special character - -- highlighting. screen:expect([[ | {EOB:~ }| diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 5d112d7f35..5d563895d6 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -116,6 +116,31 @@ local function test_cmdline(linegrid) }}} end) + it('from normal mode when : is mapped', function() + command('nnoremap ; :') + + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {3:n }| + | + ]]} + + feed(';') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {3:c }| + | + ]], cmdline={{ + firstc = ":", + content = {{""}}, + pos = 0, + }}} + end) + it('but not with scrolled messages', function() screen:try_resize(35,10) feed(':echoerr doesnotexist<cr>') @@ -600,6 +625,137 @@ local function test_cmdline(linegrid) pos = 12, }}} end) + + it('works together with ext_popupmenu', function() + local expected = { + {'define', '', '', ''}, + {'jump', '', '', ''}, + {'list', '', '', ''}, + {'place', '', '', ''}, + {'undefine', '', '', ''}, + {'unplace', '', '', ''}, + } + + command('set wildmode=full') + command('set wildmenu') + screen:set_option('ext_popupmenu', true) + feed(':sign <tab>') + + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]], cmdline={{ + firstc = ":", + content = {{"sign define"}}, + pos = 11, + }}, popupmenu={items=expected, pos=0, anchor={-1, 0, 5}}} + + feed('<tab>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]], cmdline={{ + firstc = ":", + content = {{"sign jump"}}, + pos = 9, + }}, popupmenu={items=expected, pos=1, anchor={-1, 0, 5}}} + + feed('<left><left>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]], cmdline={{ + firstc = ":", + content = {{"sign "}}, + pos = 5, + }}, popupmenu={items=expected, pos=-1, anchor={-1, 0, 5}}} + + feed('<right>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]], cmdline={{ + firstc = ":", + content = {{"sign define"}}, + pos = 11, + }}, popupmenu={items=expected, pos=0, anchor={-1, 0, 5}}} + + feed('a') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]], cmdline={{ + firstc = ":", + content = {{"sign definea"}}, + pos = 12, + }}} + feed('<esc>') + + -- check positioning with multibyte char in pattern + command("e långfile1") + command("sp långfile2") + feed(':b lå<tab>') + screen:expect{grid=[[ + ^ | + {3:långfile2 }| + | + {2:långfile1 }| + | + ]], popupmenu={ + anchor = { -1, 0, 2 }, + items = {{ "långfile1", "", "", "" }, { "långfile2", "", "", "" }}, + pos = 0 + }, cmdline={{ + content = {{ "b långfile1" }}, + firstc = ":", + pos = 12 + }}} + end) + + it('ext_wildmenu takes precedence over ext_popupmenu', function() + local expected = { + 'define', + 'jump', + 'list', + 'place', + 'undefine', + 'unplace', + } + + command('set wildmode=full') + command('set wildmenu') + screen:set_option('ext_wildmenu', true) + screen:set_option('ext_popupmenu', true) + feed(':sign <tab>') + + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]], cmdline={{ + firstc = ":", + content = {{"sign define"}}, + pos = 11, + }}, wildmenu_items=expected, wildmenu_pos=0} + end) + end -- the representation of cmdline and cmdline_block contents changed with ext_linegrid diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua index 3e0370db14..4dc86f1e1f 100644 --- a/test/functional/ui/cursor_spec.lua +++ b/test/functional/ui/cursor_spec.lua @@ -216,10 +216,10 @@ describe('ui/cursor', function() if m.blinkwait then m.blinkwait = 700 end end if m.hl_id then - m.hl_id = 49 + m.hl_id = 50 m.attr = {background = Screen.colors.DarkGray} end - if m.id_lm then m.id_lm = 50 end + if m.id_lm then m.id_lm = 51 end end -- Assert the new expectation. diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua index 8e6756e550..8eb2bbf779 100644 --- a/test/functional/ui/diff_spec.lua +++ b/test/functional/ui/diff_spec.lua @@ -62,12 +62,12 @@ describe('Diff mode screen', function() {1: }5 {3:│}{1: }5 | {1: }6 {3:│}{1: }6 | {1:+ }{5:+-- 4 lines: 7···}{3:│}{1:+ }{5:+-- 4 lines: 7··}| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| :set diffopt=filler | ]]) @@ -82,12 +82,12 @@ describe('Diff mode screen', function() {1: }5 {3:│}{1: }5 | {1: }6 {3:│}{1: }6 | {1:+ }{5:+-- 4 lines: 7···}{3:│}{1:+ }{5:+-- 4 lines: 7··}| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| :set diffopt+=internal | ]]) @@ -108,12 +108,12 @@ describe('Diff mode screen', function() {1: }5 {3:│}{1: }5 | {1: }6 {3:│}{1: }6 | {1:+ }{5:+-- 4 lines: 7···}{3:│}{1:+ }{5:+-- 4 lines: 7··}| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| :set diffopt=filler | ]]) @@ -128,12 +128,12 @@ describe('Diff mode screen', function() {1: }5 {3:│}{1: }5 | {1: }6 {3:│}{1: }6 | {1:+ }{5:+-- 4 lines: 7···}{3:│}{1:+ }{5:+-- 4 lines: 7··}| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| :set diffopt+=internal | ]]) @@ -154,12 +154,12 @@ describe('Diff mode screen', function() {1: }9 {3:│}{1: }9 | {1: }10 {3:│}{1: }10 | {1: }{2:------------------}{3:│}{1: }{4:11 }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| :set diffopt=filler | ]]) @@ -174,12 +174,12 @@ describe('Diff mode screen', function() {1: }9 {3:│}{1: }9 | {1: }10 {3:│}{1: }10 | {1: }{2:------------------}{3:│}{1: }{4:11 }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| :set diffopt+=internal | ]]) @@ -200,12 +200,12 @@ describe('Diff mode screen', function() {1: }9 {3:│}{1: }9 | {1: }10 {3:│}{1: }10 | {1: }{4:11 }{3:│}{1: }{2:-----------------}| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| :set diffopt=filler | ]]) @@ -220,12 +220,12 @@ describe('Diff mode screen', function() {1: }9 {3:│}{1: }9 | {1: }10 {3:│}{1: }10 | {1: }{4:11 }{3:│}{1: }{2:-----------------}| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| :set diffopt+=internal | ]]) @@ -250,8 +250,8 @@ describe('Diff mode screen', function() {1: }9 {3:│}{1: }9 | {1: }10 {3:│}{1: }10 | {1: }{4:11 }{3:│}{1: }{2:-----------------}| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| :set diffopt=filler | ]]) @@ -270,8 +270,8 @@ describe('Diff mode screen', function() {1: }9 {3:│}{1: }9 | {1: }10 {3:│}{1: }10 | {1: }{4:11 }{3:│}{1: }{2:-----------------}| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| :set diffopt+=internal | ]]) @@ -296,8 +296,8 @@ describe('Diff mode screen', function() {1: }9 {3:│}{1: }9 | {1: }10 {3:│}{1: }10 | {1: }{2:------------------}{3:│}{1: }{4:11 }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| :set diffopt=filler | ]]) @@ -316,8 +316,8 @@ describe('Diff mode screen', function() {1: }9 {3:│}{1: }9 | {1: }10 {3:│}{1: }10 | {1: }{2:------------------}{3:│}{1: }{4:11 }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| :set diffopt+=internal | ]]) @@ -546,11 +546,11 @@ int main(int argc, char **argv) {1: }{2:------------------}{3:│}{1: }{4: values.each do }| {1: } v.finalize {3:│}{1: } v.finalize | {1: } end {3:│}{1: } end | - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| :set diffopt=internal,filler | ]]) @@ -569,11 +569,11 @@ int main(int argc, char **argv) {1: } values.each do |{3:│}{1: } values.each do | {1: } v.finalize {3:│}{1: } v.finalize | {1: } end {3:│}{1: } end | - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| | ]]) @@ -593,11 +593,11 @@ int main(int argc, char **argv) {1: } values.each do |{3:│}{1: } values.each do | {1: } v.finalize {3:│}{1: } v.finalize | {1: } end {3:│}{1: } end | - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| : | ]]) @@ -612,19 +612,19 @@ int main(int argc, char **argv) feed(':set diffopt=filler<cr>') screen:expect([[ {1:+ }{5:^+-- 10 lines: 1···}{3:│}{1:+ }{5:+-- 10 lines: 1··}| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| :set diffopt=filler | ]]) @@ -632,19 +632,19 @@ int main(int argc, char **argv) feed(':set diffopt+=internal<cr>') screen:expect([[ {1:+ }{5:^+-- 10 lines: 1···}{3:│}{1:+ }{5:+-- 10 lines: 1··}| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| :set diffopt+=internal | ]]) @@ -658,19 +658,19 @@ int main(int argc, char **argv) feed(':set diffopt=filler<cr>') screen:expect([[ {1:- }^ {3:│}{1:- } | - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| :set diffopt=filler | ]]) @@ -678,19 +678,19 @@ int main(int argc, char **argv) feed(':set diffopt+=internal<cr>') screen:expect([[ {1:- }^ {3:│}{1:- } | - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| :set diffopt+=internal | ]]) @@ -706,17 +706,17 @@ int main(int argc, char **argv) {1: }^a {3:│}{1: }A | {1: }b {3:│}{1: }b | {1: }{9:cd }{3:│}{1: }{9:cD}{8:e}{9: }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| :set diffopt=filler,icase | ]]) @@ -726,17 +726,17 @@ int main(int argc, char **argv) {1: }^a {3:│}{1: }A | {1: }b {3:│}{1: }b | {1: }{9:cd }{3:│}{1: }{9:cD}{8:e}{9: }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| :set diffopt+=internal | ]]) @@ -763,12 +763,12 @@ int main(int argc, char **argv) {1: } return 0; {3:│}{1: } return 0; | {1: }{2:------------------}{3:│}{1: }{4: } }| {1: }} {3:│}{1: }} | - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| :set diffopt=filler,iwhite | ]]) @@ -786,12 +786,12 @@ int main(int argc, char **argv) {1: } return 0; {3:│}{1: } return 0; | {1: }{2:------------------}{3:│}{1: }{4: } }| {1: }} {3:│}{1: }} | - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| :set diffopt=filler,iwhite,internal | ]]) @@ -815,14 +815,14 @@ int main(int argc, char **argv) {1: }cd {3:│}{1: }cd | {1: }ef {3:│}{1: } | {1: }{8:xxx}{9: }{3:│}{1: }ef | - {1: }{6:~ }{3:│}{1: }{8:yyy}{9: }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{1: }{8:yyy}{9: }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| :set diffopt=internal,filler,iblank | ]]) @@ -838,15 +838,15 @@ int main(int argc, char **argv) {1: } {3:│}{1: } | {1: }cd {3:│}{1: }ef | {1: }ef {3:│}{1: }{8:yyy}{9: }| - {1: }{8:xxx}{9: }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {1: }{8:xxx}{9: }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| : | ]]) @@ -862,15 +862,15 @@ int main(int argc, char **argv) {1: } {3:│}{1: } | {1: }cd {3:│}{1: }ef | {1: }ef {3:│}{1: }{8:yyy}{9: }| - {1: }{8:xxx}{9: }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {1: }{8:xxx}{9: }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| : | ]]) @@ -886,15 +886,15 @@ int main(int argc, char **argv) {1: } {3:│}{1: } | {1: }cd {3:│}{1: }ef | {1: }ef {3:│}{1: }{8:yyy}{9: }| - {1: }{8:xxx}{9: }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {1: }{8:xxx}{9: }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| : | ]]) @@ -921,12 +921,12 @@ int main(int argc, char **argv) {1: }foo {3:│}{1: }foo | {1: }{2:------------------}{3:│}{1: }{4: }| {1: }bar {3:│}{1: }bar | - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| : | ]]) @@ -945,12 +945,12 @@ int main(int argc, char **argv) {1: }foo {3:│}{1: }foo | {1: }{2:------------------}{3:│}{1: }{4: }| {1: }bar {3:│}{1: }bar | - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| - {1: }{6:~ }{3:│}{1: }{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| + {6:~ }{3:│}{6:~ }| {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| : | ]]) diff --git a/test/functional/ui/embed_spec.lua b/test/functional/ui/embed_spec.lua index 10dbc68672..9196c8af40 100644 --- a/test/functional/ui/embed_spec.lua +++ b/test/functional/ui/embed_spec.lua @@ -8,7 +8,7 @@ local clear = helpers.clear local function test_embed(ext_linegrid) local screen local function startup(...) - clear{headless=false, args={...}} + clear{args_rm={'--headless'}, args={...}} -- attach immediately after startup, for early UI screen = Screen.new(60, 8) diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 3be2182eb4..a567fbb941 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -5,6 +5,7 @@ local clear, feed = helpers.clear, helpers.feed local command, feed_command = helpers.command, helpers.feed_command local eval = helpers.eval local eq = helpers.eq +local insert = helpers.insert local meths = helpers.meths local curbufmeths = helpers.curbufmeths local funcs = helpers.funcs @@ -29,9 +30,27 @@ describe('floating windows', function() [10] = {background = Screen.colors.LightGrey, underline = true, bold = true, foreground = Screen.colors.Magenta}, [11] = {bold = true, foreground = Screen.colors.Magenta}, [12] = {background = Screen.colors.Red, bold = true, foreground = Screen.colors.Blue1}, - [13] = {background = Screen.colors.WebGray} + [13] = {background = Screen.colors.WebGray}, + [14] = {foreground = Screen.colors.Brown}, + [15] = {background = Screen.colors.Grey20}, + [16] = {background = Screen.colors.Grey20, bold = true, foreground = Screen.colors.Blue1}, + [17] = {background = Screen.colors.Yellow}, } + it('behavior', function() + -- Create three windows and test that ":wincmd <direction>" changes to the + -- first window, if the previous window is invalid. + command('split') + meths.open_win(0, true, {width=10, height=10, relative='editor', row=0, col=0}) + eq(1002, funcs.win_getid()) + eq('editor', meths.win_get_config(1002).relative) + command([[ + call nvim_win_close(1001, v:false) + wincmd j + ]]) + eq(1000, funcs.win_getid()) + end) + local function with_ext_multigrid(multigrid) local screen before_each(function() @@ -42,13 +61,11 @@ describe('floating windows', function() it('can be created and reconfigured', function() local buf = meths.create_buf(false,false) - local win = meths.open_win(buf, false, 20, 2, {relative='editor', row=2, col=5}) - meths.win_set_option(win , 'winhl', 'Normal:PMenu') + local win = meths.open_win(buf, false, {relative='editor', width=20, height=2, row=2, col=5}) local expected_pos = { [3]={{id=1001}, 'NW', 1, 2, 5, true}, } - if multigrid then screen:expect{grid=[[ ## grid 1 @@ -83,7 +100,7 @@ describe('floating windows', function() end - meths.win_config(win,0,0,{relative='editor', row=0, col=10}) + meths.win_set_config(win, {relative='editor', row=0, col=10}) expected_pos[3][4] = 0 expected_pos[3][5] = 10 if multigrid then @@ -151,20 +168,226 @@ describe('floating windows', function() end end) + it('return their configuration', function() + local buf = meths.create_buf(false, false) + local win = meths.open_win(buf, false, {relative='editor', width=20, height=2, row=3, col=5}) + local expected = {anchor='NW', col=5, external=false, focusable=true, height=2, relative='editor', row=3, width=20} + eq(expected, meths.win_get_config(win)) + + eq({relative='', external=false, focusable=true}, meths.win_get_config(0)) + + if multigrid then + meths.win_set_config(win, {external=true, width=10, height=1}) + eq({external=true,focusable=true,width=10,height=1,relative=''}, meths.win_get_config(win)) + end + end) + + it('defaults to nonumber and NormalFloat highlight', function() + command('set number') + command('hi NormalFloat guibg=#333333') + feed('ix<cr>y<cr><esc>gg') + local win = meths.open_win(0, false, {relative='editor', width=20, height=4, row=4, col=10}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + {14: 1 }^x | + {14: 2 }y | + {14: 3 } | + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {15:x }| + {15:y }| + {15: }| + {16:~ }| + ]], float_pos={[3] = {{id = 1001}, "NW", 1, 4, 10, true}}} + else + screen:expect([[ + {14: 1 }^x | + {14: 2 }y | + {14: 3 } {15:x } | + {0:~ }{15:y }{0: }| + {0:~ }{15: }{0: }| + {0:~ }{16:~ }{0: }| + | + ]]) + end + + local buf = meths.create_buf(false, true) + meths.win_set_buf(win, buf) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + {14: 1 }^x | + {14: 2 }y | + {14: 3 } | + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {15: }| + {16:~ }| + {16:~ }| + {16:~ }| + ]], float_pos={[3] = {{id = 1001}, "NW", 1, 4, 10, true}}} + else + screen:expect([[ + {14: 1 }^x | + {14: 2 }y | + {14: 3 } {15: } | + {0:~ }{16:~ }{0: }| + {0:~ }{16:~ }{0: }| + {0:~ }{16:~ }{0: }| + | + ]]) + end + end) + + it('can have minimum size', function() + insert("the background text") + local buf = meths.create_buf(false, true) + meths.buf_set_lines(buf, 0, -1, true, {'x'}) + local win = meths.open_win(buf, false, {relative='win', width=1, height=1, row=0, col=4, focusable=false}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + the background tex^t | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 4 + {1:x}| + ]], float_pos={ + [4] = {{id = 1002}, "NW", 2, 0, 4, false} + }} + else + screen:expect([[ + the {1:x}ackground tex^t | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end + + meths.win_set_config(win, {relative='win', row=0, col=15}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + the background tex^t | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 4 + {1:x}| + ]], float_pos={ + [4] = {{id = 1002}, "NW", 2, 0, 15, false} + }} + else + screen:expect([[ + the background {1:x}ex^t | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end + + meths.win_close(win,false) + if multigrid then + screen:expect([[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + the background tex^t | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ]]) + else + screen:expect([[ + the background tex^t | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end + end) + it('API has proper error messages', function() local buf = meths.create_buf(false,false) - eq({false, "Invalid options key 'bork'"}, - meth_pcall(meths.open_win,buf, false, 20, 2, {bork=true})) - eq({false, "'win' option is only valid with relative='win'"}, - meth_pcall(meths.open_win,buf, false, 20, 2, {relative='editor',row=0,col=0,win=0})) - eq({false, "Only one of 'relative' and 'external' should be used"}, - meth_pcall(meths.open_win,buf, false, 20, 2, {relative='editor',row=0,col=0,external=true})) - eq({false, "Invalid value of 'relative' option"}, - meth_pcall(meths.open_win,buf, false, 20, 2, {relative='shell',row=0,col=0})) - eq({false, "Invalid value of 'anchor' option"}, - meth_pcall(meths.open_win,buf, false, 20, 2, {relative='editor',row=0,col=0,anchor='bottom'})) + eq({false, "Invalid key 'bork'"}, + meth_pcall(meths.open_win,buf, false, {width=20,height=2,bork=true})) + eq({false, "'win' key is only valid with relative='win'"}, + meth_pcall(meths.open_win,buf, false, {width=20,height=2,relative='editor',row=0,col=0,win=0})) + eq({false, "Only one of 'relative' and 'external' must be used"}, + meth_pcall(meths.open_win,buf, false, {width=20,height=2,relative='editor',row=0,col=0,external=true})) + eq({false, "Invalid value of 'relative' key"}, + meth_pcall(meths.open_win,buf, false, {width=20,height=2,relative='shell',row=0,col=0})) + eq({false, "Invalid value of 'anchor' key"}, + meth_pcall(meths.open_win,buf, false, {width=20,height=2,relative='editor',row=0,col=0,anchor='bottom'})) eq({false, "All of 'relative', 'row', and 'col' has to be specified at once"}, - meth_pcall(meths.open_win,buf, false, 20, 2, {relative='editor'})) + meth_pcall(meths.open_win,buf, false, {width=20,height=2,relative='editor'})) + eq({false, "'width' key must be a positive Integer"}, + meth_pcall(meths.open_win,buf, false, {width=-1,height=2,relative='editor'})) + eq({false, "'height' key must be a positive Integer"}, + meth_pcall(meths.open_win,buf, false, {width=20,height=-1,relative='editor'})) + eq({false, "'height' key must be a positive Integer"}, + meth_pcall(meths.open_win,buf, false, {width=20,height=0,relative='editor'})) + eq({false, "Must specify 'width' and 'height'"}, + meth_pcall(meths.open_win,buf, false, {relative='editor'})) end) it('can be placed relative window or cursor', function() @@ -210,8 +433,7 @@ describe('floating windows', function() local buf = meths.create_buf(false,false) -- no 'win' arg, relative default window - local win = meths.open_win(buf, false, 20, 2, {relative='win', row=0, col=10}) - meths.win_set_option(win, 'winhl', 'Normal:PMenu') + local win = meths.open_win(buf, false, {relative='win', width=20, height=2, row=0, col=10}) if multigrid then screen:expect{grid=[[ ## grid 1 @@ -252,7 +474,7 @@ describe('floating windows', function() ]]) end - meths.win_config(win, -1, -1, {relative='cursor', row=1, col=-2}) + meths.win_set_config(win, {relative='cursor', row=1, col=-2}) if multigrid then screen:expect{grid=[[ ## grid 1 @@ -293,7 +515,7 @@ describe('floating windows', function() ]]) end - meths.win_config(win, -1, -1, {relative='cursor', row=0, col=0, anchor='SW'}) + meths.win_set_config(win, {relative='cursor', row=0, col=0, anchor='SW'}) if multigrid then screen:expect{grid=[[ ## grid 1 @@ -335,7 +557,7 @@ describe('floating windows', function() end - meths.win_config(win, -1, -1, {relative='win', win=oldwin, row=1, col=10, anchor='NW'}) + meths.win_set_config(win, {relative='win', win=oldwin, row=1, col=10, anchor='NW'}) if multigrid then screen:expect{grid=[[ ## grid 1 @@ -376,7 +598,7 @@ describe('floating windows', function() ]]) end - meths.win_config(win, -1, -1, {relative='win', win=oldwin, row=3, col=39, anchor='SE'}) + meths.win_set_config(win, {relative='win', win=oldwin, row=3, col=39, anchor='SE'}) if multigrid then screen:expect{grid=[[ ## grid 1 @@ -417,7 +639,7 @@ describe('floating windows', function() ]]) end - meths.win_config(win, -1, -1, {relative='win', win=0, row=0, col=50, anchor='NE'}) + meths.win_set_config(win, {relative='win', win=0, row=0, col=50, anchor='NE'}) if multigrid then screen:expect{grid=[[ ## grid 1 @@ -459,6 +681,66 @@ describe('floating windows', function() end end) + it('validates cursor even when window is not entered', function() + screen:try_resize(30,5) + command("set nowrap") + insert([[some text that is wider than the window]]) + if multigrid then + screen:expect([[ + ## grid 1 + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + | + ## grid 2 + that is wider than the windo^w | + {0:~ }| + {0:~ }| + {0:~ }| + ]]) + else + screen:expect([[ + that is wider than the windo^w | + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end + + local buf = meths.create_buf(false,true) + meths.buf_set_lines(buf, 0, -1, true, {'some floaty text'}) + meths.open_win(buf, false, {relative='editor', width=20, height=1, row=3, col=1}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + [2:------------------------------]| + | + ## grid 2 + that is wider than the windo^w | + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 4 + {1:some floaty text }| + ]], float_pos={ + [4] = {{id = 1002}, "NW", 1, 3, 1, true} + }} + else + screen:expect([[ + that is wider than the windo^w | + {0:~ }| + {0:~ }| + {0:~}{1:some floaty text }{0: }| + | + ]]) + end + end) + if multigrid then pending("supports second UI without multigrid", function() local session2 = helpers.connect(eval('v:servername')) @@ -467,8 +749,7 @@ describe('floating windows', function() screen2:attach(nil, session2) screen2:set_default_attr_ids(attrs) local buf = meths.create_buf(false,false) - local win = meths.open_win(buf, true, 20, 2, {relative='editor', row=2, col=5}) - meths.win_set_option(win, 'winhl', 'Normal:PMenu') + meths.open_win(buf, true, {relative='editor', width=20, height=2, row=2, col=5}) local expected_pos = { [2]={{id=1001}, 'NW', 1, 2, 5} } @@ -501,8 +782,7 @@ describe('floating windows', function() it('handles resized screen', function() local buf = meths.create_buf(false,false) meths.buf_set_lines(buf, 0, -1, true, {'such', 'very', 'float'}) - local win = meths.open_win(buf, false, 15, 4, {relative='editor', row=2, col=10}) - meths.win_set_option(win , 'winhl', 'Normal:PMenu') + local win = meths.open_win(buf, false, {relative='editor', width=15, height=4, row=2, col=10}) local expected_pos = { [4]={{id=1002}, 'NW', 1, 2, 10, true}, } @@ -673,15 +953,15 @@ describe('floating windows', function() screen:expect([[ | {0:~ }| + {0:~ }{1:such }{0: }| {0:~ }{1:very }{0: }| {0:~ }{1:^float }{0: }| - {0:~ }| - {0:~ }| + {0:~ }{2:~ }{0: }| | ]]) end - meths.win_config(win, -1, 3, {}) + meths.win_set_config(win, {height=3}) feed('gg') if multigrid then screen:expect{grid=[[ @@ -1010,10 +1290,126 @@ describe('floating windows', function() screen:expect([[ | {0:~ }| - {0:~ }{1:^such }{0: }| + {0:~ }{1:^such }{0: }| + {0:~ }{1:very }{0: }| + {0:~ }{1:float }{0: }| {0:~ }| + | + ]]) + end + end) + + it('does not crash with inccommand #9379', function() + local expected_pos = { + [3]={{id=1001}, 'NW', 1, 2, 0, true}, + } + + command("set inccommand=split") + command("set laststatus=2") + + local buf = meths.create_buf(false,false) + meths.open_win(buf, true, {relative='editor', width=30, height=3, row=2, col=0}) + + insert([[ + foo + bar + ]]) + + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + {5:[No Name] }| + | + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {1:foo }| + {1:bar }| + {1:^ }| + ]], float_pos=expected_pos} + else + screen:expect([[ + | {0:~ }| + {1:foo }{0: }| + {1:bar }{0: }| + {1:^ }{0: }| + {5:[No Name] }| + | + ]]) + end + + feed(':%s/.') + + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + {5:[Preview] }| + :%s/.^ | + ## grid 2 + | + ## grid 3 + {17:f}{1:oo }| + {17:b}{1:ar }| + {1: }| + ]], float_pos=expected_pos} + else + screen:expect([[ + | + {5:[No Name] }| + {17:f}{1:oo } | + {17:b}{1:ar } | + {1: }{0: }| + {5:[Preview] }| + :%s/.^ | + ]]) + end + + feed('<Esc>') + + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + {5:[No Name] }| + | + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {1:foo }| + {1:bar }| + {1:^ }| + ]], float_pos=expected_pos} + else + screen:expect([[ + | {0:~ }| + {1:foo }{0: }| + {1:bar }{0: }| + {1:^ }{0: }| + {5:[No Name] }| | ]]) end @@ -1021,7 +1417,7 @@ describe('floating windows', function() it('does not crash when set cmdheight #9680', function() local buf = meths.create_buf(false,false) - meths.open_win(buf, false, 20, 2, {relative='editor', row=2, col=5}) + meths.open_win(buf, false, {relative='editor', width=20, height=2, row=2, col=5}) command("set cmdheight=2") eq(1, meths.eval('1')) end) @@ -1029,7 +1425,7 @@ describe('floating windows', function() describe('and completion', function() before_each(function() local buf = meths.create_buf(false,false) - local win = meths.open_win(buf, true, 12, 4, {relative='editor', row=2, col=5}) + local win = meths.open_win(buf, true, {relative='editor', width=12, height=4, row=2, col=5}) meths.win_set_option(win , 'winhl', 'Normal:ErrorMsg') if multigrid then screen:expect{grid=[[ @@ -1266,7 +1662,7 @@ describe('floating windows', function() ]], float_pos={ [3] = {{ id = 1001 }, "NW", 1, 2, 5, true}, }, popupmenu={ - anchor = {0, 2, 3}, items = items, pos = 0 + anchor = {3, 0, 2}, items = items, pos = 0 }} else screen:expect{grid=[[ @@ -1278,7 +1674,7 @@ describe('floating windows', function() {0:~ }{12:~ }{0: }| {3:-- INSERT --} | ]], popupmenu={ - anchor = {2, 7}, items = items, pos = 0 + anchor = {1, 2, 7}, items = items, pos = 0 }} end @@ -1348,7 +1744,7 @@ describe('floating windows', function() ]], float_pos={ [3] = {{ id = 1001 }, "NW", 1, 2, 5, true}, }, popupmenu={ - anchor = {0, 0, 2}, items = items, pos = 0 + anchor = {2, 0, 0}, items = items, pos = 0 }} else screen:expect{grid=[[ @@ -1360,7 +1756,7 @@ describe('floating windows', function() {0:~ }{12:~ }{0: }| {3:-- INSERT --} | ]], popupmenu={ - anchor = {0, 0}, items = items, pos = 0 + anchor = {1, 0, 0}, items = items, pos = 0 }} end @@ -1402,9 +1798,233 @@ describe('floating windows', function() ]]) end end) - end) + describe('float shown after pum', function() + local win + before_each(function() + command('hi NormalFloat guibg=#333333') + feed('i') + funcs.complete(1, {'aa', 'word', 'longtext'}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + {3:-- INSERT --} | + ## grid 2 + aa^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {13:aa }| + {1:word }| + {1:longtext }| + ]], float_pos={ + [3] = {{id = -1}, "NW", 2, 1, 0, false}} + } + else + screen:expect([[ + aa^ | + {13:aa }{0: }| + {1:word }{0: }| + {1:longtext }{0: }| + {0:~ }| + {0:~ }| + {3:-- INSERT --} | + ]]) + end + + local buf = meths.create_buf(false,true) + meths.buf_set_lines(buf,0,-1,true,{"some info", "about item"}) + win = meths.open_win(buf, false, {relative='cursor', width=12, height=2, row=1, col=10}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + {3:-- INSERT --} | + ## grid 2 + aa^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {13:aa }| + {1:word }| + {1:longtext }| + ## grid 5 + {15:some info }| + {15:about item }| + ]], float_pos={ + [3] = {{id = -1}, "NW", 2, 1, 0, false}, + [5] = {{id = 1002}, "NW", 2, 1, 12, true}, + }} + else + screen:expect([[ + aa^ | + {13:aa }{15:e info }{0: }| + {1:word }{15:ut item }{0: }| + {1:longtext }{0: }| + {0:~ }| + {0:~ }| + {3:-- INSERT --} | + ]]) + end + end) + + it('and close pum first', function() + feed('<c-y>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + {3:-- INSERT --} | + ## grid 2 + aa^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 5 + {15:some info }| + {15:about item }| + ]], float_pos={ + [5] = {{id = 1002}, "NW", 2, 1, 12, true}, + }} + else + screen:expect([[ + aa^ | + {0:~ }{15:some info }{0: }| + {0:~ }{15:about item }{0: }| + {0:~ }| + {0:~ }| + {0:~ }| + {3:-- INSERT --} | + ]]) + end + + meths.win_close(win, false) + if multigrid then + screen:expect([[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + {3:-- INSERT --} | + ## grid 2 + aa^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ]]) + else + screen:expect([[ + aa^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {3:-- INSERT --} | + ]]) + end + end) + + it('and close float first', function() + meths.win_close(win, false) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + {3:-- INSERT --} | + ## grid 2 + aa^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {13:aa }| + {1:word }| + {1:longtext }| + ]], float_pos={ + [3] = {{id = -1}, "NW", 2, 1, 0, false}, + }} + else + screen:expect([[ + aa^ | + {13:aa }{0: }| + {1:word }{0: }| + {1:longtext }{0: }| + {0:~ }| + {0:~ }| + {3:-- INSERT --} | + ]]) + end + + feed('<c-y>') + if multigrid then + screen:expect([[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + {3:-- INSERT --} | + ## grid 2 + aa^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ]]) + else + screen:expect([[ + aa^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {3:-- INSERT --} | + ]]) + end + end) + end) describe("handles :wincmd", function() local win @@ -1415,9 +2035,8 @@ describe('floating windows', function() command("set hidden") meths.buf_set_lines(0,0,-1,true,{"x"}) local buf = meths.create_buf(false,false) - win = meths.open_win(buf, false, 20, 2, {relative='editor', row=2, col=5}) + win = meths.open_win(buf, false, {relative='editor', width=20, height=2, row=2, col=5}) meths.buf_set_lines(buf,0,-1,true,{"y"}) - meths.win_set_option(win , 'winhl', 'Normal:PMenu') expected_pos = { [3]={{id=1001}, 'NW', 1, 2, 5, true} } @@ -1526,7 +2145,7 @@ describe('floating windows', function() end) it("w with focusable=false", function() - meths.win_config(win, -1, -1, {focusable=false}) + meths.win_set_config(win, {focusable=false}) expected_pos[3][6] = false feed("<c-w>wi") -- i to provoke redraw if multigrid then @@ -1740,7 +2359,7 @@ describe('floating windows', function() end) it("focus by mouse (focusable=false)", function() - meths.win_config(win, -1, -1, {focusable=false}) + meths.win_set_config(win, {focusable=false}) meths.buf_set_lines(0, -1, -1, true, {"a"}) expected_pos[3][6] = false if multigrid then @@ -2074,39 +2693,6 @@ describe('floating windows', function() {1:y }| {2:~ }| ## grid 4 - {1:^y }| - {2:~ }| - ]], float_pos=expected_pos} - else - screen:expect([[ - {1:^y }| - {2:~ }| - {4:[No N}{1:y }{4: }| - x {2:~ } | - {0:~ }| - {5:[No Name] [+] }| - | - ]]) - end - - feed(":set winhighlight=<cr><c-l>") - if multigrid then - screen:expect{grid=[[ - ## grid 1 - [4:----------------------------------------]| - [4:----------------------------------------]| - {4:[No Name] [+] }| - [2:----------------------------------------]| - [2:----------------------------------------]| - {5:[No Name] [+] }| - | - ## grid 2 - x | - {0:~ }| - ## grid 3 - {1:y }| - {2:~ }| - ## grid 4 ^y | {0:~ }| ]], float_pos=expected_pos} @@ -2122,7 +2708,6 @@ describe('floating windows', function() ]]) end - feed("<c-w>j") if multigrid then screen:expect{grid=[[ @@ -2405,6 +2990,119 @@ describe('floating windows', function() eq(exited, true) end) + it(':quit two floats in a row', function() + -- enter first float + feed('<c-w><c-w>') + -- enter second float + meths.open_win(0, true, {relative='editor', width=20, height=2, row=4, col=8}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + x | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {1:y }| + {2:~ }| + ## grid 4 + {1:^y }| + {2:~ }| + ]], float_pos={ + [3] = {{id = 1001}, "NW", 1, 2, 5, true}, + [4] = {{id = 1002}, "NW", 1, 4, 8, true} + }} + else + screen:expect([[ + x | + {0:~ }| + {0:~ }{1:y }{0: }| + {0:~ }{2:~ }{0: }| + {0:~ }{1:^y }{0: }| + {0:~ }{2:~ }{0: }| + | + ]]) + end + + feed(':quit<cr>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + {5:[No Name] [+] }| + :quit | + ## grid 2 + x | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {1:^y }| + {2:~ }| + ]], float_pos={ + [3] = {{id = 1001}, "NW", 1, 2, 5, true}, + }} + else + screen:expect([[ + x | + {0:~ }| + {0:~ }{1:^y }{0: }| + {0:~ }{2:~ }{0: }| + {0:~ }| + {5:[No Name] [+] }| + :quit | + ]]) + end + + feed(':quit<cr>') + if multigrid then + screen:expect([[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + :quit | + ## grid 2 + ^x | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ]]) + else + screen:expect([[ + ^x | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + :quit | + ]]) + end + + eq(2, eval('1+1')) + end) + it("o (:only) non-float", function() feed("<c-w>o") if multigrid then @@ -2659,23 +3357,23 @@ describe('floating windows', function() x | {0:~ }| ## grid 3 - {1:^y }| - {2:~ }| + ^y | + {0:~ }| ]]} else screen:expect([[ x | {0:~ }| {5:[No Name] [+] }| - {1:^y }| - {2:~ }| + ^y | + {0:~ }| {4:[No Name] [+] }| | ]]) end if multigrid then - meths.win_config(0,-1,-1,{external=true}) + meths.win_set_config(0, {external=true, width=30, height=2}) expected_pos = {[3]={external=true}} screen:expect{grid=[[ ## grid 1 @@ -2693,12 +3391,12 @@ describe('floating windows', function() {0:~ }| {0:~ }| ## grid 3 - {1:^y }| - {2:~ }| + ^y | + {0:~ }| ]], float_pos=expected_pos} else eq({false, "UI doesn't support external windows"}, - meth_pcall(meths.win_config, 0,-1,-1,{external=true})) + meth_pcall(meths.win_set_config, 0, {external=true, width=30, height=2})) return end @@ -2717,11 +3415,10 @@ describe('floating windows', function() x | {0:~ }| ## grid 3 - {1:^y }| - {2:~ }| + ^y | + {0:~ }| ]]) end - end) it('movements with nested split layout', function() @@ -2786,8 +3483,8 @@ describe('floating windows', function() 4 | {0:~ }| ## grid 3 - ^5 | - {0:~ }| + {1:^5 }| + {2:~ }| ## grid 4 2 | {0:~ }| @@ -2802,8 +3499,8 @@ describe('floating windows', function() screen:expect([[ 1 {5:│}2 | {0:~ }{5:│}{0:~ }| - {5:[No N}^5 {5:ame] [+] }| - 3 {0:~ } | + {5:[No N}{1:^5 }{5:ame] [+] }| + 3 {2:~ } | {0:~ }{5:│}{0:~ }| {5:[No Name] [+] [No Name] [+] }| :enew | @@ -2895,13 +3592,14 @@ describe('floating windows', function() [2:----------------------------------------]| [2:----------------------------------------]| [2:----------------------------------------]| - {4:[No Name] [+] }| + [2:----------------------------------------]| :tabnext | ## grid 2 ^x | {0:~ }| {0:~ }| {0:~ }| + {0:~ }| ## grid 3 {1:y }| {2:~ }| @@ -2919,7 +3617,7 @@ describe('floating windows', function() {0:~ }{1:y }{0: }| {0:~ }{2:~ }{0: }| {0:~ }| - {4:[No Name] [+] }| + {0:~ }| :tabnext | ]]) end @@ -2940,6 +3638,7 @@ describe('floating windows', function() {0:~ }| {0:~ }| {0:~ }| + {0:~ }| ## grid 3 {1:y }| {2:~ }| @@ -2965,7 +3664,8 @@ describe('floating windows', function() it(":tabnew and :tabnext (external)", function() if multigrid then - meths.win_config(win,-1,-1,{external=true}) + -- also test external window wider than main screen + meths.win_set_config(win, {external=true, width=65, height=4}) expected_pos = {[3]={external=true}} feed(":tabnew<cr>") screen:expect{grid=[[ @@ -2985,8 +3685,10 @@ describe('floating windows', function() {0:~ }| {0:~ }| ## grid 3 - {1:y }| - {2:~ }| + y | + {0:~ }| + {0:~ }| + {0:~ }| ## grid 4 ^ | {0:~ }| @@ -2996,7 +3698,7 @@ describe('floating windows', function() ]], float_pos=expected_pos} else eq({false, "UI doesn't support external windows"}, - meth_pcall(meths.win_config, 0,-1,-1,{external=true})) + meth_pcall(meths.win_set_config, 0, {external=true, width=65, height=4})) end feed(":tabnext<cr>") @@ -3008,16 +3710,19 @@ describe('floating windows', function() [2:----------------------------------------]| [2:----------------------------------------]| [2:----------------------------------------]| - {4:[No Name] [+] }| + [2:----------------------------------------]| :tabnext | ## grid 2 ^x | {0:~ }| {0:~ }| {0:~ }| + {0:~ }| ## grid 3 - {1:y }| - {2:~ }| + y | + {0:~ }| + {0:~ }| + {0:~ }| ## grid 4 | {0:~ }| @@ -3036,21 +3741,25 @@ describe('floating windows', function() [4:----------------------------------------]| [4:----------------------------------------]| [4:----------------------------------------]| - {4:[No Name] }| + [4:----------------------------------------]| :tabnext | ## grid 2 x | {0:~ }| {0:~ }| {0:~ }| + {0:~ }| ## grid 3 - {1:y }| - {2:~ }| + y | + {0:~ }| + {0:~ }| + {0:~ }| ## grid 4 ^ | {0:~ }| {0:~ }| {0:~ }| + {0:~ }| ]], float_pos=expected_pos} end end) @@ -3063,6 +3772,5 @@ describe('floating windows', function() describe('without ext_multigrid', function() with_ext_multigrid(false) end) - end) diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua index 943cbcef56..5fa299bed9 100644 --- a/test/functional/ui/fold_spec.lua +++ b/test/functional/ui/fold_spec.lua @@ -39,11 +39,11 @@ describe("folded lines", function() screen:expect([[ {7:+ }{5: 1 +-- 2 lines: ·························}| {7:+ }{5: 0 ^+-- 2 lines: ·························}| - {7: }{1:~ }| - {7: }{1:~ }| - {7: }{1:~ }| - {7: }{1:~ }| - {7: }{1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| :set foldcolumn=2 | ]]) end) @@ -93,12 +93,12 @@ describe("folded lines", function() feed_command("set number foldcolumn=2") screen:expect([[ {7:+ }{5: 1 ^+-- 2 lines: å 语 x̎͂̀̂͛͛ العَرَبِيَّة···········}| - {7: }{1:~ }| - {7: }{1:~ }| - {7: }{1:~ }| - {7: }{1:~ }| - {7: }{1:~ }| - {7: }{1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| :set number foldcolumn=2 | ]]) @@ -106,12 +106,12 @@ describe("folded lines", function() feed_command("set rightleft") screen:expect([[ {5:+-- 2 lines: å ······················^· 1 }{7: +}| - {1: ~}{7: }| - {1: ~}{7: }| - {1: ~}{7: }| - {1: ~}{7: }| - {1: ~}{7: }| - {1: ~}{7: }| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| :set rightleft | ]]) @@ -178,7 +178,7 @@ describe("folded lines", function() {1::}set foldmethod=manual | {1::}let x = 1 | {1::}^ | - {1::~ }| + {1:~ }| {3:[Command Line] }| : | ]]) @@ -189,8 +189,8 @@ describe("folded lines", function() {2:[No Name] }| {1::}{5:^+-- 2 lines: set foldmethod=manual·········}| {1::} | - {1::~ }| - {1::~ }| + {1:~ }| + {1:~ }| {3:[Command Line] }| : | ]]) @@ -214,7 +214,7 @@ describe("folded lines", function() {1:/}alpha | {1:/}{6:omega} | {1:/}^ | - {1:/~ }| + {1:~ }| {3:[Command Line] }| / | ]]) @@ -224,9 +224,9 @@ describe("folded lines", function() | {2:[No Name] }| {1:/}{5:^+-- 3 lines: alpha·························}| - {1:/~ }| - {1:/~ }| - {1:/~ }| + {1:~ }| + {1:~ }| + {1:~ }| {3:[Command Line] }| / | ]]) diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index 3ee3f173d6..85b5aed2f8 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -748,6 +748,66 @@ describe('CursorLine highlight', function() ]]) end) + it('always updated. vim-patch:8.1.0849', function() + local screen = Screen.new(50,5) + screen:set_default_attr_ids({ + [1] = {foreground = Screen.colors.SlateBlue}, + [2] = {bold = true, foreground = Screen.colors.Brown}, + [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [4] = {foreground = Screen.colors.SlateBlue, background = Screen.colors.Gray90}, + [5] = {background = Screen.colors.Gray90}, + [6] = {bold = true, foreground = Screen.colors.Blue1}, + [7] = {background = Screen.colors.LightRed}, + [8] = {foreground = Screen.colors.Brown}, + }) + screen:attach() + command('set cursorline relativenumber') + command('call setline(1, ["","1","2","3",""])') + feed('Gy3k') + screen:expect([[ + {2: 0 }{5:^1 }| + {8: 1 }2 | + {8: 2 }3 | + {8: 3 } | + 4 lines yanked | + ]]) + feed('jj') + screen:expect([[ + {8: 2 }1 | + {8: 1 }2 | + {2: 0 }{5:^3 }| + {8: 1 } | + 4 lines yanked | + ]]) + end) + + it('with visual area. vim-patch:8.1.1001', function() + local screen = Screen.new(50,5) + screen:set_default_attr_ids({ + [1] = {foreground = Screen.colors.SlateBlue}, + [2] = {bold = true, foreground = Screen.colors.Brown}, + [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [4] = {foreground = Screen.colors.SlateBlue, background = Screen.colors.Gray90}, + [5] = {background = Screen.colors.Gray90}, + [6] = {bold = true, foreground = Screen.colors.Blue1}, + [7] = {background = Screen.colors.LightRed}, + [8] = {foreground = Screen.colors.Brown}, + [9] = {background = Screen.colors.LightGrey}, + [10] = {bold = true}, + }) + screen:attach() + command('set cursorline') + command('call setline(1, repeat(["abc"], 50))') + feed('V<C-f>zbkkjk') + screen:expect([[ + {9:abc} | + ^a{9:bc} | + abc | + abc | + {10:-- VISUAL LINE --} | + ]]) + end) + it('with split-windows in diff-mode', function() local screen = Screen.new(50,12) screen:set_default_attr_ids({ @@ -781,9 +841,9 @@ describe('CursorLine highlight', function() {1: }extra line! {4:│}{1: }extra line! | {1: }last line ... {4:│}{1: }last line ... | {1: } {4:│}{1: } | - {1: }{8:~ }{4:│}{1: }{8:~ }| - {1: }{8:~ }{4:│}{1: }{8:~ }| - {1: }{8:~ }{4:│}{1: }{8:~ }| + {8:~ }{4:│}{8:~ }| + {8:~ }{4:│}{8:~ }| + {8:~ }{4:│}{8:~ }| {4:[No Name] [+] }{9:[No Name] [+] }| | ]]) @@ -796,9 +856,9 @@ describe('CursorLine highlight', function() {1: }extra line! {4:│}{1: }extra line! | {1: }last line ... {4:│}{1: }last line ... | {1: }{7: }{4:│}{1: }{7:^ }| - {1: }{8:~ }{4:│}{1: }{8:~ }| - {1: }{8:~ }{4:│}{1: }{8:~ }| - {1: }{8:~ }{4:│}{1: }{8:~ }| + {8:~ }{4:│}{8:~ }| + {8:~ }{4:│}{8:~ }| + {8:~ }{4:│}{8:~ }| {4:[No Name] [+] }{9:[No Name] [+] }| | ]]) @@ -815,9 +875,9 @@ describe('CursorLine highlight', function() {1: }extra line! {4:│}{1: }extra line! | {1: }last line ... {4:│}{1: }last line ... | {1: } {4:│}{1: } | - {1: }{8:~ }{4:│}{1: }{8:~ }| - {1: }{8:~ }{4:│}{1: }{8:~ }| - {1: }{8:~ }{4:│}{1: }{8:~ }| + {8:~ }{4:│}{8:~ }| + {8:~ }{4:│}{8:~ }| + {8:~ }{4:│}{8:~ }| {4:[No Name] [+] }{9:[No Name] [+] }| | ]], { diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua index c215ece2f2..4f243e6413 100644 --- a/test/functional/ui/inccommand_spec.lua +++ b/test/functional/ui/inccommand_spec.lua @@ -2607,3 +2607,30 @@ it(':substitute with inccommand during :terminal activity', function() end) end) + +it(':substitute with inccommand, timer-induced :redraw #9777', function() + local screen = Screen.new(30,12) + clear() + command('set cmdwinheight=3') + command('call timer_start(10, {-> execute("redraw")}, {"repeat":-1})') + command('call timer_start(10, {-> execute("redrawstatus")}, {"repeat":-1})') + common_setup(screen, 'split', 'foo bar baz\nbar baz fox\nbar foo baz') + + feed('gg') + feed(':%s/foo/ZZZ') + sleep(20) -- Allow some timer activity. + screen:expect([[ + {12:ZZZ} bar baz | + bar baz fox | + bar {12:ZZZ} baz | + {15:~ }| + {15:~ }| + {15:~ }| + {11:[No Name] [+] }| + |1| {12:ZZZ} bar baz | + |3| bar {12:ZZZ} baz | + {15:~ }| + {10:[Preview] }| + :%s/foo/ZZZ^ | + ]]) +end) diff --git a/test/functional/ui/input_spec.lua b/test/functional/ui/input_spec.lua index 850efed282..121cbe47d6 100644 --- a/test/functional/ui/input_spec.lua +++ b/test/functional/ui/input_spec.lua @@ -30,6 +30,24 @@ describe('mappings', function() add_mapping('<c-s-a-d-up>', '<c-s-a-d-up>') add_mapping('<c-d-a>', '<c-d-a>') add_mapping('<d-1>', '<d-1>') + add_mapping('<khome>','<khome>') + add_mapping('<kup>','<kup>') + add_mapping('<kpageup>','<kpageup>') + add_mapping('<kleft>','<kleft>') + add_mapping('<korigin>','<korigin>') + add_mapping('<kright>','<kright>') + add_mapping('<kend>','<kend>') + add_mapping('<kdown>','<kdown>') + add_mapping('<kpagedown>','<kpagedown>') + add_mapping('<kinsert>','<kinsert>') + add_mapping('<kdel>','<kdel>') + add_mapping('<kdivide>','<kdivide>') + add_mapping('<kmultiply>','<kmultiply>') + add_mapping('<kminus>','<kminus>') + add_mapping('<kplus>','<kplus>') + add_mapping('<kenter>','<kenter>') + add_mapping('<kcomma>','<kcomma>') + add_mapping('<kequal>','<kequal>') end) it('ok', function() @@ -48,6 +66,42 @@ describe('mappings', function() check_mapping('<c-d-a>', '<c-d-a>') check_mapping('<d-c-a>', '<c-d-a>') check_mapping('<d-1>', '<d-1>') + check_mapping('<khome>','<khome>') + check_mapping('<KP7>','<khome>') + check_mapping('<kup>','<kup>') + check_mapping('<KP8>','<kup>') + check_mapping('<kpageup>','<kpageup>') + check_mapping('<KP9>','<kpageup>') + check_mapping('<kleft>','<kleft>') + check_mapping('<KP4>','<kleft>') + check_mapping('<korigin>','<korigin>') + check_mapping('<KP5>','<korigin>') + check_mapping('<kright>','<kright>') + check_mapping('<KP6>','<kright>') + check_mapping('<kend>','<kend>') + check_mapping('<KP1>','<kend>') + check_mapping('<kdown>','<kdown>') + check_mapping('<KP2>','<kdown>') + check_mapping('<kpagedown>','<kpagedown>') + check_mapping('<KP3>','<kpagedown>') + check_mapping('<kinsert>','<kinsert>') + check_mapping('<KP0>','<kinsert>') + check_mapping('<kdel>','<kdel>') + check_mapping('<KPPeriod>','<kdel>') + check_mapping('<kdivide>','<kdivide>') + check_mapping('<KPDiv>','<kdivide>') + check_mapping('<kmultiply>','<kmultiply>') + check_mapping('<KPMult>','<kmultiply>') + check_mapping('<kminus>','<kminus>') + check_mapping('<KPMinus>','<kminus>') + check_mapping('<kplus>','<kplus>') + check_mapping('<KPPlus>','<kplus>') + check_mapping('<kenter>','<kenter>') + check_mapping('<KPEnter>','<kenter>') + check_mapping('<kcomma>','<kcomma>') + check_mapping('<KPComma>','<kcomma>') + check_mapping('<kequal>','<kequal>') + check_mapping('<KPEquals>','<kequal>') end) end) diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index 388c6b3e95..d49d2f0316 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -22,8 +22,129 @@ describe('ui/ext_messages', function() [6] = {bold = true, reverse = true}, }) end) + after_each(function() + os.remove('Xtest') + end) + + it('msg_show kind=confirm,confirm_sub,emsg,wmsg', function() + feed('iline 1\nline 2<esc>') + + -- kind=confirm + feed(':echo confirm("test")<cr>') + screen:expect{grid=[[ + line 1 | + line ^2 | + {1:~ }| + {1:~ }| + {1:~ }| + ]], messages={ { + content = {{"\ntest\n[O]k: ", 4}}, + kind = 'confirm', + }}} + feed('<cr><cr>') + screen:expect{grid=[[ + line 1 | + line ^2 | + {1:~ }| + {1:~ }| + {1:~ }| + ]], messages={ { + content = { { "\ntest\n[O]k: ", 4 } }, + kind = "confirm" + }, { + content = { { "1" } }, + kind = "echo" + }, { + content = { { "Press ENTER or type command to continue", 4 } }, + kind = "return_prompt" + } }} + feed('<cr><cr>') + + -- kind=confirm_sub + feed(':%s/i/X/gc<cr>') + screen:expect{grid=[[ + l{7:i}ne 1 | + l{8:i}ne ^2 | + {1:~ }| + {1:~ }| + {1:~ }| + ]], attr_ids={ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [3] = {bold = true}, + [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, + [5] = {foreground = Screen.colors.Blue1}, + [6] = {bold = true, reverse = true}, + [7] = {reverse = true}, + [8] = {background = Screen.colors.Yellow}, + }, messages={ { + content = { { "replace with X (y/n/a/q/l/^E/^Y)?", 4 } }, + kind = "confirm_sub" + } }} + feed('nq') + + -- kind=wmsg (editing readonly file) + command('write Xtest') + command('set readonly nohls') + feed('G$x') + screen:expect{grid=[[ + line 1 | + {IGNORE}| + {1:~ }| + {1:~ }| + {1:~ }| + ]], attr_ids={ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [7] = {foreground = Screen.colors.Red}, + }, messages={ { + content = { { "W10: Warning: Changing a readonly file", 7 } }, + kind = "wmsg" + } + }} + + -- kind=wmsg ('wrapscan' after search reaches EOF) + feed('uG$/i<cr>') + screen:expect{grid=[[ + l^ine 1 | + line 2 | + {1:~ }| + {1:~ }| + {1:~ }| + ]], attr_ids={ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [3] = {bold = true}, + [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, + [5] = {foreground = Screen.colors.Blue1}, + [6] = {bold = true, reverse = true}, + [7] = {foreground = Screen.colors.Red}, + }, messages={ { + content = { { "search hit BOTTOM, continuing at TOP", 7 } }, + kind = "wmsg" + } }} + + -- kind=emsg after :throw + feed(':throw "foo"<cr>') + screen:expect{grid=[[ + l^ine 1 | + line 2 | + {1:~ }| + {1:~ }| + {1:~ }| + ]], messages={ { + content = { { "Error detected while processing :", 2 } }, + kind = "emsg" + }, { + content = { { "E605: Exception not caught: foo", 2 } }, + kind = "" + }, { + content = { { "Press ENTER or type command to continue", 4 } }, + kind = "return_prompt" + } } + } + end) - it('supports :echoerr', function() + it(':echoerr', function() feed(':echoerr "raa"<cr>') screen:expect{grid=[[ ^ | @@ -142,7 +263,7 @@ describe('ui/ext_messages', function() }} end) - it('supports showmode', function() + it('&showmode', function() command('imap <f2> <cmd>echomsg "stuff"<cr>') feed('i') screen:expect{grid=[[ @@ -179,7 +300,7 @@ describe('ui/ext_messages', function() {1:~ }| {1:~ }| ]], popupmenu={ - anchor = { 2, 0 }, + anchor = { 1, 2, 0 }, items = { { "alphpabet", "", "", "" }, { "alphanum", "", "", "" } }, pos = 1 }, showmode={ { "-- Keyword Local completion (^N^P) ", 3 }, { "match 1 of 2", 4 } }} @@ -194,7 +315,7 @@ describe('ui/ext_messages', function() {1:~ }| {1:~ }| ]], popupmenu={ - anchor = { 2, 0 }, + anchor = { 1, 2, 0 }, items = { { "alphpabet", "", "", "" }, { "alphanum", "", "", "" } }, pos = 1 }, messages={ { @@ -210,7 +331,7 @@ describe('ui/ext_messages', function() {1:~ }| {1:~ }| ]], popupmenu={ - anchor = { 2, 0 }, + anchor = { 1, 2, 0 }, items = { { "alphpabet", "", "", "" }, { "alphanum", "", "", "" } }, pos = 0 }, messages={ { @@ -230,7 +351,7 @@ describe('ui/ext_messages', function() }} end) - it('supports showmode with recording message', function() + it('&showmode with macro-recording message', function() feed('qq') screen:expect{grid=[[ ^ | @@ -268,7 +389,7 @@ describe('ui/ext_messages', function() ]]) end) - it('shows recording message with noshowmode', function() + it('shows macro-recording message with &noshowmode', function() command("set noshowmode") feed('qq') -- also check mode to avoid immediate success @@ -308,7 +429,7 @@ describe('ui/ext_messages', function() ]], mode="normal"} end) - it('supports showcmd and ruler', function() + it('supports &showcmd and &ruler', function() command('set showcmd ruler') screen:expect{grid=[[ ^ | @@ -529,7 +650,7 @@ describe('ui/ext_messages', function() local screen before_each(function() - clear{headless=false, args={"--cmd", "set shortmess-=I"}} + clear{args_rm={'--headless'}, args={"--cmd", "set shortmess-=I"}} screen = Screen.new(80, 24) screen:attach({rgb=true, ext_messages=true, ext_popupmenu=true}) screen:set_default_attr_ids({ diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua index c54d608ec4..c5a23e4661 100644 --- a/test/functional/ui/multigrid_spec.lua +++ b/test/functional/ui/multigrid_spec.lua @@ -11,7 +11,7 @@ describe('ext_multigrid', function() local screen before_each(function() - clear{headless=false, args={'--cmd', 'set laststatus=2'}} + clear{args_rm={'--headless'}, args={'--cmd', 'set laststatus=2'}} screen = Screen.new(53,14) screen:attach({ext_multigrid=true}) screen:set_default_attr_ids({ diff --git a/test/functional/ui/options_spec.lua b/test/functional/ui/options_spec.lua index ed630259be..93192934c7 100644 --- a/test/functional/ui/options_spec.lua +++ b/test/functional/ui/options_spec.lua @@ -1,10 +1,9 @@ -local global_helpers = require('test.helpers') local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear = helpers.clear local command = helpers.command local eq = helpers.eq -local shallowcopy = global_helpers.shallowcopy +local shallowcopy = helpers.shallowcopy describe('ui receives option updates', function() local screen @@ -115,7 +114,8 @@ describe('ui receives option updates', function() end) local function startup_test(headless) - local expected = reset(nil,{headless=headless,args={'--cmd', 'set guifont=Comic\\ Sans\\ 12'}}) + local expected = reset(nil, {args_rm=(headless and {} or {'--headless'}), + args={'--cmd', 'set guifont=Comic\\ Sans\\ 12'}}) expected.guifont = "Comic Sans 12" screen:expect(function() eq(expected, screen.options) diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua index 87b489fd71..38c4527a5b 100644 --- a/test/functional/ui/output_spec.lua +++ b/test/functional/ui/output_spec.lua @@ -51,7 +51,8 @@ describe("shell command :!", function() end) it("throttles shell-command output greater than ~10KB", function() - if helpers.skip_fragile(pending) then + if helpers.skip_fragile(pending, + (os.getenv("TRAVIS") and helpers.os_name() == "osx")) then return end child_session.feed_data( diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 1e6ebb87f5..b457ebebab 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -50,7 +50,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=0, - anchor={1,0}, + anchor={1,1,0}, }} feed('<c-p>') @@ -66,7 +66,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=-1, - anchor={1,0}, + anchor={1,1,0}, }} -- down moves the selection in the menu, but does not insert anything @@ -83,7 +83,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=1, - anchor={1,0}, + anchor={1,1,0}, }} feed('<cr>') @@ -113,7 +113,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=0, - anchor={1,0}, + anchor={1,1,0}, }} meths.select_popupmenu_item(1,false,false,{}) @@ -129,7 +129,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=1, - anchor={1,0}, + anchor={1,1,0}, }} meths.select_popupmenu_item(2,true,false,{}) @@ -145,7 +145,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=2, - anchor={1,0}, + anchor={1,1,0}, }} meths.select_popupmenu_item(0,true,true,{}) @@ -174,7 +174,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=0, - anchor={1,0}, + anchor={1,1,0}, }} meths.select_popupmenu_item(-1,false,false,{}) @@ -190,7 +190,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=-1, - anchor={1,0}, + anchor={1,1,0}, }} meths.select_popupmenu_item(1,true,false,{}) @@ -206,7 +206,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=1, - anchor={1,0}, + anchor={1,1,0}, }} meths.select_popupmenu_item(-1,true,false,{}) @@ -222,7 +222,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=-1, - anchor={1,0}, + anchor={1,1,0}, }} meths.select_popupmenu_item(0,true,false,{}) @@ -238,7 +238,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=0, - anchor={1,0}, + anchor={1,1,0}, }} meths.select_popupmenu_item(-1,true,true,{}) @@ -269,7 +269,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=0, - anchor={1,0}, + anchor={1,1,0}, }} feed('<f1>') @@ -285,7 +285,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=2, - anchor={1,0}, + anchor={1,1,0}, }} feed('<f2>') @@ -301,7 +301,7 @@ describe('ui/ext_popupmenu', function() ]], popupmenu={ items=expected, pos=-1, - anchor={1,0}, + anchor={1,1,0}, }} feed('<f3>') @@ -366,6 +366,113 @@ describe('ui/ext_popupmenu', function() {2:-- INSERT --} | ]]) end) + + it('works with wildoptions=pum', function() + screen:try_resize(32,10) + command('set wildmenu') + command('set wildoptions=pum') + + local wild_expected = { + {'define', '', '', ''}, + {'jump', '', '', ''}, + {'list', '', '', ''}, + {'place', '', '', ''}, + {'undefine', '', '', ''}, + {'unplace', '', '', ''}, + } + + feed(':sign ') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign ^ | + ]]) + + feed('<tab>') + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign define^ | + ]], popupmenu={items=wild_expected, pos=0, anchor={1, 9, 6}}} + + feed('<left>') + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign ^ | + ]], popupmenu={items=wild_expected, pos=-1, anchor={1, 9, 6}}} + + feed('<left>') + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign unplace^ | + ]], popupmenu={items=wild_expected, pos=5, anchor={1, 9, 6}}} + + feed('x') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign unplacex^ | + ]]) + feed('<esc>') + + -- check positioning with multibyte char in pattern + command("e långfile1") + command("sp långfile2") + feed(':b lå<tab>') + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {4:långfile2 }| + | + {1:~ }| + {1:~ }| + {3:långfile1 }| + :b långfile1^ | + ]], popupmenu={ + anchor = {1, 9, 3}, + items = {{"långfile1", "", "", "" }, {"långfile2", "", "", ""}}, + pos = 0, + }} + end) end) @@ -1209,7 +1316,7 @@ describe('builtin popupmenu', function() ]]) meths.input_mouse('wheel', 'down', '', 0, 6, 15) - screen:expect([[ + screen:expect{grid=[[ choice^ | {1:~ }| {n:word }{1: }| @@ -1218,7 +1325,7 @@ describe('builtin popupmenu', function() {n:thing }{1: }| {3:[No Name] [+] }| {2:-- INSERT --} | - ]]) + ]], unchanged=true} end) it('works with kind, menu and abbr attributes', function() @@ -1273,6 +1380,131 @@ describe('builtin popupmenu', function() ]]) end) + it('works with wildoptions=pum', function() + screen:try_resize(32,10) + command('set wildmenu') + command('set wildoptions=pum') + + feed(':sign ') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign ^ | + ]]) + + feed('<tab>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{s: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign define^ | + ]]) + + feed('<left>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{n: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign ^ | + ]]) + + feed('<left>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{n: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{s: unplace }{1: }| + :sign unplace^ | + ]]) + + feed('x') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign unplacex^ | + ]]) + + feed('<esc>') + + -- check positioning with multibyte char in pattern + command("e långfile1") + command("sp långfile2") + feed(':b lå<tab>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {4:långfile2 }| + | + {1:~ }| + {1:~ }{s: långfile1 }{1: }| + {3:lå}{n: långfile2 }{3: }| + :b långfile1^ | + ]]) + + -- check doesn't crash on screen resize + screen:try_resize(20,6) + screen:expect([[ + | + {1:~ }| + {4:långfile2 }| + {s: långfile1 } | + {3:lå}{n: långfile2 }{3: }| + :b långfile1^ | + ]]) + + screen:try_resize(50,15) + screen:expect([[ + | + {1:~ }| + {4:långfile2 }| + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }{s: långfile1 }{1: }| + {3:lå}{n: långfile2 }{3: }| + :b långfile1^ | + ]]) + end) + it("'pumblend' RGB-color", function() screen:try_resize(60,14) screen:set_default_attr_ids({ diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 8b1b77eb81..a81851cbba 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -71,10 +71,10 @@ -- To help write screen tests, see Screen:snapshot_util(). -- To debug screen tests, see Screen:redraw_debug(). -local global_helpers = require('test.helpers') -local deepcopy = global_helpers.deepcopy -local shallowcopy = global_helpers.shallowcopy local helpers = require('test.functional.helpers')(nil) +local deepcopy = helpers.deepcopy +local shallowcopy = helpers.shallowcopy +local concat_tables = helpers.concat_tables local request, run_session = helpers.request, helpers.run_session local eq = helpers.eq local dedent = helpers.dedent @@ -259,22 +259,19 @@ local ext_keys = { 'messages', 'showmode', 'showcmd', 'ruler', 'float_pos', } --- Asserts that the screen state eventually matches an expected state +-- Asserts that the screen state eventually matches an expected state. -- --- This function can either be called with the positional forms --- --- screen:expect(grid, [attr_ids, attr_ignore]) --- screen:expect(condition) --- --- or to use additional arguments (or grid and condition at the same time) --- the keyword form has to be used: --- --- screen:expect{grid=[[...]], cmdline={...}, condition=function() ... end} +-- Can be called with positional args: +-- screen:expect(grid, [attr_ids, attr_ignore]) +-- screen:expect(condition) +-- or keyword args (supports more options): +-- screen:expect{grid=[[...]], cmdline={...}, condition=function() ... end} -- -- -- grid: Expected screen state (string). Each line represents a screen -- row. Last character of each row (typically "|") is stripped. -- Common indentation is stripped. +-- Lines containing only "{IGNORE}|" are skipped. -- attr_ids: Expected text attributes. Screen rows are transformed according -- to this table, as follows: each substring S composed of -- characters having the same attributes will be substituted by @@ -416,26 +413,23 @@ screen:redraw_debug() to show all intermediate screen states. ]]) end end - -- Extension features. The default expectations should cover the case of + -- UI extensions. The default expectations should cover the case of -- the ext_ feature being disabled, or the feature currently not activated - -- (for instance no external cmdline visible). Some extensions require + -- (e.g. no external cmdline visible). Some extensions require -- preprocessing to represent highlights in a reproducible way. local extstate = self:_extstate_repr(attr_state) - - -- convert assertion errors into invalid screen state descriptions - local status, res = pcall(function() - for _, k in ipairs(ext_keys) do - -- Empty states is considered the default and need not be mentioned - if not (expected[k] == nil and isempty(extstate[k])) then - eq(expected[k], extstate[k], k) + if expected['mode'] ~= nil then + extstate['mode'] = self.mode + end + -- Convert assertion errors into invalid screen state descriptions. + for _, k in ipairs(concat_tables(ext_keys, {'mode'})) do + -- Empty states are considered the default and need not be mentioned. + if (not (expected[k] == nil and isempty(extstate[k]))) then + local status, res = pcall(eq, expected[k], extstate[k], k) + if not status then + return (tostring(res)..'\nHint: full state of "'..k..'":\n '..inspect(extstate[k])) end end - if expected.mode ~= nil then - eq(expected.mode, self.mode, "mode") - end - end) - if not status then - return tostring(res) end end, expected) end @@ -937,10 +931,7 @@ function Screen:_handle_option_set(name, value) end function Screen:_handle_popupmenu_show(items, selected, row, col, grid) - if (not self._options.ext_multigrid) and grid == 1 then - grid = nil - end - self.popupmenu = {items=items, pos=selected, anchor={row, col, grid}} + self.popupmenu = {items=items, pos=selected, anchor={grid, row, col}} end function Screen:_handle_popupmenu_select(selected) diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua index a46670d8a2..65ae124353 100644 --- a/test/functional/ui/searchhl_spec.lua +++ b/test/functional/ui/searchhl_spec.lua @@ -163,12 +163,14 @@ describe('search highlighting', function() ]]) feed('/foo') sleep(50) -- Allow some terminal activity. - screen:expect([[ - {3:foo} bar baz {3:│}xxx | - bar baz {2:foo} {3:│}xxx | - bar {2:foo} baz {3:│}xxx | - {3:│}xxx | - {1:~ }{3:│}xxx | + -- NB: in earlier versions terminal output was redrawn during cmdline mode. + -- For now just assert that the screens remain unchanged. + screen:expect([[ + {3:foo} bar baz {3:│} | + bar baz {2:foo} {3:│} | + bar {2:foo} baz {3:│} | + {3:│} | + {1:~ }{3:│} | {5:[No Name] [+] }{3:term }| /foo^ | ]], { [1] = {bold = true, foreground = Screen.colors.Blue1}, diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua index bc0e2e3799..74019046c0 100644 --- a/test/functional/ui/sign_spec.lua +++ b/test/functional/ui/sign_spec.lua @@ -43,15 +43,15 @@ describe('Signs', function() {2: }b | {1:>>}c | {2: }^ | - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| | ]]) end) @@ -72,14 +72,14 @@ describe('Signs', function() {1:>>}b | {2: }c | {2: } | - {2: }{0:~ }| - {2: }{0:~ }| + {0:~ }| + {0:~ }| {4:[No Name] [+] }| {2: }{3:a }| {1:>>}b | {2: }c | {2: } | - {2: }{0:~ }| + {0:~ }| {5:[No Name] [+] }| | ]]) @@ -102,31 +102,140 @@ describe('Signs', function() {2: }{6: 2 }{8:b }| {2: }{7: 3 }c | {1:>>}{7: 4 }{8:^ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| | ]]) end) + it('multiple signs #9295', function() + feed('ia<cr>b<cr>c<cr><esc>') + command('set number') + command('set signcolumn=yes:2') + command('sign define pietSearch text=>> texthl=Search') + command('sign define pietError text=XX texthl=Error') + command('sign define pietWarn text=WW texthl=Warning') + command('sign place 1 line=1 name=pietSearch buffer=1') + command('sign place 2 line=1 name=pietError buffer=1') + -- Line 2 helps checking that signs in the same line are ordered by Id. + command('sign place 4 line=2 name=pietSearch buffer=1') + command('sign place 3 line=2 name=pietError buffer=1') + -- Line 3 checks that with a limit over the maximum number + -- of signs, the ones with the highest Ids are being picked, + -- and presented by their sorted Id order. + command('sign place 4 line=3 name=pietSearch buffer=1') + command('sign place 5 line=3 name=pietWarn buffer=1') + command('sign place 3 line=3 name=pietError buffer=1') + screen:expect([[ + {1:>>}XX{6: 1 }a | + XX{1:>>}{6: 2 }b | + {1:>>}WW{6: 3 }c | + {2: }{6: 4 }^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + -- With the default setting, we get the sign with the top id. + command('set signcolumn=yes:1') + screen:expect([[ + XX{6: 1 }a | + {1:>>}{6: 2 }b | + WW{6: 3 }c | + {2: }{6: 4 }^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + -- "auto:3" accommodates all the signs we defined so far. + command('set signcolumn=auto:3') + screen:expect([[ + {1:>>}XX{2: }{6: 1 }a | + XX{1:>>}{2: }{6: 2 }b | + XX{1:>>}WW{6: 3 }c | + {2: }{6: 4 }^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + -- Check "yes:9". + command('set signcolumn=yes:9') + screen:expect([[ + {1:>>}XX{2: }{6: 1 }a | + XX{1:>>}{2: }{6: 2 }b | + XX{1:>>}WW{2: }{6: 3 }c | + {2: }{6: 4 }^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + -- Check "auto:N" larger than the maximum number of signs defined in + -- a single line (same result as "auto:3"). + command('set signcolumn=auto:4') + screen:expect{grid=[[ + {1:>>}XX{2: }{6: 1 }a | + XX{1:>>}{2: }{6: 2 }b | + XX{1:>>}WW{6: 3 }c | + {2: }{6: 4 }^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]} + end) + it('can have 32bit sign IDs', function() command('sign define piet text=>> texthl=Search') command('sign place 100000 line=1 name=piet buffer=1') feed(':sign place<cr>') screen:expect([[ {1:>>} | - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| {4: }| :sign place | {9:--- Signs ---} | @@ -139,18 +248,18 @@ describe('Signs', function() feed('<cr>') screen:expect([[ {1:>>}^ | - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| - {2: }{0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| | ]]) end) diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua index 7cd09fb222..f4b80fd428 100644 --- a/test/functional/ui/wildmode_spec.lua +++ b/test/functional/ui/wildmode_spec.lua @@ -1,7 +1,6 @@ -local global_helpers = require('test.helpers') -local shallowcopy = global_helpers.shallowcopy local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') +local shallowcopy = helpers.shallowcopy local clear, feed, command = helpers.clear, helpers.feed, helpers.command local iswin = helpers.iswin local funcs = helpers.funcs @@ -29,8 +28,7 @@ describe("'wildmenu'", function() end it(':sign <tab> shows wildmenu completions', function() - command('set wildmode=full') - command('set wildmenu') + command('set wildmenu wildmode=full') feed(':sign <tab>') screen:expect([[ | @@ -96,10 +94,12 @@ describe("'wildmenu'", function() feed([[<C-\><C-N>gg]]) feed([[:sign <Tab>]]) -- Invoke wildmenu. + -- NB: in earlier versions terminal output was redrawn during cmdline mode. + -- For now just assert that the screen remains unchanged. expect_stay_unchanged{grid=[[ - foo | - foo | - foo | + | + | + | define jump list > | :sign define^ | ]]} @@ -201,14 +201,28 @@ describe('command line completion', function() ]]) end) + it('completes env var names #9681', function() + clear() + screen:attach() + command('let $XTEST_1 = "foo" | let $XTEST_2 = "bar"') + command('set wildmenu wildmode=full') + feed(':!echo $XTEST_<tab>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {2:XTEST_1}{3: XTEST_2 }| + :!echo $XTEST_1^ | + ]]) + end) + it('completes (multibyte) env var names #9655', function() clear({env={ ['XTEST_1AaあB']='foo', ['XTEST_2']='bar', }}) screen:attach() - command('set wildmode=full') - command('set wildmenu') + command('set wildmenu wildmode=full') feed(':!echo $XTEST_<tab>') screen:expect([[ | diff --git a/test/functional/viml/completion_spec.lua b/test/functional/viml/completion_spec.lua index cd1b312265..9d4cb325d9 100644 --- a/test/functional/viml/completion_spec.lua +++ b/test/functional/viml/completion_spec.lua @@ -904,9 +904,9 @@ describe('completion', function() | {8:[No Name] }| {0::}foo faa fee f^ | - {0::~ }| - {0::~ }| - {0::~ }| + {0:~ }| + {0:~ }| + {0:~ }| {9:[Command Line] }| {3:-- INSERT --} | ]] ) @@ -915,9 +915,9 @@ describe('completion', function() | {8:[No Name] }| {0::}foo faa fee foo^ | - {0::~ }{2: foo }{0: }| - {0::~ }{1: faa }{0: }| - {0::~ }{1: fee }{0: }| + {0:~ }{2: foo }{0: }| + {0:~ }{1: faa }{0: }| + {0:~ }{1: fee }{0: }| {9:[Command Line] }| {3:-- Keyword Local completion (^N^P) }{4:match 1 of 3} | ]]) @@ -926,9 +926,9 @@ describe('completion', function() | {8:[No Name] }| {0::}foo faa fee foo | - {0::~ }| - {0::~ }| - {0::~ }| + {0:~ }| + {0:~ }| + {0:~ }| {9:[Command Line] }| :foo faa fee foo^ | ]]) @@ -1072,4 +1072,83 @@ describe('completion', function() set complete&vim completeopt&vim ]]) end) + + it('CompleteChanged autocommand', function() + curbufmeths.set_lines(0, 1, false, { 'foo', 'bar', 'foobar', ''}) + source([[ + set complete=. completeopt=noinsert,noselect,menuone + function! OnPumChange() + let g:event = copy(v:event) + let g:item = get(v:event, 'completed_item', {}) + let g:word = get(g:item, 'word', v:null) + endfunction + autocmd! CompleteChanged * :call OnPumChange() + call cursor(4, 1) + ]]) + + feed('Sf<C-N>') + screen:expect([[ + foo | + bar | + foobar | + f^ | + {1:foo }{0: }| + {1:foobar }{0: }| + {0:~ }| + {3:-- Keyword completion (^N^P) }{5:Back at original} | + ]]) + eq({completed_item = {}, width = 15, + height = 2, size = 2, + col = 0, row = 4, scrollbar = false}, + eval('g:event')) + feed('<C-N>') + screen:expect([[ + foo | + bar | + foobar | + foo^ | + {2:foo }{0: }| + {1:foobar }{0: }| + {0:~ }| + {3:-- Keyword completion (^N^P) }{4:match 1 of 2} | + ]]) + eq('foo', eval('g:word')) + feed('<C-N>') + screen:expect([[ + foo | + bar | + foobar | + foobar^ | + {1:foo }{0: }| + {2:foobar }{0: }| + {0:~ }| + {3:-- Keyword completion (^N^P) }{4:match 2 of 2} | + ]]) + eq('foobar', eval('g:word')) + feed('<up>') + screen:expect([[ + foo | + bar | + foobar | + foobar^ | + {2:foo }{0: }| + {1:foobar }{0: }| + {0:~ }| + {3:-- Keyword completion (^N^P) }{4:match 1 of 2} | + ]]) + eq('foo', eval('g:word')) + feed('<down>') + screen:expect([[ + foo | + bar | + foobar | + foobar^ | + {1:foo }{0: }| + {2:foobar }{0: }| + {0:~ }| + {3:-- Keyword completion (^N^P) }{4:match 2 of 2} | + ]]) + eq('foobar', eval('g:word')) + feed('<esc>') + end) end) diff --git a/test/functional/viml/errorlist_spec.lua b/test/functional/viml/errorlist_spec.lua index 6c5a63e6b1..c5390cbd12 100644 --- a/test/functional/viml/errorlist_spec.lua +++ b/test/functional/viml/errorlist_spec.lua @@ -26,7 +26,7 @@ describe('setqflist()', function() it('sets w:quickfix_title', function() setqflist({''}, 'r', 'foo') command('copen') - eq(':foo', get_cur_win_var('quickfix_title')) + eq('foo', get_cur_win_var('quickfix_title')) setqflist({''}, 'r', {['title'] = 'qf_title'}) eq('qf_title', get_cur_win_var('quickfix_title')) end) @@ -34,7 +34,7 @@ describe('setqflist()', function() it('allows string {what} for backwards compatibility', function() setqflist({}, 'r', '5') command('copen') - eq(':5', get_cur_win_var('quickfix_title')) + eq('5', get_cur_win_var('quickfix_title')) end) it('requires a dict for {what}', function() @@ -64,8 +64,8 @@ describe('setloclist()', function() setloclist(1, {}, 'r', 'foo') setloclist(2, {}, 'r', 'bar') command('lopen') - eq(':bar', get_cur_win_var('quickfix_title')) + eq('bar', get_cur_win_var('quickfix_title')) command('lclose | wincmd w | lopen') - eq(':foo', get_cur_win_var('quickfix_title')) + eq('foo', get_cur_win_var('quickfix_title')) end) end) diff --git a/test/helpers.lua b/test/helpers.lua index 3a766b99f5..2a6285e685 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -1,8 +1,10 @@ require('vim.compat') +local shared = require('vim.shared') local assert = require('luassert') local luv = require('luv') local lfs = require('lfs') local relpath = require('pl.path').relpath +local Paths = require('test.config.paths') local quote_me = '[^.%w%+%-%@%_%/]' -- complement (needn't quote) local function shell_quote(str) @@ -235,6 +237,11 @@ local function hasenv(name) return nil end +local function deps_prefix() + local env = os.getenv('DEPS_PREFIX') + return (env and env ~= '') and env or '.deps/usr' +end + local tests_skipped = 0 local function check_cores(app, force) @@ -263,7 +270,7 @@ local function check_cores(app, force) else initial_path = '.' re = '/core[^/]*$' - exc_re = { '^/%.deps$', local_tmpdir, '^/%node_modules$' } + exc_re = { '^/%.deps$', '^/%'..deps_prefix()..'$', local_tmpdir, '^/%node_modules$' } db_cmd = gdb_db_cmd random_skip = true end @@ -329,30 +336,6 @@ local function shallowcopy(orig) return copy end -local deepcopy - -local function id(v) - return v -end - -local deepcopy_funcs = { - table = function(orig) - local copy = {} - for k, v in pairs(orig) do - copy[deepcopy(k)] = deepcopy(v) - end - return copy - end, - number = id, - string = id, - ['nil'] = id, - boolean = id, -} - -deepcopy = function(orig) - return deepcopy_funcs[type(orig)](orig) -end - local REMOVE_THIS = {} local function mergedicts_copy(d1, d2) @@ -415,6 +398,7 @@ local function updated(d, d2) return d end +-- Concat list-like tables. local function concat_tables(...) local ret = {} for i = 1, select('#', ...) do @@ -604,24 +588,6 @@ 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 - local function hexdump(str) local len = string.len(str) local dump = "" @@ -742,7 +708,6 @@ local module = { check_logs = check_logs, concat_tables = concat_tables, dedent = dedent, - deepcopy = deepcopy, dictdiff = dictdiff, eq = eq, expect_err = expect_err, @@ -770,7 +735,6 @@ local module = { repeated_read_cmd = repeated_read_cmd, shallowcopy = shallowcopy, sleep = sleep, - table_flatten = table_flatten, tmpname = tmpname, uname = uname, updated = updated, @@ -778,5 +742,6 @@ local module = { write_file = write_file, trim = trim, } +module = shared.tbl_extend('error', module, Paths, shared) return module diff --git a/test/symbolic/klee/nvim/keymap.c b/test/symbolic/klee/nvim/keymap.c index a341a73689..07eb4fa70a 100644 --- a/test/symbolic/klee/nvim/keymap.c +++ b/test/symbolic/klee/nvim/keymap.c @@ -165,6 +165,7 @@ static const struct key_name_entry { { K_DEL, "Del" }, { K_DEL, "Delete" }, // Alternative name { K_KDEL, "kDel" }, + { K_KDEL, "KPPeriod" }, // termkey KPPeriod value { K_UP, "Up" }, { K_DOWN, "Down" }, { K_LEFT, "Left" }, @@ -173,6 +174,14 @@ static const struct key_name_entry { { K_XDOWN, "xDown" }, { K_XLEFT, "xLeft" }, { K_XRIGHT, "xRight" }, + { K_KUP, "kUp" }, + { K_KUP, "KP8" }, + { K_KDOWN, "kDown" }, + { K_KDOWN, "KP2" }, + { K_KLEFT, "kLeft" }, + { K_KLEFT, "KP4" }, + { K_KRIGHT, "kRight" }, + { K_KRIGHT, "KP6" }, { K_F1, "F1" }, { K_F2, "F2" }, @@ -225,8 +234,10 @@ static const struct key_name_entry { { K_INS, "Insert" }, { K_INS, "Ins" }, // Alternative name { K_KINS, "kInsert" }, + { K_KINS, "KP0" }, { K_HOME, "Home" }, { K_KHOME, "kHome" }, + { K_KHOME, "KP7" }, { K_XHOME, "xHome" }, { K_ZHOME, "zHome" }, { K_END, "End" }, @@ -236,13 +247,22 @@ static const struct key_name_entry { { K_PAGEUP, "PageUp" }, { K_PAGEDOWN, "PageDown" }, { K_KPAGEUP, "kPageUp" }, + { K_KPAGEUP, "KP9" }, { K_KPAGEDOWN, "kPageDown" }, + { K_KPAGEDOWN, "KP3" }, + { K_KORIGIN, "kOrigin" }, + { K_KORIGIN, "KP5" }, { K_KPLUS, "kPlus" }, + { K_KPLUS, "KPPlus" }, { K_KMINUS, "kMinus" }, + { K_KMINUS, "KPMinus" }, { K_KDIVIDE, "kDivide" }, + { K_KDIVIDE, "KPDiv" }, { K_KMULTIPLY, "kMultiply" }, + { K_KMULTIPLY, "KPMult" }, { K_KENTER, "kEnter" }, + { K_KENTER, "KPEnter" }, { K_KPOINT, "kPoint" }, { K_K0, "k0" }, diff --git a/test/unit/eval/typval_spec.lua b/test/unit/eval/typval_spec.lua index 919a42fbb9..4535d6a0b2 100644 --- a/test/unit/eval/typval_spec.lua +++ b/test/unit/eval/typval_spec.lua @@ -1,7 +1,6 @@ local bit = require('bit') local helpers = require('test.unit.helpers')(after_each) local eval_helpers = require('test.unit.eval.helpers') -local global_helpers = require('test.helpers') local itp = helpers.gen_itp(it) @@ -14,6 +13,8 @@ local NULL = helpers.NULL local cimport = helpers.cimport local to_cstr = helpers.to_cstr local alloc_log_new = helpers.alloc_log_new +local concat_tables = helpers.concat_tables +local map = helpers.map local a = eval_helpers.alloc_logging_helpers local int = eval_helpers.int @@ -40,9 +41,6 @@ local callback2tbl = eval_helpers.callback2tbl local tbl2callback = eval_helpers.tbl2callback local dict_watchers = eval_helpers.dict_watchers -local concat_tables = global_helpers.concat_tables -local map = global_helpers.map - local lib = cimport('./src/nvim/eval/typval.h', './src/nvim/memory.h', './src/nvim/mbyte.h', './src/nvim/garray.h', './src/nvim/eval.h', './src/nvim/vim.h', diff --git a/test/unit/helpers.lua b/test/unit/helpers.lua index 1345fbce17..b5d3dd9f47 100644 --- a/test/unit/helpers.lua +++ b/test/unit/helpers.lua @@ -15,7 +15,6 @@ local dedent = global_helpers.dedent local neq = global_helpers.neq local map = global_helpers.map local eq = global_helpers.eq -local ok = global_helpers.ok local trim = global_helpers.trim -- C constants. @@ -839,9 +838,6 @@ local module = { cimport = cimport, cppimport = cppimport, internalize = internalize, - ok = ok, - eq = eq, - neq = neq, ffi = ffi, lib = lib, cstr = cstr, @@ -866,6 +862,7 @@ local module = { ptr2key = ptr2key, debug_log = debug_log, } +module = global_helpers.tbl_extend('error', module, global_helpers) return function() return module end diff --git a/test/unit/undo_spec.lua b/test/unit/undo_spec.lua index f23110b329..616c6fbe3d 100644 --- a/test/unit/undo_spec.lua +++ b/test/unit/undo_spec.lua @@ -2,9 +2,7 @@ local helpers = require('test.unit.helpers')(after_each) local itp = helpers.gen_itp(it) local lfs = require('lfs') local child_call_once = helpers.child_call_once - -local global_helpers = require('test.helpers') -local sleep = global_helpers.sleep +local sleep = helpers.sleep local ffi = helpers.ffi local cimport = helpers.cimport @@ -156,12 +154,12 @@ describe('u_write_undo', function() local file_contents = "testing permissions" -- Write a text file where the undofile should go local correct_name = ffi.string(undo.u_get_undo_file_name(file_buffer.b_ffname, false)) - global_helpers.write_file(correct_name, file_contents, true, false) + helpers.write_file(correct_name, file_contents, true, false) -- Call with `forceit`. u_write_undo(correct_name, true, file_buffer, buffer_hash) - local undo_file_contents = global_helpers.read_file(correct_name) + local undo_file_contents = helpers.read_file(correct_name) neq(file_contents, undo_file_contents) local success, deletion_err = os.remove(correct_name) -- delete the file now that we're done with it. diff --git a/test/unit/viml/expressions/lexer_spec.lua b/test/unit/viml/expressions/lexer_spec.lua index 1b57a24ad5..358e858d61 100644 --- a/test/unit/viml/expressions/lexer_spec.lua +++ b/test/unit/viml/expressions/lexer_spec.lua @@ -1,5 +1,4 @@ local helpers = require('test.unit.helpers')(after_each) -local global_helpers = require('test.helpers') local itp = helpers.gen_itp(it) local viml_helpers = require('test.unit.viml.helpers') @@ -8,6 +7,8 @@ local conv_enum = helpers.conv_enum local cimport = helpers.cimport local ffi = helpers.ffi local eq = helpers.eq +local shallowcopy = helpers.shallowcopy +local intchar2lua = helpers.intchar2lua local conv_ccs = viml_helpers.conv_ccs local new_pstate = viml_helpers.new_pstate @@ -15,9 +16,6 @@ local conv_cmp_type = viml_helpers.conv_cmp_type local pstate_set_str = viml_helpers.pstate_set_str local conv_expr_asgn_type = viml_helpers.conv_expr_asgn_type -local shallowcopy = global_helpers.shallowcopy -local intchar2lua = global_helpers.intchar2lua - local lib = cimport('./src/nvim/viml/parser/expressions.h') local eltkn_type_tab, eltkn_mul_type_tab, eltkn_opt_scope_tab diff --git a/test/unit/viml/expressions/parser_spec.lua b/test/unit/viml/expressions/parser_spec.lua index 73388e5dd2..a8f29529ec 100644 --- a/test/unit/viml/expressions/parser_spec.lua +++ b/test/unit/viml/expressions/parser_spec.lua @@ -1,5 +1,4 @@ local helpers = require('test.unit.helpers')(after_each) -local global_helpers = require('test.helpers') local itp = helpers.gen_itp(it) local viml_helpers = require('test.unit.viml.helpers') @@ -14,6 +13,11 @@ local cimport = helpers.cimport local ffi = helpers.ffi local neq = helpers.neq local eq = helpers.eq +local mergedicts_copy = helpers.mergedicts_copy +local format_string = helpers.format_string +local format_luav = helpers.format_luav +local intchar2lua = helpers.intchar2lua +local dictdiff = helpers.dictdiff local conv_ccs = viml_helpers.conv_ccs local new_pstate = viml_helpers.new_pstate @@ -21,12 +25,6 @@ local conv_cmp_type = viml_helpers.conv_cmp_type local pstate_set_str = viml_helpers.pstate_set_str local conv_expr_asgn_type = viml_helpers.conv_expr_asgn_type -local mergedicts_copy = global_helpers.mergedicts_copy -local format_string = global_helpers.format_string -local format_luav = global_helpers.format_luav -local intchar2lua = global_helpers.intchar2lua -local dictdiff = global_helpers.dictdiff - local lib = cimport('./src/nvim/viml/parser/expressions.h', './src/nvim/syntax.h') |