From c410440edcb438d1c7d090da24722fcbcb4e3b74 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 15 Sep 2019 17:28:42 -0700 Subject: fix api_level_6.mpack This was generated incorrectly in the 0.4.1 release, fixed in the 0.4.1 release. --- test/functional/fixtures/api_level_6.mpack | Bin 25194 -> 25287 bytes 1 file changed, 0 insertions(+), 0 deletions(-) (limited to 'test') diff --git a/test/functional/fixtures/api_level_6.mpack b/test/functional/fixtures/api_level_6.mpack index b348f86beb..1c939d5931 100644 Binary files a/test/functional/fixtures/api_level_6.mpack and b/test/functional/fixtures/api_level_6.mpack differ -- cgit From 4df38ec9df4764d4b2ae0b12c1b62c34889f1aa5 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 16 Sep 2019 19:16:39 +0200 Subject: server_requests_spec: fix assertion, pass Lua paths via args (#10875) This makes it pick up the nvim Luarocks module properly when not installed via third-party. --- test/functional/api/rpc_fixture.lua | 14 +++++--------- test/functional/api/server_requests_spec.lua | 16 ++++++++++++---- 2 files changed, 17 insertions(+), 13 deletions(-) (limited to 'test') diff --git a/test/functional/api/rpc_fixture.lua b/test/functional/api/rpc_fixture.lua index 87f5a91115..94df751363 100644 --- a/test/functional/api/rpc_fixture.lua +++ b/test/functional/api/rpc_fixture.lua @@ -1,12 +1,8 @@ -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;' .. - package.path - -package.cpath = deps_prefix .. '/lib/lua/5.1/?.so;' .. - package.cpath +--- RPC server fixture. +-- +-- Lua's paths are passed as arguments to reflect the path in the test itself. +package.path = arg[1] +package.cpath = arg[2] local mpack = require('mpack') local StdioStream = require('nvim.stdio_stream') diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index e275d8cd35..5a9ef7dd40 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -241,10 +241,14 @@ describe('server -> client', function() \ 'rpc': v:true \ } ]]) - meths.set_var("args", {helpers.test_lua_prg, - 'test/functional/api/rpc_fixture.lua'}) + meths.set_var("args", { + helpers.test_lua_prg, + 'test/functional/api/rpc_fixture.lua', + package.path, + package.cpath, + }) jobid = eval("jobstart(g:args, g:job_opts)") - neq(0, 'jobid') + neq(0, jobid) end) after_each(function() @@ -254,7 +258,11 @@ describe('server -> client', function() if helpers.pending_win32(pending) then return end it('rpc and text stderr can be combined', function() - eq("ok",funcs.rpcrequest(jobid, "poll")) + local status, rv = pcall(funcs.rpcrequest, jobid, 'poll') + if not status then + error(string.format('missing nvim Lua module? (%s)', rv)) + end + eq('ok', rv) funcs.rpcnotify(jobid, "ping") eq({'notification', 'pong', {}}, next_msg()) eq("done!",funcs.rpcrequest(jobid, "write_stderr", "fluff\n")) -- cgit From 4b2d7bb5eafde6edbbd55b563e8f73dba4165853 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 16 Sep 2019 19:17:07 +0200 Subject: tests: fix flaky 'scrollback' option deletes lines (only) if necessary (#11003) Using `screen:expect` with the complete grid appears to fix its flakiness. Fixes https://github.com/neovim/neovim/issues/10723. --- test/functional/terminal/scrollback_spec.lua | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua index 7413081510..ff6a74fe89 100644 --- a/test/functional/terminal/scrollback_spec.lua +++ b/test/functional/terminal/scrollback_spec.lua @@ -438,9 +438,29 @@ describe("'scrollback' option", function() command('sleep 100m') feed_data(nvim_dir.."/shell-test REP 41 line"..(iswin() and '\r' or '\n')) - screen:expect{any='40: line '} + if iswin() then + screen:expect{grid=[[ + 37: line | + 38: line | + 39: line | + 40: line | + | + ${1: } | + {3:-- TERMINAL --} | + ]]} + else + screen:expect{grid=[[ + 36: line | + 37: line | + 38: line | + 39: line | + 40: line | + {IGNORE}| + {3:-- TERMINAL --} | + ]]} + end + expect_lines(58) - retry(nil, nil, function() expect_lines(58) end) -- Verify off-screen state eq((iswin() and '36: line' or '35: line'), eval("getline(line('w0') - 1)")) eq((iswin() and '27: line' or '26: line'), eval("getline(line('w0') - 10)")) -- cgit From 0b71bb73e8431400c870dcd458f322dc50da96d1 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Tue, 17 Sep 2019 00:39:33 +0200 Subject: tests: improve error message with literat "~" directory (#11032) --- test/unit/os/fs_spec.lua | 2 +- test/unit/path_spec.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/unit/os/fs_spec.lua b/test/unit/os/fs_spec.lua index 526a09e845..7fd71cb1ae 100644 --- a/test/unit/os/fs_spec.lua +++ b/test/unit/os/fs_spec.lua @@ -110,7 +110,7 @@ describe('fs.c', function() describe('os_chdir', function() itp('fails with path="~"', function() - eq(false, os_isdir('~')) -- sanity check: no literal "~" directory. + eq(false, os_isdir('~'), 'sanity check: no literal "~" directory') local length = 4096 local expected_cwd = cstr(length, '') local cwd = cstr(length, '') diff --git a/test/unit/path_spec.lua b/test/unit/path_spec.lua index e8ce660ce1..da52af1bf9 100644 --- a/test/unit/path_spec.lua +++ b/test/unit/path_spec.lua @@ -456,7 +456,7 @@ describe('path.c', function() end) itp('fails and uses filename when the path is relative to HOME', function() - eq(false, cimp.os_isdir('~')) -- sanity check: no literal "~" directory. + eq(false, cimp.os_isdir('~'), 'sanity check: no literal "~" directory') local absolute_path = '~/home.file' local buflen = string.len(absolute_path) + 1 local do_expand = 1 -- cgit From 8db9e82e3e1aa094ca9224b01384da1b07fda410 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Mon, 16 Sep 2019 22:26:41 -0400 Subject: vim-patch:8.0.1770: assert functions don't return anything Problem: Assert functions don't return anything. Solution: Return non-zero when the assertion fails. https://github.com/vim/vim/commit/65a5464985f980d2bbbf4e14d39d416dce065ec7 --- test/functional/legacy/assert_spec.lua | 36 +++++++++++++++++----------------- 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'test') diff --git a/test/functional/legacy/assert_spec.lua b/test/functional/legacy/assert_spec.lua index 8df2d89b70..97c1f1405c 100644 --- a/test/functional/legacy/assert_spec.lua +++ b/test/functional/legacy/assert_spec.lua @@ -47,18 +47,18 @@ describe('assert function:', function() end) it('should not change v:errors when expected is equal to actual', function() - call('assert_equal', '', '') - call('assert_equal', 'string', 'string') + eq(0, call('assert_equal', '', '')) + eq(0, call('assert_equal', 'string', 'string')) expected_empty() end) it('should change v:errors when expected is not equal to actual', function() - call('assert_equal', 0, {0}) + eq(1, call('assert_equal', 0, {0})) expected_errors({'Expected 0 but got [0]'}) end) it('should change v:errors when expected is not equal to actual', function() - call('assert_equal', 0, "0") + eq(1, call('assert_equal', 0, "0")) expected_errors({"Expected 0 but got '0'"}) end) @@ -96,13 +96,13 @@ describe('assert function:', function() -- assert_notequal({expected}, {actual}[, {msg}]) describe('assert_notequal', function() it('should not change v:errors when expected differs from actual', function() - call('assert_notequal', 'foo', 4) - call('assert_notequal', {1, 2, 3}, 'foo') + eq(0, call('assert_notequal', 'foo', 4)) + eq(0, call('assert_notequal', {1, 2, 3}, 'foo')) expected_empty() end) it('should change v:errors when expected is equal to actual', function() - call('assert_notequal', 'foo', 'foo') + eq(1, call('assert_notequal', 'foo', 'foo')) expected_errors({"Expected not equal to 'foo'"}) end) end) @@ -110,13 +110,13 @@ describe('assert function:', function() -- assert_false({actual}, [, {msg}]) describe('assert_false', function() it('should not change v:errors when actual is false', function() - call('assert_false', 0) - call('assert_false', false) + eq(0, call('assert_false', 0)) + eq(0, call('assert_false', false)) expected_empty() end) it('should change v:errors when actual is not false', function() - call('assert_false', 1) + eq(1, call('assert_false', 1)) expected_errors({'Expected False but got 1'}) end) @@ -129,14 +129,14 @@ describe('assert function:', function() -- assert_true({actual}, [, {msg}]) describe('assert_true', function() it('should not change v:errors when actual is true', function() - call('assert_true', 1) - call('assert_true', -1) -- In Vim script, non-zero Numbers are TRUE. - call('assert_true', true) + eq(0, call('assert_true', 1)) + eq(0, call('assert_true', -1)) -- In Vim script, non-zero Numbers are TRUE. + eq(0, call('assert_true', true)) expected_empty() end) it('should change v:errors when actual is not true', function() - call('assert_true', 1.5) + eq(1, call('assert_true', 1.5)) expected_errors({'Expected True but got 1.5'}) end) end) @@ -277,7 +277,7 @@ describe('assert function:', function() -- assert_report({msg}) describe('assert_report()', function() it('should add a message to v:errors', function() - command("call assert_report('something is wrong')") + eq(1, call('assert_report', 'something is wrong')) command("call assert_match('something is wrong', v:errors[0])") command('call remove(v:errors, 0)') expected_empty() @@ -291,7 +291,7 @@ describe('assert function:', function() try nocommand catch - call assert_exception('E492') + call assert_equal(0, assert_exception('E492')) endtry ]]) expected_empty() @@ -304,9 +304,9 @@ describe('assert function:', function() catch try " illegal argument, get NULL for error - call assert_exception([]) + call assert_equal(1, assert_exception([])) catch - call assert_exception('E730') + call assert_equal(0, assert_exception('E730')) endtry endtry ]]) -- cgit From 1070c092c7bf989f261047b861165e61e94c1941 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Wed, 18 Sep 2019 18:22:38 +0200 Subject: win_update: fix redraw regression (#11027) Before 6e9ea5adc `win_ins_lines` would return `FAIL` for `i/line_count == 0`. Handle this by checking it in the outer `if`. Ref: https://github.com/neovim/neovim/commit/6e9ea5ad#commitcomment-35084669 --- test/functional/ui/diff_spec.lua | 74 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) (limited to 'test') diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua index 8eb2bbf779..572ed5c695 100644 --- a/test/functional/ui/diff_spec.lua +++ b/test/functional/ui/diff_spec.lua @@ -3,6 +3,8 @@ local Screen = require('test.functional.ui.screen') local feed = helpers.feed local clear = helpers.clear +local command = helpers.command +local insert = helpers.insert local write_file = helpers.write_file describe('Diff mode screen', function() @@ -957,3 +959,75 @@ int main(int argc, char **argv) end) end) end) + +it('win_update redraws lines properly', function() + local screen + clear() + screen = Screen.new(30, 10) + screen:attach() + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [3] = {background = Screen.colors.Red, foreground = Screen.colors.Grey100, special = Screen.colors.Yellow}, + [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, + [5] = {special = Screen.colors.Yellow}, + [6] = {special = Screen.colors.Yellow, bold = true, foreground = Screen.colors.SeaGreen4}, + [7] = {foreground = Screen.colors.Grey0, background = Screen.colors.Grey100}, + [8] = {foreground = Screen.colors.Gray90, background = Screen.colors.Grey100}, + [9] = {foreground = tonumber('0x00000c'), background = Screen.colors.Grey100}, + [10] = {background = Screen.colors.Grey100, bold = true, foreground = tonumber('0xe5e5ff')}, + [11] = {background = Screen.colors.Grey100, bold = true, foreground = tonumber('0x2b8452')}, + [12] = {bold = true, reverse = true}, + [13] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray}, + [14] = {reverse = true}, + [15] = {background = Screen.colors.LightBlue}, + [16] = {background = Screen.colors.LightCyan1, bold = true, foreground = Screen.colors.Blue1}, + [17] = {bold = true, background = Screen.colors.Red}, + [18] = {background = Screen.colors.LightMagenta}, + }) + + insert([[ + 1 + + + 2 + 1a + ]]) + command("vnew") + insert([[ + 2 + 2a + 2b + ]]) + command("windo diffthis") + command("windo 1") + screen:expect{grid=[[ + {13: }{16:-------}{14:│}{13: }{15:^1 }| + {13: }{16:-------}{14:│}{13: }{15: }| + {13: }{16:-------}{14:│}{13: }{15: }| + {13: }2 {14:│}{13: }2 | + {13: }{17:2}{18:a }{14:│}{13: }{17:1}{18:a }| + {13: }{15:2b }{14:│}{13: }{16:------------------}| + {13: } {14:│}{13: } | + {1:~ }{14:│}{1:~ }| + {14:') + feed('') + feed('') + feed('') + feed('') + screen:expect{grid=[[ + {13: }{16:-------}{14:│}{13: }{15:1 }| + {13: }{16:-------}{14:│}{13: }{15: }| + {13: }{16:-------}{14:│}{13: }{15:^ }| + {13: }2 {14:│}{13: }2 | + {13: }{17:2}{18:a }{14:│}{13: }{17:1}{18:a }| + {13: }{15:2b }{14:│}{13: }{16:------------------}| + {13: } {14:│}{13: } | + {1:~ }{14:│}{1:~ }| + {14: Date: Fri, 20 Sep 2019 09:37:43 +0200 Subject: screen: fix vcol counting with virtual text. Fixes #9941 --- test/functional/ui/bufhl_spec.lua | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'test') diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua index bcccef84b6..d8ca947645 100644 --- a/test/functional/ui/bufhl_spec.lua +++ b/test/functional/ui/bufhl_spec.lua @@ -31,6 +31,9 @@ describe('Buffer highlighting', function() [14] = {background = Screen.colors.Gray90}, [15] = {background = Screen.colors.Gray90, bold = true, foreground = Screen.colors.Brown}, [16] = {foreground = Screen.colors.Magenta, background = Screen.colors.Gray90}, + [17] = {foreground = Screen.colors.Magenta, background = Screen.colors.LightRed}, + [18] = {background = Screen.colors.LightRed}, + [19] = {foreground = Screen.colors.Blue1, background = Screen.colors.LightRed}, }) end) @@ -516,6 +519,32 @@ describe('Buffer highlighting', function() | ]]) end) + + it('works with color column', function() + eq(-1, set_virtual_text(-1, 3, {{"暗x事", "Comment"}}, {})) + screen:expect{grid=[[ + ^1 + 2 {3:=}{2: 3} | + 3 + {11:ERROR:} invalid syntax | + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| + , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s| + x = 4 {12:暗x事} | + {1:~ }| + {1:~ }| + | + ]]} + + command("set colorcolumn=9") + screen:expect{grid=[[ + ^1 + 2 {3:=}{2: }{17:3} | + 3 + {11:ERROR:} invalid syntax | + 5, 5, 5,{18: }5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| + , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s| + x = 4 {12:暗}{19:x}{12:事} | + {1:~ }| + {1:~ }| + | + ]]} + end) end) it('and virtual text use the same namespace counter', function() -- cgit From b3e56957f8e9468497e5db508d97d7b560ccfe85 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 21 Sep 2019 17:03:46 -0400 Subject: vim-patch:8.1.0460: assert_fails() message argument #11051 Problem: assert_fails() does not take a message argument Solution: Add the argument. https://github.com/vim/vim/commit/1307d1c003b01b4f67524c95feb07c3d91c7c428 --- test/functional/legacy/assert_spec.lua | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/test/functional/legacy/assert_spec.lua b/test/functional/legacy/assert_spec.lua index 97c1f1405c..3cb5d97869 100644 --- a/test/functional/legacy/assert_spec.lua +++ b/test/functional/legacy/assert_spec.lua @@ -3,6 +3,7 @@ local nvim, call = helpers.meths, helpers.call local clear, eq = helpers.clear, helpers.eq local source, command = helpers.source, helpers.command local exc_exec = helpers.exc_exec +local eval = helpers.eval local function expected_errors(errors) eq(errors, nvim.get_vvar('errors')) @@ -233,20 +234,31 @@ describe('assert function:', function() -- assert_fails({cmd}, [, {error}]) describe('assert_fails', function() it('should change v:errors when error does not match v:errmsg', function() - command([[call assert_fails('xxx', {})]]) + eq(1, eval([[assert_fails('xxx', {})]])) command([[call assert_match("Expected {} but got 'E731:", v:errors[0])]]) expected_errors({"Expected {} but got 'E731: using Dictionary as a String'"}) end) it('should not change v:errors when cmd errors', function() - call('assert_fails', 'NonexistentCmd') + eq(0, eval([[assert_fails('NonexistentCmd')]])) expected_empty() end) it('should change v:errors when cmd succeeds', function() - call('assert_fails', 'call empty("")') + eq(1, eval([[assert_fails('call empty("")', '')]])) expected_errors({'command did not fail: call empty("")'}) end) + + it('can specify and get a message about what failed', function() + eq(1, eval([[assert_fails('xxx', {}, 'stupid')]])) + command([[call assert_match("stupid: Expected {} but got 'E731:", v:errors[0])]]) + expected_errors({"stupid: Expected {} but got 'E731: using Dictionary as a String'"}) + end) + + it('can specify and get a message even when cmd succeeds', function() + eq(1, eval([[assert_fails('echo', '', 'echo command')]])) + expected_errors({'command did not fail: echo command'}) + end) end) -- assert_inrange({lower}, {upper}, {actual}[, {msg}]) -- cgit From 18e5869f56aab8a52d84185e5bd043799c36ae2d Mon Sep 17 00:00:00 2001 From: Zach Wegner Date: Sun, 15 Sep 2019 14:16:44 -0500 Subject: Fix "precedes" listchar behavior in wrap mode Previously, the "precedes" character would be rendered on every row when w_skipcol > 0 (i.e., when viewing a single line longer than the entire screen), instead of just on the first row. Make sure to only render it on the first row in this case. Add a test for this behavior. Fix documentation for the "precedes" character, which erroneously stated that it was only active when wrap mode was off. --- test/functional/ui/highlight_spec.lua | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'test') diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index f40f658275..95a19aec81 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -657,6 +657,30 @@ describe("'listchars' highlight", function() ]]) end) + it("'listchar' with wrap", function() + screen:set_default_attr_ids({ + [0] = {bold=true, foreground=Screen.colors.Blue}, + }) + feed_command('set wrap') + feed_command('set listchars=eol:¬,precedes:< list') + feed('90ia') + screen:expect([[ + {0:<}aaaaaaaaaaaaaaaaaaa| + aaaaaaaaaaaaaaaaaaaa| + aaaaaaaaaaaaaaaaaaaa| + aaaaaaaaa^a{0:¬} | + | + ]]) + feed('0') + screen:expect([[ + ^aaaaaaaaaaaaaaaaaaaa| + aaaaaaaaaaaaaaaaaaaa| + aaaaaaaaaaaaaaaaaaaa| + aaaaaaaaaaaaaaaaaaaa| + | + ]]) + end) + it("'listchar' in visual mode", function() screen:set_default_attr_ids({ [1] = {background=Screen.colors.Grey90}, -- cgit From f316916758c487054138762d66a966430e38e612 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Tue, 17 Sep 2019 20:26:43 +0200 Subject: screen: missing redraw/highlight for ruler in message area --- test/functional/ui/messages_spec.lua | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'test') diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index 875e4092a6..377d49c036 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -810,6 +810,7 @@ describe('ui/builtin messages', function() [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, [5] = {foreground = Screen.colors.Blue1}, [6] = {bold = true, foreground = Screen.colors.Magenta}, + [7] = {background = Screen.colors.Grey20}, }) end) @@ -902,6 +903,41 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim meths.command_output('syntax list vimComment')) -- luacheck: pop end) + + it('supports ruler with laststatus=0', function() + command("set ruler laststatus=0") + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + 0,0-1 All | + ]]} + + command("hi MsgArea guibg=#333333") + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {7: 0,0-1 All }| + ]]} + + command("set rulerformat=%15(%c%V\\ %p%%%)") + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {7: 0,0-1 100% }| + ]]} + end) end) describe('ui/ext_messages', function() -- cgit From ed11721b6bb36042ab065b5045c8eb01115b8902 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 22 Sep 2019 14:57:44 +0200 Subject: tests: unit: fix preprocess: pass -m32 for 32bit ABI (#11073) --- test/unit/preprocess.lua | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'test') diff --git a/test/unit/preprocess.lua b/test/unit/preprocess.lua index 1073855a7d..3786bc2122 100644 --- a/test/unit/preprocess.lua +++ b/test/unit/preprocess.lua @@ -89,6 +89,10 @@ local Gcc = { get_defines_extra_flags = {'-std=c99', '-dM', '-E'}, get_declarations_extra_flags = {'-std=c99', '-P', '-E'}, } +if ffi.abi("32bit") then + table.insert(Gcc.get_defines_extra_flags, '-m32') + table.insert(Gcc.get_declarations_extra_flags, '-m32') +end function Gcc:define(name, args, val) local define = '-D' .. name -- cgit From 6807779c68220e738b99486118c97c0ebc108b0e Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 22 Sep 2019 14:58:38 +0200 Subject: tests: make 'win_update redraws lines properly' more readable (#11068) --- test/functional/ui/diff_spec.lua | 44 ++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'test') diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua index 572ed5c695..252991aca7 100644 --- a/test/functional/ui/diff_spec.lua +++ b/test/functional/ui/diff_spec.lua @@ -963,7 +963,7 @@ end) it('win_update redraws lines properly', function() local screen clear() - screen = Screen.new(30, 10) + screen = Screen.new(50, 10) screen:attach() screen:set_default_attr_ids({ [1] = {bold = true, foreground = Screen.colors.Blue1}, @@ -993,7 +993,7 @@ it('win_update redraws lines properly', function() 2 1a ]]) - command("vnew") + command("vnew left") insert([[ 2 2a @@ -1002,16 +1002,16 @@ it('win_update redraws lines properly', function() command("windo diffthis") command("windo 1") screen:expect{grid=[[ - {13: }{16:-------}{14:│}{13: }{15:^1 }| - {13: }{16:-------}{14:│}{13: }{15: }| - {13: }{16:-------}{14:│}{13: }{15: }| - {13: }2 {14:│}{13: }2 | - {13: }{17:2}{18:a }{14:│}{13: }{17:1}{18:a }| - {13: }{15:2b }{14:│}{13: }{16:------------------}| - {13: } {14:│}{13: } | - {1:~ }{14:│}{1:~ }| - {14:') feed('') @@ -1019,15 +1019,15 @@ it('win_update redraws lines properly', function() feed('') feed('') screen:expect{grid=[[ - {13: }{16:-------}{14:│}{13: }{15:1 }| - {13: }{16:-------}{14:│}{13: }{15: }| - {13: }{16:-------}{14:│}{13: }{15:^ }| - {13: }2 {14:│}{13: }2 | - {13: }{17:2}{18:a }{14:│}{13: }{17:1}{18:a }| - {13: }{15:2b }{14:│}{13: }{16:------------------}| - {13: } {14:│}{13: } | - {1:~ }{14:│}{1:~ }| - {14: Date: Tue, 24 Sep 2019 08:35:29 +0200 Subject: tui_spec: improve "TUI paste: exactly 64 bytes" (#11086) Doing the screen test first might give insights about a possible (flaky?) failure, where it looks like "feed_data" is processed out of order: [ ERROR ] test/functional/terminal/tui_spec.lua @ 561: TUI paste: exactly 64 bytes #10311 test/functional/helpers.lua:388: retry() attempts: 490 test/functional/terminal/tui_spec.lua:66: Expected objects to be the same. Passed in: (table: 0x44042de8) { *[1] = ' endzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' } Expected: (table: 0x41d6e568) { *[1] = 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz end' } stack traceback: test/functional/helpers.lua:388: in function 'retry' test/functional/terminal/tui_spec.lua:63: in function 'expect_child_buf_lines' test/functional/terminal/tui_spec.lua:569: in function Ref: https://github.com/neovim/neovim/pull/11083#issuecomment-534375201 Build log: https://travis-ci.org/neovim/neovim/jobs/588749739#L5597 --- test/functional/terminal/tui_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index c55093cb0f..f70b630442 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -566,7 +566,6 @@ describe('TUI', function() feed_data('\027[200~'..expected..'\027[201~') feed_data(' end') expected = expected..' end' - expect_child_buf_lines({expected}) screen:expect([[ zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz| zzzzzzzzzzzzzz end{1: } | @@ -576,6 +575,7 @@ describe('TUI', function() {3:-- INSERT --} | {3:-- TERMINAL --} | ]]) + expect_child_buf_lines({expected}) end) it('paste: big burst of input', function() -- cgit From 0ab7da8561bfcc4c644afb9cf48083a5696c1792 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Tue, 24 Sep 2019 08:55:27 +0200 Subject: timer_spec: fix/harden flaky tests (#11080) Those are flaky when using luacov (which causes reproducible slowness). E.g.: [ ERROR ] test/functional\eval\timer_spec.lua @ 105: timers can invoke redraw in blocking getchar() call test\functional\ui\screen.lua:587: Row 3 did not match. Expected: |ITEM 1 | |ITEM 2 | |*{1:~ }| |{1:~ }| |{1:~ }| |^ | Actual: |ITEM 1 | |ITEM 2 | |*ITEM 3 | |{1:~ }| |{1:~ }| |^ | --- test/functional/eval/timer_spec.lua | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/test/functional/eval/timer_spec.lua b/test/functional/eval/timer_spec.lua index 2ccb9cfbac..ef7df69fdb 100644 --- a/test/functional/eval/timer_spec.lua +++ b/test/functional/eval/timer_spec.lua @@ -111,7 +111,13 @@ describe('timers', function() curbufmeths.set_lines(0, -1, true, {"ITEM 1", "ITEM 2"}) source([[ + let g:cont = 0 func! AddItem(timer) + if !g:cont + return + endif + call timer_stop(a:timer) + call nvim_buf_set_lines(0, 2, 2, v:true, ['ITEM 3']) " Meant to test for what Vim tests in Test_peek_and_get_char. @@ -121,7 +127,7 @@ describe('timers', function() endfunc ]]) nvim_async("command", "let g:c2 = getchar()") - nvim_async("command", "call timer_start("..load_adjust(100)..", 'AddItem')") + nvim_async("command", "call timer_start("..load_adjust(100)..", 'AddItem', {'repeat': -1})") screen:expect([[ ITEM 1 | @@ -131,6 +137,7 @@ describe('timers', function() {1:~ }| ^ | ]]) + nvim_async("command", "let g:cont = 1") screen:expect([[ ITEM 1 | @@ -222,12 +229,17 @@ describe('timers', function() source([[ let g:val = 0 func! MyHandler(timer) + while !g:val + return + endwhile + call timer_stop(a:timer) + echo "evil" redraw - let g:val = 1 + let g:val = 2 endfunc ]]) - command("call timer_start(100, 'MyHandler', {'repeat': 1})") + command("call timer_start(100, 'MyHandler', {'repeat': -1})") feed(":good") screen:expect([[ | @@ -237,6 +249,7 @@ describe('timers', function() {0:~ }| :good^ | ]]) + command('let g:val = 1') screen:expect{grid=[[ | @@ -247,6 +260,6 @@ describe('timers', function() :good^ | ]], intermediate=true, timeout=load_adjust(200)} - eq(1, eval('g:val')) + eq(2, eval('g:val')) end) end) -- cgit From db6b4b677d611a2891a5b6d686e485aea08a8f81 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Wed, 25 Sep 2019 02:20:32 +0200 Subject: tests: busted: nvim handler: display durations always (#11075) This shows them also with test failures/errors, where it is useful to see how long the test took (for flaky failures running into timeout). --- test/busted/outputHandlers/nvim.lua | 44 ++++++++++--------------------------- 1 file changed, 11 insertions(+), 33 deletions(-) (limited to 'test') diff --git a/test/busted/outputHandlers/nvim.lua b/test/busted/outputHandlers/nvim.lua index 1b500fc999..8f3aad776e 100644 --- a/test/busted/outputHandlers/nvim.lua +++ b/test/busted/outputHandlers/nvim.lua @@ -227,8 +227,12 @@ return function(options) return nil, true end + local function write_status(element, string) + io.write(timeString:format(getElapsedTime(element)) .. ' ' .. string) + io.flush() + end + handler.testEnd = function(element, _parent, status, _debug) - local elapsedTime_ms = getElapsedTime(element) local string fileTestCount = fileTestCount + 1 @@ -241,45 +245,21 @@ return function(options) string = skippedString elseif status == 'failure' then failureCount = failureCount + 1 - string = nil + string = failureString .. failureDescription(handler.failures[#handler.failures]) elseif status == 'error' then errorCount = errorCount + 1 - string = nil - end - - if string ~= nil then - if elapsedTime_ms == elapsedTime_ms then - string = timeString:format(elapsedTime_ms) .. ' ' .. string - end - io.write(string) - io.flush() + string = errorString .. failureDescription(handler.errors[#handler.errors]) + else + string = "unexpected test status! ("..status..")" end + write_status(element, string) return nil, true end - handler.testFailure = function(_element, _parent, _message, _debug) - io.write(failureString) - io.flush() - - io.write(failureDescription(handler.failures[#handler.failures])) - io.flush() - return nil, true - end - - handler.testError = function(_element, _parent, _message, _debug) - io.write(errorString) - io.flush() - - io.write(failureDescription(handler.errors[#handler.errors])) - io.flush() - return nil, true - end - handler.error = function(element, _parent, _message, _debug) if element.descriptor ~= 'it' then - io.write(failureDescription(handler.errors[#handler.errors])) - io.flush() + write_status(element, failureDescription(handler.errors[#handler.errors])) errorCount = errorCount + 1 end @@ -293,8 +273,6 @@ return function(options) busted.subscribe({ 'file', 'end' }, handler.fileEnd) busted.subscribe({ 'test', 'start' }, handler.testStart, { predicate = handler.cancelOnPending }) busted.subscribe({ 'test', 'end' }, handler.testEnd, { predicate = handler.cancelOnPending }) - busted.subscribe({ 'failure', 'it' }, handler.testFailure) - busted.subscribe({ 'error', 'it' }, handler.testError) busted.subscribe({ 'failure' }, handler.error) busted.subscribe({ 'error' }, handler.error) -- cgit From bb6b1267e7532e0c2e065c4e9b5552623062c70f Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Wed, 11 Sep 2019 13:48:09 +0200 Subject: Revert "win/os_env_exists(): workaround libuv bug #10734" This reverts commit 278c5d452c2cbc436a9cc317407ae6021a226c3a. --- test/functional/eval/environ_spec.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'test') diff --git a/test/functional/eval/environ_spec.lua b/test/functional/eval/environ_spec.lua index 4c2adcf1bf..54d2dc960b 100644 --- a/test/functional/eval/environ_spec.lua +++ b/test/functional/eval/environ_spec.lua @@ -10,6 +10,7 @@ describe('environment variables', function() eq("", environ()['EMPTY_VAR']) eq(nil, environ()['DOES_NOT_EXIST']) end) + it('exists() handles empty env variable', function() clear({env={EMPTY_VAR=""}}) eq(1, exists('$EMPTY_VAR')) -- cgit From 70827ea1fa3db6cb221b8c50677e1a6524937a5c Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Wed, 11 Sep 2019 13:47:23 +0200 Subject: test/functional/preload.lua: _set_fmode for Windows --- test/functional/preload.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'test') diff --git a/test/functional/preload.lua b/test/functional/preload.lua index 1107b45d54..24a3977e6b 100644 --- a/test/functional/preload.lua +++ b/test/functional/preload.lua @@ -2,3 +2,13 @@ -- Busted started doing this to help provide more isolation. See issue #62 -- for more information about this. local helpers = require('test.functional.helpers')(nil) +local iswin = helpers.iswin + +if iswin() then + local ffi = require('ffi') + ffi.cdef[[ + typedef int errno_t; + errno_t _set_fmode(int mode); + ]] + ffi.C._set_fmode(0x8000) +end -- cgit From 0571145c40b0a2ae106acc43891c2680c76b8383 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Wed, 25 Sep 2019 09:15:33 +0200 Subject: paste: fix handling of "<" in cmdline (#11094) Fixes https://github.com/neovim/neovim/issues/11088. --- test/functional/terminal/tui_spec.lua | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'test') diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index f70b630442..89468359ef 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -578,6 +578,23 @@ describe('TUI', function() expect_child_buf_lines({expected}) end) + it('paste: less-than sign in cmdline #11088', function() + local expected = '<' + feed_data(':') + wait_for_mode('c') + -- "bracketed paste" + feed_data('\027[200~'..expected..'\027[201~') + screen:expect{grid=[[ + | + {4:~ }| + {4:~ }| + {4:~ }| + {5:[No Name] }| + :<{1: } | + {3:-- TERMINAL --} | + ]]} + end) + it('paste: big burst of input', function() feed_data(':set ruler\n') local t = {} -- cgit From cb252071718a58c2d9747177ebeb81ff1210ddd1 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 17 Jun 2019 22:35:07 +0200 Subject: vim-patch:8.0.0914: highlight attributes are always combined (#10256) Problem: Highlight attributes are always combined. Solution: Add the 'nocombine' value to replace attributes instead of combining them. (scauligi, closes vim/vim#1963) https://github.com/vim/vim/commit/0cd2a94a4030f6bd12eaec44db92db108e33c913 Closes https://github.com/neovim/neovim/pull/10256. --- test/functional/ui/highlight_spec.lua | 48 +++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'test') diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index 95a19aec81..1b25570997 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -438,6 +438,54 @@ describe('highlight', function() }) end) + it('nocombine', function() + screen:detach() + screen = Screen.new(25,6) + screen:set_default_attr_ids{ + [1] = {foreground = Screen.colors.SlateBlue, underline = true}, + [2] = {bold = true, foreground = Screen.colors.Blue1}, + [3] = {underline = true, reverse = true, foreground = Screen.colors.SlateBlue}, + [4] = {background = Screen.colors.Yellow, reverse = true, foreground = Screen.colors.SlateBlue}, + [5] = {foreground = Screen.colors.Red}, + } + screen:attach() + feed_command('syntax on') + feed_command('hi! Underlined cterm=underline gui=underline') + feed_command('syn keyword Underlined foobar') + feed_command('hi Search cterm=inverse,nocombine gui=inverse,nocombine') + insert([[ + foobar + foobar + ]]) + screen:expect{grid=[[ + {1:foobar} | + {1:foobar} | + ^ | + {2:~ }| + {2:~ }| + | + ]]} + + feed('/foo') + screen:expect{grid=[[ + {3:foo}{1:bar} | + {4:foo}{1:bar} | + | + {2:~ }| + {2:~ }| + /foo^ | + ]]} + feed('') + screen:expect{grid=[[ + {4:^foo}{1:bar} | + {4:foo}{1:bar} | + | + {2:~ }| + {2:~ }| + {5:search hit...uing at TOP} | + ]]} + end) + it('guisp (special/undercurl)', function() feed_command('syntax on') feed_command('syn keyword TmpKeyword neovim') -- cgit From b52ae0e8ba04498b0dd6de2e2947a45057111b3c Mon Sep 17 00:00:00 2001 From: John Szakmeister Date: Sun, 1 Sep 2019 12:13:34 -0400 Subject: build: add support for building for FreeBSD under Sourcehut [skip ci] --- test/helpers.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/helpers.lua b/test/helpers.lua index ebc0a7d811..30e43a9ea4 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -715,11 +715,14 @@ end function module.isCI(name) local any = (name == nil) - assert(any or name == 'appveyor' or name == 'quickbuild' or name == 'travis') + assert(any or name == 'appveyor' or name == 'quickbuild' or name == 'travis' + or name == 'sourcehut') local av = ((any or name == 'appveyor') and nil ~= os.getenv('APPVEYOR')) local tr = ((any or name == 'travis') and nil ~= os.getenv('TRAVIS')) local qb = ((any or name == 'quickbuild') and nil ~= lfs.attributes('/usr/home/quickbuild')) - return tr or av or qb + local sh = ((any or name == 'sourcehut') and nil ~= os.getenv('SOURCEHUT')) + return tr or av or qb or sh + end -- Gets the contents of $NVIM_LOG_FILE for printing to the build log. -- cgit From 54c66e636aa7c9f9379c0028e62c7d6d617f691c Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 26 Sep 2019 07:37:51 +0200 Subject: Fix two more flaky tests (#11095) * mode_spec: retry with increasing matchtime `matchtime=2` might still be too low (with luacov on AppVeyor). [ ERROR ] test/functional\ui\mode_spec.lua @ 47: ui mode_change event works in insert mode test\functional\ui\screen.lua:587: mode Expected objects to be the same. Passed in: (string) 'insert' Expected: (string) 'showmatch' Hint: full state of "mode": "insert" Followup to fe60013fb. ref #10941 Initially regressed in 7ed212262242 `` * ui/screen_basic_spec: set timeoutlen=10000 This fixes the test on slow CI. Ref: https://ci.appveyor.com/project/neovim/neovim/builds/27600387/job/t468h2b3w9lwtlm5#L10930 --- test/functional/ui/mode_spec.lua | 53 ++++++++++++++++++-------------- test/functional/ui/screen_basic_spec.lua | 1 + 2 files changed, 31 insertions(+), 23 deletions(-) (limited to 'test') diff --git a/test/functional/ui/mode_spec.lua b/test/functional/ui/mode_spec.lua index 200f6eecdb..9390f268b3 100644 --- a/test/functional/ui/mode_spec.lua +++ b/test/functional/ui/mode_spec.lua @@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen') local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local command = helpers.command +local retry = helpers.retry describe('ui mode_change event', function() local screen @@ -61,30 +62,36 @@ describe('ui mode_change event', function() | ]], mode="normal"} + local matchtime = 0 command("set showmatch") - command("set matchtime=2") -- tenths of seconds - feed('a(stuff') - screen:expect{grid=[[ - word(stuff^ | - {0:~ }| - {0:~ }| - {2:-- INSERT --} | - ]], mode="insert"} - - feed(')') - screen:expect{grid=[[ - word^(stuff) | - {0:~ }| - {0:~ }| - {2:-- INSERT --} | - ]], mode="showmatch"} - - screen:expect{grid=[[ - word(stuff)^ | - {0:~ }| - {0:~ }| - {2:-- INSERT --} | - ]], mode="insert"} + retry(nil, nil, function() + matchtime = matchtime + 1 + local screen_timeout = 1000 * matchtime -- fail faster for retry. + + command("set matchtime=" .. matchtime) -- tenths of seconds + feed('a(stuff') + screen:expect{grid=[[ + word(stuff^ | + {0:~ }| + {0:~ }| + {2:-- INSERT --} | + ]], mode="insert", timeout=screen_timeout} + + feed(')') + screen:expect{grid=[[ + word^(stuff) | + {0:~ }| + {0:~ }| + {2:-- INSERT --} | + ]], mode="showmatch", timeout=screen_timeout} + + screen:expect{grid=[[ + word(stuff)^ | + {0:~ }| + {0:~ }| + {2:-- INSERT --} | + ]], mode="insert", timeout=screen_timeout} + end) end) it('works in replace mode', function() diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua index 46f0b5060c..150ee2a103 100644 --- a/test/functional/ui/screen_basic_spec.lua +++ b/test/functional/ui/screen_basic_spec.lua @@ -915,6 +915,7 @@ local function screen_tests(linegrid) -- Regression test for #8357 it('does not have artifacts after temporary chars in insert mode', function() + command('set timeoutlen=10000') command('inoremap jk ') feed('ifooj') screen:expect([[ -- cgit From 4ea5e63aa8c866b4fcc9d10f1a26078d2517f96a Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 9 Jun 2019 13:26:48 +0200 Subject: tree-sitter: add basic testing on ci build tree-sitter c parser on ci for testing purposes --- test/functional/lua/tree_sitter_spec.lua | 67 ++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 test/functional/lua/tree_sitter_spec.lua (limited to 'test') diff --git a/test/functional/lua/tree_sitter_spec.lua b/test/functional/lua/tree_sitter_spec.lua new file mode 100644 index 0000000000..e25eb47a60 --- /dev/null +++ b/test/functional/lua/tree_sitter_spec.lua @@ -0,0 +1,67 @@ +-- Test suite for testing interactions with API bindings +local helpers = require('test.functional.helpers')(after_each) + +local meths = helpers.meths +local clear = helpers.clear +local eq = helpers.eq +local insert = helpers.insert +local meth_pcall = helpers.meth_pcall +local exec_lua = helpers.exec_lua +local iswin = helpers.iswin + +before_each(clear) + +describe('tree-sitter API', function() + -- error tests not requiring a parser library + it('handles basic errors', function() + --eq({false, 'Error executing lua: vim.schedule: expected function'}, + -- meth_pcall(meths.execute_lua, "parser = vim.tree_sitter.create_parser(0, 'nosuchlang')", {})) + + + + end) + + local ts_path = os.getenv("TREE_SITTER_DIR") + + describe('with C parser', function() + if ts_path == nil then + it("works", function() pending("TREE_SITTER_PATH not set, skipping tree-sitter parser tests") end) + return + end + + before_each(function() + -- TODO the .so/.dylib/.dll thingie + local path = ts_path .. '/bin/c'..(iswin() and '.dll' or '.so') + exec_lua([[ + local path = ... + vim.tree_sitter.add_language(path,'c') + + ]], path) + end) + + it('parses buffer', function() + insert([[ + int main() { + int x = 3; + }]]) + + exec_lua([[ + parser = vim.tree_sitter.create_parser(0, "c") + tree = parser:parse_tree() + root = tree:root() + ]]) + + --eq("", exec_lua("return tostring(parser)")) + eq("", exec_lua("return tostring(tree)")) + eq("", exec_lua("return tostring(root)")) + eq({0,0,3,0}, exec_lua("return {root:range()}")) + + eq(1, exec_lua("return root:child_count()")) + exec_lua("child = root:child(0)") + eq("", exec_lua("return tostring(child)")) + eq({0,0,2,1}, exec_lua("return {child:range()}")) + end) + + end) +end) + -- cgit From c8f861b739b4703b1198dc1f88b09edbeb0d9f2e Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 15 Jun 2019 12:10:12 +0200 Subject: tree-sitter: rename tree_sitter => treesitter for consistency --- test/functional/lua/tree_sitter_spec.lua | 67 -------------------------------- test/functional/lua/treesitter_spec.lua | 67 ++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 67 deletions(-) delete mode 100644 test/functional/lua/tree_sitter_spec.lua create mode 100644 test/functional/lua/treesitter_spec.lua (limited to 'test') diff --git a/test/functional/lua/tree_sitter_spec.lua b/test/functional/lua/tree_sitter_spec.lua deleted file mode 100644 index e25eb47a60..0000000000 --- a/test/functional/lua/tree_sitter_spec.lua +++ /dev/null @@ -1,67 +0,0 @@ --- Test suite for testing interactions with API bindings -local helpers = require('test.functional.helpers')(after_each) - -local meths = helpers.meths -local clear = helpers.clear -local eq = helpers.eq -local insert = helpers.insert -local meth_pcall = helpers.meth_pcall -local exec_lua = helpers.exec_lua -local iswin = helpers.iswin - -before_each(clear) - -describe('tree-sitter API', function() - -- error tests not requiring a parser library - it('handles basic errors', function() - --eq({false, 'Error executing lua: vim.schedule: expected function'}, - -- meth_pcall(meths.execute_lua, "parser = vim.tree_sitter.create_parser(0, 'nosuchlang')", {})) - - - - end) - - local ts_path = os.getenv("TREE_SITTER_DIR") - - describe('with C parser', function() - if ts_path == nil then - it("works", function() pending("TREE_SITTER_PATH not set, skipping tree-sitter parser tests") end) - return - end - - before_each(function() - -- TODO the .so/.dylib/.dll thingie - local path = ts_path .. '/bin/c'..(iswin() and '.dll' or '.so') - exec_lua([[ - local path = ... - vim.tree_sitter.add_language(path,'c') - - ]], path) - end) - - it('parses buffer', function() - insert([[ - int main() { - int x = 3; - }]]) - - exec_lua([[ - parser = vim.tree_sitter.create_parser(0, "c") - tree = parser:parse_tree() - root = tree:root() - ]]) - - --eq("", exec_lua("return tostring(parser)")) - eq("", exec_lua("return tostring(tree)")) - eq("", exec_lua("return tostring(root)")) - eq({0,0,3,0}, exec_lua("return {root:range()}")) - - eq(1, exec_lua("return root:child_count()")) - exec_lua("child = root:child(0)") - eq("", exec_lua("return tostring(child)")) - eq({0,0,2,1}, exec_lua("return {child:range()}")) - end) - - end) -end) - diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua new file mode 100644 index 0000000000..8916e59563 --- /dev/null +++ b/test/functional/lua/treesitter_spec.lua @@ -0,0 +1,67 @@ +-- Test suite for testing interactions with API bindings +local helpers = require('test.functional.helpers')(after_each) + +local meths = helpers.meths +local clear = helpers.clear +local eq = helpers.eq +local insert = helpers.insert +local meth_pcall = helpers.meth_pcall +local exec_lua = helpers.exec_lua +local iswin = helpers.iswin + +before_each(clear) + +describe('tree-sitter API', function() + -- error tests not requiring a parser library + it('handles basic errors', function() + --eq({false, 'Error executing lua: vim.schedule: expected function'}, + -- meth_pcall(meths.execute_lua, "parser = vim.treesitter.create_parser(0, 'nosuchlang')", {})) + + + + end) + + local ts_path = os.getenv("TREE_SITTER_DIR") + + describe('with C parser', function() + if ts_path == nil then + it("works", function() pending("TREE_SITTER_PATH not set, skipping tree-sitter parser tests") end) + return + end + + before_each(function() + -- TODO the .so/.dylib/.dll thingie + local path = ts_path .. '/bin/c'..(iswin() and '.dll' or '.so') + exec_lua([[ + local path = ... + vim.treesitter.add_language(path,'c') + + ]], path) + end) + + it('parses buffer', function() + insert([[ + int main() { + int x = 3; + }]]) + + exec_lua([[ + parser = vim.treesitter.create_parser(0, "c") + tree = parser:parse_tree() + root = tree:root() + ]]) + + --eq("", exec_lua("return tostring(parser)")) + eq("", exec_lua("return tostring(tree)")) + eq("", exec_lua("return tostring(root)")) + eq({0,0,3,0}, exec_lua("return {root:range()}")) + + eq(1, exec_lua("return root:child_count()")) + exec_lua("child = root:child(0)") + eq("", exec_lua("return tostring(child)")) + eq({0,0,2,1}, exec_lua("return {child:range()}")) + end) + + end) +end) + -- cgit From 167a1cfdef0c4b3526830ad0356f06bf480df6af Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Mon, 17 Jun 2019 21:46:31 +0200 Subject: tree-sitter: improve parser API (shared parser between plugins) --- test/functional/lua/treesitter_spec.lua | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index 8916e59563..f3f7f4fd0a 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -8,6 +8,7 @@ local insert = helpers.insert local meth_pcall = helpers.meth_pcall local exec_lua = helpers.exec_lua local iswin = helpers.iswin +local feed = helpers.feed before_each(clear) @@ -46,12 +47,11 @@ describe('tree-sitter API', function() }]]) exec_lua([[ - parser = vim.treesitter.create_parser(0, "c") - tree = parser:parse_tree() + parser = vim.treesitter.get_parser(0, "c") + tree = parser:parse() root = tree:root() ]]) - --eq("", exec_lua("return tostring(parser)")) eq("", exec_lua("return tostring(tree)")) eq("", exec_lua("return tostring(root)")) eq({0,0,3,0}, exec_lua("return {root:range()}")) @@ -60,6 +60,27 @@ describe('tree-sitter API', function() exec_lua("child = root:child(0)") eq("", exec_lua("return tostring(child)")) eq({0,0,2,1}, exec_lua("return {child:range()}")) + + exec_lua("descendant = root:descendant_for_point_range(1,2,1,12)") + eq("", exec_lua("return tostring(descendant)")) + eq({1,2,1,12}, exec_lua("return {descendant:range()}")) + eq("(declaration (primitive_type) (init_declarator (identifier) (number_literal)))", exec_lua("return descendant:sexpr()")) + + feed("2G7|ay") + exec_lua([[ + tree2 = parser:parse() + root2 = tree2:root() + descendant2 = root2:descendant_for_point_range(1,2,1,13) + ]]) + eq(false, exec_lua("return tree2 == tree1")) + eq("", exec_lua("return tostring(descendant2)")) + eq({1,2,1,13}, exec_lua("return {descendant2:range()}")) + + -- orginal tree did not change + eq({1,2,1,12}, exec_lua("return {descendant:range()}")) + + -- unchanged buffer: return the same tree + eq(true, exec_lua("return parser:parse() == tree2")) end) end) -- cgit From 06ee45b9b1c14c7ce6cb23403cdbe2852d495cad Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Fri, 21 Jun 2019 14:14:51 +0200 Subject: tree-sitter: fix lint, delete "demo" plugin (replaced by functional tests) --- test/functional/lua/treesitter_spec.lua | 2 -- 1 file changed, 2 deletions(-) (limited to 'test') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index f3f7f4fd0a..5aaaa80868 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -1,11 +1,9 @@ -- Test suite for testing interactions with API bindings local helpers = require('test.functional.helpers')(after_each) -local meths = helpers.meths local clear = helpers.clear local eq = helpers.eq local insert = helpers.insert -local meth_pcall = helpers.meth_pcall local exec_lua = helpers.exec_lua local iswin = helpers.iswin local feed = helpers.feed -- cgit From e0d6228978dd1389f75a3e0351f6e6d5625643ae Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 21 Sep 2019 10:10:47 +0200 Subject: tree-sitter: use "range" instead of "point_range" consistently in lua API --- test/functional/lua/treesitter_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index 5aaaa80868..d566f15649 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -59,7 +59,7 @@ describe('tree-sitter API', function() eq("", exec_lua("return tostring(child)")) eq({0,0,2,1}, exec_lua("return {child:range()}")) - exec_lua("descendant = root:descendant_for_point_range(1,2,1,12)") + exec_lua("descendant = root:descendant_for_range(1,2,1,12)") eq("", exec_lua("return tostring(descendant)")) eq({1,2,1,12}, exec_lua("return {descendant:range()}")) eq("(declaration (primitive_type) (init_declarator (identifier) (number_literal)))", exec_lua("return descendant:sexpr()")) @@ -68,7 +68,7 @@ describe('tree-sitter API', function() exec_lua([[ tree2 = parser:parse() root2 = tree2:root() - descendant2 = root2:descendant_for_point_range(1,2,1,13) + descendant2 = root2:descendant_for_range(1,2,1,13) ]]) eq(false, exec_lua("return tree2 == tree1")) eq("", exec_lua("return tostring(descendant2)")) -- cgit From d5a69eb07648a515d03aa5c9e268aef852015ea9 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 22 Sep 2019 11:33:55 +0200 Subject: tree-sitter: handle node equality --- test/functional/lua/treesitter_spec.lua | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'test') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index d566f15649..8e21faca12 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -64,6 +64,13 @@ describe('tree-sitter API', function() eq({1,2,1,12}, exec_lua("return {descendant:range()}")) eq("(declaration (primitive_type) (init_declarator (identifier) (number_literal)))", exec_lua("return descendant:sexpr()")) + eq(true, exec_lua("return child == child")) + -- separate lua object, but represents same node + eq(true, exec_lua("return child == root:child(0)")) + eq(false, exec_lua("return child == descendant2")) + eq(false, exec_lua("return child == nil")) + eq(false, exec_lua("return child == tree")) + feed("2G7|ay") exec_lua([[ tree2 = parser:parse() @@ -71,6 +78,7 @@ describe('tree-sitter API', function() descendant2 = root2:descendant_for_range(1,2,1,13) ]]) eq(false, exec_lua("return tree2 == tree1")) + eq(false, exec_lua("return root2 == root")) eq("", exec_lua("return tostring(descendant2)")) eq({1,2,1,13}, exec_lua("return {descendant2:range()}")) -- cgit From 9fa850991dbe8984996afdc149b5b32dc248197e Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 28 Sep 2019 09:32:55 +0200 Subject: tree-sitter: improve and cleanup tests --- test/functional/lua/treesitter_spec.lua | 73 +++++++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 9 deletions(-) (limited to 'test') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index 8e21faca12..700e4599f2 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -7,34 +7,40 @@ local insert = helpers.insert local exec_lua = helpers.exec_lua local iswin = helpers.iswin local feed = helpers.feed +local pcall_err = helpers.pcall_err +local matches = helpers.matches before_each(clear) -describe('tree-sitter API', function() +describe('treesitter API', function() -- error tests not requiring a parser library - it('handles basic errors', function() - --eq({false, 'Error executing lua: vim.schedule: expected function'}, - -- meth_pcall(meths.execute_lua, "parser = vim.treesitter.create_parser(0, 'nosuchlang')", {})) + it('handles missing language', function() + local path_pat = 'Error executing lua: '..(iswin() and '.+\\vim\\' or '.+/vim/') + matches(path_pat..'treesitter.lua:39: no such language: borklang', + pcall_err(exec_lua, "parser = vim.treesitter.create_parser(0, 'borklang')")) + -- actual message depends on platform + matches('Error executing lua: Failed to load parser: uv_dlopen: .+', + pcall_err(exec_lua, "parser = vim.treesitter.add_language('borkbork.so', 'borklang')")) + eq('Error executing lua: [string ""]:1: no such language: borklang', + pcall_err(exec_lua, "parser = vim.treesitter.inspect_language('borklang')")) end) local ts_path = os.getenv("TREE_SITTER_DIR") describe('with C parser', function() if ts_path == nil then - it("works", function() pending("TREE_SITTER_PATH not set, skipping tree-sitter parser tests") end) + it("works", function() pending("TREE_SITTER_PATH not set, skipping treesitter parser tests") end) return end before_each(function() - -- TODO the .so/.dylib/.dll thingie local path = ts_path .. '/bin/c'..(iswin() and '.dll' or '.so') exec_lua([[ local path = ... vim.treesitter.add_language(path,'c') - ]], path) end) @@ -48,6 +54,7 @@ describe('tree-sitter API', function() parser = vim.treesitter.get_parser(0, "c") tree = parser:parse() root = tree:root() + lang = vim.treesitter.inspect_language('c') ]]) eq("", exec_lua("return tostring(tree)")) @@ -59,10 +66,21 @@ describe('tree-sitter API', function() eq("", exec_lua("return tostring(child)")) eq({0,0,2,1}, exec_lua("return {child:range()}")) + eq("function_definition", exec_lua("return child:type()")) + eq(true, exec_lua("return child:named()")) + eq("number", type(exec_lua("return child:symbol()"))) + eq({'function_definition', true}, exec_lua("return lang.symbols[child:symbol()]")) + + exec_lua("anon = root:descendant_for_range(0,8,0,9)") + eq("(", exec_lua("return anon:type()")) + eq(false, exec_lua("return anon:named()")) + eq("number", type(exec_lua("return anon:symbol()"))) + eq({'(', false}, exec_lua("return lang.symbols[anon:symbol()]")) + exec_lua("descendant = root:descendant_for_range(1,2,1,12)") eq("", exec_lua("return tostring(descendant)")) eq({1,2,1,12}, exec_lua("return {descendant:range()}")) - eq("(declaration (primitive_type) (init_declarator (identifier) (number_literal)))", exec_lua("return descendant:sexpr()")) + eq("(declaration type: (primitive_type) declarator: (init_declarator declarator: (identifier) value: (number_literal)))", exec_lua("return descendant:sexpr()")) eq(true, exec_lua("return child == child")) -- separate lua object, but represents same node @@ -89,6 +107,43 @@ describe('tree-sitter API', function() eq(true, exec_lua("return parser:parse() == tree2")) end) + it('inspects language', function() + local keys, fields, symbols = unpack(exec_lua([[ + local lang = vim.treesitter.inspect_language('c') + local keys, symbols = {}, {} + for k,_ in pairs(lang) do + keys[k] = true + end + + -- symbols array can have "holes" and is thus not a valid msgpack array + -- but we don't care about the numbers here (checked in the parser test) + for _, v in pairs(lang.symbols) do + table.insert(symbols, v) + end + return {keys, lang.fields, symbols} + ]])) + + eq({fields=true, symbols=true}, keys) + + local fset = {} + for _,f in pairs(fields) do + eq("string", type(f)) + fset[f] = true + end + eq(true, fset["directive"]) + eq(true, fset["initializer"]) + + local has_named, has_anonymous + for _,s in pairs(symbols) do + eq("string", type(s[1])) + eq("boolean", type(s[2])) + if s[1] == "for_statement" and s[2] == true then + has_named = true + elseif s[1] == "|=" and s[2] == false then + has_anonymous = true + end + end + eq({true,true}, {has_named,has_anonymous}) + end) end) end) - -- cgit From 0636b25f28e408c8b16026354db7edfef079614a Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 28 Sep 2019 21:00:27 +0200 Subject: cmdline: wildmenumode() should be true with wildoptions+=pum --- test/functional/ui/popupmenu_spec.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'test') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index ae2136f451..37eb550835 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -516,6 +516,7 @@ describe('ui/ext_popupmenu', function() {1:~ }| :sign ^ | ]]) + eq(0, funcs.wildmenumode()) feed('') screen:expect{grid=[[ @@ -530,6 +531,7 @@ describe('ui/ext_popupmenu', function() {1:~ }| :sign define^ | ]], popupmenu={items=wild_expected, pos=0, anchor={1, 9, 6}}} + eq(1, funcs.wildmenumode()) feed('') screen:expect{grid=[[ @@ -589,6 +591,7 @@ describe('ui/ext_popupmenu', function() :sign unplace^ | ]], popupmenu={items=wild_expected, pos=5, anchor={1, 9, 6}}} feed('') + eq(0, funcs.wildmenumode()) -- check positioning with multibyte char in pattern command("e långfile1") -- cgit From dd26bd59745c9fd358624312feb315ec0f106de8 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 1 Sep 2019 11:13:13 +0200 Subject: screen: don't crash on invalid grid cells being recomposed --- test/functional/helpers.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index b29161e34c..bd36bac062 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -38,7 +38,7 @@ module.nvim_prog = ( module.nvim_set = ( 'set shortmess+=IS background=light noswapfile noautoindent' ..' laststatus=1 undodir=. directory=. viewdir=. backupdir=.' - ..' belloff= wildoptions-=pum noshowcmd noruler nomore') + ..' belloff= wildoptions-=pum noshowcmd noruler nomore redrawdebug=invalid') module.nvim_argv = { module.nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', module.nvim_set, '--embed'} -- cgit From 8a4ae3d664a22cfaa3ec05635d26a8d662458c7e Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 30 Sep 2019 22:00:55 +0200 Subject: tui: improve handle_background_color: short-circuit (#11067) * handle_background_color: short-circuit if handled already * Unit tests for handle_background_color * set waiting_for_bg_response to false in tui_terminal_after_startup By then it should have been received. --- test/functional/terminal/tui_spec.lua | 74 +----------------- test/unit/tui_spec.lua | 139 ++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+), 70 deletions(-) create mode 100644 test/unit/tui_spec.lua (limited to 'test') diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 89468359ef..ed904f27ca 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -1376,7 +1376,6 @@ describe('TUI background color', function() end) it("handles deferred background color", function() - local last_bg = 'dark' local function wait_for_bg(bg) -- Retry until the terminal response is handled. retry(100, nil, function() @@ -1394,76 +1393,11 @@ describe('TUI background color', function() ]], bg) }) end) - last_bg = bg end - local function assert_bg(colorspace, color, bg) - -- Ensure the opposite of the expected bg is active. - local other_bg = (bg == 'dark' and 'light' or 'dark') - if last_bg ~= other_bg then - feed_data(other_bg == 'light' and '\027]11;rgb:f/f/f\007' - or '\027]11;rgb:0/0/0\007') - wait_for_bg(other_bg) - end - - feed_data('\027]11;'..colorspace..':'..color..'\007') - wait_for_bg(bg) - end - - assert_bg('rgb', '0000/0000/0000', 'dark') - assert_bg('rgb', 'ffff/ffff/ffff', 'light') - assert_bg('rgb', '000/000/000', 'dark') - assert_bg('rgb', 'fff/fff/fff', 'light') - assert_bg('rgb', '00/00/00', 'dark') - assert_bg('rgb', 'ff/ff/ff', 'light') - assert_bg('rgb', '0/0/0', 'dark') - assert_bg('rgb', 'f/f/f', 'light') - - assert_bg('rgb', 'f/0/0', 'dark') - assert_bg('rgb', '0/f/0', 'light') - assert_bg('rgb', '0/0/f', 'dark') - - assert_bg('rgb', '1/1/1', 'dark') - assert_bg('rgb', '2/2/2', 'dark') - assert_bg('rgb', '3/3/3', 'dark') - assert_bg('rgb', '4/4/4', 'dark') - assert_bg('rgb', '5/5/5', 'dark') - assert_bg('rgb', '6/6/6', 'dark') - assert_bg('rgb', '7/7/7', 'dark') - assert_bg('rgb', '8/8/8', 'light') - assert_bg('rgb', '9/9/9', 'light') - assert_bg('rgb', 'a/a/a', 'light') - assert_bg('rgb', 'b/b/b', 'light') - assert_bg('rgb', 'c/c/c', 'light') - assert_bg('rgb', 'd/d/d', 'light') - assert_bg('rgb', 'e/e/e', 'light') - - assert_bg('rgb', '0/e/0', 'light') - assert_bg('rgb', '0/d/0', 'light') - assert_bg('rgb', '0/c/0', 'dark') - assert_bg('rgb', '0/b/0', 'dark') - - assert_bg('rgb', 'f/0/f', 'dark') - assert_bg('rgb', 'f/1/f', 'dark') - assert_bg('rgb', 'f/2/f', 'dark') - assert_bg('rgb', 'f/3/f', 'light') - assert_bg('rgb', 'f/4/f', 'light') - - assert_bg('rgba', '0000/0000/0000/0000', 'dark') - assert_bg('rgba', '0000/0000/0000/ffff', 'dark') - assert_bg('rgba', 'ffff/ffff/ffff/0000', 'light') - assert_bg('rgba', 'ffff/ffff/ffff/ffff', 'light') - assert_bg('rgba', '000/000/000/000', 'dark') - assert_bg('rgba', '000/000/000/fff', 'dark') - assert_bg('rgba', 'fff/fff/fff/000', 'light') - assert_bg('rgba', 'fff/fff/fff/fff', 'light') - assert_bg('rgba', '00/00/00/00', 'dark') - assert_bg('rgba', '00/00/00/ff', 'dark') - assert_bg('rgba', 'ff/ff/ff/00', 'light') - assert_bg('rgba', 'ff/ff/ff/ff', 'light') - assert_bg('rgba', '0/0/0/0', 'dark') - assert_bg('rgba', '0/0/0/f', 'dark') - assert_bg('rgba', 'f/f/f/0', 'light') - assert_bg('rgba', 'f/f/f/f', 'light') + -- Only single integration test. + -- See test/unit/tui_spec.lua for unit tests. + feed_data('\027]11;rgb:ffff/ffff/ffff\007') + wait_for_bg('light') end) end) diff --git a/test/unit/tui_spec.lua b/test/unit/tui_spec.lua new file mode 100644 index 0000000000..47dbd87b71 --- /dev/null +++ b/test/unit/tui_spec.lua @@ -0,0 +1,139 @@ +local helpers = require("test.unit.helpers")(after_each) +local cimport = helpers.cimport +local eq = helpers.eq +local ffi = helpers.ffi +local itp = helpers.gen_itp(it) +local to_cstr = helpers.to_cstr + +local cinput = cimport("./src/nvim/tui/input.h") +local rbuffer = cimport("./test/unit/fixtures/rbuffer.h") +local globals = cimport("./src/nvim/globals.h") +local multiqueue = cimport("./test/unit/fixtures/multiqueue.h") + +itp('handle_background_color', function() + local handle_background_color = cinput.ut_handle_background_color + local term_input = ffi.new('TermInput', {}) + local events = globals.main_loop.thread_events + + -- Short-circuit when not waiting for response. + term_input.waiting_for_bg_response = false + eq(false, handle_background_color(term_input)) + + local capacity = 100 + local rbuf = ffi.gc(rbuffer.rbuffer_new(capacity), rbuffer.rbuffer_free) + term_input.read_stream.buffer = rbuf + + local function assert_bg(colorspace, color, bg) + local term_response = '\027]11;'..colorspace..':'..color..'\007' + rbuffer.rbuffer_write(rbuf, to_cstr(term_response), #term_response) + + term_input.waiting_for_bg_response = true + eq(true, handle_background_color(term_input)) + eq(false, term_input.waiting_for_bg_response) + eq(1, multiqueue.multiqueue_size(events)) + + local event = multiqueue.multiqueue_get(events) + local bg_event = ffi.cast("Event*", event.argv[1]) + eq(bg, ffi.string(bg_event.argv[0])) + + -- Buffer has been consumed. + eq(0, rbuf.size) + end + + assert_bg('rgb', '0000/0000/0000', 'dark') + assert_bg('rgb', 'ffff/ffff/ffff', 'light') + assert_bg('rgb', '000/000/000', 'dark') + assert_bg('rgb', 'fff/fff/fff', 'light') + assert_bg('rgb', '00/00/00', 'dark') + assert_bg('rgb', 'ff/ff/ff', 'light') + assert_bg('rgb', '0/0/0', 'dark') + assert_bg('rgb', 'f/f/f', 'light') + + assert_bg('rgb', 'f/0/0', 'dark') + assert_bg('rgb', '0/f/0', 'light') + assert_bg('rgb', '0/0/f', 'dark') + + assert_bg('rgb', '1/1/1', 'dark') + assert_bg('rgb', '2/2/2', 'dark') + assert_bg('rgb', '3/3/3', 'dark') + assert_bg('rgb', '4/4/4', 'dark') + assert_bg('rgb', '5/5/5', 'dark') + assert_bg('rgb', '6/6/6', 'dark') + assert_bg('rgb', '7/7/7', 'dark') + assert_bg('rgb', '8/8/8', 'light') + assert_bg('rgb', '9/9/9', 'light') + assert_bg('rgb', 'a/a/a', 'light') + assert_bg('rgb', 'b/b/b', 'light') + assert_bg('rgb', 'c/c/c', 'light') + assert_bg('rgb', 'd/d/d', 'light') + assert_bg('rgb', 'e/e/e', 'light') + + assert_bg('rgb', '0/e/0', 'light') + assert_bg('rgb', '0/d/0', 'light') + assert_bg('rgb', '0/c/0', 'dark') + assert_bg('rgb', '0/b/0', 'dark') + + assert_bg('rgb', 'f/0/f', 'dark') + assert_bg('rgb', 'f/1/f', 'dark') + assert_bg('rgb', 'f/2/f', 'dark') + assert_bg('rgb', 'f/3/f', 'light') + assert_bg('rgb', 'f/4/f', 'light') + + assert_bg('rgba', '0000/0000/0000/0000', 'dark') + assert_bg('rgba', '0000/0000/0000/ffff', 'dark') + assert_bg('rgba', 'ffff/ffff/ffff/0000', 'light') + assert_bg('rgba', 'ffff/ffff/ffff/ffff', 'light') + assert_bg('rgba', '000/000/000/000', 'dark') + assert_bg('rgba', '000/000/000/fff', 'dark') + assert_bg('rgba', 'fff/fff/fff/000', 'light') + assert_bg('rgba', 'fff/fff/fff/fff', 'light') + assert_bg('rgba', '00/00/00/00', 'dark') + assert_bg('rgba', '00/00/00/ff', 'dark') + assert_bg('rgba', 'ff/ff/ff/00', 'light') + assert_bg('rgba', 'ff/ff/ff/ff', 'light') + assert_bg('rgba', '0/0/0/0', 'dark') + assert_bg('rgba', '0/0/0/f', 'dark') + assert_bg('rgba', 'f/f/f/0', 'light') + assert_bg('rgba', 'f/f/f/f', 'light') + + + -- Incomplete sequence: not necessarily correct behavior, but tests it. + local term_response = '\027]11;rgba:f/f/f/f' -- missing '\007 + rbuffer.rbuffer_write(rbuf, to_cstr(term_response), #term_response) + + term_input.waiting_for_bg_response = true + eq(true, term_input.waiting_for_bg_response) + eq(false, handle_background_color(term_input)) + eq(false, term_input.waiting_for_bg_response) + + eq(0, multiqueue.multiqueue_size(events)) + eq(0, rbuf.size) + + + -- Does nothing when not at start of buffer. + term_response = '123\027]11;rgba:f/f/f/f\007456' + rbuffer.rbuffer_write(rbuf, to_cstr(term_response), #term_response) + + term_input.waiting_for_bg_response = true + eq(true, term_input.waiting_for_bg_response) + eq(false, handle_background_color(term_input)) + eq(true, term_input.waiting_for_bg_response) + + eq(0, multiqueue.multiqueue_size(events)) + eq(#term_response, rbuf.size) + rbuffer.rbuffer_consumed(rbuf, #term_response) + + + -- Keeps trailing buffer. + term_response = '\027]11;rgba:f/f/f/f\007456' + rbuffer.rbuffer_write(rbuf, to_cstr(term_response), #term_response) + + term_input.waiting_for_bg_response = true + eq(true, term_input.waiting_for_bg_response) + eq(true, handle_background_color(term_input)) + eq(false, term_input.waiting_for_bg_response) + + eq(1, multiqueue.multiqueue_size(events)) + eq(3, rbuf.size) + rbuffer.rbuffer_consumed(rbuf, rbuf.size) +end) -- cgit From b7d6caaa036c3d1be716bb6e4b0f56c08fb8dcf5 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Wed, 2 Oct 2019 03:51:46 +0200 Subject: Fix redraw regression with w_p_cole in visual mode Fixes https://github.com/neovim/neovim/issues/11024, regressed in 23c71d51. Closes https://github.com/neovim/neovim/pull/11120. --- test/functional/ui/syntax_conceal_spec.lua | 46 ++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'test') diff --git a/test/functional/ui/syntax_conceal_spec.lua b/test/functional/ui/syntax_conceal_spec.lua index 00e94ef94b..7079b43414 100644 --- a/test/functional/ui/syntax_conceal_spec.lua +++ b/test/functional/ui/syntax_conceal_spec.lua @@ -17,6 +17,7 @@ describe('Screen', function() [3] = {reverse = true}, [4] = {bold = true}, [5] = {background = Screen.colors.Yellow}, + [6] = {background = Screen.colors.LightGrey}, } ) end) @@ -823,5 +824,50 @@ describe('Screen', function() ]]) end) end) + + it('redraws properly with concealcursor in visual mode', function() + command('set concealcursor=v conceallevel=2') + + feed('10Ofoo barf bar barf eggs') + feed(':3o aggV') + screen:expect{grid=[[ + ^f{6:oo }{1:b}{6: bar }{1:b}{6: eggs} | + foo {1:b} bar {1:b} eggs | + foo {1:b} bar {1:b} eggs | + a | + foo {1:b} bar {1:b} eggs | + foo {1:b} bar {1:b} eggs | + foo {1:b} bar {1:b} eggs | + foo {1:b} bar {1:b} eggs | + foo {1:b} bar {1:b} eggs | + {4:-- VISUAL LINE --} | + ]]} + feed(string.rep('j', 15)) + screen:expect{grid=[[ + {6:foo }{1:b}{6: bar }{1:b}{6: eggs} | + {6:foo }{1:b}{6: bar }{1:b}{6: eggs} | + {6:foo }{1:b}{6: bar }{1:b}{6: eggs} | + {6:foo }{1:b}{6: bar }{1:b}{6: eggs} | + {6:foo }{1:b}{6: bar }{1:b}{6: eggs} | + {6:foo }{1:b}{6: bar }{1:b}{6: eggs} | + {6:foo }{1:b}{6: bar }{1:b}{6: eggs} | + {6:foo }{1:b}{6: bar }{1:b}{6: eggs} | + ^f{6:oo }{1:b}{6: bar }{1:b}{6: eggs} | + {4:-- VISUAL LINE --} | + ]]} + feed(string.rep('k', 15)) + screen:expect{grid=[[ + ^f{6:oo }{1:b}{6: bar }{1:b}{6: eggs} | + foo {1:b} bar {1:b} eggs | + foo {1:b} bar {1:b} eggs | + a | + foo {1:b} bar {1:b} eggs | + foo {1:b} bar {1:b} eggs | + foo {1:b} bar {1:b} eggs | + foo {1:b} bar {1:b} eggs | + foo {1:b} bar {1:b} eggs | + {4:-- VISUAL LINE --} | + ]]} + end) end) end) -- cgit From 1f4c9da9c60f3cf5573c2f35e74c48a0f56056b4 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Wed, 25 Sep 2019 01:56:29 -0400 Subject: test: fix screen assertions --- test/functional/ui/inccommand_spec.lua | 36 +++++++++++++++++----------------- test/functional/ui/mouse_spec.lua | 4 ++-- test/functional/ui/popupmenu_spec.lua | 6 +++--- 3 files changed, 23 insertions(+), 23 deletions(-) (limited to 'test') diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua index 351c4b4bcf..e9a7c8c2df 100644 --- a/test/functional/ui/inccommand_spec.lua +++ b/test/functional/ui/inccommand_spec.lua @@ -734,11 +734,11 @@ describe(":substitute, inccommand=split", function() feed_command("set nomodified") feed(":%s/tw") screen:expect([[ + Inc substitution on | + {12:tw}o lines | Inc substitution on | {12:tw}o lines | | - {15:~ }| - {15:~ }| {11:[No Name] }| |2| {12:tw}o lines | |4| {12:tw}o lines | @@ -791,11 +791,11 @@ describe(":substitute, inccommand=split", function() it('shows split window when typing the pattern', function() feed(":%s/tw") screen:expect([[ + Inc substitution on | + {12:tw}o lines | Inc substitution on | {12:tw}o lines | | - {15:~ }| - {15:~ }| {11:[No Name] [+] }| |2| {12:tw}o lines | |4| {12:tw}o lines | @@ -812,11 +812,11 @@ describe(":substitute, inccommand=split", function() it('shows preview with empty replacement', function() feed(":%s/tw/") screen:expect([[ + Inc substitution on | + o lines | Inc substitution on | o lines | | - {15:~ }| - {15:~ }| {11:[No Name] [+] }| |2| o lines | |4| o lines | @@ -831,11 +831,11 @@ describe(":substitute, inccommand=split", function() feed("x") screen:expect([[ + Inc substitution on | + {12:x}o lines | Inc substitution on | {12:x}o lines | | - {15:~ }| - {15:~ }| {11:[No Name] [+] }| |2| {12:x}o lines | |4| {12:x}o lines | @@ -850,11 +850,11 @@ describe(":substitute, inccommand=split", function() feed("") screen:expect([[ + Inc substitution on | + o lines | Inc substitution on | o lines | | - {15:~ }| - {15:~ }| {11:[No Name] [+] }| |2| o lines | |4| o lines | @@ -872,11 +872,11 @@ describe(":substitute, inccommand=split", function() it('shows split window when typing replacement', function() feed(":%s/tw/XX") screen:expect([[ + Inc substitution on | + {12:XX}o lines | Inc substitution on | {12:XX}o lines | | - {15:~ }| - {15:~ }| {11:[No Name] [+] }| |2| {12:XX}o lines | |4| {12:XX}o lines | @@ -938,11 +938,11 @@ describe(":substitute, inccommand=split", function() feed(":%s/tw") -- 'cursorline' is NOT active during preview. screen:expect([[ + Inc substitution on | {12:tw}o lines | Inc substitution on | {12:tw}o lines | | - {15:~ }| {11:[No Name] [+] }| |2| {12:tw}o lines | |4| {12:tw}o lines | @@ -2205,11 +2205,11 @@ describe(":substitute", function() feed("/KKK") screen:expect([[ + T T123 T T123 T2T TT T23423424| + x | afa {12:KKK}adf la;lkd {12:KKK}alx | | {15:~ }| - {15:~ }| - {15:~ }| {11:[No Name] [+] }| |3| afa {12:KKK}adf la;lkd {12:KKK}alx | {15:~ }| @@ -2485,11 +2485,11 @@ describe(":substitute", function() wait() feed([[:%s/\(some\)\@!thing/one/]]) screen:expect([[ + something | every{12:one} | someone | {15:~ }| {15:~ }| - {15:~ }| {11:[No Name] [+] }| |2| every{12:one} | {15:~ }| @@ -2527,11 +2527,11 @@ describe(":substitute", function() wait() feed([[:%s/some\(thing\)\@!/every/]]) screen:expect([[ + something | + everything | {12:every}one | {15:~ }| {15:~ }| - {15:~ }| - {15:~ }| {11:[No Name] [+] }| |3| {12:every}one | {15:~ }| diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index 3bd6b81ff1..440bae58e0 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -419,9 +419,9 @@ describe('ui/mouse/input', function() meths.set_option('showtabline', 2) screen:expect([[ {fill:test-test2 }| + testing | mouse | support and selectio^n | - {0:~ }| | ]]) meths.set_var('reply', {}) @@ -539,9 +539,9 @@ describe('ui/mouse/input', function() feed_command('tabprevious') -- go to first tab screen:expect([[ {sel: + foo }{tab: + bar }{fill: }{tab:X}| + testing | mouse | support and selectio^n | - {0:~ }| :tabprevious | ]]) feed('<10,0>') -- go to second tab diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 37eb550835..fabcc05ce6 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -1491,20 +1491,20 @@ describe('builtin popupmenu', function() command("split") screen:expect([[ + xx | choice^ | - {1:~ }| {n:word }{1: }| {s:choice }{4: }| {n:text } | - {n:thing }{1: }| + {n:thing } | {3:[No Name] [+] }| {2:-- INSERT --} | ]]) meths.input_mouse('wheel', 'down', '', 0, 6, 15) screen:expect{grid=[[ + xx | choice^ | - {1:~ }| {n:word }{1: }| {s:choice }{4: }| {n:text } | -- cgit From 333dc3d1381f5d3c8f0770141c0a989cfff93f57 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Wed, 2 Oct 2019 04:56:22 +0200 Subject: Fix flaky test: tui_spec: increase timeout (#11134) Meant to fix: [ ERROR ] test/functional/terminal/tui_spec.lua @ 925: TUI FocusGained/FocusLost in terminal-mode test/functional/ui/screen.lua:587: Row 6 did not match. Expected: |{1:r}eady $ | |[Process exited 0] | | | | | | | |*gained | |{3:-- TERMINAL --} | Actual: |{1:r}eady $ | |[Process exited 0] | | | | | | | |*:terminal | |{3:-- TERMINAL --} | To print the expect() call that would assert the current screen state, use screen:snapshot_util(). In case of non-deterministic failures, use screen:redraw_debug() to show all intermediate screen states. stack traceback: test/functional/ui/screen.lua:587: in function '_wait' test/functional/ui/screen.lua:370: in function 'expect' test/functional/terminal/tui_spec.lua:934: in function I've thought about adding this, but it might not be really relevant, and slows down the tests a bit (and a warning "warning: Screen test succeeded immediately" with another test): ```diff diff --git i/test/functional/terminal/tui_spec.lua w/test/functional/terminal/tui_spec.lua index ada073c4e..4bc2ab4e0 100644 --- i/test/functional/terminal/tui_spec.lua +++ w/test/functional/terminal/tui_spec.lua @@ -818,6 +818,11 @@ describe('TUI FocusGained/FocusLost', function() ..'", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile noshowcmd noruler"]') feed_data(":autocmd FocusGained * echo 'gained'\n") feed_data(":autocmd FocusLost * echo 'lost'\n") + -- Wait for autocommand to be registered. + retry(nil, nil, function() + feed_data(":autocmd FocusLost\n") + screen:expect{any=" echo 'lost'"} + end) feed_data("\034\016") -- CTRL-\ CTRL-N end) ``` --- test/functional/terminal/tui_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index ed904f27ca..ada073c4e6 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -939,7 +939,7 @@ describe('TUI FocusGained/FocusLost', function() | gained | {3:-- TERMINAL --} | - ]], timeout=(3 * screen.timeout)} + ]], timeout=(4 * screen.timeout)} feed_data('\027[O') screen:expect([[ -- cgit From b069e9b20f9e1f24fde34bee7d6e5d95f47ef10d Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 3 Oct 2019 07:41:57 +0200 Subject: tests: unit: NVIM_TEST_TRACE_LEVEL: default to 0 #11144 Traces are not useful normally (unless debugging/fixing tests), but only add overhead. Disable them by default. --- test/README.md | 11 ++++++----- test/unit/helpers.lua | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'test') diff --git a/test/README.md b/test/README.md index 64892b5576..2b19740434 100644 --- a/test/README.md +++ b/test/README.md @@ -315,11 +315,12 @@ Number; !must be defined to function properly): - `NVIM_TEST_RUN_TESTTEST` (U) (1): allows running `test/unit/testtest_spec.lua` used to check how testing infrastructure works. -- `NVIM_TEST_TRACE_LEVEL` (U) (N): specifies unit tests tracing level: `0` - disables tracing (the fastest, but you get no data if tests crash and there - was no core dump generated), `1` or empty/undefined leaves only C function - cals and returns in the trace (faster then recording everything), `2` records - all function calls, returns and lua source lines exuecuted. +- `NVIM_TEST_TRACE_LEVEL` (U) (N): specifies unit tests tracing level: + - `0` disables tracing (the fastest, but you get no data if tests crash and + there no core dump was generated), + - `1` leaves only C function calls and returns in the trace (faster than + recording everything), + - `2` records all function calls, returns and executed Lua source lines. - `NVIM_TEST_TRACE_ON_ERROR` (U) (1): makes unit tests yield trace on error in addition to regular error message. diff --git a/test/unit/helpers.lua b/test/unit/helpers.lua index 24dbc65bd0..bacdc54416 100644 --- a/test/unit/helpers.lua +++ b/test/unit/helpers.lua @@ -545,7 +545,7 @@ local tracehelp = dedent([[ local function child_sethook(wr) local trace_level = os.getenv('NVIM_TEST_TRACE_LEVEL') if not trace_level or trace_level == '' then - trace_level = 1 + trace_level = 0 else trace_level = tonumber(trace_level) end @@ -708,7 +708,7 @@ local function check_child_err(rd) local eres = sc.read(rd, 2) if eres ~= '$\n' then if #trace == 0 then - err = '\nTest crashed, no trace available\n' + err = '\nTest crashed, no trace available (check NVIM_TEST_TRACE_LEVEL)\n' else err = '\nTest crashed, trace:\n' .. tracehelp for i = 1, #trace do -- cgit From f96d1e6bc416fe0d1d11321234637695ff0e514e Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 3 Oct 2019 08:04:24 +0200 Subject: tui: fix handling of bg response after suspend (#11145) `tui_terminal_after_startup` gets called right after resuming from suspending (via `Ctrl-z`) already (not delayed as with the startup itself), and would set `waiting_for_bg_response` to false then directly. This results in the terminal response not being processed then anymore, and leaking into Neovim itself. This changes it to try 5 times always, which means that it typically would stop after a few characters of input from the user typically, e.g. with tmux, which does not send a reply. While it might be better to have something based on the time (e.g. only wait for max 1s), this appears to be easier to do. Fixes regression in 8a4ae3d. --- test/unit/tui_spec.lua | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'test') diff --git a/test/unit/tui_spec.lua b/test/unit/tui_spec.lua index 47dbd87b71..e6b5c889d7 100644 --- a/test/unit/tui_spec.lua +++ b/test/unit/tui_spec.lua @@ -16,7 +16,7 @@ itp('handle_background_color', function() local events = globals.main_loop.thread_events -- Short-circuit when not waiting for response. - term_input.waiting_for_bg_response = false + term_input.waiting_for_bg_response = 0 eq(false, handle_background_color(term_input)) local capacity = 100 @@ -27,9 +27,9 @@ itp('handle_background_color', function() local term_response = '\027]11;'..colorspace..':'..color..'\007' rbuffer.rbuffer_write(rbuf, to_cstr(term_response), #term_response) - term_input.waiting_for_bg_response = true + term_input.waiting_for_bg_response = 1 eq(true, handle_background_color(term_input)) - eq(false, term_input.waiting_for_bg_response) + eq(0, term_input.waiting_for_bg_response) eq(1, multiqueue.multiqueue_size(events)) local event = multiqueue.multiqueue_get(events) @@ -101,10 +101,9 @@ itp('handle_background_color', function() local term_response = '\027]11;rgba:f/f/f/f' -- missing '\007 rbuffer.rbuffer_write(rbuf, to_cstr(term_response), #term_response) - term_input.waiting_for_bg_response = true - eq(true, term_input.waiting_for_bg_response) + term_input.waiting_for_bg_response = 1 eq(false, handle_background_color(term_input)) - eq(false, term_input.waiting_for_bg_response) + eq(0, term_input.waiting_for_bg_response) eq(0, multiqueue.multiqueue_size(events)) eq(0, rbuf.size) @@ -114,10 +113,9 @@ itp('handle_background_color', function() term_response = '123\027]11;rgba:f/f/f/f\007456' rbuffer.rbuffer_write(rbuf, to_cstr(term_response), #term_response) - term_input.waiting_for_bg_response = true - eq(true, term_input.waiting_for_bg_response) + term_input.waiting_for_bg_response = 3 eq(false, handle_background_color(term_input)) - eq(true, term_input.waiting_for_bg_response) + eq(2, term_input.waiting_for_bg_response) eq(0, multiqueue.multiqueue_size(events)) eq(#term_response, rbuf.size) @@ -128,10 +126,9 @@ itp('handle_background_color', function() term_response = '\027]11;rgba:f/f/f/f\007456' rbuffer.rbuffer_write(rbuf, to_cstr(term_response), #term_response) - term_input.waiting_for_bg_response = true - eq(true, term_input.waiting_for_bg_response) + term_input.waiting_for_bg_response = 1 eq(true, handle_background_color(term_input)) - eq(false, term_input.waiting_for_bg_response) + eq(0, term_input.waiting_for_bg_response) eq(1, multiqueue.multiqueue_size(events)) eq(3, rbuf.size) -- cgit From cd73a0342a457c035b84e4406428ac30b30bf754 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Tue, 1 Oct 2019 00:06:53 +0200 Subject: tests: tui_spec: improve/merge OptionSet/deferred Closes https://github.com/neovim/neovim/pull/11129. --- test/functional/terminal/tui_spec.lua | 75 ++++++++++------------------------- 1 file changed, 21 insertions(+), 54 deletions(-) (limited to 'test') diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index ada073c4e6..978267e040 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -1345,59 +1345,26 @@ describe("TUI", function() end) -describe('TUI background color', function() - local screen - - before_each(function() - clear() - screen = thelpers.screen_setup(0, '["'..nvim_prog - ..'", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile"]') - end) - - it("triggers OptionSet event on terminal-response", function() - feed_data('\027:autocmd OptionSet background echo "did OptionSet, yay!"\n') - - -- Wait for the child Nvim to register the OptionSet handler. - feed_data('\027:autocmd OptionSet\n') - screen:expect({any='--- Autocommands ---'}) - - feed_data('\012') -- CTRL-L: clear the screen - screen:expect([[ - {1: } | - {4:~ }| - {4:~ }| - {4:~ }| - {5:[No Name] 0,0-1 All}| - | - {3:-- TERMINAL --} | - ]]) - feed_data('\027]11;rgb:ffff/ffff/ffff\007') - screen:expect{any='did OptionSet, yay!'} - end) - - it("handles deferred background color", function() - local function wait_for_bg(bg) - -- 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 +it('TUI bg color triggers OptionSet event on terminal-response', function() + -- Only single integration test. + -- See test/unit/tui_spec.lua for unit tests. + clear() + local screen = thelpers.screen_setup(0, '["'..nvim_prog + ..'", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile", ' + ..'"-c", "autocmd OptionSet background echo \\"did OptionSet, yay!\\""]') + + screen:expect([[ + {1: } | + {4:~ }| + {4:~ }| + {4:~ }| + {5:[No Name] 0,0-1 All}| + | + {3:-- TERMINAL --} | + ]]) + feed_data('\027]11;rgb:ffff/ffff/ffff\007') + screen:expect{any='did OptionSet, yay!'} - -- Only single integration test. - -- See test/unit/tui_spec.lua for unit tests. - feed_data('\027]11;rgb:ffff/ffff/ffff\007') - wait_for_bg('light') - end) + feed_data(':echo "new_bg=".&background\n') + screen:expect{any='new_bg=light'} end) -- cgit From a341eb608706e5e8ac691a7e8f4a9d314bafee20 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 26 Sep 2019 09:15:21 +0200 Subject: win_line: update `w_last_cursorline` always Vim patch 8.1.0856 (54d9ea6) caused a performance regression in Neovim, when `set conceallevel=1 nocursorline` was used, since then due to refactoring in 23c71d5 `w_last_cursorline` would never get updated anymore. Adds/uses `redrawdebug+=nodelta` for testing this. Fixes https://github.com/neovim/neovim/issues/11100. Closes https://github.com/neovim/neovim/pull/11101. --- test/functional/ui/syntax_conceal_spec.lua | 47 ++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'test') diff --git a/test/functional/ui/syntax_conceal_spec.lua b/test/functional/ui/syntax_conceal_spec.lua index 7079b43414..566d183f11 100644 --- a/test/functional/ui/syntax_conceal_spec.lua +++ b/test/functional/ui/syntax_conceal_spec.lua @@ -1,6 +1,7 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, feed, command = helpers.clear, helpers.feed, helpers.command +local eq = helpers.eq local insert = helpers.insert describe('Screen', function() @@ -870,4 +871,50 @@ describe('Screen', function() ]]} end) end) + + it('redraws not too much with conceallevel=1', function() + command('set conceallevel=1') + command('set redrawdebug+=nodelta') + + insert([[ + aaa + bbb + ccc + ]]) + screen:expect{grid=[[ + aaa | + bbb | + ccc | + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]} + + -- XXX: hack to get notifications, and check only a single line is + -- updated. Could use next_msg() also. + local orig_handle_grid_line = screen._handle_grid_line + local grid_lines = {} + function screen._handle_grid_line(self, grid, row, col, items) + table.insert(grid_lines, {row, col, items}) + orig_handle_grid_line(self, grid, row, col, items) + end + feed('k') + screen:expect{grid=[[ + aaa | + bbb | + ^ccc | + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]} + eq(grid_lines, {{2, 0, {{'c', 0, 3}}}}) + end) end) -- cgit From fe074611cd5b3319a3f639f68289df6a718e64eb Mon Sep 17 00:00:00 2001 From: Jurica Bradarić Date: Sun, 6 Oct 2019 05:35:48 +0200 Subject: vim-patch:8.1.1371: cannot recover from a swap file #11081 Problem: Cannot recover from a swap file. Solution: Do not expand environment variables in the swap file name. Do not check the extension when we already know a file is a swap file. (Ken Takata, closes 4415, closes vim/vim#4369) https://github.com/vim/vim/commit/99499b1c05f85f83876b828eea3f6e14f0f407b4 --- test/unit/path_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/unit/path_spec.lua b/test/unit/path_spec.lua index da52af1bf9..356c4997fa 100644 --- a/test/unit/path_spec.lua +++ b/test/unit/path_spec.lua @@ -66,10 +66,10 @@ describe('path.c', function() end) describe('path_full_compare', function() - local function path_full_compare(s1, s2, cn) + local function path_full_compare(s1, s2, cn, ee) s1 = to_cstr(s1) s2 = to_cstr(s2) - return cimp.path_full_compare(s1, s2, cn or 0) + return cimp.path_full_compare(s1, s2, cn or 0, ee or 1) end local f1 = 'f1.o' -- cgit From 55007180a39e762dad7e80b7cd57fe4630e2e20a Mon Sep 17 00:00:00 2001 From: Vikram Pal Date: Sun, 6 Oct 2019 14:51:06 +0530 Subject: doc: Fix TEST_FILTER example #11158 --- test/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/README.md b/test/README.md index 2b19740434..2cee7da009 100644 --- a/test/README.md +++ b/test/README.md @@ -126,7 +126,7 @@ end) To run only test with filter name: - TEST_TAG='foo.*api' make functionaltest + TEST_FILTER='foo.*api' make functionaltest ### Filter by file -- cgit From e452988960b11e971d839c27dcd2f42e68f3aa4d Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 6 Oct 2019 22:26:54 +0200 Subject: tests/functional: keep $TMPDIR in env (#11163) --- test/functional/helpers.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'test') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index bd36bac062..c195983e93 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -437,6 +437,7 @@ function module.new_argv(...) 'NVIM_LOG_FILE', 'NVIM_RPLUGIN_MANIFEST', 'GCOV_ERROR_FILE', + 'TMPDIR', }) do if not env_tbl[k] then env_tbl[k] = os.getenv(k) -- cgit From 2b08dd8f062c3e0dc1c01c1b695a7dd282b8ff21 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 6 Oct 2019 22:47:40 +0200 Subject: tests: retry: "wait() evaluates the condition on given interval" (#11155) Ref: https://github.com/neovim/neovim/issues/11137 --- test/functional/eval/wait_spec.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/functional/eval/wait_spec.lua b/test/functional/eval/wait_spec.lua index ad7d1574cb..ee95e02a7f 100644 --- a/test/functional/eval/wait_spec.lua +++ b/test/functional/eval/wait_spec.lua @@ -58,8 +58,11 @@ describe('wait()', function() endfunction ]]) - nvim('set_var', 'counter', 0) - eq(-1, call('wait', 20, 'Count() >= 5', 99999)) + -- XXX: flaky (#11137) + helpers.retry(nil, nil, function() + nvim('set_var', 'counter', 0) + eq(-1, call('wait', 20, 'Count() >= 5', 99999)) + end) nvim('set_var', 'counter', 0) eq(0, call('wait', 10000, 'Count() >= 5', 5)) -- cgit From 51f2826f617532aaf5d682dfc3229f3723427ce6 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Thu, 10 Oct 2019 04:16:02 -0400 Subject: doc: update shellquote for powershell #11122 shellquote is not treated like shellxquote for non-quote values. --- test/functional/helpers.lua | 15 +++++++++++++-- test/functional/ui/output_spec.lua | 16 ++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index c195983e93..20371b8ab0 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -501,9 +501,20 @@ function module.source(code) end function module.set_shell_powershell() + local shell = iswin() and 'powershell' or 'pwsh' + if not module.eval('executable("'..shell..'")') then + error(shell..' is not executable') + end + local aliases = iswin() and {'cat', 'sleep'} or {} + local cmd = '' + for _, alias in ipairs(aliases) do + cmd = cmd .. 'Remove-Item -Force alias:' .. alias .. ';' + end module.source([[ - set shell=powershell shellquote=( shellpipe=\| shellredir=> shellxquote= - let &shellcmdflag = '-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command Remove-Item -Force alias:sleep; Remove-Item -Force alias:cat;' + let &shell = ']]..shell..[[' + set shellquote= shellpipe=\| shellxquote= + let &shellredir = '| Out-File -Encoding UTF8' + let &shellcmdflag = '-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command ]]..cmd..[[' ]]) end diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua index c028f44b44..c5d3e536ad 100644 --- a/test/functional/ui/output_spec.lua +++ b/test/functional/ui/output_spec.lua @@ -10,6 +10,7 @@ local iswin = helpers.iswin local clear = helpers.clear local command = helpers.command local nvim_dir = helpers.nvim_dir +local set_shell_powershell = helpers.set_shell_powershell describe("shell command :!", function() local screen @@ -230,4 +231,19 @@ describe("shell command :!", function() ]]) end) end) + if iswin() or eval('executable("pwsh")') == 1 then + it('powershell supports literal strings', function() + set_shell_powershell() + local screen = Screen.new(30, 4) + screen:attach() + feed_command([[!'echo $a']]) + screen:expect{any='\necho %$a', timeout=10000} + feed_command([[!$a = 1; echo '$a']]) + screen:expect{any='\n%$a', timeout=10000} + feed_command([[!"echo $a"]]) + screen:expect{any='\necho', timeout=10000} + feed_command([[!$a = 1; echo "$a"]]) + screen:expect{any='\n1', timeout=10000} + end) + end end) -- cgit From a7fc2f3f64f05ffd2a97c8ccf2e5c74d905ac808 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Fri, 11 Oct 2019 00:30:20 -0400 Subject: test: "!:&" works with powershell #11201 Removed 'echo' alias because it does not behave like POSIX echo. --- test/functional/eval/system_spec.lua | 8 ++++---- test/functional/helpers.lua | 12 ++++-------- test/functional/ui/output_spec.lua | 16 ++++++++++------ 3 files changed, 18 insertions(+), 18 deletions(-) (limited to 'test') diff --git a/test/functional/eval/system_spec.lua b/test/functional/eval/system_spec.lua index 0a478fd05c..85d57006b5 100644 --- a/test/functional/eval/system_spec.lua +++ b/test/functional/eval/system_spec.lua @@ -84,7 +84,7 @@ describe('system()', function() it('does NOT run in shell', function() if iswin() then - eq("%PATH%\n", eval("system(['powershell', '-NoProfile', '-NoLogo', '-ExecutionPolicy', 'RemoteSigned', '-Command', 'echo', '%PATH%'])")) + eq("%PATH%\n", eval("system(['powershell', '-NoProfile', '-NoLogo', '-ExecutionPolicy', 'RemoteSigned', '-Command', 'Write-Output', '%PATH%'])")) else eq("* $PATH %PATH%\n", eval("system(['echo', '*', '$PATH', '%PATH%'])")) end @@ -133,7 +133,7 @@ describe('system()', function() eval([[system('"ping" "-n" "1" "127.0.0.1"')]]) eq(0, eval('v:shell_error')) eq('"a b"\n', eval([[system('cmd /s/c "cmd /s/c "cmd /s/c "echo "a b""""')]])) - eq('"a b"\n', eval([[system('powershell -NoProfile -NoLogo -ExecutionPolicy RemoteSigned -Command echo ''\^"a b\^"''')]])) + eq('"a b"\n', eval([[system('powershell -NoProfile -NoLogo -ExecutionPolicy RemoteSigned -Command Write-Output ''\^"a b\^"''')]])) end it('with shell=cmd.exe', function() @@ -169,9 +169,9 @@ describe('system()', function() it('works with powershell', function() helpers.set_shell_powershell() - eq('a\nb\n', eval([[system('echo a b')]])) + eq('a\nb\n', eval([[system('Write-Output a b')]])) eq('C:\\\n', eval([[system('cd c:\; (Get-Location).Path')]])) - eq('a b\n', eval([[system('echo "a b"')]])) + eq('a b\n', eval([[system('Write-Output "a b"')]])) end) end diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 20371b8ab0..2473fc0d3b 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -502,14 +502,10 @@ end function module.set_shell_powershell() local shell = iswin() and 'powershell' or 'pwsh' - if not module.eval('executable("'..shell..'")') then - error(shell..' is not executable') - end - local aliases = iswin() and {'cat', 'sleep'} or {} - local cmd = '' - for _, alias in ipairs(aliases) do - cmd = cmd .. 'Remove-Item -Force alias:' .. alias .. ';' - end + assert(module.eval('executable("'..shell..'")')) + local cmd = 'Remove-Item -Force '..table.concat(iswin() + and {'alias:cat', 'alias:echo', 'alias:sleep'} + or {'alias:echo'}, ',')..';' module.source([[ let &shell = ']]..shell..[[' set shellquote= shellpipe=\| shellxquote= diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua index c5d3e536ad..20413cb784 100644 --- a/test/functional/ui/output_spec.lua +++ b/test/functional/ui/output_spec.lua @@ -236,14 +236,18 @@ describe("shell command :!", function() set_shell_powershell() local screen = Screen.new(30, 4) screen:attach() - feed_command([[!'echo $a']]) - screen:expect{any='\necho %$a', timeout=10000} - feed_command([[!$a = 1; echo '$a']]) + feed_command([[!'Write-Output $a']]) + screen:expect{any='\nWrite%-Output %$a', timeout=10000} + feed_command([[!$a = 1; Write-Output '$a']]) screen:expect{any='\n%$a', timeout=10000} - feed_command([[!"echo $a"]]) - screen:expect{any='\necho', timeout=10000} - feed_command([[!$a = 1; echo "$a"]]) + feed_command([[!"Write-Output $a"]]) + screen:expect{any='\nWrite%-Output', timeout=10000} + feed_command([[!$a = 1; Write-Output "$a"]]) screen:expect{any='\n1', timeout=10000} + feed_command(iswin() + and [[!& 'C:\\Windows\\system32\\cmd.exe' /c 'echo $a']] + or [[!& '/bin/sh' -c 'echo ''$a''']]) + screen:expect{any='\n%$a', timeout=10000} end) end end) -- cgit From 5f60861f5a7c7c588e1d638f734897bc5dc291cc Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Thu, 26 Sep 2019 23:04:59 +0100 Subject: fnamemodify: fix handling of :r after :e #11165 - Test fnamemodify() - Test handling of `expand("%:e:e:r")`. - Fix :e:e:r on filenames with insufficiently many extensions During `fnamemodify()`, ensuring that we don't go before the filename's tail is insufficient in cases where we've already handled a ":e" modifier, for example: ``` "path/to/this.file.ext" :e:e:r:r ^ ^-------- *fnamep +------------- tail ``` This means for a ":r", we'll go before `*fnamep`, and outside the bounds of the filename. This is both incorrect and causes neovim to exit with an allocation error. We exit because we attempt to calculate `s - *fnamep` (line 23948). Since `s` is before `*fnamep`, we caluclate a negative length, which ends up being interpreted as an amount to allocate, causing neovim to exit with ENOMEM (`memory.c:xmalloc`). We must instead ensure we don't go before `*fnamep` nor `tail`. The check for `tail` is still relevant, for example: ``` "path/to/this.file.ext" :r:r:r ^ ^------------- tail +--------------------- *fnamep ``` Here we don't want to go before `tail`. close #11165 --- test/functional/eval/fnamemodify_spec.lua | 119 +++++++++++++++++++++++++++++- 1 file changed, 118 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/eval/fnamemodify_spec.lua b/test/functional/eval/fnamemodify_spec.lua index fe6b50a544..d54a6db417 100644 --- a/test/functional/eval/fnamemodify_spec.lua +++ b/test/functional/eval/fnamemodify_spec.lua @@ -3,8 +3,14 @@ local clear = helpers.clear local eq = helpers.eq local iswin = helpers.iswin local fnamemodify = helpers.funcs.fnamemodify +local getcwd = helpers.funcs.getcwd local command = helpers.command local write_file = helpers.write_file +local alter_slashes = helpers.alter_slashes + +local function eq_slashconvert(expected, got) + eq(alter_slashes(expected), alter_slashes(got)) +end describe('fnamemodify()', function() setup(function() @@ -17,7 +23,7 @@ describe('fnamemodify()', function() os.remove('Xtest-fnamemodify.txt') end) - it('works', function() + it('handles the root path', function() local root = helpers.pathroot() eq(root, fnamemodify([[/]], ':p:h')) eq(root, fnamemodify([[/]], ':p')) @@ -36,4 +42,115 @@ describe('fnamemodify()', function() it(':8 works', function() eq('Xtest-fnamemodify.txt', fnamemodify([[Xtest-fnamemodify.txt]], ':8')) end) + + it('handles examples from ":help filename-modifiers"', function() + local filename = "src/version.c" + local cwd = getcwd() + + eq_slashconvert(cwd .. '/src/version.c', fnamemodify(filename, ':p')) + + eq_slashconvert('src/version.c', fnamemodify(filename, ':p:.')) + eq_slashconvert(cwd .. '/src', fnamemodify(filename, ':p:h')) + eq_slashconvert(cwd .. '', fnamemodify(filename, ':p:h:h')) + eq('version.c', fnamemodify(filename, ':p:t')) + eq_slashconvert(cwd .. '/src/version', fnamemodify(filename, ':p:r')) + + eq_slashconvert(cwd .. '/src/main.c', fnamemodify(filename, ':s?version?main?:p')) + + local converted_cwd = cwd:gsub('/', '\\') + eq(converted_cwd .. '\\src\\version.c', fnamemodify(filename, ':p:gs?/?\\\\?')) + + eq('src', fnamemodify(filename, ':h')) + eq('version.c', fnamemodify(filename, ':t')) + eq_slashconvert('src/version', fnamemodify(filename, ':r')) + eq('version', fnamemodify(filename, ':t:r')) + eq('c', fnamemodify(filename, ':e')) + + eq_slashconvert('src/main.c', fnamemodify(filename, ':s?version?main?')) + end) + + it('handles advanced examples from ":help filename-modifiers"', function() + local filename = "src/version.c.gz" + + eq('gz', fnamemodify(filename, ':e')) + eq('c.gz', fnamemodify(filename, ':e:e')) + eq('c.gz', fnamemodify(filename, ':e:e:e')) + + eq('c', fnamemodify(filename, ':e:e:r')) + + eq_slashconvert('src/version.c', fnamemodify(filename, ':r')) + eq('c', fnamemodify(filename, ':r:e')) + + eq_slashconvert('src/version', fnamemodify(filename, ':r:r')) + eq_slashconvert('src/version', fnamemodify(filename, ':r:r:r')) + end) + + it('handles :h', function() + eq('.', fnamemodify('hello.txt', ':h')) + + eq_slashconvert('path/to', fnamemodify('path/to/hello.txt', ':h')) + end) + + it('handles :t', function() + eq('hello.txt', fnamemodify('hello.txt', ':t')) + eq_slashconvert('hello.txt', fnamemodify('path/to/hello.txt', ':t')) + end) + + it('handles :r', function() + eq('hello', fnamemodify('hello.txt', ':r')) + eq_slashconvert('path/to/hello', fnamemodify('path/to/hello.txt', ':r')) + end) + + it('handles :e', function() + eq('txt', fnamemodify('hello.txt', ':e')) + eq_slashconvert('txt', fnamemodify('path/to/hello.txt', ':e')) + end) + + it('handles regex replacements', function() + eq('content-there-here.txt', fnamemodify('content-here-here.txt', ':s/here/there/')) + eq('content-there-there.txt', fnamemodify('content-here-here.txt', ':gs/here/there/')) + end) + + it('handles shell escape', function() + local expected + + if iswin() then + -- we expand with double-quotes on Windows + expected = [["hello there! quote ' newline]] .. '\n' .. [["]] + else + expected = [['hello there! quote '\'' newline]] .. '\n' .. [[']] + end + + eq(expected, fnamemodify("hello there! quote ' newline\n", ':S')) + end) + + it('can combine :e and :r', function() + -- simple, single extension filename + eq('c', fnamemodify('a.c', ':e')) + eq('c', fnamemodify('a.c', ':e:e')) + eq('c', fnamemodify('a.c', ':e:e:r')) + eq('c', fnamemodify('a.c', ':e:e:r:r')) + + -- multi extension filename + eq('rb', fnamemodify('a.spec.rb', ':e:r')) + eq('rb', fnamemodify('a.spec.rb', ':e:r:r')) + + eq('spec', fnamemodify('a.spec.rb', ':e:e:r')) + eq('spec', fnamemodify('a.spec.rb', ':e:e:r:r')) + + eq('spec', fnamemodify('a.b.spec.rb', ':e:e:r')) + eq('b.spec', fnamemodify('a.b.spec.rb', ':e:e:e:r')) + eq('b', fnamemodify('a.b.spec.rb', ':e:e:e:r:r')) + + eq('spec', fnamemodify('a.b.spec.rb', ':r:e')) + eq('b', fnamemodify('a.b.spec.rb', ':r:r:e')) + + -- extraneous :e expansions + eq('c', fnamemodify('a.b.c.d.e', ':r:r:e')) + eq('b.c', fnamemodify('a.b.c.d.e', ':r:r:e:e')) + + -- :e never includes the whole filename, so "a.b":e:e:e --> "b" + eq('b.c', fnamemodify('a.b.c.d.e', ':r:r:e:e:e')) + eq('b.c', fnamemodify('a.b.c.d.e', ':r:r:e:e:e:e')) + end) end) -- cgit From 5a85699425661a1b508627843c40812d1d07fb2c Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Fri, 11 Oct 2019 19:27:15 +0200 Subject: tests/ui: make screen.lua use "linegrid" representation internally PR #8221 took a short-cut when implementing the tests: screen.lua would translate the linegrid highlight ids back into the old per-cell attribute description. Apart from cleaning up technical debt, this enables to check both rgb and cterm colors in the same expect(), which previously was needlessly restricted to ext_hlstate tests only. --- test/functional/terminal/helpers.lua | 2 +- test/functional/ui/hlstate_spec.lua | 2 +- test/functional/ui/screen.lua | 110 +++++++++++++++++++---------------- 3 files changed, 63 insertions(+), 51 deletions(-) (limited to 'test') diff --git a/test/functional/terminal/helpers.lua b/test/functional/terminal/helpers.lua index f6cab6bd1e..d909888613 100644 --- a/test/functional/terminal/helpers.lua +++ b/test/functional/terminal/helpers.lua @@ -52,7 +52,7 @@ local function screen_setup(extra_rows, command, cols, opts) [3] = {bold = true}, [4] = {foreground = 12}, [5] = {bold = true, reverse = true}, - [6] = {background = 11}, + -- 6 was a duplicate item [7] = {foreground = 130}, [8] = {foreground = 15, background = 1}, -- error message [9] = {foreground = 4}, diff --git a/test/functional/ui/hlstate_spec.lua b/test/functional/ui/hlstate_spec.lua index d1c115587e..1e18df835a 100644 --- a/test/functional/ui/hlstate_spec.lua +++ b/test/functional/ui/hlstate_spec.lua @@ -259,7 +259,7 @@ describe('ext_hlstate detailed highlights', function() it("can use independent cterm and rgb colors", function() -- tell test module to save all attributes (doesn't change nvim options) - screen:set_hlstate_cterm(true) + screen:set_rgb_cterm(true) screen:set_default_attr_ids({ [1] = {{bold = true, foreground = Screen.colors.Blue1}, {foreground = 12}, {{hi_name = "NonText", ui_name = "EndOfBuffer", kind = "ui"}}}, diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 06a2ac3ca2..68c3d54922 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -172,9 +172,9 @@ function Screen.new(width, height) _default_attr_ignore = nil, _mouse_enabled = true, _attrs = {}, - _hl_info = {}, + _hl_info = {[0]={}}, _attr_table = {[0]={{},{}}}, - _clear_attrs = {}, + _clear_attrs = nil, _new_attrs = false, _width = width, _height = height, @@ -206,8 +206,8 @@ function Screen:set_default_attr_ignore(attr_ignore) self._default_attr_ignore = attr_ignore end -function Screen:set_hlstate_cterm(val) - self._hlstate_cterm = val +function Screen:set_rgb_cterm(val) + self._rgb_cterm = val end function Screen:attach(options, session) @@ -223,7 +223,7 @@ function Screen:attach(options, session) self._session = session self._options = options - self._clear_attrs = (options.ext_linegrid and {{},{}}) or {} + self._clear_attrs = (not options.ext_linegrid) and {} or nil self:_handle_resize(self._width, self._height) self.uimeths.attach(self._width, self._height, options) if self._options.rgb == nil then @@ -363,8 +363,8 @@ function Screen:expect(expected, attr_ids, attr_ignore, ...) ids = attr_ids or self._default_attr_ids, ignore = attr_ignore or self._default_attr_ignore, } - if self._options.ext_hlstate then - attr_state.id_to_index = self:hlstate_check_attrs(attr_state.ids or {}) + if self._options.ext_linegrid then + attr_state.id_to_index = self:linegrid_check_attrs(attr_state.ids or {}) end self._new_attrs = false self:_wait(function() @@ -375,8 +375,8 @@ function Screen:expect(expected, attr_ids, attr_ignore, ...) end end - if self._options.ext_hlstate and self._new_attrs then - attr_state.id_to_index = self:hlstate_check_attrs(attr_state.ids or {}) + if self._options.ext_linegrid and self._new_attrs then + attr_state.id_to_index = self:linegrid_check_attrs(attr_state.ids or {}) end local actual_rows = self:render(not expected.any, attr_state) @@ -898,19 +898,16 @@ function Screen:_handle_grid_line(grid, row, col, items) assert(self._options.ext_linegrid) local line = self._grids[grid].rows[row+1] local colpos = col+1 - local hl = self._clear_attrs local hl_id = 0 for _,item in ipairs(items) do local text, hl_id_cell, count = unpack(item) if hl_id_cell ~= nil then hl_id = hl_id_cell - hl = self._attr_table[hl_id] end for _ = 1, (count or 1) do local cell = line[colpos] cell.text = text cell.hl_id = hl_id - cell.attrs = hl colpos = colpos+1 end end @@ -1070,6 +1067,7 @@ function Screen:_clear_row_section(grid, rownum, startcol, stopcol, invalid) for i = startcol, stopcol do row[i].text = (invalid and '�' or ' ') row[i].attrs = self._clear_attrs + row[i].hl_id = 0 end end @@ -1100,11 +1098,7 @@ function Screen:_row_repr(gridnr, rownr, attr_state, cursor) end if not did_window then - local attrs = row[i].attrs - if self._options.ext_linegrid then - attrs = attrs[(self._options.rgb and 1) or 2] - end - local attr_id = self:_get_attr_id(attr_state, attrs, row[i].hl_id) + local attr_id = self:_get_attr_id(attr_state, row[i].attrs, row[i].hl_id) if current_attr_id and attr_id ~= current_attr_id then -- close current attribute bracket table.insert(rv, '}') @@ -1261,8 +1255,8 @@ function Screen:get_snapshot(attrs, ignore) attr_state.ids[i] = a end end - if self._options.ext_hlstate then - attr_state.id_to_index = self:hlstate_check_attrs(attr_state.ids) + if self._options.ext_linegrid then + attr_state.id_to_index = self:linegrid_check_attrs(attr_state.ids) end local lines = self:render(true, attr_state, true) @@ -1299,8 +1293,8 @@ function Screen:print_snapshot(attrs, ignore) local attrstrs = {} for i, a in pairs(attr_state.ids) do local dict - if self._options.ext_hlstate then - dict = self:_pprint_hlstate(a) + if self._options.ext_linegrid then + dict = self:_pprint_hlitem(a) else dict = "{"..self:_pprint_attrs(a).."}" end @@ -1328,37 +1322,41 @@ function Screen:_insert_hl_id(attr_state, hl_id) return attr_state.id_to_index[hl_id] end local raw_info = self._hl_info[hl_id] - local info = {} - if #raw_info > 1 then - for i, item in ipairs(raw_info) do - info[i] = self:_insert_hl_id(attr_state, item.id) - end - else - info[1] = {} - for k, v in pairs(raw_info[1]) do - if k ~= "id" then - info[1][k] = v + local info = nil + if self._options.ext_hlstate then + info = {} + if #raw_info > 1 then + for i, item in ipairs(raw_info) do + info[i] = self:_insert_hl_id(attr_state, item.id) + end + else + info[1] = {} + for k, v in pairs(raw_info[1]) do + if k ~= "id" then + info[1][k] = v + end end end end local entry = self._attr_table[hl_id] local attrval - if self._hlstate_cterm then + if self._rgb_cterm then attrval = {entry[1], entry[2], info} -- unpack() doesn't work - else + elseif self._options.ext_hlstate then attrval = {entry[1], info} + else + attrval = self._options.rgb and entry[1] or entry[2] end - table.insert(attr_state.ids, attrval) attr_state.id_to_index[hl_id] = #attr_state.ids return #attr_state.ids end -function Screen:hlstate_check_attrs(attrs) +function Screen:linegrid_check_attrs(attrs) local id_to_index = {} - for i = 1,#self._attr_table do + for i, def_attr in pairs(self._attr_table) do local iinfo = self._hl_info[i] local matchinfo = {} if #iinfo > 1 then @@ -1370,13 +1368,16 @@ function Screen:hlstate_check_attrs(attrs) end for k,v in pairs(attrs) do local attr, info, attr_rgb, attr_cterm - if self._hlstate_cterm then + if self._rgb_cterm then attr_rgb, attr_cterm, info = unpack(v) attr = {attr_rgb, attr_cterm} - else + elseif self._options.ext_hlstate then attr, info = unpack(v) + else + attr = v + info = {} end - if self:_equal_attr_def(attr, self._attr_table[i]) then + if self:_equal_attr_def(attr, def_attr) then if #info == #matchinfo then local match = false if #info == 1 then @@ -1397,24 +1398,31 @@ function Screen:hlstate_check_attrs(attrs) end end end + if self:_equal_attr_def(self._rgb_cterm and {{}, {}} or {}, def_attr) and #self._hl_info[i] == 0 then + id_to_index[i] = "" + end end return id_to_index end -function Screen:_pprint_hlstate(item) +function Screen:_pprint_hlitem(item) -- print(inspect(item)) - local attrdict = "{"..self:_pprint_attrs(item[1]).."}, " + local multi = self._rgb_cterm or self._options.ext_hlstate + local attrdict = "{"..self:_pprint_attrs(multi and item[1] or item).."}" local attrdict2, hlinfo - if self._hlstate_cterm then - attrdict2 = "{"..self:_pprint_attrs(item[2]).."}, " + local descdict = "" + if self._rgb_cterm then + attrdict2 = ", {"..self:_pprint_attrs(item[2]).."}" hlinfo = item[3] else attrdict2 = "" hlinfo = item[2] end - local descdict = "{"..self:_pprint_hlinfo(hlinfo).."}" - return "{"..attrdict..attrdict2..descdict.."}" + if self._options.ext_hlstate then + descdict = ", {"..self:_pprint_hlinfo(hlinfo).."}" + end + return (multi and "{" or "")..attrdict..attrdict2..descdict..(multi and "}" or "") end function Screen:_pprint_hlinfo(states) @@ -1464,9 +1472,11 @@ function Screen:_get_attr_id(attr_state, attrs, hl_id) return end - if self._options.ext_hlstate then + if self._options.ext_linegrid then local id = attr_state.id_to_index[hl_id] - if id ~= nil or hl_id == 0 then + if id == "" then -- sentinel for empty it + return nil + elseif id ~= nil then return id end if attr_state.mutable then @@ -1497,10 +1507,12 @@ function Screen:_get_attr_id(attr_state, attrs, hl_id) end function Screen:_equal_attr_def(a, b) - if self._hlstate_cterm then + if self._rgb_cterm then return self:_equal_attrs(a[1],b[1]) and self:_equal_attrs(a[2],b[2]) - else + elseif self._options.rgb then return self:_equal_attrs(a,b[1]) + else + return self:_equal_attrs(a,b[2]) end end -- cgit From a330129a280a34963e42d498f7cb1f53e6723e85 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 12 Oct 2019 13:29:51 +0200 Subject: tests/ui: cleanup illegitimate usages of "attr_ignore" "attr_ignore" is an anti-pattern, with snapshot_util() just include all the highlights already. --- .../legacy/063_match_and_matchadd_spec.lua | 20 +++++---- test/functional/legacy/search_spec.lua | 5 +-- test/functional/plugin/health_spec.lua | 20 ++++----- test/functional/plugin/man_spec.lua | 50 +++++++++++----------- test/functional/provider/clipboard_spec.lua | 48 +++++++++++++-------- test/functional/terminal/buffer_spec.lua | 6 +-- test/functional/ui/mouse_spec.lua | 14 +++--- test/functional/ui/screen.lua | 10 ++--- 8 files changed, 90 insertions(+), 83 deletions(-) (limited to 'test') diff --git a/test/functional/legacy/063_match_and_matchadd_spec.lua b/test/functional/legacy/063_match_and_matchadd_spec.lua index 518d79861b..a4f5d6ac5b 100644 --- a/test/functional/legacy/063_match_and_matchadd_spec.lua +++ b/test/functional/legacy/063_match_and_matchadd_spec.lua @@ -14,6 +14,10 @@ describe('063: Test for ":match", "matchadd()" and related functions', function( it('is working', function() local screen = Screen.new(40, 5) screen:attach() + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, + [1] = {background = Screen.colors.Red}, + }) -- Check that "matcharg()" returns the correct group and pattern if a match -- is defined. @@ -126,22 +130,22 @@ describe('063: Test for ":match", "matchadd()" and related functions', function( command("call matchaddpos('MyGroup1', [[1, 5], [1, 8, 3]], 10, 3)") screen:expect([[ abcd{1:e}fg{1:hij}klmnop^q | - ~ | - ~ | - ~ | + {0:~ }| + {0:~ }| + {0:~ }| | - ]], {[1] = {background = Screen.colors.Red}}, {{bold = true, foreground = Screen.colors.Blue}}) + ]]) command("call clearmatches()") command("call setline(1, 'abcdΣabcdef')") command("call matchaddpos('MyGroup1', [[1, 4, 2], [1, 9, 2]])") screen:expect([[ abc{1:dΣ}ab{1:cd}e^f | - ~ | - ~ | - ~ | + {0:~ }| + {0:~ }| + {0:~ }| | - ]],{[1] = {background = Screen.colors.Red}}, {{bold = true, foreground = Screen.colors.Blue}}) + ]]) end) end) diff --git a/test/functional/legacy/search_spec.lua b/test/functional/legacy/search_spec.lua index 3ed06a22e7..bed4dc2a09 100644 --- a/test/functional/legacy/search_spec.lua +++ b/test/functional/legacy/search_spec.lua @@ -408,10 +408,7 @@ describe('search cmdline', function() screen = Screen.new(20, 6) screen:attach() screen:set_default_attr_ids({ - inc = {reverse = true} - }) - screen:set_default_attr_ignore({ - {bold=true, reverse=true}, {bold=true, foreground=Screen.colors.Blue1} + inc = {reverse = true}, }) tenlines() diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua index 3525e235de..a78ed07876 100644 --- a/test/functional/plugin/health_spec.lua +++ b/test/functional/plugin/health_spec.lua @@ -116,8 +116,6 @@ describe('health.vim', function() screen:set_default_attr_ids({ Ok = { foreground = Screen.colors.Grey3, background = 6291200 }, Error = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - }) - screen:set_default_attr_ignore({ Heading = { bold=true, foreground=Screen.colors.Magenta }, Heading2 = { foreground = Screen.colors.SlateBlue }, Bar = { foreground=Screen.colors.Purple }, @@ -126,18 +124,18 @@ describe('health.vim', function() command("checkhealth foo success1") command("1tabclose") command("set laststatus=0") - screen:expect([[ + screen:expect{grid=[[ ^ | - health#foo#check | - ========================================================================| - - {Error:ERROR:} No healthcheck found for "foo" plugin. | + {Heading:health#foo#check} | + {Bar:========================================================================}| + {Bullet: -} {Error:ERROR:} No healthcheck found for "foo" plugin. | | - health#success1#check | - ========================================================================| - ## report 1 | - - {Ok:OK:} everything is fine | + {Heading:health#success1#check} | + {Bar:========================================================================}| + {Heading2:##}{Heading: report 1} | + {Bullet: -} {Ok:OK:} everything is fine | | - ]]) + ]]} end) it("gracefully handles invalid healthcheck", function() diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua index d95995797e..e06e4b874e 100644 --- a/test/functional/plugin/man_spec.lua +++ b/test/functional/plugin/man_spec.lua @@ -19,10 +19,8 @@ describe(':Man', function() u = { underline = true }, bi = { bold = true, italic = true }, biu = { bold = true, italic = true, underline = true }, - }) - screen:set_default_attr_ignore({ - { foreground = Screen.colors.Blue }, -- control chars - { bold = true, foreground = Screen.colors.Blue } -- empty line '~'s + c = { foreground = Screen.colors.Blue }, -- control chars + eob = { bold = true, foreground = Screen.colors.Blue } -- empty line '~'s }) screen:attach() end) @@ -36,21 +34,21 @@ describe(':Man', function() ithis iiss aa test with _o_v_e_r_s_t_r_u_c_k text]]) - screen:expect([[ - this i^His^Hs a^Ha test | - with _^Ho_^Hv_^He_^Hr_^Hs_^Ht_^Hr_^Hu_^Hc_^Hk tex^t | - ~ | - ~ | - | - ]]) + screen:expect{grid=[[ + this i{c:^H}is{c:^H}s a{c:^H}a test | + with _{c:^H}o_{c:^H}v_{c:^H}e_{c:^H}r_{c:^H}s_{c:^H}t_{c:^H}r_{c:^H}u_{c:^H}c_{c:^H}k tex^t | + {eob:~ }| + {eob:~ }| + | + ]]} eval('man#init_pager()') screen:expect([[ ^this {b:is} {b:a} test | with {u:overstruck} text | - ~ | - ~ | + {eob:~ }| + {eob:~ }| | ]]) end) @@ -60,21 +58,21 @@ describe(':Man', function() ithis [1mis [3ma [4mtest[0m [4mwith[24m [4mescaped[24m [4mtext[24m]]) - screen:expect([=[ - this ^[[1mis ^[[3ma ^[[4mtest^[[0m | - ^[[4mwith^[[24m ^[[4mescaped^[[24m ^[[4mtext^[[24^m | - ~ | - ~ | - | - ]=]) + screen:expect{grid=[=[ + this {c:^[}[1mis {c:^[}[3ma {c:^[}[4mtest{c:^[}[0m | + {c:^[}[4mwith{c:^[}[24m {c:^[}[4mescaped{c:^[}[24m {c:^[}[4mtext{c:^[}[24^m | + {eob:~ }| + {eob:~ }| + | + ]=]} eval('man#init_pager()') screen:expect([[ ^this {b:is }{bi:a }{biu:test} | {u:with} {u:escaped} {u:text} | - ~ | - ~ | + {eob:~ }| + {eob:~ }| | ]]) end) @@ -88,8 +86,8 @@ describe(':Man', function() screen:expect([[ ^this {b:is} {b:あ} test | with {u:överstrũck} te{i:xt¶} | - ~ | - ~ | + {eob:~ }| + {eob:~ }| | ]]) end) @@ -105,7 +103,7 @@ describe(':Man', function() {b:^_begins} | {b:mid_dle} | {u:mid_dle} | - ~ | + {eob:~ }| | ]]) end) @@ -121,7 +119,7 @@ describe(':Man', function() ^· {b:·} | {b:·} | {b:·} double | - ~ | + {eob:~ }| | ]]) end) diff --git a/test/functional/provider/clipboard_spec.lua b/test/functional/provider/clipboard_spec.lua index b2d75db745..da9dd09129 100644 --- a/test/functional/provider/clipboard_spec.lua +++ b/test/functional/provider/clipboard_spec.lua @@ -88,6 +88,11 @@ describe('clipboard', function() before_each(function() clear() screen = Screen.new(72, 4) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, + [1] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [2] = {bold = true, foreground = Screen.colors.SeaGreen4}, + }) screen:attach() command("set display-=msgsep") end) @@ -103,22 +108,22 @@ describe('clipboard', function() feed_command('redir @+> | :silent echo system("cat CONTRIBUTING.md") | redir END') screen:expect([[ ^ | - ~ | - ~ | + {0:~ }| + {0:~ }| clipboard: No provider. Try ":checkhealth" or ":h clipboard". | - ]], nil, {{bold = true, foreground = Screen.colors.Blue}}) + ]]) end) it('`:redir @+>|bogus_cmd|redir END` + invalid g:clipboard must not recurse #7184', function() command("let g:clipboard = 'bogus'") feed_command('redir @+> | bogus_cmd | redir END') - screen:expect([[ - ~ | + screen:expect{grid=[[ + {0:~ }| clipboard: No provider. Try ":checkhealth" or ":h clipboard". | - E492: Not an editor command: bogus_cmd | redir END | - Press ENTER or type command to continue^ | - ]], nil, {{bold = true, foreground = Screen.colors.Blue}}) + {1:E492: Not an editor command: bogus_cmd | redir END} | + {2:Press ENTER or type command to continue}^ | + ]]} end) it('invalid g:clipboard shows hint if :redir is not active', function() @@ -131,10 +136,10 @@ describe('clipboard', function() feed_command('let @+="foo"') screen:expect([[ ^ | - ~ | - ~ | + {0:~ }| + {0:~ }| clipboard: No provider. Try ":checkhealth" or ":h clipboard". | - ]], nil, {{bold = true, foreground = Screen.colors.Blue}}) + ]]) end) it('valid g:clipboard', function() @@ -266,13 +271,17 @@ describe('clipboard (with fake clipboard.vim)', function() function() local screen = Screen.new(72, 4) screen:attach() + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, + [1] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + }) feed_command('redir @+> | bogus_cmd | redir END') screen:expect([[ ^ | - ~ | - ~ | - E492: Not an editor command: bogus_cmd | redir END | - ]], nil, {{bold = true, foreground = Screen.colors.Blue}}) + {0:~ }| + {0:~ }| + {1:E492: Not an editor command: bogus_cmd | redir END} | + ]]) end) it('has independent "* and unnamed registers by default', function() @@ -637,6 +646,9 @@ describe('clipboard (with fake clipboard.vim)', function() feed_command('set mouse=a') local screen = Screen.new(30, 5) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, + }) screen:attach() insert([[ the source @@ -646,10 +658,10 @@ describe('clipboard (with fake clipboard.vim)', function() screen:expect([[ the ^source | a target | - ~ | - ~ | + {0:~ }| + {0:~ }| | - ]], nil, {{bold = true, foreground = Screen.colors.Blue}}) + ]]) feed('<0,1>') expect([[ diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index 1763574bf9..7560b0e872 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -208,18 +208,18 @@ describe(':terminal buffer', function() feed_command('terminal') feed('') feed_command('confirm bdelete') - screen:expect{any='Close "term://', attr_ignore=true} + screen:expect{any='Close "term://'} end) it('with &confirm', function() feed_command('terminal') feed('') feed_command('bdelete') - screen:expect{any='E89', attr_ignore=true} + screen:expect{any='E89'} feed('') eq('terminal', eval('&buftype')) feed_command('set confirm | bdelete') - screen:expect{any='Close "term://', attr_ignore=true} + screen:expect{any='Close "term://'} feed('y') neq('terminal', eval('&buftype')) end) diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index 440bae58e0..fedef7da8a 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -26,6 +26,8 @@ describe('ui/mouse/input', function() }, [4] = {reverse = true}, [5] = {bold = true, reverse = true}, + [6] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [7] = {bold = true, foreground = Screen.colors.SeaGreen4}, }) command("set display-=msgsep") feed('itestingmousesupport and selection') @@ -620,12 +622,12 @@ describe('ui/mouse/input', function() meths.set_option('tags', './non-existent-tags-file') feed('<0,0>') screen:expect([[ - E433: No tags file | - E426: tag not found: test| - ing | - Press ENTER or type comma| - nd to continue^ | - ]],nil,true) + {6:E433: No tags file} | + {6:E426: tag not found: test}| + {6:ing} | + {7:Press ENTER or type comma}| + {7:nd to continue}^ | + ]]) feed('') end) diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 68c3d54922..b15e2980de 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -66,7 +66,6 @@ -- [1] = {reverse = true, bold = true}, -- [2] = {reverse = true} -- }) --- screen:set_default_attr_ignore( {{}, {bold=true, foreground=NonText}} ) -- -- To help write screen tests, see Screen:snapshot_util(). -- To debug screen tests, see Screen:redraw_debug(). @@ -169,7 +168,6 @@ function Screen.new(width, height) ruler = {}, hl_groups = {}, _default_attr_ids = nil, - _default_attr_ignore = nil, _mouse_enabled = true, _attrs = {}, _hl_info = {[0]={}}, @@ -202,10 +200,6 @@ function Screen:get_default_attr_ids() return deepcopy(self._default_attr_ids) end -function Screen:set_default_attr_ignore(attr_ignore) - self._default_attr_ignore = attr_ignore -end - function Screen:set_rgb_cterm(val) self._rgb_cterm = val end @@ -361,7 +355,7 @@ function Screen:expect(expected, attr_ids, attr_ignore, ...) end local attr_state = { ids = attr_ids or self._default_attr_ids, - ignore = attr_ignore or self._default_attr_ignore, + ignore = attr_ignore } if self._options.ext_linegrid then attr_state.id_to_index = self:linegrid_check_attrs(attr_state.ids or {}) @@ -1478,6 +1472,8 @@ function Screen:_get_attr_id(attr_state, attrs, hl_id) return nil elseif id ~= nil then return id + elseif attr_state.ignore == true then + return nil end if attr_state.mutable then id = self:_insert_hl_id(attr_state, hl_id) -- cgit From 4987311fb5b8f4a11d26995f71f5f402a9e2ace4 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 13 Oct 2019 20:18:22 +0200 Subject: tests/ui: remove unnecessary screen:detach() It is perfectly fine and expected to detach from the screen just by the UI disconnecting from nvim or exiting nvim. Just keep detach() in screen_basic_spec, to get some coverage of the detach method itself. This avoids hang on failure in many situations (though one could argue that detach() should be "fast", or at least "as fast as resize", which works in press-return already). Never use detach() just to change the size of the screen, try_resize() method exists for that specifically. --- test/functional/api/menu_spec.lua | 4 ---- test/functional/core/job_spec.lua | 3 --- test/functional/eval/api_functions_spec.lua | 1 - test/functional/eval/system_spec.lua | 4 ---- test/functional/ex_cmds/drop_spec.lua | 4 ---- test/functional/ex_cmds/highlight_spec.lua | 4 ---- test/functional/legacy/045_folding_spec.lua | 3 --- test/functional/legacy/search_spec.lua | 31 +++++++--------------------- test/functional/options/chars_spec.lua | 8 ------- test/functional/plugin/man_spec.lua | 4 ---- test/functional/terminal/mouse_spec.lua | 4 ---- test/functional/terminal/scrollback_spec.lua | 8 ------- test/functional/terminal/tui_spec.lua | 4 ---- test/functional/ui/bufhl_spec.lua | 4 ---- test/functional/ui/cmdline_spec.lua | 8 ------- test/functional/ui/cursor_spec.lua | 4 ---- test/functional/ui/fold_spec.lua | 4 ---- test/functional/ui/highlight_spec.lua | 31 +++++++--------------------- test/functional/ui/inccommand_spec.lua | 15 -------------- test/functional/ui/mouse_spec.lua | 4 ---- test/functional/ui/multibyte_spec.lua | 8 ------- test/functional/ui/multigrid_spec.lua | 4 ---- test/functional/ui/options_spec.lua | 4 ---- test/functional/ui/output_spec.lua | 1 - test/functional/ui/sign_spec.lua | 4 ---- test/functional/ui/spell_spec.lua | 4 ---- test/functional/ui/syntax_conceal_spec.lua | 4 ---- test/functional/ui/tabline_spec.lua | 4 ---- 28 files changed, 14 insertions(+), 171 deletions(-) (limited to 'test') diff --git a/test/functional/api/menu_spec.lua b/test/functional/api/menu_spec.lua index 2cfa0e3e47..34a92477f3 100644 --- a/test/functional/api/menu_spec.lua +++ b/test/functional/api/menu_spec.lua @@ -15,10 +15,6 @@ describe("update_menu notification", function() screen:attach() end) - after_each(function() - screen:detach() - end) - local function expect_sent(expected) screen:expect{condition=function() if screen.update_menu ~= expected then diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index 9c37e55f42..d4ce690867 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -963,9 +963,6 @@ describe("pty process teardown", function() | ]]) end) - after_each(function() - screen:detach() - end) it("does not prevent/delay exit. #4798 #4900", function() if helpers.pending_win32(pending) then return end diff --git a/test/functional/eval/api_functions_spec.lua b/test/functional/eval/api_functions_spec.lua index 4fbd08f102..f527aff33f 100644 --- a/test/functional/eval/api_functions_spec.lua +++ b/test/functional/eval/api_functions_spec.lua @@ -144,7 +144,6 @@ describe('eval-API', function() {5:~ }| | ]]) - screen:detach() end) it('cannot be called from sandbox', function() diff --git a/test/functional/eval/system_spec.lua b/test/functional/eval/system_spec.lua index 85d57006b5..1e4d760dbc 100644 --- a/test/functional/eval/system_spec.lua +++ b/test/functional/eval/system_spec.lua @@ -121,10 +121,6 @@ describe('system()', function() screen:attach() end) - after_each(function() - screen:detach() - end) - if iswin() then local function test_more() eq('root = true', eval([[get(split(system('"more" ".editorconfig"'), "\n"), 0, '')]])) diff --git a/test/functional/ex_cmds/drop_spec.lua b/test/functional/ex_cmds/drop_spec.lua index d6da0d8e88..762ea3d166 100644 --- a/test/functional/ex_cmds/drop_spec.lua +++ b/test/functional/ex_cmds/drop_spec.lua @@ -19,10 +19,6 @@ describe(":drop", function() command("set laststatus=2 shortmess-=F") end) - after_each(function() - screen:detach() - end) - it("works like :e when called with only one window open", function() feed_command("drop tmp1.vim") screen:expect([[ diff --git a/test/functional/ex_cmds/highlight_spec.lua b/test/functional/ex_cmds/highlight_spec.lua index 25968b8204..1cd6759a53 100644 --- a/test/functional/ex_cmds/highlight_spec.lua +++ b/test/functional/ex_cmds/highlight_spec.lua @@ -13,10 +13,6 @@ describe(':highlight', function() screen:attach() end) - after_each(function() - screen:detach() - end) - it('invalid color name', function() eq('Vim(highlight):E421: Color name or number not recognized: ctermfg=#181818', exc_exec("highlight normal ctermfg=#181818")) diff --git a/test/functional/legacy/045_folding_spec.lua b/test/functional/legacy/045_folding_spec.lua index 6ca1176aea..1e5239ceac 100644 --- a/test/functional/legacy/045_folding_spec.lua +++ b/test/functional/legacy/045_folding_spec.lua @@ -14,9 +14,6 @@ describe('folding', function() screen = Screen.new(20, 8) screen:attach() end) - after_each(function() - screen:detach() - end) it('creation, opening, moving (to the end) and closing', function() insert([[ diff --git a/test/functional/legacy/search_spec.lua b/test/functional/legacy/search_spec.lua index bed4dc2a09..a207b176d3 100644 --- a/test/functional/legacy/search_spec.lua +++ b/test/functional/legacy/search_spec.lua @@ -17,7 +17,10 @@ describe('search cmdline', function() screen = Screen.new(20, 3) screen:attach() screen:set_default_attr_ids({ - inc = {reverse = true} + inc = {reverse = true}, + err = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, + more = { bold = true, foreground = Screen.colors.SeaGreen4 }, + tilde = { bold = true, foreground = Screen.colors.Blue1 }, }) end) @@ -404,12 +407,7 @@ describe('search cmdline', function() end) it('keeps the view after deleting a char from the search', function() - screen:detach() - screen = Screen.new(20, 6) - screen:attach() - screen:set_default_attr_ids({ - inc = {reverse = true}, - }) + screen:try_resize(20, 6) tenlines() feed('/foo') @@ -445,14 +443,7 @@ describe('search cmdline', function() end) it('restores original view after failed search', function() - screen:detach() - screen = Screen.new(40, 3) - screen:attach() - screen:set_default_attr_ids({ - inc = {reverse = true}, - err = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - more = { bold = true, foreground = Screen.colors.SeaGreen4 }, - }) + screen:try_resize(40, 3) tenlines() feed('0') feed('/foo') @@ -481,15 +472,7 @@ describe('search cmdline', function() it("CTRL-G with 'incsearch' and ? goes in the right direction", function() -- oldtest: Test_search_cmdline4(). - screen:detach() - screen = Screen.new(40, 4) - screen:attach() - screen:set_default_attr_ids({ - inc = {reverse = true}, - err = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - more = { bold = true, foreground = Screen.colors.SeaGreen4 }, - tilde = { bold = true, foreground = Screen.colors.Blue1 }, - }) + screen:try_resize(40, 4) command('enew!') funcs.setline(1, {' 1 the first', ' 2 the second', ' 3 the third'}) command('set laststatus=0 shortmess+=s') diff --git a/test/functional/options/chars_spec.lua b/test/functional/options/chars_spec.lua index 1330c29e61..3453e79429 100644 --- a/test/functional/options/chars_spec.lua +++ b/test/functional/options/chars_spec.lua @@ -16,10 +16,6 @@ describe("'fillchars'", function() screen:attach() end) - after_each(function() - screen:detach() - end) - local function shouldfail(val,errval) errval = errval or val eq('Vim(set):E474: Invalid argument: fillchars='..errval, @@ -100,10 +96,6 @@ describe("'listchars'", function() screen:attach() end) - after_each(function() - screen:detach() - end) - it('is local to window', function() feed('i') command('set laststatus=0') diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua index e06e4b874e..e5b2e7dc1f 100644 --- a/test/functional/plugin/man_spec.lua +++ b/test/functional/plugin/man_spec.lua @@ -25,10 +25,6 @@ describe(':Man', function() screen:attach() end) - after_each(function() - screen:detach() - end) - it('clears backspaces from text and adds highlights', function() rawfeed([[ ithis iiss aa test diff --git a/test/functional/terminal/mouse_spec.lua b/test/functional/terminal/mouse_spec.lua index 64f437f206..ee3db7ae97 100644 --- a/test/functional/terminal/mouse_spec.lua +++ b/test/functional/terminal/mouse_spec.lua @@ -31,10 +31,6 @@ describe(':terminal mouse', function() ]]) end) - after_each(function() - screen:detach() - end) - describe('when the terminal has focus', function() it('will exit focus on mouse-scroll', function() eq('t', eval('mode()')) diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua index ff6a74fe89..060f065bfc 100644 --- a/test/functional/terminal/scrollback_spec.lua +++ b/test/functional/terminal/scrollback_spec.lua @@ -21,10 +21,6 @@ describe(':terminal scrollback', function() screen = thelpers.screen_setup(nil, nil, 30) end) - after_each(function() - screen:detach() - end) - describe('when the limit is exceeded', function() before_each(function() local lines = {} @@ -406,8 +402,6 @@ describe("'scrollback' option", function() feed_data(nvim_dir..'/shell-test REP 31 line'..(iswin() and '\r' or '\n')) screen:expect{any='30: line '} retry(nil, nil, function() expect_lines(7) end) - - screen:detach() end) it('deletes lines (only) if necessary', function() @@ -464,8 +458,6 @@ describe("'scrollback' option", function() -- Verify off-screen state eq((iswin() and '36: line' or '35: line'), eval("getline(line('w0') - 1)")) eq((iswin() and '27: line' or '26: line'), eval("getline(line('w0') - 10)")) - - screen:detach() end) it('defaults to 10000 in :terminal buffers', function() diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 978267e040..326a578bb7 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -45,10 +45,6 @@ describe('TUI', function() child_session = helpers.connect(child_server) end) - after_each(function() - screen:detach() - end) - -- Wait for mode in the child Nvim (avoid "typeahead race" #10826). local function wait_for_mode(mode) retry(nil, nil, function() diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua index d8ca947645..5df909f79c 100644 --- a/test/functional/ui/bufhl_spec.lua +++ b/test/functional/ui/bufhl_spec.lua @@ -37,10 +37,6 @@ describe('Buffer highlighting', function() }) end) - after_each(function() - screen:detach() - end) - local add_highlight = curbufmeths.add_highlight local clear_namespace = curbufmeths.clear_namespace diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index f9769c706f..fe1b2c13d1 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -25,10 +25,6 @@ local function test_cmdline(linegrid) screen = new_screen({rgb=true, ext_cmdline=true, ext_linegrid=linegrid}) end) - after_each(function() - screen:detach() - end) - it('works', function() feed(':') screen:expect{grid=[[ @@ -804,10 +800,6 @@ describe('cmdline redraw', function() screen = new_screen({rgb=true}) end) - after_each(function() - screen:detach() - end) - it('with timer', function() feed(':012345678901234567890123456789') screen:expect{grid=[[ diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua index 67aba919b0..8ad4182f41 100644 --- a/test/functional/ui/cursor_spec.lua +++ b/test/functional/ui/cursor_spec.lua @@ -13,10 +13,6 @@ describe('ui/cursor', function() screen:attach() end) - after_each(function() - screen:detach() - end) - it("'guicursor' is published as a UI event", function() local expected_mode_info = { [1] = { diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua index c5ef718883..eb81aba131 100644 --- a/test/functional/ui/fold_spec.lua +++ b/test/functional/ui/fold_spec.lua @@ -24,10 +24,6 @@ describe("folded lines", function() }) end) - after_each(function() - screen:detach() - end) - it("work with more than one signcolumn", function() command("set signcolumn=yes:9") feed("i") diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index 1b25570997..d7791a3107 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -35,7 +35,6 @@ describe('highlight: `:syntax manual`', function() end) after_each(function() - screen:detach() os.remove('Xtest-functional-ui-highlight.tmp.vim') end) @@ -97,10 +96,6 @@ describe('highlight defaults', function() command("set display-=msgsep") end) - after_each(function() - screen:detach() - end) - it('window status bar', function() screen:set_default_attr_ids({ [0] = {bold=true, foreground=Screen.colors.Blue}, @@ -346,17 +341,10 @@ describe('highlight defaults', function() end) describe('highlight', function() - local screen - - before_each(function() - clear() - screen = Screen.new(25,10) - screen:attach() - end) + before_each(clear) it('visual', function() - screen:detach() - screen = Screen.new(20,4) + local screen = Screen.new(20,4) screen:attach() screen:set_default_attr_ids({ [1] = {background = Screen.colors.LightGrey}, @@ -389,8 +377,7 @@ describe('highlight', function() end) it('cterm=standout gui=standout', function() - screen:detach() - screen = Screen.new(20,5) + local screen = Screen.new(20,5) screen:attach() screen:set_default_attr_ids({ [1] = {bold = true, foreground = Screen.colors.Blue1}, @@ -413,8 +400,7 @@ describe('highlight', function() end) it('strikethrough', function() - screen:detach() - screen = Screen.new(25,6) + local screen = Screen.new(25,6) screen:attach() feed_command('syntax on') feed_command('syn keyword TmpKeyword foo') @@ -439,8 +425,7 @@ describe('highlight', function() end) it('nocombine', function() - screen:detach() - screen = Screen.new(25,6) + local screen = Screen.new(25,6) screen:set_default_attr_ids{ [1] = {foreground = Screen.colors.SlateBlue, underline = true}, [2] = {bold = true, foreground = Screen.colors.Blue1}, @@ -487,6 +472,8 @@ describe('highlight', function() end) it('guisp (special/undercurl)', function() + local screen = Screen.new(25,10) + screen:attach() feed_command('syntax on') feed_command('syn keyword TmpKeyword neovim') feed_command('syn keyword TmpKeyword1 special') @@ -542,10 +529,6 @@ describe("'listchars' highlight", function() screen:attach() end) - after_each(function() - screen:detach() - end) - it("'cursorline' and 'cursorcolumn'", function() screen:set_default_attr_ids({ [0] = {bold=true, foreground=Screen.colors.Blue}, diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua index e9a7c8c2df..d60cd08fb0 100644 --- a/test/functional/ui/inccommand_spec.lua +++ b/test/functional/ui/inccommand_spec.lua @@ -556,7 +556,6 @@ describe(":substitute, 'inccommand' preserves undo", function() ]]) end end - screen:detach() end) it('with undolevels=2', function() @@ -647,7 +646,6 @@ describe(":substitute, 'inccommand' preserves undo", function() Already ...t change | ]]) end - screen:detach() end end) @@ -713,7 +711,6 @@ describe(":substitute, 'inccommand' preserves undo", function() Already ...t change | ]]) end - screen:detach() end) end) @@ -726,10 +723,6 @@ describe(":substitute, inccommand=split", function() common_setup(screen, "split", default_text .. default_text) end) - after_each(function() - screen:detach() - end) - it("preserves 'modified' buffer flag", function() feed_command("set nomodified") feed(":%s/tw") @@ -1241,10 +1234,6 @@ describe("inccommand=nosplit", function() common_setup(screen, "nosplit", default_text .. default_text) end) - after_each(function() - if screen then screen:detach() end - end) - it("works with :smagic, :snomagic", function() feed_command("set hlsearch") insert("Line *.3.* here") @@ -1719,10 +1708,6 @@ describe("'inccommand' split windows", function() common_setup(screen, "split", default_text) end - after_each(function() - screen:detach() - end) - it('work after more splits', function() refresh() diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index fedef7da8a..7840ba9167 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -40,10 +40,6 @@ describe('ui/mouse/input', function() ]]) end) - after_each(function() - screen:detach() - end) - it('single left click moves cursor', function() feed('<2,1>') screen:expect([[ diff --git a/test/functional/ui/multibyte_spec.lua b/test/functional/ui/multibyte_spec.lua index 3e63353ad2..8122cb08a3 100644 --- a/test/functional/ui/multibyte_spec.lua +++ b/test/functional/ui/multibyte_spec.lua @@ -21,10 +21,6 @@ describe("multibyte rendering", function() }) end) - after_each(function() - screen:detach() - end) - it("works with composed char at start of line", function() insert([[ ̊ @@ -131,10 +127,6 @@ describe('multibyte rendering: statusline', function() command('set laststatus=2') end) - after_each(function() - screen:detach() - end) - it('last char shows (multibyte)', function() command('set statusline=你好') screen:expect([[ diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua index 30a5b63d89..01ffe80be3 100644 --- a/test/functional/ui/multigrid_spec.lua +++ b/test/functional/ui/multigrid_spec.lua @@ -37,10 +37,6 @@ describe('ext_multigrid', function() }) end) - after_each(function() - screen:detach() - end) - it('default initial screen', function() screen:expect{grid=[[ ## grid 1 diff --git a/test/functional/ui/options_spec.lua b/test/functional/ui/options_spec.lua index 93192934c7..ea71f5eae9 100644 --- a/test/functional/ui/options_spec.lua +++ b/test/functional/ui/options_spec.lua @@ -40,10 +40,6 @@ describe('ui receives option updates', function() return defaults end - after_each(function() - screen:detach() - end) - it("for defaults", function() local expected = reset() screen:expect(function() diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua index 20413cb784..a201dfe898 100644 --- a/test/functional/ui/output_spec.lua +++ b/test/functional/ui/output_spec.lua @@ -31,7 +31,6 @@ describe("shell command :!", function() after_each(function() child_session.feed_data("\3") -- Ctrl-C - screen:detach() end) it("displays output without LF/EOF. #4646 #4569 #3772", function() diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua index 68e675b8e5..0ed62b21b2 100644 --- a/test/functional/ui/sign_spec.lua +++ b/test/functional/ui/sign_spec.lua @@ -26,10 +26,6 @@ describe('Signs', function() } ) end) - after_each(function() - screen:detach() - end) - describe(':sign place', function() it('allows signs with combining characters', function() feed('iab') diff --git a/test/functional/ui/spell_spec.lua b/test/functional/ui/spell_spec.lua index 913f1b9bed..243b737583 100644 --- a/test/functional/ui/spell_spec.lua +++ b/test/functional/ui/spell_spec.lua @@ -20,10 +20,6 @@ describe("'spell'", function() }) end) - after_each(function() - screen:detach() - end) - it('joins long lines #7937', function() feed_command('set spell') insert([[ diff --git a/test/functional/ui/syntax_conceal_spec.lua b/test/functional/ui/syntax_conceal_spec.lua index 566d183f11..d1af0e955c 100644 --- a/test/functional/ui/syntax_conceal_spec.lua +++ b/test/functional/ui/syntax_conceal_spec.lua @@ -22,10 +22,6 @@ describe('Screen', function() } ) end) - after_each(function() - screen:detach() - end) - describe("match and conceal", function() before_each(function() diff --git a/test/functional/ui/tabline_spec.lua b/test/functional/ui/tabline_spec.lua index dcab9f7ef4..0ee7e03fac 100644 --- a/test/functional/ui/tabline_spec.lua +++ b/test/functional/ui/tabline_spec.lua @@ -17,10 +17,6 @@ describe('ui/ext_tabline', function() end) end) - after_each(function() - screen:detach() - end) - it('publishes UI events', function() command("tabedit another-tab") -- cgit From cc0d7252304f10ed6cdc0bc58789100093f7d021 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 13 Oct 2019 09:19:57 +0200 Subject: tests/ui: completely delete "attr_ignore" feature All existing usages are ad-hoc/random/lazyness. Generating attribute specifications is not hard since four years, just do it always. --- test/functional/ui/screen.lua | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) (limited to 'test') diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index b15e2980de..8bc1e14e13 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -259,7 +259,7 @@ local ext_keys = { -- Asserts that the screen state eventually matches an expected state. -- -- Can be called with positional args: --- screen:expect(grid, [attr_ids, attr_ignore]) +-- screen:expect(grid, [attr_ids]) -- screen:expect(condition) -- or keyword args (supports more options): -- screen:expect{grid=[[...]], cmdline={...}, condition=function() ... end} @@ -276,8 +276,6 @@ local ext_keys = { -- attributes in the final state are an error. -- Use screen:set_default_attr_ids() to define attributes for many -- expect() calls. --- attr_ignore: Ignored text attributes, or `true` to ignore all. By default --- nothing is ignored. -- condition: Function asserting some arbitrary condition. Return value is -- ignored, throw an error (use eq() or similar) to signal failure. -- any: Lua pattern string expected to match a screen line. NB: the @@ -312,13 +310,13 @@ local ext_keys = { -- cmdline_block: Expected ext_cmdline block (for function definitions) -- wildmenu_items: Expected items for ext_wildmenu -- wildmenu_pos: Expected position for ext_wildmenu -function Screen:expect(expected, attr_ids, attr_ignore, ...) +function Screen:expect(expected, attr_ids, ...) local grid, condition = nil, nil local expected_rows = {} assert(next({...}) == nil, "invalid args to expect()") if type(expected) == "table" then - assert(not (attr_ids ~= nil or attr_ignore ~= nil)) - local is_key = {grid=true, attr_ids=true, attr_ignore=true, condition=true, + assert(not (attr_ids ~= nil)) + local is_key = {grid=true, attr_ids=true, condition=true, any=true, mode=true, unchanged=true, intermediate=true, reset=true, timeout=true, request_cb=true, hl_groups=true} for _, v in ipairs(ext_keys) do @@ -331,14 +329,13 @@ function Screen:expect(expected, attr_ids, attr_ignore, ...) end grid = expected.grid attr_ids = expected.attr_ids - attr_ignore = expected.attr_ignore condition = expected.condition assert(not (expected.any ~= nil and grid ~= nil)) elseif type(expected) == "string" then grid = expected expected = {} elseif type(expected) == "function" then - assert(not (attr_ids ~= nil or attr_ignore ~= nil)) + assert(not (attr_ids ~= nil)) condition = expected expected = {} else @@ -355,7 +352,6 @@ function Screen:expect(expected, attr_ids, attr_ignore, ...) end local attr_state = { ids = attr_ids or self._default_attr_ids, - ignore = attr_ignore } if self._options.ext_linegrid then attr_state.id_to_index = self:linegrid_check_attrs(attr_state.ids or {}) @@ -1472,8 +1468,6 @@ function Screen:_get_attr_id(attr_state, attrs, hl_id) return nil elseif id ~= nil then return id - elseif attr_state.ignore == true then - return nil end if attr_state.mutable then id = self:_insert_hl_id(attr_state, hl_id) @@ -1482,9 +1476,7 @@ function Screen:_get_attr_id(attr_state, attrs, hl_id) end return "UNEXPECTED "..self:_pprint_attrs(self._attr_table[hl_id][1]) else - if self:_equal_attrs(attrs, {}) or - attr_state.ignore == true or - self:_attr_index(attr_state.ignore, attrs) ~= nil then + if self:_equal_attrs(attrs, {}) then -- ignore this attrs return nil end -- cgit From 932edf4f338c4d31f94fdaaa125d3ff8c2e6fe08 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Tue, 15 Oct 2019 20:50:51 +0200 Subject: tests: tui_spec: fix waiting for terminal to be ready (#11232) The screen would have '-- TERMINAL --' already initially. Related to flakiness of "TUI FocusGained/FocusLost in terminal-mode". --- test/functional/terminal/tui_spec.lua | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 326a578bb7..4f5cfa930a 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -924,7 +924,15 @@ describe('TUI FocusGained/FocusLost', function() feed_data(':terminal\n') -- Wait for terminal to be ready. - screen:expect{any='-- TERMINAL --'} + screen:expect{grid=[[ + {1:r}eady $ | + [Process exited 0] | + | + | + | + :terminal | + {3:-- TERMINAL --} | + ]]} feed_data('\027[I') screen:expect{grid=[[ -- cgit From 4bbad5481773ac2a273a41a9fe8035ca57e03cd8 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 18 Oct 2019 04:46:30 +0200 Subject: tests: fix non-controversial misuse of `pending` (#11247) Ref: https://github.com/neovim/neovim/pull/11184 --- test/functional/api/server_requests_spec.lua | 9 +++------ test/functional/core/job_spec.lua | 3 +-- test/functional/ex_cmds/write_spec.lua | 7 +++---- test/functional/legacy/delete_spec.lua | 2 +- test/functional/terminal/tui_spec.lua | 2 +- test/functional/ui/cmdline_spec.lua | 3 +-- test/functional/ui/embed_spec.lua | 3 +-- test/functional/ui/output_spec.lua | 6 ++---- 8 files changed, 13 insertions(+), 22 deletions(-) (limited to 'test') diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index 5a9ef7dd40..61184d2c59 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -317,8 +317,7 @@ describe('server -> client', function() set_session(server) local status, address = pcall(funcs.serverstart, "127.0.0.1:") if not status then - pending('no ipv4 stack', function() end) - return + pending('no ipv4 stack') end eq('127.0.0.1:', string.sub(address,1,10)) connect_test(server, 'tcp', address) @@ -329,8 +328,7 @@ describe('server -> client', function() set_session(server) local status, address = pcall(funcs.serverstart, '::1:') if not status then - pending('no ipv6 stack', function() end) - return + pending('no ipv6 stack') end eq('::1:', string.sub(address,1,4)) connect_test(server, 'tcp', address) @@ -349,8 +347,7 @@ describe('server -> client', function() it('does not deadlock', function() if not helpers.isCI('travis') and helpers.is_os('mac') then -- It does, in fact, deadlock on QuickBuild. #6851 - pending("deadlocks on QuickBuild", function() end) - return + pending("deadlocks on QuickBuild") end local address = funcs.serverlist()[1] local first = string.sub(address,1,1) diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index d4ce690867..d285008a33 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -202,8 +202,7 @@ describe('jobs', function() if helpers.isCI('travis') and os.getenv('CC') == 'gcc-4.9' and helpers.is_os('mac') then -- XXX: Hangs Travis macOS since e9061117a5b8f195c3f26a5cb94e18ddd7752d86. - pending("[Hangs on Travis macOS. #5002]", function() end) - return + pending("[Hangs on Travis macOS. #5002]") end nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)") diff --git a/test/functional/ex_cmds/write_spec.lua b/test/functional/ex_cmds/write_spec.lua index 3f54ff6f41..4f526ddfca 100644 --- a/test/functional/ex_cmds/write_spec.lua +++ b/test/functional/ex_cmds/write_spec.lua @@ -41,7 +41,7 @@ describe(':write', function() command("silent !ln -s test_bkc_file.txt test_bkc_link.txt") end if eval('v:shell_error') ~= 0 then - pending('Cannot create symlink', function()end) + pending('Cannot create symlink') end source([[ edit test_bkc_link.txt @@ -61,7 +61,7 @@ describe(':write', function() command("silent !ln -s test_bkc_file.txt test_bkc_link.txt") end if eval('v:shell_error') ~= 0 then - pending('Cannot create symlink', function()end) + pending('Cannot create symlink') end source([[ edit test_bkc_link.txt @@ -75,8 +75,7 @@ describe(':write', function() it("appends FIFO file", function() -- mkfifo creates read-only .lnk files on Windows if iswin() or eval("executable('mkfifo')") == 0 then - pending('missing "mkfifo" command', function()end) - return + pending('missing "mkfifo" command') end local text = "some fifo text from write_spec" diff --git a/test/functional/legacy/delete_spec.lua b/test/functional/legacy/delete_spec.lua index 9ea3269828..f2ced8942d 100644 --- a/test/functional/legacy/delete_spec.lua +++ b/test/functional/legacy/delete_spec.lua @@ -56,7 +56,7 @@ describe('Test for delete()', function() endif ]]) if eval('v:shell_error') ~= 0 then - pending('Cannot create symlink', function()end) + pending('Cannot create symlink') end -- Delete the link, not the file eq(0, eval("delete('Xlink')")) diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 4f5cfa930a..bc83660c19 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -1287,7 +1287,7 @@ describe("TUI 'term' option", function() elseif is_macos then local status, _ = pcall(assert_term, "xterm", "xterm") if not status then - pending("macOS: unibilium could not find terminfo", function() end) + pending("macOS: unibilium could not find terminfo") end else assert_term("xterm", "xterm") diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index fe1b2c13d1..c2354103c2 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -821,8 +821,7 @@ describe('cmdline redraw', function() it('with ', function() if 'openbsd' == helpers.uname() then - pending('FIXME #10804', function() end) - return + pending('FIXME #10804') end command('cmap a call sin(0)') -- no-op feed(':012345678901234567890123456789') diff --git a/test/functional/ui/embed_spec.lua b/test/functional/ui/embed_spec.lua index f3cd223f53..8218c8e12d 100644 --- a/test/functional/ui/embed_spec.lua +++ b/test/functional/ui/embed_spec.lua @@ -50,8 +50,7 @@ local function test_embed(ext_linegrid) it("doesn't erase output when setting color scheme", function() if 'openbsd' == helpers.uname() then - pending('FIXME #10804', function() end) - return + pending('FIXME #10804') end startup('--cmd', 'echoerr "foo"', '--cmd', 'color default', '--cmd', 'echoerr "bar"') screen:expect([[ diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua index a201dfe898..9b1e803649 100644 --- a/test/functional/ui/output_spec.lua +++ b/test/functional/ui/output_spec.lua @@ -51,8 +51,7 @@ describe("shell command :!", function() it("throttles shell-command output greater than ~10KB", function() if 'openbsd' == helpers.uname() then - pending('FIXME #10804', function() end) - return + pending('FIXME #10804') end child_session.feed_data(":!"..nvim_dir.."/shell-test REP 30001 foo\n") @@ -96,8 +95,7 @@ describe("shell command :!", function() it('handles control codes', function() if iswin() then - pending('missing printf', function() end) - return + pending('missing printf') end local screen = Screen.new(50, 4) screen:attach() -- cgit From 84aa86afb7c58f6a769ec9215fa69dec19619f5f Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 18 Oct 2019 16:32:56 +0200 Subject: build: do not build test fixtures by default (#11230) - tty-test is also used on Windows - FUNCTIONALTEST_PREREQS: add printenv-test --- test/functional/fixtures/CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'test') diff --git a/test/functional/fixtures/CMakeLists.txt b/test/functional/fixtures/CMakeLists.txt index dbcb157956..270540de2e 100644 --- a/test/functional/fixtures/CMakeLists.txt +++ b/test/functional/fixtures/CMakeLists.txt @@ -1,12 +1,12 @@ -add_executable(tty-test tty-test.c) +add_executable(tty-test EXCLUDE_FROM_ALL tty-test.c) target_link_libraries(tty-test ${LIBUV_LIBRARIES}) -add_executable(shell-test shell-test.c) -add_executable(printargs-test printargs-test.c) -add_executable(printenv-test printenv-test.c) +add_executable(shell-test EXCLUDE_FROM_ALL shell-test.c) +add_executable(printargs-test EXCLUDE_FROM_ALL printargs-test.c) +add_executable(printenv-test EXCLUDE_FROM_ALL printenv-test.c) if(WIN32) set_target_properties(printenv-test PROPERTIES LINK_FLAGS -municode) endif() -add_executable(streams-test streams-test.c) +add_executable(streams-test EXCLUDE_FROM_ALL streams-test.c) target_link_libraries(streams-test ${LIBUV_LIBRARIES}) -- cgit From 175ca82ca7baec7ce449d9e72f77a8f12d2e50dc Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 18 Oct 2019 20:41:24 +0200 Subject: tests: let_spec: enable "multibyte env var to child process" (#11233) --- test/functional/eval/let_spec.lua | 4 ---- test/functional/fixtures/printenv-test.c | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) (limited to 'test') diff --git a/test/functional/eval/let_spec.lua b/test/functional/eval/let_spec.lua index 63e18f943f..f8fcdfd41f 100644 --- a/test/functional/eval/let_spec.lua +++ b/test/functional/eval/let_spec.lua @@ -59,10 +59,6 @@ describe(':let', function() end) it("multibyte env var to child process #8398 #9267", function() - if (not helpers.iswin()) and helpers.isCI() then - -- Fails on non-Windows CI. Buffering/timing issue? - pending('fails on unix CI', function() end) - end local cmd_get_child_env = "let g:env_from_child = system(['"..nvim_dir.."/printenv-test', 'NVIM_TEST'])" command("let $NVIM_TEST = 'AìaB'") command(cmd_get_child_env) diff --git a/test/functional/fixtures/printenv-test.c b/test/functional/fixtures/printenv-test.c index 5ac076f653..0e68129543 100644 --- a/test/functional/fixtures/printenv-test.c +++ b/test/functional/fixtures/printenv-test.c @@ -44,7 +44,7 @@ int main(int argc, char **argv) utf8_len, NULL, NULL); - fprintf(stderr, "%s", utf8_value); + fprintf(stdout, "%s", utf8_value); free(utf8_value); #else char *value = getenv(argv[1]); @@ -52,8 +52,8 @@ int main(int argc, char **argv) fprintf(stderr, "env var not found: %s", argv[1]); return 1; } - // Print to stderr to avoid buffering. - fprintf(stderr, "%s", value); + fprintf(stdout, "%s", value); #endif + fflush(stdout); return 0; } -- cgit From d89ec55c45e73544c614a3436ae16b9ea17b5535 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 19 Oct 2019 23:15:07 +0200 Subject: test/functional: retry/Screen: failure instead of error #11173 - Running out of retries, or unexpected screen state should make the test FAIL, not ERROR. - Uses levels to report the location of the caller. - Improve message with retry-failure (formatting). Before: [ RUN ] test: 103.53 ms ERR test/functional/helpers.lua:388: retry() attempts: 1 test/functional/ui/screen.lua:587: Row 1 did not match. Expected: |*X^ | |{0:~ }| |{0:~ }| | | Actual: |*^ | |{0:~ }| |{0:~ }| | | To print the expect() call that would assert the current screen state, use screen:snapshot_util(). In case of non-deterministic failures, use screen:redraw_debug() to show all intermediate screen states. stack traceback: test/functional/helpers.lua:388: in function 'retry' test/functional/test_spec.lua:24: in function After: [ RUN ] test: 105.22 ms FAIL test/functional/test_spec.lua:24: stopping after 1 retry() attempts. test/functional/test_spec.lua:25: Row 1 did not match. Expected: |*X^ | |{0:~ }| |{0:~ }| | | Actual: |*^ | |{0:~ }| |{0:~ }| | | To print the expect() call that would assert the current screen state, use screen:snapshot_util(). In case of non-deterministic failures, use screen:redraw_debug() to show all intermediate screen states. stack traceback: test/functional/helpers.lua:389: in function 'retry' test/functional/test_spec.lua:24: in function --- test/functional/helpers.lua | 3 ++- test/functional/ui/screen.lua | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 2473fc0d3b..a6ff10c0a4 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -1,4 +1,5 @@ require('coxpcall') +local busted = require('busted') local luv = require('luv') local lfs = require('lfs') local mpack = require('mpack') @@ -385,7 +386,7 @@ function module.retry(max, max_ms, fn) end luv.update_time() -- Update cached value of luv.now() (libuv: uv_now()). if (max and tries >= max) or (luv.now() - start_time > timeout) then - error("\nretry() attempts: "..tostring(tries).."\n"..tostring(result)) + busted.fail(string.format("retry() attempts: %d\n%s", tries, tostring(result)), 2) end tries = tries + 1 luv.sleep(20) -- Avoid hot loop... diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 8bc1e14e13..b57e13fea1 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -71,6 +71,7 @@ -- To debug screen tests, see Screen:redraw_debug(). local helpers = require('test.functional.helpers')(nil) +local busted = require('busted') local deepcopy = helpers.deepcopy local shallowcopy = helpers.shallowcopy local concat_tables = helpers.concat_tables @@ -574,7 +575,7 @@ asynchronous (feed(), nvim_input()) and synchronous API calls. if err then - assert(false, err) + busted.fail(err, 3) elseif did_warn then local tb = debug.traceback() local index = string.find(tb, '\n%s*%[C]') -- cgit From 93fe30593b47fe98a31c6bb67f4d6effb8b725fe Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 19 Oct 2019 23:45:27 +0200 Subject: ex_echo: fix check for got_int #11225 It needs to return to not output any remaining parts. Followup to https://github.com/neovim/neovim/pull/10926 Ref: https://github.com/neovim/neovim/issues/10923 --- test/functional/ui/messages_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index 377d49c036..d16559bab2 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -1125,7 +1125,7 @@ aliquip ex ea commodo consequat.]]) it('can be quit', function() screen:try_resize(25,5) - feed(':echon join(map(range(0, &lines*2), "v:val"), "\\n")') + feed(':echon join(map(range(0, &lines*10), "v:val"), "\\n")') screen:expect{grid=[[ 0 | 1 | -- cgit From 019c8d13dd7056725c0715dc15e451118b767b7d Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 19 Oct 2019 18:04:08 -0700 Subject: build/doc/CI: remove/update quickbuild references #11258 --- test/functional/api/server_requests_spec.lua | 4 ---- test/functional/helpers.lua | 4 +--- test/helpers.lua | 6 ++---- test/unit/mbyte_spec.lua | 5 ----- 4 files changed, 3 insertions(+), 16 deletions(-) (limited to 'test') diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index 61184d2c59..237a4b01e4 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -345,10 +345,6 @@ describe('server -> client', function() describe('connecting to its own pipe address', function() it('does not deadlock', function() - if not helpers.isCI('travis') and helpers.is_os('mac') then - -- It does, in fact, deadlock on QuickBuild. #6851 - pending("deadlocks on QuickBuild") - end local address = funcs.serverlist()[1] local first = string.sub(address,1,1) ok(first == '/' or first == '\\') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index a6ff10c0a4..1108fbb2ba 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -29,10 +29,8 @@ local module = { } local start_dir = lfs.currentdir() --- XXX: NVIM_PROG takes precedence, QuickBuild sets it. module.nvim_prog = ( - os.getenv('NVIM_PROG') - or os.getenv('NVIM_PRG') + os.getenv('NVIM_PRG') or global_helpers.test_build_dir .. '/bin/nvim' ) -- Default settings for the test session. diff --git a/test/helpers.lua b/test/helpers.lua index 30e43a9ea4..4c526d217f 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -715,13 +715,11 @@ end function module.isCI(name) local any = (name == nil) - assert(any or name == 'appveyor' or name == 'quickbuild' or name == 'travis' - or name == 'sourcehut') + assert(any or name == 'appveyor' or name == 'travis' or name == 'sourcehut') local av = ((any or name == 'appveyor') and nil ~= os.getenv('APPVEYOR')) local tr = ((any or name == 'travis') and nil ~= os.getenv('TRAVIS')) - local qb = ((any or name == 'quickbuild') and nil ~= lfs.attributes('/usr/home/quickbuild')) local sh = ((any or name == 'sourcehut') and nil ~= os.getenv('SOURCEHUT')) - return tr or av or qb or sh + return tr or av or sh end diff --git a/test/unit/mbyte_spec.lua b/test/unit/mbyte_spec.lua index d27f52923a..fdb1bceab0 100644 --- a/test/unit/mbyte_spec.lua +++ b/test/unit/mbyte_spec.lua @@ -8,11 +8,6 @@ local mbyte = helpers.cimport("./src/nvim/mbyte.h") local charset = helpers.cimport('./src/nvim/charset.h') describe('mbyte', function() - if helpers.isCI('quickbuild') then - pending("crashes on quickbuild", function() end) - return - end - -- Array for composing characters local intp = ffi.typeof('int[?]') local function to_intp() -- cgit From 996a057fb9b4b7d791adad19f07b2f9c53a88ab5 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Mon, 21 Oct 2019 23:46:28 +0900 Subject: lua/stdlib: adjust some validation messages #11271 close #11271 --- test/functional/lua/utility_functions_spec.lua | 42 +++++++++++++++++--------- 1 file changed, 27 insertions(+), 15 deletions(-) (limited to 'test') diff --git a/test/functional/lua/utility_functions_spec.lua b/test/functional/lua/utility_functions_spec.lua index ea2b1fc8a9..dfcbcf06eb 100644 --- a/test/functional/lua/utility_functions_spec.lua +++ b/test/functional/lua/utility_functions_spec.lua @@ -9,6 +9,8 @@ local eval = helpers.eval local feed = helpers.feed local pcall_err = helpers.pcall_err local exec_lua = helpers.exec_lua +local matches = helpers.matches +local iswin = helpers.iswin before_each(clear) @@ -147,11 +149,8 @@ describe('lua stdlib', function() eq({"yy","xx"}, exec_lua("return test_table")) -- type checked args - eq('Error executing lua: vim.schedule: expected function', - pcall_err(exec_lua, "vim.schedule('stringly')")) - - eq('Error executing lua: vim.schedule: expected function', - pcall_err(exec_lua, "vim.schedule()")) + eq('Error executing lua: vim.schedule: expected function', pcall_err(exec_lua, "vim.schedule('stringly')")) + eq('Error executing lua: vim.schedule: expected function', pcall_err(exec_lua, "vim.schedule()")) exec_lua([[ vim.schedule(function() @@ -195,8 +194,8 @@ describe('lua stdlib', function() end) it("vim.split", function() - local split = function(str, sep) - return exec_lua('return vim.split(...)', str, sep) + local split = function(str, sep, plain) + return exec_lua('return vim.split(...)', str, sep, plain) end local tests = { @@ -221,10 +220,15 @@ describe('lua stdlib', function() } for _, t in ipairs(loops) do - local status, err = pcall(split, t[1], t[2]) - eq(false, status) - assert(string.match(err, "Infinite loop detected")) + matches(".*Infinite loop detected", pcall_err(split, t[1], t[2])) end + + -- type checked args + eq(true, pcall(split, 'string', 'string', nil)) + local path_pattern = iswin() and '[a-zA-Z]:[^:]+:%d+:' or '[^:]+:%d+:' + matches("Error executing lua: "..path_pattern.." Expected string, got number", pcall_err(split, 1, 'string', nil)) + matches("Error executing lua: "..path_pattern.." Expected string, got number", pcall_err(split, 'string', 1, nil)) + matches("Error executing lua: "..path_pattern.." Expected boolean or nil, got number", pcall_err(split, 'string', 'string', 1)) end) it('vim.trim', function() @@ -243,9 +247,9 @@ describe('lua stdlib', function() assert(t[2], trim(t[1])) end - local status, err = pcall(trim, 2) - eq(false, status) - assert(string.match(err, "Only strings can be trimmed")) + -- type checked args + local path_pattern = iswin() and '[a-zA-Z]:[^:]+:%d+:' or '[^:]+:%d+:' + matches("Error executing lua: "..path_pattern.." Expected string, got number", pcall_err(trim, 2)) end) it('vim.inspect', function() @@ -285,7 +289,15 @@ describe('lua stdlib', function() end) it('vim.pesc', function() - eq('foo%-bar', exec_lua([[return vim.pesc('foo-bar')]])) - eq('foo%%%-bar', exec_lua([[return vim.pesc(vim.pesc('foo-bar'))]])) + local pesc = function(s) + return exec_lua('return vim.pesc(...)', s) + end + + eq('foo%-bar', pesc('foo-bar')) + eq('foo%%%-bar', pesc(pesc('foo-bar'))) + + -- type checked args + local path_pattern = iswin() and '[a-zA-Z]:[^:]+:%d+:' or '[^:]+:%d+:' + matches("Error executing lua: "..path_pattern.." Expected string, got number", pcall_err(pesc, 2)) end) end) -- cgit From 316c29bbf36d3d36c459b7c955d921b29ca659d0 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 26 Oct 2019 01:30:58 -0700 Subject: test/pcall_err(): truncate full paths, omit linenr ref #11271 --- test/functional/lua/treesitter_spec.lua | 4 +-- test/functional/lua/utility_functions_spec.lua | 41 +++++++++++++------------- test/helpers.lua | 13 +++++++- 3 files changed, 33 insertions(+), 25 deletions(-) (limited to 'test') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index 700e4599f2..5a53ca1425 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -15,9 +15,7 @@ before_each(clear) describe('treesitter API', function() -- error tests not requiring a parser library it('handles missing language', function() - local path_pat = 'Error executing lua: '..(iswin() and '.+\\vim\\' or '.+/vim/') - - matches(path_pat..'treesitter.lua:39: no such language: borklang', + eq('Error executing lua: .../treesitter.lua: no such language: borklang', pcall_err(exec_lua, "parser = vim.treesitter.create_parser(0, 'borklang')")) -- actual message depends on platform diff --git a/test/functional/lua/utility_functions_spec.lua b/test/functional/lua/utility_functions_spec.lua index dfcbcf06eb..a51334398c 100644 --- a/test/functional/lua/utility_functions_spec.lua +++ b/test/functional/lua/utility_functions_spec.lua @@ -10,7 +10,6 @@ local feed = helpers.feed local pcall_err = helpers.pcall_err local exec_lua = helpers.exec_lua local matches = helpers.matches -local iswin = helpers.iswin before_each(clear) @@ -148,9 +147,11 @@ describe('lua stdlib', function() ]]) eq({"yy","xx"}, exec_lua("return test_table")) - -- type checked args - eq('Error executing lua: vim.schedule: expected function', pcall_err(exec_lua, "vim.schedule('stringly')")) - eq('Error executing lua: vim.schedule: expected function', pcall_err(exec_lua, "vim.schedule()")) + -- Validates args. + eq('Error executing lua: vim.schedule: expected function', + pcall_err(exec_lua, "vim.schedule('stringly')")) + eq('Error executing lua: vim.schedule: expected function', + pcall_err(exec_lua, "vim.schedule()")) exec_lua([[ vim.schedule(function() @@ -223,12 +224,14 @@ describe('lua stdlib', function() matches(".*Infinite loop detected", pcall_err(split, t[1], t[2])) end - -- type checked args + -- Validates args. eq(true, pcall(split, 'string', 'string', nil)) - local path_pattern = iswin() and '[a-zA-Z]:[^:]+:%d+:' or '[^:]+:%d+:' - matches("Error executing lua: "..path_pattern.." Expected string, got number", pcall_err(split, 1, 'string', nil)) - matches("Error executing lua: "..path_pattern.." Expected string, got number", pcall_err(split, 'string', 1, nil)) - matches("Error executing lua: "..path_pattern.." Expected boolean or nil, got number", pcall_err(split, 'string', 'string', 1)) + eq('Error executing lua: .../shared.lua: Expected string, got number', + pcall_err(split, 1, 'string', nil)) + eq('Error executing lua: .../shared.lua: Expected string, got number', + pcall_err(split, 'string', 1, nil)) + eq('Error executing lua: .../shared.lua: Expected boolean or nil, got number', + pcall_err(split, 'string', 'string', 1)) end) it('vim.trim', function() @@ -247,9 +250,9 @@ describe('lua stdlib', function() assert(t[2], trim(t[1])) end - -- type checked args - local path_pattern = iswin() and '[a-zA-Z]:[^:]+:%d+:' or '[^:]+:%d+:' - matches("Error executing lua: "..path_pattern.." Expected string, got number", pcall_err(trim, 2)) + -- Validates args. + eq('Error executing lua: .../shared.lua: Expected string, got number', + pcall_err(trim, 2)) end) it('vim.inspect', function() @@ -289,15 +292,11 @@ describe('lua stdlib', function() end) it('vim.pesc', function() - local pesc = function(s) - return exec_lua('return vim.pesc(...)', s) - end - - eq('foo%-bar', pesc('foo-bar')) - eq('foo%%%-bar', pesc(pesc('foo-bar'))) + eq('foo%-bar', exec_lua([[return vim.pesc('foo-bar')]])) + eq('foo%%%-bar', exec_lua([[return vim.pesc(vim.pesc('foo-bar'))]])) - -- type checked args - local path_pattern = iswin() and '[a-zA-Z]:[^:]+:%d+:' or '[^:]+:%d+:' - matches("Error executing lua: "..path_pattern.." Expected string, got number", pcall_err(pesc, 2)) + -- Validates args. + eq("Error executing lua: .../shared.lua: Expected string, got number", + pcall_err(exec_lua, [[return vim.pesc(2)]])) end) end) diff --git a/test/helpers.lua b/test/helpers.lua index 4c526d217f..3f29a28c0d 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -74,7 +74,8 @@ function module.matches(pat, actual) error(string.format('Pattern does not match.\nPattern:\n%s\nActual:\n%s', pat, actual)) end --- Invokes `fn` and returns the error string, or raises an error if `fn` succeeds. +-- Invokes `fn` and returns the error string (may truncate full paths), or +-- raises an error if `fn` succeeds. -- -- Usage: -- -- Match exact string. @@ -88,7 +89,17 @@ function module.pcall_err(fn, ...) if status == true then error('expected failure, but got success') end + -- From this: + -- /home/foo/neovim/runtime/lua/vim/shared.lua:186: Expected string, got number + -- to this: + -- Expected string, got number local errmsg = tostring(rv):gsub('^[^:]+:%d+: ', '') + -- From this: + -- Error executing lua: /very/long/foo.lua:186: Expected string, got number + -- to this: + -- Error executing lua: .../foo.lua:186: Expected string, got number + errmsg = errmsg:gsub([[lua: [a-zA-Z]?:?[^:]-[/\]([^:/\]+):%d+: ]], 'lua: .../%1: ') + -- ^ Windows drive-letter (C:) return errmsg end -- cgit From 4b5e2f7a0b275230456f92892a89c781616284a8 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 26 Oct 2019 21:43:38 +0200 Subject: tests: remove some redundant legacy tests #11028 These were turned into new-style Vim tests in cbecae46f. --- test/functional/legacy/022_line_ending_spec.lua | 25 ---------- .../041_writing_and_reading_hundred_kbyte_spec.lua | 43 ----------------- test/functional/legacy/077_mf_hash_grow_spec.lua | 52 --------------------- test/functional/legacy/084_curswant_spec.lua | 49 -------------------- test/functional/legacy/098_scrollbind_spec.lua | 48 ------------------- test/functional/legacy/104_let_assignment_spec.lua | 54 ---------------------- 6 files changed, 271 deletions(-) delete mode 100644 test/functional/legacy/022_line_ending_spec.lua delete mode 100644 test/functional/legacy/041_writing_and_reading_hundred_kbyte_spec.lua delete mode 100644 test/functional/legacy/077_mf_hash_grow_spec.lua delete mode 100644 test/functional/legacy/084_curswant_spec.lua delete mode 100644 test/functional/legacy/098_scrollbind_spec.lua delete mode 100644 test/functional/legacy/104_let_assignment_spec.lua (limited to 'test') diff --git a/test/functional/legacy/022_line_ending_spec.lua b/test/functional/legacy/022_line_ending_spec.lua deleted file mode 100644 index fb4b782011..0000000000 --- a/test/functional/legacy/022_line_ending_spec.lua +++ /dev/null @@ -1,25 +0,0 @@ --- Tests for file with some lines ending in CTRL-M, some not - -local helpers = require('test.functional.helpers')(after_each) -local clear, feed = helpers.clear, helpers.feed -local feed_command, expect = helpers.feed_command, helpers.expect - -describe('line ending', function() - setup(clear) - - it('is working', function() - feed('i', [[ - this lines ends in a - this one doesn't - this one does - and the last one doesn't]], '') - - feed_command('set ta tx') - feed_command('e!') - - expect("this lines ends in a\r\n".. - "this one doesn't\n".. - "this one does\r\n".. - "and the last one doesn't") - end) -end) diff --git a/test/functional/legacy/041_writing_and_reading_hundred_kbyte_spec.lua b/test/functional/legacy/041_writing_and_reading_hundred_kbyte_spec.lua deleted file mode 100644 index b526d82519..0000000000 --- a/test/functional/legacy/041_writing_and_reading_hundred_kbyte_spec.lua +++ /dev/null @@ -1,43 +0,0 @@ --- Test for writing and reading a file of over 100 Kbyte - -local helpers = require('test.functional.helpers')(after_each) - -local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert -local command, expect = helpers.command, helpers.expect -local wait = helpers.wait - -describe('writing and reading a file of over 100 Kbyte', function() - setup(clear) - - it('is working', function() - insert([[ - This is the start - This is the leader - This is the middle - This is the trailer - This is the end]]) - - feed('kY3000p2GY3000p') - wait() - - command('w! test.out') - command('%d') - command('e! test.out') - command('yank A') - command('3003yank A') - command('6005yank A') - command('%d') - command('0put a') - command('$d') - command('w!') - - expect([[ - This is the start - This is the middle - This is the end]]) - end) - - teardown(function() - os.remove('test.out') - end) -end) diff --git a/test/functional/legacy/077_mf_hash_grow_spec.lua b/test/functional/legacy/077_mf_hash_grow_spec.lua deleted file mode 100644 index 4719a3ecbf..0000000000 --- a/test/functional/legacy/077_mf_hash_grow_spec.lua +++ /dev/null @@ -1,52 +0,0 @@ --- Inserts 2 million lines with consecutive integers starting from 1 --- (essentially, the output of GNU's seq 1 2000000), writes them to Xtest --- and calculates its cksum. --- We need 2 million lines to trigger a call to mf_hash_grow(). If it would mess --- up the lines the checksum would differ. --- cksum is part of POSIX and so should be available on most Unixes. --- If it isn't available then the test will be skipped. - -local helpers = require('test.functional.helpers')(after_each) - -local feed = helpers.feed -local wait = helpers.wait -local clear = helpers.clear -local expect = helpers.expect -local command = helpers.command - -describe('mf_hash_grow()', function() - setup(clear) - - -- Check to see if cksum exists, otherwise skip the test - local null = helpers.iswin() and 'nul' or '/dev/null' - if os.execute('cksum --help >' .. null .. ' 2>&1') ~= 0 then - pending('was not tested because cksum was not found', function() end) - else - it('is working', function() - command('set fileformat=unix undolevels=-1') - - -- Fill the buffer with numbers 1 - 2000000 - command('let i = 1') - command('while i <= 2000000 | call append(i, range(i, i + 99)) | let i += 100 | endwhile') - - -- Delete empty first line, save to Xtest, and clear buffer - feed('ggdd') - wait() - command('w! Xtest') - feed('ggdG') - wait() - - -- Calculate the cksum of Xtest and delete first line - command('r !cksum Xtest') - feed('ggdd') - - -- Assert correct output of cksum. - expect([[ - 3678979763 14888896 Xtest]]) - end) - end - - teardown(function() - os.remove('Xtest') - end) -end) diff --git a/test/functional/legacy/084_curswant_spec.lua b/test/functional/legacy/084_curswant_spec.lua deleted file mode 100644 index 42cb2fc56d..0000000000 --- a/test/functional/legacy/084_curswant_spec.lua +++ /dev/null @@ -1,49 +0,0 @@ --- Tests for curswant not changing when setting an option. - -local helpers = require('test.functional.helpers')(after_each) -local insert, source = helpers.insert, helpers.source -local clear, expect = helpers.clear, helpers.expect - -describe('curswant', function() - setup(clear) - - -- luacheck: ignore 621 (Indentation) - it('is working', function() - insert([[ - start target options - tabstop - timeoutlen - ttimeoutlen - end target options]]) - - source([[ - /^start target options$/+1,/^end target options$/-1 yank - let target_option_names = split(@0) - function TestCurswant(option_name) - normal! ggf8j - let curswant_before = winsaveview().curswant - execute 'let' '&'.a:option_name '=' '&'.a:option_name - let curswant_after = winsaveview().curswant - return [a:option_name, curswant_before, curswant_after] - endfunction - - new - put =['1234567890', '12345'] - 1 delete _ - let result = [] - for option_name in target_option_names - call add(result, TestCurswant(option_name)) - endfor - - new - put =map(copy(result), 'join(v:val, '' '')') - 1 delete _ - ]]) - - -- Assert buffer contents. - expect([[ - tabstop 7 4 - timeoutlen 7 7 - ttimeoutlen 7 7]]) - end) -end) diff --git a/test/functional/legacy/098_scrollbind_spec.lua b/test/functional/legacy/098_scrollbind_spec.lua deleted file mode 100644 index d22aefdcbc..0000000000 --- a/test/functional/legacy/098_scrollbind_spec.lua +++ /dev/null @@ -1,48 +0,0 @@ --- Test for 'scrollbind' causing an unexpected scroll of one of the windows. - -local helpers = require('test.functional.helpers')(after_each) -local source = helpers.source -local clear, expect = helpers.clear, helpers.expect - -describe('scrollbind', function() - setup(clear) - - it('is working', function() - source([[ - set laststatus=0 - let g:totalLines = &lines * 20 - let middle = g:totalLines / 2 - wincmd n - wincmd o - for i in range(1, g:totalLines) - call setline(i, 'LINE ' . i) - endfor - exe string(middle) - normal zt - normal M - aboveleft vert new - for i in range(1, g:totalLines) - call setline(i, 'line ' . i) - endfor - exe string(middle) - normal zt - normal M - setl scb | wincmd p - setl scb - wincmd w - let topLineLeft = line('w0') - wincmd p - let topLineRight = line('w0') - setl noscrollbind - wincmd p - setl noscrollbind - q! - %del _ - call setline(1, 'Difference between the top lines (left - right): ' . string(topLineLeft - topLineRight)) - brewind - ]]) - - -- Assert buffer contents. - expect("Difference between the top lines (left - right): 0") - end) -end) diff --git a/test/functional/legacy/104_let_assignment_spec.lua b/test/functional/legacy/104_let_assignment_spec.lua deleted file mode 100644 index a03bb026f6..0000000000 --- a/test/functional/legacy/104_let_assignment_spec.lua +++ /dev/null @@ -1,54 +0,0 @@ --- Tests for :let. - -local helpers = require('test.functional.helpers')(after_each) -local clear, source = helpers.clear, helpers.source -local command, expect = helpers.command, helpers.expect - -describe(':let', function() - setup(clear) - - it('is working', function() - command('set runtimepath+=test/functional/fixtures') - - -- Test to not autoload when assigning. It causes internal error. - source([[ - try - let Test104#numvar = function('tr') - $put ='OK: ' . string(Test104#numvar) - catch - $put ='FAIL: ' . v:exception - endtry - let a = 1 - let b = 2 - for letargs in ['a b', '{0 == 1 ? "a" : "b"}', '{0 == 1 ? "a" : "b"} a', 'a {0 == 1 ? "a" : "b"}'] - try - redir => messages - execute 'let' letargs - redir END - $put ='OK:' - $put =split(substitute(messages, '\n', '\0 ', 'g'), '\n') - catch - $put ='FAIL: ' . v:exception - redir END - endtry - endfor]]) - - -- Remove empty line - command('1d') - - -- Assert buffer contents. - expect([[ - OK: function('tr') - OK: - a #1 - b #2 - OK: - b #2 - OK: - b #2 - a #1 - OK: - a #1 - b #2]]) - end) -end) -- cgit From 8ee7c94a92598d46b488b7fe3b1a5cff6b1bf94a Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 25 Aug 2019 22:01:35 +0200 Subject: lua: add vim.fn.{func} for direct access to vimL function compared to vim.api.|nvim_call_function|, this fixes some typing issues due to the indirect conversion via the API. float values are preserved as such (fixes #9389) as well as empty dicts/arrays. Ref https://github.com/norcalli/nvim.lua for the call syntax --- test/functional/lua/utility_functions_spec.lua | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'test') diff --git a/test/functional/lua/utility_functions_spec.lua b/test/functional/lua/utility_functions_spec.lua index a51334398c..0b789e84b0 100644 --- a/test/functional/lua/utility_functions_spec.lua +++ b/test/functional/lua/utility_functions_spec.lua @@ -10,6 +10,7 @@ local feed = helpers.feed local pcall_err = helpers.pcall_err local exec_lua = helpers.exec_lua local matches = helpers.matches +local source = helpers.source before_each(clear) @@ -299,4 +300,31 @@ describe('lua stdlib', function() eq("Error executing lua: .../shared.lua: Expected string, got number", pcall_err(exec_lua, [[return vim.pesc(2)]])) end) + + it('vim.call and vim.fn', function() + eq(true, exec_lua([[return vim.call('sin', 0.0) == 0.0 ]])) + eq(true, exec_lua([[return vim.fn.sin(0.0) == 0.0 ]])) + -- compat: nvim_call_function uses "special" value for vimL float + eq(false, exec_lua([[return vim.api.nvim_call_function('sin', {0.0}) == 0.0 ]])) + + source([[ + func! FooFunc(test) + let g:test = a:test + return {} + endfunc + func! VarArg(...) + return a:000 + endfunc + ]]) + eq(true, exec_lua([[return next(vim.fn.FooFunc(3)) == nil ]])) + eq(3, eval("g:test")) + -- compat: nvim_call_function uses "special" value for empty dict + eq(true, exec_lua([[return next(vim.api.nvim_call_function("FooFunc", {5})) == true ]])) + eq(5, eval("g:test")) + + eq({2, "foo", true}, exec_lua([[return vim.fn.VarArg(2, "foo", true)]])) + + -- error handling + eq({false, 'Vim:E714: List required'}, exec_lua([[return {pcall(vim.fn.add, "aa", "bb")}]])) + end) end) -- cgit From d4384cbbf37786f0185f6bbb2e5bf82f5573e532 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Wed, 30 Oct 2019 20:38:41 +0000 Subject: Remove unnecessary expr in 'icm' test --- test/functional/ui/inccommand_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua index d60cd08fb0..82251a4b88 100644 --- a/test/functional/ui/inccommand_spec.lua +++ b/test/functional/ui/inccommand_spec.lua @@ -88,7 +88,7 @@ local function common_setup(screen, inccommand, text) }) end - command("set inccommand=" .. (inccommand and inccommand or "")) + command("set inccommand=" .. (inccommand or "")) if text then insert(text) -- cgit From 1c7aa1131297b4b3686d66aae06090e1398da56c Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Fri, 8 Mar 2019 22:49:48 +0000 Subject: Allow multiple leading colons before and after modifiers for 'inccommand' --- test/functional/ui/inccommand_spec.lua | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'test') diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua index 82251a4b88..c5ad093eca 100644 --- a/test/functional/ui/inccommand_spec.lua +++ b/test/functional/ui/inccommand_spec.lua @@ -779,6 +779,13 @@ describe(":substitute, inccommand=split", function() {15:~ }| :silent tabedit %s/tw/to^ | ]]) + feed('') + + -- leading colons + feed(':::%s/tw/to') + screen:expect{any=[[{12:to}o lines]]} + feed('') + screen:expect{any=[[two lines]]} end) it('shows split window when typing the pattern', function() -- cgit From d52d7823898c7fee0121c4d6da730a0530bf8c50 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Tue, 29 Oct 2019 22:31:40 +0000 Subject: Prevent :topleft, etc modifying the inccommand preview window --- test/functional/ui/inccommand_spec.lua | 48 +++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua index c5ad093eca..0d6aa7f128 100644 --- a/test/functional/ui/inccommand_spec.lua +++ b/test/functional/ui/inccommand_spec.lua @@ -95,7 +95,7 @@ local function common_setup(screen, inccommand, text) end end -describe(":substitute, inccommand=split", function() +describe(":substitute, inccommand=split interactivity", function() before_each(function() clear() common_setup(nil, "split", default_text) @@ -788,6 +788,52 @@ describe(":substitute, inccommand=split", function() screen:expect{any=[[two lines]]} end) + it("ignores new-window modifiers when splitting the preview window", function() + -- one modifier + feed(':topleft %s/tw/to') + screen:expect([[ + Inc substitution on | + {12:to}o lines | + Inc substitution on | + {12:to}o lines | + | + {11:[No Name] [+] }| + |2| {12:to}o lines | + |4| {12:to}o lines | + {15:~ }| + {15:~ }| + {15:~ }| + {15:~ }| + {15:~ }| + {10:[Preview] }| + :topleft %s/tw/to^ | + ]]) + feed('') + screen:expect{any=[[two lines]]} + + -- multiple modifiers + feed(':topleft vert %s/tw/to') + screen:expect([[ + Inc substitution on | + {12:to}o lines | + Inc substitution on | + {12:to}o lines | + | + {11:[No Name] [+] }| + |2| {12:to}o lines | + |4| {12:to}o lines | + {15:~ }| + {15:~ }| + {15:~ }| + {15:~ }| + {15:~ }| + {10:[Preview] }| + :topleft vert %s/tw/to^ | + ]]) + feed('') + screen:expect{any=[[two lines]]} + end) + it('shows split window when typing the pattern', function() feed(":%s/tw") screen:expect([[ -- cgit From d04ab11f24521e60278a0daed9a7d5abeeaf6f4f Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Tue, 29 Oct 2019 22:32:25 +0000 Subject: Prevent prompts during inccommand previews For example, "Backwards range given, OK to swap (y/n)?" on each keypress. --- test/functional/ui/inccommand_spec.lua | 43 ++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'test') diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua index 0d6aa7f128..b841574643 100644 --- a/test/functional/ui/inccommand_spec.lua +++ b/test/functional/ui/inccommand_spec.lua @@ -2582,6 +2582,49 @@ describe(":substitute", function() :%s/some\(thing\)\@!/every/^ | ]]) end) + + it("doesn't prompt to swap cmd range", function() + screen = Screen.new(50, 8) -- wide to avoid hit-enter prompt + common_setup(screen, "split", default_text) + feed(':2,1s/tw/MO/g') + + -- substitution preview should have been made, without prompting + screen:expect([[ + {12:MO}o lines | + {11:[No Name] [+] }| + |2| {12:MO}o lines | + {15:~ }| + {15:~ }| + {15:~ }| + {10:[Preview] }| + :2,1s/tw/MO/g^ | + ]]) + + -- but should be prompted on hitting enter + feed('') + screen:expect([[ + {12:MO}o lines | + {11:[No Name] [+] }| + |2| {12:MO}o lines | + {15:~ }| + {15:~ }| + {15:~ }| + {10:[Preview] }| + {13:Backwards range given, OK to swap (y/n)?}^ | + ]]) + + feed('y') + screen:expect([[ + Inc substitution on | + ^MOo lines | + | + {15:~ }| + {15:~ }| + {15:~ }| + {15:~ }| + {13:Backwards range given, OK to swap (y/n)?}y | + ]]) + end) end) it(':substitute with inccommand during :terminal activity', function() -- cgit From 33cdff1b5cf2912b7630a892c08a46041a989a69 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 2 Nov 2019 10:55:40 +0100 Subject: test/screen: make snapshot_util() work properly in rgb_cterm mode --- test/functional/ui/screen.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index b57e13fea1..05caaade93 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -1362,6 +1362,7 @@ function Screen:linegrid_check_attrs(attrs) if self._rgb_cterm then attr_rgb, attr_cterm, info = unpack(v) attr = {attr_rgb, attr_cterm} + info = info or {} elseif self._options.ext_hlstate then attr, info = unpack(v) else @@ -1400,11 +1401,12 @@ end function Screen:_pprint_hlitem(item) -- print(inspect(item)) local multi = self._rgb_cterm or self._options.ext_hlstate - local attrdict = "{"..self:_pprint_attrs(multi and item[1] or item).."}" + local cterm = (not self._rgb_cterm and not self._options.rgb) + local attrdict = "{"..self:_pprint_attrs(multi and item[1] or item, cterm).."}" local attrdict2, hlinfo local descdict = "" if self._rgb_cterm then - attrdict2 = ", {"..self:_pprint_attrs(item[2]).."}" + attrdict2 = ", {"..self:_pprint_attrs(item[2], true).."}" hlinfo = item[3] else attrdict2 = "" @@ -1433,13 +1435,15 @@ function Screen:_pprint_hlinfo(states) end -function Screen:_pprint_attrs(attrs) +function Screen:_pprint_attrs(attrs, cterm) local items = {} for f, v in pairs(attrs) do local desc = tostring(v) if f == "foreground" or f == "background" or f == "special" then if Screen.colornames[v] ~= nil then desc = "Screen.colors."..Screen.colornames[v] + elseif cterm then + desc = tostring(v) else desc = string.format("tonumber('0x%06x')",v) end -- cgit From f707a7ef6885d791411077079e1a2783d8c1b169 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 2 Nov 2019 10:57:07 +0100 Subject: terminal: add tests for palette color forwarding --- test/functional/core/main_spec.lua | 2 +- test/functional/terminal/highlight_spec.lua | 57 ++++++++++++++++++++++++++--- test/functional/terminal/tui_spec.lua | 54 +++++++++++++++++++++++++-- test/functional/ui/hlstate_spec.lua | 10 ++--- test/functional/ui/screen.lua | 3 +- 5 files changed, 111 insertions(+), 15 deletions(-) (limited to 'test') diff --git a/test/functional/core/main_spec.lua b/test/functional/core/main_spec.lua index b793e531c9..37a9f0b836 100644 --- a/test/functional/core/main_spec.lua +++ b/test/functional/core/main_spec.lua @@ -67,7 +67,7 @@ describe('Command-line option', function() | | ]], { - [1] = {foreground = 4210943}, + [1] = {foreground = tonumber('0x4040ff'), fg_indexed=true}, [2] = {bold = true, reverse = true} }) feed('i:cq') diff --git a/test/functional/terminal/highlight_spec.lua b/test/functional/terminal/highlight_spec.lua index 06a6fd6f2b..8d3f0218af 100644 --- a/test/functional/terminal/highlight_spec.lua +++ b/test/functional/terminal/highlight_spec.lua @@ -121,13 +121,12 @@ it(':terminal highlight has lower precedence than editor #9964', function() 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')}, + N_child = {foreground = tonumber('0x4040ff'), background = tonumber('0xffff40'), fg_indexed=true, bg_indexed=true}, -- "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}, + -- note: bg is indexed as it comes from the (cterm) child, while fg isn't as it comes from (rgb) parent + Q = {background = tonumber('0xffff40'), bold = true, foreground = Screen.colors.SeaGreen4, bg_indexed=true}, }) screen:attach({rgb=true}) -- Child nvim process in :terminal (with cterm colors). @@ -160,6 +159,54 @@ it(':terminal highlight has lower precedence than editor #9964', function() ]]) end) +describe(':terminal highlight forwarding', function() + local screen + + before_each(function() + clear() + screen = Screen.new(50, 7) + screen:set_rgb_cterm(true) + screen:set_default_attr_ids({ + [1] = {{reverse = true}, {reverse = true}}, + [2] = {{bold = true}, {bold = true}}, + [3] = {{fg_indexed = true, foreground = tonumber('0xe0e000')}, {foreground = 3}}, + [4] = {{foreground = tonumber('0xff8000')}, {}}, + }) + screen:attach() + command('enew | call termopen(["'..nvim_dir..'/tty-test"])') + feed('i') + screen:expect([[ + tty ready | + {1: } | + | + | + | + | + {2:-- TERMINAL --} | + ]]) + end) + + it('will handle cterm and rgb attributes', function() + if helpers.pending_win32(pending) then return end + thelpers.set_fg(3) + thelpers.feed_data('text') + thelpers.feed_termcode('[38:2:255:128:0m') + thelpers.feed_data('color') + thelpers.clear_attrs() + thelpers.feed_data('text') + screen:expect{grid=[[ + tty ready | + {3:text}{4:color}text{1: } | + | + | + | + | + {2:-- TERMINAL --} | + ]]} + end) +end) + + describe(':terminal highlight with custom palette', function() local screen @@ -167,7 +214,7 @@ describe(':terminal highlight with custom palette', function() clear() screen = Screen.new(50, 7) screen:set_default_attr_ids({ - [1] = {foreground = tonumber('0x123456')}, + [1] = {foreground = tonumber('0x123456')}, -- no fg_indexed when overriden [2] = {foreground = 12}, [3] = {bold = true, reverse = true}, [5] = {background = 11}, diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index bc83660c19..5ac2ffb611 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -680,11 +680,11 @@ describe('TUI', function() screen:set_option('rgb', true) screen:set_default_attr_ids({ [1] = {reverse = true}, - [2] = {foreground = tonumber('0x4040ff')}, + [2] = {foreground = tonumber('0x4040ff'), fg_indexed=true}, [3] = {bold = true, reverse = true}, [4] = {bold = true}, - [5] = {reverse = true, foreground = tonumber('0xe0e000')}, - [6] = {foreground = tonumber('0xe0e000')}, + [5] = {reverse = true, foreground = tonumber('0xe0e000'), fg_indexed=true}, + [6] = {foreground = tonumber('0xe0e000'), fg_indexed=true}, [7] = {reverse = true, foreground = Screen.colors.SeaGreen4}, [8] = {foreground = Screen.colors.SeaGreen4}, [9] = {bold = true, foreground = Screen.colors.Blue1}, @@ -728,6 +728,54 @@ describe('TUI', function() ]]) end) + it('forwards :term palette colors with termguicolors', function() + screen:set_rgb_cterm(true) + screen:set_default_attr_ids({ + [1] = {{reverse = true}, {reverse = true}}, + [2] = {{bold = true, reverse = true}, {bold = true, reverse = true}}, + [3] = {{bold = true}, {bold = true}}, + [4] = {{fg_indexed = true, foreground = tonumber('0xe0e000')}, {foreground = 3}}, + [5] = {{foreground = tonumber('0xff8000')}, {}}, + }) + + feed_data(':set statusline=^^^^^^^\n') + feed_data(':set termguicolors\n') + feed_data(':terminal '..nvim_dir..'/tty-test\n') + -- Depending on platform the above might or might not fit in the cmdline + -- so clear it for consistent behavior. + feed_data(':\027') + screen:expect{grid=[[ + {1:t}ty ready | + | + | + | + {2:^^^^^^^ }| + | + {3:-- TERMINAL --} | + ]]} + feed_data(':call chansend(&channel, "\\033[38;5;3mtext\\033[38:2:255:128:0mcolor\\033[0;10mtext")\n') + screen:expect{grid=[[ + {1:t}ty ready | + {4:text}{5:color}text | + | + | + {2:^^^^^^^ }| + | + {3:-- TERMINAL --} | + ]]} + + feed_data(':set notermguicolors\n') + screen:expect{grid=[[ + {1:t}ty ready | + {4:text}colortext | + | + | + {2:^^^^^^^ }| + :set notermguicolors | + {3:-- TERMINAL --} | + ]]} + end) + 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_" })))})\r') screen:expect([=[ diff --git a/test/functional/ui/hlstate_spec.lua b/test/functional/ui/hlstate_spec.lua index 1e18df835a..2a567b28ee 100644 --- a/test/functional/ui/hlstate_spec.lua +++ b/test/functional/ui/hlstate_spec.lua @@ -181,11 +181,11 @@ describe('ext_hlstate detailed highlights', function() it("work with :terminal", function() screen:set_default_attr_ids({ [1] = {{}, {{hi_name = "TermCursorNC", ui_name = "TermCursorNC", kind = "ui"}}}, - [2] = {{foreground = 52479}, {{kind = "term"}}}, - [3] = {{bold = true, foreground = 52479}, {{kind = "term"}}}, - [4] = {{foreground = 52479}, {2, 1}}, - [5] = {{foreground = 4259839}, {{kind = "term"}}}, - [6] = {{foreground = 4259839}, {5, 1}}, + [2] = {{foreground = tonumber('0x00ccff'), fg_indexed=true}, {{kind = "term"}}}, + [3] = {{bold = true, foreground = tonumber('0x00ccff'), fg_indexed=true}, {{kind = "term"}}}, + [4] = {{foreground = tonumber('0x00ccff'), fg_indexed=true}, {2, 1}}, + [5] = {{foreground = tonumber('0x40ffff'), fg_indexed=true}, {{kind = "term"}}}, + [6] = {{foreground = tonumber('0x40ffff'), fg_indexed=true}, {5, 1}}, [7] = {{}, {{hi_name = "MsgArea", ui_name = "MsgArea", kind = "ui"}}}, }) command('enew | call termopen(["'..nvim_dir..'/tty-test"])') diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 05caaade93..41e022791e 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -1515,7 +1515,8 @@ function Screen:_equal_attrs(a, b) a.italic == b.italic and a.reverse == b.reverse and a.foreground == b.foreground and a.background == b.background and a.special == b.special and a.blend == b.blend and - a.strikethrough == b.strikethrough + a.strikethrough == b.strikethrough and + a.fg_indexed == b.fg_indexed and a.bg_indexed == b.bg_indexed end function Screen:_equal_info(a, b) -- cgit From 9ef16a1628722958b6e14fe9274006e50ed6682d Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 27 Oct 2019 15:05:59 -0700 Subject: doc: vim.fn, vim.call(), vim.api [ci skip] --- test/functional/lua/utility_functions_spec.lua | 2 +- test/functional/terminal/tui_spec.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/functional/lua/utility_functions_spec.lua b/test/functional/lua/utility_functions_spec.lua index 0b789e84b0..6aeea5fc4f 100644 --- a/test/functional/lua/utility_functions_spec.lua +++ b/test/functional/lua/utility_functions_spec.lua @@ -301,7 +301,7 @@ describe('lua stdlib', function() pcall_err(exec_lua, [[return vim.pesc(2)]])) end) - it('vim.call and vim.fn', function() + it('vim.call, vim.fn', function() eq(true, exec_lua([[return vim.call('sin', 0.0) == 0.0 ]])) eq(true, exec_lua([[return vim.fn.sin(0.0) == 0.0 ]])) -- compat: nvim_call_function uses "special" value for vimL float diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 5ac2ffb611..831d3939df 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -535,7 +535,7 @@ describe('TUI', function() | {4:~ }| {5: }| - {8:paste: Error executing lua: vim.lua:197: Vim:E21: }| + {8:paste: Error executing lua: vim.lua:211: Vim:E21: }| {8:Cannot make changes, 'modifiable' is off} | {10:Press ENTER or type command to continue}{1: } | {3:-- TERMINAL --} | -- cgit From 7a23b67d3594ffb8b6d8629fd9ca1ef8147596db Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 9 Nov 2019 21:18:51 -0800 Subject: paste: Select-mode, Visual-mode #11360 fix #11344 --- test/functional/terminal/tui_spec.lua | 45 ++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 831d3939df..e773d2ea62 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -302,6 +302,49 @@ describe('TUI', function() expect_child_buf_lines({''}) end) + it('paste: select-mode', function() + feed_data('ithis is line 1\nthis is line 2\nline 3 is here\n\027') + wait_for_mode('n') + screen:expect{grid=[[ + this is line 1 | + this is line 2 | + line 3 is here | + {1: } | + {5:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]} + -- Select-mode. Use to move down. + feed_data('gg04lgh\14\14') + wait_for_mode('s') + feed_data('\027[200~') + feed_data('just paste it™') + feed_data('\027[201~') + screen:expect{grid=[[ + thisjust paste it™{1:3} is here | + | + {4:~ }| + {4:~ }| + {5:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]} + -- Undo. + feed_data('u') + expect_child_buf_lines{ + 'this is line 1', + 'this is line 2', + 'line 3 is here', + '', + } + -- Redo. + feed_data('\18') -- + expect_child_buf_lines{ + 'thisjust paste it™3 is here', + '', + } + end) + it('paste: terminal mode', function() feed_data(':set statusline=^^^^^^^\n') feed_data(':terminal '..nvim_dir..'/tty-test\n') @@ -535,7 +578,7 @@ describe('TUI', function() | {4:~ }| {5: }| - {8:paste: Error executing lua: vim.lua:211: Vim:E21: }| + {8:paste: Error executing lua: vim.lua:214: Vim:E21: }| {8:Cannot make changes, 'modifiable' is off} | {10:Press ENTER or type command to continue}{1: } | {3:-- TERMINAL --} | -- cgit From c0abaf9ca604485ceee04ae8ca83c11382febc89 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 12 Sep 2019 13:06:34 +0200 Subject: tests: Screen:expect: support "{MATCH:…}" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/functional/ui/screen.lua | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'test') diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 41e022791e..e9583bf805 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -391,14 +391,17 @@ function Screen:expect(expected, attr_ids, ...) .. ' differs from actual height ' .. #actual_rows .. '.' end for i = 1, #expected_rows do - msg_expected_rows[i] = expected_rows[i] + msg_expected_rows[i] = expected_rows[i] if expected_rows[i] ~= actual_rows[i] and expected_rows[i] ~= "{IGNORE}|" then - msg_expected_rows[i] = '*' .. msg_expected_rows[i] - if i <= #actual_rows then - actual_rows[i] = '*' .. actual_rows[i] - end - if err_msg == nil then - err_msg = 'Row ' .. tostring(i) .. ' did not match.' + local m = expected_rows[i]:match('{MATCH:(.*)}') + if not m or not actual_rows[i]:match(m) then + msg_expected_rows[i] = '*' .. msg_expected_rows[i] + if i <= #actual_rows then + actual_rows[i] = '*' .. actual_rows[i] + end + if err_msg == nil then + err_msg = 'Row ' .. tostring(i) .. ' did not match.' + end end end end -- cgit From 4abb67c027e93afac8c2f436d48956fffcd69848 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 9 Nov 2019 22:22:24 -0800 Subject: test/Screen:expect: replace "{IGNORE}" with "{MATCH:…}" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref #11004 --- test/functional/terminal/scrollback_spec.lua | 2 +- test/functional/terminal/tui_spec.lua | 2 +- test/functional/ui/messages_spec.lua | 14 +++++++------- test/functional/ui/screen.lua | 24 +++++++++++------------- 4 files changed, 20 insertions(+), 22 deletions(-) (limited to 'test') diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua index 060f065bfc..1df8df6f6e 100644 --- a/test/functional/terminal/scrollback_spec.lua +++ b/test/functional/terminal/scrollback_spec.lua @@ -449,7 +449,7 @@ describe("'scrollback' option", function() 38: line | 39: line | 40: line | - {IGNORE}| + {MATCH:.*}| {3:-- TERMINAL --} | ]]} end diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index e773d2ea62..676d6ef76d 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -578,7 +578,7 @@ describe('TUI', function() | {4:~ }| {5: }| - {8:paste: Error executing lua: vim.lua:214: Vim:E21: }| + {MATCH:paste: Error executing lua: vim.lua:%d+: Vim:E21: }| {8:Cannot make changes, 'modifiable' is off} | {10:Press ENTER or type command to continue}{1: } | {3:-- TERMINAL --} | diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index d16559bab2..8ad3aff21f 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -122,7 +122,7 @@ describe('ui/ext_messages', function() feed('G$x') screen:expect{grid=[[ line 1 | - {IGNORE}| + {MATCH:.*}| {1:~ }| {1:~ }| {1:~ }| @@ -966,7 +966,7 @@ describe('ui/ext_messages', function() {1:~ }| {1:~ }| {1:~ }| - {IGNORE}| + {MATCH:.*}| {1:~ }| {1:~ }Nvim is open source and freely distributable{1: }| {1:~ }https://neovim.io/#chat{1: }| @@ -976,8 +976,8 @@ describe('ui/ext_messages', function() {1:~ }type :q{5:} to exit {1: }| {1:~ }type :help{5:} for help {1: }| {1:~ }| - {IGNORE}| - {IGNORE}| + {MATCH:.*}| + {MATCH:.*}| {1:~ }| {1:~ }| {1:~ }| @@ -1022,7 +1022,7 @@ describe('ui/ext_messages', function() | | | - {IGNORE}| + {MATCH:.*}| | Nvim is open source and freely distributable | https://neovim.io/#chat | @@ -1032,8 +1032,8 @@ describe('ui/ext_messages', function() type :q{5:} to exit | type :help{5:} for help | | - {IGNORE}| - {IGNORE}| + {MATCH:.*}| + {MATCH:.*}| | | | diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index e9583bf805..d3f78bf77b 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -269,7 +269,7 @@ local ext_keys = { -- 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. +-- "{MATCH:x}|" lines are matched against Lua pattern `x`. -- 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 @@ -390,18 +390,16 @@ function Screen:expect(expected, attr_ids, ...) err_msg = "Expected screen height " .. #expected_rows .. ' differs from actual height ' .. #actual_rows .. '.' end - for i = 1, #expected_rows do - msg_expected_rows[i] = expected_rows[i] - if expected_rows[i] ~= actual_rows[i] and expected_rows[i] ~= "{IGNORE}|" then - local m = expected_rows[i]:match('{MATCH:(.*)}') - if not m or not actual_rows[i]:match(m) then - msg_expected_rows[i] = '*' .. msg_expected_rows[i] - if i <= #actual_rows then - actual_rows[i] = '*' .. actual_rows[i] - end - if err_msg == nil then - err_msg = 'Row ' .. tostring(i) .. ' did not match.' - end + for i, row in ipairs(expected_rows) do + msg_expected_rows[i] = row + local m = (row ~= actual_rows[i] and row:match('{MATCH:(.*)}') or nil) + if row ~= actual_rows[i] and (not m or not actual_rows[i]:match(m)) then + msg_expected_rows[i] = '*' .. msg_expected_rows[i] + if i <= #actual_rows then + actual_rows[i] = '*' .. actual_rows[i] + end + if err_msg == nil then + err_msg = 'Row ' .. tostring(i) .. ' did not match.' end end end -- cgit From 474d0bcbf724c7eed740f60391a0ed35d651e1d3 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 27 Oct 2019 20:49:03 +0100 Subject: lua: vim.rpcrequest, vim.rpcnotify, vim.NIL --- test/functional/lua/utility_functions_spec.lua | 72 ++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'test') diff --git a/test/functional/lua/utility_functions_spec.lua b/test/functional/lua/utility_functions_spec.lua index 6aeea5fc4f..6631aa8e4c 100644 --- a/test/functional/lua/utility_functions_spec.lua +++ b/test/functional/lua/utility_functions_spec.lua @@ -3,6 +3,8 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local funcs = helpers.funcs +local meths = helpers.meths +local command = helpers.command local clear = helpers.clear local eq = helpers.eq local eval = helpers.eval @@ -11,6 +13,7 @@ local pcall_err = helpers.pcall_err local exec_lua = helpers.exec_lua local matches = helpers.matches local source = helpers.source +local NIL = helpers.NIL before_each(clear) @@ -315,6 +318,9 @@ describe('lua stdlib', function() func! VarArg(...) return a:000 endfunc + func! Nilly() + return [v:null, v:null] + endfunc ]]) eq(true, exec_lua([[return next(vim.fn.FooFunc(3)) == nil ]])) eq(3, eval("g:test")) @@ -324,7 +330,73 @@ describe('lua stdlib', function() eq({2, "foo", true}, exec_lua([[return vim.fn.VarArg(2, "foo", true)]])) + eq(true, exec_lua([[ + local x = vim.fn.Nilly() + return #x == 2 and x[1] == vim.NIL and x[2] == vim.NIL + ]])) + eq({NIL, NIL}, exec_lua([[return vim.fn.Nilly()]])) + -- error handling eq({false, 'Vim:E714: List required'}, exec_lua([[return {pcall(vim.fn.add, "aa", "bb")}]])) end) + + it('vim.rpcrequest and vim.rpcnotify', function() + exec_lua([[ + chan = vim.fn.jobstart({'cat'}, {rpc=true}) + vim.rpcrequest(chan, 'nvim_set_current_line', 'meow') + ]]) + eq('meow', meths.get_current_line()) + command("let x = [3, 'aa', v:true, v:null]") + eq(true, exec_lua([[ + ret = vim.rpcrequest(chan, 'nvim_get_var', 'x') + return #ret == 4 and ret[1] == 3 and ret[2] == 'aa' and ret[3] == true and ret[4] == vim.NIL + ]])) + eq({3, 'aa', true, NIL}, exec_lua([[return ret]])) + + -- error handling + eq({false, 'Invalid channel: 23'}, + exec_lua([[return {pcall(vim.rpcrequest, 23, 'foo')}]])) + eq({false, 'Invalid channel: 23'}, + exec_lua([[return {pcall(vim.rpcnotify, 23, 'foo')}]])) + + eq({false, 'Vim:E121: Undefined variable: foobar'}, + exec_lua([[return {pcall(vim.rpcrequest, chan, 'nvim_eval', "foobar")}]])) + + + -- rpcnotify doesn't wait on request + eq('meow', exec_lua([[ + vim.rpcnotify(chan, 'nvim_set_current_line', 'foo') + return vim.api.nvim_get_current_line() + ]])) + eq('foo', meths.get_current_line()) + + local screen = Screen.new(50,7) + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {bold = true, reverse = true}, + [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, + }) + screen:attach() + exec_lua([[ + local timer = vim.loop.new_timer() + timer:start(20, 0, function () + -- notify ok (executed later when safe) + vim.rpcnotify(chan, 'nvim_set_var', 'yy', {3, vim.NIL}) + -- rpcrequest an error + vim.rpcrequest(chan, 'nvim_set_current_line', 'bork') + end) + ]]) + screen:expect{grid=[[ + foo | + {1:~ }| + {2: }| + {3:Error executing luv callback:} | + {3:[string ""]:6: E5560: rpcrequest must not be}| + {3: called in a lua loop callback} | + {4:Press ENTER or type command to continue}^ | + ]]} + feed('') + eq({3, NIL}, meths.get_var('yy')) + end) end) -- cgit From 1cb4674547828a315b7aef5b6c635726b3bc12e5 Mon Sep 17 00:00:00 2001 From: Marco Hinz Date: Sun, 10 Nov 2019 16:38:04 +0100 Subject: api: add nvim_buf_get_virtual_text() (#11354) This adds the missing partner function of nvim_buf_set_virtual_text(). --- test/functional/ui/bufhl_spec.lua | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'test') diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua index 5df909f79c..65c5f67726 100644 --- a/test/functional/ui/bufhl_spec.lua +++ b/test/functional/ui/bufhl_spec.lua @@ -386,6 +386,22 @@ describe('Buffer highlighting', function() ]]) end) + it('can be retrieved', function() + local get_virtual_text = curbufmeths.get_virtual_text + local line_count = curbufmeths.line_count + + local s1 = {{'Köttbullar', 'Comment'}, {'Kräuterbutter'}} + local s2 = {{'こんにちは', 'Comment'}} + + set_virtual_text(-1, 0, s1, {}) + eq(s1, get_virtual_text(0)) + + set_virtual_text(-1, line_count(), s2, {}) + eq(s2, get_virtual_text(line_count())) + + eq({}, get_virtual_text(line_count() + 9000)) + end) + it('is not highlighted by visual selection', function() feed("ggVG") screen:expect([[ -- cgit From d200a818a71bba0f2b3d4f7f173b4d799eb3c7f0 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 10 Nov 2019 17:12:41 +0100 Subject: tests: vim.rpcnotify test is flaky --- test/functional/lua/utility_functions_spec.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/lua/utility_functions_spec.lua b/test/functional/lua/utility_functions_spec.lua index 6631aa8e4c..7dc97ee5af 100644 --- a/test/functional/lua/utility_functions_spec.lua +++ b/test/functional/lua/utility_functions_spec.lua @@ -14,6 +14,7 @@ local exec_lua = helpers.exec_lua local matches = helpers.matches local source = helpers.source local NIL = helpers.NIL +local retry = helpers.retry before_each(clear) @@ -368,7 +369,9 @@ describe('lua stdlib', function() vim.rpcnotify(chan, 'nvim_set_current_line', 'foo') return vim.api.nvim_get_current_line() ]])) - eq('foo', meths.get_current_line()) + retry(10, nil, function() + eq('foo', meths.get_current_line()) + end) local screen = Screen.new(50,7) screen:set_default_attr_ids({ -- cgit From 678a51b1da0c0535299341e7a598c080adcf8553 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Mon, 28 Oct 2019 20:52:18 +0900 Subject: Lua: vim.validate() We often want to do type checking of public function arguments. - test: Rename utility_function_spec.lua to vim_spec.lua - .luacov: Map lua module names --- test/functional/lua/utility_functions_spec.lua | 405 ---------------------- test/functional/lua/vim_spec.lua | 458 +++++++++++++++++++++++++ 2 files changed, 458 insertions(+), 405 deletions(-) delete mode 100644 test/functional/lua/utility_functions_spec.lua create mode 100644 test/functional/lua/vim_spec.lua (limited to 'test') diff --git a/test/functional/lua/utility_functions_spec.lua b/test/functional/lua/utility_functions_spec.lua deleted file mode 100644 index 7dc97ee5af..0000000000 --- a/test/functional/lua/utility_functions_spec.lua +++ /dev/null @@ -1,405 +0,0 @@ --- Test suite for testing interactions with API bindings -local helpers = require('test.functional.helpers')(after_each) -local Screen = require('test.functional.ui.screen') - -local funcs = helpers.funcs -local meths = helpers.meths -local command = helpers.command -local clear = helpers.clear -local eq = helpers.eq -local eval = helpers.eval -local feed = helpers.feed -local pcall_err = helpers.pcall_err -local exec_lua = helpers.exec_lua -local matches = helpers.matches -local source = helpers.source -local NIL = helpers.NIL -local retry = helpers.retry - -before_each(clear) - -describe('lua stdlib', function() - -- İ: `tolower("İ")` is `i` which has length 1 while `İ` itself has - -- length 2 (in bytes). - -- Ⱥ: `tolower("Ⱥ")` is `ⱥ` which has length 2 while `Ⱥ` itself has - -- length 3 (in bytes). - -- - -- Note: 'i' !=? 'İ' and 'ⱥ' !=? 'Ⱥ' on some systems. - -- Note: Built-in Nvim comparison (on systems lacking `strcasecmp`) works - -- only on ASCII characters. - it('vim.stricmp', function() - eq(0, funcs.luaeval('vim.stricmp("a", "A")')) - eq(0, funcs.luaeval('vim.stricmp("A", "a")')) - eq(0, funcs.luaeval('vim.stricmp("a", "a")')) - eq(0, funcs.luaeval('vim.stricmp("A", "A")')) - - eq(0, funcs.luaeval('vim.stricmp("", "")')) - eq(0, funcs.luaeval('vim.stricmp("\\0", "\\0")')) - eq(0, funcs.luaeval('vim.stricmp("\\0\\0", "\\0\\0")')) - eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0", "\\0\\0\\0")')) - eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0A", "\\0\\0\\0a")')) - eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0A")')) - eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0a")')) - - eq(0, funcs.luaeval('vim.stricmp("a\\0", "A\\0")')) - eq(0, funcs.luaeval('vim.stricmp("A\\0", "a\\0")')) - eq(0, funcs.luaeval('vim.stricmp("a\\0", "a\\0")')) - eq(0, funcs.luaeval('vim.stricmp("A\\0", "A\\0")')) - - eq(0, funcs.luaeval('vim.stricmp("\\0a", "\\0A")')) - eq(0, funcs.luaeval('vim.stricmp("\\0A", "\\0a")')) - eq(0, funcs.luaeval('vim.stricmp("\\0a", "\\0a")')) - eq(0, funcs.luaeval('vim.stricmp("\\0A", "\\0A")')) - - eq(0, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0A\\0")')) - eq(0, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0a\\0")')) - eq(0, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0a\\0")')) - eq(0, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0A\\0")')) - - eq(-1, funcs.luaeval('vim.stricmp("a", "B")')) - eq(-1, funcs.luaeval('vim.stricmp("A", "b")')) - eq(-1, funcs.luaeval('vim.stricmp("a", "b")')) - eq(-1, funcs.luaeval('vim.stricmp("A", "B")')) - - eq(-1, funcs.luaeval('vim.stricmp("", "\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0", "\\0\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0\\0", "\\0\\0\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0\\0\\0A", "\\0\\0\\0b")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0B")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0b")')) - - eq(-1, funcs.luaeval('vim.stricmp("a\\0", "B\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("A\\0", "b\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("a\\0", "b\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("A\\0", "B\\0")')) - - eq(-1, funcs.luaeval('vim.stricmp("\\0a", "\\0B")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0A", "\\0b")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0a", "\\0b")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0A", "\\0B")')) - - eq(-1, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0B\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0b\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0b\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0B\\0")')) - - eq(1, funcs.luaeval('vim.stricmp("c", "B")')) - eq(1, funcs.luaeval('vim.stricmp("C", "b")')) - eq(1, funcs.luaeval('vim.stricmp("c", "b")')) - eq(1, funcs.luaeval('vim.stricmp("C", "B")')) - - eq(1, funcs.luaeval('vim.stricmp("\\0", "")')) - eq(1, funcs.luaeval('vim.stricmp("\\0\\0", "\\0")')) - eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0", "\\0\\0")')) - eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0\\0", "\\0\\0\\0")')) - eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0C", "\\0\\0\\0b")')) - eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0c", "\\0\\0\\0B")')) - eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0c", "\\0\\0\\0b")')) - - eq(1, funcs.luaeval('vim.stricmp("c\\0", "B\\0")')) - eq(1, funcs.luaeval('vim.stricmp("C\\0", "b\\0")')) - eq(1, funcs.luaeval('vim.stricmp("c\\0", "b\\0")')) - eq(1, funcs.luaeval('vim.stricmp("C\\0", "B\\0")')) - - eq(1, funcs.luaeval('vim.stricmp("c\\0", "B")')) - eq(1, funcs.luaeval('vim.stricmp("C\\0", "b")')) - eq(1, funcs.luaeval('vim.stricmp("c\\0", "b")')) - eq(1, funcs.luaeval('vim.stricmp("C\\0", "B")')) - - eq(1, funcs.luaeval('vim.stricmp("\\0c", "\\0B")')) - eq(1, funcs.luaeval('vim.stricmp("\\0C", "\\0b")')) - eq(1, funcs.luaeval('vim.stricmp("\\0c", "\\0b")')) - eq(1, funcs.luaeval('vim.stricmp("\\0C", "\\0B")')) - - eq(1, funcs.luaeval('vim.stricmp("\\0c\\0", "\\0B\\0")')) - eq(1, funcs.luaeval('vim.stricmp("\\0C\\0", "\\0b\\0")')) - eq(1, funcs.luaeval('vim.stricmp("\\0c\\0", "\\0b\\0")')) - eq(1, funcs.luaeval('vim.stricmp("\\0C\\0", "\\0B\\0")')) - end) - - it("vim.str_utfindex/str_byteindex", function() - exec_lua([[_G.test_text = "xy åäö ɧ 汉语 ↥ 🤦x🦄 å بِيَّ"]]) - local indicies32 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,29,33,34,35,37,38,40,42,44,46,48} - local indicies16 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,28,29,33,33,34,35,37,38,40,42,44,46,48} - for i,k in pairs(indicies32) do - eq(k, exec_lua("return vim.str_byteindex(_G.test_text, ...)", i), i) - end - for i,k in pairs(indicies16) do - eq(k, exec_lua("return vim.str_byteindex(_G.test_text, ..., true)", i), i) - end - local i32, i16 = 0, 0 - for k = 0,48 do - if indicies32[i32] < k then - i32 = i32 + 1 - end - if indicies16[i16] < k then - i16 = i16 + 1 - if indicies16[i16+1] == indicies16[i16] then - i16 = i16 + 1 - end - end - eq({i32, i16}, exec_lua("return {vim.str_utfindex(_G.test_text, ...)}", k), k) - end - end) - - it("vim.schedule", function() - exec_lua([[ - test_table = {} - vim.schedule(function() - table.insert(test_table, "xx") - end) - table.insert(test_table, "yy") - ]]) - eq({"yy","xx"}, exec_lua("return test_table")) - - -- Validates args. - eq('Error executing lua: vim.schedule: expected function', - pcall_err(exec_lua, "vim.schedule('stringly')")) - eq('Error executing lua: vim.schedule: expected function', - pcall_err(exec_lua, "vim.schedule()")) - - exec_lua([[ - vim.schedule(function() - error("big failure\nvery async") - end) - ]]) - - feed("") - eq('Error executing vim.schedule lua callback: [string ""]:2: big failure\nvery async', eval("v:errmsg")) - - local screen = Screen.new(60,5) - screen:set_default_attr_ids({ - [1] = {bold = true, foreground = Screen.colors.Blue1}, - [2] = {bold = true, reverse = true}, - [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, - [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, - }) - screen:attach() - screen:expect{grid=[[ - ^ | - {1:~ }| - {1:~ }| - {1:~ }| - | - ]]} - - -- nvim_command causes a vimL exception, check that it is properly caught - -- and propagated as an error message in async contexts.. #10809 - exec_lua([[ - vim.schedule(function() - vim.api.nvim_command(":echo 'err") - end) - ]]) - screen:expect{grid=[[ - | - {2: }| - {3:Error executing vim.schedule lua callback: [string ""]}| - {3::2: Vim(echo):E115: Missing quote: 'err} | - {4:Press ENTER or type command to continue}^ | - ]]} - end) - - it("vim.split", function() - local split = function(str, sep, plain) - return exec_lua('return vim.split(...)', str, sep, plain) - end - - local tests = { - { "a,b", ",", false, { 'a', 'b' } }, - { ":aa::bb:", ":", false, { '', 'aa', '', 'bb', '' } }, - { "::ee::ff:", ":", false, { '', '', 'ee', '', 'ff', '' } }, - { "ab", ".", false, { '', '', '' } }, - { "a1b2c", "[0-9]", false, { 'a', 'b', 'c' } }, - { "xy", "", false, { 'x', 'y' } }, - { "here be dragons", " ", false, { "here", "be", "dragons"} }, - { "axaby", "ab?", false, { '', 'x', 'y' } }, - { "f v2v v3v w2w ", "([vw])2%1", false, { 'f ', ' v3v ', ' ' } }, - { "x*yz*oo*l", "*", true, { 'x', 'yz', 'oo', 'l' } }, - } - - for _, t in ipairs(tests) do - eq(t[4], split(t[1], t[2], t[3])) - end - - local loops = { - { "abc", ".-" }, - } - - for _, t in ipairs(loops) do - matches(".*Infinite loop detected", pcall_err(split, t[1], t[2])) - end - - -- Validates args. - eq(true, pcall(split, 'string', 'string', nil)) - eq('Error executing lua: .../shared.lua: Expected string, got number', - pcall_err(split, 1, 'string', nil)) - eq('Error executing lua: .../shared.lua: Expected string, got number', - pcall_err(split, 'string', 1, nil)) - eq('Error executing lua: .../shared.lua: Expected boolean or nil, got number', - pcall_err(split, 'string', 'string', 1)) - end) - - it('vim.trim', function() - local trim = function(s) - return exec_lua('return vim.trim(...)', s) - end - - local trims = { - { " a", "a" }, - { " b ", "b" }, - { "\tc" , "c" }, - { "r\n", "r" }, - } - - for _, t in ipairs(trims) do - assert(t[2], trim(t[1])) - end - - -- Validates args. - eq('Error executing lua: .../shared.lua: Expected string, got number', - pcall_err(trim, 2)) - end) - - it('vim.inspect', function() - -- just make sure it basically works, it has its own test suite - local inspect = function(t, opts) - return exec_lua('return vim.inspect(...)', t, opts) - end - - eq('2', inspect(2)) - eq('{+a = {+b = 1+}+}', - inspect({ a = { b = 1 } }, { newline = '+', indent = '' })) - - -- special value vim.inspect.KEY works - eq('{ KEY_a = "x", KEY_b = "y"}', exec_lua([[ - return vim.inspect({a="x", b="y"}, {newline = '', process = function(item, path) - if path[#path] == vim.inspect.KEY then - return 'KEY_'..item - end - return item - end}) - ]])) - end) - - it("vim.deepcopy", function() - local is_dc = exec_lua([[ - local a = { x = { 1, 2 }, y = 5} - local b = vim.deepcopy(a) - - local count = 0 - for _ in pairs(b) do count = count + 1 end - - return b.x[1] == 1 and b.x[2] == 2 and b.y == 5 and count == 2 - and tostring(a) ~= tostring(b) - ]]) - - assert(is_dc) - end) - - it('vim.pesc', function() - eq('foo%-bar', exec_lua([[return vim.pesc('foo-bar')]])) - eq('foo%%%-bar', exec_lua([[return vim.pesc(vim.pesc('foo-bar'))]])) - - -- Validates args. - eq("Error executing lua: .../shared.lua: Expected string, got number", - pcall_err(exec_lua, [[return vim.pesc(2)]])) - end) - - it('vim.call, vim.fn', function() - eq(true, exec_lua([[return vim.call('sin', 0.0) == 0.0 ]])) - eq(true, exec_lua([[return vim.fn.sin(0.0) == 0.0 ]])) - -- compat: nvim_call_function uses "special" value for vimL float - eq(false, exec_lua([[return vim.api.nvim_call_function('sin', {0.0}) == 0.0 ]])) - - source([[ - func! FooFunc(test) - let g:test = a:test - return {} - endfunc - func! VarArg(...) - return a:000 - endfunc - func! Nilly() - return [v:null, v:null] - endfunc - ]]) - eq(true, exec_lua([[return next(vim.fn.FooFunc(3)) == nil ]])) - eq(3, eval("g:test")) - -- compat: nvim_call_function uses "special" value for empty dict - eq(true, exec_lua([[return next(vim.api.nvim_call_function("FooFunc", {5})) == true ]])) - eq(5, eval("g:test")) - - eq({2, "foo", true}, exec_lua([[return vim.fn.VarArg(2, "foo", true)]])) - - eq(true, exec_lua([[ - local x = vim.fn.Nilly() - return #x == 2 and x[1] == vim.NIL and x[2] == vim.NIL - ]])) - eq({NIL, NIL}, exec_lua([[return vim.fn.Nilly()]])) - - -- error handling - eq({false, 'Vim:E714: List required'}, exec_lua([[return {pcall(vim.fn.add, "aa", "bb")}]])) - end) - - it('vim.rpcrequest and vim.rpcnotify', function() - exec_lua([[ - chan = vim.fn.jobstart({'cat'}, {rpc=true}) - vim.rpcrequest(chan, 'nvim_set_current_line', 'meow') - ]]) - eq('meow', meths.get_current_line()) - command("let x = [3, 'aa', v:true, v:null]") - eq(true, exec_lua([[ - ret = vim.rpcrequest(chan, 'nvim_get_var', 'x') - return #ret == 4 and ret[1] == 3 and ret[2] == 'aa' and ret[3] == true and ret[4] == vim.NIL - ]])) - eq({3, 'aa', true, NIL}, exec_lua([[return ret]])) - - -- error handling - eq({false, 'Invalid channel: 23'}, - exec_lua([[return {pcall(vim.rpcrequest, 23, 'foo')}]])) - eq({false, 'Invalid channel: 23'}, - exec_lua([[return {pcall(vim.rpcnotify, 23, 'foo')}]])) - - eq({false, 'Vim:E121: Undefined variable: foobar'}, - exec_lua([[return {pcall(vim.rpcrequest, chan, 'nvim_eval', "foobar")}]])) - - - -- rpcnotify doesn't wait on request - eq('meow', exec_lua([[ - vim.rpcnotify(chan, 'nvim_set_current_line', 'foo') - return vim.api.nvim_get_current_line() - ]])) - retry(10, nil, function() - eq('foo', meths.get_current_line()) - end) - - local screen = Screen.new(50,7) - screen:set_default_attr_ids({ - [1] = {bold = true, foreground = Screen.colors.Blue1}, - [2] = {bold = true, reverse = true}, - [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, - [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, - }) - screen:attach() - exec_lua([[ - local timer = vim.loop.new_timer() - timer:start(20, 0, function () - -- notify ok (executed later when safe) - vim.rpcnotify(chan, 'nvim_set_var', 'yy', {3, vim.NIL}) - -- rpcrequest an error - vim.rpcrequest(chan, 'nvim_set_current_line', 'bork') - end) - ]]) - screen:expect{grid=[[ - foo | - {1:~ }| - {2: }| - {3:Error executing luv callback:} | - {3:[string ""]:6: E5560: rpcrequest must not be}| - {3: called in a lua loop callback} | - {4:Press ENTER or type command to continue}^ | - ]]} - feed('') - eq({3, NIL}, meths.get_var('yy')) - end) -end) diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua new file mode 100644 index 0000000000..cb1f027623 --- /dev/null +++ b/test/functional/lua/vim_spec.lua @@ -0,0 +1,458 @@ +-- Test suite for testing interactions with API bindings +local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') + +local funcs = helpers.funcs +local meths = helpers.meths +local command = helpers.command +local clear = helpers.clear +local eq = helpers.eq +local eval = helpers.eval +local feed = helpers.feed +local pcall_err = helpers.pcall_err +local exec_lua = helpers.exec_lua +local matches = helpers.matches +local source = helpers.source +local NIL = helpers.NIL +local retry = helpers.retry + +before_each(clear) + +describe('lua stdlib', function() + -- İ: `tolower("İ")` is `i` which has length 1 while `İ` itself has + -- length 2 (in bytes). + -- Ⱥ: `tolower("Ⱥ")` is `ⱥ` which has length 2 while `Ⱥ` itself has + -- length 3 (in bytes). + -- + -- Note: 'i' !=? 'İ' and 'ⱥ' !=? 'Ⱥ' on some systems. + -- Note: Built-in Nvim comparison (on systems lacking `strcasecmp`) works + -- only on ASCII characters. + it('vim.stricmp', function() + eq(0, funcs.luaeval('vim.stricmp("a", "A")')) + eq(0, funcs.luaeval('vim.stricmp("A", "a")')) + eq(0, funcs.luaeval('vim.stricmp("a", "a")')) + eq(0, funcs.luaeval('vim.stricmp("A", "A")')) + + eq(0, funcs.luaeval('vim.stricmp("", "")')) + eq(0, funcs.luaeval('vim.stricmp("\\0", "\\0")')) + eq(0, funcs.luaeval('vim.stricmp("\\0\\0", "\\0\\0")')) + eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0", "\\0\\0\\0")')) + eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0A", "\\0\\0\\0a")')) + eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0A")')) + eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0a")')) + + eq(0, funcs.luaeval('vim.stricmp("a\\0", "A\\0")')) + eq(0, funcs.luaeval('vim.stricmp("A\\0", "a\\0")')) + eq(0, funcs.luaeval('vim.stricmp("a\\0", "a\\0")')) + eq(0, funcs.luaeval('vim.stricmp("A\\0", "A\\0")')) + + eq(0, funcs.luaeval('vim.stricmp("\\0a", "\\0A")')) + eq(0, funcs.luaeval('vim.stricmp("\\0A", "\\0a")')) + eq(0, funcs.luaeval('vim.stricmp("\\0a", "\\0a")')) + eq(0, funcs.luaeval('vim.stricmp("\\0A", "\\0A")')) + + eq(0, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0A\\0")')) + eq(0, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0a\\0")')) + eq(0, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0a\\0")')) + eq(0, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0A\\0")')) + + eq(-1, funcs.luaeval('vim.stricmp("a", "B")')) + eq(-1, funcs.luaeval('vim.stricmp("A", "b")')) + eq(-1, funcs.luaeval('vim.stricmp("a", "b")')) + eq(-1, funcs.luaeval('vim.stricmp("A", "B")')) + + eq(-1, funcs.luaeval('vim.stricmp("", "\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0", "\\0\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0\\0", "\\0\\0\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0\\0\\0A", "\\0\\0\\0b")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0B")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0b")')) + + eq(-1, funcs.luaeval('vim.stricmp("a\\0", "B\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("A\\0", "b\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("a\\0", "b\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("A\\0", "B\\0")')) + + eq(-1, funcs.luaeval('vim.stricmp("\\0a", "\\0B")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0A", "\\0b")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0a", "\\0b")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0A", "\\0B")')) + + eq(-1, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0B\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0b\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0b\\0")')) + eq(-1, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0B\\0")')) + + eq(1, funcs.luaeval('vim.stricmp("c", "B")')) + eq(1, funcs.luaeval('vim.stricmp("C", "b")')) + eq(1, funcs.luaeval('vim.stricmp("c", "b")')) + eq(1, funcs.luaeval('vim.stricmp("C", "B")')) + + eq(1, funcs.luaeval('vim.stricmp("\\0", "")')) + eq(1, funcs.luaeval('vim.stricmp("\\0\\0", "\\0")')) + eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0", "\\0\\0")')) + eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0\\0", "\\0\\0\\0")')) + eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0C", "\\0\\0\\0b")')) + eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0c", "\\0\\0\\0B")')) + eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0c", "\\0\\0\\0b")')) + + eq(1, funcs.luaeval('vim.stricmp("c\\0", "B\\0")')) + eq(1, funcs.luaeval('vim.stricmp("C\\0", "b\\0")')) + eq(1, funcs.luaeval('vim.stricmp("c\\0", "b\\0")')) + eq(1, funcs.luaeval('vim.stricmp("C\\0", "B\\0")')) + + eq(1, funcs.luaeval('vim.stricmp("c\\0", "B")')) + eq(1, funcs.luaeval('vim.stricmp("C\\0", "b")')) + eq(1, funcs.luaeval('vim.stricmp("c\\0", "b")')) + eq(1, funcs.luaeval('vim.stricmp("C\\0", "B")')) + + eq(1, funcs.luaeval('vim.stricmp("\\0c", "\\0B")')) + eq(1, funcs.luaeval('vim.stricmp("\\0C", "\\0b")')) + eq(1, funcs.luaeval('vim.stricmp("\\0c", "\\0b")')) + eq(1, funcs.luaeval('vim.stricmp("\\0C", "\\0B")')) + + eq(1, funcs.luaeval('vim.stricmp("\\0c\\0", "\\0B\\0")')) + eq(1, funcs.luaeval('vim.stricmp("\\0C\\0", "\\0b\\0")')) + eq(1, funcs.luaeval('vim.stricmp("\\0c\\0", "\\0b\\0")')) + eq(1, funcs.luaeval('vim.stricmp("\\0C\\0", "\\0B\\0")')) + end) + + it("vim.str_utfindex/str_byteindex", function() + exec_lua([[_G.test_text = "xy åäö ɧ 汉语 ↥ 🤦x🦄 å بِيَّ"]]) + local indicies32 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,29,33,34,35,37,38,40,42,44,46,48} + local indicies16 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,28,29,33,33,34,35,37,38,40,42,44,46,48} + for i,k in pairs(indicies32) do + eq(k, exec_lua("return vim.str_byteindex(_G.test_text, ...)", i), i) + end + for i,k in pairs(indicies16) do + eq(k, exec_lua("return vim.str_byteindex(_G.test_text, ..., true)", i), i) + end + local i32, i16 = 0, 0 + for k = 0,48 do + if indicies32[i32] < k then + i32 = i32 + 1 + end + if indicies16[i16] < k then + i16 = i16 + 1 + if indicies16[i16+1] == indicies16[i16] then + i16 = i16 + 1 + end + end + eq({i32, i16}, exec_lua("return {vim.str_utfindex(_G.test_text, ...)}", k), k) + end + end) + + it("vim.schedule", function() + exec_lua([[ + test_table = {} + vim.schedule(function() + table.insert(test_table, "xx") + end) + table.insert(test_table, "yy") + ]]) + eq({"yy","xx"}, exec_lua("return test_table")) + + -- Validates args. + eq('Error executing lua: vim.schedule: expected function', + pcall_err(exec_lua, "vim.schedule('stringly')")) + eq('Error executing lua: vim.schedule: expected function', + pcall_err(exec_lua, "vim.schedule()")) + + exec_lua([[ + vim.schedule(function() + error("big failure\nvery async") + end) + ]]) + + feed("") + eq('Error executing vim.schedule lua callback: [string ""]:2: big failure\nvery async', eval("v:errmsg")) + + local screen = Screen.new(60,5) + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {bold = true, reverse = true}, + [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, + }) + screen:attach() + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + -- nvim_command causes a vimL exception, check that it is properly caught + -- and propagated as an error message in async contexts.. #10809 + exec_lua([[ + vim.schedule(function() + vim.api.nvim_command(":echo 'err") + end) + ]]) + screen:expect{grid=[[ + | + {2: }| + {3:Error executing vim.schedule lua callback: [string ""]}| + {3::2: Vim(echo):E115: Missing quote: 'err} | + {4:Press ENTER or type command to continue}^ | + ]]} + end) + + it("vim.split", function() + local split = function(str, sep, plain) + return exec_lua('return vim.split(...)', str, sep, plain) + end + + local tests = { + { "a,b", ",", false, { 'a', 'b' } }, + { ":aa::bb:", ":", false, { '', 'aa', '', 'bb', '' } }, + { "::ee::ff:", ":", false, { '', '', 'ee', '', 'ff', '' } }, + { "ab", ".", false, { '', '', '' } }, + { "a1b2c", "[0-9]", false, { 'a', 'b', 'c' } }, + { "xy", "", false, { 'x', 'y' } }, + { "here be dragons", " ", false, { "here", "be", "dragons"} }, + { "axaby", "ab?", false, { '', 'x', 'y' } }, + { "f v2v v3v w2w ", "([vw])2%1", false, { 'f ', ' v3v ', ' ' } }, + { "x*yz*oo*l", "*", true, { 'x', 'yz', 'oo', 'l' } }, + } + + for _, t in ipairs(tests) do + eq(t[4], split(t[1], t[2], t[3])) + end + + local loops = { + { "abc", ".-" }, + } + + for _, t in ipairs(loops) do + matches(".*Infinite loop detected", pcall_err(split, t[1], t[2])) + end + + -- Validates args. + eq(true, pcall(split, 'string', 'string', nil)) + eq('Error executing lua: .../shared.lua: Expected string, got number', + pcall_err(split, 1, 'string', nil)) + eq('Error executing lua: .../shared.lua: Expected string, got number', + pcall_err(split, 'string', 1, nil)) + eq('Error executing lua: .../shared.lua: Expected boolean or nil, got number', + pcall_err(split, 'string', 'string', 1)) + end) + + it('vim.trim', function() + local trim = function(s) + return exec_lua('return vim.trim(...)', s) + end + + local trims = { + { " a", "a" }, + { " b ", "b" }, + { "\tc" , "c" }, + { "r\n", "r" }, + } + + for _, t in ipairs(trims) do + assert(t[2], trim(t[1])) + end + + -- Validates args. + eq('Error executing lua: .../shared.lua: Expected string, got number', + pcall_err(trim, 2)) + end) + + it('vim.inspect', function() + -- just make sure it basically works, it has its own test suite + local inspect = function(t, opts) + return exec_lua('return vim.inspect(...)', t, opts) + end + + eq('2', inspect(2)) + eq('{+a = {+b = 1+}+}', + inspect({ a = { b = 1 } }, { newline = '+', indent = '' })) + + -- special value vim.inspect.KEY works + eq('{ KEY_a = "x", KEY_b = "y"}', exec_lua([[ + return vim.inspect({a="x", b="y"}, {newline = '', process = function(item, path) + if path[#path] == vim.inspect.KEY then + return 'KEY_'..item + end + return item + end}) + ]])) + end) + + it("vim.deepcopy", function() + local is_dc = exec_lua([[ + local a = { x = { 1, 2 }, y = 5} + local b = vim.deepcopy(a) + + local count = 0 + for _ in pairs(b) do count = count + 1 end + + return b.x[1] == 1 and b.x[2] == 2 and b.y == 5 and count == 2 + and tostring(a) ~= tostring(b) + ]]) + + assert(is_dc) + end) + + it('vim.pesc', function() + eq('foo%-bar', exec_lua([[return vim.pesc('foo-bar')]])) + eq('foo%%%-bar', exec_lua([[return vim.pesc(vim.pesc('foo-bar'))]])) + + -- Validates args. + eq("Error executing lua: .../shared.lua: Expected string, got number", + pcall_err(exec_lua, [[return vim.pesc(2)]])) + end) + + it('vim.call, vim.fn', function() + eq(true, exec_lua([[return vim.call('sin', 0.0) == 0.0 ]])) + eq(true, exec_lua([[return vim.fn.sin(0.0) == 0.0 ]])) + -- compat: nvim_call_function uses "special" value for vimL float + eq(false, exec_lua([[return vim.api.nvim_call_function('sin', {0.0}) == 0.0 ]])) + + source([[ + func! FooFunc(test) + let g:test = a:test + return {} + endfunc + func! VarArg(...) + return a:000 + endfunc + func! Nilly() + return [v:null, v:null] + endfunc + ]]) + eq(true, exec_lua([[return next(vim.fn.FooFunc(3)) == nil ]])) + eq(3, eval("g:test")) + -- compat: nvim_call_function uses "special" value for empty dict + eq(true, exec_lua([[return next(vim.api.nvim_call_function("FooFunc", {5})) == true ]])) + eq(5, eval("g:test")) + + eq({2, "foo", true}, exec_lua([[return vim.fn.VarArg(2, "foo", true)]])) + + eq(true, exec_lua([[ + local x = vim.fn.Nilly() + return #x == 2 and x[1] == vim.NIL and x[2] == vim.NIL + ]])) + eq({NIL, NIL}, exec_lua([[return vim.fn.Nilly()]])) + + -- error handling + eq({false, 'Vim:E714: List required'}, exec_lua([[return {pcall(vim.fn.add, "aa", "bb")}]])) + end) + + it('vim.rpcrequest and vim.rpcnotify', function() + exec_lua([[ + chan = vim.fn.jobstart({'cat'}, {rpc=true}) + vim.rpcrequest(chan, 'nvim_set_current_line', 'meow') + ]]) + eq('meow', meths.get_current_line()) + command("let x = [3, 'aa', v:true, v:null]") + eq(true, exec_lua([[ + ret = vim.rpcrequest(chan, 'nvim_get_var', 'x') + return #ret == 4 and ret[1] == 3 and ret[2] == 'aa' and ret[3] == true and ret[4] == vim.NIL + ]])) + eq({3, 'aa', true, NIL}, exec_lua([[return ret]])) + + -- error handling + eq({false, 'Invalid channel: 23'}, + exec_lua([[return {pcall(vim.rpcrequest, 23, 'foo')}]])) + eq({false, 'Invalid channel: 23'}, + exec_lua([[return {pcall(vim.rpcnotify, 23, 'foo')}]])) + + eq({false, 'Vim:E121: Undefined variable: foobar'}, + exec_lua([[return {pcall(vim.rpcrequest, chan, 'nvim_eval', "foobar")}]])) + + + -- rpcnotify doesn't wait on request + eq('meow', exec_lua([[ + vim.rpcnotify(chan, 'nvim_set_current_line', 'foo') + return vim.api.nvim_get_current_line() + ]])) + retry(10, nil, function() + eq('foo', meths.get_current_line()) + end) + + local screen = Screen.new(50,7) + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {bold = true, reverse = true}, + [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, + }) + screen:attach() + exec_lua([[ + local timer = vim.loop.new_timer() + timer:start(20, 0, function () + -- notify ok (executed later when safe) + vim.rpcnotify(chan, 'nvim_set_var', 'yy', {3, vim.NIL}) + -- rpcrequest an error + vim.rpcrequest(chan, 'nvim_set_current_line', 'bork') + end) + ]]) + screen:expect{grid=[[ + foo | + {1:~ }| + {2: }| + {3:Error executing luv callback:} | + {3:[string ""]:6: E5560: rpcrequest must not be}| + {3: called in a lua loop callback} | + {4:Press ENTER or type command to continue}^ | + ]]} + feed('') + eq({3, NIL}, meths.get_var('yy')) + end) + + it('vim.validate', function() + eq(NIL, exec_lua("vim.validate({ arg1={ {}, 'table' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ {}, 't' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ nil, 't', true }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ { foo='foo' }, 't' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ { 'foo' }, 't' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ 'foo', 'string' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ 'foo', 's' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ '', 's' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ nil, 's', true }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ 1, 'number' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ 1, 'n' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ 0, 'n' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ 0.1, 'n' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'n', true }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ true, 'boolean' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ true, 'b' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ false, 'b' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'b', true }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ function()end, 'function' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ function()end, 'f' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'f', true }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'nil' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'nil', true }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ coroutine.create(function()end), 'thread' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'thread', true }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ {}, 't' } }, { arg2={ 'foo', 's' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ {}, 't' }, arg2={ 'foo', 's' }})")) + eq(NIL, exec_lua("vim.validate({ arg1={ 2, function(a) return (a % 2) == 0 end, 'even number' }})")) + + eq("Error executing lua: .../shared.lua: arg1: expected table, got number", pcall_err(exec_lua, "vim.validate({ arg1={ 1, 't' }})")) + eq("Error executing lua: .../shared.lua: arg2: expected string, got number", pcall_err(exec_lua, "vim.validate({ arg1={ {}, 't' }, arg2={ 1, 's' }})")) + eq("Error executing lua: .../shared.lua: arg2: expected string, got nil", pcall_err(exec_lua, "vim.validate({ arg1={ {}, 't' }, arg2={ nil, 's' }})")) + eq("Error executing lua: .../shared.lua: arg2: expected string, got nil", pcall_err(exec_lua, "vim.validate({ arg1={ {}, 't' }, arg2={ nil, 's' }})")) + eq("Error executing lua: .../shared.lua: arg1: expected even number, got 3", pcall_err(exec_lua, "vim.validate({ arg1={ 3, function(a) return a == 1 end, 'even number' }})")) + end) + + it('vim.is_callable', function() + eq(true, exec_lua("return vim.is_callable(function()end)")) + eq(true, exec_lua([[ + local meta = { __call = function()end } + local function new_callable() + return setmetatable({}, meta) + end + local callable = new_callable() + return vim.is_callable(callable) + ]])) + + eq(false, exec_lua("return vim.is_callable(1)")) + eq(false, exec_lua("return vim.is_callable('foo')")) + eq(false, exec_lua("return vim.is_callable({})")) + end) +end) -- cgit From 7aa4042d3bddf2f39d048b9ba1dd7adf2193d4eb Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 10 Nov 2019 19:58:14 -0800 Subject: Lua: vim.validate() --- test/functional/lua/vim_spec.lua | 81 +++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 34 deletions(-) (limited to 'test') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index cb1f027623..a9c52bfcd9 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -404,40 +404,53 @@ describe('lua stdlib', function() end) it('vim.validate', function() - eq(NIL, exec_lua("vim.validate({ arg1={ {}, 'table' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ {}, 't' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ nil, 't', true }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ { foo='foo' }, 't' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ { 'foo' }, 't' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ 'foo', 'string' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ 'foo', 's' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ '', 's' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ nil, 's', true }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ 1, 'number' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ 1, 'n' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ 0, 'n' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ 0.1, 'n' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'n', true }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ true, 'boolean' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ true, 'b' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ false, 'b' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'b', true }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ function()end, 'function' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ function()end, 'f' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'f', true }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'nil' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'nil', true }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ coroutine.create(function()end), 'thread' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ nil, 'thread', true }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ {}, 't' } }, { arg2={ 'foo', 's' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ {}, 't' }, arg2={ 'foo', 's' }})")) - eq(NIL, exec_lua("vim.validate({ arg1={ 2, function(a) return (a % 2) == 0 end, 'even number' }})")) - - eq("Error executing lua: .../shared.lua: arg1: expected table, got number", pcall_err(exec_lua, "vim.validate({ arg1={ 1, 't' }})")) - eq("Error executing lua: .../shared.lua: arg2: expected string, got number", pcall_err(exec_lua, "vim.validate({ arg1={ {}, 't' }, arg2={ 1, 's' }})")) - eq("Error executing lua: .../shared.lua: arg2: expected string, got nil", pcall_err(exec_lua, "vim.validate({ arg1={ {}, 't' }, arg2={ nil, 's' }})")) - eq("Error executing lua: .../shared.lua: arg2: expected string, got nil", pcall_err(exec_lua, "vim.validate({ arg1={ {}, 't' }, arg2={ nil, 's' }})")) - eq("Error executing lua: .../shared.lua: arg1: expected even number, got 3", pcall_err(exec_lua, "vim.validate({ arg1={ 3, function(a) return a == 1 end, 'even number' }})")) + exec_lua("vim.validate{arg1={{}, 'table' }}") + exec_lua("vim.validate{arg1={{}, 't' }}") + exec_lua("vim.validate{arg1={nil, 't', true }}") + exec_lua("vim.validate{arg1={{ foo='foo' }, 't' }}") + exec_lua("vim.validate{arg1={{ 'foo' }, 't' }}") + exec_lua("vim.validate{arg1={'foo', 'string' }}") + exec_lua("vim.validate{arg1={'foo', 's' }}") + exec_lua("vim.validate{arg1={'', 's' }}") + exec_lua("vim.validate{arg1={nil, 's', true }}") + exec_lua("vim.validate{arg1={1, 'number' }}") + exec_lua("vim.validate{arg1={1, 'n' }}") + exec_lua("vim.validate{arg1={0, 'n' }}") + exec_lua("vim.validate{arg1={0.1, 'n' }}") + exec_lua("vim.validate{arg1={nil, 'n', true }}") + exec_lua("vim.validate{arg1={true, 'boolean' }}") + exec_lua("vim.validate{arg1={true, 'b' }}") + exec_lua("vim.validate{arg1={false, 'b' }}") + exec_lua("vim.validate{arg1={nil, 'b', true }}") + exec_lua("vim.validate{arg1={function()end, 'function' }}") + exec_lua("vim.validate{arg1={function()end, 'f' }}") + exec_lua("vim.validate{arg1={nil, 'f', true }}") + exec_lua("vim.validate{arg1={nil, 'nil' }}") + exec_lua("vim.validate{arg1={nil, 'nil', true }}") + exec_lua("vim.validate{arg1={coroutine.create(function()end), 'thread' }}") + exec_lua("vim.validate{arg1={nil, 'thread', true }}") + exec_lua("vim.validate{arg1={{}, 't' }, arg2={ 'foo', 's' }}") + exec_lua("vim.validate{arg1={2, function(a) return (a % 2) == 0 end, 'even number' }}") + + eq("Error executing lua: .../shared.lua: 1: expected table, got number", + pcall_err(exec_lua, "vim.validate{ 1, 'x' }")) + eq("Error executing lua: .../shared.lua: invalid type name: x", + pcall_err(exec_lua, "vim.validate{ arg1={ 1, 'x' }}")) + eq("Error executing lua: .../shared.lua: invalid type name: 1", + pcall_err(exec_lua, "vim.validate{ arg1={ 1, 1 }}")) + eq("Error executing lua: .../shared.lua: invalid type name: nil", + pcall_err(exec_lua, "vim.validate{ arg1={ 1 }}")) + + eq("Error executing lua: .../shared.lua: arg1: expected table, got number", + pcall_err(exec_lua, "vim.validate{arg1={1, 't'}}")) + eq("Error executing lua: .../shared.lua: arg2: expected string, got number", + pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={1, 's'}}")) + eq("Error executing lua: .../shared.lua: arg2: expected string, got nil", + pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}")) + eq("Error executing lua: .../shared.lua: arg2: expected string, got nil", + pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}")) + eq("Error executing lua: .../shared.lua: arg1: expected even number, got 3", + pcall_err(exec_lua, "vim.validate{arg1={3, function(a) return a == 1 end, 'even number'}}")) end) it('vim.is_callable', function() -- cgit From a0d992785feeefaea2810dcf08564fd8bea8cab9 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 10 Nov 2019 22:18:59 -0800 Subject: Lua: Use vim.validate() instead of assert() --- test/functional/lua/vim_spec.lua | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'test') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index a9c52bfcd9..a25ae1d2c0 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -230,12 +230,12 @@ describe('lua stdlib', function() end -- Validates args. - eq(true, pcall(split, 'string', 'string', nil)) - eq('Error executing lua: .../shared.lua: Expected string, got number', - pcall_err(split, 1, 'string', nil)) - eq('Error executing lua: .../shared.lua: Expected string, got number', - pcall_err(split, 'string', 1, nil)) - eq('Error executing lua: .../shared.lua: Expected boolean or nil, got number', + eq(true, pcall(split, 'string', 'string')) + eq('Error executing lua: .../shared.lua: s: expected string, got number', + pcall_err(split, 1, 'string')) + eq('Error executing lua: .../shared.lua: sep: expected string, got number', + pcall_err(split, 'string', 1)) + eq('Error executing lua: .../shared.lua: plain: expected boolean, got number', pcall_err(split, 'string', 'string', 1)) end) @@ -256,7 +256,7 @@ describe('lua stdlib', function() end -- Validates args. - eq('Error executing lua: .../shared.lua: Expected string, got number', + eq('Error executing lua: .../shared.lua: s: expected string, got number', pcall_err(trim, 2)) end) @@ -301,7 +301,7 @@ describe('lua stdlib', function() eq('foo%%%-bar', exec_lua([[return vim.pesc(vim.pesc('foo-bar'))]])) -- Validates args. - eq("Error executing lua: .../shared.lua: Expected string, got number", + eq('Error executing lua: .../shared.lua: s: expected string, got number', pcall_err(exec_lua, [[return vim.pesc(2)]])) end) @@ -441,16 +441,25 @@ describe('lua stdlib', function() eq("Error executing lua: .../shared.lua: invalid type name: nil", pcall_err(exec_lua, "vim.validate{ arg1={ 1 }}")) + -- Validated parameters are required by default. + eq("Error executing lua: .../shared.lua: arg1: expected string, got nil", + pcall_err(exec_lua, "vim.validate{ arg1={ nil, 's' }}")) + -- Explicitly required. + eq("Error executing lua: .../shared.lua: arg1: expected string, got nil", + pcall_err(exec_lua, "vim.validate{ arg1={ nil, 's', false }}")) + eq("Error executing lua: .../shared.lua: arg1: expected table, got number", pcall_err(exec_lua, "vim.validate{arg1={1, 't'}}")) eq("Error executing lua: .../shared.lua: arg2: expected string, got number", - pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={1, 's'}}")) + pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={1, 's'}}")) eq("Error executing lua: .../shared.lua: arg2: expected string, got nil", - pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}")) + pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}")) eq("Error executing lua: .../shared.lua: arg2: expected string, got nil", pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}")) eq("Error executing lua: .../shared.lua: arg1: expected even number, got 3", pcall_err(exec_lua, "vim.validate{arg1={3, function(a) return a == 1 end, 'even number'}}")) + eq("Error executing lua: .../shared.lua: arg1: expected ?, got 3", + pcall_err(exec_lua, "vim.validate{arg1={3, function(a) return a == 1 end}}")) end) it('vim.is_callable', function() -- cgit From a9065a50518ef59351f9d0d32041a991a751653f Mon Sep 17 00:00:00 2001 From: timeyyy Date: Wed, 18 Jan 2017 13:20:07 +0100 Subject: nsmarks: initial commit --- test/functional/api/mark_extended_spec.lua | 1365 ++++++++++++++++++++ .../legacy/046_multi_line_regexps_spec.lua | 30 +- test/functional/ui/inccommand_spec.lua | 16 +- test/functional/ui/mouse_spec.lua | 1 - 4 files changed, 1388 insertions(+), 24 deletions(-) create mode 100644 test/functional/api/mark_extended_spec.lua (limited to 'test') diff --git a/test/functional/api/mark_extended_spec.lua b/test/functional/api/mark_extended_spec.lua new file mode 100644 index 0000000000..6bf0e59133 --- /dev/null +++ b/test/functional/api/mark_extended_spec.lua @@ -0,0 +1,1365 @@ +-- TODO(timeyyy): go through todo's lol +-- change representation of stored marks to have location start at 0 +-- check with memsan, asan etc + +local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') + +local request = helpers.request +local eq = helpers.eq +local ok = helpers.ok +local curbufmeths = helpers.curbufmeths +local meth_pcall = helpers.meth_pcall +local insert = helpers.insert +local feed = helpers.feed +local clear = helpers.clear + +local ALL = -1 + +local rv = nil + +local function check_undo_redo(ns, mark, sr, sc, er, ec) --s = start, e = end + rv = curbufmeths.get_extmark_by_id(ns, mark) + eq({er, ec}, rv) + feed("u") + rv = curbufmeths.get_extmark_by_id(ns, mark) + eq({sr, sc}, rv) + feed("") + rv = curbufmeths.get_extmark_by_id(ns, mark) + eq({er, ec}, rv) +end + +describe('Extmarks buffer api', function() + local screen + local marks, positions, ns_string2, ns_string, init_text, row, col + local ns, ns2 + + before_each(function() + -- Initialize some namespaces and insert 12345 into a buffer + marks = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} + positions = {{0, 0,}, {0, 2}, {0, 3}} + + ns_string = "my-fancy-plugin" + ns_string2 = "my-fancy-plugin2" + init_text = "12345" + row = 0 + col = 2 + + clear() + screen = Screen.new(15, 10) + screen:attach() + + insert(init_text) + ns = request('nvim_create_namespace', ns_string) + ns2 = request('nvim_create_namespace', ns_string2) + end) + + it('adds, updates and deletes marks #extmarks', function() + rv = curbufmeths.set_extmark(ns, marks[1], positions[1][1], positions[1][2]) + eq(marks[1], rv) + rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + eq({positions[1][1], positions[1][2]}, rv) + -- Test adding a second mark on same row works + rv = curbufmeths.set_extmark(ns, marks[2], positions[2][1], positions[2][2]) + eq(marks[2], rv) + + -- Test an update, (same pos) + rv = curbufmeths.set_extmark(ns, marks[1], positions[1][1], positions[1][2]) + eq(0, rv) + rv = curbufmeths.get_extmark_by_id(ns, marks[2]) + eq({positions[2][1], positions[2][2]}, rv) + -- Test an update, (new pos) + row = positions[1][1] + col = positions[1][2] + 1 + rv = curbufmeths.set_extmark(ns, marks[1], row, col) + eq(0, rv) + rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + eq({row, col}, rv) + + -- remove the test marks + eq(true, curbufmeths.del_extmark(ns, marks[1])) + eq(false, curbufmeths.del_extmark(ns, marks[1])) + eq(true, curbufmeths.del_extmark(ns, marks[2])) + eq(false, curbufmeths.del_extmark(ns, marks[3])) + eq(false, curbufmeths.del_extmark(ns, 1000)) + end) + + it('can clear a specific namespace range #extmarks', function() + curbufmeths.set_extmark(ns, 1, 0, 1) + curbufmeths.set_extmark(ns2, 1, 0, 1) + -- force a new undo buffer + feed('o') + curbufmeths.clear_namespace(ns2, 0, -1) + eq({{1, 0, 1}}, curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL)) + eq({}, curbufmeths.get_extmarks(ns2, {0, 0}, {-1, -1}, ALL)) + feed('u') + eq({{1, 0, 1}}, curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL)) + eq({{1, 0, 1}}, curbufmeths.get_extmarks(ns2, {0, 0}, {-1, -1}, ALL)) + feed('') + eq({{1, 0, 1}}, curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL)) + eq({}, curbufmeths.get_extmarks(ns2, {0, 0}, {-1, -1}, ALL)) + end) + + it('can clear a namespace range using ALL #extmarks', function() + curbufmeths.set_extmark(ns, 1, 0, 1) + curbufmeths.set_extmark(ns2, 1, 0, 1) + -- force a new undo buffer + feed('o') + curbufmeths.clear_namespace(-1, 0, -1) + eq({}, curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL)) + eq({}, curbufmeths.get_extmarks(ns2, {0, 0}, {-1, -1}, ALL)) + feed('u') + eq({{1, 0, 1}}, curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL)) + eq({{1, 0, 1}}, curbufmeths.get_extmarks(ns2, {0, 0}, {-1, -1}, ALL)) + feed('') + eq({}, curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL)) + eq({}, curbufmeths.get_extmarks(ns2, {0, 0}, {-1, -1}, ALL)) + end) + + it('querying for information and ranges #extmarks', function() + -- add some more marks + for i, m in ipairs(marks) do + if positions[i] ~= nil then + rv = curbufmeths.set_extmark(ns, m, positions[i][1], positions[i][2]) + eq(m, rv) + end + end + + -- {0, 0} and {-1, -1} work as extreme values + eq({{1, 0, 0}}, curbufmeths.get_extmarks(ns, {0, 0}, {0, 0}, ALL)) + eq({}, curbufmeths.get_extmarks(ns, {-1, -1}, {-1, -1}, ALL)) + rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL) + for i, m in ipairs(marks) do + if positions[i] ~= nil then + eq({m, positions[i][1], positions[i][2]}, rv[i]) + end + end + + -- 0 and -1 works as short hand extreme values + eq({{1, 0, 0}}, curbufmeths.get_extmarks(ns, 0, 0, ALL)) + eq({}, curbufmeths.get_extmarks(ns, -1, -1, ALL)) + rv = curbufmeths.get_extmarks(ns, 0, -1, ALL) + for i, m in ipairs(marks) do + if positions[i] ~= nil then + eq({m, positions[i][1], positions[i][2]}, rv[i]) + end + end + + -- next with mark id + rv = curbufmeths.get_extmarks(ns, marks[1], {-1, -1}, 1) + eq({{marks[1], positions[1][1], positions[1][2]}}, rv) + rv = curbufmeths.get_extmarks(ns, marks[2], {-1, -1}, 1) + eq({{marks[2], positions[2][1], positions[2][2]}}, rv) + -- next with positional when mark exists at position + rv = curbufmeths.get_extmarks(ns, positions[1], {-1, -1}, 1) + eq({{marks[1], positions[1][1], positions[1][2]}}, rv) + -- next with positional index (no mark at position) + rv = curbufmeths.get_extmarks(ns, {positions[1][1], positions[1][2] +1}, {-1, -1}, 1) + eq({{marks[2], positions[2][1], positions[2][2]}}, rv) + -- next with Extremity index + rv = curbufmeths.get_extmarks(ns, {0,0}, {-1, -1}, 1) + eq({{marks[1], positions[1][1], positions[1][2]}}, rv) + + -- nextrange with mark id + rv = curbufmeths.get_extmarks(ns, marks[1], marks[3], ALL) + eq({marks[1], positions[1][1], positions[1][2]}, rv[1]) + eq({marks[2], positions[2][1], positions[2][2]}, rv[2]) + -- nextrange with amount + rv = curbufmeths.get_extmarks(ns, marks[1], marks[3], 2) + eq(2, table.getn(rv)) + -- nextrange with positional when mark exists at position + rv = curbufmeths.get_extmarks(ns, positions[1], positions[3], ALL) + eq({marks[1], positions[1][1], positions[1][2]}, rv[1]) + eq({marks[2], positions[2][1], positions[2][2]}, rv[2]) + rv = curbufmeths.get_extmarks(ns, positions[2], positions[3], ALL) + eq(2, table.getn(rv)) + -- nextrange with positional index (no mark at position) + local lower = {positions[1][1], positions[2][2] -1} + local upper = {positions[2][1], positions[3][2] - 1} + rv = curbufmeths.get_extmarks(ns, lower, upper, ALL) + eq({{marks[2], positions[2][1], positions[2][2]}}, rv) + lower = {positions[3][1], positions[3][2] + 1} + upper = {positions[3][1], positions[3][2] + 2} + rv = curbufmeths.get_extmarks(ns, lower, upper, ALL) + eq({}, rv) + -- nextrange with extremity index + lower = {positions[2][1], positions[2][2]+1} + upper = {-1, -1} + rv = curbufmeths.get_extmarks(ns, lower, upper, ALL) + eq({{marks[3], positions[3][1], positions[3][2]}}, rv) + + -- prev with mark id + rv = curbufmeths.get_extmarks(ns, marks[3], {0, 0}, 1) + eq({{marks[3], positions[3][1], positions[3][2]}}, rv) + rv = curbufmeths.get_extmarks(ns, marks[2], {0, 0}, 1) + eq({{marks[2], positions[2][1], positions[2][2]}}, rv) + -- prev with positional when mark exists at position + rv = curbufmeths.get_extmarks(ns, positions[3], {0, 0}, 1) + eq({{marks[3], positions[3][1], positions[3][2]}}, rv) + -- prev with positional index (no mark at position) + rv = curbufmeths.get_extmarks(ns, {positions[1][1], positions[1][2] +1}, {0, 0}, 1) + eq({{marks[1], positions[1][1], positions[1][2]}}, rv) + -- prev with Extremity index + rv = curbufmeths.get_extmarks(ns, {-1,-1}, {0,0}, 1) + eq({{marks[3], positions[3][1], positions[3][2]}}, rv) + + -- prevrange with mark id + rv = curbufmeths.get_extmarks(ns, marks[3], marks[1], ALL) + eq({marks[3], positions[3][1], positions[3][2]}, rv[1]) + eq({marks[2], positions[2][1], positions[2][2]}, rv[2]) + eq({marks[1], positions[1][1], positions[1][2]}, rv[3]) + -- prevrange with amount + rv = curbufmeths.get_extmarks(ns, marks[3], marks[1], 2) + eq(2, table.getn(rv)) + -- prevrange with positional when mark exists at position + rv = curbufmeths.get_extmarks(ns, positions[3], positions[1], ALL) + eq({{marks[3], positions[3][1], positions[3][2]}, + {marks[2], positions[2][1], positions[2][2]}, + {marks[1], positions[1][1], positions[1][2]}}, rv) + rv = curbufmeths.get_extmarks(ns, positions[2], positions[1], ALL) + eq(2, table.getn(rv)) + -- prevrange with positional index (no mark at position) + lower = {positions[2][1], positions[2][2] + 1} + upper = {positions[3][1], positions[3][2] + 1} + rv = curbufmeths.get_extmarks(ns, upper, lower, ALL) + eq({{marks[3], positions[3][1], positions[3][2]}}, rv) + lower = {positions[3][1], positions[3][2] + 1} + upper = {positions[3][1], positions[3][2] + 2} + rv = curbufmeths.get_extmarks(ns, upper, lower, ALL) + eq({}, rv) + -- prevrange with extremity index + lower = {0,0} + upper = {positions[2][1], positions[2][2] - 1} + rv = curbufmeths.get_extmarks(ns, upper, lower, ALL) + eq({{marks[1], positions[1][1], positions[1][2]}}, rv) + end) + + it('querying for information with amount #extmarks', function() + -- add some more marks + for i, m in ipairs(marks) do + if positions[i] ~= nil then + rv = curbufmeths.set_extmark(ns, m, positions[i][1], positions[i][2]) + eq(m, rv) + end + end + + rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, 1) + eq(1, table.getn(rv)) + rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, 2) + eq(2, table.getn(rv)) + rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, 3) + eq(3, table.getn(rv)) + + -- now in reverse + rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, 1) + eq(1, table.getn(rv)) + rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, 2) + eq(2, table.getn(rv)) + rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, 3) + eq(3, table.getn(rv)) + end) + + it('get_marks works when mark col > upper col #extmarks', function() + feed('A12345') + feed('A12345') + curbufmeths.set_extmark(ns, 10, 0, 2) -- this shouldn't be found + curbufmeths.set_extmark(ns, 11, 2, 1) -- this shouldn't be found + curbufmeths.set_extmark(ns, marks[1], 0, 4) -- check col > our upper bound + curbufmeths.set_extmark(ns, marks[2], 1, 1) -- check col < lower bound + curbufmeths.set_extmark(ns, marks[3], 2, 0) -- check is inclusive + eq({{marks[1], 0, 4}, + {marks[2], 1, 1}, + {marks[3], 2, 0}}, + curbufmeths.get_extmarks(ns, {0, 3}, {2, 0}, -1)) + end) + + it('get_marks works in reverse when mark col < lower col #extmarks', function() + feed('A12345') + feed('A12345') + curbufmeths.set_extmark(ns, 10, 0, 1) -- this shouldn't be found + curbufmeths.set_extmark(ns, 11, 2, 4) -- this shouldn't be found + curbufmeths.set_extmark(ns, marks[1], 2, 1) -- check col < our lower bound + curbufmeths.set_extmark(ns, marks[2], 1, 4) -- check col > upper bound + curbufmeths.set_extmark(ns, marks[3], 0, 2) -- check is inclusive + rv = curbufmeths.get_extmarks(ns, {2, 3}, {0, 2}, -1) + eq({{marks[1], 2, 1}, + {marks[2], 1, 4}, + {marks[3], 0, 2}}, + rv) + end) + + it('get_marks amount 0 returns nothing #extmarks', function() + curbufmeths.set_extmark(ns, marks[1], positions[1][1], positions[1][2]) + rv = curbufmeths.get_extmarks(ns, {-1, -1}, {-1, -1}, 0) + eq({}, rv) + end) + + + it('marks move with line insertations #extmarks', function() + curbufmeths.set_extmark(ns, marks[1], 0, 0) + feed("yyP") + check_undo_redo(ns, marks[1], 0, 0, 1, 0) + end) + + it('marks move with multiline insertations #extmarks', function() + feed("a2233") + curbufmeths.set_extmark(ns, marks[1], 1, 1) + feed('ggVGyP') + check_undo_redo(ns, marks[1], 1, 1, 4, 1) + end) + + it('marks move with line join #extmarks', function() + -- do_join in ops.c + feed("a222") + curbufmeths.set_extmark(ns, marks[1], 1, 0) + feed('ggJ') + check_undo_redo(ns, marks[1], 1, 0, 0, 6) + end) + + it('join works when no marks are present #extmarks', function() + feed("a1") + feed('kJ') + -- This shouldn't seg fault + screen:expect([[ + 12345^ 1 | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + | + ]]) + end) + + it('marks move with multiline join #extmarks', function() + -- do_join in ops.c + feed("a222333444") + curbufmeths.set_extmark(ns, marks[1], 3, 0) + feed('2GVGJ') + check_undo_redo(ns, marks[1], 3, 0, 1, 8) + end) + + it('marks move with line deletes #extmarks', function() + feed("a222333444") + curbufmeths.set_extmark(ns, marks[1], 2, 1) + feed('ggjdd') + check_undo_redo(ns, marks[1], 2, 1, 1, 1) + end) + + it('marks move with multiline deletes #extmarks', function() + feed("a222333444") + curbufmeths.set_extmark(ns, marks[1], 3, 0) + feed('gg2dd') + check_undo_redo(ns, marks[1], 3, 0, 1, 0) + -- regression test, undoing multiline delete when mark is on row 1 + feed('ugg3dd') + check_undo_redo(ns, marks[1], 3, 0, 0, 0) + end) + + it('marks move with open line #extmarks', function() + -- open_line in misc1.c + -- testing marks below are also moved + feed("yyP") + curbufmeths.set_extmark(ns, marks[1], 0, 4) + curbufmeths.set_extmark(ns, marks[2], 1, 4) + feed('1G') + check_undo_redo(ns, marks[1], 0, 4, 1, 4) + check_undo_redo(ns, marks[2], 1, 4, 2, 4) + feed('2Go') + check_undo_redo(ns, marks[1], 1, 4, 1, 4) + check_undo_redo(ns, marks[2], 2, 4, 3, 4) + end) + + -- NO idea why this doesn't work... works in program. + pending('marks move with char inserts #extmarks', function() + -- insertchar in edit.c (the ins_str branch) + curbufmeths.set_extmark(ns, marks[1], 1, 3) + feed('0') + insert('abc') + screen:expect([[ + ab^c12345 | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + | + ]]) + rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + eq(1, rv[2]) + eq(6, rv[3]) + -- check_undo_redo(ns, marks[1], 0, 2, 0, 5) + end) + + -- gravity right as definted in tk library + it('marks have gravity right #extmarks', function() + -- insertchar in edit.c (the ins_str branch) + curbufmeths.set_extmark(ns, marks[1], 0, 2) + feed('03l') + insert("X") + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + + -- check multibyte chars + feed('03l') + insert("~~") + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + end) + + it('we can insert multibyte chars #extmarks', function() + -- insertchar in edit.c + feed('a12345') + curbufmeths.set_extmark(ns, marks[1], 1, 2) + -- Insert a fullwidth (two col) tilde, NICE + feed('0i~') + check_undo_redo(ns, marks[1], 1, 2, 1, 3) + end) + + it('marks move with blockwise inserts #extmarks', function() + -- op_insert in ops.c + feed('a12345') + curbufmeths.set_extmark(ns, marks[1], 1, 2) + feed('0lkI9') + check_undo_redo(ns, marks[1], 1, 2, 1, 3) + end) + + it('marks move with line splits (using enter) #extmarks', function() + -- open_line in misc1.c + -- testing marks below are also moved + feed("yyP") + curbufmeths.set_extmark(ns, marks[1], 0, 4) + curbufmeths.set_extmark(ns, marks[2], 1, 4) + feed('1Gla') + check_undo_redo(ns, marks[1], 0, 4, 1, 2) + check_undo_redo(ns, marks[2], 1, 4, 2, 4) + end) + + -- TODO mark_col_adjust for normal marks fails in vim/neovim + -- because flags is 9 in: if (flags & OPENLINE_MARKFIX) { + it('marks at last line move on insert new line #extmarks', function() + -- open_line in misc1.c + curbufmeths.set_extmark(ns, marks[1], 0, 4) + feed('0i') + check_undo_redo(ns, marks[1], 0, 4, 1, 4) + end) + + it('yet again marks move with line splits #extmarks', function() + -- the first test above wasn't catching all errors.. + feed("A67890") + curbufmeths.set_extmark(ns, marks[1], 0, 4) + feed("04li") + check_undo_redo(ns, marks[1], 0, 4, 1, 0) + end) + + it('and one last time line splits... #extmarks', function() + curbufmeths.set_extmark(ns, marks[1], 0, 1) + curbufmeths.set_extmark(ns, marks[2], 0, 2) + feed("02li") + check_undo_redo(ns, marks[1], 0, 1, 0, 1) + check_undo_redo(ns, marks[2], 0, 2, 1, 0) + end) + + it('multiple marks move with mark splits #extmarks', function() + curbufmeths.set_extmark(ns, marks[1], 0, 1) + curbufmeths.set_extmark(ns, marks[2], 0, 3) + feed("0li") + check_undo_redo(ns, marks[1], 0, 1, 1, 0) + check_undo_redo(ns, marks[2], 0, 3, 1, 2) + end) + + it('deleting on a mark works #extmarks', function() + -- op_delete in ops.c + curbufmeths.set_extmark(ns, marks[1], 0, 2) + feed('02lx') + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + end) + + it('marks move with char deletes #extmarks', function() + -- op_delete in ops.c + curbufmeths.set_extmark(ns, marks[1], 0, 2) + feed('02dl') + check_undo_redo(ns, marks[1], 0, 2, 0, 0) + -- from the other side (nothing should happen) + feed('$x') + check_undo_redo(ns, marks[1], 0, 0, 0, 0) + end) + + it('marks move with char deletes over a range #extmarks', function() + -- op_delete in ops.c + curbufmeths.set_extmark(ns, marks[1], 0, 2) + curbufmeths.set_extmark(ns, marks[2], 0, 3) + feed('0l3dl') + check_undo_redo(ns, marks[1], 0, 2, 0, 1) + check_undo_redo(ns, marks[2], 0, 3, 0, 1) + -- delete 1, nothing should happend to our marks + feed('u') + feed('$x') + -- TODO do we need to test marks[1] ??? + check_undo_redo(ns, marks[2], 0, 3, 0, 3) + end) + + it('deleting marks at end of line works #extmarks', function() + -- mark_extended.c/extmark_col_adjust_delete + curbufmeths.set_extmark(ns, marks[1], 0, 4) + feed('$x') + check_undo_redo(ns, marks[1], 0, 4, 0, 4) + -- check the copy happened correctly on delete at eol + feed('$x') + check_undo_redo(ns, marks[1], 0, 4, 0, 3) + feed('u') + check_undo_redo(ns, marks[1], 0, 4, 0, 4) + end) + + it('marks move with blockwise deletes #extmarks', function() + -- op_delete in ops.c + feed('a12345') + curbufmeths.set_extmark(ns, marks[1], 1, 4) + feed('hhhkd') + check_undo_redo(ns, marks[1], 1, 4, 1, 1) + end) + + it('marks move with blockwise deletes over a range #extmarks', function() + -- op_delete in ops.c + feed('a12345') + curbufmeths.set_extmark(ns, marks[1], 0, 1) + curbufmeths.set_extmark(ns, marks[2], 0, 3) + curbufmeths.set_extmark(ns, marks[3], 1, 2) + feed('0k3lx') + check_undo_redo(ns, marks[1], 0, 1, 0, 0) + check_undo_redo(ns, marks[2], 0, 3, 0, 0) + check_undo_redo(ns, marks[3], 1, 2, 1, 0) + -- delete 1, nothing should happend to our marks + feed('u') + feed('$jx') + -- TODO do we need to test marks[1] ??? + check_undo_redo(ns, marks[2], 0, 3, 0, 3) + check_undo_redo(ns, marks[3], 1, 2, 1, 2) + end) + + it('works with char deletes over multilines #extmarks', function() + feed('a12345test-me') + curbufmeths.set_extmark(ns, marks[1], 2, 5) + feed('gg') + feed('dv?-m?') + check_undo_redo(ns, marks[1], 2, 5, 0, 0) + end) + + it('marks outside of deleted range move with visual char deletes #extmarks', function() + -- op_delete in ops.c + curbufmeths.set_extmark(ns, marks[1], 0, 3) + feed('0vx') + check_undo_redo(ns, marks[1], 0, 3, 0, 2) + + feed("u") + feed('0vlx') + check_undo_redo(ns, marks[1], 0, 3, 0, 1) + + feed("u") + feed('0v2lx') + check_undo_redo(ns, marks[1], 0, 3, 0, 0) + + -- from the other side (nothing should happen) + feed('$vx') + check_undo_redo(ns, marks[1], 0, 0, 0, 0) + end) + + it('marks outside of deleted range move with char deletes #extmarks', function() + -- op_delete in ops.c + curbufmeths.set_extmark(ns, marks[1], 0, 3) + feed('0x') + check_undo_redo(ns, marks[1], 0, 3, 0, 2) + + feed("u") + feed('02x') + check_undo_redo(ns, marks[1], 0, 3, 0, 1) + + feed("u") + feed('0v3lx') + check_undo_redo(ns, marks[1], 0, 3, 0, 0) + + -- from the other side (nothing should happen) + feed("u") + feed('$vx') + check_undo_redo(ns, marks[1], 0, 3, 0, 3) + end) + + it('marks move with P(backward) paste #extmarks', function() + -- do_put in ops.c + feed('0iabc') + curbufmeths.set_extmark(ns, marks[1], 0, 7) + feed('0veyP') + check_undo_redo(ns, marks[1], 0, 7, 0, 15) + end) + + it('marks move with p(forward) paste #extmarks', function() + -- do_put in ops.c + feed('0iabc') + curbufmeths.set_extmark(ns, marks[1], 0, 7) + feed('0veyp') + check_undo_redo(ns, marks[1], 0, 7, 0, 14) + end) + + it('marks move with blockwise P(backward) paste #extmarks', function() + -- do_put in ops.c + feed('a12345') + curbufmeths.set_extmark(ns, marks[1], 1, 4) + feed('hhkyP') + check_undo_redo(ns, marks[1], 1, 4, 1, 7) + end) + + it('marks move with blockwise p(forward) paste #extmarks', function() + -- do_put in ops.c + feed('a12345') + curbufmeths.set_extmark(ns, marks[1], 1, 4) + feed('hhkyp') + check_undo_redo(ns, marks[1], 1, 4, 1, 6) + end) + + it('replace works #extmarks', function() + curbufmeths.set_extmark(ns, marks[1], 0, 2) + feed('0r2') + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + end) + + it('blockwise replace works #extmarks', function() + feed('a12345') + curbufmeths.set_extmark(ns, marks[1], 0, 2) + feed('0llkr1') + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + end) + + it('shift line #extmarks', function() + -- shift_line in ops.c + feed(':set shiftwidth=4') + curbufmeths.set_extmark(ns, marks[1], 0, 2) + feed('0>>') + check_undo_redo(ns, marks[1], 0, 2, 0, 6) + + feed('>>') + check_undo_redo(ns, marks[1], 0, 6, 0, 10) + + feed('') -- have to escape, same as << + check_undo_redo(ns, marks[1], 0, 10, 0, 6) + end) + + it('blockwise shift #extmarks', function() + -- shift_block in ops.c + feed(':set shiftwidth=4') + feed('a12345') + curbufmeths.set_extmark(ns, marks[1], 1, 2) + feed('0k>') + check_undo_redo(ns, marks[1], 1, 2, 1, 6) + feed('j>') + check_undo_redo(ns, marks[1], 1, 6, 1, 10) + + feed('j') + check_undo_redo(ns, marks[1], 1, 10, 1, 6) + end) + + it('tab works with expandtab #extmarks', function() + -- ins_tab in edit.c + feed(':set expandtab') + feed(':set shiftwidth=2') + curbufmeths.set_extmark(ns, marks[1], 0, 2) + feed('0i') + check_undo_redo(ns, marks[1], 0, 2, 0, 6) + end) + + it('tabs work #extmarks', function() + -- ins_tab in edit.c + feed(':set noexpandtab') + feed(':set shiftwidth=2') + feed(':set softtabstop=2') + feed(':set tabstop=8') + curbufmeths.set_extmark(ns, marks[1], 0, 2) + feed('0i') + check_undo_redo(ns, marks[1], 0, 2, 0, 4) + feed('0iX') + check_undo_redo(ns, marks[1], 0, 4, 0, 6) + end) + + it('marks move when using :move #extmarks', function() + curbufmeths.set_extmark(ns, marks[1], 0, 0) + feed('A2:1move 2') + check_undo_redo(ns, marks[1], 0, 0, 1, 0) + -- test codepath when moving lines up + feed(':2move 0') + check_undo_redo(ns, marks[1], 1, 0, 0, 0) + end) + + it('marks move when using :move part 2 #extmarks', function() + -- make sure we didn't get lucky with the math... + feed('A23456') + curbufmeths.set_extmark(ns, marks[1], 1, 0) + feed(':2,3move 5') + check_undo_redo(ns, marks[1], 1, 0, 3, 0) + -- test codepath when moving lines up + feed(':4,5move 1') + check_undo_redo(ns, marks[1], 3, 0, 1, 0) + end) + + it('undo and redo of set and unset marks #extmarks', function() + -- Force a new undo head + feed('o') + curbufmeths.set_extmark(ns, marks[1], 0, 1) + feed('o') + curbufmeths.set_extmark(ns, marks[2], 0, -1) + curbufmeths.set_extmark(ns, marks[3], 0, -1) + + feed("u") + rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL) + eq(1, table.getn(rv)) + + feed("") + rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL) + eq(3, table.getn(rv)) + + -- Test updates + feed('o') + curbufmeths.set_extmark(ns, marks[1], positions[1][1], positions[1][2]) + rv = curbufmeths.get_extmarks(ns, marks[1], marks[1], 1) + feed("u") + feed("") + check_undo_redo(ns, marks[1], 0, 1, positions[1][1], positions[1][2]) + + -- Test unset + feed('o') + curbufmeths.del_extmark(ns, marks[3]) + feed("u") + rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL) + eq(3, table.getn(rv)) + feed("") + rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL) + eq(2, table.getn(rv)) + end) + + it('undo and redo of marks deleted during edits #extmarks', function() + -- test extmark_adjust + feed('A12345') + curbufmeths.set_extmark(ns, marks[1], 1, 2) + feed('dd') + check_undo_redo(ns, marks[1], 1, 2, 1, 0) + end) + + it('namespaces work properly #extmarks', function() + rv = curbufmeths.set_extmark(ns, marks[1], positions[1][1], positions[1][2]) + eq(1, rv) + rv = curbufmeths.set_extmark(ns2, marks[1], positions[1][1], positions[1][2]) + eq(1, rv) + rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL) + eq(1, table.getn(rv)) + rv = curbufmeths.get_extmarks(ns2, {0, 0}, {-1, -1}, ALL) + eq(1, table.getn(rv)) + + -- Set more marks for testing the ranges + rv = curbufmeths.set_extmark(ns, marks[2], positions[2][1], positions[2][2]) + rv = curbufmeths.set_extmark(ns, marks[3], positions[3][1], positions[3][2]) + rv = curbufmeths.set_extmark(ns2, marks[2], positions[2][1], positions[2][2]) + rv = curbufmeths.set_extmark(ns2, marks[3], positions[3][1], positions[3][2]) + + -- get_next (amount set) + rv = curbufmeths.get_extmarks(ns, {0, 0}, positions[2], 1) + eq(1, table.getn(rv)) + rv = curbufmeths.get_extmarks(ns2, {0, 0}, positions[2], 1) + eq(1, table.getn(rv)) + -- get_prev (amount set) + rv = curbufmeths.get_extmarks(ns, positions[1], {0, 0}, 1) + eq(1, table.getn(rv)) + rv = curbufmeths.get_extmarks(ns2, positions[1], {0, 0}, 1) + eq(1, table.getn(rv)) + + -- get_next (amount not set) + rv = curbufmeths.get_extmarks(ns, positions[1], positions[2], ALL) + eq(2, table.getn(rv)) + rv = curbufmeths.get_extmarks(ns2, positions[1], positions[2], ALL) + eq(2, table.getn(rv)) + -- get_prev (amount not set) + rv = curbufmeths.get_extmarks(ns, positions[2], positions[1], ALL) + eq(2, table.getn(rv)) + rv = curbufmeths.get_extmarks(ns2, positions[2], positions[1], ALL) + eq(2, table.getn(rv)) + + curbufmeths.del_extmark(ns, marks[1]) + rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL) + eq(2, table.getn(rv)) + curbufmeths.del_extmark(ns2, marks[1]) + rv = curbufmeths.get_extmarks(ns2, {0, 0}, {-1, -1}, ALL) + eq(2, table.getn(rv)) + end) + + it('mark set can create unique identifiers #extmarks', function() + -- create mark with id 1 + eq(1, curbufmeths.set_extmark(ns, 1, positions[1][1], positions[1][2])) + -- ask for unique id, it should be the next one, i e 2 + eq(2, curbufmeths.set_extmark(ns, 0, positions[1][1], positions[1][2])) + eq(3, curbufmeths.set_extmark(ns, 3, positions[2][1], positions[2][2])) + eq(4, curbufmeths.set_extmark(ns, 0, positions[1][1], positions[1][2])) + + -- mixing manual and allocated id:s are not recommened, but it should + -- do something reasonable + eq(6, curbufmeths.set_extmark(ns, 6, positions[2][1], positions[2][2])) + eq(7, curbufmeths.set_extmark(ns, 0, positions[1][1], positions[1][2])) + eq(8, curbufmeths.set_extmark(ns, 0, positions[1][1], positions[1][2])) + end) + + it('auto indenting with enter works #extmarks', function() + -- op_reindent in ops.c + feed(':set cindent') + feed(':set autoindent') + feed(':set shiftwidth=2') + feed("0iint A {1M1b") + -- Set the mark on the M, should move.. + curbufmeths.set_extmark(ns, marks[1], 0, 12) + -- Set the mark before the cursor, should stay there + curbufmeths.set_extmark(ns, marks[2], 0, 10) + feed("i") + rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + eq({1, 3}, rv) + rv = curbufmeths.get_extmark_by_id(ns, marks[2]) + eq({0, 10}, rv) + check_undo_redo(ns, marks[1], 0, 12, 1, 3) + end) + + it('auto indenting entire line works #extmarks', function() + feed(':set cindent') + feed(':set autoindent') + feed(':set shiftwidth=2') + -- will force an indent of 2 + feed("0iint A {0i1M1") + curbufmeths.set_extmark(ns, marks[1], 1, 1) + feed("0i") + rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + eq({1, 3}, rv) + check_undo_redo(ns, marks[1], 1, 1, 1, 3) + -- now check when cursor at eol + feed("uA") + rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + eq({1, 3}, rv) + end) + + it('removing auto indenting with works #extmarks', function() + feed(':set cindent') + feed(':set autoindent') + feed(':set shiftwidth=2') + feed("0i") + curbufmeths.set_extmark(ns, marks[1], 0, 3) + feed("bi") + rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + eq({0, 1}, rv) + check_undo_redo(ns, marks[1], 0, 3, 0, 1) + -- check when cursor at eol + feed("uA") + rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + eq({0, 1}, rv) + end) + + it('indenting multiple lines with = works #extmarks', function() + feed(':set cindent') + feed(':set autoindent') + feed(':set shiftwidth=2') + feed("0iint A {1M12M2") + curbufmeths.set_extmark(ns, marks[1], 1, 1) + curbufmeths.set_extmark(ns, marks[2], 2, 1) + feed('=gg') + check_undo_redo(ns, marks[1], 1, 1, 1, 3) + check_undo_redo(ns, marks[2], 2, 1, 2, 5) + end) + + it('substitutes by deleting inside the replace matches #extmarks_sub', function() + -- do_sub in ex_cmds.c + curbufmeths.set_extmark(ns, marks[1], 0, 2) + curbufmeths.set_extmark(ns, marks[2], 0, 3) + feed(':s/34/xx') + check_undo_redo(ns, marks[1], 0, 2, 0, 4) + check_undo_redo(ns, marks[2], 0, 3, 0, 4) + end) + + it('substitutes when insert text > deleted #extmarks_sub', function() + -- do_sub in ex_cmds.c + curbufmeths.set_extmark(ns, marks[1], 0, 2) + curbufmeths.set_extmark(ns, marks[2], 0, 3) + feed(':s/34/xxx') + check_undo_redo(ns, marks[1], 0, 2, 0, 5) + check_undo_redo(ns, marks[2], 0, 3, 0, 5) + end) + + it('substitutes when marks around eol #extmarks_sub', function() + -- do_sub in ex_cmds.c + curbufmeths.set_extmark(ns, marks[1], 0, 4) + curbufmeths.set_extmark(ns, marks[2], 0, 5) + feed(':s/5/xxx') + check_undo_redo(ns, marks[1], 0, 4, 0, 7) + check_undo_redo(ns, marks[2], 0, 5, 0, 7) + end) + + it('substitutes over range insert text > deleted #extmarks_sub', function() + -- do_sub in ex_cmds.c + feed('Ax34xx') + feed('Axxx34') + curbufmeths.set_extmark(ns, marks[1], 0, 2) + curbufmeths.set_extmark(ns, marks[2], 1, 1) + curbufmeths.set_extmark(ns, marks[3], 2, 4) + feed(':1,3s/34/xxx') + check_undo_redo(ns, marks[1], 0, 2, 0, 5) + check_undo_redo(ns, marks[2], 1, 1, 1, 4) + check_undo_redo(ns, marks[3], 2, 4, 2, 6) + end) + + it('substitutes multiple matches in a line #extmarks_sub', function() + -- do_sub in ex_cmds.c + feed('ddi3x3x3') + curbufmeths.set_extmark(ns, marks[1], 0, 0) + curbufmeths.set_extmark(ns, marks[2], 0, 2) + curbufmeths.set_extmark(ns, marks[3], 0, 4) + feed(':s/3/yy/g') + check_undo_redo(ns, marks[1], 0, 0, 0, 2) + check_undo_redo(ns, marks[2], 0, 2, 0, 5) + check_undo_redo(ns, marks[3], 0, 4, 0, 8) + end) + + it('substitions over multiple lines with newline in pattern #extmarks_sub', function() + feed('A67890xx') + curbufmeths.set_extmark(ns, marks[1], 0, 3) + curbufmeths.set_extmark(ns, marks[2], 0, 4) + curbufmeths.set_extmark(ns, marks[3], 1, 0) + curbufmeths.set_extmark(ns, marks[4], 1, 5) + curbufmeths.set_extmark(ns, marks[5], 2, 0) + feed([[:1,2s:5\n:5 ]]) + check_undo_redo(ns, marks[1], 0, 3, 0, 3) + check_undo_redo(ns, marks[2], 0, 4, 0, 6) + check_undo_redo(ns, marks[3], 1, 0, 0, 6) + check_undo_redo(ns, marks[4], 1, 5, 0, 11) + check_undo_redo(ns, marks[5], 2, 0, 1, 0) + end) + + it('inserting #extmarks_sub', function() + feed('A67890xx') + curbufmeths.set_extmark(ns, marks[1], 0, 3) + curbufmeths.set_extmark(ns, marks[2], 0, 4) + curbufmeths.set_extmark(ns, marks[3], 1, 0) + curbufmeths.set_extmark(ns, marks[4], 1, 5) + curbufmeths.set_extmark(ns, marks[5], 2, 0) + curbufmeths.set_extmark(ns, marks[6], 1, 2) + feed([[:1,2s:5\n67:X]]) + check_undo_redo(ns, marks[1], 0, 3, 0, 3) + check_undo_redo(ns, marks[2], 0, 4, 0, 5) + check_undo_redo(ns, marks[3], 1, 0, 0, 5) + check_undo_redo(ns, marks[4], 1, 5, 0, 8) + check_undo_redo(ns, marks[5], 2, 0, 1, 0) + check_undo_redo(ns, marks[6], 1, 2, 0, 5) + end) + + it('substitions with multiple newlines in pattern #extmarks_sub', function() + feed('A67890xx') + curbufmeths.set_extmark(ns, marks[1], 0, 4) + curbufmeths.set_extmark(ns, marks[2], 0, 5) + curbufmeths.set_extmark(ns, marks[3], 1, 0) + curbufmeths.set_extmark(ns, marks[4], 1, 5) + curbufmeths.set_extmark(ns, marks[5], 2, 0) + feed([[:1,2s:\n.*\n:X]]) + check_undo_redo(ns, marks[1], 0, 4, 0, 4) + check_undo_redo(ns, marks[2], 0, 5, 0, 6) + check_undo_redo(ns, marks[3], 1, 0, 0, 6) + check_undo_redo(ns, marks[4], 1, 5, 0, 6) + check_undo_redo(ns, marks[5], 2, 0, 0, 6) + end) + + it('substitions over multiple lines with replace in substition #extmarks_sub', function() + feed('A67890xx') + curbufmeths.set_extmark(ns, marks[1], 0, 1) + curbufmeths.set_extmark(ns, marks[2], 0, 2) + curbufmeths.set_extmark(ns, marks[3], 0, 4) + curbufmeths.set_extmark(ns, marks[4], 1, 0) + curbufmeths.set_extmark(ns, marks[5], 2, 0) + feed([[:1,2s:3:\r]]) + check_undo_redo(ns, marks[1], 0, 1, 0, 1) + check_undo_redo(ns, marks[2], 0, 2, 1, 0) + check_undo_redo(ns, marks[3], 0, 4, 1, 1) + check_undo_redo(ns, marks[4], 1, 0, 2, 0) + check_undo_redo(ns, marks[5], 2, 0, 3, 0) + feed('u') + feed([[:1,2s:3:\rxx]]) + eq({1, 3}, curbufmeths.get_extmark_by_id(ns, marks[3])) + end) + + it('substitions over multiple lines with replace in substition #extmarks_sub', function() + feed('Ax3xx') + curbufmeths.set_extmark(ns, marks[1], 1, 0) + curbufmeths.set_extmark(ns, marks[2], 1, 1) + curbufmeths.set_extmark(ns, marks[3], 1, 2) + feed([[:2,2s:3:\r]]) + check_undo_redo(ns, marks[1], 1, 0, 1, 0) + check_undo_redo(ns, marks[2], 1, 1, 2, 0) + check_undo_redo(ns, marks[3], 1, 2, 2, 0) + end) + + it('substitions over multiple lines with replace in substition #extmarks_sub', function() + feed('Ax3xx') + curbufmeths.set_extmark(ns, marks[1], 0, 1) + curbufmeths.set_extmark(ns, marks[2], 0, 2) + curbufmeths.set_extmark(ns, marks[3], 0, 4) + curbufmeths.set_extmark(ns, marks[4], 1, 1) + curbufmeths.set_extmark(ns, marks[5], 2, 0) + feed([[:1,2s:3:\r]]) + check_undo_redo(ns, marks[1], 0, 1, 0, 1) + check_undo_redo(ns, marks[2], 0, 2, 1, 0) + check_undo_redo(ns, marks[3], 0, 4, 1, 1) + check_undo_redo(ns, marks[4], 1, 1, 3, 0) + check_undo_redo(ns, marks[5], 2, 0, 4, 0) + feed('u') + feed([[:1,2s:3:\rxx]]) + check_undo_redo(ns, marks[3], 0, 4, 1, 3) + end) + + it('substitions with newline in match and sub, delta is 0 #extmarks_sub', function() + feed('A67890xx') + curbufmeths.set_extmark(ns, marks[1], 0, 3) + curbufmeths.set_extmark(ns, marks[2], 0, 4) + curbufmeths.set_extmark(ns, marks[3], 0, 5) + curbufmeths.set_extmark(ns, marks[4], 1, 0) + curbufmeths.set_extmark(ns, marks[5], 1, 5) + curbufmeths.set_extmark(ns, marks[6], 2, 0) + feed([[:1,1s:5\n:\r]]) + check_undo_redo(ns, marks[1], 0, 3, 0, 3) + check_undo_redo(ns, marks[2], 0, 4, 1, 0) + check_undo_redo(ns, marks[3], 0, 5, 1, 0) + check_undo_redo(ns, marks[4], 1, 0, 1, 0) + check_undo_redo(ns, marks[5], 1, 5, 1, 5) + check_undo_redo(ns, marks[6], 2, 0, 2, 0) + end) + + it('substitions with newline in match and sub, delta > 0 #extmarks_sub', function() + feed('A67890xx') + curbufmeths.set_extmark(ns, marks[1], 0, 3) + curbufmeths.set_extmark(ns, marks[2], 0, 4) + curbufmeths.set_extmark(ns, marks[3], 0, 5) + curbufmeths.set_extmark(ns, marks[4], 1, 0) + curbufmeths.set_extmark(ns, marks[5], 1, 5) + curbufmeths.set_extmark(ns, marks[6], 2, 0) + feed([[:1,1s:5\n:\r\r]]) + check_undo_redo(ns, marks[1], 0, 3, 0, 3) + check_undo_redo(ns, marks[2], 0, 4, 2, 0) + check_undo_redo(ns, marks[3], 0, 5, 2, 0) + check_undo_redo(ns, marks[4], 1, 0, 2, 0) + check_undo_redo(ns, marks[5], 1, 5, 2, 5) + check_undo_redo(ns, marks[6], 2, 0, 3, 0) + end) + + it('substitions with newline in match and sub, delta < 0 #extmarks_sub', function() + feed('A67890xxxx') + curbufmeths.set_extmark(ns, marks[1], 0, 3) + curbufmeths.set_extmark(ns, marks[2], 0, 4) + curbufmeths.set_extmark(ns, marks[3], 0, 5) + curbufmeths.set_extmark(ns, marks[4], 1, 0) + curbufmeths.set_extmark(ns, marks[5], 1, 5) + curbufmeths.set_extmark(ns, marks[6], 2, 1) + curbufmeths.set_extmark(ns, marks[7], 3, 0) + feed([[:1,2s:5\n.*\n:\r]]) + check_undo_redo(ns, marks[1], 0, 3, 0, 3) + check_undo_redo(ns, marks[2], 0, 4, 1, 0) + check_undo_redo(ns, marks[3], 0, 5, 1, 0) + check_undo_redo(ns, marks[4], 1, 0, 1, 0) + check_undo_redo(ns, marks[5], 1, 5, 1, 0) + check_undo_redo(ns, marks[6], 2, 1, 1, 1) + check_undo_redo(ns, marks[7], 3, 0, 2, 0) + end) + + it('substitions with backrefs, newline inserted into sub #extmarks_sub', function() + feed('A67890xxxx') + curbufmeths.set_extmark(ns, marks[1], 0, 3) + curbufmeths.set_extmark(ns, marks[2], 0, 4) + curbufmeths.set_extmark(ns, marks[3], 0, 5) + curbufmeths.set_extmark(ns, marks[4], 1, 0) + curbufmeths.set_extmark(ns, marks[5], 1, 5) + curbufmeths.set_extmark(ns, marks[6], 2, 0) + feed([[:1,1s:5\(\n\):\0\1]]) + check_undo_redo(ns, marks[1], 0, 3, 0, 3) + check_undo_redo(ns, marks[2], 0, 4, 2, 0) + check_undo_redo(ns, marks[3], 0, 5, 2, 0) + check_undo_redo(ns, marks[4], 1, 0, 2, 0) + check_undo_redo(ns, marks[5], 1, 5, 2, 5) + check_undo_redo(ns, marks[6], 2, 0, 3, 0) + end) + + it('substitions a ^ #extmarks_sub', function() + curbufmeths.set_extmark(ns, marks[1], 0, 0) + curbufmeths.set_extmark(ns, marks[2], 0, 1) + feed([[:s:^:x]]) + check_undo_redo(ns, marks[1], 0, 0, 0, 1) + check_undo_redo(ns, marks[2], 0, 1, 0, 2) + end) + + it('using without increase in order of magnitude #extmarks_inc_dec', function() + -- do_addsub in ops.c + feed('ddiabc998xxxTc') + curbufmeths.set_extmark(ns, marks[1], 0, 2) + curbufmeths.set_extmark(ns, marks[2], 0, 3) + curbufmeths.set_extmark(ns, marks[3], 0, 5) + curbufmeths.set_extmark(ns, marks[4], 0, 6) + curbufmeths.set_extmark(ns, marks[5], 0, 7) + feed('') + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + check_undo_redo(ns, marks[2], 0, 3, 0, 6) + check_undo_redo(ns, marks[3], 0, 5, 0, 6) + check_undo_redo(ns, marks[4], 0, 6, 0, 6) + check_undo_redo(ns, marks[5], 0, 7, 0, 7) + end) + + it('using when increase in order of magnitude #extmarks_inc_dec', function() + -- do_addsub in ops.c + feed('ddiabc999xxxTc') + curbufmeths.set_extmark(ns, marks[1], 0, 2) + curbufmeths.set_extmark(ns, marks[2], 0, 3) + curbufmeths.set_extmark(ns, marks[3], 0, 5) + curbufmeths.set_extmark(ns, marks[4], 0, 6) + curbufmeths.set_extmark(ns, marks[5], 0, 7) + feed('') + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + check_undo_redo(ns, marks[2], 0, 3, 0, 7) + check_undo_redo(ns, marks[3], 0, 5, 0, 7) + check_undo_redo(ns, marks[4], 0, 6, 0, 7) + check_undo_redo(ns, marks[5], 0, 7, 0, 8) + end) + + it('using when negative and without decrease in order of magnitude #extmarks_inc_dec', function() + feed('ddiabc-999xxxT-') + curbufmeths.set_extmark(ns, marks[1], 0, 2) + curbufmeths.set_extmark(ns, marks[2], 0, 3) + curbufmeths.set_extmark(ns, marks[3], 0, 6) + curbufmeths.set_extmark(ns, marks[4], 0, 7) + curbufmeths.set_extmark(ns, marks[5], 0, 8) + feed('') + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + check_undo_redo(ns, marks[2], 0, 3, 0, 7) + check_undo_redo(ns, marks[3], 0, 6, 0, 7) + check_undo_redo(ns, marks[4], 0, 7, 0, 7) + check_undo_redo(ns, marks[5], 0, 8, 0, 8) + end) + + it('using when negative and decrease in order of magnitude #extmarks_inc_dec', function() + feed('ddiabc-1000xxxT-') + curbufmeths.set_extmark(ns, marks[1], 0, 2) + curbufmeths.set_extmark(ns, marks[2], 0, 3) + curbufmeths.set_extmark(ns, marks[3], 0, 7) + curbufmeths.set_extmark(ns, marks[4], 0, 8) + curbufmeths.set_extmark(ns, marks[5], 0, 9) + feed('') + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + check_undo_redo(ns, marks[2], 0, 3, 0, 7) + check_undo_redo(ns, marks[3], 0, 7, 0, 7) + check_undo_redo(ns, marks[4], 0, 8, 0, 7) + check_undo_redo(ns, marks[5], 0, 9, 0, 8) + end) + + it('using without decrease in order of magnitude #extmarks_inc_dec', function() + -- do_addsub in ops.c + feed('ddiabc999xxxTc') + curbufmeths.set_extmark(ns, marks[1], 0, 2) + curbufmeths.set_extmark(ns, marks[2], 0, 3) + curbufmeths.set_extmark(ns, marks[3], 0, 5) + curbufmeths.set_extmark(ns, marks[4], 0, 6) + curbufmeths.set_extmark(ns, marks[5], 0, 7) + feed('') + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + check_undo_redo(ns, marks[2], 0, 3, 0, 6) + check_undo_redo(ns, marks[3], 0, 5, 0, 6) + check_undo_redo(ns, marks[4], 0, 6, 0, 6) + check_undo_redo(ns, marks[5], 0, 7, 0, 7) + end) + + it('using when decrease in order of magnitude #extmarks_inc_dec', function() + -- do_addsub in ops.c + feed('ddiabc1000xxxTc') + curbufmeths.set_extmark(ns, marks[1], 0, 2) + curbufmeths.set_extmark(ns, marks[2], 0, 3) + curbufmeths.set_extmark(ns, marks[3], 0, 6) + curbufmeths.set_extmark(ns, marks[4], 0, 7) + curbufmeths.set_extmark(ns, marks[5], 0, 8) + feed('') + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + check_undo_redo(ns, marks[2], 0, 3, 0, 6) + check_undo_redo(ns, marks[3], 0, 6, 0, 6) + check_undo_redo(ns, marks[4], 0, 7, 0, 6) + check_undo_redo(ns, marks[5], 0, 8, 0, 7) + end) + + it('using when negative and without increase in order of magnitude #extmarks_inc_dec', function() + feed('ddiabc-998xxxT-') + curbufmeths.set_extmark(ns, marks[1], 0, 2) + curbufmeths.set_extmark(ns, marks[2], 0, 3) + curbufmeths.set_extmark(ns, marks[3], 0, 6) + curbufmeths.set_extmark(ns, marks[4], 0, 7) + curbufmeths.set_extmark(ns, marks[5], 0, 8) + feed('') + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + check_undo_redo(ns, marks[2], 0, 3, 0, 7) + check_undo_redo(ns, marks[3], 0, 6, 0, 7) + check_undo_redo(ns, marks[4], 0, 7, 0, 7) + check_undo_redo(ns, marks[5], 0, 8, 0, 8) + end) + + it('using when negative and increase in order of magnitude #extmarks_inc_dec', function() + feed('ddiabc-999xxxT-') + curbufmeths.set_extmark(ns, marks[1], 0, 2) + curbufmeths.set_extmark(ns, marks[2], 0, 3) + curbufmeths.set_extmark(ns, marks[3], 0, 6) + curbufmeths.set_extmark(ns, marks[4], 0, 7) + curbufmeths.set_extmark(ns, marks[5], 0, 8) + feed('') + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + check_undo_redo(ns, marks[2], 0, 3, 0, 8) + check_undo_redo(ns, marks[3], 0, 6, 0, 8) + check_undo_redo(ns, marks[4], 0, 7, 0, 8) + check_undo_redo(ns, marks[5], 0, 8, 0, 9) + end) + + -- TODO catch exceptions + pending('throws consistent error codes #todo', function() + local ns_invalid = ns2 + 1 + rv = curbufmeths.set_extmark(ns_invalid, marks[1], positions[1][1], positions[1][2]) + rv = curbufmeths.del_extmark(ns_invalid, marks[1]) + rv = curbufmeths.get_extmarks(ns_invalid, positions[1], positions[2], ALL) + rv = curbufmeths.get_extmark_by_id(ns_invalid, marks[1]) + + end) + + it('when col = line-length, set the mark on eol #extmarks', function() + curbufmeths.set_extmark(ns, marks[1], 0, -1) + rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + eq({0, init_text:len()}, rv) + -- Test another + curbufmeths.set_extmark(ns, marks[1], 0, -1) + rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + eq({0, init_text:len()}, rv) + end) + + it('when col = line-length, set the mark on eol #extmarks', function() + local invalid_col = init_text:len() + 1 + eq({false, "col value outside range"}, meth_pcall(curbufmeths.set_extmark, ns, marks[1], 0, invalid_col)) + end) + + -- TODO(bfredl): decide what to do with this + pending('when line > line, set the mark on end of buffer #extmarks', function() + local invalid_col = init_text:len() + 1 + local invalid_lnum = 3 -- line1 ends in an eol. so line 2 contains a valid position (eol)? + curbufmeths.set_extmark(ns, marks[1], invalid_lnum, invalid_col) + rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + eq({2, 1}, rv) + end) + + it('bug from check_col in extmark_set #extmarks_sub', function() + -- This bug was caused by extmark_set always using + -- check_col. check_col always uses the current buffer. + -- This wasn't working during undo so we now use + -- check_col and check_lnum only when they are required. + feed('A67890xx') + feed('A1234567890xx') + curbufmeths.set_extmark(ns, marks[1], 3, 4) + feed([[:1,5s:5\n:5 ]]) + check_undo_redo(ns, marks[1], 3, 4, 2, 6) + end) + +end) + +describe('Extmarks buffer api with many marks', function() + local ns1 + local ns2 + local ns_marks = {} + before_each(function() + clear() + ns1 = request('nvim_create_namespace', "ns1") + ns2 = request('nvim_create_namespace', "ns2") + ns_marks = {[ns1]={}, [ns2]={}} + local lines = {} + for i = 1,30 do + lines[#lines+1] = string.rep("x ",i) + end + curbufmeths.set_lines(0, -1, true, lines) + local ns = ns1 + local q = 0 + for i = 0,29 do + for j = 0,i do + local id = curbufmeths.set_extmark(ns,0, i,j) + eq(nil, ns_marks[ns][id]) + ok(id > 0) + ns_marks[ns][id] = {i,j} + ns = ns1+ns2-ns + q = q + 1 + end + end + eq(233, #ns_marks[ns1]) + eq(232, #ns_marks[ns2]) + + end) + + local function get_marks(ns) + local mark_list = curbufmeths.get_extmarks(ns, 0, -1, -1) + local marks = {} + for _, mark in ipairs(mark_list) do + local id, row, col = unpack(mark) + eq(nil, marks[id], "duplicate mark") + marks[id] = {row,col} + end + return marks + end + + it("can get marks #extmarks", function() + eq(ns_marks[ns1], get_marks(ns1)) + eq(ns_marks[ns2], get_marks(ns2)) + end) + + it("can clear all marks in ns #extmarks", function() + curbufmeths.clear_namespace(ns1, 0, -1) + eq({}, get_marks(ns1)) + eq(ns_marks[ns2], get_marks(ns2)) + curbufmeths.clear_namespace(ns2, 0, -1) + eq({}, get_marks(ns1)) + eq({}, get_marks(ns2)) + end) + + it("can clear line range #extmarks", function() + curbufmeths.clear_namespace(ns1, 10, 20) + for id, mark in pairs(ns_marks[ns1]) do + if 10 <= mark[1] and mark[1] < 20 then + ns_marks[ns1][id] = nil + end + end + eq(ns_marks[ns1], get_marks(ns1)) + eq(ns_marks[ns2], get_marks(ns2)) + end) + + it("can delete line #extmarks", function() + feed('10Gdd') + for _, marks in pairs(ns_marks) do + for id, mark in pairs(marks) do + if mark[1] == 9 then + marks[id] = {9,0} + elseif mark[1] >= 10 then + mark[1] = mark[1] - 1 + end + end + end + eq(ns_marks[ns1], get_marks(ns1)) + eq(ns_marks[ns2], get_marks(ns2)) + end) + + it("can delete lines #extmarks", function() + feed('10G10dd') + for _, marks in pairs(ns_marks) do + for id, mark in pairs(marks) do + if 9 <= mark[1] and mark[1] < 19 then + marks[id] = {9,0} + elseif mark[1] >= 19 then + mark[1] = mark[1] - 10 + end + end + end + eq(ns_marks[ns1], get_marks(ns1)) + eq(ns_marks[ns2], get_marks(ns2)) + end) +end) diff --git a/test/functional/legacy/046_multi_line_regexps_spec.lua b/test/functional/legacy/046_multi_line_regexps_spec.lua index 30ec76ea3e..9d3ee57b46 100644 --- a/test/functional/legacy/046_multi_line_regexps_spec.lua +++ b/test/functional/legacy/046_multi_line_regexps_spec.lua @@ -8,22 +8,22 @@ local expect = helpers.expect describe('multi-line regexp', function() setup(clear) - it('is working', function() + it('is working #fail', function() insert([[ - 1 aa - bb - cc - 2 dd - ee - 3 ef - gh - 4 ij - 5 a8 - 8b c9 - 9d - 6 e7 - 77f - xxxxx]]) +1 aa +bb +cc +2 dd +ee +3 ef +gh +4 ij +5 a8 +8b c9 +9d +6 e7 +77f +xxxxx]]) -- Test if replacing a line break works with a back reference feed([[:/^1/,/^2/s/\n\(.\)/ \1/]]) diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua index b841574643..0136e4e7e0 100644 --- a/test/functional/ui/inccommand_spec.lua +++ b/test/functional/ui/inccommand_spec.lua @@ -131,7 +131,7 @@ describe(":substitute, inccommand=split interactivity", function() end) end) -describe(":substitute, 'inccommand' preserves", function() +describe(":substitute, 'inccommand' preserves #inc", function() before_each(clear) it('listed buffers (:ls)', function() @@ -293,7 +293,7 @@ describe(":substitute, 'inccommand' preserves", function() end) -describe(":substitute, 'inccommand' preserves undo", function() +describe(":substitute, 'inccommand' preserves undo #inc", function() local cases = { "", "split", "nosplit" } local substrings = { @@ -1962,7 +1962,7 @@ describe(":substitute", function() clear() end) - it("inccommand=split, highlights multiline substitutions", function() + it("inccommand=split, highlights multiline substitutions #inc2", function() common_setup(screen, "split", multiline_text) feed("gg") @@ -2024,7 +2024,7 @@ describe(":substitute", function() ]]) end) - it("inccommand=nosplit, highlights multiline substitutions", function() + it("inccommand=nosplit, highlights multiline substitutions #inc2", function() common_setup(screen, "nosplit", multiline_text) feed("gg") @@ -2117,7 +2117,7 @@ describe(":substitute", function() ]]) end) - it("inccommand=split, with \\zs", function() + it("inccommand=split, with \\zs #inc", function() common_setup(screen, "split", multiline_text) feed("gg") @@ -2141,7 +2141,7 @@ describe(":substitute", function() ]]) end) - it("inccommand=nosplit, with \\zs", function() + it("inccommand=nosplit, with \\zs #inc", function() common_setup(screen, "nosplit", multiline_text) feed("gg") @@ -2212,7 +2212,7 @@ describe(":substitute", function() ]]) end) - it("inccommand=split, contraction of lines", function() + it("inccommand=split, contraction of lines #inc2", function() local text = [[ T T123 T T123 T2T TT T23423424 x @@ -2261,7 +2261,7 @@ describe(":substitute", function() ]]) end) - it("inccommand=nosplit, contraction of lines", function() + it("inccommand=nosplit, contraction of lines #inc2", function() local text = [[ T T123 T T123 T2T TT T23423424 x diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index 7840ba9167..2c50bcb97b 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -817,7 +817,6 @@ describe('ui/mouse/input', function() feed_command('syntax match NonText "cats" conceal cchar=X') feed_command('syntax match NonText "x" conceal cchar=>') - -- First column is there to retain the tabs. insert([[ |Section *t1* | *t2* *t3* *t4* -- cgit From 18a8b702c0ce7a8bacd84f6c95e440ae23a3299e Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 9 Nov 2019 12:41:50 +0100 Subject: extmark: review changes --- test/functional/api/mark_extended_spec.lua | 624 +++++++++++---------- .../legacy/046_multi_line_regexps_spec.lua | 30 +- test/functional/ui/inccommand_spec.lua | 16 +- test/functional/ui/mouse_spec.lua | 1 + 4 files changed, 338 insertions(+), 333 deletions(-) (limited to 'test') diff --git a/test/functional/api/mark_extended_spec.lua b/test/functional/api/mark_extended_spec.lua index 6bf0e59133..a5d68c6b9f 100644 --- a/test/functional/api/mark_extended_spec.lua +++ b/test/functional/api/mark_extended_spec.lua @@ -1,7 +1,3 @@ --- TODO(timeyyy): go through todo's lol --- change representation of stored marks to have location start at 0 --- check with memsan, asan etc - local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') @@ -9,17 +5,14 @@ local request = helpers.request local eq = helpers.eq local ok = helpers.ok local curbufmeths = helpers.curbufmeths -local meth_pcall = helpers.meth_pcall +local pcall_err = helpers.pcall_err local insert = helpers.insert local feed = helpers.feed local clear = helpers.clear - -local ALL = -1 - -local rv = nil +local command = helpers.command local function check_undo_redo(ns, mark, sr, sc, er, ec) --s = start, e = end - rv = curbufmeths.get_extmark_by_id(ns, mark) + local rv = curbufmeths.get_extmark_by_id(ns, mark) eq({er, ec}, rv) feed("u") rv = curbufmeths.get_extmark_by_id(ns, mark) @@ -29,6 +22,20 @@ local function check_undo_redo(ns, mark, sr, sc, er, ec) --s = start, e = end eq({er, ec}, rv) end +local function set_extmark(ns_id, id, line, col, opts) + if opts == nil then + opts = {} + end + return curbufmeths.set_extmark(ns_id, id, line, col, opts) +end + +local function get_extmarks(ns_id, start, end_, opts) + if opts == nil then + opts = {} + end + return curbufmeths.get_extmarks(ns_id, start, end_, opts) +end + describe('Extmarks buffer api', function() local screen local marks, positions, ns_string2, ns_string, init_text, row, col @@ -55,24 +62,24 @@ describe('Extmarks buffer api', function() end) it('adds, updates and deletes marks #extmarks', function() - rv = curbufmeths.set_extmark(ns, marks[1], positions[1][1], positions[1][2]) + local rv = set_extmark(ns, marks[1], positions[1][1], positions[1][2]) eq(marks[1], rv) rv = curbufmeths.get_extmark_by_id(ns, marks[1]) eq({positions[1][1], positions[1][2]}, rv) -- Test adding a second mark on same row works - rv = curbufmeths.set_extmark(ns, marks[2], positions[2][1], positions[2][2]) + rv = set_extmark(ns, marks[2], positions[2][1], positions[2][2]) eq(marks[2], rv) -- Test an update, (same pos) - rv = curbufmeths.set_extmark(ns, marks[1], positions[1][1], positions[1][2]) - eq(0, rv) + rv = set_extmark(ns, marks[1], positions[1][1], positions[1][2]) + eq(marks[1], rv) rv = curbufmeths.get_extmark_by_id(ns, marks[2]) eq({positions[2][1], positions[2][2]}, rv) -- Test an update, (new pos) row = positions[1][1] col = positions[1][2] + 1 - rv = curbufmeths.set_extmark(ns, marks[1], row, col) - eq(0, rv) + rv = set_extmark(ns, marks[1], row, col) + eq(marks[1], rv) rv = curbufmeths.get_extmark_by_id(ns, marks[1]) eq({row, col}, rv) @@ -85,50 +92,50 @@ describe('Extmarks buffer api', function() end) it('can clear a specific namespace range #extmarks', function() - curbufmeths.set_extmark(ns, 1, 0, 1) - curbufmeths.set_extmark(ns2, 1, 0, 1) + set_extmark(ns, 1, 0, 1) + set_extmark(ns2, 1, 0, 1) -- force a new undo buffer feed('o') curbufmeths.clear_namespace(ns2, 0, -1) - eq({{1, 0, 1}}, curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL)) - eq({}, curbufmeths.get_extmarks(ns2, {0, 0}, {-1, -1}, ALL)) + eq({{1, 0, 1}}, get_extmarks(ns, {0, 0}, {-1, -1})) + eq({}, get_extmarks(ns2, {0, 0}, {-1, -1})) feed('u') - eq({{1, 0, 1}}, curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL)) - eq({{1, 0, 1}}, curbufmeths.get_extmarks(ns2, {0, 0}, {-1, -1}, ALL)) + eq({{1, 0, 1}}, get_extmarks(ns, {0, 0}, {-1, -1})) + eq({{1, 0, 1}}, get_extmarks(ns2, {0, 0}, {-1, -1})) feed('') - eq({{1, 0, 1}}, curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL)) - eq({}, curbufmeths.get_extmarks(ns2, {0, 0}, {-1, -1}, ALL)) + eq({{1, 0, 1}}, get_extmarks(ns, {0, 0}, {-1, -1})) + eq({}, get_extmarks(ns2, {0, 0}, {-1, -1})) end) - it('can clear a namespace range using ALL #extmarks', function() - curbufmeths.set_extmark(ns, 1, 0, 1) - curbufmeths.set_extmark(ns2, 1, 0, 1) + it('can clear a namespace range using 0,-1 #extmarks', function() + set_extmark(ns, 1, 0, 1) + set_extmark(ns2, 1, 0, 1) -- force a new undo buffer feed('o') curbufmeths.clear_namespace(-1, 0, -1) - eq({}, curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL)) - eq({}, curbufmeths.get_extmarks(ns2, {0, 0}, {-1, -1}, ALL)) + eq({}, get_extmarks(ns, {0, 0}, {-1, -1})) + eq({}, get_extmarks(ns2, {0, 0}, {-1, -1})) feed('u') - eq({{1, 0, 1}}, curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL)) - eq({{1, 0, 1}}, curbufmeths.get_extmarks(ns2, {0, 0}, {-1, -1}, ALL)) + eq({{1, 0, 1}}, get_extmarks(ns, {0, 0}, {-1, -1})) + eq({{1, 0, 1}}, get_extmarks(ns2, {0, 0}, {-1, -1})) feed('') - eq({}, curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL)) - eq({}, curbufmeths.get_extmarks(ns2, {0, 0}, {-1, -1}, ALL)) + eq({}, get_extmarks(ns, {0, 0}, {-1, -1})) + eq({}, get_extmarks(ns2, {0, 0}, {-1, -1})) end) it('querying for information and ranges #extmarks', function() -- add some more marks for i, m in ipairs(marks) do if positions[i] ~= nil then - rv = curbufmeths.set_extmark(ns, m, positions[i][1], positions[i][2]) + local rv = set_extmark(ns, m, positions[i][1], positions[i][2]) eq(m, rv) end end -- {0, 0} and {-1, -1} work as extreme values - eq({{1, 0, 0}}, curbufmeths.get_extmarks(ns, {0, 0}, {0, 0}, ALL)) - eq({}, curbufmeths.get_extmarks(ns, {-1, -1}, {-1, -1}, ALL)) - rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL) + eq({{1, 0, 0}}, get_extmarks(ns, {0, 0}, {0, 0})) + eq({}, get_extmarks(ns, {-1, -1}, {-1, -1})) + local rv = get_extmarks(ns, {0, 0}, {-1, -1}) for i, m in ipairs(marks) do if positions[i] ~= nil then eq({m, positions[i][1], positions[i][2]}, rv[i]) @@ -136,9 +143,9 @@ describe('Extmarks buffer api', function() end -- 0 and -1 works as short hand extreme values - eq({{1, 0, 0}}, curbufmeths.get_extmarks(ns, 0, 0, ALL)) - eq({}, curbufmeths.get_extmarks(ns, -1, -1, ALL)) - rv = curbufmeths.get_extmarks(ns, 0, -1, ALL) + eq({{1, 0, 0}}, get_extmarks(ns, 0, 0)) + eq({}, get_extmarks(ns, -1, -1)) + rv = get_extmarks(ns, 0, -1) for i, m in ipairs(marks) do if positions[i] ~= nil then eq({m, positions[i][1], positions[i][2]}, rv[i]) @@ -146,91 +153,91 @@ describe('Extmarks buffer api', function() end -- next with mark id - rv = curbufmeths.get_extmarks(ns, marks[1], {-1, -1}, 1) + rv = get_extmarks(ns, marks[1], {-1, -1}, {amount=1}) eq({{marks[1], positions[1][1], positions[1][2]}}, rv) - rv = curbufmeths.get_extmarks(ns, marks[2], {-1, -1}, 1) + rv = get_extmarks(ns, marks[2], {-1, -1}, {amount=1}) eq({{marks[2], positions[2][1], positions[2][2]}}, rv) -- next with positional when mark exists at position - rv = curbufmeths.get_extmarks(ns, positions[1], {-1, -1}, 1) + rv = get_extmarks(ns, positions[1], {-1, -1}, {amount=1}) eq({{marks[1], positions[1][1], positions[1][2]}}, rv) -- next with positional index (no mark at position) - rv = curbufmeths.get_extmarks(ns, {positions[1][1], positions[1][2] +1}, {-1, -1}, 1) + rv = get_extmarks(ns, {positions[1][1], positions[1][2] +1}, {-1, -1}, {amount=1}) eq({{marks[2], positions[2][1], positions[2][2]}}, rv) -- next with Extremity index - rv = curbufmeths.get_extmarks(ns, {0,0}, {-1, -1}, 1) + rv = get_extmarks(ns, {0,0}, {-1, -1}, {amount=1}) eq({{marks[1], positions[1][1], positions[1][2]}}, rv) -- nextrange with mark id - rv = curbufmeths.get_extmarks(ns, marks[1], marks[3], ALL) + rv = get_extmarks(ns, marks[1], marks[3]) eq({marks[1], positions[1][1], positions[1][2]}, rv[1]) eq({marks[2], positions[2][1], positions[2][2]}, rv[2]) -- nextrange with amount - rv = curbufmeths.get_extmarks(ns, marks[1], marks[3], 2) + rv = get_extmarks(ns, marks[1], marks[3], {amount=2}) eq(2, table.getn(rv)) -- nextrange with positional when mark exists at position - rv = curbufmeths.get_extmarks(ns, positions[1], positions[3], ALL) + rv = get_extmarks(ns, positions[1], positions[3]) eq({marks[1], positions[1][1], positions[1][2]}, rv[1]) eq({marks[2], positions[2][1], positions[2][2]}, rv[2]) - rv = curbufmeths.get_extmarks(ns, positions[2], positions[3], ALL) + rv = get_extmarks(ns, positions[2], positions[3]) eq(2, table.getn(rv)) -- nextrange with positional index (no mark at position) local lower = {positions[1][1], positions[2][2] -1} local upper = {positions[2][1], positions[3][2] - 1} - rv = curbufmeths.get_extmarks(ns, lower, upper, ALL) + rv = get_extmarks(ns, lower, upper) eq({{marks[2], positions[2][1], positions[2][2]}}, rv) lower = {positions[3][1], positions[3][2] + 1} upper = {positions[3][1], positions[3][2] + 2} - rv = curbufmeths.get_extmarks(ns, lower, upper, ALL) + rv = get_extmarks(ns, lower, upper) eq({}, rv) -- nextrange with extremity index lower = {positions[2][1], positions[2][2]+1} upper = {-1, -1} - rv = curbufmeths.get_extmarks(ns, lower, upper, ALL) + rv = get_extmarks(ns, lower, upper) eq({{marks[3], positions[3][1], positions[3][2]}}, rv) -- prev with mark id - rv = curbufmeths.get_extmarks(ns, marks[3], {0, 0}, 1) + rv = get_extmarks(ns, marks[3], {0, 0}, {amount=1}) eq({{marks[3], positions[3][1], positions[3][2]}}, rv) - rv = curbufmeths.get_extmarks(ns, marks[2], {0, 0}, 1) + rv = get_extmarks(ns, marks[2], {0, 0}, {amount=1}) eq({{marks[2], positions[2][1], positions[2][2]}}, rv) -- prev with positional when mark exists at position - rv = curbufmeths.get_extmarks(ns, positions[3], {0, 0}, 1) + rv = get_extmarks(ns, positions[3], {0, 0}, {amount=1}) eq({{marks[3], positions[3][1], positions[3][2]}}, rv) -- prev with positional index (no mark at position) - rv = curbufmeths.get_extmarks(ns, {positions[1][1], positions[1][2] +1}, {0, 0}, 1) + rv = get_extmarks(ns, {positions[1][1], positions[1][2] +1}, {0, 0}, {amount=1}) eq({{marks[1], positions[1][1], positions[1][2]}}, rv) -- prev with Extremity index - rv = curbufmeths.get_extmarks(ns, {-1,-1}, {0,0}, 1) + rv = get_extmarks(ns, {-1,-1}, {0,0}, {amount=1}) eq({{marks[3], positions[3][1], positions[3][2]}}, rv) -- prevrange with mark id - rv = curbufmeths.get_extmarks(ns, marks[3], marks[1], ALL) + rv = get_extmarks(ns, marks[3], marks[1]) eq({marks[3], positions[3][1], positions[3][2]}, rv[1]) eq({marks[2], positions[2][1], positions[2][2]}, rv[2]) eq({marks[1], positions[1][1], positions[1][2]}, rv[3]) -- prevrange with amount - rv = curbufmeths.get_extmarks(ns, marks[3], marks[1], 2) + rv = get_extmarks(ns, marks[3], marks[1], {amount=2}) eq(2, table.getn(rv)) -- prevrange with positional when mark exists at position - rv = curbufmeths.get_extmarks(ns, positions[3], positions[1], ALL) + rv = get_extmarks(ns, positions[3], positions[1]) eq({{marks[3], positions[3][1], positions[3][2]}, {marks[2], positions[2][1], positions[2][2]}, {marks[1], positions[1][1], positions[1][2]}}, rv) - rv = curbufmeths.get_extmarks(ns, positions[2], positions[1], ALL) + rv = get_extmarks(ns, positions[2], positions[1]) eq(2, table.getn(rv)) -- prevrange with positional index (no mark at position) lower = {positions[2][1], positions[2][2] + 1} upper = {positions[3][1], positions[3][2] + 1} - rv = curbufmeths.get_extmarks(ns, upper, lower, ALL) + rv = get_extmarks(ns, upper, lower) eq({{marks[3], positions[3][1], positions[3][2]}}, rv) lower = {positions[3][1], positions[3][2] + 1} upper = {positions[3][1], positions[3][2] + 2} - rv = curbufmeths.get_extmarks(ns, upper, lower, ALL) + rv = get_extmarks(ns, upper, lower) eq({}, rv) -- prevrange with extremity index lower = {0,0} upper = {positions[2][1], positions[2][2] - 1} - rv = curbufmeths.get_extmarks(ns, upper, lower, ALL) + rv = get_extmarks(ns, upper, lower) eq({{marks[1], positions[1][1], positions[1][2]}}, rv) end) @@ -238,50 +245,50 @@ describe('Extmarks buffer api', function() -- add some more marks for i, m in ipairs(marks) do if positions[i] ~= nil then - rv = curbufmeths.set_extmark(ns, m, positions[i][1], positions[i][2]) + local rv = set_extmark(ns, m, positions[i][1], positions[i][2]) eq(m, rv) end end - rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, 1) + local rv = get_extmarks(ns, {0, 0}, {-1, -1}, {amount=1}) eq(1, table.getn(rv)) - rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, 2) + rv = get_extmarks(ns, {0, 0}, {-1, -1}, {amount=2}) eq(2, table.getn(rv)) - rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, 3) + rv = get_extmarks(ns, {0, 0}, {-1, -1}, {amount=3}) eq(3, table.getn(rv)) -- now in reverse - rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, 1) + rv = get_extmarks(ns, {0, 0}, {-1, -1}, {amount=1}) eq(1, table.getn(rv)) - rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, 2) + rv = get_extmarks(ns, {0, 0}, {-1, -1}, {amount=2}) eq(2, table.getn(rv)) - rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, 3) + rv = get_extmarks(ns, {0, 0}, {-1, -1}, {amount=3}) eq(3, table.getn(rv)) end) it('get_marks works when mark col > upper col #extmarks', function() feed('A12345') feed('A12345') - curbufmeths.set_extmark(ns, 10, 0, 2) -- this shouldn't be found - curbufmeths.set_extmark(ns, 11, 2, 1) -- this shouldn't be found - curbufmeths.set_extmark(ns, marks[1], 0, 4) -- check col > our upper bound - curbufmeths.set_extmark(ns, marks[2], 1, 1) -- check col < lower bound - curbufmeths.set_extmark(ns, marks[3], 2, 0) -- check is inclusive + set_extmark(ns, 10, 0, 2) -- this shouldn't be found + set_extmark(ns, 11, 2, 1) -- this shouldn't be found + set_extmark(ns, marks[1], 0, 4) -- check col > our upper bound + set_extmark(ns, marks[2], 1, 1) -- check col < lower bound + set_extmark(ns, marks[3], 2, 0) -- check is inclusive eq({{marks[1], 0, 4}, {marks[2], 1, 1}, {marks[3], 2, 0}}, - curbufmeths.get_extmarks(ns, {0, 3}, {2, 0}, -1)) + get_extmarks(ns, {0, 3}, {2, 0})) end) it('get_marks works in reverse when mark col < lower col #extmarks', function() feed('A12345') feed('A12345') - curbufmeths.set_extmark(ns, 10, 0, 1) -- this shouldn't be found - curbufmeths.set_extmark(ns, 11, 2, 4) -- this shouldn't be found - curbufmeths.set_extmark(ns, marks[1], 2, 1) -- check col < our lower bound - curbufmeths.set_extmark(ns, marks[2], 1, 4) -- check col > upper bound - curbufmeths.set_extmark(ns, marks[3], 0, 2) -- check is inclusive - rv = curbufmeths.get_extmarks(ns, {2, 3}, {0, 2}, -1) + set_extmark(ns, 10, 0, 1) -- this shouldn't be found + set_extmark(ns, 11, 2, 4) -- this shouldn't be found + set_extmark(ns, marks[1], 2, 1) -- check col < our lower bound + set_extmark(ns, marks[2], 1, 4) -- check col > upper bound + set_extmark(ns, marks[3], 0, 2) -- check is inclusive + local rv = get_extmarks(ns, {2, 3}, {0, 2}) eq({{marks[1], 2, 1}, {marks[2], 1, 4}, {marks[3], 0, 2}}, @@ -289,21 +296,21 @@ describe('Extmarks buffer api', function() end) it('get_marks amount 0 returns nothing #extmarks', function() - curbufmeths.set_extmark(ns, marks[1], positions[1][1], positions[1][2]) - rv = curbufmeths.get_extmarks(ns, {-1, -1}, {-1, -1}, 0) + set_extmark(ns, marks[1], positions[1][1], positions[1][2]) + local rv = get_extmarks(ns, {-1, -1}, {-1, -1}, {amount=0}) eq({}, rv) end) it('marks move with line insertations #extmarks', function() - curbufmeths.set_extmark(ns, marks[1], 0, 0) + set_extmark(ns, marks[1], 0, 0) feed("yyP") check_undo_redo(ns, marks[1], 0, 0, 1, 0) end) it('marks move with multiline insertations #extmarks', function() feed("a2233") - curbufmeths.set_extmark(ns, marks[1], 1, 1) + set_extmark(ns, marks[1], 1, 1) feed('ggVGyP') check_undo_redo(ns, marks[1], 1, 1, 4, 1) end) @@ -311,7 +318,7 @@ describe('Extmarks buffer api', function() it('marks move with line join #extmarks', function() -- do_join in ops.c feed("a222") - curbufmeths.set_extmark(ns, marks[1], 1, 0) + set_extmark(ns, marks[1], 1, 0) feed('ggJ') check_undo_redo(ns, marks[1], 1, 0, 0, 6) end) @@ -337,21 +344,21 @@ describe('Extmarks buffer api', function() it('marks move with multiline join #extmarks', function() -- do_join in ops.c feed("a222333444") - curbufmeths.set_extmark(ns, marks[1], 3, 0) + set_extmark(ns, marks[1], 3, 0) feed('2GVGJ') check_undo_redo(ns, marks[1], 3, 0, 1, 8) end) it('marks move with line deletes #extmarks', function() feed("a222333444") - curbufmeths.set_extmark(ns, marks[1], 2, 1) + set_extmark(ns, marks[1], 2, 1) feed('ggjdd') check_undo_redo(ns, marks[1], 2, 1, 1, 1) end) it('marks move with multiline deletes #extmarks', function() feed("a222333444") - curbufmeths.set_extmark(ns, marks[1], 3, 0) + set_extmark(ns, marks[1], 3, 0) feed('gg2dd') check_undo_redo(ns, marks[1], 3, 0, 1, 0) -- regression test, undoing multiline delete when mark is on row 1 @@ -363,8 +370,8 @@ describe('Extmarks buffer api', function() -- open_line in misc1.c -- testing marks below are also moved feed("yyP") - curbufmeths.set_extmark(ns, marks[1], 0, 4) - curbufmeths.set_extmark(ns, marks[2], 1, 4) + set_extmark(ns, marks[1], 0, 4) + set_extmark(ns, marks[2], 1, 4) feed('1G') check_undo_redo(ns, marks[1], 0, 4, 1, 4) check_undo_redo(ns, marks[2], 1, 4, 2, 4) @@ -373,10 +380,9 @@ describe('Extmarks buffer api', function() check_undo_redo(ns, marks[2], 2, 4, 3, 4) end) - -- NO idea why this doesn't work... works in program. - pending('marks move with char inserts #extmarks', function() + it('marks move with char inserts #extmarks', function() -- insertchar in edit.c (the ins_str branch) - curbufmeths.set_extmark(ns, marks[1], 1, 3) + set_extmark(ns, marks[1], 0, 3) feed('0') insert('abc') screen:expect([[ @@ -391,16 +397,15 @@ describe('Extmarks buffer api', function() ~ | | ]]) - rv = curbufmeths.get_extmark_by_id(ns, marks[1]) - eq(1, rv[2]) - eq(6, rv[3]) + local rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + eq({0, 6}, rv) -- check_undo_redo(ns, marks[1], 0, 2, 0, 5) end) -- gravity right as definted in tk library it('marks have gravity right #extmarks', function() -- insertchar in edit.c (the ins_str branch) - curbufmeths.set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[1], 0, 2) feed('03l') insert("X") check_undo_redo(ns, marks[1], 0, 2, 0, 2) @@ -414,7 +419,7 @@ describe('Extmarks buffer api', function() it('we can insert multibyte chars #extmarks', function() -- insertchar in edit.c feed('a12345') - curbufmeths.set_extmark(ns, marks[1], 1, 2) + set_extmark(ns, marks[1], 1, 2) -- Insert a fullwidth (two col) tilde, NICE feed('0i~') check_undo_redo(ns, marks[1], 1, 2, 1, 3) @@ -423,7 +428,7 @@ describe('Extmarks buffer api', function() it('marks move with blockwise inserts #extmarks', function() -- op_insert in ops.c feed('a12345') - curbufmeths.set_extmark(ns, marks[1], 1, 2) + set_extmark(ns, marks[1], 1, 2) feed('0lkI9') check_undo_redo(ns, marks[1], 1, 2, 1, 3) end) @@ -432,18 +437,16 @@ describe('Extmarks buffer api', function() -- open_line in misc1.c -- testing marks below are also moved feed("yyP") - curbufmeths.set_extmark(ns, marks[1], 0, 4) - curbufmeths.set_extmark(ns, marks[2], 1, 4) + set_extmark(ns, marks[1], 0, 4) + set_extmark(ns, marks[2], 1, 4) feed('1Gla') check_undo_redo(ns, marks[1], 0, 4, 1, 2) check_undo_redo(ns, marks[2], 1, 4, 2, 4) end) - -- TODO mark_col_adjust for normal marks fails in vim/neovim - -- because flags is 9 in: if (flags & OPENLINE_MARKFIX) { it('marks at last line move on insert new line #extmarks', function() -- open_line in misc1.c - curbufmeths.set_extmark(ns, marks[1], 0, 4) + set_extmark(ns, marks[1], 0, 4) feed('0i') check_undo_redo(ns, marks[1], 0, 4, 1, 4) end) @@ -451,22 +454,22 @@ describe('Extmarks buffer api', function() it('yet again marks move with line splits #extmarks', function() -- the first test above wasn't catching all errors.. feed("A67890") - curbufmeths.set_extmark(ns, marks[1], 0, 4) + set_extmark(ns, marks[1], 0, 4) feed("04li") check_undo_redo(ns, marks[1], 0, 4, 1, 0) end) it('and one last time line splits... #extmarks', function() - curbufmeths.set_extmark(ns, marks[1], 0, 1) - curbufmeths.set_extmark(ns, marks[2], 0, 2) + set_extmark(ns, marks[1], 0, 1) + set_extmark(ns, marks[2], 0, 2) feed("02li") check_undo_redo(ns, marks[1], 0, 1, 0, 1) check_undo_redo(ns, marks[2], 0, 2, 1, 0) end) it('multiple marks move with mark splits #extmarks', function() - curbufmeths.set_extmark(ns, marks[1], 0, 1) - curbufmeths.set_extmark(ns, marks[2], 0, 3) + set_extmark(ns, marks[1], 0, 1) + set_extmark(ns, marks[2], 0, 3) feed("0li") check_undo_redo(ns, marks[1], 0, 1, 1, 0) check_undo_redo(ns, marks[2], 0, 3, 1, 2) @@ -474,14 +477,14 @@ describe('Extmarks buffer api', function() it('deleting on a mark works #extmarks', function() -- op_delete in ops.c - curbufmeths.set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[1], 0, 2) feed('02lx') check_undo_redo(ns, marks[1], 0, 2, 0, 2) end) it('marks move with char deletes #extmarks', function() -- op_delete in ops.c - curbufmeths.set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[1], 0, 2) feed('02dl') check_undo_redo(ns, marks[1], 0, 2, 0, 0) -- from the other side (nothing should happen) @@ -491,21 +494,20 @@ describe('Extmarks buffer api', function() it('marks move with char deletes over a range #extmarks', function() -- op_delete in ops.c - curbufmeths.set_extmark(ns, marks[1], 0, 2) - curbufmeths.set_extmark(ns, marks[2], 0, 3) + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 0, 3) feed('0l3dl') check_undo_redo(ns, marks[1], 0, 2, 0, 1) check_undo_redo(ns, marks[2], 0, 3, 0, 1) -- delete 1, nothing should happend to our marks feed('u') feed('$x') - -- TODO do we need to test marks[1] ??? check_undo_redo(ns, marks[2], 0, 3, 0, 3) end) it('deleting marks at end of line works #extmarks', function() -- mark_extended.c/extmark_col_adjust_delete - curbufmeths.set_extmark(ns, marks[1], 0, 4) + set_extmark(ns, marks[1], 0, 4) feed('$x') check_undo_redo(ns, marks[1], 0, 4, 0, 4) -- check the copy happened correctly on delete at eol @@ -518,7 +520,7 @@ describe('Extmarks buffer api', function() it('marks move with blockwise deletes #extmarks', function() -- op_delete in ops.c feed('a12345') - curbufmeths.set_extmark(ns, marks[1], 1, 4) + set_extmark(ns, marks[1], 1, 4) feed('hhhkd') check_undo_redo(ns, marks[1], 1, 4, 1, 1) end) @@ -526,9 +528,9 @@ describe('Extmarks buffer api', function() it('marks move with blockwise deletes over a range #extmarks', function() -- op_delete in ops.c feed('a12345') - curbufmeths.set_extmark(ns, marks[1], 0, 1) - curbufmeths.set_extmark(ns, marks[2], 0, 3) - curbufmeths.set_extmark(ns, marks[3], 1, 2) + set_extmark(ns, marks[1], 0, 1) + set_extmark(ns, marks[2], 0, 3) + set_extmark(ns, marks[3], 1, 2) feed('0k3lx') check_undo_redo(ns, marks[1], 0, 1, 0, 0) check_undo_redo(ns, marks[2], 0, 3, 0, 0) @@ -536,14 +538,13 @@ describe('Extmarks buffer api', function() -- delete 1, nothing should happend to our marks feed('u') feed('$jx') - -- TODO do we need to test marks[1] ??? check_undo_redo(ns, marks[2], 0, 3, 0, 3) check_undo_redo(ns, marks[3], 1, 2, 1, 2) end) it('works with char deletes over multilines #extmarks', function() feed('a12345test-me') - curbufmeths.set_extmark(ns, marks[1], 2, 5) + set_extmark(ns, marks[1], 2, 5) feed('gg') feed('dv?-m?') check_undo_redo(ns, marks[1], 2, 5, 0, 0) @@ -551,7 +552,7 @@ describe('Extmarks buffer api', function() it('marks outside of deleted range move with visual char deletes #extmarks', function() -- op_delete in ops.c - curbufmeths.set_extmark(ns, marks[1], 0, 3) + set_extmark(ns, marks[1], 0, 3) feed('0vx') check_undo_redo(ns, marks[1], 0, 3, 0, 2) @@ -570,7 +571,7 @@ describe('Extmarks buffer api', function() it('marks outside of deleted range move with char deletes #extmarks', function() -- op_delete in ops.c - curbufmeths.set_extmark(ns, marks[1], 0, 3) + set_extmark(ns, marks[1], 0, 3) feed('0x') check_undo_redo(ns, marks[1], 0, 3, 0, 2) @@ -591,7 +592,7 @@ describe('Extmarks buffer api', function() it('marks move with P(backward) paste #extmarks', function() -- do_put in ops.c feed('0iabc') - curbufmeths.set_extmark(ns, marks[1], 0, 7) + set_extmark(ns, marks[1], 0, 7) feed('0veyP') check_undo_redo(ns, marks[1], 0, 7, 0, 15) end) @@ -599,7 +600,7 @@ describe('Extmarks buffer api', function() it('marks move with p(forward) paste #extmarks', function() -- do_put in ops.c feed('0iabc') - curbufmeths.set_extmark(ns, marks[1], 0, 7) + set_extmark(ns, marks[1], 0, 7) feed('0veyp') check_undo_redo(ns, marks[1], 0, 7, 0, 14) end) @@ -607,7 +608,7 @@ describe('Extmarks buffer api', function() it('marks move with blockwise P(backward) paste #extmarks', function() -- do_put in ops.c feed('a12345') - curbufmeths.set_extmark(ns, marks[1], 1, 4) + set_extmark(ns, marks[1], 1, 4) feed('hhkyP') check_undo_redo(ns, marks[1], 1, 4, 1, 7) end) @@ -615,20 +616,20 @@ describe('Extmarks buffer api', function() it('marks move with blockwise p(forward) paste #extmarks', function() -- do_put in ops.c feed('a12345') - curbufmeths.set_extmark(ns, marks[1], 1, 4) + set_extmark(ns, marks[1], 1, 4) feed('hhkyp') check_undo_redo(ns, marks[1], 1, 4, 1, 6) end) it('replace works #extmarks', function() - curbufmeths.set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[1], 0, 2) feed('0r2') check_undo_redo(ns, marks[1], 0, 2, 0, 2) end) it('blockwise replace works #extmarks', function() feed('a12345') - curbufmeths.set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[1], 0, 2) feed('0llkr1') check_undo_redo(ns, marks[1], 0, 2, 0, 2) end) @@ -636,7 +637,7 @@ describe('Extmarks buffer api', function() it('shift line #extmarks', function() -- shift_line in ops.c feed(':set shiftwidth=4') - curbufmeths.set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[1], 0, 2) feed('0>>') check_undo_redo(ns, marks[1], 0, 2, 0, 6) @@ -651,7 +652,7 @@ describe('Extmarks buffer api', function() -- shift_block in ops.c feed(':set shiftwidth=4') feed('a12345') - curbufmeths.set_extmark(ns, marks[1], 1, 2) + set_extmark(ns, marks[1], 1, 2) feed('0k>') check_undo_redo(ns, marks[1], 1, 2, 1, 6) feed('j>') @@ -665,7 +666,7 @@ describe('Extmarks buffer api', function() -- ins_tab in edit.c feed(':set expandtab') feed(':set shiftwidth=2') - curbufmeths.set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[1], 0, 2) feed('0i') check_undo_redo(ns, marks[1], 0, 2, 0, 6) end) @@ -676,7 +677,7 @@ describe('Extmarks buffer api', function() feed(':set shiftwidth=2') feed(':set softtabstop=2') feed(':set tabstop=8') - curbufmeths.set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[1], 0, 2) feed('0i') check_undo_redo(ns, marks[1], 0, 2, 0, 4) feed('0iX') @@ -684,7 +685,7 @@ describe('Extmarks buffer api', function() end) it('marks move when using :move #extmarks', function() - curbufmeths.set_extmark(ns, marks[1], 0, 0) + set_extmark(ns, marks[1], 0, 0) feed('A2:1move 2') check_undo_redo(ns, marks[1], 0, 0, 1, 0) -- test codepath when moving lines up @@ -695,7 +696,7 @@ describe('Extmarks buffer api', function() it('marks move when using :move part 2 #extmarks', function() -- make sure we didn't get lucky with the math... feed('A23456') - curbufmeths.set_extmark(ns, marks[1], 1, 0) + set_extmark(ns, marks[1], 1, 0) feed(':2,3move 5') check_undo_redo(ns, marks[1], 1, 0, 3, 0) -- test codepath when moving lines up @@ -706,23 +707,24 @@ describe('Extmarks buffer api', function() it('undo and redo of set and unset marks #extmarks', function() -- Force a new undo head feed('o') - curbufmeths.set_extmark(ns, marks[1], 0, 1) + set_extmark(ns, marks[1], 0, 1) feed('o') - curbufmeths.set_extmark(ns, marks[2], 0, -1) - curbufmeths.set_extmark(ns, marks[3], 0, -1) + set_extmark(ns, marks[2], 0, -1) + set_extmark(ns, marks[3], 0, -1) feed("u") - rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL) + local rv = get_extmarks(ns, {0, 0}, {-1, -1}) eq(1, table.getn(rv)) feed("") - rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL) + rv = get_extmarks(ns, {0, 0}, {-1, -1}) eq(3, table.getn(rv)) -- Test updates feed('o') - curbufmeths.set_extmark(ns, marks[1], positions[1][1], positions[1][2]) - rv = curbufmeths.get_extmarks(ns, marks[1], marks[1], 1) + set_extmark(ns, marks[1], positions[1][1], positions[1][2]) + rv = get_extmarks(ns, marks[1], marks[1], {amount=1}) + eq(1, table.getn(rv)) feed("u") feed("") check_undo_redo(ns, marks[1], 0, 1, positions[1][1], positions[1][2]) @@ -731,80 +733,80 @@ describe('Extmarks buffer api', function() feed('o') curbufmeths.del_extmark(ns, marks[3]) feed("u") - rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL) + rv = get_extmarks(ns, {0, 0}, {-1, -1}) eq(3, table.getn(rv)) feed("") - rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL) + rv = get_extmarks(ns, {0, 0}, {-1, -1}) eq(2, table.getn(rv)) end) it('undo and redo of marks deleted during edits #extmarks', function() -- test extmark_adjust feed('A12345') - curbufmeths.set_extmark(ns, marks[1], 1, 2) + set_extmark(ns, marks[1], 1, 2) feed('dd') check_undo_redo(ns, marks[1], 1, 2, 1, 0) end) it('namespaces work properly #extmarks', function() - rv = curbufmeths.set_extmark(ns, marks[1], positions[1][1], positions[1][2]) + local rv = set_extmark(ns, marks[1], positions[1][1], positions[1][2]) eq(1, rv) - rv = curbufmeths.set_extmark(ns2, marks[1], positions[1][1], positions[1][2]) + rv = set_extmark(ns2, marks[1], positions[1][1], positions[1][2]) eq(1, rv) - rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL) + rv = get_extmarks(ns, {0, 0}, {-1, -1}) eq(1, table.getn(rv)) - rv = curbufmeths.get_extmarks(ns2, {0, 0}, {-1, -1}, ALL) + rv = get_extmarks(ns2, {0, 0}, {-1, -1}) eq(1, table.getn(rv)) -- Set more marks for testing the ranges - rv = curbufmeths.set_extmark(ns, marks[2], positions[2][1], positions[2][2]) - rv = curbufmeths.set_extmark(ns, marks[3], positions[3][1], positions[3][2]) - rv = curbufmeths.set_extmark(ns2, marks[2], positions[2][1], positions[2][2]) - rv = curbufmeths.set_extmark(ns2, marks[3], positions[3][1], positions[3][2]) + set_extmark(ns, marks[2], positions[2][1], positions[2][2]) + set_extmark(ns, marks[3], positions[3][1], positions[3][2]) + set_extmark(ns2, marks[2], positions[2][1], positions[2][2]) + set_extmark(ns2, marks[3], positions[3][1], positions[3][2]) -- get_next (amount set) - rv = curbufmeths.get_extmarks(ns, {0, 0}, positions[2], 1) + rv = get_extmarks(ns, {0, 0}, positions[2], {amount=1}) eq(1, table.getn(rv)) - rv = curbufmeths.get_extmarks(ns2, {0, 0}, positions[2], 1) + rv = get_extmarks(ns2, {0, 0}, positions[2], {amount=1}) eq(1, table.getn(rv)) -- get_prev (amount set) - rv = curbufmeths.get_extmarks(ns, positions[1], {0, 0}, 1) + rv = get_extmarks(ns, positions[1], {0, 0}, {amount=1}) eq(1, table.getn(rv)) - rv = curbufmeths.get_extmarks(ns2, positions[1], {0, 0}, 1) + rv = get_extmarks(ns2, positions[1], {0, 0}, {amount=1}) eq(1, table.getn(rv)) -- get_next (amount not set) - rv = curbufmeths.get_extmarks(ns, positions[1], positions[2], ALL) + rv = get_extmarks(ns, positions[1], positions[2]) eq(2, table.getn(rv)) - rv = curbufmeths.get_extmarks(ns2, positions[1], positions[2], ALL) + rv = get_extmarks(ns2, positions[1], positions[2]) eq(2, table.getn(rv)) -- get_prev (amount not set) - rv = curbufmeths.get_extmarks(ns, positions[2], positions[1], ALL) + rv = get_extmarks(ns, positions[2], positions[1]) eq(2, table.getn(rv)) - rv = curbufmeths.get_extmarks(ns2, positions[2], positions[1], ALL) + rv = get_extmarks(ns2, positions[2], positions[1]) eq(2, table.getn(rv)) curbufmeths.del_extmark(ns, marks[1]) - rv = curbufmeths.get_extmarks(ns, {0, 0}, {-1, -1}, ALL) + rv = get_extmarks(ns, {0, 0}, {-1, -1}) eq(2, table.getn(rv)) curbufmeths.del_extmark(ns2, marks[1]) - rv = curbufmeths.get_extmarks(ns2, {0, 0}, {-1, -1}, ALL) + rv = get_extmarks(ns2, {0, 0}, {-1, -1}) eq(2, table.getn(rv)) end) it('mark set can create unique identifiers #extmarks', function() -- create mark with id 1 - eq(1, curbufmeths.set_extmark(ns, 1, positions[1][1], positions[1][2])) + eq(1, set_extmark(ns, 1, positions[1][1], positions[1][2])) -- ask for unique id, it should be the next one, i e 2 - eq(2, curbufmeths.set_extmark(ns, 0, positions[1][1], positions[1][2])) - eq(3, curbufmeths.set_extmark(ns, 3, positions[2][1], positions[2][2])) - eq(4, curbufmeths.set_extmark(ns, 0, positions[1][1], positions[1][2])) + eq(2, set_extmark(ns, 0, positions[1][1], positions[1][2])) + eq(3, set_extmark(ns, 3, positions[2][1], positions[2][2])) + eq(4, set_extmark(ns, 0, positions[1][1], positions[1][2])) -- mixing manual and allocated id:s are not recommened, but it should -- do something reasonable - eq(6, curbufmeths.set_extmark(ns, 6, positions[2][1], positions[2][2])) - eq(7, curbufmeths.set_extmark(ns, 0, positions[1][1], positions[1][2])) - eq(8, curbufmeths.set_extmark(ns, 0, positions[1][1], positions[1][2])) + eq(6, set_extmark(ns, 6, positions[2][1], positions[2][2])) + eq(7, set_extmark(ns, 0, positions[1][1], positions[1][2])) + eq(8, set_extmark(ns, 0, positions[1][1], positions[1][2])) end) it('auto indenting with enter works #extmarks', function() @@ -814,11 +816,11 @@ describe('Extmarks buffer api', function() feed(':set shiftwidth=2') feed("0iint A {1M1b") -- Set the mark on the M, should move.. - curbufmeths.set_extmark(ns, marks[1], 0, 12) + set_extmark(ns, marks[1], 0, 12) -- Set the mark before the cursor, should stay there - curbufmeths.set_extmark(ns, marks[2], 0, 10) + set_extmark(ns, marks[2], 0, 10) feed("i") - rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + local rv = curbufmeths.get_extmark_by_id(ns, marks[1]) eq({1, 3}, rv) rv = curbufmeths.get_extmark_by_id(ns, marks[2]) eq({0, 10}, rv) @@ -831,9 +833,9 @@ describe('Extmarks buffer api', function() feed(':set shiftwidth=2') -- will force an indent of 2 feed("0iint A {0i1M1") - curbufmeths.set_extmark(ns, marks[1], 1, 1) + set_extmark(ns, marks[1], 1, 1) feed("0i") - rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + local rv = curbufmeths.get_extmark_by_id(ns, marks[1]) eq({1, 3}, rv) check_undo_redo(ns, marks[1], 1, 1, 1, 3) -- now check when cursor at eol @@ -847,9 +849,9 @@ describe('Extmarks buffer api', function() feed(':set autoindent') feed(':set shiftwidth=2') feed("0i") - curbufmeths.set_extmark(ns, marks[1], 0, 3) + set_extmark(ns, marks[1], 0, 3) feed("bi") - rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + local rv = curbufmeths.get_extmark_by_id(ns, marks[1]) eq({0, 1}, rv) check_undo_redo(ns, marks[1], 0, 3, 0, 1) -- check when cursor at eol @@ -863,8 +865,8 @@ describe('Extmarks buffer api', function() feed(':set autoindent') feed(':set shiftwidth=2') feed("0iint A {1M12M2") - curbufmeths.set_extmark(ns, marks[1], 1, 1) - curbufmeths.set_extmark(ns, marks[2], 2, 1) + set_extmark(ns, marks[1], 1, 1) + set_extmark(ns, marks[2], 2, 1) feed('=gg') check_undo_redo(ns, marks[1], 1, 1, 1, 3) check_undo_redo(ns, marks[2], 2, 1, 2, 5) @@ -872,8 +874,8 @@ describe('Extmarks buffer api', function() it('substitutes by deleting inside the replace matches #extmarks_sub', function() -- do_sub in ex_cmds.c - curbufmeths.set_extmark(ns, marks[1], 0, 2) - curbufmeths.set_extmark(ns, marks[2], 0, 3) + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 0, 3) feed(':s/34/xx') check_undo_redo(ns, marks[1], 0, 2, 0, 4) check_undo_redo(ns, marks[2], 0, 3, 0, 4) @@ -881,8 +883,8 @@ describe('Extmarks buffer api', function() it('substitutes when insert text > deleted #extmarks_sub', function() -- do_sub in ex_cmds.c - curbufmeths.set_extmark(ns, marks[1], 0, 2) - curbufmeths.set_extmark(ns, marks[2], 0, 3) + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 0, 3) feed(':s/34/xxx') check_undo_redo(ns, marks[1], 0, 2, 0, 5) check_undo_redo(ns, marks[2], 0, 3, 0, 5) @@ -890,8 +892,8 @@ describe('Extmarks buffer api', function() it('substitutes when marks around eol #extmarks_sub', function() -- do_sub in ex_cmds.c - curbufmeths.set_extmark(ns, marks[1], 0, 4) - curbufmeths.set_extmark(ns, marks[2], 0, 5) + set_extmark(ns, marks[1], 0, 4) + set_extmark(ns, marks[2], 0, 5) feed(':s/5/xxx') check_undo_redo(ns, marks[1], 0, 4, 0, 7) check_undo_redo(ns, marks[2], 0, 5, 0, 7) @@ -901,9 +903,9 @@ describe('Extmarks buffer api', function() -- do_sub in ex_cmds.c feed('Ax34xx') feed('Axxx34') - curbufmeths.set_extmark(ns, marks[1], 0, 2) - curbufmeths.set_extmark(ns, marks[2], 1, 1) - curbufmeths.set_extmark(ns, marks[3], 2, 4) + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 1, 1) + set_extmark(ns, marks[3], 2, 4) feed(':1,3s/34/xxx') check_undo_redo(ns, marks[1], 0, 2, 0, 5) check_undo_redo(ns, marks[2], 1, 1, 1, 4) @@ -913,9 +915,9 @@ describe('Extmarks buffer api', function() it('substitutes multiple matches in a line #extmarks_sub', function() -- do_sub in ex_cmds.c feed('ddi3x3x3') - curbufmeths.set_extmark(ns, marks[1], 0, 0) - curbufmeths.set_extmark(ns, marks[2], 0, 2) - curbufmeths.set_extmark(ns, marks[3], 0, 4) + set_extmark(ns, marks[1], 0, 0) + set_extmark(ns, marks[2], 0, 2) + set_extmark(ns, marks[3], 0, 4) feed(':s/3/yy/g') check_undo_redo(ns, marks[1], 0, 0, 0, 2) check_undo_redo(ns, marks[2], 0, 2, 0, 5) @@ -924,11 +926,11 @@ describe('Extmarks buffer api', function() it('substitions over multiple lines with newline in pattern #extmarks_sub', function() feed('A67890xx') - curbufmeths.set_extmark(ns, marks[1], 0, 3) - curbufmeths.set_extmark(ns, marks[2], 0, 4) - curbufmeths.set_extmark(ns, marks[3], 1, 0) - curbufmeths.set_extmark(ns, marks[4], 1, 5) - curbufmeths.set_extmark(ns, marks[5], 2, 0) + set_extmark(ns, marks[1], 0, 3) + set_extmark(ns, marks[2], 0, 4) + set_extmark(ns, marks[3], 1, 0) + set_extmark(ns, marks[4], 1, 5) + set_extmark(ns, marks[5], 2, 0) feed([[:1,2s:5\n:5 ]]) check_undo_redo(ns, marks[1], 0, 3, 0, 3) check_undo_redo(ns, marks[2], 0, 4, 0, 6) @@ -939,12 +941,12 @@ describe('Extmarks buffer api', function() it('inserting #extmarks_sub', function() feed('A67890xx') - curbufmeths.set_extmark(ns, marks[1], 0, 3) - curbufmeths.set_extmark(ns, marks[2], 0, 4) - curbufmeths.set_extmark(ns, marks[3], 1, 0) - curbufmeths.set_extmark(ns, marks[4], 1, 5) - curbufmeths.set_extmark(ns, marks[5], 2, 0) - curbufmeths.set_extmark(ns, marks[6], 1, 2) + set_extmark(ns, marks[1], 0, 3) + set_extmark(ns, marks[2], 0, 4) + set_extmark(ns, marks[3], 1, 0) + set_extmark(ns, marks[4], 1, 5) + set_extmark(ns, marks[5], 2, 0) + set_extmark(ns, marks[6], 1, 2) feed([[:1,2s:5\n67:X]]) check_undo_redo(ns, marks[1], 0, 3, 0, 3) check_undo_redo(ns, marks[2], 0, 4, 0, 5) @@ -956,11 +958,11 @@ describe('Extmarks buffer api', function() it('substitions with multiple newlines in pattern #extmarks_sub', function() feed('A67890xx') - curbufmeths.set_extmark(ns, marks[1], 0, 4) - curbufmeths.set_extmark(ns, marks[2], 0, 5) - curbufmeths.set_extmark(ns, marks[3], 1, 0) - curbufmeths.set_extmark(ns, marks[4], 1, 5) - curbufmeths.set_extmark(ns, marks[5], 2, 0) + set_extmark(ns, marks[1], 0, 4) + set_extmark(ns, marks[2], 0, 5) + set_extmark(ns, marks[3], 1, 0) + set_extmark(ns, marks[4], 1, 5) + set_extmark(ns, marks[5], 2, 0) feed([[:1,2s:\n.*\n:X]]) check_undo_redo(ns, marks[1], 0, 4, 0, 4) check_undo_redo(ns, marks[2], 0, 5, 0, 6) @@ -971,11 +973,11 @@ describe('Extmarks buffer api', function() it('substitions over multiple lines with replace in substition #extmarks_sub', function() feed('A67890xx') - curbufmeths.set_extmark(ns, marks[1], 0, 1) - curbufmeths.set_extmark(ns, marks[2], 0, 2) - curbufmeths.set_extmark(ns, marks[3], 0, 4) - curbufmeths.set_extmark(ns, marks[4], 1, 0) - curbufmeths.set_extmark(ns, marks[5], 2, 0) + set_extmark(ns, marks[1], 0, 1) + set_extmark(ns, marks[2], 0, 2) + set_extmark(ns, marks[3], 0, 4) + set_extmark(ns, marks[4], 1, 0) + set_extmark(ns, marks[5], 2, 0) feed([[:1,2s:3:\r]]) check_undo_redo(ns, marks[1], 0, 1, 0, 1) check_undo_redo(ns, marks[2], 0, 2, 1, 0) @@ -989,9 +991,9 @@ describe('Extmarks buffer api', function() it('substitions over multiple lines with replace in substition #extmarks_sub', function() feed('Ax3xx') - curbufmeths.set_extmark(ns, marks[1], 1, 0) - curbufmeths.set_extmark(ns, marks[2], 1, 1) - curbufmeths.set_extmark(ns, marks[3], 1, 2) + set_extmark(ns, marks[1], 1, 0) + set_extmark(ns, marks[2], 1, 1) + set_extmark(ns, marks[3], 1, 2) feed([[:2,2s:3:\r]]) check_undo_redo(ns, marks[1], 1, 0, 1, 0) check_undo_redo(ns, marks[2], 1, 1, 2, 0) @@ -1000,11 +1002,11 @@ describe('Extmarks buffer api', function() it('substitions over multiple lines with replace in substition #extmarks_sub', function() feed('Ax3xx') - curbufmeths.set_extmark(ns, marks[1], 0, 1) - curbufmeths.set_extmark(ns, marks[2], 0, 2) - curbufmeths.set_extmark(ns, marks[3], 0, 4) - curbufmeths.set_extmark(ns, marks[4], 1, 1) - curbufmeths.set_extmark(ns, marks[5], 2, 0) + set_extmark(ns, marks[1], 0, 1) + set_extmark(ns, marks[2], 0, 2) + set_extmark(ns, marks[3], 0, 4) + set_extmark(ns, marks[4], 1, 1) + set_extmark(ns, marks[5], 2, 0) feed([[:1,2s:3:\r]]) check_undo_redo(ns, marks[1], 0, 1, 0, 1) check_undo_redo(ns, marks[2], 0, 2, 1, 0) @@ -1018,12 +1020,12 @@ describe('Extmarks buffer api', function() it('substitions with newline in match and sub, delta is 0 #extmarks_sub', function() feed('A67890xx') - curbufmeths.set_extmark(ns, marks[1], 0, 3) - curbufmeths.set_extmark(ns, marks[2], 0, 4) - curbufmeths.set_extmark(ns, marks[3], 0, 5) - curbufmeths.set_extmark(ns, marks[4], 1, 0) - curbufmeths.set_extmark(ns, marks[5], 1, 5) - curbufmeths.set_extmark(ns, marks[6], 2, 0) + set_extmark(ns, marks[1], 0, 3) + set_extmark(ns, marks[2], 0, 4) + set_extmark(ns, marks[3], 0, 5) + set_extmark(ns, marks[4], 1, 0) + set_extmark(ns, marks[5], 1, 5) + set_extmark(ns, marks[6], 2, 0) feed([[:1,1s:5\n:\r]]) check_undo_redo(ns, marks[1], 0, 3, 0, 3) check_undo_redo(ns, marks[2], 0, 4, 1, 0) @@ -1035,12 +1037,12 @@ describe('Extmarks buffer api', function() it('substitions with newline in match and sub, delta > 0 #extmarks_sub', function() feed('A67890xx') - curbufmeths.set_extmark(ns, marks[1], 0, 3) - curbufmeths.set_extmark(ns, marks[2], 0, 4) - curbufmeths.set_extmark(ns, marks[3], 0, 5) - curbufmeths.set_extmark(ns, marks[4], 1, 0) - curbufmeths.set_extmark(ns, marks[5], 1, 5) - curbufmeths.set_extmark(ns, marks[6], 2, 0) + set_extmark(ns, marks[1], 0, 3) + set_extmark(ns, marks[2], 0, 4) + set_extmark(ns, marks[3], 0, 5) + set_extmark(ns, marks[4], 1, 0) + set_extmark(ns, marks[5], 1, 5) + set_extmark(ns, marks[6], 2, 0) feed([[:1,1s:5\n:\r\r]]) check_undo_redo(ns, marks[1], 0, 3, 0, 3) check_undo_redo(ns, marks[2], 0, 4, 2, 0) @@ -1052,13 +1054,13 @@ describe('Extmarks buffer api', function() it('substitions with newline in match and sub, delta < 0 #extmarks_sub', function() feed('A67890xxxx') - curbufmeths.set_extmark(ns, marks[1], 0, 3) - curbufmeths.set_extmark(ns, marks[2], 0, 4) - curbufmeths.set_extmark(ns, marks[3], 0, 5) - curbufmeths.set_extmark(ns, marks[4], 1, 0) - curbufmeths.set_extmark(ns, marks[5], 1, 5) - curbufmeths.set_extmark(ns, marks[6], 2, 1) - curbufmeths.set_extmark(ns, marks[7], 3, 0) + set_extmark(ns, marks[1], 0, 3) + set_extmark(ns, marks[2], 0, 4) + set_extmark(ns, marks[3], 0, 5) + set_extmark(ns, marks[4], 1, 0) + set_extmark(ns, marks[5], 1, 5) + set_extmark(ns, marks[6], 2, 1) + set_extmark(ns, marks[7], 3, 0) feed([[:1,2s:5\n.*\n:\r]]) check_undo_redo(ns, marks[1], 0, 3, 0, 3) check_undo_redo(ns, marks[2], 0, 4, 1, 0) @@ -1071,12 +1073,12 @@ describe('Extmarks buffer api', function() it('substitions with backrefs, newline inserted into sub #extmarks_sub', function() feed('A67890xxxx') - curbufmeths.set_extmark(ns, marks[1], 0, 3) - curbufmeths.set_extmark(ns, marks[2], 0, 4) - curbufmeths.set_extmark(ns, marks[3], 0, 5) - curbufmeths.set_extmark(ns, marks[4], 1, 0) - curbufmeths.set_extmark(ns, marks[5], 1, 5) - curbufmeths.set_extmark(ns, marks[6], 2, 0) + set_extmark(ns, marks[1], 0, 3) + set_extmark(ns, marks[2], 0, 4) + set_extmark(ns, marks[3], 0, 5) + set_extmark(ns, marks[4], 1, 0) + set_extmark(ns, marks[5], 1, 5) + set_extmark(ns, marks[6], 2, 0) feed([[:1,1s:5\(\n\):\0\1]]) check_undo_redo(ns, marks[1], 0, 3, 0, 3) check_undo_redo(ns, marks[2], 0, 4, 2, 0) @@ -1087,8 +1089,8 @@ describe('Extmarks buffer api', function() end) it('substitions a ^ #extmarks_sub', function() - curbufmeths.set_extmark(ns, marks[1], 0, 0) - curbufmeths.set_extmark(ns, marks[2], 0, 1) + set_extmark(ns, marks[1], 0, 0) + set_extmark(ns, marks[2], 0, 1) feed([[:s:^:x]]) check_undo_redo(ns, marks[1], 0, 0, 0, 1) check_undo_redo(ns, marks[2], 0, 1, 0, 2) @@ -1097,11 +1099,11 @@ describe('Extmarks buffer api', function() it('using without increase in order of magnitude #extmarks_inc_dec', function() -- do_addsub in ops.c feed('ddiabc998xxxTc') - curbufmeths.set_extmark(ns, marks[1], 0, 2) - curbufmeths.set_extmark(ns, marks[2], 0, 3) - curbufmeths.set_extmark(ns, marks[3], 0, 5) - curbufmeths.set_extmark(ns, marks[4], 0, 6) - curbufmeths.set_extmark(ns, marks[5], 0, 7) + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 0, 3) + set_extmark(ns, marks[3], 0, 5) + set_extmark(ns, marks[4], 0, 6) + set_extmark(ns, marks[5], 0, 7) feed('') check_undo_redo(ns, marks[1], 0, 2, 0, 2) check_undo_redo(ns, marks[2], 0, 3, 0, 6) @@ -1113,11 +1115,11 @@ describe('Extmarks buffer api', function() it('using when increase in order of magnitude #extmarks_inc_dec', function() -- do_addsub in ops.c feed('ddiabc999xxxTc') - curbufmeths.set_extmark(ns, marks[1], 0, 2) - curbufmeths.set_extmark(ns, marks[2], 0, 3) - curbufmeths.set_extmark(ns, marks[3], 0, 5) - curbufmeths.set_extmark(ns, marks[4], 0, 6) - curbufmeths.set_extmark(ns, marks[5], 0, 7) + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 0, 3) + set_extmark(ns, marks[3], 0, 5) + set_extmark(ns, marks[4], 0, 6) + set_extmark(ns, marks[5], 0, 7) feed('') check_undo_redo(ns, marks[1], 0, 2, 0, 2) check_undo_redo(ns, marks[2], 0, 3, 0, 7) @@ -1128,11 +1130,11 @@ describe('Extmarks buffer api', function() it('using when negative and without decrease in order of magnitude #extmarks_inc_dec', function() feed('ddiabc-999xxxT-') - curbufmeths.set_extmark(ns, marks[1], 0, 2) - curbufmeths.set_extmark(ns, marks[2], 0, 3) - curbufmeths.set_extmark(ns, marks[3], 0, 6) - curbufmeths.set_extmark(ns, marks[4], 0, 7) - curbufmeths.set_extmark(ns, marks[5], 0, 8) + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 0, 3) + set_extmark(ns, marks[3], 0, 6) + set_extmark(ns, marks[4], 0, 7) + set_extmark(ns, marks[5], 0, 8) feed('') check_undo_redo(ns, marks[1], 0, 2, 0, 2) check_undo_redo(ns, marks[2], 0, 3, 0, 7) @@ -1143,11 +1145,11 @@ describe('Extmarks buffer api', function() it('using when negative and decrease in order of magnitude #extmarks_inc_dec', function() feed('ddiabc-1000xxxT-') - curbufmeths.set_extmark(ns, marks[1], 0, 2) - curbufmeths.set_extmark(ns, marks[2], 0, 3) - curbufmeths.set_extmark(ns, marks[3], 0, 7) - curbufmeths.set_extmark(ns, marks[4], 0, 8) - curbufmeths.set_extmark(ns, marks[5], 0, 9) + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 0, 3) + set_extmark(ns, marks[3], 0, 7) + set_extmark(ns, marks[4], 0, 8) + set_extmark(ns, marks[5], 0, 9) feed('') check_undo_redo(ns, marks[1], 0, 2, 0, 2) check_undo_redo(ns, marks[2], 0, 3, 0, 7) @@ -1159,11 +1161,11 @@ describe('Extmarks buffer api', function() it('using without decrease in order of magnitude #extmarks_inc_dec', function() -- do_addsub in ops.c feed('ddiabc999xxxTc') - curbufmeths.set_extmark(ns, marks[1], 0, 2) - curbufmeths.set_extmark(ns, marks[2], 0, 3) - curbufmeths.set_extmark(ns, marks[3], 0, 5) - curbufmeths.set_extmark(ns, marks[4], 0, 6) - curbufmeths.set_extmark(ns, marks[5], 0, 7) + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 0, 3) + set_extmark(ns, marks[3], 0, 5) + set_extmark(ns, marks[4], 0, 6) + set_extmark(ns, marks[5], 0, 7) feed('') check_undo_redo(ns, marks[1], 0, 2, 0, 2) check_undo_redo(ns, marks[2], 0, 3, 0, 6) @@ -1175,11 +1177,11 @@ describe('Extmarks buffer api', function() it('using when decrease in order of magnitude #extmarks_inc_dec', function() -- do_addsub in ops.c feed('ddiabc1000xxxTc') - curbufmeths.set_extmark(ns, marks[1], 0, 2) - curbufmeths.set_extmark(ns, marks[2], 0, 3) - curbufmeths.set_extmark(ns, marks[3], 0, 6) - curbufmeths.set_extmark(ns, marks[4], 0, 7) - curbufmeths.set_extmark(ns, marks[5], 0, 8) + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 0, 3) + set_extmark(ns, marks[3], 0, 6) + set_extmark(ns, marks[4], 0, 7) + set_extmark(ns, marks[5], 0, 8) feed('') check_undo_redo(ns, marks[1], 0, 2, 0, 2) check_undo_redo(ns, marks[2], 0, 3, 0, 6) @@ -1190,11 +1192,11 @@ describe('Extmarks buffer api', function() it('using when negative and without increase in order of magnitude #extmarks_inc_dec', function() feed('ddiabc-998xxxT-') - curbufmeths.set_extmark(ns, marks[1], 0, 2) - curbufmeths.set_extmark(ns, marks[2], 0, 3) - curbufmeths.set_extmark(ns, marks[3], 0, 6) - curbufmeths.set_extmark(ns, marks[4], 0, 7) - curbufmeths.set_extmark(ns, marks[5], 0, 8) + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 0, 3) + set_extmark(ns, marks[3], 0, 6) + set_extmark(ns, marks[4], 0, 7) + set_extmark(ns, marks[5], 0, 8) feed('') check_undo_redo(ns, marks[1], 0, 2, 0, 2) check_undo_redo(ns, marks[2], 0, 3, 0, 7) @@ -1205,11 +1207,11 @@ describe('Extmarks buffer api', function() it('using when negative and increase in order of magnitude #extmarks_inc_dec', function() feed('ddiabc-999xxxT-') - curbufmeths.set_extmark(ns, marks[1], 0, 2) - curbufmeths.set_extmark(ns, marks[2], 0, 3) - curbufmeths.set_extmark(ns, marks[3], 0, 6) - curbufmeths.set_extmark(ns, marks[4], 0, 7) - curbufmeths.set_extmark(ns, marks[5], 0, 8) + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 0, 3) + set_extmark(ns, marks[3], 0, 6) + set_extmark(ns, marks[4], 0, 7) + set_extmark(ns, marks[5], 0, 8) feed('') check_undo_redo(ns, marks[1], 0, 2, 0, 2) check_undo_redo(ns, marks[2], 0, 3, 0, 8) @@ -1218,38 +1220,34 @@ describe('Extmarks buffer api', function() check_undo_redo(ns, marks[5], 0, 8, 0, 9) end) - -- TODO catch exceptions - pending('throws consistent error codes #todo', function() + it('throws consistent error codes', function() local ns_invalid = ns2 + 1 - rv = curbufmeths.set_extmark(ns_invalid, marks[1], positions[1][1], positions[1][2]) - rv = curbufmeths.del_extmark(ns_invalid, marks[1]) - rv = curbufmeths.get_extmarks(ns_invalid, positions[1], positions[2], ALL) - rv = curbufmeths.get_extmark_by_id(ns_invalid, marks[1]) - + eq("Invalid ns_id", pcall_err(set_extmark, ns_invalid, marks[1], positions[1][1], positions[1][2])) + eq("Invalid ns_id", pcall_err(curbufmeths.del_extmark, ns_invalid, marks[1])) + eq("Invalid ns_id", pcall_err(get_extmarks, ns_invalid, positions[1], positions[2])) + eq("Invalid ns_id", pcall_err(curbufmeths.get_extmark_by_id, ns_invalid, marks[1])) end) it('when col = line-length, set the mark on eol #extmarks', function() - curbufmeths.set_extmark(ns, marks[1], 0, -1) - rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + set_extmark(ns, marks[1], 0, -1) + local rv = curbufmeths.get_extmark_by_id(ns, marks[1]) eq({0, init_text:len()}, rv) -- Test another - curbufmeths.set_extmark(ns, marks[1], 0, -1) + set_extmark(ns, marks[1], 0, -1) rv = curbufmeths.get_extmark_by_id(ns, marks[1]) eq({0, init_text:len()}, rv) end) it('when col = line-length, set the mark on eol #extmarks', function() local invalid_col = init_text:len() + 1 - eq({false, "col value outside range"}, meth_pcall(curbufmeths.set_extmark, ns, marks[1], 0, invalid_col)) + eq("col value outside range", pcall_err(set_extmark, ns, marks[1], 0, invalid_col)) end) - -- TODO(bfredl): decide what to do with this - pending('when line > line, set the mark on end of buffer #extmarks', function() + it('when line > line_count, throw error #extmarks', function() local invalid_col = init_text:len() + 1 - local invalid_lnum = 3 -- line1 ends in an eol. so line 2 contains a valid position (eol)? - curbufmeths.set_extmark(ns, marks[1], invalid_lnum, invalid_col) - rv = curbufmeths.get_extmark_by_id(ns, marks[1]) - eq({2, 1}, rv) + local invalid_lnum = 3 + eq('line value outside range', pcall_err(set_extmark, ns, marks[1], invalid_lnum, invalid_col)) + eq({}, curbufmeths.get_extmark_by_id(ns, marks[1])) end) it('bug from check_col in extmark_set #extmarks_sub', function() @@ -1259,7 +1257,7 @@ describe('Extmarks buffer api', function() -- check_col and check_lnum only when they are required. feed('A67890xx') feed('A1234567890xx') - curbufmeths.set_extmark(ns, marks[1], 3, 4) + set_extmark(ns, marks[1], 3, 4) feed([[:1,5s:5\n:5 ]]) check_undo_redo(ns, marks[1], 3, 4, 2, 6) end) @@ -1284,7 +1282,7 @@ describe('Extmarks buffer api with many marks', function() local q = 0 for i = 0,29 do for j = 0,i do - local id = curbufmeths.set_extmark(ns,0, i,j) + local id = set_extmark(ns,0, i,j) eq(nil, ns_marks[ns][id]) ok(id > 0) ns_marks[ns][id] = {i,j} @@ -1298,7 +1296,7 @@ describe('Extmarks buffer api with many marks', function() end) local function get_marks(ns) - local mark_list = curbufmeths.get_extmarks(ns, 0, -1, -1) + local mark_list = get_extmarks(ns, 0, -1) local marks = {} for _, mark in ipairs(mark_list) do local id, row, col = unpack(mark) @@ -1362,4 +1360,10 @@ describe('Extmarks buffer api with many marks', function() eq(ns_marks[ns1], get_marks(ns1)) eq(ns_marks[ns2], get_marks(ns2)) end) + + it("can wipe buffer #extmarks", function() + command('bwipe!') + eq({}, get_marks(ns1)) + eq({}, get_marks(ns2)) + end) end) diff --git a/test/functional/legacy/046_multi_line_regexps_spec.lua b/test/functional/legacy/046_multi_line_regexps_spec.lua index 9d3ee57b46..30ec76ea3e 100644 --- a/test/functional/legacy/046_multi_line_regexps_spec.lua +++ b/test/functional/legacy/046_multi_line_regexps_spec.lua @@ -8,22 +8,22 @@ local expect = helpers.expect describe('multi-line regexp', function() setup(clear) - it('is working #fail', function() + it('is working', function() insert([[ -1 aa -bb -cc -2 dd -ee -3 ef -gh -4 ij -5 a8 -8b c9 -9d -6 e7 -77f -xxxxx]]) + 1 aa + bb + cc + 2 dd + ee + 3 ef + gh + 4 ij + 5 a8 + 8b c9 + 9d + 6 e7 + 77f + xxxxx]]) -- Test if replacing a line break works with a back reference feed([[:/^1/,/^2/s/\n\(.\)/ \1/]]) diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua index 0136e4e7e0..b841574643 100644 --- a/test/functional/ui/inccommand_spec.lua +++ b/test/functional/ui/inccommand_spec.lua @@ -131,7 +131,7 @@ describe(":substitute, inccommand=split interactivity", function() end) end) -describe(":substitute, 'inccommand' preserves #inc", function() +describe(":substitute, 'inccommand' preserves", function() before_each(clear) it('listed buffers (:ls)', function() @@ -293,7 +293,7 @@ describe(":substitute, 'inccommand' preserves #inc", function() end) -describe(":substitute, 'inccommand' preserves undo #inc", function() +describe(":substitute, 'inccommand' preserves undo", function() local cases = { "", "split", "nosplit" } local substrings = { @@ -1962,7 +1962,7 @@ describe(":substitute", function() clear() end) - it("inccommand=split, highlights multiline substitutions #inc2", function() + it("inccommand=split, highlights multiline substitutions", function() common_setup(screen, "split", multiline_text) feed("gg") @@ -2024,7 +2024,7 @@ describe(":substitute", function() ]]) end) - it("inccommand=nosplit, highlights multiline substitutions #inc2", function() + it("inccommand=nosplit, highlights multiline substitutions", function() common_setup(screen, "nosplit", multiline_text) feed("gg") @@ -2117,7 +2117,7 @@ describe(":substitute", function() ]]) end) - it("inccommand=split, with \\zs #inc", function() + it("inccommand=split, with \\zs", function() common_setup(screen, "split", multiline_text) feed("gg") @@ -2141,7 +2141,7 @@ describe(":substitute", function() ]]) end) - it("inccommand=nosplit, with \\zs #inc", function() + it("inccommand=nosplit, with \\zs", function() common_setup(screen, "nosplit", multiline_text) feed("gg") @@ -2212,7 +2212,7 @@ describe(":substitute", function() ]]) end) - it("inccommand=split, contraction of lines #inc2", function() + it("inccommand=split, contraction of lines", function() local text = [[ T T123 T T123 T2T TT T23423424 x @@ -2261,7 +2261,7 @@ describe(":substitute", function() ]]) end) - it("inccommand=nosplit, contraction of lines #inc2", function() + it("inccommand=nosplit, contraction of lines", function() local text = [[ T T123 T T123 T2T TT T23423424 x diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index 2c50bcb97b..7840ba9167 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -817,6 +817,7 @@ describe('ui/mouse/input', function() feed_command('syntax match NonText "cats" conceal cchar=X') feed_command('syntax match NonText "x" conceal cchar=>') + -- First column is there to retain the tabs. insert([[ |Section *t1* | *t2* *t3* *t4* -- cgit From 00dc12c5d8454a2d3c6806710f63bbb446076e96 Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Wed, 13 Nov 2019 12:55:26 -0800 Subject: lua LSP client: initial implementation (#11336) Mainly configuration and RPC infrastructure can be considered "done". Specific requests and their callbacks will be improved later (and also served by plugins). There are also some TODO:s for the client itself, like incremental updates. Co-authored by at-tjdevries and at-h-michael, with many review/suggestion contributions. --- test/functional/fixtures/lsp-test-rpc-server.lua | 424 +++++++++++++++ test/functional/lua/uri_spec.lua | 107 ++++ test/functional/lua/vim_spec.lua | 72 +++ test/functional/plugin/lsp/lsp_spec.lua | 634 +++++++++++++++++++++++ 4 files changed, 1237 insertions(+) create mode 100644 test/functional/fixtures/lsp-test-rpc-server.lua create mode 100644 test/functional/lua/uri_spec.lua create mode 100644 test/functional/plugin/lsp/lsp_spec.lua (limited to 'test') diff --git a/test/functional/fixtures/lsp-test-rpc-server.lua b/test/functional/fixtures/lsp-test-rpc-server.lua new file mode 100644 index 0000000000..971e61b072 --- /dev/null +++ b/test/functional/fixtures/lsp-test-rpc-server.lua @@ -0,0 +1,424 @@ +local protocol = require 'vim.lsp.protocol' + +-- Internal utility methods. + +-- TODO replace with a better implementation. +local function json_encode(data) + local status, result = pcall(vim.fn.json_encode, data) + if status then + return result + else + return nil, result + end +end +local function json_decode(data) + local status, result = pcall(vim.fn.json_decode, data) + if status then + return result + else + return nil, result + end +end + +local function message_parts(sep, ...) + local parts = {} + for i = 1, select("#", ...) do + local arg = select(i, ...) + if arg ~= nil then + table.insert(parts, arg) + end + end + return table.concat(parts, sep) +end + +-- Assert utility methods + +local function assert_eq(a, b, ...) + if not vim.deep_equal(a, b) then + error(message_parts(": ", + ..., "assert_eq failed", + string.format("left == %q, right == %q", vim.inspect(a), vim.inspect(b)) + )) + end +end + +local function format_message_with_content_length(encoded_message) + return table.concat { + 'Content-Length: '; tostring(#encoded_message); '\r\n\r\n'; + encoded_message; + } +end + +-- Server utility methods. + +local function read_message() + local line = io.read("*l") + local length = line:lower():match("content%-length:%s*(%d+)") + return assert(json_decode(io.read(2 + length):sub(2)), "read_message.json_decode") +end + +local function send(payload) + io.stdout:write(format_message_with_content_length(json_encode(payload))) +end + +local function respond(id, err, result) + assert(type(id) == 'number', "id must be a number") + send { jsonrpc = "2.0"; id = id, error = err, result = result } +end + +local function notify(method, params) + assert(type(method) == 'string', "method must be a string") + send { method = method, params = params or {} } +end + +local function expect_notification(method, params, ...) + local message = read_message() + assert_eq(method, message.method, + ..., "expect_notification", "method") + assert_eq(params, message.params, + ..., "expect_notification", method, "params") + assert_eq({jsonrpc = "2.0"; method=method, params=params}, message, + ..., "expect_notification", "message") +end + +local function expect_request(method, callback, ...) + local req = read_message() + assert_eq(method, req.method, + ..., "expect_request", "method") + local err, result = callback(req.params) + respond(req.id, err, result) +end + +io.stderr:setvbuf("no") + +local function skeleton(config) + local on_init = assert(config.on_init) + local body = assert(config.body) + expect_request("initialize", function(params) + return nil, on_init(params) + end) + expect_notification("initialized", {}) + body() + expect_request("shutdown", function() + return nil, {} + end) + expect_notification("exit", nil) +end + +-- The actual tests. + +local tests = {} + +function tests.basic_init() + skeleton { + on_init = function(_params) + return { capabilities = {} } + end; + body = function() + notify('test') + end; + } +end + +function tests.basic_check_capabilities() + skeleton { + on_init = function(params) + local expected_capabilities = protocol.make_client_capabilities() + assert_eq(params.capabilities, expected_capabilities) + return { + capabilities = { + textDocumentSync = protocol.TextDocumentSyncKind.Full; + } + } + end; + body = function() + end; + } +end + +function tests.basic_finish() + skeleton { + on_init = function(params) + local expected_capabilities = protocol.make_client_capabilities() + assert_eq(params.capabilities, expected_capabilities) + return { + capabilities = { + textDocumentSync = protocol.TextDocumentSyncKind.Full; + } + } + end; + body = function() + expect_notification("finish") + notify('finish') + end; + } +end + +function tests.basic_check_buffer_open() + skeleton { + on_init = function(params) + local expected_capabilities = protocol.make_client_capabilities() + assert_eq(params.capabilities, expected_capabilities) + return { + capabilities = { + textDocumentSync = protocol.TextDocumentSyncKind.Full; + } + } + end; + body = function() + notify('start') + expect_notification('textDocument/didOpen', { + textDocument = { + languageId = ""; + text = table.concat({"testing"; "123"}, "\n"); + uri = "file://"; + version = 0; + }; + }) + expect_notification("finish") + notify('finish') + end; + } +end + +function tests.basic_check_buffer_open_and_change() + skeleton { + on_init = function(params) + local expected_capabilities = protocol.make_client_capabilities() + assert_eq(params.capabilities, expected_capabilities) + return { + capabilities = { + textDocumentSync = protocol.TextDocumentSyncKind.Full; + } + } + end; + body = function() + notify('start') + expect_notification('textDocument/didOpen', { + textDocument = { + languageId = ""; + text = table.concat({"testing"; "123"}, "\n"); + uri = "file://"; + version = 0; + }; + }) + expect_notification('textDocument/didChange', { + textDocument = { + uri = "file://"; + version = 3; + }; + contentChanges = { + { text = table.concat({"testing"; "boop"}, "\n"); }; + } + }) + expect_notification("finish") + notify('finish') + end; + } +end + +function tests.basic_check_buffer_open_and_change_multi() + skeleton { + on_init = function(params) + local expected_capabilities = protocol.make_client_capabilities() + assert_eq(params.capabilities, expected_capabilities) + return { + capabilities = { + textDocumentSync = protocol.TextDocumentSyncKind.Full; + } + } + end; + body = function() + notify('start') + expect_notification('textDocument/didOpen', { + textDocument = { + languageId = ""; + text = table.concat({"testing"; "123"}, "\n"); + uri = "file://"; + version = 0; + }; + }) + expect_notification('textDocument/didChange', { + textDocument = { + uri = "file://"; + version = 3; + }; + contentChanges = { + { text = table.concat({"testing"; "321"}, "\n"); }; + } + }) + expect_notification('textDocument/didChange', { + textDocument = { + uri = "file://"; + version = 4; + }; + contentChanges = { + { text = table.concat({"testing"; "boop"}, "\n"); }; + } + }) + expect_notification("finish") + notify('finish') + end; + } +end + +function tests.basic_check_buffer_open_and_change_multi_and_close() + skeleton { + on_init = function(params) + local expected_capabilities = protocol.make_client_capabilities() + assert_eq(params.capabilities, expected_capabilities) + return { + capabilities = { + textDocumentSync = protocol.TextDocumentSyncKind.Full; + } + } + end; + body = function() + notify('start') + expect_notification('textDocument/didOpen', { + textDocument = { + languageId = ""; + text = table.concat({"testing"; "123"}, "\n"); + uri = "file://"; + version = 0; + }; + }) + expect_notification('textDocument/didChange', { + textDocument = { + uri = "file://"; + version = 3; + }; + contentChanges = { + { text = table.concat({"testing"; "321"}, "\n"); }; + } + }) + expect_notification('textDocument/didChange', { + textDocument = { + uri = "file://"; + version = 4; + }; + contentChanges = { + { text = table.concat({"testing"; "boop"}, "\n"); }; + } + }) + expect_notification('textDocument/didClose', { + textDocument = { + uri = "file://"; + }; + }) + expect_notification("finish") + notify('finish') + end; + } +end + +function tests.basic_check_buffer_open_and_change_incremental() + skeleton { + on_init = function(params) + local expected_capabilities = protocol.make_client_capabilities() + assert_eq(params.capabilities, expected_capabilities) + return { + capabilities = { + textDocumentSync = protocol.TextDocumentSyncKind.Incremental; + } + } + end; + body = function() + notify('start') + expect_notification('textDocument/didOpen', { + textDocument = { + languageId = ""; + text = table.concat({"testing"; "123"}, "\n"); + uri = "file://"; + version = 0; + }; + }) + expect_notification('textDocument/didChange', { + textDocument = { + uri = "file://"; + version = 3; + }; + contentChanges = { + { + range = { + start = { line = 1; character = 0; }; + ["end"] = { line = 2; character = 0; }; + }; + rangeLength = 4; + text = "boop\n"; + }; + } + }) + expect_notification("finish") + notify('finish') + end; + } +end + +function tests.basic_check_buffer_open_and_change_incremental_editting() + skeleton { + on_init = function(params) + local expected_capabilities = protocol.make_client_capabilities() + assert_eq(params.capabilities, expected_capabilities) + return { + capabilities = { + textDocumentSync = protocol.TextDocumentSyncKind.Incremental; + } + } + end; + body = function() + notify('start') + expect_notification('textDocument/didOpen', { + textDocument = { + languageId = ""; + text = table.concat({"testing"; "123"}, "\n"); + uri = "file://"; + version = 0; + }; + }) + expect_notification('textDocument/didChange', { + textDocument = { + uri = "file://"; + version = 3; + }; + contentChanges = { + { + range = { + start = { line = 0; character = 0; }; + ["end"] = { line = 1; character = 0; }; + }; + rangeLength = 4; + text = "testing\n\n"; + }; + } + }) + expect_notification("finish") + notify('finish') + end; + } +end + +function tests.invalid_header() + io.stdout:write("Content-length: \r\n") +end + +-- Tests will be indexed by TEST_NAME + +local kill_timer = vim.loop.new_timer() +kill_timer:start(_G.TIMEOUT or 1e3, 0, function() + kill_timer:stop() + kill_timer:close() + io.stderr:write("TIMEOUT") + os.exit(100) +end) + +local test_name = _G.TEST_NAME -- lualint workaround +assert(type(test_name) == 'string', 'TEST_NAME must be specified.') +local status, err = pcall(assert(tests[test_name], "Test not found")) +kill_timer:stop() +kill_timer:close() +if not status then + io.stderr:write(err) + os.exit(1) +end +os.exit(0) diff --git a/test/functional/lua/uri_spec.lua b/test/functional/lua/uri_spec.lua new file mode 100644 index 0000000000..19b1eb1f61 --- /dev/null +++ b/test/functional/lua/uri_spec.lua @@ -0,0 +1,107 @@ +local helpers = require('test.functional.helpers')(after_each) +local clear = helpers.clear +local exec_lua = helpers.exec_lua +local eq = helpers.eq + +describe('URI methods', function() + before_each(function() + clear() + end) + + describe('file path to uri', function() + describe('encode Unix file path', function() + it('file path includes only ascii charactors', function() + exec_lua("filepath = '/Foo/Bar/Baz.txt'") + + eq('file:///Foo/Bar/Baz.txt', exec_lua("return vim.uri_from_fname(filepath)")) + end) + + it('file path including white space', function() + exec_lua("filepath = '/Foo /Bar/Baz.txt'") + + eq('file:///Foo%20/Bar/Baz.txt', exec_lua("return vim.uri_from_fname(filepath)")) + end) + + it('file path including Unicode charactors', function() + exec_lua("filepath = '/xy/åäö/ɧ/汉语/↥/🤦/🦄/å/بِيَّ.txt'") + + -- The URI encoding should be case-insensitive + eq('file:///xy/%c3%a5%c3%a4%c3%b6/%c9%a7/%e6%b1%89%e8%af%ad/%e2%86%a5/%f0%9f%a4%a6/%f0%9f%a6%84/a%cc%8a/%d8%a8%d9%90%d9%8a%d9%8e%d9%91.txt', exec_lua("return vim.uri_from_fname(filepath)")) + end) + end) + + describe('encode Windows filepath', function() + it('file path includes only ascii charactors', function() + exec_lua([[filepath = 'C:\\Foo\\Bar\\Baz.txt']]) + + eq('file:///C:/Foo/Bar/Baz.txt', exec_lua("return vim.uri_from_fname(filepath)")) + end) + + it('file path including white space', function() + exec_lua([[filepath = 'C:\\Foo \\Bar\\Baz.txt']]) + + eq('file:///C:/Foo%20/Bar/Baz.txt', exec_lua("return vim.uri_from_fname(filepath)")) + end) + + it('file path including Unicode charactors', function() + exec_lua([[filepath = 'C:\\xy\\åäö\\ɧ\\汉语\\↥\\🤦\\🦄\\å\\بِيَّ.txt']]) + + eq('file:///C:/xy/%c3%a5%c3%a4%c3%b6/%c9%a7/%e6%b1%89%e8%af%ad/%e2%86%a5/%f0%9f%a4%a6/%f0%9f%a6%84/a%cc%8a/%d8%a8%d9%90%d9%8a%d9%8e%d9%91.txt', exec_lua("return vim.uri_from_fname(filepath)")) + end) + end) + end) + + describe('uri to filepath', function() + describe('decode Unix file path', function() + it('file path includes only ascii charactors', function() + exec_lua("uri = 'file:///Foo/Bar/Baz.txt'") + + eq('/Foo/Bar/Baz.txt', exec_lua("return vim.uri_to_fname(uri)")) + end) + + it('file path including white space', function() + exec_lua("uri = 'file:///Foo%20/Bar/Baz.txt'") + + eq('/Foo /Bar/Baz.txt', exec_lua("return vim.uri_to_fname(uri)")) + end) + + it('file path including Unicode charactors', function() + local test_case = [[ + local uri = 'file:///xy/%C3%A5%C3%A4%C3%B6/%C9%A7/%E6%B1%89%E8%AF%AD/%E2%86%A5/%F0%9F%A4%A6/%F0%9F%A6%84/a%CC%8A/%D8%A8%D9%90%D9%8A%D9%8E%D9%91.txt' + return vim.uri_to_fname(uri) + ]] + + eq('/xy/åäö/ɧ/汉语/↥/🤦/🦄/å/بِيَّ.txt', exec_lua(test_case)) + end) + end) + + describe('decode Windows filepath', function() + it('file path includes only ascii charactors', function() + local test_case = [[ + local uri = 'file:///C:/Foo/Bar/Baz.txt' + return vim.uri_to_fname(uri) + ]] + + eq('C:\\Foo\\Bar\\Baz.txt', exec_lua(test_case)) + end) + + it('file path including white space', function() + local test_case = [[ + local uri = 'file:///C:/Foo%20/Bar/Baz.txt' + return vim.uri_to_fname(uri) + ]] + + eq('C:\\Foo \\Bar\\Baz.txt', exec_lua(test_case)) + end) + + it('file path including Unicode charactors', function() + local test_case = [[ + local uri = 'file:///C:/xy/%C3%A5%C3%A4%C3%B6/%C9%A7/%E6%B1%89%E8%AF%AD/%E2%86%A5/%F0%9F%A4%A6/%F0%9F%A6%84/a%CC%8A/%D8%A8%D9%90%D9%8A%D9%8E%D9%91.txt' + return vim.uri_to_fname(uri) + ]] + + eq('C:\\xy\\åäö\\ɧ\\汉语\\↥\\🤦\\🦄\\å\\بِيَّ.txt', exec_lua(test_case)) + end) + end) + end) +end) diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index a25ae1d2c0..028f2dcd52 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -305,6 +305,78 @@ describe('lua stdlib', function() pcall_err(exec_lua, [[return vim.pesc(2)]])) end) + it('vim.tbl_keys', function() + eq({}, exec_lua("return vim.tbl_keys({})")) + for _, v in pairs(exec_lua("return vim.tbl_keys({'a', 'b', 'c'})")) do + eq(true, exec_lua("return vim.tbl_contains({ 1, 2, 3 }, ...)", v)) + end + for _, v in pairs(exec_lua("return vim.tbl_keys({a=1, b=2, c=3})")) do + eq(true, exec_lua("return vim.tbl_contains({ 'a', 'b', 'c' }, ...)", v)) + end + end) + + it('vim.tbl_values', function() + eq({}, exec_lua("return vim.tbl_values({})")) + for _, v in pairs(exec_lua("return vim.tbl_values({'a', 'b', 'c'})")) do + eq(true, exec_lua("return vim.tbl_contains({ 'a', 'b', 'c' }, ...)", v)) + end + for _, v in pairs(exec_lua("return vim.tbl_values({a=1, b=2, c=3})")) do + eq(true, exec_lua("return vim.tbl_contains({ 1, 2, 3 }, ...)", v)) + end + end) + + it('vim.tbl_islist', function() + eq(NIL, exec_lua("return vim.tbl_islist({})")) + eq(true, exec_lua("return vim.tbl_islist({'a', 'b', 'c'})")) + eq(false, exec_lua("return vim.tbl_islist({'a', '32', a='hello', b='baz'})")) + eq(false, exec_lua("return vim.tbl_islist({1, a='hello', b='baz'})")) + eq(false, exec_lua("return vim.tbl_islist({a='hello', b='baz', 1})")) + eq(false, exec_lua("return vim.tbl_islist({1, 2, nil, a='hello'})")) + end) + + it('vim.tbl_isempty', function() + eq(true, exec_lua("return vim.tbl_isempty({})")) + eq(false, exec_lua("return vim.tbl_isempty({ 1, 2, 3 })")) + eq(false, exec_lua("return vim.tbl_isempty({a=1, b=2, c=3})")) + end) + + it('vim.deep_equal', function() + eq(true, exec_lua [[ return vim.deep_equal({a=1}, {a=1}) ]]) + eq(true, exec_lua [[ return vim.deep_equal({a={b=1}}, {a={b=1}}) ]]) + eq(true, exec_lua [[ return vim.deep_equal({a={b={nil}}}, {a={b={}}}) ]]) + eq(true, exec_lua [[ return vim.deep_equal({a=1, [5]=5}, {nil,nil,nil,nil,5,a=1}) ]]) + eq(false, exec_lua [[ return vim.deep_equal(1, {nil,nil,nil,nil,5,a=1}) ]]) + eq(false, exec_lua [[ return vim.deep_equal(1, 3) ]]) + eq(false, exec_lua [[ return vim.deep_equal(nil, 3) ]]) + eq(false, exec_lua [[ return vim.deep_equal({a=1}, {a=2}) ]]) + end) + + it('vim.list_extend', function() + eq({1,2,3}, exec_lua [[ return vim.list_extend({1}, {2,3}) ]]) + eq('Error executing lua: .../shared.lua: src must be a table', + pcall_err(exec_lua, [[ return vim.list_extend({1}, nil) ]])) + eq({1,2}, exec_lua [[ return vim.list_extend({1}, {2;a=1}) ]]) + eq(true, exec_lua [[ local a = {1} return vim.list_extend(a, {2;a=1}) == a ]]) + end) + + it('vim.tbl_add_reverse_lookup', function() + eq(true, exec_lua [[ + local a = { A = 1 } + vim.tbl_add_reverse_lookup(a) + return vim.deep_equal(a, { A = 1; [1] = 'A'; }) + ]]) + -- Throw an error for trying to do it twice (run into an existing key) + local code = [[ + local res = {} + local a = { A = 1 } + vim.tbl_add_reverse_lookup(a) + assert(vim.deep_equal(a, { A = 1; [1] = 'A'; })) + vim.tbl_add_reverse_lookup(a) + ]] + matches('Error executing lua: .../shared.lua: The reverse lookup found an existing value for "[1A]" while processing key "[1A]"', + pcall_err(exec_lua, code)) + end) + it('vim.call, vim.fn', function() eq(true, exec_lua([[return vim.call('sin', 0.0) == 0.0 ]])) eq(true, exec_lua([[return vim.fn.sin(0.0) == 0.0 ]])) diff --git a/test/functional/plugin/lsp/lsp_spec.lua b/test/functional/plugin/lsp/lsp_spec.lua new file mode 100644 index 0000000000..cd0974b81c --- /dev/null +++ b/test/functional/plugin/lsp/lsp_spec.lua @@ -0,0 +1,634 @@ +local helpers = require('test.functional.helpers')(after_each) + +local clear = helpers.clear +local exec_lua = helpers.exec_lua +local eq = helpers.eq +local NIL = helpers.NIL + +-- Use these to get access to a coroutine so that I can run async tests and use +-- yield. +local run, stop = helpers.run, helpers.stop + +if helpers.pending_win32(pending) then return end + +local is_windows = require'luv'.os_uname().sysname == "Windows" +local lsp_test_rpc_server_file = "test/functional/fixtures/lsp-test-rpc-server.lua" +if is_windows then + lsp_test_rpc_server_file = lsp_test_rpc_server_file:gsub("/", "\\") +end + +local function test_rpc_server_setup(test_name, timeout_ms) + exec_lua([=[ + lsp = require('vim.lsp') + local test_name, fixture_filename, timeout = ... + TEST_RPC_CLIENT_ID = lsp.start_client { + cmd = { + vim.api.nvim_get_vvar("progpath"), '-Es', '-u', 'NONE', '--headless', + "-c", string.format("lua TEST_NAME = %q", test_name), + "-c", string.format("lua TIMEOUT = %d", timeout), + "-c", "luafile "..fixture_filename, + }; + callbacks = setmetatable({}, { + __index = function(t, method) + return function(...) + return vim.rpcrequest(1, 'callback', ...) + end + end; + }); + root_dir = vim.loop.cwd(); + on_init = function(client, result) + TEST_RPC_CLIENT = client + vim.rpcrequest(1, "init", result) + end; + on_exit = function(...) + vim.rpcnotify(1, "exit", ...) + end; + } + ]=], test_name, lsp_test_rpc_server_file, timeout_ms or 1e3) +end + +local function test_rpc_server(config) + if config.test_name then + clear() + test_rpc_server_setup(config.test_name, config.timeout_ms or 1e3) + end + local client = setmetatable({}, { + __index = function(_, name) + -- Workaround for not being able to yield() inside __index for Lua 5.1 :( + -- Otherwise I would just return the value here. + return function(...) + return exec_lua([=[ + local name = ... + if type(TEST_RPC_CLIENT[name]) == 'function' then + return TEST_RPC_CLIENT[name](select(2, ...)) + else + return TEST_RPC_CLIENT[name] + end + ]=], name, ...) + end + end; + }) + local code, signal + local function on_request(method, args) + if method == "init" then + if config.on_init then + config.on_init(client, unpack(args)) + end + return NIL + end + if method == 'callback' then + if config.on_callback then + config.on_callback(unpack(args)) + end + end + return NIL + end + local function on_notify(method, args) + if method == 'exit' then + code, signal = unpack(args) + return stop() + end + end + -- TODO specify timeout? + -- run(on_request, on_notify, config.on_setup, 1000) + run(on_request, on_notify, config.on_setup) + if config.on_exit then + config.on_exit(code, signal) + end + stop() + if config.test_name then + exec_lua("lsp._vim_exit_handler()") + end +end + +describe('Language Client API', function() + describe('server_name is specified', function() + before_each(function() + clear() + -- Run an instance of nvim on the file which contains our "scripts". + -- Pass TEST_NAME to pick the script. + local test_name = "basic_init" + exec_lua([=[ + lsp = require('vim.lsp') + local test_name, fixture_filename = ... + TEST_RPC_CLIENT_ID = lsp.start_client { + cmd = { + vim.api.nvim_get_vvar("progpath"), '-Es', '-u', 'NONE', '--headless', + "-c", string.format("lua TEST_NAME = %q", test_name), + "-c", "luafile "..fixture_filename; + }; + root_dir = vim.loop.cwd(); + } + ]=], test_name, lsp_test_rpc_server_file) + end) + + after_each(function() + exec_lua("lsp._vim_exit_handler()") + -- exec_lua("lsp.stop_all_clients(true)") + end) + + describe('start_client and stop_client', function() + it('should return true', function() + for _ = 1, 20 do + helpers.sleep(10) + if exec_lua("return #lsp.get_active_clients()") > 0 then + break + end + end + eq(1, exec_lua("return #lsp.get_active_clients()")) + eq(false, exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID) == nil")) + eq(false, exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID).is_stopped()")) + exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID).stop()") + eq(false, exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID).is_stopped()")) + for _ = 1, 20 do + helpers.sleep(10) + if exec_lua("return #lsp.get_active_clients()") == 0 then + break + end + end + eq(true, exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID) == nil")) + end) + end) + end) + + describe('basic_init test', function() + it('should run correctly', function() + local expected_callbacks = { + {NIL, "test", {}, 1}; + } + test_rpc_server { + test_name = "basic_init"; + on_init = function(client, _init_result) + -- client is a dummy object which will queue up commands to be run + -- once the server initializes. It can't accept lua callbacks or + -- other types that may be unserializable for now. + client.stop() + end; + -- If the program timed out, then code will be nil. + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + -- Note that NIL must be used here. + -- on_callback(err, method, result, client_id) + on_callback = function(...) + eq(table.remove(expected_callbacks), {...}) + end; + } + end) + + it('should fail', function() + local expected_callbacks = { + {NIL, "test", {}, 1}; + } + test_rpc_server { + test_name = "basic_init"; + on_init = function(client) + client.notify('test') + client.stop() + end; + on_exit = function(code, signal) + eq(1, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(...) + eq(table.remove(expected_callbacks), {...}, "expected callback") + end; + } + end) + + it('should succeed with manual shutdown', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "test", {}, 1}; + } + test_rpc_server { + test_name = "basic_init"; + on_init = function(client) + eq(0, client.resolved_capabilities().text_document_did_change) + client.request('shutdown') + client.notify('exit') + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(...) + eq(table.remove(expected_callbacks), {...}, "expected callback") + end; + } + end) + + it('should verify capabilities sent', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + } + test_rpc_server { + test_name = "basic_check_capabilities"; + on_init = function(client) + client.stop() + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(...) + eq(table.remove(expected_callbacks), {...}, "expected callback") + end; + } + end) + + it('should not send didOpen if the buffer closes before init', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_finish"; + on_setup = function() + exec_lua [[ + BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { + "testing"; + "123"; + }) + ]] + eq(1, exec_lua("return TEST_RPC_CLIENT_ID")) + eq(true, exec_lua("return lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)")) + eq(true, exec_lua("return lsp.buf_is_attached(BUFFER, TEST_RPC_CLIENT_ID)")) + exec_lua [[ + vim.api.nvim_command(BUFFER.."bwipeout") + ]] + end; + on_init = function(_client) + client = _client + local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + eq(full_kind, client.resolved_capabilities().text_document_did_change) + eq(true, client.resolved_capabilities().text_document_open_close) + client.notify('finish') + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + it('should check the body sent attaching before init', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open"; + on_setup = function() + exec_lua [[ + BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { + "testing"; + "123"; + }) + ]] + exec_lua [[ + assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) + ]] + end; + on_init = function(_client) + client = _client + local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + eq(full_kind, client.resolved_capabilities().text_document_did_change) + eq(true, client.resolved_capabilities().text_document_open_close) + exec_lua [[ + assert(not lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID), "Shouldn't attach twice") + ]] + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + it('should check the body sent attaching after init', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open"; + on_setup = function() + exec_lua [[ + BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { + "testing"; + "123"; + }) + ]] + end; + on_init = function(_client) + client = _client + local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + eq(full_kind, client.resolved_capabilities().text_document_did_change) + eq(true, client.resolved_capabilities().text_document_open_close) + exec_lua [[ + assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) + ]] + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + it('should check the body and didChange full', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open_and_change"; + on_setup = function() + exec_lua [[ + BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { + "testing"; + "123"; + }) + ]] + end; + on_init = function(_client) + client = _client + local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + eq(full_kind, client.resolved_capabilities().text_document_did_change) + eq(true, client.resolved_capabilities().text_document_open_close) + exec_lua [[ + assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) + ]] + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + exec_lua [[ + vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { + "boop"; + }) + ]] + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + -- TODO(askhan) we don't support full for now, so we can disable these tests. + pending('should check the body and didChange incremental', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open_and_change_incremental"; + on_setup = function() + exec_lua [[ + BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { + "testing"; + "123"; + }) + ]] + end; + on_init = function(_client) + client = _client + local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental") + eq(sync_kind, client.resolved_capabilities().text_document_did_change) + eq(true, client.resolved_capabilities().text_document_open_close) + exec_lua [[ + assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) + ]] + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + exec_lua [[ + vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { + "boop"; + }) + ]] + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + -- TODO(askhan) we don't support full for now, so we can disable these tests. + pending('should check the body and didChange incremental normal mode editting', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open_and_change_incremental_editting"; + on_setup = function() + exec_lua [[ + BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { + "testing"; + "123"; + }) + ]] + end; + on_init = function(_client) + client = _client + local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental") + eq(sync_kind, client.resolved_capabilities().text_document_did_change) + eq(true, client.resolved_capabilities().text_document_open_close) + exec_lua [[ + assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) + ]] + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + helpers.command("normal! 1Go") + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + it('should check the body and didChange full with 2 changes', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open_and_change_multi"; + on_setup = function() + exec_lua [[ + BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { + "testing"; + "123"; + }) + ]] + end; + on_init = function(_client) + client = _client + local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + eq(sync_kind, client.resolved_capabilities().text_document_did_change) + eq(true, client.resolved_capabilities().text_document_open_close) + exec_lua [[ + assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) + ]] + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + exec_lua [[ + vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { + "321"; + }) + vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { + "boop"; + }) + ]] + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + it('should check the body and didChange full lifecycle', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open_and_change_multi_and_close"; + on_setup = function() + exec_lua [[ + BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { + "testing"; + "123"; + }) + ]] + end; + on_init = function(_client) + client = _client + local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + eq(sync_kind, client.resolved_capabilities().text_document_did_change) + eq(true, client.resolved_capabilities().text_document_open_close) + exec_lua [[ + assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) + ]] + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + exec_lua [[ + vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { + "321"; + }) + vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { + "boop"; + }) + vim.api.nvim_command(BUFFER.."bwipeout") + ]] + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + end) + + describe("parsing tests", function() + it('should handle invalid content-length correctly', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "invalid_header"; + on_setup = function() + end; + on_init = function(_client) + client = _client + client.stop(true) + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + end; + } + end) + + end) +end) -- cgit From ebdf90e7d7c97b4355f42e06769e9424c279d695 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 16 Nov 2019 11:05:56 +0100 Subject: extmark: don't crash in RO buffer. --- test/functional/api/mark_extended_spec.lua | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'test') diff --git a/test/functional/api/mark_extended_spec.lua b/test/functional/api/mark_extended_spec.lua index a5d68c6b9f..76db9f9d81 100644 --- a/test/functional/api/mark_extended_spec.lua +++ b/test/functional/api/mark_extended_spec.lua @@ -1262,6 +1262,12 @@ describe('Extmarks buffer api', function() check_undo_redo(ns, marks[1], 3, 4, 2, 6) end) + it('in read-only buffer', function() + command("view! runtime/doc/help.txt") + eq(true, curbufmeths.get_option('ro')) + local id = set_extmark(ns, 0, 0, 2) + eq({{id, 0, 2}}, get_extmarks(ns,0, -1)) + end) end) describe('Extmarks buffer api with many marks', function() -- cgit From dab40f43b18d35b283804ecb033310198cbf7548 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 30 Oct 2019 20:53:09 +0100 Subject: Add v:lua.func() vimL syntax for calling lua Also simplify error messages when calling lua from vimL. --- test/functional/lua/api_spec.lua | 30 ++++---- test/functional/lua/commands_spec.lua | 99 ++++++++++++------------ test/functional/lua/luaeval_spec.lua | 96 +++++++++++++++++++++-- test/functional/lua/overrides_spec.lua | 27 +++---- test/functional/ui/messages_spec.lua | 137 ++++++++++++++++----------------- 5 files changed, 237 insertions(+), 152 deletions(-) (limited to 'test') diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua index b1dc5c07fd..23167d3ed9 100644 --- a/test/functional/lua/api_spec.lua +++ b/test/functional/lua/api_spec.lua @@ -155,41 +155,41 @@ describe('luaeval(vim.api.…)', function() it('errors out correctly when working with API', function() -- Conversion errors - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Cannot convert given lua type', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Cannot convert given lua type', exc_exec([[call luaeval("vim.api.nvim__id(vim.api.nvim__id)")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Cannot convert given lua table', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Cannot convert given lua table', exc_exec([[call luaeval("vim.api.nvim__id({1, foo=42})")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Cannot convert given lua type', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Cannot convert given lua type', exc_exec([[call luaeval("vim.api.nvim__id({42, vim.api.nvim__id})")]])) -- Errors in number of arguments - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Expected 1 argument', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected 1 argument', exc_exec([[call luaeval("vim.api.nvim__id()")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Expected 1 argument', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected 1 argument', exc_exec([[call luaeval("vim.api.nvim__id(1, 2)")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Expected 2 arguments', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected 2 arguments', exc_exec([[call luaeval("vim.api.nvim_set_var(1, 2, 3)")]])) -- Error in argument types - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Expected lua string', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua string', exc_exec([[call luaeval("vim.api.nvim_set_var(1, 2)")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Expected lua number', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua number', exc_exec([[call luaeval("vim.api.nvim_buf_get_lines(0, 'test', 1, false)")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Number is not integral', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Number is not integral', exc_exec([[call luaeval("vim.api.nvim_buf_get_lines(0, 1.5, 1, false)")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Expected lua table', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua table', exc_exec([[call luaeval("vim.api.nvim__id_float('test')")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Unexpected type', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Unexpected type', exc_exec([[call luaeval("vim.api.nvim__id_float({[vim.type_idx]=vim.types.dictionary})")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Expected lua table', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua table', exc_exec([[call luaeval("vim.api.nvim__id_array(1)")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Unexpected type', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Unexpected type', exc_exec([[call luaeval("vim.api.nvim__id_array({[vim.type_idx]=vim.types.dictionary})")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Expected lua table', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua table', exc_exec([[call luaeval("vim.api.nvim__id_dictionary(1)")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: Unexpected type', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Unexpected type', exc_exec([[call luaeval("vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.array})")]])) -- TODO: check for errors with Tabpage argument -- TODO: check for errors with Window argument diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index 26dcbe0534..96eaa7991b 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -13,6 +13,7 @@ local source = helpers.source local dedent = helpers.dedent local command = helpers.command local exc_exec = helpers.exc_exec +local pcall_err = helpers.pcall_err local write_file = helpers.write_file local redir_exec = helpers.redir_exec local curbufmeths = helpers.curbufmeths @@ -42,16 +43,16 @@ describe(':lua command', function() eq({'', 'ETTS', 'TTSE', 'STTE'}, curbufmeths.get_lines(0, 100, false)) end) it('throws catchable errors', function() - eq([[Vim(lua):E5104: Error while creating lua chunk: [string ""]:1: unexpected symbol near ')']], - exc_exec('lua ()')) - eq([[Vim(lua):E5105: Error while calling lua chunk: [string ""]:1: TEST]], + eq([[Vim(lua):E5107: Error loading lua [string ":lua"]:1: unexpected symbol near ')']], + pcall_err(command, 'lua ()')) + eq([[Vim(lua):E5108: Error executing lua [string ":lua"]:1: TEST]], exc_exec('lua error("TEST")')) - eq([[Vim(lua):E5105: Error while calling lua chunk: [string ""]:1: Invalid buffer id]], + eq([[Vim(lua):E5108: Error executing lua [string ":lua"]:1: Invalid buffer id]], exc_exec('lua vim.api.nvim_buf_set_lines(-10, 1, 1, false, {"TEST"})')) eq({''}, curbufmeths.get_lines(0, 100, false)) end) it('works with NULL errors', function() - eq([=[Vim(lua):E5105: Error while calling lua chunk: [NULL]]=], + eq([=[Vim(lua):E5108: Error executing lua [NULL]]=], exc_exec('lua error(nil)')) end) it('accepts embedded NLs without heredoc', function() @@ -74,7 +75,7 @@ describe(':lua command', function() it('works with long strings', function() local s = ('x'):rep(100500) - eq('\nE5104: Error while creating lua chunk: [string ""]:1: unfinished string near \'\'', redir_exec(('lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"%s})'):format(s))) + eq('\nE5107: Error loading lua [string ":lua"]:1: unfinished string near \'\'', redir_exec(('lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"%s})'):format(s))) eq({''}, curbufmeths.get_lines(0, -1, false)) eq('', redir_exec(('lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"%s"})'):format(s))) @@ -82,7 +83,7 @@ describe(':lua command', function() end) it('can show multiline error messages', function() - local screen = Screen.new(50,10) + local screen = Screen.new(40,10) screen:attach() screen:set_default_attr_ids({ [1] = {bold = true, foreground = Screen.colors.Blue1}, @@ -92,51 +93,51 @@ describe(':lua command', function() }) feed(':lua error("fail\\nmuch error\\nsuch details")') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {2: }| - {3:E5105: Error while calling lua chunk: [string ""]:1: fail} | - {3:much error} | - {3:such details} | - {4:Press ENTER or type command to continue}^ | - ]]) + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {2: }| + {3:E5108: Error executing lua [string ":lua}| + {3:"]:1: fail} | + {3:much error} | + {3:such details} | + {4:Press ENTER or type command to continue}^ | + ]]} feed('') - screen:expect([[ - ^ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - | - ]]) - eq('E5105: Error while calling lua chunk: [string ""]:1: fail\nmuch error\nsuch details', eval('v:errmsg')) + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + eq('E5108: Error executing lua [string ":lua"]:1: fail\nmuch error\nsuch details', eval('v:errmsg')) local status, err = pcall(command,'lua error("some error\\nin a\\nAPI command")') - local expected = 'Vim(lua):E5105: Error while calling lua chunk: [string ""]:1: some error\nin a\nAPI command' + local expected = 'Vim(lua):E5108: Error executing lua [string ":lua"]:1: some error\nin a\nAPI command' eq(false, status) eq(expected, string.sub(err, -string.len(expected))) feed(':messages') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {1:~ }| - {2: }| - {3:E5105: Error while calling lua chunk: [string ""]:1: fail} | - {3:much error} | - {3:such details} | - {4:Press ENTER or type command to continue}^ | - ]]) + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {2: }| + {3:E5108: Error executing lua [string ":lua}| + {3:"]:1: fail} | + {3:much error} | + {3:such details} | + {4:Press ENTER or type command to continue}^ | + ]]} end) end) @@ -167,13 +168,13 @@ describe(':luado command', function() eq({''}, curbufmeths.get_lines(0, -1, false)) end) it('fails on errors', function() - eq([[Vim(luado):E5109: Error while creating lua chunk: [string ""]:1: unexpected symbol near ')']], + eq([[Vim(luado):E5109: Error loading lua: [string ":luado"]:1: unexpected symbol near ')']], exc_exec('luado ()')) - eq([[Vim(luado):E5111: Error while calling lua function: [string ""]:1: attempt to perform arithmetic on global 'liness' (a nil value)]], + eq([[Vim(luado):E5111: Error calling lua: [string ":luado"]:1: attempt to perform arithmetic on global 'liness' (a nil value)]], exc_exec('luado return liness + 1')) end) it('works with NULL errors', function() - eq([=[Vim(luado):E5111: Error while calling lua function: [NULL]]=], + eq([=[Vim(luado):E5111: Error calling lua: [NULL]]=], exc_exec('luado error(nil)')) end) it('fails in sandbox when needed', function() @@ -185,7 +186,7 @@ describe(':luado command', function() it('works with long strings', function() local s = ('x'):rep(100500) - eq('\nE5109: Error while creating lua chunk: [string ""]:1: unfinished string near \'\'', redir_exec(('luado return "%s'):format(s))) + eq('\nE5109: Error loading lua: [string ":luado"]:1: unfinished string near \'\'', redir_exec(('luado return "%s'):format(s))) eq({''}, curbufmeths.get_lines(0, -1, false)) eq('', redir_exec(('luado return "%s"'):format(s))) diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index 760105df6b..61c8e5c02e 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -1,13 +1,17 @@ -- Test suite for testing luaeval() function local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') local redir_exec = helpers.redir_exec +local pcall_err = helpers.pcall_err local exc_exec = helpers.exc_exec +local exec_lua = helpers.exec_lua local command = helpers.command local meths = helpers.meths local funcs = helpers.funcs local clear = helpers.clear local eval = helpers.eval +local feed = helpers.feed local NIL = helpers.NIL local eq = helpers.eq @@ -186,9 +190,9 @@ describe('luaeval()', function() exc_exec('call luaeval("{1, foo=2}")')) eq("Vim(call):E5101: Cannot convert given lua type", exc_exec('call luaeval("vim.api.nvim_buf_get_lines")')) - startswith("Vim(call):E5107: Error while creating lua chunk for luaeval(): ", + startswith("Vim(call):E5107: Error loading lua [string \"luaeval()\"]:", exc_exec('call luaeval("1, 2, 3")')) - startswith("Vim(call):E5108: Error while calling lua chunk for luaeval(): ", + startswith("Vim(call):E5108: Error executing lua [string \"luaeval()\"]:", exc_exec('call luaeval("(nil)()")')) eq("Vim(call):E5101: Cannot convert given lua type", exc_exec('call luaeval("{42, vim.api}")')) @@ -237,19 +241,99 @@ describe('luaeval()', function() it('errors out correctly when doing incorrect things in lua', function() -- Conversion errors - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: attempt to call field \'xxx_nonexistent_key_xxx\' (a nil value)', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: attempt to call field \'xxx_nonexistent_key_xxx\' (a nil value)', exc_exec([[call luaeval("vim.xxx_nonexistent_key_xxx()")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string ""]:1: ERROR', + eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: ERROR', exc_exec([[call luaeval("error('ERROR')")]])) - eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [NULL]', + eq('Vim(call):E5108: Error executing lua [NULL]', exc_exec([[call luaeval("error(nil)")]])) end) it('does not leak memory when called with too long line', function() local s = ('x'):rep(65536) - eq('Vim(call):E5107: Error while creating lua chunk for luaeval(): [string ""]:1: unexpected symbol near \')\'', + eq('Vim(call):E5107: Error loading lua [string "luaeval()"]:1: unexpected symbol near \')\'', exc_exec([[call luaeval("(']] .. s ..[[' + )")]])) eq(s, funcs.luaeval('"' .. s .. '"')) end) end) + +describe('v:lua', function() + before_each(function() + exec_lua([[ + function _G.foo(a,b,n) + _G.val = n + return a+b + end + mymod = {} + function mymod.noisy(name) + vim.api.nvim_set_current_line("hey "..name) + end + function mymod.crashy() + nonexistent() + end + function mymod.omni(findstart, base) + if findstart == 1 then + return 5 + else + if base == 'st' then + return {'stuff', 'steam', 'strange things'} + end + end + end + vim.api.nvim_buf_set_option(0, 'omnifunc', 'v:lua.mymod.omni') + ]]) + end) + + it('works in expressions', function() + eq(7, eval('v:lua.foo(3,4,v:null)')) + eq(true, exec_lua([[return _G.val == vim.NIL]])) + eq(NIL, eval('v:lua.mymod.noisy("eval")')) + eq("hey eval", meths.get_current_line()) + + eq("Vim:E5108: Error executing lua [string \"\"]:10: attempt to call global 'nonexistent' (a nil value)", + pcall_err(eval, 'v:lua.mymod.crashy()')) + end) + + it('works in :call', function() + command(":call v:lua.mymod.noisy('command')") + eq("hey command", meths.get_current_line()) + eq("Vim(call):E5108: Error executing lua [string \"\"]:10: attempt to call global 'nonexistent' (a nil value)", + pcall_err(command, 'call v:lua.mymod.crashy()')) + end) + + it('works in func options', function() + local screen = Screen.new(60, 8) + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {background = Screen.colors.WebGray}, + [3] = {background = Screen.colors.LightMagenta}, + [4] = {bold = true}, + [5] = {bold = true, foreground = Screen.colors.SeaGreen4}, + }) + screen:attach() + feed('isome st') + screen:expect{grid=[[ + some stuff^ | + {1:~ }{2: stuff }{1: }| + {1:~ }{3: steam }{1: }| + {1:~ }{3: strange things }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {4:-- Omni completion (^O^N^P) }{5:match 1 of 3} | + ]]} + end) + + it('throw errors for invalid use', function() + eq('Vim(let):E15: Invalid expression: v:lua.func', pcall_err(command, "let g:Func = v:lua.func")) + eq('Vim(let):E15: Invalid expression: v:lua', pcall_err(command, "let g:Func = v:lua")) + eq("Vim(let):E15: Invalid expression: v:['lua']", pcall_err(command, "let g:Func = v:['lua']")) + + eq("Vim:E15: Invalid expression: v:['lua'].foo()", pcall_err(eval, "v:['lua'].foo()")) + eq("Vim(call):E461: Illegal variable name: v:['lua']", pcall_err(command, "call v:['lua'].baar()")) + + eq("Vim(let):E46: Cannot change read-only variable \"v:['lua']\"", pcall_err(command, "let v:['lua'] = 'xx'")) + eq("Vim(let):E46: Cannot change read-only variable \"v:lua\"", pcall_err(command, "let v:lua = 'xx'")) + end) +end) diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua index f6439001ac..8c260632d9 100644 --- a/test/functional/lua/overrides_spec.lua +++ b/test/functional/lua/overrides_spec.lua @@ -54,11 +54,12 @@ describe('print', function() v_tblout = setmetatable({}, meta_tblout) ]]) eq('', redir_exec('luafile ' .. fname)) - eq('\nE5105: Error while calling lua chunk: E5114: Error while converting print argument #2: [NULL]', + -- TODO(bfredl): these look weird, print() should not use "E5114:" style errors.. + eq('\nE5108: Error executing lua E5114: Error while converting print argument #2: [NULL]', redir_exec('lua print("foo", v_nilerr, "bar")')) - eq('\nE5105: Error while calling lua chunk: E5114: Error while converting print argument #2: Xtest-functional-lua-overrides-luafile:2: abc', + eq('\nE5108: Error executing lua E5114: Error while converting print argument #2: Xtest-functional-lua-overrides-luafile:2: abc', redir_exec('lua print("foo", v_abcerr, "bar")')) - eq('\nE5105: Error while calling lua chunk: E5114: Error while converting print argument #2: ', + eq('\nE5108: Error executing lua E5114: Error while converting print argument #2: ', redir_exec('lua print("foo", v_tblout, "bar")')) end) it('prints strings with NULs and NLs correctly', function() @@ -156,7 +157,8 @@ describe('debug.debug', function() lua_debug> ^ | ]]) feed('') - screen:expect([[ + screen:expect{grid=[[ + {0:~ }| {0:~ }| {0:~ }| {0:~ }| @@ -167,11 +169,10 @@ describe('debug.debug', function() lua_debug> print("TEST") | TEST | | - {E:E5105: Error while calling lua chunk: [string ""]:5: attempt to perform arithmetic o}| - {E:n local 'a' (a nil value)} | + {E:E5108: Error executing lua [string ":lua"]:5: attempt}| + {E: to perform arithmetic on local 'a' (a nil value)} | Interrupt: {cr:Press ENTER or type command to continue}^ | - ]]) + ]]} feed(':lua Test()\n') screen:expect([[ {0:~ }| @@ -190,7 +191,8 @@ describe('debug.debug', function() lua_debug> ^ | ]]) feed('\n') - screen:expect([[ + screen:expect{grid=[[ + {0:~ }| {0:~ }| {0:~ }| {0:~ }| @@ -201,11 +203,10 @@ describe('debug.debug', function() {0:~ }| nil | lua_debug> | - {E:E5105: Error while calling lua chunk: [string ""]:5: attempt to perform arithmetic o}| - {E:n local 'a' (a nil value)} | + {E:E5108: Error executing lua [string ":lua"]:5: attempt}| + {E: to perform arithmetic on local 'a' (a nil value)} | {cr:Press ENTER or type command to continue}^ | - ]]) + ]]} end) it("can be safely exited with 'cont'", function() diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index 8ad3aff21f..40ea030f73 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -747,7 +747,7 @@ describe('ui/ext_messages', function() {1:~ }| {1:~ }| ]], messages={{ - content = {{'E5105: Error while calling lua chunk: [string ""]:1: such\nmultiline\nerror', 2}}, + content = {{'E5108: Error executing lua [string ":lua"]:1: such\nmultiline\nerror', 2}}, kind = "lua_error" }}} end) @@ -1146,97 +1146,96 @@ aliquip ex ea commodo consequat.]]) it('handles wrapped lines with line scroll', function() feed(':lua error(_G.x)') screen:expect{grid=[[ - {2:E5105: Error while calling lua chun}| - {2:k: [string ""}| - {2:]:1: Lorem ipsum dolor sit amet, co}| - {2:nsectetur} | + {2:E5108: Error executing lua [string }| + {2:":lua"]:1: Lorem ipsum dolor sit am}| + {2:et, consectetur} | {2:adipisicing elit, sed do eiusmod te}| {2:mpor} | {2:incididunt ut labore et dolore magn}| + {2:a aliqua.} | {4:-- More --}^ | ]]} feed('j') screen:expect{grid=[[ - {2:k: [string ""}| - {2:]:1: Lorem ipsum dolor sit amet, co}| - {2:nsectetur} | + {2:":lua"]:1: Lorem ipsum dolor sit am}| + {2:et, consectetur} | {2:adipisicing elit, sed do eiusmod te}| {2:mpor} | {2:incididunt ut labore et dolore magn}| {2:a aliqua.} | + {2:Ut enim ad minim veniam, quis nostr}| {4:-- More --}^ | ]]} feed('k') screen:expect{grid=[[ - {2:E5105: Error while calling lua chun}| - {2:k: [string ""}| - {2:]:1: Lorem ipsum dolor sit amet, co}| - {2:nsectetur} | + {2:E5108: Error executing lua [string }| + {2:":lua"]:1: Lorem ipsum dolor sit am}| + {2:et, consectetur} | {2:adipisicing elit, sed do eiusmod te}| {2:mpor} | {2:incididunt ut labore et dolore magn}| + {2:a aliqua.} | {4:-- More --}^ | ]]} feed('j') screen:expect{grid=[[ - {2:k: [string ""}| - {2:]:1: Lorem ipsum dolor sit amet, co}| - {2:nsectetur} | + {2:":lua"]:1: Lorem ipsum dolor sit am}| + {2:et, consectetur} | {2:adipisicing elit, sed do eiusmod te}| {2:mpor} | {2:incididunt ut labore et dolore magn}| {2:a aliqua.} | + {2:Ut enim ad minim veniam, quis nostr}| {4:-- More --}^ | ]]} - end) it('handles wrapped lines with page scroll', function() feed(':lua error(_G.x)') screen:expect{grid=[[ - {2:E5105: Error while calling lua chun}| - {2:k: [string ""}| - {2:]:1: Lorem ipsum dolor sit amet, co}| - {2:nsectetur} | + {2:E5108: Error executing lua [string }| + {2:":lua"]:1: Lorem ipsum dolor sit am}| + {2:et, consectetur} | {2:adipisicing elit, sed do eiusmod te}| {2:mpor} | {2:incididunt ut labore et dolore magn}| + {2:a aliqua.} | {4:-- More --}^ | ]]} feed('d') screen:expect{grid=[[ - {2:adipisicing elit, sed do eiusmod te}| - {2:mpor} | {2:incididunt ut labore et dolore magn}| {2:a aliqua.} | {2:Ut enim ad minim veniam, quis nostr}| {2:ud xercitation} | {2:ullamco laboris nisi ut} | - {4:-- More --}^ | + {2:aliquip ex ea commodo consequat.} | + {4:Press ENTER or type command to cont}| + {4:inue}^ | ]]} feed('u') screen:expect{grid=[[ - {2:E5105: Error while calling lua chun}| - {2:k: [string ""}| - {2:]:1: Lorem ipsum dolor sit amet, co}| - {2:nsectetur} | + {2:E5108: Error executing lua [string }| + {2:":lua"]:1: Lorem ipsum dolor sit am}| + {2:et, consectetur} | {2:adipisicing elit, sed do eiusmod te}| {2:mpor} | {2:incididunt ut labore et dolore magn}| + {2:a aliqua.} | {4:-- More --}^ | ]]} feed('d') screen:expect{grid=[[ - {2:adipisicing elit, sed do eiusmod te}| {2:mpor} | {2:incididunt ut labore et dolore magn}| {2:a aliqua.} | {2:Ut enim ad minim veniam, quis nostr}| {2:ud xercitation} | {2:ullamco laboris nisi ut} | + {2:aliquip ex ea commodo consequat.} | {4:-- More --}^ | ]]} end) @@ -1246,49 +1245,49 @@ aliquip ex ea commodo consequat.]]) feed(':lua error(_G.x)') screen:expect{grid=[[ - {3:E5105: Error while calling lua chun}| - {3:k: [string ""}| - {3:]:1: Lorem ipsum dolor sit amet, co}| - {3:nsectetur}{5: }| + {3:E5108: Error executing lua [string }| + {3:":lua"]:1: Lorem ipsum dolor sit am}| + {3:et, consectetur}{5: }| {3:adipisicing elit, sed do eiusmod te}| {3:mpor}{5: }| {3:incididunt ut labore et dolore magn}| + {3:a aliqua.}{5: }| {6:-- More --}{5:^ }| ]]} feed('j') screen:expect{grid=[[ - {3:k: [string ""}| - {3:]:1: Lorem ipsum dolor sit amet, co}| - {3:nsectetur}{5: }| + {3:":lua"]:1: Lorem ipsum dolor sit am}| + {3:et, consectetur}{5: }| {3:adipisicing elit, sed do eiusmod te}| {3:mpor}{5: }| {3:incididunt ut labore et dolore magn}| {3:a aliqua.}{5: }| + {3:Ut enim ad minim veniam, quis nostr}| {6:-- More --}{5:^ }| ]]} feed('k') screen:expect{grid=[[ - {3:E5105: Error while calling lua chun}| - {3:k: [string ""}| - {3:]:1: Lorem ipsum dolor sit amet, co}| - {3:nsectetur}{5: }| + {3:E5108: Error executing lua [string }| + {3:":lua"]:1: Lorem ipsum dolor sit am}| + {3:et, consectetur}{5: }| {3:adipisicing elit, sed do eiusmod te}| {3:mpor}{5: }| {3:incididunt ut labore et dolore magn}| + {3:a aliqua.}{5: }| {6:-- More --}{5:^ }| ]]} feed('j') screen:expect{grid=[[ - {3:k: [string ""}| - {3:]:1: Lorem ipsum dolor sit amet, co}| - {3:nsectetur}{5: }| + {3:":lua"]:1: Lorem ipsum dolor sit am}| + {3:et, consectetur}{5: }| {3:adipisicing elit, sed do eiusmod te}| {3:mpor}{5: }| {3:incididunt ut labore et dolore magn}| {3:a aliqua.}{5: }| + {3:Ut enim ad minim veniam, quis nostr}| {6:-- More --}{5:^ }| ]]} end) @@ -1297,46 +1296,46 @@ aliquip ex ea commodo consequat.]]) command("hi MsgArea guisp=Yellow") feed(':lua error(_G.x)') screen:expect{grid=[[ - {3:E5105: Error while calling lua chun}| - {3:k: [string ""}| - {3:]:1: Lorem ipsum dolor sit amet, co}| - {3:nsectetur}{5: }| + {3:E5108: Error executing lua [string }| + {3:":lua"]:1: Lorem ipsum dolor sit am}| + {3:et, consectetur}{5: }| {3:adipisicing elit, sed do eiusmod te}| {3:mpor}{5: }| {3:incididunt ut labore et dolore magn}| + {3:a aliqua.}{5: }| {6:-- More --}{5:^ }| ]]} feed('d') screen:expect{grid=[[ - {3:adipisicing elit, sed do eiusmod te}| - {3:mpor}{5: }| {3:incididunt ut labore et dolore magn}| {3:a aliqua.}{5: }| {3:Ut enim ad minim veniam, quis nostr}| {3:ud xercitation}{5: }| {3:ullamco laboris nisi ut}{5: }| - {6:-- More --}{5:^ }| + {3:aliquip ex ea commodo consequat.}{5: }| + {6:Press ENTER or type command to cont}| + {6:inue}{5:^ }| ]]} feed('u') screen:expect{grid=[[ - {3:E5105: Error while calling lua chun}| - {3:k: [string ""}| - {3:]:1: Lorem ipsum dolor sit amet, co}| - {3:nsectetur}{5: }| + {3:E5108: Error executing lua [string }| + {3:":lua"]:1: Lorem ipsum dolor sit am}| + {3:et, consectetur}{5: }| {3:adipisicing elit, sed do eiusmod te}| {3:mpor}{5: }| {3:incididunt ut labore et dolore magn}| + {3:a aliqua.}{5: }| {6:-- More --}{5:^ }| ]]} feed('d') screen:expect{grid=[[ - {3:adipisicing elit, sed do eiusmod te}| {3:mpor}{5: }| {3:incididunt ut labore et dolore magn}| {3:a aliqua.}{5: }| {3:Ut enim ad minim veniam, quis nostr}| {3:ud xercitation}{5: }| {3:ullamco laboris nisi ut}{5: }| + {3:aliquip ex ea commodo consequat.}{5: }| {6:-- More --}{5:^ }| ]]} end) @@ -1473,23 +1472,23 @@ aliquip ex ea commodo consequat.]]) it('can be resized', function() feed(':lua error(_G.x)') screen:expect{grid=[[ - {2:E5105: Error while calling lua chun}| - {2:k: [string ""}| - {2:]:1: Lorem ipsum dolor sit amet, co}| - {2:nsectetur} | + {2:E5108: Error executing lua [string }| + {2:":lua"]:1: Lorem ipsum dolor sit am}| + {2:et, consectetur} | {2:adipisicing elit, sed do eiusmod te}| {2:mpor} | {2:incididunt ut labore et dolore magn}| + {2:a aliqua.} | {4:-- More --}^ | ]]} -- responds to resize, but text is not reflown screen:try_resize(45, 5) screen:expect{grid=[[ - {2:nsectetur} | {2:adipisicing elit, sed do eiusmod te} | {2:mpor} | {2:incididunt ut labore et dolore magn} | + {2:a aliqua.} | {4:-- More --}^ | ]]} @@ -1497,14 +1496,14 @@ aliquip ex ea commodo consequat.]]) -- text is not reflown; existing lines get cut screen:try_resize(30, 12) screen:expect{grid=[[ - {2:E5105: Error while calling lua}| - {2:k: [string "') screen:expect{grid=[[ - {2:k: [string " Date: Mon, 18 Nov 2019 15:38:27 +0800 Subject: vim-patch:8.1.0251: support full paths for 'backupdir' #11269 Problem: Using a full path is supported for 'directory' but not for 'backupdir'. (Mikolaj Machowski) Solution: Support 'backupdir' as well. (Christian Brabandt, closes vim/vim#179) https://github.com/vim/vim/commit/b782ba475a3f8f2b0be99dda164ba4545347f60f --- test/functional/core/fileio_spec.lua | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'test') diff --git a/test/functional/core/fileio_spec.lua b/test/functional/core/fileio_spec.lua index e6bce85b8a..f4c476560d 100644 --- a/test/functional/core/fileio_spec.lua +++ b/test/functional/core/fileio_spec.lua @@ -9,9 +9,12 @@ local nvim_prog = helpers.nvim_prog local request = helpers.request local retry = helpers.retry local rmdir = helpers.rmdir +local mkdir = helpers.mkdir local sleep = helpers.sleep local read_file = helpers.read_file local trim = helpers.trim +local currentdir = helpers.funcs.getcwd +local iswin = helpers.iswin describe('fileio', function() before_each(function() @@ -24,6 +27,7 @@ describe('fileio', function() os.remove('Xtest_startup_file2') os.remove('Xtest_тест.md') rmdir('Xtest_startup_swapdir') + rmdir('Xtest_backupdir') end) it('fsync() codepaths #8304', function() @@ -88,6 +92,27 @@ describe('fileio', function() eq('foo', bar_contents); end) + it('backup with full path #11214', function() + clear() + mkdir('Xtest_backupdir') + command('set backup') + command('set backupdir=Xtest_backupdir//') + command('write Xtest_startup_file1') + feed('ifoo') + command('write') + feed('Abar') + command('write') + + -- Backup filename = fullpath, separators replaced with "%". + local backup_file_name = string.gsub(currentdir()..'/Xtest_startup_file1', + iswin() and '[:/\\]' or '/', '%%') .. '~' + local foo_contents = trim(read_file('Xtest_backupdir/'..backup_file_name)) + local foobar_contents = trim(read_file('Xtest_startup_file1')) + + eq('foobar', foobar_contents); + eq('foo', foo_contents); + end) + it('readfile() on multibyte filename #10586', function() clear() local text = { -- cgit From b984f613c1e8dadbe59bf0d7093a6ed12af61b37 Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Wed, 20 Nov 2019 17:09:21 -0800 Subject: Extend list_extend to take start/finish. --- test/functional/lua/vim_spec.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 028f2dcd52..c8a4c1364f 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -353,10 +353,14 @@ describe('lua stdlib', function() it('vim.list_extend', function() eq({1,2,3}, exec_lua [[ return vim.list_extend({1}, {2,3}) ]]) - eq('Error executing lua: .../shared.lua: src must be a table', + eq('Error executing lua: .../shared.lua: src: expected table, got nil', pcall_err(exec_lua, [[ return vim.list_extend({1}, nil) ]])) eq({1,2}, exec_lua [[ return vim.list_extend({1}, {2;a=1}) ]]) eq(true, exec_lua [[ local a = {1} return vim.list_extend(a, {2;a=1}) == a ]]) + eq({2}, exec_lua [[ return vim.list_extend({}, {2;a=1}, 1) ]]) + eq({}, exec_lua [[ return vim.list_extend({}, {2;a=1}, 2) ]]) + eq({}, exec_lua [[ return vim.list_extend({}, {2;a=1}, 1, -1) ]]) + eq({2}, exec_lua [[ return vim.list_extend({}, {2;a=1}, -1, 2) ]]) end) it('vim.tbl_add_reverse_lookup', function() -- cgit From 76e0a8bd935b27270f8f6a594c3025bc494f4422 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Thu, 21 Nov 2019 10:29:54 +0100 Subject: lsp: transmit "\n" after last line when 'eol' is set Otherwise some servers like clangd will emit spurious "no newline at end of file" warnings. --- test/functional/fixtures/lsp-test-rpc-server.lua | 53 ++++++++++++++++++++---- test/functional/plugin/lsp/lsp_spec.lua | 48 +++++++++++++++++++++ 2 files changed, 92 insertions(+), 9 deletions(-) (limited to 'test') diff --git a/test/functional/fixtures/lsp-test-rpc-server.lua b/test/functional/fixtures/lsp-test-rpc-server.lua index 971e61b072..798883ced0 100644 --- a/test/functional/fixtures/lsp-test-rpc-server.lua +++ b/test/functional/fixtures/lsp-test-rpc-server.lua @@ -170,7 +170,7 @@ function tests.basic_check_buffer_open() expect_notification('textDocument/didOpen', { textDocument = { languageId = ""; - text = table.concat({"testing"; "123"}, "\n"); + text = table.concat({"testing"; "123"}, "\n") .. '\n'; uri = "file://"; version = 0; }; @@ -182,6 +182,42 @@ function tests.basic_check_buffer_open() end function tests.basic_check_buffer_open_and_change() + skeleton { + on_init = function(params) + local expected_capabilities = protocol.make_client_capabilities() + assert_eq(params.capabilities, expected_capabilities) + return { + capabilities = { + textDocumentSync = protocol.TextDocumentSyncKind.Full; + } + } + end; + body = function() + notify('start') + expect_notification('textDocument/didOpen', { + textDocument = { + languageId = ""; + text = table.concat({"testing"; "123"}, "\n") .. '\n'; + uri = "file://"; + version = 0; + }; + }) + expect_notification('textDocument/didChange', { + textDocument = { + uri = "file://"; + version = 3; + }; + contentChanges = { + { text = table.concat({"testing"; "boop"}, "\n") .. '\n'; }; + } + }) + expect_notification("finish") + notify('finish') + end; + } +end + +function tests.basic_check_buffer_open_and_change_noeol() skeleton { on_init = function(params) local expected_capabilities = protocol.make_client_capabilities() @@ -216,7 +252,6 @@ function tests.basic_check_buffer_open_and_change() end; } end - function tests.basic_check_buffer_open_and_change_multi() skeleton { on_init = function(params) @@ -233,7 +268,7 @@ function tests.basic_check_buffer_open_and_change_multi() expect_notification('textDocument/didOpen', { textDocument = { languageId = ""; - text = table.concat({"testing"; "123"}, "\n"); + text = table.concat({"testing"; "123"}, "\n") .. '\n'; uri = "file://"; version = 0; }; @@ -244,7 +279,7 @@ function tests.basic_check_buffer_open_and_change_multi() version = 3; }; contentChanges = { - { text = table.concat({"testing"; "321"}, "\n"); }; + { text = table.concat({"testing"; "321"}, "\n") .. '\n'; }; } }) expect_notification('textDocument/didChange', { @@ -253,7 +288,7 @@ function tests.basic_check_buffer_open_and_change_multi() version = 4; }; contentChanges = { - { text = table.concat({"testing"; "boop"}, "\n"); }; + { text = table.concat({"testing"; "boop"}, "\n") .. '\n'; }; } }) expect_notification("finish") @@ -278,7 +313,7 @@ function tests.basic_check_buffer_open_and_change_multi_and_close() expect_notification('textDocument/didOpen', { textDocument = { languageId = ""; - text = table.concat({"testing"; "123"}, "\n"); + text = table.concat({"testing"; "123"}, "\n") .. '\n'; uri = "file://"; version = 0; }; @@ -289,7 +324,7 @@ function tests.basic_check_buffer_open_and_change_multi_and_close() version = 3; }; contentChanges = { - { text = table.concat({"testing"; "321"}, "\n"); }; + { text = table.concat({"testing"; "321"}, "\n") .. '\n'; }; } }) expect_notification('textDocument/didChange', { @@ -298,7 +333,7 @@ function tests.basic_check_buffer_open_and_change_multi_and_close() version = 4; }; contentChanges = { - { text = table.concat({"testing"; "boop"}, "\n"); }; + { text = table.concat({"testing"; "boop"}, "\n") .. '\n'; }; } }) expect_notification('textDocument/didClose', { @@ -328,7 +363,7 @@ function tests.basic_check_buffer_open_and_change_incremental() expect_notification('textDocument/didOpen', { textDocument = { languageId = ""; - text = table.concat({"testing"; "123"}, "\n"); + text = table.concat({"testing"; "123"}, "\n") .. '\n'; uri = "file://"; version = 0; }; diff --git a/test/functional/plugin/lsp/lsp_spec.lua b/test/functional/plugin/lsp/lsp_spec.lua index cd0974b81c..c38c9b72ce 100644 --- a/test/functional/plugin/lsp/lsp_spec.lua +++ b/test/functional/plugin/lsp/lsp_spec.lua @@ -410,6 +410,54 @@ describe('Language Client API', function() } end) + it('should check the body and didChange full with noeol', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open_and_change_noeol"; + on_setup = function() + exec_lua [[ + BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { + "testing"; + "123"; + }) + vim.api.nvim_buf_set_option(BUFFER, 'eol', false) + ]] + end; + on_init = function(_client) + client = _client + local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + eq(full_kind, client.resolved_capabilities().text_document_did_change) + eq(true, client.resolved_capabilities().text_document_open_close) + exec_lua [[ + assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) + ]] + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + exec_lua [[ + vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { + "boop"; + }) + ]] + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + -- TODO(askhan) we don't support full for now, so we can disable these tests. pending('should check the body and didChange incremental', function() local expected_callbacks = { -- cgit From bcae04f6c62b23104e85bb08c54a16d0cdc33852 Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Thu, 21 Nov 2019 15:19:06 -0800 Subject: Updates - Use correct implementation of text_edits. - Send indent options to rangeFormatting and formatting. - Remove references to vim bindings and filetype from lsp.txt - Add more examples to docs. - Add before_init to allow changing initialize_params. --- test/functional/plugin/lsp/util_spec.lua | 78 ++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 test/functional/plugin/lsp/util_spec.lua (limited to 'test') diff --git a/test/functional/plugin/lsp/util_spec.lua b/test/functional/plugin/lsp/util_spec.lua new file mode 100644 index 0000000000..6516fa8a08 --- /dev/null +++ b/test/functional/plugin/lsp/util_spec.lua @@ -0,0 +1,78 @@ +local helpers = require('test.functional.helpers')(after_each) +local eq = helpers.eq +local exec_lua = helpers.exec_lua +local dedent = helpers.dedent +local insert = helpers.insert +local clear = helpers.clear +local command = helpers.command +local NIL = helpers.NIL + +describe('LSP util', function() + local test_text = dedent([[ + First line of text + Second line of text + Third line of text + Fourth line of text]]) + + local function reset() + clear() + insert(test_text) + end + + before_each(reset) + + local function make_edit(y_0, x_0, y_1, x_1, text) + return { + range = { + start = { line = y_0, character = x_0 }; + ["end"] = { line = y_1, character = x_1 }; + }; + newText = type(text) == 'table' and table.concat(text, '\n') or (text or ""); + } + end + + local function buf_lines(bufnr) + return exec_lua("return vim.api.nvim_buf_get_lines((...), 0, -1, false)", bufnr) + end + + describe('apply_edits', function() + it('should apply simple edits', function() + local edits = { + make_edit(0, 0, 0, 0, {"123"}); + make_edit(1, 0, 1, 1, {"2"}); + make_edit(2, 0, 2, 2, {"3"}); + } + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + eq({ + '123First line of text'; + '2econd line of text'; + '3ird line of text'; + 'Fourth line of text'; + }, buf_lines(1)) + end) + + it('should apply complex edits', function() + local edits = { + make_edit(0, 0, 0, 0, {"", "12"}); + make_edit(0, 0, 0, 0, {"3", "foo"}); + make_edit(0, 1, 0, 1, {"bar", "123"}); + make_edit(0, #"First ", 0, #"First line of text", {"guy"}); + make_edit(1, 0, 1, #'Second', {"baz"}); + make_edit(2, #'Th', 2, #"Third", {"e next"}); + make_edit(3, #'', 3, #"Fourth", {"another line of text", "before this"}); + make_edit(3, #'Fourth', 3, #"Fourth line of text", {"!"}); + } + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + eq({ + ''; + '123'; + 'fooFbar'; + '123irst guy'; + 'baz line of text'; + 'The next line of text'; + 'another line of text'; + 'before this!'; + }, buf_lines(1)) + end) + end) +end) -- cgit From b4ca07896cbf29ac4ca2373f681930be3ac3b882 Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Thu, 21 Nov 2019 15:23:43 -0800 Subject: lualint --- test/functional/plugin/lsp/util_spec.lua | 2 -- 1 file changed, 2 deletions(-) (limited to 'test') diff --git a/test/functional/plugin/lsp/util_spec.lua b/test/functional/plugin/lsp/util_spec.lua index 6516fa8a08..1cf0e48be4 100644 --- a/test/functional/plugin/lsp/util_spec.lua +++ b/test/functional/plugin/lsp/util_spec.lua @@ -4,8 +4,6 @@ local exec_lua = helpers.exec_lua local dedent = helpers.dedent local insert = helpers.insert local clear = helpers.clear -local command = helpers.command -local NIL = helpers.NIL describe('LSP util', function() local test_text = dedent([[ -- cgit From d5f14b8372b3c8d441187eea659156534cb4c9ba Mon Sep 17 00:00:00 2001 From: Dennis B Date: Fri, 22 Nov 2019 20:55:04 +1100 Subject: Clear 'cc' in nvim_open_win 'minimal' style #11361 (#11427) * Clear 'cc' in nvim_open_win 'minimal' style #11361 Add 'colorcolumn' to the list of options that should be cleared when creating a 'minimal'-style floating window. --- test/functional/ui/float_spec.lua | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) (limited to 'test') diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index dbaf6f802b..8ddb2e90a6 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -39,6 +39,7 @@ describe('floating windows', function() [19] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray}, [20] = {bold = true, foreground = Screen.colors.Brown}, [21] = {background = Screen.colors.Gray90}, + [22] = {background = Screen.colors.LightRed}, } it('behavior', function() @@ -398,6 +399,7 @@ describe('floating windows', function() it("can use 'minimal' style", function() command('set number') command('set signcolumn=yes') + command('set colorcolumn=1') command('set cursorline') command('set foldcolumn=1') command('hi NormalFloat guibg=#333333') @@ -414,9 +416,9 @@ describe('floating windows', function() [2:----------------------------------------]| [3:----------------------------------------]| ## grid 2 - {19: }{20: 1 }{21:^x }| - {19: }{14: 2 }y | - {19: }{14: 3 } | + {19: }{20: 1 }{22:^x}{21: }| + {19: }{14: 2 }{22:y} | + {19: }{14: 3 }{22: } | {0:~ }| {0:~ }| {0:~ }| @@ -430,9 +432,9 @@ describe('floating windows', function() ]], float_pos={[4] = {{id = 1001}, "NW", 1, 4, 10, true}}} else screen:expect{grid=[[ - {19: }{20: 1 }{21:^x }| - {19: }{14: 2 }y | - {19: }{14: 3 } {15:x } | + {19: }{20: 1 }{22:^x}{21: }| + {19: }{14: 2 }{22:y} | + {19: }{14: 3 }{22: } {15:x } | {0:~ }{15:y }{0: }| {0:~ }{15: }{0: }| {0:~ }{15: }{0: }| @@ -454,9 +456,9 @@ describe('floating windows', function() [2:----------------------------------------]| [3:----------------------------------------]| ## grid 2 - {19: }{17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{20: 1 }{21:^x }| - {19: }{14: 2 }y | - {19: }{14: 3 } | + {19: }{17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{20: 1 }{22:^x}{21: }| + {19: }{14: 2 }{22:y} | + {19: }{14: 3 }{22: } | {0:~ }| {0:~ }| {0:~ }| @@ -471,9 +473,9 @@ describe('floating windows', function() else screen:expect([[ - {19: }{17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{20: 1 }{21:^x }| - {19: }{14: 2 }y | - {19: }{14: 3 } {17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{15:x } | + {19: }{17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{20: 1 }{22:^x}{21: }| + {19: }{14: 2 }{22:y} | + {19: }{14: 3 }{22: } {17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{15:x } | {0:~ }{19: }{15:y }{0: }| {0:~ }{19: }{15: }{0: }| {0:~ }{15: }{0: }| @@ -495,9 +497,9 @@ describe('floating windows', function() [2:----------------------------------------]| [3:----------------------------------------]| ## grid 2 - {19: }{20: 1 }{21:^x }| - {19: }{14: 2 }y | - {19: }{14: 3 } | + {19: }{20: 1 }{22:^x}{21: }| + {19: }{14: 2 }{22:y} | + {19: }{14: 3 }{22: } | {0:~ }| {0:~ }| {0:~ }| @@ -511,9 +513,9 @@ describe('floating windows', function() ]], float_pos={[4] = {{id = 1001}, "NW", 1, 4, 10, true}}} else screen:expect([[ - {19: }{20: 1 }{21:^x }| - {19: }{14: 2 }y | - {19: }{14: 3 } {15: } | + {19: }{20: 1 }{22:^x}{21: }| + {19: }{14: 2 }{22:y} | + {19: }{14: 3 }{22: } {15: } | {0:~ }{15: }{0: }| {0:~ }{15: }{0: }| {0:~ }{15: }{0: }| -- cgit From bdebe8516c90839930acbfe3c6f1e354ee56df3f Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Fri, 29 Jun 2018 13:35:42 +0200 Subject: bufhl: use extmark column adjustment for bufhl NB: this is not the final implementation. Bufhl should be made a part of the extmark tree, so that "start" adjustment just works automatically. But "stop" will still need some ad-hoc trickery, until extended marks natively support ranges (hopefully sooner than forever). --- test/functional/ui/bufhl_spec.lua | 155 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) (limited to 'test') diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua index 65c5f67726..20a2aa9a67 100644 --- a/test/functional/ui/bufhl_spec.lua +++ b/test/functional/ui/bufhl_spec.lua @@ -217,6 +217,161 @@ describe('Buffer highlighting', function() | ]]) end) + + it('and adjusting columns', function() + -- insert before + feed('ggiquite ') + screen:expect{grid=[[ + quite^ a {5:longer} example | + in {6:order} to {7:de}{5:monstr}{7:ate} | + {7:combin}{8:ing}{9: hi}ghlights | + {9:from }{8:diff}{7:erent} sources | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + feed('u') + screen:expect{grid=[[ + ^a {5:longer} example | + in {6:order} to {7:de}{5:monstr}{7:ate} | + {7:combin}{8:ing}{9: hi}ghlights | + {9:from }{8:diff}{7:erent} sources | + {1:~ }| + {1:~ }| + {1:~ }| + 1 change; before #2 0 seconds ago | + ]]} + + -- change/insert in the middle + feed('+fesAAAA') + screen:expect{grid=[[ + a {5:longer} example | + in {6:ordAAAA^r} to {7:de}{5:monstr}{7:ate} | + {7:combin}{8:ing}{9: hi}ghlights | + {9:from }{8:diff}{7:erent} sources | + {1:~ }| + {1:~ }| + {1:~ }| + {7:-- INSERT --} | + ]]} + + feed('tdD') + screen:expect{grid=[[ + a {5:longer} example | + in {6:ordAAAAr} t^o | + {7:combin}{8:ing}{9: hi}ghlights | + {9:from }{8:diff}{7:erent} sources | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + feed('u') + screen:expect{grid=[[ + a {5:longer} example | + in {6:ordAAAAr} to^ demonstrate | + {7:combin}{8:ing}{9: hi}ghlights | + {9:from }{8:diff}{7:erent} sources | + {1:~ }| + {1:~ }| + {1:~ }| + 1 change; before #4 0 seconds ago | + ]]} + + feed('u') + screen:expect{grid=[[ + a {5:longer} example | + in {6:ord^er} to demonstrate | + {7:combin}{8:ing}{9: hi}ghlights | + {9:from }{8:diff}{7:erent} sources | + {1:~ }| + {1:~ }| + {1:~ }| + 1 change; before #3 0 seconds ago | + ]]} + end) + + it('and joining lines', function() + feed('ggJJJ') + screen:expect{grid=[[ + a {5:longer} example in {6:order} to {7:de}{5:monstr}{7:ate}| + {7: combin}{8:ing hi}{7:ghlights^ }{8:from diff}{7:erent sou}| + {7:rces} | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + -- TODO(bfredl): perhaps better undo + feed('uuu') + screen:expect{grid=[[ + ^a longer example | + in order to demonstrate | + combining highlights | + from different sources | + {1:~ }| + {1:~ }| + {1:~ }| + 1 more line; before #2 0 seconds ago | + ]]} + end) + + it('and splitting lines', function() + feed('2Gtti') + screen:expect{grid=[[ + a {5:longer} example | + in {6:order} | + ^ to {7:de}{5:monstr}{7:ate} | + {7:combin}{8:ing}{9: hi}ghlights | + {9:from }{8:diff}{7:erent} sources | + {1:~ }| + {1:~ }| + {7:-- INSERT --} | + ]]} + + -- TODO(bfredl): keep both "parts" after split, requires proper extmark ranges + feed('tsi') + screen:expect{grid=[[ + a {5:longer} example | + in {6:order} | + to {7:de}{5:mo} | + ^nstrate | + {7:combin}{8:ing}{9: hi}ghlights | + {9:from }{8:diff}{7:erent} sources | + {1:~ }| + {7:-- INSERT --} | + ]]} + + -- TODO(bfredl): perhaps better undo + feed('u') + screen:expect{grid=[[ + a {5:longer} example | + in {6:order} | + to demo{7:^nstrat}{8:e} | + {7:combin}{8:ing}{9: hi}ghlights | + {9:from }{8:diff}{7:erent} sources | + {1:~ }| + {1:~ }| + 1 line less; before #3 0 seconds ago | + ]]} + + feed('u') + screen:expect{grid=[[ + a {5:longer} example | + in order^ to demonstrate | + {7:combin}{8:ing}{9: hi}ghlights | + {9:from }{8:diff}{7:erent} sources | + {1:~ }| + {1:~ }| + {1:~ }| + 1 line less; before #2 0 seconds ago | + ]]} + end) end) it('prioritizes latest added highlight', function() -- cgit From 2cc83c961c0533222890adec51ac56041fb2a6b4 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Thu, 14 Nov 2019 20:06:13 +0100 Subject: refactor: use inserted_bytes pattern from vim This covers all "small" inserts and deletes in insert mode, as well as a few more cases like small normal mode deletes vim-patch:8.1.0678: text properties as not adjusted for inserted text --- test/functional/api/mark_extended_spec.lua | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'test') diff --git a/test/functional/api/mark_extended_spec.lua b/test/functional/api/mark_extended_spec.lua index 76db9f9d81..04b2b3bcc5 100644 --- a/test/functional/api/mark_extended_spec.lua +++ b/test/functional/api/mark_extended_spec.lua @@ -475,6 +475,13 @@ describe('Extmarks buffer api', function() check_undo_redo(ns, marks[2], 0, 3, 1, 2) end) + it('deleting right before a mark works #extmarks', function() + -- op_delete in ops.c + set_extmark(ns, marks[1], 0, 2) + feed('0lx') + check_undo_redo(ns, marks[1], 0, 2, 0, 1) + end) + it('deleting on a mark works #extmarks', function() -- op_delete in ops.c set_extmark(ns, marks[1], 0, 2) -- cgit From ddf509c2ba18048c97b5669710fb96a3bce60341 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Thu, 14 Nov 2019 20:24:17 +0100 Subject: test was wrong --- test/functional/api/mark_extended_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/api/mark_extended_spec.lua b/test/functional/api/mark_extended_spec.lua index 04b2b3bcc5..1f6c00b7d2 100644 --- a/test/functional/api/mark_extended_spec.lua +++ b/test/functional/api/mark_extended_spec.lua @@ -422,7 +422,7 @@ describe('Extmarks buffer api', function() set_extmark(ns, marks[1], 1, 2) -- Insert a fullwidth (two col) tilde, NICE feed('0i~') - check_undo_redo(ns, marks[1], 1, 2, 1, 3) + check_undo_redo(ns, marks[1], 1, 2, 1, 5) end) it('marks move with blockwise inserts #extmarks', function() -- cgit From 7d5988feeee275f0ae25e753dcb1d2e1954cd4ac Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 23 Nov 2019 21:26:16 +0100 Subject: tests: remove irrelevant timing info --- test/functional/ui/bufhl_spec.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'test') diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua index 20a2aa9a67..f589bb0e83 100644 --- a/test/functional/ui/bufhl_spec.lua +++ b/test/functional/ui/bufhl_spec.lua @@ -241,7 +241,7 @@ describe('Buffer highlighting', function() {1:~ }| {1:~ }| {1:~ }| - 1 change; before #2 0 seconds ago | + 1 change; before #2 {MATCH:.*}| ]]} -- change/insert in the middle @@ -278,7 +278,7 @@ describe('Buffer highlighting', function() {1:~ }| {1:~ }| {1:~ }| - 1 change; before #4 0 seconds ago | + 1 change; before #4 {MATCH:.*}| ]]} feed('u') @@ -290,7 +290,7 @@ describe('Buffer highlighting', function() {1:~ }| {1:~ }| {1:~ }| - 1 change; before #3 0 seconds ago | + 1 change; before #3 {MATCH:.*}| ]]} end) @@ -317,7 +317,7 @@ describe('Buffer highlighting', function() {1:~ }| {1:~ }| {1:~ }| - 1 more line; before #2 0 seconds ago | + 1 more line; before #2 {MATCH:.*}| ]]} end) @@ -357,7 +357,7 @@ describe('Buffer highlighting', function() {9:from }{8:diff}{7:erent} sources | {1:~ }| {1:~ }| - 1 line less; before #3 0 seconds ago | + 1 line less; before #3 {MATCH:.*}| ]]} feed('u') @@ -369,7 +369,7 @@ describe('Buffer highlighting', function() {1:~ }| {1:~ }| {1:~ }| - 1 line less; before #2 0 seconds ago | + 1 line less; before #2 {MATCH:.*}| ]]} end) end) -- cgit From d0d38fc36e0c1602186aa540417070fa6c1e2746 Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Sun, 24 Nov 2019 02:28:48 -0800 Subject: Lua: vim.env, vim.{g,v,w,bo,wo} #11442 - Add vim variable meta accessors: vim.env, vim.{g,v,w,bo,wo} - Redo gen_char_blob to generate multiple blobs instead of just one so that multiple Lua modules can be inlined. - Reorder vim.lua inclusion so that it can use previously defined C functions and utility functions like vim.shared and vim.inspect things. - Inline shared.lua into nvim, but also keep it available in runtime. --- test/functional/lua/vim_spec.lua | 57 ++++++++++++++++++++++++++++++++++++++++ test/helpers.lua | 3 +++ 2 files changed, 60 insertions(+) (limited to 'test') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 028f2dcd52..446bbafc3c 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -549,4 +549,61 @@ describe('lua stdlib', function() eq(false, exec_lua("return vim.is_callable('foo')")) eq(false, exec_lua("return vim.is_callable({})")) end) + + it('vim.g', function() + exec_lua [[ + vim.api.nvim_set_var("testing", "hi") + vim.api.nvim_set_var("other", 123) + ]] + eq('hi', funcs.luaeval "vim.g.testing") + eq(123, funcs.luaeval "vim.g.other") + eq(NIL, funcs.luaeval "vim.g.nonexistant") + end) + + it('vim.env', function() + exec_lua [[ + vim.fn.setenv("A", 123) + ]] + eq('123', funcs.luaeval "vim.env.A") + eq(NIL, funcs.luaeval "vim.env.B") + end) + + it('vim.v', function() + eq(funcs.luaeval "vim.api.nvim_get_vvar('progpath')", funcs.luaeval "vim.v.progpath") + eq(false, funcs.luaeval "vim.v['false']") + eq(NIL, funcs.luaeval "vim.v.null") + end) + + it('vim.bo', function() + eq('', funcs.luaeval "vim.bo.filetype") + exec_lua [[ + vim.api.nvim_buf_set_option(0, "filetype", "markdown") + BUF = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_option(BUF, "modifiable", false) + ]] + eq(false, funcs.luaeval "vim.bo.modified") + eq('markdown', funcs.luaeval "vim.bo.filetype") + eq(false, funcs.luaeval "vim.bo(BUF).modifiable") + exec_lua [[ + vim.bo.filetype = '' + vim.bo(BUF).modifiable = true + ]] + eq('', funcs.luaeval "vim.bo.filetype") + eq(true, funcs.luaeval "vim.bo(BUF).modifiable") + end) + + it('vim.wo', function() + eq('', funcs.luaeval "vim.bo.filetype") + exec_lua [[ + vim.api.nvim_win_set_option(0, "cole", 2) + BUF = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_option(BUF, "modifiable", false) + ]] + eq(2, funcs.luaeval "vim.wo.cole") + exec_lua [[ + vim.wo.conceallevel = 0 + vim.bo(BUF).modifiable = true + ]] + eq(0, funcs.luaeval "vim.wo.cole") + end) end) diff --git a/test/helpers.lua b/test/helpers.lua index 3f29a28c0d..98f003f208 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -99,6 +99,9 @@ function module.pcall_err(fn, ...) -- to this: -- Error executing lua: .../foo.lua:186: Expected string, got number errmsg = errmsg:gsub([[lua: [a-zA-Z]?:?[^:]-[/\]([^:/\]+):%d+: ]], 'lua: .../%1: ') + -- Compiled modules will not have a path and will just be a name like + -- shared.lua:186, so strip the number. + errmsg = errmsg:gsub([[lua: ([^:/\ ]+):%d+: ]], 'lua: .../%1: ') -- ^ Windows drive-letter (C:) return errmsg end -- cgit From fd5710ae9a3bcbc0f9cbb71de9e39253350ff09c Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 25 Nov 2019 01:08:02 -0800 Subject: doc + extmarks tweaks #11421 - nvim_buf_get_extmarks: rename "amount" => "limit" - rename `set_extmark_index_from_obj` --- test/functional/api/mark_extended_spec.lua | 75 +++++++++++++++--------------- test/functional/api/proc_spec.lua | 2 +- test/functional/cmdline/ctrl_r_spec.lua | 2 +- test/functional/normal/put_spec.lua | 6 +-- 4 files changed, 42 insertions(+), 43 deletions(-) (limited to 'test') diff --git a/test/functional/api/mark_extended_spec.lua b/test/functional/api/mark_extended_spec.lua index 1f6c00b7d2..6735b8c0f5 100644 --- a/test/functional/api/mark_extended_spec.lua +++ b/test/functional/api/mark_extended_spec.lua @@ -36,7 +36,7 @@ local function get_extmarks(ns_id, start, end_, opts) return curbufmeths.get_extmarks(ns_id, start, end_, opts) end -describe('Extmarks buffer api', function() +describe('API/extmarks', function() local screen local marks, positions, ns_string2, ns_string, init_text, row, col local ns, ns2 @@ -153,26 +153,26 @@ describe('Extmarks buffer api', function() end -- next with mark id - rv = get_extmarks(ns, marks[1], {-1, -1}, {amount=1}) + rv = get_extmarks(ns, marks[1], {-1, -1}, {limit=1}) eq({{marks[1], positions[1][1], positions[1][2]}}, rv) - rv = get_extmarks(ns, marks[2], {-1, -1}, {amount=1}) + rv = get_extmarks(ns, marks[2], {-1, -1}, {limit=1}) eq({{marks[2], positions[2][1], positions[2][2]}}, rv) -- next with positional when mark exists at position - rv = get_extmarks(ns, positions[1], {-1, -1}, {amount=1}) + rv = get_extmarks(ns, positions[1], {-1, -1}, {limit=1}) eq({{marks[1], positions[1][1], positions[1][2]}}, rv) -- next with positional index (no mark at position) - rv = get_extmarks(ns, {positions[1][1], positions[1][2] +1}, {-1, -1}, {amount=1}) + rv = get_extmarks(ns, {positions[1][1], positions[1][2] +1}, {-1, -1}, {limit=1}) eq({{marks[2], positions[2][1], positions[2][2]}}, rv) -- next with Extremity index - rv = get_extmarks(ns, {0,0}, {-1, -1}, {amount=1}) + rv = get_extmarks(ns, {0,0}, {-1, -1}, {limit=1}) eq({{marks[1], positions[1][1], positions[1][2]}}, rv) -- nextrange with mark id rv = get_extmarks(ns, marks[1], marks[3]) eq({marks[1], positions[1][1], positions[1][2]}, rv[1]) eq({marks[2], positions[2][1], positions[2][2]}, rv[2]) - -- nextrange with amount - rv = get_extmarks(ns, marks[1], marks[3], {amount=2}) + -- nextrange with `limit` + rv = get_extmarks(ns, marks[1], marks[3], {limit=2}) eq(2, table.getn(rv)) -- nextrange with positional when mark exists at position rv = get_extmarks(ns, positions[1], positions[3]) @@ -196,18 +196,18 @@ describe('Extmarks buffer api', function() eq({{marks[3], positions[3][1], positions[3][2]}}, rv) -- prev with mark id - rv = get_extmarks(ns, marks[3], {0, 0}, {amount=1}) + rv = get_extmarks(ns, marks[3], {0, 0}, {limit=1}) eq({{marks[3], positions[3][1], positions[3][2]}}, rv) - rv = get_extmarks(ns, marks[2], {0, 0}, {amount=1}) + rv = get_extmarks(ns, marks[2], {0, 0}, {limit=1}) eq({{marks[2], positions[2][1], positions[2][2]}}, rv) -- prev with positional when mark exists at position - rv = get_extmarks(ns, positions[3], {0, 0}, {amount=1}) + rv = get_extmarks(ns, positions[3], {0, 0}, {limit=1}) eq({{marks[3], positions[3][1], positions[3][2]}}, rv) -- prev with positional index (no mark at position) - rv = get_extmarks(ns, {positions[1][1], positions[1][2] +1}, {0, 0}, {amount=1}) + rv = get_extmarks(ns, {positions[1][1], positions[1][2] +1}, {0, 0}, {limit=1}) eq({{marks[1], positions[1][1], positions[1][2]}}, rv) -- prev with Extremity index - rv = get_extmarks(ns, {-1,-1}, {0,0}, {amount=1}) + rv = get_extmarks(ns, {-1,-1}, {0,0}, {limit=1}) eq({{marks[3], positions[3][1], positions[3][2]}}, rv) -- prevrange with mark id @@ -215,8 +215,8 @@ describe('Extmarks buffer api', function() eq({marks[3], positions[3][1], positions[3][2]}, rv[1]) eq({marks[2], positions[2][1], positions[2][2]}, rv[2]) eq({marks[1], positions[1][1], positions[1][2]}, rv[3]) - -- prevrange with amount - rv = get_extmarks(ns, marks[3], marks[1], {amount=2}) + -- prevrange with limit + rv = get_extmarks(ns, marks[3], marks[1], {limit=2}) eq(2, table.getn(rv)) -- prevrange with positional when mark exists at position rv = get_extmarks(ns, positions[3], positions[1]) @@ -241,7 +241,7 @@ describe('Extmarks buffer api', function() eq({{marks[1], positions[1][1], positions[1][2]}}, rv) end) - it('querying for information with amount #extmarks', function() + it('querying for information with limit #extmarks', function() -- add some more marks for i, m in ipairs(marks) do if positions[i] ~= nil then @@ -250,19 +250,19 @@ describe('Extmarks buffer api', function() end end - local rv = get_extmarks(ns, {0, 0}, {-1, -1}, {amount=1}) + local rv = get_extmarks(ns, {0, 0}, {-1, -1}, {limit=1}) eq(1, table.getn(rv)) - rv = get_extmarks(ns, {0, 0}, {-1, -1}, {amount=2}) + rv = get_extmarks(ns, {0, 0}, {-1, -1}, {limit=2}) eq(2, table.getn(rv)) - rv = get_extmarks(ns, {0, 0}, {-1, -1}, {amount=3}) + rv = get_extmarks(ns, {0, 0}, {-1, -1}, {limit=3}) eq(3, table.getn(rv)) -- now in reverse - rv = get_extmarks(ns, {0, 0}, {-1, -1}, {amount=1}) + rv = get_extmarks(ns, {0, 0}, {-1, -1}, {limit=1}) eq(1, table.getn(rv)) - rv = get_extmarks(ns, {0, 0}, {-1, -1}, {amount=2}) + rv = get_extmarks(ns, {0, 0}, {-1, -1}, {limit=2}) eq(2, table.getn(rv)) - rv = get_extmarks(ns, {0, 0}, {-1, -1}, {amount=3}) + rv = get_extmarks(ns, {0, 0}, {-1, -1}, {limit=3}) eq(3, table.getn(rv)) end) @@ -295,9 +295,9 @@ describe('Extmarks buffer api', function() rv) end) - it('get_marks amount 0 returns nothing #extmarks', function() + it('get_marks limit=0 returns nothing #extmarks', function() set_extmark(ns, marks[1], positions[1][1], positions[1][2]) - local rv = get_extmarks(ns, {-1, -1}, {-1, -1}, {amount=0}) + local rv = get_extmarks(ns, {-1, -1}, {-1, -1}, {limit=0}) eq({}, rv) end) @@ -730,7 +730,7 @@ describe('Extmarks buffer api', function() -- Test updates feed('o') set_extmark(ns, marks[1], positions[1][1], positions[1][2]) - rv = get_extmarks(ns, marks[1], marks[1], {amount=1}) + rv = get_extmarks(ns, marks[1], marks[1], {limit=1}) eq(1, table.getn(rv)) feed("u") feed("") @@ -771,23 +771,23 @@ describe('Extmarks buffer api', function() set_extmark(ns2, marks[2], positions[2][1], positions[2][2]) set_extmark(ns2, marks[3], positions[3][1], positions[3][2]) - -- get_next (amount set) - rv = get_extmarks(ns, {0, 0}, positions[2], {amount=1}) + -- get_next (limit set) + rv = get_extmarks(ns, {0, 0}, positions[2], {limit=1}) eq(1, table.getn(rv)) - rv = get_extmarks(ns2, {0, 0}, positions[2], {amount=1}) + rv = get_extmarks(ns2, {0, 0}, positions[2], {limit=1}) eq(1, table.getn(rv)) - -- get_prev (amount set) - rv = get_extmarks(ns, positions[1], {0, 0}, {amount=1}) + -- get_prev (limit set) + rv = get_extmarks(ns, positions[1], {0, 0}, {limit=1}) eq(1, table.getn(rv)) - rv = get_extmarks(ns2, positions[1], {0, 0}, {amount=1}) + rv = get_extmarks(ns2, positions[1], {0, 0}, {limit=1}) eq(1, table.getn(rv)) - -- get_next (amount not set) + -- get_next (no limit) rv = get_extmarks(ns, positions[1], positions[2]) eq(2, table.getn(rv)) rv = get_extmarks(ns2, positions[1], positions[2]) eq(2, table.getn(rv)) - -- get_prev (amount not set) + -- get_prev (no limit) rv = get_extmarks(ns, positions[2], positions[1]) eq(2, table.getn(rv)) rv = get_extmarks(ns2, positions[2], positions[1]) @@ -1250,7 +1250,7 @@ describe('Extmarks buffer api', function() eq("col value outside range", pcall_err(set_extmark, ns, marks[1], 0, invalid_col)) end) - it('when line > line_count, throw error #extmarks', function() + it('fails when line > line_count #extmarks', function() local invalid_col = init_text:len() + 1 local invalid_lnum = 3 eq('line value outside range', pcall_err(set_extmark, ns, marks[1], invalid_lnum, invalid_col)) @@ -1258,10 +1258,9 @@ describe('Extmarks buffer api', function() end) it('bug from check_col in extmark_set #extmarks_sub', function() - -- This bug was caused by extmark_set always using - -- check_col. check_col always uses the current buffer. - -- This wasn't working during undo so we now use - -- check_col and check_lnum only when they are required. + -- This bug was caused by extmark_set always using check_col. check_col + -- always uses the current buffer. This wasn't working during undo so we + -- now use check_col and check_lnum only when they are required. feed('A67890xx') feed('A1234567890xx') set_extmark(ns, marks[1], 3, 4) diff --git a/test/functional/api/proc_spec.lua b/test/functional/api/proc_spec.lua index 063d382790..d828bdf948 100644 --- a/test/functional/api/proc_spec.lua +++ b/test/functional/api/proc_spec.lua @@ -10,7 +10,7 @@ local request = helpers.request local retry = helpers.retry local NIL = helpers.NIL -describe('api', function() +describe('API', function() before_each(clear) describe('nvim_get_proc_children', function() diff --git a/test/functional/cmdline/ctrl_r_spec.lua b/test/functional/cmdline/ctrl_r_spec.lua index d2dad23e98..a0f3955282 100644 --- a/test/functional/cmdline/ctrl_r_spec.lua +++ b/test/functional/cmdline/ctrl_r_spec.lua @@ -15,7 +15,7 @@ describe('cmdline CTRL-R', function() -- inserted between lines, NOT after the final line. eq('line1abc\rline2somemoretext', funcs.getcmdline()) - -- Yank 2 lines characterwise, then paste to cmdline. + -- Yank 2 lines charwise, then paste to cmdline. feed([[gg05lyvj:0]]) -- inserted between lines, NOT after the final line. eq('abc\rline2', funcs.getcmdline()) diff --git a/test/functional/normal/put_spec.lua b/test/functional/normal/put_spec.lua index 40a4f051e3..357fafec44 100644 --- a/test/functional/normal/put_spec.lua +++ b/test/functional/normal/put_spec.lua @@ -307,7 +307,7 @@ describe('put command', function() -- }}} -- Conversion functions {{{ - local function convert_characterwise(expect_base, conversion_table, + local function convert_charwise(expect_base, conversion_table, virtualedit_end, visual_put) expect_base = dedent(expect_base) -- There is no difference between 'P' and 'p' when VIsual_active @@ -335,7 +335,7 @@ describe('put command', function() expect_base = expect_base:gsub('(test_stringx?)"', '%1.') end return expect_base - end -- convert_characterwise() + end -- convert_charwise() local function make_back(string) local prev_line @@ -500,7 +500,7 @@ describe('put command', function() local function run_normal_mode_tests(test_string, base_map, extra_setup, virtualedit_end, selection_string) local function convert_closure(e, c) - return convert_characterwise(e, c, virtualedit_end, selection_string) + return convert_charwise(e, c, virtualedit_end, selection_string) end local function expect_normal_creator(expect_base, conversion_table) local test_expect = expect_creator(convert_closure, expect_base, conversion_table) -- cgit From 4a77df2e518a51ffd5a5fe311424b4b5305009a7 Mon Sep 17 00:00:00 2001 From: notomo Date: Tue, 26 Nov 2019 00:50:30 +0900 Subject: [RFC] extmark: fix E315 in nvim_buf_set_extmark (#11449) extmark: need to use buf instead of curbuf --- test/functional/api/mark_extended_spec.lua | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'test') diff --git a/test/functional/api/mark_extended_spec.lua b/test/functional/api/mark_extended_spec.lua index 6735b8c0f5..edb0f8ac2b 100644 --- a/test/functional/api/mark_extended_spec.lua +++ b/test/functional/api/mark_extended_spec.lua @@ -5,6 +5,7 @@ local request = helpers.request local eq = helpers.eq local ok = helpers.ok local curbufmeths = helpers.curbufmeths +local bufmeths = helpers.bufmeths local pcall_err = helpers.pcall_err local insert = helpers.insert local feed = helpers.feed @@ -1274,6 +1275,13 @@ describe('API/extmarks', function() local id = set_extmark(ns, 0, 0, 2) eq({{id, 0, 2}}, get_extmarks(ns,0, -1)) end) + + it('can set a mark to other buffer', function() + local buf = request('nvim_create_buf', 0, 1) + request('nvim_buf_set_lines', buf, 0, -1, 1, {"", ""}) + local id = bufmeths.set_extmark(buf, ns, 0, 1, 0, {}) + eq({{id, 1, 0}}, bufmeths.get_extmarks(buf, ns, 0, -1, {})) + end) end) describe('Extmarks buffer api with many marks', function() -- cgit From 36d1335a667d54c26ab7cca23bc60998cb8e0fb2 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 25 Nov 2019 08:56:42 -0800 Subject: UI: emit mouse_on/mouse_off on attach #11455 closes #11372 --- test/functional/ui/options_spec.lua | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/ui/options_spec.lua b/test/functional/ui/options_spec.lua index ea71f5eae9..31007b92b1 100644 --- a/test/functional/ui/options_spec.lua +++ b/test/functional/ui/options_spec.lua @@ -5,7 +5,7 @@ local command = helpers.command local eq = helpers.eq local shallowcopy = helpers.shallowcopy -describe('ui receives option updates', function() +describe('UI receives option updates', function() local screen local function reset(opts, ...) @@ -47,6 +47,33 @@ describe('ui receives option updates', function() end) end) + it('on attach #11372', function() + clear() + local evs = {} + screen = Screen.new(20,5) + -- Override mouse_on/mouse_off handlers. + function screen._handle_mouse_on() + table.insert(evs, 'mouse_on') + end + function screen._handle_mouse_off() + table.insert(evs, 'mouse_off') + end + screen:attach() + screen:expect(function() + eq({'mouse_off'}, evs) + end) + command("set mouse=nvi") + screen:expect(function() + eq({'mouse_off','mouse_on'}, evs) + end) + screen:detach() + eq({'mouse_off','mouse_on'}, evs) + screen:attach() + screen:expect(function() + eq({'mouse_off','mouse_on','mouse_on'}, evs) + end) + end) + it("when setting options", function() local expected = reset() local defaults = shallowcopy(expected) -- cgit From a76a669ac24ec91144153b65e0a0dc5598802653 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Tue, 26 Nov 2019 17:57:53 +0100 Subject: lua: make vim.wo and vim.bo used nested indexing for specified handle Also missing option should be an error. Options are functionality, not arbitrary variable names (as for vim.g) --- test/functional/lua/vim_spec.lua | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index ebe394f164..720a33d430 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -587,13 +587,17 @@ describe('lua stdlib', function() ]] eq(false, funcs.luaeval "vim.bo.modified") eq('markdown', funcs.luaeval "vim.bo.filetype") - eq(false, funcs.luaeval "vim.bo(BUF).modifiable") + eq(false, funcs.luaeval "vim.bo[BUF].modifiable") exec_lua [[ vim.bo.filetype = '' - vim.bo(BUF).modifiable = true + vim.bo[BUF].modifiable = true ]] eq('', funcs.luaeval "vim.bo.filetype") - eq(true, funcs.luaeval "vim.bo(BUF).modifiable") + eq(true, funcs.luaeval "vim.bo[BUF].modifiable") + matches("^Error executing lua: .*: Invalid option name: 'nosuchopt'$", + pcall_err(exec_lua, 'return vim.bo.nosuchopt')) + matches("^Error executing lua: .*: Expected lua string$", + pcall_err(exec_lua, 'return vim.bo[0][0].autoread')) end) it('vim.wo', function() @@ -606,8 +610,12 @@ describe('lua stdlib', function() eq(2, funcs.luaeval "vim.wo.cole") exec_lua [[ vim.wo.conceallevel = 0 - vim.bo(BUF).modifiable = true + vim.bo[BUF].modifiable = true ]] eq(0, funcs.luaeval "vim.wo.cole") + matches("^Error executing lua: .*: Invalid option name: 'notanopt'$", + pcall_err(exec_lua, 'return vim.wo.notanopt')) + matches("^Error executing lua: .*: Expected lua string$", + pcall_err(exec_lua, 'return vim.wo[0][0].list')) end) end) -- cgit From 49a40f425d88cbbac09fdf442c22f725bffc2249 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 24 Nov 2019 10:59:15 +0100 Subject: options: make 'fillchars' and 'listchars' global-local These options were previously global. A global-local window option behaves closer to a global option "per default" (i e with :set), but still supports local behavior via :setl Also this restores back-compat for nvim_set_option("fcs", ...) which are currently broken on 0.4.x but worked in earlier versions --- test/functional/options/chars_spec.lua | 42 +++++++++++++++++++++++++++------- test/functional/ui/mouse_spec.lua | 8 +++++-- 2 files changed, 40 insertions(+), 10 deletions(-) (limited to 'test') diff --git a/test/functional/options/chars_spec.lua b/test/functional/options/chars_spec.lua index 3453e79429..5439ca3dba 100644 --- a/test/functional/options/chars_spec.lua +++ b/test/functional/options/chars_spec.lua @@ -67,15 +67,28 @@ describe("'fillchars'", function() shouldfail('eob:xy') -- two ascii chars shouldfail('eob:\255', 'eob:') -- invalid UTF-8 end) - it('is local to window', function() - clear() - screen = Screen.new(50, 5) - screen:attach() + it('has global value', function() + screen:try_resize(50, 5) insert("foo\nbar") command('set laststatus=0') command('1,2fold') command('vsplit') command('set fillchars=fold:x') + screen:expect([[ + ^+-- 2 lines: fooxxxxxxxx│+-- 2 lines: fooxxxxxxx| + ~ │~ | + ~ │~ | + ~ │~ | + | + ]]) + end) + it('has local window value', function() + screen:try_resize(50, 5) + insert("foo\nbar") + command('set laststatus=0') + command('1,2fold') + command('vsplit') + command('setl fillchars=fold:x') screen:expect([[ ^+-- 2 lines: fooxxxxxxxx│+-- 2 lines: foo·······| ~ │~ | @@ -96,12 +109,25 @@ describe("'listchars'", function() screen:attach() end) - it('is local to window', function() + it('has global value', function() + feed('i') + command('set list laststatus=0') + command('vsplit') + command('set listchars=tab:<->') + screen:expect([[ + <------><------>^<------> │<------><------><------>| + ~ │~ | + ~ │~ | + ~ │~ | + | + ]]) + end) + it('has value local to window', function() feed('i') - command('set laststatus=0') - command('set list listchars=tab:<->') + command('set list laststatus=0') + command('setl listchars=tab:<->') command('vsplit') - command('set listchars&') + command('setl listchars<') screen:expect([[ > > ^> │<------><------><------>| ~ │~ | diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index 7840ba9167..d857b57a31 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -12,7 +12,10 @@ describe('ui/mouse/input', function() clear() meths.set_option('mouse', 'a') meths.set_option('list', true) - meths.set_option('listchars', 'eol:$') + -- NB: this is weird, but mostly irrelevant to the test + -- So I didn't bother to change it + command('set listchars=eol:$') + command('setl listchars=nbsp:x') screen = Screen.new(25, 5) screen:attach() screen:set_default_attr_ids({ @@ -812,7 +815,8 @@ describe('ui/mouse/input', function() feed_command('set concealcursor=ni') feed_command('set nowrap') - feed_command('set shiftwidth=2 tabstop=4 list listchars=tab:>-') + feed_command('set shiftwidth=2 tabstop=4 list') + feed_command('setl listchars=tab:>-') feed_command('syntax match NonText "\\*" conceal') feed_command('syntax match NonText "cats" conceal cchar=X') feed_command('syntax match NonText "x" conceal cchar=>') -- cgit From 001e69cd4602e84219fd7cfd8ade62f0cb24097c Mon Sep 17 00:00:00 2001 From: Brian Wignall Date: Tue, 26 Nov 2019 07:15:14 -0500 Subject: doc: fix typos close #11459 --- test/functional/api/mark_extended_spec.lua | 4 ++-- test/functional/autocmd/cmdline_spec.lua | 2 +- test/functional/cmdline/history_spec.lua | 4 ++-- test/functional/ui/cmdline_spec.lua | 2 +- test/functional/ui/searchhl_spec.lua | 2 +- test/unit/os/env_spec.lua | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) (limited to 'test') diff --git a/test/functional/api/mark_extended_spec.lua b/test/functional/api/mark_extended_spec.lua index edb0f8ac2b..bf910568b1 100644 --- a/test/functional/api/mark_extended_spec.lua +++ b/test/functional/api/mark_extended_spec.lua @@ -507,7 +507,7 @@ describe('API/extmarks', function() feed('0l3dl') check_undo_redo(ns, marks[1], 0, 2, 0, 1) check_undo_redo(ns, marks[2], 0, 3, 0, 1) - -- delete 1, nothing should happend to our marks + -- delete 1, nothing should happen to our marks feed('u') feed('$x') check_undo_redo(ns, marks[2], 0, 3, 0, 3) @@ -543,7 +543,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[1], 0, 1, 0, 0) check_undo_redo(ns, marks[2], 0, 3, 0, 0) check_undo_redo(ns, marks[3], 1, 2, 1, 0) - -- delete 1, nothing should happend to our marks + -- delete 1, nothing should happen to our marks feed('u') feed('$jx') check_undo_redo(ns, marks[2], 0, 3, 0, 3) diff --git a/test/functional/autocmd/cmdline_spec.lua b/test/functional/autocmd/cmdline_spec.lua index 51b7b819e9..8ec06dc148 100644 --- a/test/functional/autocmd/cmdline_spec.lua +++ b/test/functional/autocmd/cmdline_spec.lua @@ -33,7 +33,7 @@ describe('cmdline autocommands', function() eq({'notification', 'CmdlineEnter', {{cmdtype=':', cmdlevel=1}}}, next_msg()) -- note: feed('bork') might not consume 'bork' - -- due to out-of-band interupt handling + -- due to out-of-band interrupt handling feed('bork') eq({'notification', 'CmdlineLeave', {{cmdtype=':', cmdlevel=1, abort=true}}}, next_msg()) diff --git a/test/functional/cmdline/history_spec.lua b/test/functional/cmdline/history_spec.lua index 20f9cf06a2..ee2d36f642 100644 --- a/test/functional/cmdline/history_spec.lua +++ b/test/functional/cmdline/history_spec.lua @@ -6,7 +6,7 @@ describe('history support code', function() before_each(clear) it('correctly clears start of the history', function() - -- Regression test: check absense of the memory leak when clearing start of + -- Regression test: check absence of the memory leak when clearing start of -- the history using ex_getln.c/clr_history(). eq(1, funcs.histadd(':', 'foo')) eq(1, funcs.histdel(':')) @@ -14,7 +14,7 @@ describe('history support code', function() end) it('correctly clears end of the history', function() - -- Regression test: check absense of the memory leak when clearing end of + -- Regression test: check absence of the memory leak when clearing end of -- the history using ex_getln.c/clr_history(). meths.set_option('history', 1) eq(1, funcs.histadd(':', 'foo')) diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index c2354103c2..21c01b3458 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -775,7 +775,7 @@ local function test_cmdline(linegrid) }}} -- This used to send an invalid event where pos where larger than the total - -- lenght of content. Checked in _handle_cmdline_show. + -- length of content. Checked in _handle_cmdline_show. feed('') screen:expect([[ ^ | diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua index 486de02a09..635ce7392b 100644 --- a/test/functional/ui/searchhl_spec.lua +++ b/test/functional/ui/searchhl_spec.lua @@ -442,7 +442,7 @@ describe('search highlighting', function() feed_command("call matchadd('MyGroup', 'special')") feed_command("call matchadd('MyGroup2', 'text', 0)") - -- searchhl and matchadd matches are exclusive, only the higest priority + -- searchhl and matchadd matches are exclusive, only the highest priority -- is used (and matches with lower priorities are not combined) feed_command("/ial te") screen:expect([[ diff --git a/test/unit/os/env_spec.lua b/test/unit/os/env_spec.lua index c543551607..e24a389d69 100644 --- a/test/unit/os/env_spec.lua +++ b/test/unit/os/env_spec.lua @@ -121,7 +121,7 @@ describe('env.c', function() local name = 'NVIM_UNIT_TEST_GETENV_1N' local value = 'NVIM_UNIT_TEST_GETENV_1V' eq(NULL, os_getenv(name)) - -- Use os_setenv because Lua dosen't have setenv. + -- Use os_setenv because Lua doesn't have setenv. os_setenv(name, value, 1) eq(value, os_getenv(name)) -- cgit From 1bb7ea189e0b1bf402f4733d42dbf3d74ade932e Mon Sep 17 00:00:00 2001 From: erw7 Date: Fri, 29 Nov 2019 13:09:03 +0900 Subject: win_line: Fix crash with 'rightleft' in :terminal #11460 fixes #11438 Backtrace: 0 schar_from_ascii ( p=0x801cc9e112c3 , c=32 ' ') at ../src/nvim/screen.c:5263 1 0x00007f31460eccc5 in win_line (wp=wp@entry=0x7fffc9df6230, lnum=lnum@entry=11, startrow=startrow@entry=10, endrow=41, nochange=false, number_only=number_only@entry=false) at ../src/nvim/screen.c:4025 2 0x00007f31460eed8e in win_update (wp=wp@entry=0x7fffc9df6230) at ../src/nvim/screen.c:1403 3 0x00007f31460f011f in update_screen (type=) at ../src/nvim/screen.c:502 4 0x00007f3146138ef4 in normal_redraw (s=s@entry=0x7fffd0a5f700) at ../src/nvim/normal.c:1247 5 0x00007f314613b159 in normal_check (state=0x7fffd0a5f700) at ../src/nvim/normal.c:1324 6 0x00007f31460accfe in state_enter (s=0x7fffd0a5f700) at ../src/nvim/state.c:28 7 0x00007f3146143099 in normal_enter (cmdwin=, noexmode=) at ../src/nvim/normal.c:463 8 0x00007f314618b541 in main (argc=, argv=) at ../src/nvim/main.c:580 --- test/functional/terminal/buffer_spec.lua | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'test') diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index 7560b0e872..2fc7a021cb 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -5,6 +5,7 @@ local wait = helpers.wait local eval, feed_command, source = helpers.eval, helpers.feed_command, helpers.source local eq, neq = helpers.eq, helpers.neq local write_file = helpers.write_file +local command= helpers.command describe(':terminal buffer', function() local screen @@ -224,6 +225,22 @@ describe(':terminal buffer', function() neq('terminal', eval('&buftype')) end) end) + + it('it works with set rightleft #11438', function() + local columns = eval('&columns') + feed(string.rep('a', columns)) + command('set rightleft') + screen:expect([[ + ydaer ytt| + {1:a}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + | + | + | + | + {3:-- TERMINAL --} | + ]]) + command('bdelete!') + end) end) describe('No heap-buffer-overflow when using', function() -- cgit From f6e7857c54a015cdfac9ce65ec0b65d65d590aeb Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 29 Nov 2019 23:48:14 -0800 Subject: floatwin: show error if window is closed immediately #11476 Autocmds may close window while it is being entered, then win_set_minimal_style(wp) operates on an invalid pointer. We could silently ignore this instead, but it is unlikely to be intentional, so it is more useful to show an error. fix #11383 --- test/functional/ui/float_spec.lua | 29 ++++++++++++++++++++++++++++- test/functional/ui/options_spec.lua | 4 ++-- 2 files changed, 30 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 8ddb2e90a6..7a5569c14b 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -2,9 +2,11 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local os = require('os') local clear, feed = helpers.clear, helpers.feed +local assert_alive = helpers.assert_alive local command, feed_command = helpers.command, helpers.feed_command local eval = helpers.eval local eq = helpers.eq +local exec_lua = helpers.exec_lua local insert = helpers.insert local meths = helpers.meths local curbufmeths = helpers.curbufmeths @@ -12,7 +14,7 @@ local funcs = helpers.funcs local run = helpers.run local pcall_err = helpers.pcall_err -describe('floating windows', function() +describe('floatwin', function() before_each(function() clear() end) @@ -56,6 +58,31 @@ describe('floating windows', function() eq(1000, funcs.win_getid()) end) + it('closed immediately by autocmd #11383', function() + eq('Error executing lua: [string ""]:4: Window was closed immediately', + pcall_err(exec_lua, [[ + local a = vim.api + local function crashes(contents) + local buf = a.nvim_create_buf(false, true) + local floatwin = a.nvim_open_win(buf, true, { + relative = 'cursor'; + style = 'minimal'; + row = 0; col = 0; + height = #contents; + width = 10; + }) + a.nvim_buf_set_lines(buf, 0, -1, true, contents) + local winnr = vim.fn.win_id2win(floatwin) + a.nvim_command('wincmd p') + a.nvim_command('autocmd CursorMoved * ++once '..winnr..'wincmd c') + return buf, floatwin + end + crashes{'foo'} + crashes{'bar'} + ]])) + assert_alive() + end) + local function with_ext_multigrid(multigrid) local screen before_each(function() diff --git a/test/functional/ui/options_spec.lua b/test/functional/ui/options_spec.lua index 31007b92b1..581e196bbb 100644 --- a/test/functional/ui/options_spec.lua +++ b/test/functional/ui/options_spec.lua @@ -52,10 +52,10 @@ describe('UI receives option updates', function() local evs = {} screen = Screen.new(20,5) -- Override mouse_on/mouse_off handlers. - function screen._handle_mouse_on() + function screen:_handle_mouse_on() table.insert(evs, 'mouse_on') end - function screen._handle_mouse_off() + function screen:_handle_mouse_off() table.insert(evs, 'mouse_off') end screen:attach() -- cgit From a17ccb0d24eff5e6ce0e08f8ce9c4273cd9803b4 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 1 Dec 2019 01:06:10 -0800 Subject: screen.lua: remove screen:_on_event #11488 Tests can redefine the handlers, so we don't need this extra hook. --- test/functional/example_spec.lua | 38 ++++++++++++++++++++++++++++++++++++- test/functional/ui/screen.lua | 21 ++++++-------------- test/functional/ui/tabline_spec.lua | 8 +++----- 3 files changed, 46 insertions(+), 21 deletions(-) (limited to 'test') diff --git a/test/functional/example_spec.lua b/test/functional/example_spec.lua index 883fe4ba63..f07f88b2b6 100644 --- a/test/functional/example_spec.lua +++ b/test/functional/example_spec.lua @@ -3,7 +3,10 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') -local clear, feed = helpers.clear, helpers.feed +local clear = helpers.clear +local command = helpers.command +local eq = helpers.eq +local feed = helpers.feed describe('example', function() local screen @@ -33,4 +36,37 @@ describe('example', function() | ]]) end) + + it('override UI event-handler', function() + -- Example: override the "tabline_update" UI event handler. + -- + -- screen.lua defines default handlers for UI events, but tests + -- may sometimes want to override a handler. + + -- The UI must declare that it wants to handle the UI events. + -- For this example, we enable `ext_tabline`: + screen:detach() + screen = Screen.new(25, 5) + screen:attach({rgb=true, ext_tabline=true}) + + -- From ":help ui" we find that `tabline_update` receives `curtab` and + -- `tabs` objects. So we declare the UI handler like this: + local event_tabs, event_curtab + function screen:_handle_tabline_update(curtab, tabs) + event_curtab, event_tabs = curtab, tabs + end + + -- Create a tabpage... + command('tabedit foo') + + -- Use screen:expect{condition=…} to check the result. + screen:expect{condition=function() + eq({ id = 2 }, event_curtab) + eq({ + {tab = { id = 1 }, name = '[No Name]'}, + {tab = { id = 2 }, name = 'foo'}, + }, + event_tabs) + end} + end) end) diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index d3f78bf77b..64f784afe3 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -606,17 +606,12 @@ function Screen:_redraw(updates) for i = 2, #update do local handler_name = '_handle_'..method local handler = self[handler_name] - if handler ~= nil then - local status, res = pcall(handler, self, unpack(update[i])) - if not status then - error(handler_name..' failed' - ..'\n payload: '..inspect(update) - ..'\n error: '..tostring(res)) - end - else - assert(self._on_event, - "Add Screen:"..handler_name.." or call Screen:set_on_event_handler") - self._on_event(method, update[i]) + assert(handler ~= nil, "missing handler: Screen:"..handler_name) + local status, res = pcall(handler, self, unpack(update[i])) + if not status then + error(handler_name..' failed' + ..'\n payload: '..inspect(update) + ..'\n error: '..tostring(res)) end end if k == #updates and method == "flush" then @@ -626,10 +621,6 @@ function Screen:_redraw(updates) return did_flush end -function Screen:set_on_event_handler(callback) - self._on_event = callback -end - function Screen:_handle_resize(width, height) self:_handle_grid_resize(1, width, height) self._scroll_region = { diff --git a/test/functional/ui/tabline_spec.lua b/test/functional/ui/tabline_spec.lua index 0ee7e03fac..23aae81745 100644 --- a/test/functional/ui/tabline_spec.lua +++ b/test/functional/ui/tabline_spec.lua @@ -10,11 +10,9 @@ describe('ui/ext_tabline', function() clear() screen = Screen.new(25, 5) screen:attach({rgb=true, ext_tabline=true}) - screen:set_on_event_handler(function(name, data) - if name == "tabline_update" then - event_curtab, event_tabs = unpack(data) - end - end) + function screen:_handle_tabline_update(curtab, tabs) + event_curtab, event_tabs = curtab, tabs + end end) it('publishes UI events', function() -- cgit From edca84cfc91e637e97fcadd484a57911b20cfe75 Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Sun, 1 Dec 2019 05:04:57 -0800 Subject: Return nil instead of NIL for vim.env (#11486) --- test/functional/lua/vim_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 720a33d430..877d14f7e7 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -569,7 +569,7 @@ describe('lua stdlib', function() vim.fn.setenv("A", 123) ]] eq('123', funcs.luaeval "vim.env.A") - eq(NIL, funcs.luaeval "vim.env.B") + eq(true, funcs.luaeval "vim.env.B == nil") end) it('vim.v', function() -- cgit From e6da21d12895e2f34c6ce41bb16400d5eef3ea12 Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Sun, 1 Dec 2019 05:28:53 -0800 Subject: Add vim.cmd as an alias for nvim_command (#11446) --- test/functional/lua/vim_spec.lua | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'test') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 877d14f7e7..45818d2a99 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -618,4 +618,13 @@ describe('lua stdlib', function() matches("^Error executing lua: .*: Expected lua string$", pcall_err(exec_lua, 'return vim.wo[0][0].list')) end) + + it('vim.cmd', function() + exec_lua [[ + vim.cmd "autocmd BufNew * ++once lua BUF = vim.fn.expand('')" + vim.cmd "new" + ]] + eq('2', funcs.luaeval "BUF") + eq(2, funcs.luaeval "#vim.api.nvim_list_bufs()") + end) end) -- cgit From 70b606166640d043fc7b78a52b89ff1bba798b6a Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Sun, 1 Dec 2019 05:32:55 -0800 Subject: Add vim.startswith and vim.endswith (#11248) --- test/functional/lua/vim_spec.lua | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'test') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 45818d2a99..22c975147f 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -117,6 +117,34 @@ describe('lua stdlib', function() eq(1, funcs.luaeval('vim.stricmp("\\0C\\0", "\\0B\\0")')) end) + it('vim.startswith', function() + eq(true, funcs.luaeval('vim.startswith("123", "1")')) + eq(true, funcs.luaeval('vim.startswith("123", "")')) + eq(true, funcs.luaeval('vim.startswith("123", "123")')) + eq(true, funcs.luaeval('vim.startswith("", "")')) + + eq(false, funcs.luaeval('vim.startswith("123", " ")')) + eq(false, funcs.luaeval('vim.startswith("123", "2")')) + eq(false, funcs.luaeval('vim.startswith("123", "1234")')) + + eq("string", type(pcall_err(funcs.luaeval, 'vim.startswith("123", nil)'))) + eq("string", type(pcall_err(funcs.luaeval, 'vim.startswith(nil, "123")'))) + end) + + it('vim.endswith', function() + eq(true, funcs.luaeval('vim.endswith("123", "3")')) + eq(true, funcs.luaeval('vim.endswith("123", "")')) + eq(true, funcs.luaeval('vim.endswith("123", "123")')) + eq(true, funcs.luaeval('vim.endswith("", "")')) + + eq(false, funcs.luaeval('vim.endswith("123", " ")')) + eq(false, funcs.luaeval('vim.endswith("123", "2")')) + eq(false, funcs.luaeval('vim.endswith("123", "1234")')) + + eq("string", type(pcall_err(funcs.luaeval, 'vim.endswith("123", nil)'))) + eq("string", type(pcall_err(funcs.luaeval, 'vim.endswith(nil, "123")'))) + end) + it("vim.str_utfindex/str_byteindex", function() exec_lua([[_G.test_text = "xy åäö ɧ 汉语 ↥ 🤦x🦄 å بِيَّ"]]) local indicies32 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,29,33,34,35,37,38,40,42,44,46,48} -- cgit From 6aa03e86da041284b5f27a59f73cef0991fc577e Mon Sep 17 00:00:00 2001 From: Siddhant Gupta Date: Sun, 6 Oct 2019 13:37:54 -0700 Subject: API: nvim_source --- test/functional/api/vim_spec.lua | 78 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) (limited to 'test') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 8b77dbcaa6..14ed474eb1 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -74,6 +74,84 @@ describe('API', function() eq({mode='i', blocking=false}, nvim("get_mode")) end) + describe('nvim_source', function() + it('works with a one-liner', function() + nvim('source', "let x1 = 'a'") + eq(nvim('get_var', 'x1'), 'a') + end) + + it('works with stray newline character', function() + nvim('source', "let x2 = 'a'\n") + eq(nvim('get_var', 'x2'),'a') + end) + + it('works with multiline command', function() + nvim('source', 'lua < Date: Sun, 6 Oct 2019 19:40:36 -0700 Subject: API: nvim_source: fix multiline input - DOCMD_REPEAT is needed to source all lines of input. - Fix ":verbose set {option}?" by handling SID_STR in get_scriptname(). closes #8722 --- test/functional/api/vim_spec.lua | 131 ++++++++++++++++++++++----------------- 1 file changed, 73 insertions(+), 58 deletions(-) (limited to 'test') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 14ed474eb1..a01ef2d6dd 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -16,6 +16,7 @@ local parse_context = helpers.parse_context local request = helpers.request local source = helpers.source local next_msg = helpers.next_msg +local write_file = helpers.write_file local pcall_err = helpers.pcall_err local format_string = helpers.format_string @@ -75,80 +76,94 @@ describe('API', function() end) describe('nvim_source', function() - it('works with a one-liner', function() + it('one-line input', function() nvim('source', "let x1 = 'a'") - eq(nvim('get_var', 'x1'), 'a') + eq('a', nvim('get_var', 'x1')) end) - it('works with stray newline character', function() - nvim('source', "let x2 = 'a'\n") - eq(nvim('get_var', 'x2'),'a') - end) - - it('works with multiline command', function() - nvim('source', 'lua < Date: Wed, 9 Oct 2019 18:34:37 +0530 Subject: API: nvim_source_output - Similar to nvim_source but will capture the output - Add meaningful VimL tracebacks for nvim_source - Handle got_int - Add error reporting --- test/functional/api/vim_spec.lua | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index a01ef2d6dd..9a7744142a 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -84,7 +84,7 @@ describe('API', function() it(':verbose set {option}?', function() nvim('source', 'set nowrap') eq('nowrap\n\tLast set from :source (no file)', - nvim('command_output', 'verbose set wrap?')) + nvim('source_output', 'verbose set wrap?')) end) it('multiline input', function() @@ -165,6 +165,36 @@ describe('API', function() eq('overwritten', request('nvim_get_var', 'x5')) os.remove(fname) end) + + it('traceback', function() + local fname = helpers.tmpname() + write_file(fname, 'echo "hello"\n') + local sourcing_fname = helpers.tmpname() + write_file(sourcing_fname, 'call nvim_source("source '..fname..'")\n') + meths.source('set verbose=2') + print() + local traceback_output = 'line 0: sourcing "'..sourcing_fname..'"\n'.. + 'line 0: sourcing "'..fname..'"\n'.. + 'hello\n'.. + 'finished sourcing '..fname..'\n'.. + 'continuing in nvim_source(..) called at '..sourcing_fname..':1\n'.. + 'finished sourcing '..sourcing_fname..'\n'.. + 'continuing in nvim_source(..) called at nvim_source_output(..):0' + eq(traceback_output, meths.source_output('call nvim_source("source '..sourcing_fname..'")')) + os.remove(fname) + os.remove(sourcing_fname) + end) + end) + + describe('nvim_source_output', function() + it('multiline input', function() + eq('this is spinal tap', + nvim('source_output', 'lua < Date: Sun, 1 Dec 2019 22:26:36 -0800 Subject: API: rename nvim_source => nvim_exec - Eliminate nvim_source_output(): add boolean `output` param to nvim_exec() instead. --- test/functional/api/vim_spec.lua | 79 +++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 41 deletions(-) (limited to 'test') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 9a7744142a..d7baf68a5b 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -16,6 +16,7 @@ local parse_context = helpers.parse_context local request = helpers.request local source = helpers.source local next_msg = helpers.next_msg +local tmpname = helpers.tmpname local write_file = helpers.write_file local pcall_err = helpers.pcall_err @@ -75,131 +76,127 @@ describe('API', function() eq({mode='i', blocking=false}, nvim("get_mode")) end) - describe('nvim_source', function() + describe('nvim_exec', function() it('one-line input', function() - nvim('source', "let x1 = 'a'") + nvim('exec', "let x1 = 'a'", false) eq('a', nvim('get_var', 'x1')) end) it(':verbose set {option}?', function() - nvim('source', 'set nowrap') + nvim('exec', 'set nowrap', false) eq('nowrap\n\tLast set from :source (no file)', - nvim('source_output', 'verbose set wrap?')) + nvim('exec', 'verbose set wrap?', true)) end) it('multiline input', function() -- Heredoc + empty lines. - nvim('source', "let x2 = 'a'\n") + nvim('exec', "let x2 = 'a'\n", false) eq('a', nvim('get_var', 'x2')) - nvim('source','lua < Date: Mon, 2 Dec 2019 19:09:30 +0900 Subject: dictwatcher: fix use-after-free #11495 fixes #11494 --- test/functional/ex_cmds/dict_notifications_spec.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'test') diff --git a/test/functional/ex_cmds/dict_notifications_spec.lua b/test/functional/ex_cmds/dict_notifications_spec.lua index 48e7e05e4c..5c67431221 100644 --- a/test/functional/ex_cmds/dict_notifications_spec.lua +++ b/test/functional/ex_cmds/dict_notifications_spec.lua @@ -357,4 +357,18 @@ describe('VimL dictionary notifications', function() eq(2, eval('1+1')) -- Still alive? end) + it('does not cause use-after-free when unletting from callback', function() + source([[ + let g:called = 0 + function W(...) abort + unlet g:d + let g:called = 1 + endfunction + let g:d = {} + call dictwatcheradd(g:d, '*', function('W')) + let g:d.foo = 123 + ]]) + eq(1, eval('g:called')) + end) + end) -- cgit From 0b7a7b23cce8c9eeeaac1a38190fd49e1033625c Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 2 Dec 2019 17:18:37 +0100 Subject: oldtest: support for running by filename (#11473) Follow-up to 8969efca8 (Vim patch 8.1.0723) NOTE: This changes the main entrypoint for running single oldtest files to not use/require the ".res" extension anymore. But it is handled for B/C. Adds a phony rule to run oldtest by filename. Not going through "$(MAKE)" avoids GNUmakefile being used then (which I use for WIP things), and it seems like SINGLE_MAKE should be used anyway probably. --- test/README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/test/README.md b/test/README.md index 2cee7da009..a6e9080a40 100644 --- a/test/README.md +++ b/test/README.md @@ -77,11 +77,14 @@ To run all legacy Vim tests: make oldtest -To run a *single* legacy test set `TEST_FILE`, for example: +To run a *single* legacy test file you can use either: - TEST_FILE=test_syntax.res make oldtest + make oldtest TEST_FILE=test_syntax.vim + +or: + + make src/nvim/testdir/test_syntax.vim -- The `.res` extension (instead of `.vim`) is required. - Specify only the test file name, not the full path. -- cgit From 22b52dd462e5dc9d5429305215bfb20aa20517c5 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 2 Dec 2019 22:21:15 +0100 Subject: log_init: call log_path_init (#11501) This has to be done after `init_homedir` for XDG default and `set_init_1` for lookup from env, which could be done earlier likely (to help with https://github.com/neovim/neovim/issues/10937), but this keeps it in sync with Vim. Fixes https://github.com/neovim/neovim/issues/11499. --- test/functional/options/defaults_spec.lua | 9 --------- 1 file changed, 9 deletions(-) (limited to 'test') diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua index 490a04186d..57e5077989 100644 --- a/test/functional/options/defaults_spec.lua +++ b/test/functional/options/defaults_spec.lua @@ -224,9 +224,6 @@ describe('startup defaults', function() XDG_DATA_HOME=xdgdir, NVIM_LOG_FILE='', -- Empty is invalid. }}) - -- server_start() calls ELOG, which tickles log_path_init(). - pcall(command, 'call serverstart(serverlist()[0])') - eq(xdgdir..'/'..datasubdir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/')) end) it('defaults to stdpath("data")/log if invalid', function() @@ -235,9 +232,6 @@ describe('startup defaults', function() XDG_DATA_HOME=xdgdir, NVIM_LOG_FILE='.', -- Any directory is invalid. }}) - -- server_start() calls ELOG, which tickles log_path_init(). - pcall(command, 'call serverstart(serverlist()[0])') - eq(xdgdir..'/'..datasubdir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/')) end) it('defaults to .nvimlog if stdpath("data") is invalid', function() @@ -245,9 +239,6 @@ describe('startup defaults', function() XDG_DATA_HOME='Xtest-missing-xdg-dir', NVIM_LOG_FILE='.', -- Any directory is invalid. }}) - -- server_start() calls ELOG, which tickles log_path_init(). - pcall(command, 'call serverstart(serverlist()[0])') - eq('.nvimlog', eval('$NVIM_LOG_FILE')) end) end) -- cgit From c34130d13a842ae0c0c1724d05800a954547d327 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 1 Dec 2019 22:43:16 -0800 Subject: API: deprecate nvim_command_output --- test/functional/api/keymap_spec.lua | 4 ++-- test/functional/api/vim_spec.lua | 4 ++-- test/functional/autocmd/tabclose_spec.lua | 18 +++++++++--------- test/functional/autocmd/tabnewentered_spec.lua | 8 ++++---- test/functional/ex_cmds/script_spec.lua | 4 ++-- test/functional/ex_cmds/sign_spec.lua | 4 ++-- test/functional/options/keymap_spec.lua | 2 +- test/functional/terminal/buffer_spec.lua | 2 +- test/functional/ui/cmdline_highlight_spec.lua | 8 ++++---- test/functional/ui/messages_spec.lua | 4 ++-- 10 files changed, 29 insertions(+), 29 deletions(-) (limited to 'test') diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua index 773207d360..210394c83f 100644 --- a/test/functional/api/keymap_spec.lua +++ b/test/functional/api/keymap_spec.lua @@ -585,13 +585,13 @@ describe('nvim_set_keymap, nvim_del_keymap', function() end) it('can set mappings whose RHS change dynamically', function() - meths.command_output([[ + meths.exec([[ function! FlipFlop() abort if !exists('g:flip') | let g:flip = 0 | endif let g:flip = !g:flip return g:flip endfunction - ]]) + ]], true) eq(1, meths.call_function('FlipFlop', {})) eq(0, meths.call_function('FlipFlop', {})) eq(1, meths.call_function('FlipFlop', {})) diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index d7baf68a5b..4f3279c80e 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -84,7 +84,7 @@ describe('API', function() it(':verbose set {option}?', function() nvim('exec', 'set nowrap', false) - eq('nowrap\n\tLast set from :source (no file)', + eq('nowrap\n\tLast set from anonymous :source', nvim('exec', 'verbose set wrap?', true)) end) @@ -1800,7 +1800,7 @@ describe('API', function() eq(' 1 %a "[No Name]" line 1\n'.. ' 3 h "[Scratch]" line 0\n'.. ' 4 h "[Scratch]" line 0', - meths.command_output("ls")) + meths.exec('ls', true)) -- current buffer didn't change eq({id=1}, meths.get_current_buf()) diff --git a/test/functional/autocmd/tabclose_spec.lua b/test/functional/autocmd/tabclose_spec.lua index b7c33dc3d8..92d860c628 100644 --- a/test/functional/autocmd/tabclose_spec.lua +++ b/test/functional/autocmd/tabclose_spec.lua @@ -11,10 +11,10 @@ describe('TabClosed', function() repeat nvim('command', 'tabnew') until nvim('eval', 'tabpagenr()') == 6 -- current tab is now 6 - eq("tabclosed:6:6:5", nvim('command_output', 'tabclose')) -- close last 6, current tab is now 5 - eq("tabclosed:5:5:4", nvim('command_output', 'close')) -- close last window on tab, closes tab - eq("tabclosed:2:2:3", nvim('command_output', '2tabclose')) -- close tab 2, current tab is now 3 - eq("tabclosed:1:1:2\ntabclosed:1:1:1", nvim('command_output', 'tabonly')) -- close tabs 1 and 2 + eq("tabclosed:6:6:5", nvim('exec', 'tabclose', true)) -- close last 6, current tab is now 5 + eq("tabclosed:5:5:4", nvim('exec', 'close', true)) -- close last window on tab, closes tab + eq("tabclosed:2:2:3", nvim('exec', '2tabclose', true)) -- close tab 2, current tab is now 3 + eq("tabclosed:1:1:2\ntabclosed:1:1:1", nvim('exec', 'tabonly', true)) -- close tabs 1 and 2 end) it('is triggered when closing a window via bdelete from another tab', function() @@ -23,7 +23,7 @@ describe('TabClosed', function() nvim('command', '1tabedit Xtestfile') nvim('command', 'normal! 1gt') eq({1, 3}, nvim('eval', '[tabpagenr(), tabpagenr("$")]')) - eq("tabclosed:2:2:1\ntabclosed:2:2:1", nvim('command_output', 'bdelete Xtestfile')) + eq("tabclosed:2:2:1\ntabclosed:2:2:1", nvim('exec', 'bdelete Xtestfile', true)) eq({1, 1}, nvim('eval', '[tabpagenr(), tabpagenr("$")]')) end) @@ -35,7 +35,7 @@ describe('TabClosed', function() -- Only one tab is closed, and the alternate file is used for the other. eq({2, 3}, nvim('eval', '[tabpagenr(), tabpagenr("$")]')) - eq("tabclosed:2:2:2", nvim('command_output', 'bdelete Xtestfile2')) + eq("tabclosed:2:2:2", nvim('exec', 'bdelete Xtestfile2', true)) eq('Xtestfile1', nvim('eval', 'bufname("")')) end) end) @@ -48,9 +48,9 @@ describe('TabClosed', function() nvim('command', 'tabnew') until nvim('eval', 'tabpagenr()') == 7 -- current tab is now 7 -- sanity check, we shouldn't match on tabs with numbers other than 2 - eq("tabclosed:7:7:6", nvim('command_output', 'tabclose')) + eq("tabclosed:7:7:6", nvim('exec', 'tabclose', true)) -- close tab page 2, current tab is now 5 - eq("tabclosed:2:2:5\ntabclosed:match", nvim('command_output', '2tabclose')) + eq("tabclosed:2:2:5\ntabclosed:match", nvim('exec', '2tabclose', true)) end) end) @@ -59,7 +59,7 @@ describe('TabClosed', function() nvim('command', 'au! TabClosed * echom "tabclosed:".expand("").":".expand("").":".tabpagenr()') nvim('command', 'tabedit Xtestfile') eq({2, 2}, nvim('eval', '[tabpagenr(), tabpagenr("$")]')) - eq("tabclosed:2:2:1", nvim('command_output', 'close')) + eq("tabclosed:2:2:1", nvim('exec', 'close', true)) eq({1, 1}, nvim('eval', '[tabpagenr(), tabpagenr("$")]')) end) end) diff --git a/test/functional/autocmd/tabnewentered_spec.lua b/test/functional/autocmd/tabnewentered_spec.lua index 59cac07b34..32e341184d 100644 --- a/test/functional/autocmd/tabnewentered_spec.lua +++ b/test/functional/autocmd/tabnewentered_spec.lua @@ -7,15 +7,15 @@ describe('TabNewEntered', function() it('matches when entering any new tab', function() clear() nvim('command', 'au! TabNewEntered * echom "tabnewentered:".tabpagenr().":".bufnr("")') - eq("tabnewentered:2:2", nvim('command_output', 'tabnew')) - eq("tabnewentered:3:3", nvim('command_output', 'tabnew test.x2')) + eq("tabnewentered:2:2", nvim('exec', 'tabnew', true)) + eq("tabnewentered:3:3", nvim('exec', 'tabnew test.x2', true)) end) end) describe('with FILE as ', function() it('matches when opening a new tab for FILE', function() nvim('command', 'au! TabNewEntered Xtest-tabnewentered echom "tabnewentered:match"') eq('tabnewentered:4:4\ntabnewentered:match', - nvim('command_output', 'tabnew Xtest-tabnewentered')) + nvim('exec', 'tabnew Xtest-tabnewentered', true)) end) end) describe('with CTRL-W T', function() @@ -24,7 +24,7 @@ describe('TabNewEntered', function() nvim('command', 'au! TabNewEntered * echom "entered"') nvim('command', 'tabnew test.x2') nvim('command', 'split') - eq('entered', nvim('command_output', 'execute "normal \\T"')) + eq('entered', nvim('exec', 'execute "normal \\T"', true)) end) end) end) diff --git a/test/functional/ex_cmds/script_spec.lua b/test/functional/ex_cmds/script_spec.lua index 4e57d2755d..0a772c559b 100644 --- a/test/functional/ex_cmds/script_spec.lua +++ b/test/functional/ex_cmds/script_spec.lua @@ -22,7 +22,7 @@ describe('script_get-based command', function() %s %s endif ]])):format(cmd, garbage))) - eq('', meths.command_output('messages')) + eq('', meths.exec('messages', true)) if check_neq then neq(0, exc_exec(dedent([[ %s %s @@ -37,7 +37,7 @@ describe('script_get-based command', function() EOF endif ]])):format(cmd, garbage))) - eq('', meths.command_output('messages')) + eq('', meths.exec('messages', true)) if check_neq then eq(true, pcall(source, (dedent([[ let g:exc = 0 diff --git a/test/functional/ex_cmds/sign_spec.lua b/test/functional/ex_cmds/sign_spec.lua index 9d08a66625..891cfe1670 100644 --- a/test/functional/ex_cmds/sign_spec.lua +++ b/test/functional/ex_cmds/sign_spec.lua @@ -16,8 +16,8 @@ describe('sign', function() nvim('command', 'sign place 34 line=3 name=Foo buffer='..buf2) -- now unplace without specifying a buffer nvim('command', 'sign unplace 34') - eq("--- Signs ---\n", nvim('command_output', 'sign place buffer='..buf1)) - eq("--- Signs ---\n", nvim('command_output', 'sign place buffer='..buf2)) + eq("--- Signs ---\n", nvim('exec', 'sign place buffer='..buf1, true)) + eq("--- Signs ---\n", nvim('exec', 'sign place buffer='..buf2, true)) end) end) end) diff --git a/test/functional/options/keymap_spec.lua b/test/functional/options/keymap_spec.lua index 7f6d623dc7..52a714f7a8 100644 --- a/test/functional/options/keymap_spec.lua +++ b/test/functional/options/keymap_spec.lua @@ -30,7 +30,7 @@ describe("'keymap' / :lmap", function() command('lmapclear ') command('set keymap=dvorak') command('set nomore') - local bindings = funcs.nvim_command_output('lmap') + local bindings = funcs.nvim_exec('lmap', true) eq(dedent([[ l " @_ diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index 2fc7a021cb..d40baca871 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -60,7 +60,7 @@ describe(':terminal buffer', function() end) it('does not create swap files', function() - local swapfile = nvim('command_output', 'swapname'):gsub('\n', '') + local swapfile = nvim('exec', 'swapname', true):gsub('\n', '') eq(nil, io.open(swapfile)) end) diff --git a/test/functional/ui/cmdline_highlight_spec.lua b/test/functional/ui/cmdline_highlight_spec.lua index 052414a43d..9c746b99bd 100644 --- a/test/functional/ui/cmdline_highlight_spec.lua +++ b/test/functional/ui/cmdline_highlight_spec.lua @@ -362,7 +362,7 @@ describe('Command-line coloring', function() {EOB:~ }| :e^ | ]]) - eq('', meths.command_output('messages')) + eq('', meths.exec('messages', true)) end) it('silences :echon', function() set_color_cb('Echoning') @@ -377,7 +377,7 @@ describe('Command-line coloring', function() {EOB:~ }| :e^ | ]]) - eq('', meths.command_output('messages')) + eq('', meths.exec('messages', true)) end) it('silences :echomsg', function() set_color_cb('Echomsging') @@ -392,7 +392,7 @@ describe('Command-line coloring', function() {EOB:~ }| :e^ | ]]) - eq('', meths.command_output('messages')) + eq('', meths.exec('messages', true)) end) it('does the right thing when throwing', function() set_color_cb('Throwing') @@ -857,7 +857,7 @@ describe('Ex commands coloring', function() ]]) feed('') eq('Error detected while processing :\nE605: Exception not caught: 42\nE749: empty buffer', - meths.command_output('messages')) + meths.exec('messages', true)) end) it('errors out when failing to get callback', function() meths.set_var('Nvim_color_cmdline', 42) diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index 40ea030f73..25b38b1feb 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -861,7 +861,7 @@ describe('ui/builtin messages', function() -- screen size doesn't affect internal output #10285 eq('ErrorMsg xxx ctermfg=15 ctermbg=1 guifg=White guibg=Red', - meths.command_output("hi ErrorMsg")) + meths.exec("hi ErrorMsg", true)) end) it(':syntax list langGroup output', function() @@ -900,7 +900,7 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim match /\ Date: Mon, 2 Dec 2019 00:46:46 -0800 Subject: API: rename nvim_execute_lua => nvim_exec_lua - We already find ourselves renaming nvim_execute_lua in tests and scripts, which suggests "exec" is the verb we actually want. - Add "exec" verb to `:help dev-api`. --- test/functional/api/vim_spec.lua | 33 ++++++++++++++++++--------------- test/functional/helpers.lua | 2 +- test/functional/lua/overrides_spec.lua | 7 ++----- test/functional/terminal/tui_spec.lua | 6 +++--- 4 files changed, 24 insertions(+), 24 deletions(-) (limited to 'test') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 4f3279c80e..d901a5e2eb 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -433,41 +433,44 @@ describe('API', function() end) end) - describe('nvim_execute_lua', function() + describe('nvim_exec_lua', function() it('works', function() - meths.execute_lua('vim.api.nvim_set_var("test", 3)', {}) + meths.exec_lua('vim.api.nvim_set_var("test", 3)', {}) eq(3, meths.get_var('test')) - eq(17, meths.execute_lua('a, b = ...\nreturn a + b', {10,7})) + eq(17, meths.exec_lua('a, b = ...\nreturn a + b', {10,7})) - eq(NIL, meths.execute_lua('function xx(a,b)\nreturn a..b\nend',{})) + eq(NIL, meths.exec_lua('function xx(a,b)\nreturn a..b\nend',{})) + eq("xy", meths.exec_lua('return xx(...)', {'x','y'})) + + -- Deprecated name: nvim_execute_lua. eq("xy", meths.execute_lua('return xx(...)', {'x','y'})) end) it('reports errors', function() eq([[Error loading lua: [string ""]:1: '=' expected near '+']], - pcall_err(meths.execute_lua, 'a+*b', {})) + pcall_err(meths.exec_lua, 'a+*b', {})) eq([[Error loading lua: [string ""]:1: unexpected symbol near '1']], - pcall_err(meths.execute_lua, '1+2', {})) + pcall_err(meths.exec_lua, '1+2', {})) eq([[Error loading lua: [string ""]:1: unexpected symbol]], - pcall_err(meths.execute_lua, 'aa=bb\0', {})) + pcall_err(meths.exec_lua, 'aa=bb\0', {})) eq([[Error executing lua: [string ""]:1: attempt to call global 'bork' (a nil value)]], - pcall_err(meths.execute_lua, 'bork()', {})) + pcall_err(meths.exec_lua, 'bork()', {})) eq('Error executing lua: [string ""]:1: did\nthe\nfail', - pcall_err(meths.execute_lua, 'error("did\\nthe\\nfail")', {})) + pcall_err(meths.exec_lua, 'error("did\\nthe\\nfail")', {})) end) it('uses native float values', function() - eq(2.5, meths.execute_lua("return select(1, ...)", {2.5})) - eq("2.5", meths.execute_lua("return vim.inspect(...)", {2.5})) + eq(2.5, meths.exec_lua("return select(1, ...)", {2.5})) + eq("2.5", meths.exec_lua("return vim.inspect(...)", {2.5})) -- "special" float values are still accepted as return values. - eq(2.5, meths.execute_lua("return vim.api.nvim_eval('2.5')", {})) - eq("{\n [false] = 2.5,\n [true] = 3\n}", meths.execute_lua("return vim.inspect(vim.api.nvim_eval('2.5'))", {})) + eq(2.5, meths.exec_lua("return vim.api.nvim_eval('2.5')", {})) + eq("{\n [false] = 2.5,\n [true] = 3\n}", meths.exec_lua("return vim.inspect(vim.api.nvim_eval('2.5'))", {})) end) end) @@ -573,7 +576,7 @@ describe('API', function() eq({0,3,14,0}, funcs.getpos('.')) end) it('vim.paste() failure', function() - nvim('execute_lua', 'vim.paste = (function(lines, phase) error("fake fail") end)', {}) + nvim('exec_lua', 'vim.paste = (function(lines, phase) error("fake fail") end)', {}) eq([[Error executing lua: [string ""]:1: fake fail]], pcall_err(request, 'nvim_paste', 'line 1\nline 2\nline 3', false, 1)) end) @@ -797,7 +800,7 @@ describe('API', function() ok(nil ~= string.find(rv, 'noequalalways\n'.. '\tLast set from API client %(channel id %d+%)')) - nvim('execute_lua', 'vim.api.nvim_set_option("equalalways", true)', {}) + nvim('exec_lua', 'vim.api.nvim_set_option("equalalways", true)', {}) status, rv = pcall(nvim, 'command_output', 'verbose set equalalways?') eq(true, status) diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 1108fbb2ba..0f2b04ea00 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -706,7 +706,7 @@ module.curwinmeths = module.create_callindex(module.curwin) module.curtabmeths = module.create_callindex(module.curtab) function module.exec_lua(code, ...) - return module.meths.execute_lua(code, {...}) + return module.meths.exec_lua(code, {...}) end function module.redir_exec(cmd) diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua index 8c260632d9..1bccc02847 100644 --- a/test/functional/lua/overrides_spec.lua +++ b/test/functional/lua/overrides_spec.lua @@ -299,14 +299,11 @@ describe('package.path/package.cpath', function() end return new_paths end - local function execute_lua(cmd, ...) - return meths.execute_lua(cmd, {...}) - end local function eval_lua(expr, ...) - return meths.execute_lua('return ' .. expr, {...}) + return meths.exec_lua('return '..expr, {...}) end local function set_path(which, value) - return execute_lua('package[select(1, ...)] = select(2, ...)', which, value) + return exec_lua('package[select(1, ...)] = select(2, ...)', which, value) end it('contains directories from &runtimepath on first invocation', function() diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 676d6ef76d..077e9dc7d5 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -486,7 +486,7 @@ describe('TUI', function() end) it('paste: recovers from vim.paste() failure', function() - child_session:request('nvim_execute_lua', [[ + child_session:request('nvim_exec_lua', [[ _G.save_paste_fn = vim.paste vim.paste = function(lines, phase) error("fake fail") end ]], {}) @@ -544,7 +544,7 @@ describe('TUI', function() {3:-- TERMINAL --} | ]]} -- Paste works if vim.paste() succeeds. - child_session:request('nvim_execute_lua', [[ + child_session:request('nvim_exec_lua', [[ vim.paste = _G.save_paste_fn ]], {}) feed_data('\027[200~line A\nline B\n\027[201~') @@ -563,7 +563,7 @@ describe('TUI', function() it('paste: vim.paste() cancel (retval=false) #10865', function() -- This test only exercises the "cancel" case. Use-case would be "dangling -- paste", but that is not implemented yet. #10865 - child_session:request('nvim_execute_lua', [[ + child_session:request('nvim_exec_lua', [[ vim.paste = function(lines, phase) return false end ]], {}) feed_data('\027[200~line A\nline B\n\027[201~') -- cgit From 3beef8ee1ca9699d75b8877ec9b77493b58b0ed4 Mon Sep 17 00:00:00 2001 From: Matthieu Coudron Date: Tue, 1 Oct 2019 23:14:00 +0900 Subject: defaults: set nostartofline Having the cursor change column can be surprising. Force startofline in functional and old tests. Remove the functional breakindent test, as it's a subset of the oldtest one. --- test/functional/helpers.lua | 2 +- test/functional/legacy/breakindent_spec.lua | 214 ---------------------------- 2 files changed, 1 insertion(+), 215 deletions(-) delete mode 100644 test/functional/legacy/breakindent_spec.lua (limited to 'test') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 1108fbb2ba..9fcd1cf7b1 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -35,7 +35,7 @@ module.nvim_prog = ( ) -- Default settings for the test session. module.nvim_set = ( - 'set shortmess+=IS background=light noswapfile noautoindent' + 'set shortmess+=IS background=light noswapfile noautoindent startofline' ..' laststatus=1 undodir=. directory=. viewdir=. backupdir=.' ..' belloff= wildoptions-=pum noshowcmd noruler nomore redrawdebug=invalid') module.nvim_argv = { diff --git a/test/functional/legacy/breakindent_spec.lua b/test/functional/legacy/breakindent_spec.lua deleted file mode 100644 index fd25e809e0..0000000000 --- a/test/functional/legacy/breakindent_spec.lua +++ /dev/null @@ -1,214 +0,0 @@ --- Test for breakindent - -local helpers = require('test.functional.helpers')(after_each) -local feed, insert = helpers.feed, helpers.insert -local clear, feed_command, expect = helpers.clear, helpers.feed_command, helpers.expect - -describe('breakindent', function() - setup(clear) - - -- luacheck: ignore 621 (Indentation) - -- luacheck: ignore 613 (Trailing whitespace in a string) - -- luacheck: ignore 611 (Line contains only whitespaces) - it('is working', function() - insert('dummy text') - - feed_command('set wildchar=^E') - feed_command('10new') - feed_command('vsp') - feed_command('vert resize 20') - feed_command([[put =\"\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP\"]]) - feed_command('set ts=4 sw=4 sts=4 breakindent') - feed_command('fu! ScreenChar(line, width)') - feed_command(' let c=""') - feed_command(' for i in range(1,a:width)') - feed_command(' let c.=nr2char(screenchar(a:line, i))') - feed_command(' endfor') - feed_command([[ let c.="\n"]]) - feed_command(' for i in range(1,a:width)') - feed_command(' let c.=nr2char(screenchar(a:line+1, i))') - feed_command(' endfor') - feed_command([[ let c.="\n"]]) - feed_command(' for i in range(1,a:width)') - feed_command(' let c.=nr2char(screenchar(a:line+2, i))') - feed_command(' endfor') - feed_command(' return c') - feed_command('endfu') - feed_command('fu DoRecordScreen()') - feed_command(' wincmd l') - feed_command([[ $put =printf(\"\n%s\", g:test)]]) - feed_command(' $put =g:line1') - feed_command(' wincmd p') - feed_command('endfu') - feed_command('set briopt=min:0') - feed_command('let g:test="Test 1: Simple breakindent"') - feed_command('let line1=ScreenChar(line("."),8)') - feed_command('call DoRecordScreen()') - feed_command('let g:test="Test 2: Simple breakindent + sbr=>>"') - feed_command('set sbr=>>') - feed_command('let line1=ScreenChar(line("."),8)') - feed_command('call DoRecordScreen()') - feed_command('let g:test ="Test 3: Simple breakindent + briopt:sbr"') - feed_command('set briopt=sbr,min:0 sbr=++') - feed_command('let line1=ScreenChar(line("."),8)') - feed_command('call DoRecordScreen()') - feed_command('let g:test ="Test 4: Simple breakindent + min width: 18"') - feed_command('set sbr= briopt=min:18') - feed_command('let line1=ScreenChar(line("."),8)') - feed_command('call DoRecordScreen()') - feed_command('let g:test =" Test 5: Simple breakindent + shift by 2"') - feed_command('set briopt=shift:2,min:0') - feed_command('let line1=ScreenChar(line("."),8)') - feed_command('call DoRecordScreen()') - feed_command('let g:test=" Test 6: Simple breakindent + shift by -1"') - feed_command('set briopt=shift:-1,min:0') - feed_command('let line1=ScreenChar(line("."),8)') - feed_command('call DoRecordScreen()') - feed_command('let g:test=" Test 7: breakindent + shift by +1 + nu + sbr=? briopt:sbr"') - feed_command('set briopt=shift:1,sbr,min:0 nu sbr=? nuw=4') - feed_command('let line1=ScreenChar(line("."),10)') - feed_command('call DoRecordScreen()') - feed_command('let g:test=" Test 8: breakindent + shift:1 + nu + sbr=# list briopt:sbr"') - feed_command('set briopt=shift:1,sbr,min:0 nu sbr=# list lcs&vi') - feed_command('let line1=ScreenChar(line("."),10)') - feed_command('call DoRecordScreen()') - feed_command([[let g:test=" Test 9: breakindent + shift by +1 + 'nu' + sbr=# list"]]) - feed_command('set briopt-=sbr') - feed_command('let line1=ScreenChar(line("."),10)') - feed_command('call DoRecordScreen()') - feed_command([[let g:test=" Test 10: breakindent + shift by +1 + 'nu' + sbr=~ cpo+=n"]]) - feed_command('set cpo+=n sbr=~ nu nuw=4 nolist briopt=sbr,min:0') - feed_command('let line1=ScreenChar(line("."),10)') - feed_command('call DoRecordScreen()') - feed_command('wincmd p') - feed_command([[let g:test="\n Test 11: strdisplaywidth when breakindent is on"]]) - feed_command('set cpo-=n sbr=>> nu nuw=4 nolist briopt= ts=4') - -- Skip leading tab when calculating text width. - feed_command('let text=getline(2)') - -- Text wraps 3 times. - feed_command('let width = strlen(text[1:])+indent(2)*4+strlen(&sbr)*3') - feed_command('$put =g:test') - feed_command([[$put =printf(\"strdisplaywidth: %d == calculated: %d\", strdisplaywidth(text), width)]]) - feed_command([[let g:str="\t\t\t\t\t{"]]) - feed_command('let g:test=" Test 12: breakindent + long indent"') - feed_command('wincmd p') - feed_command('set all& breakindent linebreak briopt=min:10 nu numberwidth=3 ts=4') - feed_command('$put =g:str') - feed('zt') - feed_command('let line1=ScreenChar(1,10)') - feed_command('wincmd p') - feed_command('call DoRecordScreen()') - - -- Test, that the string " a\tb\tc\td\te" is correctly displayed in a - -- 20 column wide window (see bug report - -- https://groups.google.com/d/msg/vim_dev/ZOdg2mc9c9Y/TT8EhFjEy0IJ ). - feed_command('only') - feed_command('vert 20new') - feed_command('set all& breakindent briopt=min:10') - feed_command([[call setline(1, [" a\tb\tc\td\te", " z y x w v"])]]) - feed_command([[/^\s*a]]) - feed('fbgjyl') - feed_command('let line1 = @0') - feed_command([[?^\s*z]]) - feed('fygjyl') - feed_command('let line2 = @0') - feed_command('quit!') - feed_command([[$put ='Test 13: breakindent with wrapping Tab']]) - feed_command('$put =line1') - feed_command('$put =line2') - - feed_command('let g:test="Test 14: breakindent + visual blockwise delete #1"') - feed_command('set all& breakindent shada+=nX-test-breakindent.shada') - feed_command('30vnew') - feed_command('normal! 3a1234567890') - feed_command('normal! a abcde') - feed_command([[exec "normal! 0\tex"]]) - feed_command('let line1=ScreenChar(line("."),8)') - feed_command('call DoRecordScreen()') - - feed_command('let g:test="Test 15: breakindent + visual blockwise delete #2"') - feed_command('%d') - feed_command('normal! 4a1234567890') - feed_command([[exec "normal! >>\3f0x"]]) - feed_command('let line1=ScreenChar(line("."),20)') - feed_command('call DoRecordScreen()') - feed_command('quit!') - - -- Assert buffer contents. - expect([[ - - abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP - - Test 1: Simple breakindent - abcd - qrst - GHIJ - - Test 2: Simple breakindent + sbr=>> - abcd - >>qr - >>EF - - Test 3: Simple breakindent + briopt:sbr - abcd - ++ qrst - ++ GHIJ - - Test 4: Simple breakindent + min width: 18 - abcd - qrstuv - IJKLMN - - Test 5: Simple breakindent + shift by 2 - abcd - qr - EF - - Test 6: Simple breakindent + shift by -1 - abcd - qrstu - HIJKL - - Test 7: breakindent + shift by +1 + nu + sbr=? briopt:sbr - 2 ab - ? m - ? x - - Test 8: breakindent + shift:1 + nu + sbr=# list briopt:sbr - 2 ^Iabcd - # opq - # BCD - - Test 9: breakindent + shift by +1 + 'nu' + sbr=# list - 2 ^Iabcd - #op - #AB - - Test 10: breakindent + shift by +1 + 'nu' + sbr=~ cpo+=n - 2 ab - ~ mn - ~ yz - - Test 11: strdisplaywidth when breakindent is on - strdisplaywidth: 46 == calculated: 64 - { - - Test 12: breakindent + long indent - 56 - - ~ - Test 13: breakindent with wrapping Tab - d - w - - Test 14: breakindent + visual blockwise delete #1 - e - ~ - ~ - - Test 15: breakindent + visual blockwise delete #2 - 1234567890 - ~ - ~ ]]) - end) -end) -- cgit From 4598e489c797dd3e287b51711ac1924cf6bded1f Mon Sep 17 00:00:00 2001 From: Matthieu Coudron Date: Fri, 9 Nov 2018 23:52:57 +0900 Subject: test: always pass a string to expect_msg_seq Seems like pcall doesn't always return a string as a 2nd element of the tuple. --- test/functional/helpers.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 0f2b04ea00..77d4b573fc 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -186,7 +186,12 @@ function module.expect_msg_seq(...) if status then return result end - final_error = cat_err(final_error, result) + local message = result + if type(result) == "table" then + -- 'eq' returns several things + message = result.message + end + final_error = cat_err(final_error, message) end error(final_error) end -- cgit From 0e6c6261e1b5a518995f53ca3898a68b9bb02012 Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Sat, 7 Dec 2019 03:34:02 -0800 Subject: Fix access on vim.wo (#11517) * Add more tests for vim.wo --- test/functional/lua/vim_spec.lua | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 22c975147f..17ffcd8d86 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -629,22 +629,27 @@ describe('lua stdlib', function() end) it('vim.wo', function() - eq('', funcs.luaeval "vim.bo.filetype") exec_lua [[ vim.api.nvim_win_set_option(0, "cole", 2) - BUF = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_option(BUF, "modifiable", false) + vim.cmd "split" + vim.api.nvim_win_set_option(0, "cole", 2) ]] eq(2, funcs.luaeval "vim.wo.cole") exec_lua [[ vim.wo.conceallevel = 0 - vim.bo[BUF].modifiable = true ]] eq(0, funcs.luaeval "vim.wo.cole") + eq(0, funcs.luaeval "vim.wo[0].cole") + eq(0, funcs.luaeval "vim.wo[1001].cole") matches("^Error executing lua: .*: Invalid option name: 'notanopt'$", pcall_err(exec_lua, 'return vim.wo.notanopt')) matches("^Error executing lua: .*: Expected lua string$", pcall_err(exec_lua, 'return vim.wo[0][0].list')) + eq(2, funcs.luaeval "vim.wo[1000].cole") + exec_lua [[ + vim.wo[1000].cole = 0 + ]] + eq(0, funcs.luaeval "vim.wo[1000].cole") end) it('vim.cmd', function() -- cgit From 39094b3faedde9601160806901941e4808925410 Mon Sep 17 00:00:00 2001 From: butwerenotthereyet <58348703+butwerenotthereyet@users.noreply.github.com> Date: Tue, 10 Dec 2019 00:56:56 -0800 Subject: jumplist: browser-style (or 'tagstack') navigation #11530 Traditionally, when navigating to a specific location from the middle of the jumplist results in shifting the current location to the bottom of the list and adding the new location after it. This behavior is not desireable to all users--see, for example https://vi.stackexchange.com/questions/18344/how-to-change-jumplist-behavior. Here, another jumplist behavior is introduced. When jumpoptions (a new option set added here) includes stack, the jumplist behaves like the tagstack or like history in a web browser. That is, when navigating to a location from the middle of the jumplist 2 first 1 second 0 third <-- current location 1 fourth 2 fifth to a new location the locations after the current location in the jump list are discarded 2 first 1 second 0 third <-- current location The result is that when moving forward from that location, the new location will be appended to the jumplist: 3 first 2 second 1 third 0 new If the new location is the same new == second as some previous (but not immediately prior) entry in the jumplist, 2 first 1 second 0 third <-- current location 1 fourth 2 fifth both occurrences preserved 3 first 2 second 1 third 0 second (new) when moving forward from that location. It would be desireable to go farther and, when the new location is the same as the location that is currently next in the jumplist, new == fourth make the result of navigating to the new location by jumping (e.g. 50gg) be the same as moving forward in the jumplist 2 first 1 second 0 third 1 new <-- current location 2 fifth and simply increment the jumplist index. That change is NOT part of this patch because it would require passing the new cursor location to the function (setpcmark) from all of its callees. That in turn would require those callees to know *before* calling what the new cursor location is, which do they do not currently. --- test/functional/normal/jump_spec.lua | 91 ++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) (limited to 'test') diff --git a/test/functional/normal/jump_spec.lua b/test/functional/normal/jump_spec.lua index 5bed541752..d53b5f7415 100644 --- a/test/functional/normal/jump_spec.lua +++ b/test/functional/normal/jump_spec.lua @@ -5,6 +5,7 @@ local command = helpers.command local eq = helpers.eq local funcs = helpers.funcs local feed = helpers.feed +local redir_exec = helpers.redir_exec local write_file = helpers.write_file describe('jumplist', function() @@ -46,3 +47,93 @@ describe('jumplist', function() eq(buf1, funcs.bufnr('%')) end) end) + +describe('jumpoptions=stack behaves like browser history', function() + before_each(function() + clear() + feed(':clearjumps') + + -- Add lines so that we have locations to jump to. + for i = 1,101,1 + do + feed('iLine ' .. i .. '') + end + + -- Jump around to add some locations to the jump list. + feed('0gg') + feed('10gg') + feed('20gg') + feed('30gg') + feed('40gg') + feed('50gg') + + feed(':set jumpoptions=stack') + end) + + after_each(function() + feed('set jumpoptions=') + end) + + it('discards the tail when navigating from the middle', function() + feed('') + feed('') + + eq( '\n' + .. ' jump line col file/text\n' + .. ' 4 102 0 \n' + .. ' 3 1 0 Line 1\n' + .. ' 2 10 0 Line 10\n' + .. ' 1 20 0 Line 20\n' + .. '> 0 30 0 Line 30\n' + .. ' 1 40 0 Line 40\n' + .. ' 2 50 0 Line 50', + redir_exec('jumps')) + + feed('90gg') + + eq( '\n' + .. ' jump line col file/text\n' + .. ' 5 102 0 \n' + .. ' 4 1 0 Line 1\n' + .. ' 3 10 0 Line 10\n' + .. ' 2 20 0 Line 20\n' + .. ' 1 30 0 Line 30\n' + .. '>', + redir_exec('jumps')) + end) + + it('does not add the same location twice adjacently', function() + feed('60gg') + feed('60gg') + + eq( '\n' + .. ' jump line col file/text\n' + .. ' 7 102 0 \n' + .. ' 6 1 0 Line 1\n' + .. ' 5 10 0 Line 10\n' + .. ' 4 20 0 Line 20\n' + .. ' 3 30 0 Line 30\n' + .. ' 2 40 0 Line 40\n' + .. ' 1 50 0 Line 50\n' + .. '>', + redir_exec('jumps')) + end) + + it('does add the same location twice nonadjacently', function() + feed('10gg') + feed('20gg') + + eq( '\n' + .. ' jump line col file/text\n' + .. ' 8 102 0 \n' + .. ' 7 1 0 Line 1\n' + .. ' 6 10 0 Line 10\n' + .. ' 5 20 0 Line 20\n' + .. ' 4 30 0 Line 30\n' + .. ' 3 40 0 Line 40\n' + .. ' 2 50 0 Line 50\n' + .. ' 1 10 0 Line 10\n' + .. '>', + redir_exec('jumps')) + end) +end) -- cgit From f3fcaedfad59684e6f57ff0bb131b75a3c7fdcaa Mon Sep 17 00:00:00 2001 From: Matthieu Coudron Date: Fri, 9 Nov 2018 23:55:47 +0900 Subject: test: new test for setting environment --- test/functional/core/job_spec.lua | 40 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'test') diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index d285008a33..af2299945e 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -26,6 +26,7 @@ describe('jobs', function() before_each(function() clear() + channel = nvim('get_api_info')[1] nvim('set_var', 'channel', channel) source([[ @@ -48,6 +49,45 @@ describe('jobs', function() ]]) end) + it('append environment #env', function() + nvim('command', "let $VAR = 'abc'") + nvim('command', "let g:job_opts.env = {'TOTO': 'hello world'}") + if iswin() then + nvim('command', [[call jobstart('echo %TOTO% %VAR%', g:job_opts)]]) + else + nvim('command', [[call jobstart('echo $TOTO $VAR', g:job_opts)]]) + end + + expect_msg_seq({ + {'notification', 'stdout', {0, {'hello world abc', ''}}}, + }) + end) + + it('replace environment #env', function() + nvim('command', "let $VAR = 'abc'") + nvim('command', "let g:job_opts.env = {'TOTO': 'hello world'}") + nvim('command', "let g:job_opts.clear_env = 1") + + -- libuv ensures that certain "required" environment variables are + -- preserved if the user doesn't provide them in a custom environment + -- https://github.com/libuv/libuv/blob/635e0ce6073c5fbc96040e336b364c061441b54b/src/win/process.c#L672 + -- https://github.com/libuv/libuv/blob/635e0ce6073c5fbc96040e336b364c061441b54b/src/win/process.c#L48-L60 + -- + -- Rather than expecting a completely empty environment, ensure that $VAR + -- is *not* in the environment but $TOTO is. + if iswin() then + nvim('command', [[call jobstart('echo %TOTO% %VAR%', g:job_opts)]]) + expect_msg_seq({ + {'notification', 'stdout', {0, {'hello world %VAR%', ''}}} + }) + else + nvim('command', [[call jobstart('echo $TOTO $VAR', g:job_opts)]]) + expect_msg_seq({ + {'notification', 'stdout', {0, {'hello world', ''}}} + }) + end + end) + it('uses &shell and &shellcmdflag if passed a string', function() nvim('command', "let $VAR = 'abc'") if iswin() then -- cgit From 91b313a904c039a9b6a53a7afc9f66e67a1e12fc Mon Sep 17 00:00:00 2001 From: James McCoy Date: Thu, 12 Dec 2019 07:26:39 -0500 Subject: Add negative test for type of job's env option --- test/functional/core/job_spec.lua | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'test') diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index af2299945e..e5d4444b92 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -49,6 +49,18 @@ describe('jobs', function() ]]) end) + it('must specify env option as a dict', function() + command("let g:job_opts.env = v:true") + local _, err = pcall(function() + if iswin() then + nvim('command', "let j = jobstart('set', g:job_opts)") + else + nvim('command', "let j = jobstart('env', g:job_opts)") + end + end) + ok(string.find(err, "E475: Invalid argument: env") ~= nil) + end) + it('append environment #env', function() nvim('command', "let $VAR = 'abc'") nvim('command', "let g:job_opts.env = {'TOTO': 'hello world'}") -- cgit From ad5049aa60c918dba0f1094118a09f265091f6c1 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 15 Dec 2019 10:57:43 -0500 Subject: vim-patch:8.2.0010: test64 is old style Problem: Test64 is old style. Solution: Convert to new style test. (Yegappan Lakshmanan, closes vim/vim#5363) https://github.com/vim/vim/commit/f9cb05c14753d984f002c0c090688f8510147e6b --- test/functional/legacy/095_regexp_multibyte_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/legacy/095_regexp_multibyte_spec.lua b/test/functional/legacy/095_regexp_multibyte_spec.lua index 845ebaaad7..fad0dc8023 100644 --- a/test/functional/legacy/095_regexp_multibyte_spec.lua +++ b/test/functional/legacy/095_regexp_multibyte_spec.lua @@ -1,5 +1,5 @@ -- Test for regexp patterns with multi-byte support, using utf-8. --- See test64 for the non-multi-byte tests. +-- See test_regexp_latin.vim for the non-multi-byte tests. -- A pattern that gives the expected result produces OK, so that we know it was -- actually tried. -- cgit From 65aca4d857ab9ff278f410b17ef31d91e48a37b7 Mon Sep 17 00:00:00 2001 From: Matthieu Coudron Date: Thu, 19 Dec 2019 21:27:21 +0100 Subject: TUI: can make the cursor transparent #11519 when setting 'guicursor' highlight blend=100. --- test/functional/ui/cursor_spec.lua | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'test') diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua index 8ad4182f41..6c913124ac 100644 --- a/test/functional/ui/cursor_spec.lua +++ b/test/functional/ui/cursor_spec.lua @@ -245,6 +245,25 @@ describe('ui/cursor', function() eq('normal', screen.mode) end) + -- update the highlight again to hide cursor + helpers.command('hi Cursor blend=100') + + for _, m in ipairs(expected_mode_info) do + if m.hl_id then + m.attr = {background = Screen.colors.Red, blend = 100} + end + end + screen:expect{grid=[[ + ^ | + ~ | + ~ | + ~ | + test | + ]], condition=function() + eq(expected_mode_info, screen._mode_info) + end + } + -- Another cursor style. meths.set_option('guicursor', 'n-v-c:ver35-blinkwait171-blinkoff172-blinkon173' ..',ve:hor35,o:ver50,i-ci:block,r-cr:hor90,sm:ver42') -- cgit From e1d63c180cc38cec5a8bf3e543bfe18472352da4 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 22 Dec 2019 11:23:39 +0100 Subject: tests: ex_terminal_spec: retry ":terminal (with fake shell)" (#11588) Flaky failure (Travis CI, macOS): [ RUN ] :terminal (with fake shell) works with gf: 10518.41 ms FAIL test/functional/terminal/ex_terminal_spec.lua:248: Row 1 did not match. Expected: |*^ready $ echo "scripts/shadacat.py" | |* | |*[Process exited 0] | |:terminal echo "scripts/shadacat.py" | Actual: |*^ | |*[Process exited 0] | |* | |:terminal echo "scripts/shadacat.py" | To print the expect() call that would assert the current screen state, use screen:snapshot_util(). In case of non-deterministic failures, use screen:redraw_debug() to show all intermediate screen states. stack traceback: test/functional/ui/screen.lua:579: in function '_wait' test/functional/ui/screen.lua:361: in function 'expect' test/functional/terminal/ex_terminal_spec.lua:248: in function --- test/functional/terminal/ex_terminal_spec.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'test') diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua index b0019d2d37..138befd978 100644 --- a/test/functional/terminal/ex_terminal_spec.lua +++ b/test/functional/terminal/ex_terminal_spec.lua @@ -245,12 +245,14 @@ describe(':terminal (with fake shell)', function() it('works with gf', function() command('set shellxquote=') -- win: avoid extra quotes terminal_with_fake_shell([[echo "scripts/shadacat.py"]]) + retry(nil, 4 * screen.timeout, function() screen:expect([[ ^ready $ echo "scripts/shadacat.py" | | [Process exited 0] | :terminal echo "scripts/shadacat.py" | ]]) + end) feed([[]]) eq('term://', string.match(eval('bufname("%")'), "^term://")) feed([[ggf"lgf]]) -- cgit From 440695c29696f261337227e5c419aa1cf313c2dd Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 28 Sep 2019 14:27:20 +0200 Subject: tree-sitter: implement query functionality and highlighting prototype [skip.lint] --- test/functional/api/highlight_spec.lua | 19 ++ test/functional/lua/treesitter_spec.lua | 476 ++++++++++++++++++++++++-------- 2 files changed, 382 insertions(+), 113 deletions(-) (limited to 'test') diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua index 5297c6454e..b6514a105c 100644 --- a/test/functional/api/highlight_spec.lua +++ b/test/functional/api/highlight_spec.lua @@ -4,6 +4,9 @@ local Screen = require('test.functional.ui.screen') local eq, eval = helpers.eq, helpers.eval local command = helpers.command local meths = helpers.meths +local funcs = helpers.funcs +local pcall_err = helpers.pcall_err +local ok = helpers.ok describe('API: highlight',function() local expected_rgb = { @@ -110,4 +113,20 @@ describe('API: highlight',function() meths.get_hl_by_name('cursorline', 0)); end) + + it('nvim_get_hl_id_by_name', function() + -- precondition: use a hl group that does not yet exist + eq('Invalid highlight name: Shrubbery', pcall_err(meths.get_hl_by_name, "Shrubbery", true)) + eq(0, funcs.hlID("Shrubbery")) + + local hl_id = meths.get_hl_id_by_name("Shrubbery") + ok(hl_id > 0) + eq(hl_id, funcs.hlID("Shrubbery")) + + command('hi Shrubbery guifg=#888888 guibg=#888888') + eq({foreground=tonumber("0x888888"), background=tonumber("0x888888")}, + meths.get_hl_by_id(hl_id, true)) + eq({foreground=tonumber("0x888888"), background=tonumber("0x888888")}, + meths.get_hl_by_name("Shrubbery", true)) + end) end) diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index 5a53ca1425..76e9899d34 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -1,5 +1,6 @@ -- Test suite for testing interactions with API bindings local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') local clear = helpers.clear local eq = helpers.eq @@ -26,122 +27,371 @@ describe('treesitter API', function() pcall_err(exec_lua, "parser = vim.treesitter.inspect_language('borklang')")) end) +end) + +describe('treesitter API with C parser', function() local ts_path = os.getenv("TREE_SITTER_DIR") - describe('with C parser', function() - if ts_path == nil then - it("works", function() pending("TREE_SITTER_PATH not set, skipping treesitter parser tests") end) - return - end - - before_each(function() - local path = ts_path .. '/bin/c'..(iswin() and '.dll' or '.so') - exec_lua([[ - local path = ... - vim.treesitter.add_language(path,'c') - ]], path) - end) - - it('parses buffer', function() - insert([[ - int main() { - int x = 3; - }]]) - - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse() - root = tree:root() - lang = vim.treesitter.inspect_language('c') - ]]) - - eq("", exec_lua("return tostring(tree)")) - eq("", exec_lua("return tostring(root)")) - eq({0,0,3,0}, exec_lua("return {root:range()}")) - - eq(1, exec_lua("return root:child_count()")) - exec_lua("child = root:child(0)") - eq("", exec_lua("return tostring(child)")) - eq({0,0,2,1}, exec_lua("return {child:range()}")) - - eq("function_definition", exec_lua("return child:type()")) - eq(true, exec_lua("return child:named()")) - eq("number", type(exec_lua("return child:symbol()"))) - eq({'function_definition', true}, exec_lua("return lang.symbols[child:symbol()]")) - - exec_lua("anon = root:descendant_for_range(0,8,0,9)") - eq("(", exec_lua("return anon:type()")) - eq(false, exec_lua("return anon:named()")) - eq("number", type(exec_lua("return anon:symbol()"))) - eq({'(', false}, exec_lua("return lang.symbols[anon:symbol()]")) - - exec_lua("descendant = root:descendant_for_range(1,2,1,12)") - eq("", exec_lua("return tostring(descendant)")) - eq({1,2,1,12}, exec_lua("return {descendant:range()}")) - eq("(declaration type: (primitive_type) declarator: (init_declarator declarator: (identifier) value: (number_literal)))", exec_lua("return descendant:sexpr()")) - - eq(true, exec_lua("return child == child")) - -- separate lua object, but represents same node - eq(true, exec_lua("return child == root:child(0)")) - eq(false, exec_lua("return child == descendant2")) - eq(false, exec_lua("return child == nil")) - eq(false, exec_lua("return child == tree")) - - feed("2G7|ay") - exec_lua([[ - tree2 = parser:parse() - root2 = tree2:root() - descendant2 = root2:descendant_for_range(1,2,1,13) - ]]) - eq(false, exec_lua("return tree2 == tree1")) - eq(false, exec_lua("return root2 == root")) - eq("", exec_lua("return tostring(descendant2)")) - eq({1,2,1,13}, exec_lua("return {descendant2:range()}")) - - -- orginal tree did not change - eq({1,2,1,12}, exec_lua("return {descendant:range()}")) - - -- unchanged buffer: return the same tree - eq(true, exec_lua("return parser:parse() == tree2")) - end) - - it('inspects language', function() - local keys, fields, symbols = unpack(exec_lua([[ - local lang = vim.treesitter.inspect_language('c') - local keys, symbols = {}, {} - for k,_ in pairs(lang) do - keys[k] = true - end - - -- symbols array can have "holes" and is thus not a valid msgpack array - -- but we don't care about the numbers here (checked in the parser test) - for _, v in pairs(lang.symbols) do - table.insert(symbols, v) - end - return {keys, lang.fields, symbols} - ]])) - - eq({fields=true, symbols=true}, keys) - - local fset = {} - for _,f in pairs(fields) do - eq("string", type(f)) - fset[f] = true + -- The tests after this requires an actual parser + if ts_path == nil then + it("works", function() pending("TREE_SITTER_PATH not set, skipping treesitter parser tests") end) + return + end + + before_each(function() + local path = ts_path .. '/bin/c'..(iswin() and '.dll' or '.so') + exec_lua([[ + local path = ... + vim.treesitter.add_language(path,'c') + ]], path) + end) + + it('parses buffer', function() + insert([[ + int main() { + int x = 3; + }]]) + + exec_lua([[ + parser = vim.treesitter.get_parser(0, "c") + tree = parser:parse() + root = tree:root() + lang = vim.treesitter.inspect_language('c') + ]]) + + eq("", exec_lua("return tostring(tree)")) + eq("", exec_lua("return tostring(root)")) + eq({0,0,3,0}, exec_lua("return {root:range()}")) + + eq(1, exec_lua("return root:child_count()")) + exec_lua("child = root:child(0)") + eq("", exec_lua("return tostring(child)")) + eq({0,0,2,1}, exec_lua("return {child:range()}")) + + eq("function_definition", exec_lua("return child:type()")) + eq(true, exec_lua("return child:named()")) + eq("number", type(exec_lua("return child:symbol()"))) + eq({'function_definition', true}, exec_lua("return lang.symbols[child:symbol()]")) + + exec_lua("anon = root:descendant_for_range(0,8,0,9)") + eq("(", exec_lua("return anon:type()")) + eq(false, exec_lua("return anon:named()")) + eq("number", type(exec_lua("return anon:symbol()"))) + eq({'(', false}, exec_lua("return lang.symbols[anon:symbol()]")) + + exec_lua("descendant = root:descendant_for_range(1,2,1,12)") + eq("", exec_lua("return tostring(descendant)")) + eq({1,2,1,12}, exec_lua("return {descendant:range()}")) + eq("(declaration type: (primitive_type) declarator: (init_declarator declarator: (identifier) value: (number_literal)))", exec_lua("return descendant:sexpr()")) + + eq(true, exec_lua("return child == child")) + -- separate lua object, but represents same node + eq(true, exec_lua("return child == root:child(0)")) + eq(false, exec_lua("return child == descendant2")) + eq(false, exec_lua("return child == nil")) + eq(false, exec_lua("return child == tree")) + + feed("2G7|ay") + exec_lua([[ + tree2 = parser:parse() + root2 = tree2:root() + descendant2 = root2:descendant_for_range(1,2,1,13) + ]]) + eq(false, exec_lua("return tree2 == tree1")) + eq(false, exec_lua("return root2 == root")) + eq("", exec_lua("return tostring(descendant2)")) + eq({1,2,1,13}, exec_lua("return {descendant2:range()}")) + + -- orginal tree did not change + eq({1,2,1,12}, exec_lua("return {descendant:range()}")) + + -- unchanged buffer: return the same tree + eq(true, exec_lua("return parser:parse() == tree2")) + end) + + local test_text = [[ +void ui_refresh(void) +{ + int width = INT_MAX, height = INT_MAX; + bool ext_widgets[kUIExtCount]; + for (UIExtension i = 0; (int)i < kUIExtCount; i++) { + ext_widgets[i] = true; + } + + bool inclusive = ui_override(); + for (size_t i = 0; i < ui_count; i++) { + UI *ui = uis[i]; + width = MIN(ui->width, width); + height = MIN(ui->height, height); + foo = BAR(ui->bazaar, bazaar); + for (UIExtension j = 0; (int)j < kUIExtCount; j++) { + ext_widgets[j] &= (ui->ui_ext[j] || inclusive); + } + } +}]] + + local query = [[ + ((call_expression function: (identifier) @minfunc (argument_list (identifier) @min_id)) (eq? @minfunc "MIN")) + "for" @keyword + (primitive_type) @type + (field_expression argument: (identifier) @fieldarg) + ]] + + it('support query and iter by capture', function() + insert(test_text) + + local res = exec_lua([[ + cquery = vim.treesitter.parse_query("c", ...) + parser = vim.treesitter.get_parser(0, "c") + tree = parser:parse() + res = {} + for cid, node in cquery:iter_captures(tree:root(), 0, 7, 14) do + -- can't transmit node over RPC. just check the name and range + table.insert(res, {cquery.captures[cid], node:type(), node:range()}) + end + return res + ]], query) + + eq({ + { "type", "primitive_type", 8, 2, 8, 6 }, + { "keyword", "for", 9, 2, 9, 5 }, + { "type", "primitive_type", 9, 7, 9, 13 }, + { "minfunc", "identifier", 11, 12, 11, 15 }, + { "fieldarg", "identifier", 11, 16, 11, 18 }, + { "min_id", "identifier", 11, 27, 11, 32 }, + { "minfunc", "identifier", 12, 13, 12, 16 }, + { "fieldarg", "identifier", 12, 17, 12, 19 }, + { "min_id", "identifier", 12, 29, 12, 35 }, + { "fieldarg", "identifier", 13, 14, 13, 16 } + }, res) + end) + + it('support query and iter by match', function() + insert(test_text) + + local res = exec_lua([[ + cquery = vim.treesitter.parse_query("c", ...) + parser = vim.treesitter.get_parser(0, "c") + tree = parser:parse() + res = {} + for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) do + -- can't transmit node over RPC. just check the name and range + local mrepr = {} + for cid,node in pairs(match) do + table.insert(mrepr, {cquery.captures[cid], node:type(), node:range()}) end - eq(true, fset["directive"]) - eq(true, fset["initializer"]) - - local has_named, has_anonymous - for _,s in pairs(symbols) do - eq("string", type(s[1])) - eq("boolean", type(s[2])) - if s[1] == "for_statement" and s[2] == true then - has_named = true - elseif s[1] == "|=" and s[2] == false then - has_anonymous = true - end + table.insert(res, {pattern, mrepr}) + end + return res + ]], query) + + eq({ + { 3, { { "type", "primitive_type", 8, 2, 8, 6 } } }, + { 2, { { "keyword", "for", 9, 2, 9, 5 } } }, + { 3, { { "type", "primitive_type", 9, 7, 9, 13 } } }, + { 4, { { "fieldarg", "identifier", 11, 16, 11, 18 } } }, + { 1, { { "minfunc", "identifier", 11, 12, 11, 15 }, { "min_id", "identifier", 11, 27, 11, 32 } } }, + { 4, { { "fieldarg", "identifier", 12, 17, 12, 19 } } }, + { 1, { { "minfunc", "identifier", 12, 13, 12, 16 }, { "min_id", "identifier", 12, 29, 12, 35 } } }, + { 4, { { "fieldarg", "identifier", 13, 14, 13, 16 } } } + }, res) + end) + + it('supports highlighting', function() + local hl_text = [[ +/// Schedule Lua callback on main loop's event queue +static int nlua_schedule(lua_State *const lstate) +{ + if (lua_type(lstate, 1) != LUA_TFUNCTION + || lstate != lstate) { + lua_pushliteral(lstate, "vim.schedule: expected function"); + return lua_error(lstate); + } + + LuaRef cb = nlua_ref(lstate, 1); + + multiqueue_put(main_loop.events, nlua_schedule_event, + 1, (void *)(ptrdiff_t)cb); + return 0; +}]] + + local hl_query = [[ +(ERROR) @ErrorMsg + +"if" @keyword +"else" @keyword +"for" @keyword +"return" @keyword + +"const" @type +"static" @type +"struct" @type +"enum" @type +"extern" @type + +(string_literal) @string + +(number_literal) @number +(char_literal) @string + +; TODO(bfredl): overlapping matches are unreliable, +; we need a proper priority mechanism +;(type_identifier) @type +((type_identifier) @Special (eq? @Special "LuaRef")) + +(primitive_type) @type +(sized_type_specifier) @type + +((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right) (eq? @WarningMsg.left @WarningMsg.right)) + +(comment) @comment +]] + + local screen = Screen.new(65, 18) + screen:attach() + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {foreground = Screen.colors.Blue1}, + [3] = {bold = true, foreground = Screen.colors.SeaGreen4}, + [4] = {bold = true, foreground = Screen.colors.Brown}, + [5] = {foreground = Screen.colors.Magenta}, + [6] = {foreground = Screen.colors.Red}, + [7] = {foreground = Screen.colors.SlateBlue}, + [8] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [9] = {foreground = Screen.colors.Magenta, background = Screen.colors.Red}, + [10] = {foreground = Screen.colors.Red, background = Screen.colors.Red}, + + }) + + insert(hl_text) + screen:expect{grid=[[ + /// Schedule Lua callback on main loop's event queue | + static int nlua_schedule(lua_State *const lstate) | + { | + if (lua_type(lstate, 1) != LUA_TFUNCTION | + || lstate != lstate) { | + lua_pushliteral(lstate, "vim.schedule: expected function"); | + return lua_error(lstate); | + } | + | + LuaRef cb = nlua_ref(lstate, 1); | + | + multiqueue_put(main_loop.events, nlua_schedule_event, | + 1, (void *)(ptrdiff_t)cb); | + return 0; | + ^} | + {1:~ }| + {1:~ }| + | + ]]} + + exec_lua([[ + local TSHighlighter = vim.treesitter.TSHighlighter + local query = ... + test_hl = TSHighlighter.new(query, 0, "c") + ]], hl_query) + screen:expect{grid=[[ + {2:/// Schedule Lua callback on main loop's event queue} | + {3:static} {3:int} nlua_schedule(lua_State *{3:const} lstate) | + { | + {4:if} (lua_type(lstate, {5:1}) != LUA_TFUNCTION | + || {6:lstate} != {6:lstate}) { | + lua_pushliteral(lstate, {5:"vim.schedule: expected function"}); | + {4:return} lua_error(lstate); | + } | + | + {7:LuaRef} cb = nlua_ref(lstate, {5:1}); | + | + multiqueue_put(main_loop.events, nlua_schedule_event, | + {5:1}, ({3:void} *)(ptrdiff_t)cb); | + {4:return} {5:0}; | + ^} | + {1:~ }| + {1:~ }| + | + ]]} + + feed('7Go*/') + screen:expect{grid=[[ + {2:/// Schedule Lua callback on main loop's event queue} | + {3:static} {3:int} nlua_schedule(lua_State *{3:const} lstate) | + { | + {4:if} (lua_type(lstate, {5:1}) != LUA_TFUNCTION | + || {6:lstate} != {6:lstate}) { | + lua_pushliteral(lstate, {5:"vim.schedule: expected function"}); | + {4:return} lua_error(lstate); | + {8:*^/} | + } | + | + {7:LuaRef} cb = nlua_ref(lstate, {5:1}); | + | + multiqueue_put(main_loop.events, nlua_schedule_event, | + {5:1}, ({3:void} *)(ptrdiff_t)cb); | + {4:return} {5:0}; | + } | + {1:~ }| + | + ]]} + + feed('3Go/*') + screen:expect{grid=[[ + {2:/// Schedule Lua callback on main loop's event queue} | + {3:static} {3:int} nlua_schedule(lua_State *{3:const} lstate) | + { | + {2:/^*} | + {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} | + {2: || lstate != lstate) {} | + {2: lua_pushliteral(lstate, "vim.schedule: expected function");} | + {2: return lua_error(lstate);} | + {2:*/} | + } | + | + {7:LuaRef} cb = nlua_ref(lstate, {5:1}); | + | + multiqueue_put(main_loop.events, nlua_schedule_event, | + {5:1}, ({3:void} *)(ptrdiff_t)cb); | + {4:return} {5:0}; | + {8:}} | + | + ]]} + end) + + it('inspects language', function() + local keys, fields, symbols = unpack(exec_lua([[ + local lang = vim.treesitter.inspect_language('c') + local keys, symbols = {}, {} + for k,_ in pairs(lang) do + keys[k] = true + end + + -- symbols array can have "holes" and is thus not a valid msgpack array + -- but we don't care about the numbers here (checked in the parser test) + for _, v in pairs(lang.symbols) do + table.insert(symbols, v) + end + return {keys, lang.fields, symbols} + ]])) + + eq({fields=true, symbols=true}, keys) + + local fset = {} + for _,f in pairs(fields) do + eq("string", type(f)) + fset[f] = true + end + eq(true, fset["directive"]) + eq(true, fset["initializer"]) + + local has_named, has_anonymous + for _,s in pairs(symbols) do + eq("string", type(s[1])) + eq("boolean", type(s[2])) + if s[1] == "for_statement" and s[2] == true then + has_named = true + elseif s[1] == "|=" and s[2] == false then + has_anonymous = true end - eq({true,true}, {has_named,has_anonymous}) - end) + end + eq({true,true}, {has_named,has_anonymous}) end) end) -- cgit From b3686b1597ea202de464df72a88fb5c76fd1b814 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Tue, 24 Dec 2019 07:53:56 +0100 Subject: system(), jobstart(): raise error on non-executable #11234 * tv_to_argv: error when cmd is not executable Callers always assume that emsg was emitted: - https://github.com/neovim/neovim/blob/57fbf288/src/nvim/eval.c#L12509 - https://github.com/neovim/neovim/blob/57fbf288/src/nvim/eval.c#L17923 - https://github.com/neovim/neovim/blob/57fbf288/src/nvim/eval.c#L18202 * test/functional/provider: display reason from missing_provider * provider#node#Detect: skip / handle non-existing node executable --- test/functional/core/job_spec.lua | 9 ++++----- test/functional/eval/system_spec.lua | 9 ++++++--- test/functional/provider/nodejs_spec.lua | 5 +++-- test/functional/provider/python3_spec.lua | 5 +++-- test/functional/provider/python_spec.lua | 5 +++-- test/functional/provider/ruby_spec.lua | 5 +++-- 6 files changed, 22 insertions(+), 16 deletions(-) (limited to 'test') diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index e5d4444b92..b63b868127 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -185,11 +185,10 @@ describe('jobs', function() return eval([[jobstart('')]]) end local executable_jobid = new_job() - local nonexecutable_jobid = eval("jobstart(['"..(iswin() - and './test/functional/fixtures' - or './test/functional/fixtures/non_executable.txt').."'])") - eq(-1, nonexecutable_jobid) - -- Should _not_ throw an error. + + local exe = iswin() and './test/functional/fixtures' or './test/functional/fixtures/non_executable.txt' + eq("Vim:E475: Invalid value for argument cmd: '"..exe.."' is not executable", + pcall_err(eval, "jobstart(['"..exe.."'])")) eq("", eval("v:errmsg")) -- Non-executable job should not increment the job ids. #5465 eq(executable_jobid + 1, new_job()) diff --git a/test/functional/eval/system_spec.lua b/test/functional/eval/system_spec.lua index 1e4d760dbc..8b18eff451 100644 --- a/test/functional/eval/system_spec.lua +++ b/test/functional/eval/system_spec.lua @@ -8,6 +8,7 @@ local command = helpers.command local exc_exec = helpers.exc_exec local iswin = helpers.iswin local os_kill = helpers.os_kill +local pcall_err = helpers.pcall_err local Screen = require('test.functional.ui.screen') @@ -32,8 +33,9 @@ describe('system()', function() return nvim_dir..'/printargs-test' .. (iswin() and '.exe' or '') end - it('sets v:shell_error if cmd[0] is not executable', function() - call('system', { 'this-should-not-exist' }) + it('throws error if cmd[0] is not executable', function() + eq("Vim:E475: Invalid value for argument cmd: 'this-should-not-exist' is not executable", + pcall_err(call, 'system', { 'this-should-not-exist' })) eq(-1, eval('v:shell_error')) end) @@ -48,7 +50,8 @@ describe('system()', function() eq(0, eval('v:shell_error')) -- Provoke a non-zero v:shell_error. - call('system', { 'this-should-not-exist' }) + eq("Vim:E475: Invalid value for argument cmd: 'this-should-not-exist' is not executable", + pcall_err(call, 'system', { 'this-should-not-exist' })) local old_val = eval('v:shell_error') eq(-1, old_val) diff --git a/test/functional/provider/nodejs_spec.lua b/test/functional/provider/nodejs_spec.lua index 07a00f8a8c..661a6f4f94 100644 --- a/test/functional/provider/nodejs_spec.lua +++ b/test/functional/provider/nodejs_spec.lua @@ -8,8 +8,9 @@ local retry = helpers.retry do clear() - if missing_provider('node') then - pending("Missing nodejs host, or nodejs version is too old.", function()end) + local reason = missing_provider('node') + if reason then + pending(string.format("Missing nodejs host, or nodejs version is too old (%s)", reason), function() end) return end end diff --git a/test/functional/provider/python3_spec.lua b/test/functional/provider/python3_spec.lua index b319d5e948..d254edc7d5 100644 --- a/test/functional/provider/python3_spec.lua +++ b/test/functional/provider/python3_spec.lua @@ -10,13 +10,14 @@ local pcall_err = helpers.pcall_err do clear() - if missing_provider('python3') then + local reason = missing_provider('python3') + if reason then it(':python3 reports E319 if provider is missing', function() local expected = [[Vim%(py3.*%):E319: No "python3" provider found.*]] matches(expected, pcall_err(command, 'py3 print("foo")')) matches(expected, pcall_err(command, 'py3file foo')) end) - pending('Python 3 (or the pynvim module) is broken/missing', function() end) + pending(string.format('Python 3 (or the pynvim module) is broken/missing (%s)', reason), function() end) return end end diff --git a/test/functional/provider/python_spec.lua b/test/functional/provider/python_spec.lua index 986f10b2e9..d60d8d1001 100644 --- a/test/functional/provider/python_spec.lua +++ b/test/functional/provider/python_spec.lua @@ -18,13 +18,14 @@ local pcall_err = helpers.pcall_err do clear() - if missing_provider('python') then + local reason = missing_provider('python') + if reason then it(':python reports E319 if provider is missing', function() local expected = [[Vim%(py.*%):E319: No "python" provider found.*]] matches(expected, pcall_err(command, 'py print("foo")')) matches(expected, pcall_err(command, 'pyfile foo')) end) - pending('Python 2 (or the pynvim module) is broken/missing', function() end) + pending(string.format('Python 2 (or the pynvim module) is broken/missing (%s)', reason), function() end) return end end diff --git a/test/functional/provider/ruby_spec.lua b/test/functional/provider/ruby_spec.lua index d20adde2ef..bb7d23ede6 100644 --- a/test/functional/provider/ruby_spec.lua +++ b/test/functional/provider/ruby_spec.lua @@ -18,13 +18,14 @@ local pcall_err = helpers.pcall_err do clear() - if missing_provider('ruby') then + local reason = missing_provider('ruby') + if reason then it(':ruby reports E319 if provider is missing', function() local expected = [[Vim%(ruby.*%):E319: No "ruby" provider found.*]] matches(expected, pcall_err(command, 'ruby puts "foo"')) matches(expected, pcall_err(command, 'rubyfile foo')) end) - pending("Missing neovim RubyGem.", function() end) + pending(string.format('Missing neovim RubyGem (%s)', reason), function() end) return end end -- cgit From bbad324b175f1bd35201f0ba73fba1b11af7093d Mon Sep 17 00:00:00 2001 From: Matthieu Coudron Date: Sun, 8 Dec 2019 01:05:49 +0100 Subject: fillchars: adding foldopen, foldsep, foldclose MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit You can try it with set fillchars+=foldopen:▾,foldsep:│,foldclose:▸ --- test/functional/ui/fold_spec.lua | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'test') diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua index eb81aba131..0b788e7afb 100644 --- a/test/functional/ui/fold_spec.lua +++ b/test/functional/ui/fold_spec.lua @@ -60,6 +60,45 @@ describe("folded lines", function() ]]) end) + it("works with multibyte fillchars", function() + insert([[ + aa + bb + cc + dd + ee + ff]]) + command("set fillchars+=foldopen:▾,foldsep:│,foldclose:▸") + feed_command('1') + command("set foldcolumn=2") + feed('zf4j') + feed('zf2j') + feed('zO') + screen:expect{grid=[[ + {7:▾▾}^aa | + {7:││}bb | + {7:││}cc | + {7:││}dd | + {7:││}ee | + {7:│ }ff | + {1:~ }| + :1 | + ]]} + + feed_command("set rightleft") + screen:expect{grid=[[ + a^a{7:▾▾}| + bb{7:││}| + cc{7:││}| + dd{7:││}| + ee{7:││}| + ff{7: │}| + {1: ~}| + :set rightleft | + ]]} + end) + + it("works with multibyte text", function() -- Currently the only allowed value of 'maxcombine' eq(6, meths.get_option('maxcombine')) -- cgit From 52566dd780a0ac5c584213111e6f5294874195a9 Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Fri, 27 Dec 2019 03:20:17 -0800 Subject: LSP: Fix flaky test #11618 --- test/functional/plugin/lsp/lsp_spec.lua | 1 - 1 file changed, 1 deletion(-) (limited to 'test') diff --git a/test/functional/plugin/lsp/lsp_spec.lua b/test/functional/plugin/lsp/lsp_spec.lua index c38c9b72ce..f10fd5c185 100644 --- a/test/functional/plugin/lsp/lsp_spec.lua +++ b/test/functional/plugin/lsp/lsp_spec.lua @@ -139,7 +139,6 @@ describe('Language Client API', function() eq(false, exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID) == nil")) eq(false, exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID).is_stopped()")) exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID).stop()") - eq(false, exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID).is_stopped()")) for _ = 1, 20 do helpers.sleep(10) if exec_lua("return #lsp.get_active_clients()") == 0 then -- cgit From 680693e263576e34d5947c43ab0ae3ff0ebfeab5 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Sun, 29 Dec 2019 02:28:00 +0900 Subject: runtime: Add vim.lsp.get_client_by_name (#11603) Since the client name is more obvious than the client id for the user, add an API to get the lsp client by the client name. --- test/functional/plugin/lsp/lsp_spec.lua | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'test') diff --git a/test/functional/plugin/lsp/lsp_spec.lua b/test/functional/plugin/lsp/lsp_spec.lua index f10fd5c185..99240ebed6 100644 --- a/test/functional/plugin/lsp/lsp_spec.lua +++ b/test/functional/plugin/lsp/lsp_spec.lua @@ -111,6 +111,7 @@ describe('Language Client API', function() exec_lua([=[ lsp = require('vim.lsp') local test_name, fixture_filename = ... + TEST_NAME = test_name TEST_RPC_CLIENT_ID = lsp.start_client { cmd = { vim.api.nvim_get_vvar("progpath"), '-Es', '-u', 'NONE', '--headless', @@ -118,6 +119,7 @@ describe('Language Client API', function() "-c", "luafile "..fixture_filename; }; root_dir = vim.loop.cwd(); + name = test_name; } ]=], test_name, lsp_test_rpc_server_file) end) @@ -137,6 +139,7 @@ describe('Language Client API', function() end eq(1, exec_lua("return #lsp.get_active_clients()")) eq(false, exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID) == nil")) + eq(false, exec_lua("return lsp.get_client_by_name(TEST_NAME) == nil")) eq(false, exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID).is_stopped()")) exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID).stop()") for _ = 1, 20 do @@ -146,6 +149,7 @@ describe('Language Client API', function() end end eq(true, exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID) == nil")) + eq(true, exec_lua("return lsp.get_client_by_name(TEST_NAME) == nil")) end) end) end) -- cgit From 34a59242a0d42687a49119cca590e7b4203496ef Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Sun, 29 Dec 2019 00:05:32 -0800 Subject: Revert "runtime: Add vim.lsp.get_client_by_name" #11623 reverts 680693e263576e34d5947c43ab0ae3ff0ebfeab5 #11603 --- test/functional/plugin/lsp/lsp_spec.lua | 4 ---- 1 file changed, 4 deletions(-) (limited to 'test') diff --git a/test/functional/plugin/lsp/lsp_spec.lua b/test/functional/plugin/lsp/lsp_spec.lua index 99240ebed6..f10fd5c185 100644 --- a/test/functional/plugin/lsp/lsp_spec.lua +++ b/test/functional/plugin/lsp/lsp_spec.lua @@ -111,7 +111,6 @@ describe('Language Client API', function() exec_lua([=[ lsp = require('vim.lsp') local test_name, fixture_filename = ... - TEST_NAME = test_name TEST_RPC_CLIENT_ID = lsp.start_client { cmd = { vim.api.nvim_get_vvar("progpath"), '-Es', '-u', 'NONE', '--headless', @@ -119,7 +118,6 @@ describe('Language Client API', function() "-c", "luafile "..fixture_filename; }; root_dir = vim.loop.cwd(); - name = test_name; } ]=], test_name, lsp_test_rpc_server_file) end) @@ -139,7 +137,6 @@ describe('Language Client API', function() end eq(1, exec_lua("return #lsp.get_active_clients()")) eq(false, exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID) == nil")) - eq(false, exec_lua("return lsp.get_client_by_name(TEST_NAME) == nil")) eq(false, exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID).is_stopped()")) exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID).stop()") for _ = 1, 20 do @@ -149,7 +146,6 @@ describe('Language Client API', function() end end eq(true, exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID) == nil")) - eq(true, exec_lua("return lsp.get_client_by_name(TEST_NAME) == nil")) end) end) end) -- cgit From 703ed11c97256997aa0ce8aa5fe04b6e89e8e829 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Tue, 10 Sep 2019 00:42:59 -0400 Subject: vim-patch:8.0.1491: the minimum width of the popup menu is hard coded Problem: The minimum width of the popup menu is hard coded. Solution: Add the 'pumwidth' option. (Christian Brabandt, James McCoy, closes vim/vim#2314) https://github.com/vim/vim/commit/a8f04aa275984183bab5bb583b128f38c64abb69 --- test/functional/ui/popupmenu_spec.lua | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'test') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index fabcc05ce6..ae84145934 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -1156,10 +1156,10 @@ describe('builtin popupmenu', function() funcs.complete(29, {'word', 'choice', 'text', 'thing'}) screen:expect([[ some long prefix before the ^ | - {1:~ }{n: word }| - {1:~ }{n: choice}| - {1:~ }{n: text }| - {1:~ }{n: thing }| + {1:~ }{n: word }| + {1:~ }{n: choice }| + {1:~ }{n: text }| + {1:~ }{n: thing }| {1:~ }| {1:~ }| {1:~ }| @@ -1204,10 +1204,10 @@ describe('builtin popupmenu', function() feed('') screen:expect([[ some long prefix before the text| - {1:^~ }{n: word }| - {1:~ }{n: choice}| - {1:~ }{s: text }| - {1:~ }{n: thing }| + {1:^~ }{n: word }| + {1:~ }{n: choice }| + {1:~ }{s: text }| + {1:~ }{n: thing }| {1:~ }| {1:~ }| {1:~ }| @@ -1301,10 +1301,10 @@ describe('builtin popupmenu', function() funcs.complete(29, {'word', 'choice', 'text', 'thing'}) screen:expect([[ some long prefix before the ^ | - {1:~ }{n: word }| - {1:~ }{n: choice}| - {1:~ }{n: text }| - {1:~ }{n: thing }| + {1:~ }{n: word }| + {1:~ }{n: choice }| + {1:~ }{n: text }| + {1:~ }{n: thing }| {1:~ }| {1:~ }| {1:~ }| -- cgit From 51c9e3c4d19f26af11a86a8f736a74a5cb6f2fa2 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Tue, 10 Sep 2019 20:53:13 -0400 Subject: vim-patch:8.0.1538: popupmenu is too far left when completion is long Problem: Popupmenu is too far left when completion is long. (Linwei) Solution: Adjust column computations. (Hirohito Higashi, closes vim/vim#2661) https://github.com/vim/vim/commit/bb008dd3239c5fe3ac04501e38e4c950fa9426c8 --- test/functional/ui/popupmenu_spec.lua | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'test') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index ae84145934..13affac571 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -1156,10 +1156,10 @@ describe('builtin popupmenu', function() funcs.complete(29, {'word', 'choice', 'text', 'thing'}) screen:expect([[ some long prefix before the ^ | - {1:~ }{n: word }| - {1:~ }{n: choice }| - {1:~ }{n: text }| - {1:~ }{n: thing }| + {n:word }{1: }| + {n:choice }{1: }| + {n:text }{1: }| + {n:thing }{1: }| {1:~ }| {1:~ }| {1:~ }| @@ -1204,10 +1204,10 @@ describe('builtin popupmenu', function() feed('') screen:expect([[ some long prefix before the text| - {1:^~ }{n: word }| - {1:~ }{n: choice }| - {1:~ }{s: text }| - {1:~ }{n: thing }| + {n:^word }{1: }| + {n:choice }{1: }| + {s:text }{1: }| + {n:thing }{1: }| {1:~ }| {1:~ }| {1:~ }| @@ -1301,10 +1301,10 @@ describe('builtin popupmenu', function() funcs.complete(29, {'word', 'choice', 'text', 'thing'}) screen:expect([[ some long prefix before the ^ | - {1:~ }{n: word }| - {1:~ }{n: choice }| - {1:~ }{n: text }| - {1:~ }{n: thing }| + {n:word }{1: }| + {n:choice }{1: }| + {n:text }{1: }| + {n:thing }{1: }| {1:~ }| {1:~ }| {1:~ }| -- cgit From 1d3d84fe818efaf47d8f818fcc44368d144443a1 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Thu, 26 Dec 2019 13:21:35 -0500 Subject: vim-patch:8.1.0554: popup menu overlaps with preview window Problem: Popup menu overlaps with preview window. Solution: Adjust the height computation. (Hirohito Higashi, closes vim/vim#3414) https://github.com/vim/vim/commit/614ab8aa00346724bfc27980d25985d482269b75 Cherry-picked "row -> pum_win_row" rename changes from patch 8.1.0062. --- test/functional/ui/popupmenu_spec.lua | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'test') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 13affac571..4c7f516c43 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -739,16 +739,16 @@ describe('builtin popupmenu', function() ee | ff | gg | - {s:aa } | - {n:bb }{3:iew][+] }| - {n:cc } | - {n:dd } | - {n:ee } | - {n:ff } | - {n:gg } | - {n:hh } | - {n:ii } | - {n:jj } | + hh | + {s:aa }{c: }{3:ew][+] }| + {n:bb }{c: } | + {n:cc }{c: } | + {n:dd }{c: } | + {n:ee }{c: } | + {n:ff }{c: } | + {n:gg }{c: } | + {n:hh }{c: } | + {n:ii }{s: } | aa^ | {4:[No Name] [+] }| {2:-- }{5:match 1 of 10} | -- cgit From ebd5c2cdda9a7114070021cbbc163054aa8f62da Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 29 Dec 2019 23:16:52 -0500 Subject: ui: add basic tests for pumheight,pumwidth --- test/functional/ui/popupmenu_spec.lua | 38 +++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'test') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 4c7f516c43..a0e5c3ca63 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -2019,4 +2019,42 @@ describe('builtin popupmenu', function() {9:-- Keyword Local completion (^N^P) }{10:match 1 of 3} | ]]) end) + + it("'pumheight'", function() + screen:try_resize(32,8) + feed('isome long prefix before the ') + command("set completeopt+=noinsert,noselect") + command("set linebreak") + command("set pumheight=2") + funcs.complete(29, {'word', 'choice', 'text', 'thing'}) + screen:expect([[ + some long prefix before the ^ | + {n:word }{c: }{1: }| + {n:choice }{s: }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + end) + + it("'pumwidth'", function() + screen:try_resize(32,8) + feed('isome long prefix before the ') + command("set completeopt+=noinsert,noselect") + command("set linebreak") + command("set pumwidth=8") + funcs.complete(29, {'word', 'choice', 'text', 'thing'}) + screen:expect([[ + some long prefix before the ^ | + {n:word }{1: }| + {n:choice }{1: }| + {n:text }{1: }| + {n:thing }{1: }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + end) end) -- cgit From 93e7c7e3bd30ae141b613e71a6a3a863e6064d91 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 10 Dec 2019 01:24:20 -0800 Subject: doc [ci skip] --- test/functional/normal/jump_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/normal/jump_spec.lua b/test/functional/normal/jump_spec.lua index d53b5f7415..9e7158e2f7 100644 --- a/test/functional/normal/jump_spec.lua +++ b/test/functional/normal/jump_spec.lua @@ -48,7 +48,7 @@ describe('jumplist', function() end) end) -describe('jumpoptions=stack behaves like browser history', function() +describe("jumpoptions=stack behaves like 'tagstack'", function() before_each(function() clear() feed(':clearjumps') -- cgit From 1836853955e51efbaf4aba7dec0718e51747b418 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Tue, 31 Dec 2019 14:21:57 -0500 Subject: ci: test powershell core on Linux --- test/functional/helpers.lua | 6 +++++- test/functional/ui/output_spec.lua | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index eead1ea3e0..0fdfcd70ba 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -504,9 +504,13 @@ function module.source(code) return fname end +function module.has_powershell() + return module.eval('executable("'..(iswin() and 'powershell' or 'pwsh')..'")') == 1 +end + function module.set_shell_powershell() local shell = iswin() and 'powershell' or 'pwsh' - assert(module.eval('executable("'..shell..'")')) + assert(module.has_powershell()) local cmd = 'Remove-Item -Force '..table.concat(iswin() and {'alias:cat', 'alias:echo', 'alias:sleep'} or {'alias:echo'}, ',')..';' diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua index 9b1e803649..d7dde6345f 100644 --- a/test/functional/ui/output_spec.lua +++ b/test/functional/ui/output_spec.lua @@ -10,6 +10,7 @@ local iswin = helpers.iswin local clear = helpers.clear local command = helpers.command local nvim_dir = helpers.nvim_dir +local has_powershell = helpers.has_powershell local set_shell_powershell = helpers.set_shell_powershell describe("shell command :!", function() @@ -228,7 +229,7 @@ describe("shell command :!", function() ]]) end) end) - if iswin() or eval('executable("pwsh")') == 1 then + if has_powershell() then it('powershell supports literal strings', function() set_shell_powershell() local screen = Screen.new(30, 4) -- cgit From 8b841196504f96a5c14126667fb4f4a0769914dd Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 31 Dec 2019 07:51:54 -0800 Subject: LSP: eliminate lsp.stop_all_clients() Reduce API surface. We don't need so many variations of functions. Too many functions means verbose, largely redundant documentation, tests, and cognitive burden. --- test/functional/plugin/lsp/lsp_spec.lua | 89 +++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 31 deletions(-) (limited to 'test') diff --git a/test/functional/plugin/lsp/lsp_spec.lua b/test/functional/plugin/lsp/lsp_spec.lua index f10fd5c185..e54275e820 100644 --- a/test/functional/plugin/lsp/lsp_spec.lua +++ b/test/functional/plugin/lsp/lsp_spec.lua @@ -3,6 +3,8 @@ local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local exec_lua = helpers.exec_lua local eq = helpers.eq +local iswin = helpers.iswin +local retry = helpers.retry local NIL = helpers.NIL -- Use these to get access to a coroutine so that I can run async tests and use @@ -11,9 +13,8 @@ local run, stop = helpers.run, helpers.stop if helpers.pending_win32(pending) then return end -local is_windows = require'luv'.os_uname().sysname == "Windows" local lsp_test_rpc_server_file = "test/functional/fixtures/lsp-test-rpc-server.lua" -if is_windows then +if iswin() then lsp_test_rpc_server_file = lsp_test_rpc_server_file:gsub("/", "\\") end @@ -101,8 +102,8 @@ local function test_rpc_server(config) end end -describe('Language Client API', function() - describe('server_name is specified', function() +describe('LSP', function() + describe('server_name specified', function() before_each(function() clear() -- Run an instance of nvim on the file which contains our "scripts". @@ -111,14 +112,17 @@ describe('Language Client API', function() exec_lua([=[ lsp = require('vim.lsp') local test_name, fixture_filename = ... - TEST_RPC_CLIENT_ID = lsp.start_client { - cmd = { - vim.api.nvim_get_vvar("progpath"), '-Es', '-u', 'NONE', '--headless', - "-c", string.format("lua TEST_NAME = %q", test_name), - "-c", "luafile "..fixture_filename; - }; - root_dir = vim.loop.cwd(); - } + function test__start_client() + return lsp.start_client { + cmd = { + vim.api.nvim_get_vvar("progpath"), '-Es', '-u', 'NONE', '--headless', + "-c", string.format("lua TEST_NAME = %q", test_name), + "-c", "luafile "..fixture_filename; + }; + root_dir = vim.loop.cwd(); + } + end + TEST_CLIENT1 = test__start_client() ]=], test_name, lsp_test_rpc_server_file) end) @@ -127,25 +131,48 @@ describe('Language Client API', function() -- exec_lua("lsp.stop_all_clients(true)") end) - describe('start_client and stop_client', function() - it('should return true', function() - for _ = 1, 20 do - helpers.sleep(10) - if exec_lua("return #lsp.get_active_clients()") > 0 then - break - end - end - eq(1, exec_lua("return #lsp.get_active_clients()")) - eq(false, exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID) == nil")) - eq(false, exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID).is_stopped()")) - exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID).stop()") - for _ = 1, 20 do - helpers.sleep(10) - if exec_lua("return #lsp.get_active_clients()") == 0 then - break - end - end - eq(true, exec_lua("return lsp.get_client_by_id(TEST_RPC_CLIENT_ID) == nil")) + it('start_client(), stop_client()', function() + retry(nil, 4000, function() + eq(1, exec_lua('return #lsp.get_active_clients()')) + end) + eq(2, exec_lua([[ + TEST_CLIENT2 = test__start_client() + return TEST_CLIENT2 + ]])) + eq(3, exec_lua([[ + TEST_CLIENT3 = test__start_client() + return TEST_CLIENT3 + ]])) + retry(nil, 4000, function() + eq(3, exec_lua('return #lsp.get_active_clients()')) + end) + + eq(false, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1) == nil')) + eq(false, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1).is_stopped()')) + exec_lua('return lsp.get_client_by_id(TEST_CLIENT1).stop()') + retry(nil, 4000, function() + eq(2, exec_lua('return #lsp.get_active_clients()')) + end) + eq(true, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1) == nil')) + + exec_lua('lsp.stop_client({TEST_CLIENT2, TEST_CLIENT3})') + retry(nil, 4000, function() + eq(0, exec_lua('return #lsp.get_active_clients()')) + end) + end) + + it('stop_client() also works on client objects', function() + exec_lua([[ + TEST_CLIENT2 = test__start_client() + TEST_CLIENT3 = test__start_client() + ]]) + retry(nil, 4000, function() + eq(3, exec_lua('return #lsp.get_active_clients()')) + end) + -- Stop all clients. + exec_lua('lsp.stop_client(lsp.get_active_clients())') + retry(nil, 4000, function() + eq(0, exec_lua('return #lsp.get_active_clients()')) end) end) end) -- cgit From ea4127e9a7a624484f51c21e17f37c766da15da0 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 27 Nov 2019 20:45:41 +0100 Subject: lua: metatable for empty dict value --- test/functional/lua/vim_spec.lua | 44 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 17ffcd8d86..e879f8b925 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -354,7 +354,8 @@ describe('lua stdlib', function() end) it('vim.tbl_islist', function() - eq(NIL, exec_lua("return vim.tbl_islist({})")) + eq(true, exec_lua("return vim.tbl_islist({})")) + eq(false, exec_lua("return vim.tbl_islist(vim.empty_dict())")) eq(true, exec_lua("return vim.tbl_islist({'a', 'b', 'c'})")) eq(false, exec_lua("return vim.tbl_islist({'a', '32', a='hello', b='baz'})")) eq(false, exec_lua("return vim.tbl_islist({1, a='hello', b='baz'})")) @@ -458,6 +459,19 @@ describe('lua stdlib', function() ]])) eq({3, 'aa', true, NIL}, exec_lua([[return ret]])) + eq({{}, {}, false, true}, exec_lua([[ + vim.rpcrequest(chan, 'nvim_exec', 'let xx = {}\nlet yy = []', false) + local dict = vim.rpcrequest(chan, 'nvim_eval', 'xx') + local list = vim.rpcrequest(chan, 'nvim_eval', 'yy') + return {dict, list, vim.tbl_islist(dict), vim.tbl_islist(list)} + ]])) + + exec_lua([[ + vim.rpcrequest(chan, 'nvim_set_var', 'aa', {}) + vim.rpcrequest(chan, 'nvim_set_var', 'bb', vim.empty_dict()) + ]]) + eq({1, 1}, eval('[type(g:aa) == type([]), type(g:bb) == type({})]')) + -- error handling eq({false, 'Invalid channel: 23'}, exec_lua([[return {pcall(vim.rpcrequest, 23, 'foo')}]])) @@ -486,7 +500,7 @@ describe('lua stdlib', function() }) screen:attach() exec_lua([[ - local timer = vim.loop.new_timer() + timer = vim.loop.new_timer() timer:start(20, 0, function () -- notify ok (executed later when safe) vim.rpcnotify(chan, 'nvim_set_var', 'yy', {3, vim.NIL}) @@ -505,6 +519,32 @@ describe('lua stdlib', function() ]]} feed('') eq({3, NIL}, meths.get_var('yy')) + + exec_lua([[timer:close()]]) + end) + + it('vim.empty_dict()', function() + eq({true, false, true, true}, exec_lua([[ + vim.api.nvim_set_var('listy', {}) + vim.api.nvim_set_var('dicty', vim.empty_dict()) + local listy = vim.fn.eval("listy") + local dicty = vim.fn.eval("dicty") + return {vim.tbl_islist(listy), vim.tbl_islist(dicty), next(listy) == nil, next(dicty) == nil} + ]])) + + -- vim.empty_dict() gives new value each time + -- equality is not overriden (still by ref) + -- non-empty table uses the usual heuristics (ignores the tag) + eq({false, {"foo"}, {namey="bar"}}, exec_lua([[ + local aa = vim.empty_dict() + local bb = vim.empty_dict() + local equally = (aa == bb) + aa[1] = "foo" + bb["namey"] = "bar" + return {equally, aa, bb} + ]])) + + eq("{ {}, vim.empty_dict() }", exec_lua("return vim.inspect({{}, vim.empty_dict()})")) end) it('vim.validate', function() -- cgit From cbc8d72fde4b19176028490934ff7a447afe523c Mon Sep 17 00:00:00 2001 From: butwerenotthereyet <58348703+butwerenotthereyet@users.noreply.github.com> Date: Thu, 2 Jan 2020 06:06:11 -0800 Subject: tabpage: track last-used tabpage #11626 In a multi-window scenario, it is possible to return focus to the last accessed window via n_CTRL-W_p. However, in the case of a multi-tab scenario, there was previously no way to return focus to the last accessed *tab*. Here, that ability is added via n_g. Additionally, the index of the previous tab is exposed via tabpagenr('#'), mirroring the existing functionality of winnr('#'). --- test/functional/autocmd/tabnewentered_spec.lua | 454 ++++++++++++++++++++++++- 1 file changed, 453 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/autocmd/tabnewentered_spec.lua b/test/functional/autocmd/tabnewentered_spec.lua index 32e341184d..6240db2042 100644 --- a/test/functional/autocmd/tabnewentered_spec.lua +++ b/test/functional/autocmd/tabnewentered_spec.lua @@ -1,5 +1,13 @@ local helpers = require('test.functional.helpers')(after_each) -local clear, nvim, eq = helpers.clear, helpers.nvim, helpers.eq + +local clear = helpers.clear +local command = helpers.command +local dedent = helpers.dedent +local eval = helpers.eval +local eq = helpers.eq +local feed = helpers.feed +local nvim = helpers.nvim +local redir_exec = helpers.redir_exec describe('TabNewEntered', function() describe('au TabNewEntered', function() @@ -29,3 +37,447 @@ describe('TabNewEntered', function() end) end) end) + +describe('TabEnter', function() + before_each(clear) + it('has correct previous tab when entering any new tab', function() + command('augroup TEMP') + nvim('command', 'au! TabEnter * echom "tabenter:".tabpagenr().":".tabpagenr(\'#\')') + command('augroup END') + eq("tabenter:2:1", nvim('exec', 'tabnew', true)) + eq("tabenter:3:2", nvim('exec', 'tabnew test.x2', true)) + command('augroup! TEMP') + end) + it('has correct previous tab when entering any preexisting tab', function() + command('tabnew') + command('tabnew') + command('augroup TEMP') + nvim('command', 'au! TabEnter * echom "tabenter:".tabpagenr().":".tabpagenr(\'#\')') + command('augroup END') + eq("tabenter:1:3", nvim('exec', 'tabnext', true)) + eq("tabenter:2:1", nvim('exec', 'tabnext', true)) + command('augroup! TEMP') + end) +end) + +describe('tabpage/previous', function() + before_each(clear) + local function switches_to_previous_after_new_tab_creation_at_end(characters) + return function() + -- Add three tabs for a total of four + command('tabnew') + command('tabnew') + command('tabnew') + + -- The previous tab is now the third. + eq(3, eval('tabpagenr(\'#\')')) + + -- Switch to the previous (third) tab + feed(characters) + + eq(dedent([=[ + + + Tab page 1 + [No Name] + Tab page 2 + [No Name] + Tab page 3 + > [No Name] + Tab page 4 + [No Name]]=]), + redir_exec('tabs') + ) + + -- The previous tab is now the fourth. + eq(4, eval('tabpagenr(\'#\')')) + end + end + it('switches to previous via g after new tab creation at end', + switches_to_previous_after_new_tab_creation_at_end('g')) + it('switches to previous via g. after new tab creation at end', switches_to_previous_after_new_tab_creation_at_end('g')) + it('switches to previous via . after new tab creation at end', switches_to_previous_after_new_tab_creation_at_end('')) + + local function switches_to_previous_after_new_tab_creation_in_middle(characters) + return function() + -- Add three tabs for a total of four + command('tabnew') + command('tabnew') + command('tabnew') + -- Switch to the second tab + command('tabnext 2') + -- Add a new tab after the second tab + command('tabnew') + + -- The previous tab is now the second. + eq(2, eval('tabpagenr(\'#\')')) + + -- Switch to the previous (second) tab + feed(characters) + eq(dedent([=[ + + + Tab page 1 + [No Name] + Tab page 2 + > [No Name] + Tab page 3 + [No Name] + Tab page 4 + [No Name] + Tab page 5 + [No Name]]=]), + redir_exec('tabs') + ) + + -- The previous tab is now the third. + eq(3, eval('tabpagenr(\'#\')')) + end + end + it('switches to previous via g after new tab creation in middle', + switches_to_previous_after_new_tab_creation_in_middle('g')) + it('switches to previous via g after new tab creation in middle', + switches_to_previous_after_new_tab_creation_in_middle('g')) + it('switches to previous via after new tab creation in middle', + switches_to_previous_after_new_tab_creation_in_middle('')) + + local function switches_to_previous_after_switching_to_next_tab(characters) + return function() + -- Add three tabs for a total of four + command('tabnew') + command('tabnew') + command('tabnew') + -- Switch to the next (first) tab + command('tabnext') + + -- The previous tab is now the fourth. + eq(4, eval('tabpagenr(\'#\')')) + + -- Switch to the previous (fourth) tab + feed(characters) + + eq(dedent([=[ + + + Tab page 1 + [No Name] + Tab page 2 + [No Name] + Tab page 3 + [No Name] + Tab page 4 + > [No Name]]=]), + redir_exec('tabs') + ) + + -- The previous tab is now the first. + eq(1, eval('tabpagenr(\'#\')')) + end + end + it('switches to previous via g after switching to next tab', + switches_to_previous_after_switching_to_next_tab('g')) + it('switches to previous via g after switching to next tab', + switches_to_previous_after_switching_to_next_tab('g')) + it('switches to previous via after switching to next tab', + switches_to_previous_after_switching_to_next_tab('')) + + local function switches_to_previous_after_switching_to_last_tab(characters) + return function() + -- Add three tabs for a total of four + command('tabnew') + command('tabnew') + command('tabnew') + -- Switch to the next (first) tab + command('tabnext') + -- Switch to the last (fourth) tab. + command('tablast') + + -- The previous tab is now the second. + eq(1, eval('tabpagenr(\'#\')')) + + -- Switch to the previous (second) tab + feed(characters) + + eq(dedent([=[ + + + Tab page 1 + > [No Name] + Tab page 2 + [No Name] + Tab page 3 + [No Name] + Tab page 4 + [No Name]]=]), + redir_exec('tabs') + ) + + -- The previous tab is now the fourth. + eq(4, eval('tabpagenr(\'#\')')) + end + end + it('switches to previous after switching to last tab', + switches_to_previous_after_switching_to_last_tab('g')) + it('switches to previous after switching to last tab', + switches_to_previous_after_switching_to_last_tab('g')) + it('switches to previous after switching to last tab', + switches_to_previous_after_switching_to_last_tab('')) + + local function switches_to_previous_after_switching_to_previous_tab(characters) + return function() + -- Add three tabs for a total of four + command('tabnew') + command('tabnew') + command('tabnew') + -- Switch to the previous (third) tab + command('tabprevious') + + -- The previous tab is now the fourth. + eq(4, eval('tabpagenr(\'#\')')) + + -- Switch to the previous (fourth) tab + feed(characters) + + eq(dedent([=[ + + + Tab page 1 + [No Name] + Tab page 2 + [No Name] + Tab page 3 + [No Name] + Tab page 4 + > [No Name]]=]), + redir_exec('tabs') + ) + + -- The previous tab is now the third. + eq(3, eval('tabpagenr(\'#\')')) + end + end + it('switches to previous via g after switching to previous tab', + switches_to_previous_after_switching_to_previous_tab('g')) + it('switches to previous via g after switching to previous tab', + switches_to_previous_after_switching_to_previous_tab('g')) + it('switches to previous via after switching to previous tab', + switches_to_previous_after_switching_to_previous_tab('')) + + local function switches_to_previous_after_switching_to_first_tab(characters) + return function() + -- Add three tabs for a total of four + command('tabnew') + command('tabnew') + command('tabnew') + -- Switch to the previous (third) tab + command('tabprevious') + -- Switch to the first tab + command('tabfirst') + + -- The previous tab is now the third. + eq(3, eval('tabpagenr(\'#\')')) + + -- Switch to the previous (third) tab + feed(characters) + + eq(dedent([=[ + + + Tab page 1 + [No Name] + Tab page 2 + [No Name] + Tab page 3 + > [No Name] + Tab page 4 + [No Name]]=]), + redir_exec('tabs') + ) + + -- The previous tab is now the first. + eq(1, eval('tabpagenr(\'#\')')) + end + end + it('switches to previous via g after switching to first tab', + switches_to_previous_after_switching_to_first_tab('g')) + it('switches to previous via g after switching to first tab', + switches_to_previous_after_switching_to_first_tab('g')) + it('switches to previous via after switching to first tab', + switches_to_previous_after_switching_to_first_tab('')) + + local function switches_to_previous_after_numbered_tab_switch(characters) + return function() + -- Add three tabs for a total of four + command('tabnew') + command('tabnew') + command('tabnew') + -- Switch to the second tab + command('tabnext 2') + + -- The previous tab is now the fourth. + eq(4, eval('tabpagenr(\'#\')')) + + -- Switch to the previous (fourth) tab + feed(characters) + + eq(dedent([=[ + + + Tab page 1 + [No Name] + Tab page 2 + [No Name] + Tab page 3 + [No Name] + Tab page 4 + > [No Name]]=]), + redir_exec('tabs') + ) + + -- The previous tab is now the second. + eq(2, eval('tabpagenr(\'#\')')) + end + end + it('switches to previous via g after numbered tab switch', + switches_to_previous_after_numbered_tab_switch('g')) + it('switches to previous via g after numbered tab switch', + switches_to_previous_after_numbered_tab_switch('g')) + it('switches to previous via after numbered tab switch', + switches_to_previous_after_numbered_tab_switch('')) + + local function switches_to_previous_after_switching_to_previous(characters1, characters2) + return function() + -- Add three tabs for a total of four + command('tabnew') + command('tabnew') + command('tabnew') + -- Switch to the second tab + command('tabnext 2') + -- Switch to the previous (fourth) tab + feed(characters1) + + -- The previous tab is now the second. + eq(2, eval('tabpagenr(\'#\')')) + + -- Switch to the previous (second) tab + feed(characters2) + + eq(dedent([=[ + + + Tab page 1 + [No Name] + Tab page 2 + > [No Name] + Tab page 3 + [No Name] + Tab page 4 + [No Name]]=]), + redir_exec('tabs') + ) + + -- The previous tab is now the fourth. + eq(4, eval('tabpagenr(\'#\')')) + end + end + it('switches to previous via g after switching to previous via g', + switches_to_previous_after_switching_to_previous('g', 'g')) + it('switches to previous via g after switching to previous via g', + switches_to_previous_after_switching_to_previous('g', 'g')) + it('switches to previous via after switching to previous via g', + switches_to_previous_after_switching_to_previous('g', '')) + it('switches to previous via g after switching to previous via g', + switches_to_previous_after_switching_to_previous('g', 'g')) + it('switches to previous via g after switching to previous via g', + switches_to_previous_after_switching_to_previous('g', 'g')) + it('switches to previous via after switching to previous via g', + switches_to_previous_after_switching_to_previous('g', '')) + it('switches to previous via g after switching to previous via ', + switches_to_previous_after_switching_to_previous('', 'g')) + it('switches to previous via g after switching to previous via ', + switches_to_previous_after_switching_to_previous('', 'g')) + it('switches to previous via after switching to previous via ', + switches_to_previous_after_switching_to_previous('', '')) + + local function does_not_switch_to_previous_after_closing_current_tab(characters) + return function() + -- Add three tabs for a total of four + command('tabnew') + command('tabnew') + command('tabnew') + -- Close the current (fourth tab) + command('wincmd c') + + -- The previous tab is now the "zeroth" -- there isn't one. + eq(0, eval('tabpagenr(\'#\')')) + + -- At this point, switching to the "previous" (i.e. fourth) tab would mean + -- switching to either a dangling or a null pointer. + feed(characters) + + eq(dedent([=[ + + + Tab page 1 + [No Name] + Tab page 2 + [No Name] + Tab page 3 + > [No Name]]=]), + redir_exec('tabs') + ) + + -- The previous tab is now the "zero". + eq(0, eval('tabpagenr(\'#\')')) + end + end + it('does not switch to previous via g after closing current tab', + does_not_switch_to_previous_after_closing_current_tab('g')) + it('does not switch to previous via g after closing current tab', + does_not_switch_to_previous_after_closing_current_tab('g')) + it('does not switch to previous via after closing current tab', + does_not_switch_to_previous_after_closing_current_tab('')) + + local function does_not_switch_to_previous_after_entering_operator_pending(characters) + return function() + -- Add three tabs for a total of four + command('tabnew') + command('tabnew') + command('tabnew') + + -- The previous tab is now the third. + eq(3, eval('tabpagenr(\'#\')')) + + -- Enter operator pending mode. + feed('d') + eq('no', eval('mode(1)')) + + -- At this point switching to the previous tab should have no effect + -- other than leaving operator pending mode. + feed(characters) + + -- Attempting to switch tabs returns us to normal mode. + eq('n', eval('mode()')) + + -- The current tab is still the fourth. + eq(4, eval('tabpagenr()')) + + -- The previous tab is still the third. + eq(3, eval('tabpagenr(\'#\')')) + end + end + it('does not switch to previous via g after entering operator pending', + does_not_switch_to_previous_after_entering_operator_pending('g')) + -- NOTE: When in operator pending mode, attempting to switch to previous has + -- the following effect: + -- - Ctrl-W exits operator pending mode + -- - g switches to the previous tab + -- In other words, the effect of "g" is to switch to the + -- previous tab even from operator pending mode, but only thanks to the + -- fact that the suffix after "" in "g" just happens to + -- be the same as the normal mode command to switch to the previous tab. + -- it('does not switch to previous via g after entering operator pending', + -- does_not_switch_to_previous_after_entering_operator_pending('g')) + it('does not switch to previous via after entering operator pending', + does_not_switch_to_previous_after_entering_operator_pending('')) +end) -- cgit From 42aa8764881ed8572d563766575c053db085f6db Mon Sep 17 00:00:00 2001 From: We're Yet <58348703+butwerenotthereyet@users.noreply.github.com> Date: Wed, 1 Jan 2020 09:52:13 -0800 Subject: vim-patch:8.1.0972: cannot switch from terminal window to next tabpage Problem: Cannot switch from terminal window to next tabpage. Solution: Make CTRL-W gt move to next tabpage. https://github.com/vim/vim/commit/72e83c1ae535e2ebc35b114d34d0a811eb62b068 --- test/functional/normal/tabpage_spec.lua | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 test/functional/normal/tabpage_spec.lua (limited to 'test') diff --git a/test/functional/normal/tabpage_spec.lua b/test/functional/normal/tabpage_spec.lua new file mode 100644 index 0000000000..68524eaf91 --- /dev/null +++ b/test/functional/normal/tabpage_spec.lua @@ -0,0 +1,25 @@ +local helpers = require('test.functional.helpers')(after_each) + +local clear = helpers.clear +local command = helpers.command +local eq = helpers.eq +local feed = helpers.feed +local eval = helpers.eval + +describe('tabpage', function() + before_each(clear) + + it('advances to the next page via gt', function() + -- add some tabpages + command('tabnew') + command('tabnew') + command('tabnew') + + eq(4, eval('tabpagenr()')) + + feed('gt') + + eq(1, eval('tabpagenr()')) + end) +end) + -- cgit From a7b6b375196ad2d0531550b2e1c7888502c9512b Mon Sep 17 00:00:00 2001 From: We're Yet <58348703+butwerenotthereyet@users.noreply.github.com> Date: Wed, 1 Jan 2020 10:08:06 -0800 Subject: vim-patch:8.1.0974: cannot switch from terminal window to previous tabpage Problem: Cannot switch from terminal window to previous tabpage. Solution: Make CTRL-W gT move to previous tabpage. https://github.com/vim/vim/commit/882d02eeb571a13a502fe82a04c9eaffa630c294 --- test/functional/normal/tabpage_spec.lua | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'test') diff --git a/test/functional/normal/tabpage_spec.lua b/test/functional/normal/tabpage_spec.lua index 68524eaf91..d1d6854b07 100644 --- a/test/functional/normal/tabpage_spec.lua +++ b/test/functional/normal/tabpage_spec.lua @@ -21,5 +21,18 @@ describe('tabpage', function() eq(1, eval('tabpagenr()')) end) + + it('retreats to the previous page via gT', function() + -- add some tabpages + command('tabnew') + command('tabnew') + command('tabnew') + + eq(4, eval('tabpagenr()')) + + feed('gT') + + eq(3, eval('tabpagenr()')) + end) end) -- cgit From 1aacab49ea0e5cff94bd89595737b6af677f4490 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 5 Jan 2020 10:40:02 -0500 Subject: vim-patch:8.1.1579: dict and list could be GC'ed while displaying error Problem: Dict and list could be GC'ed while displaying error in a timer. (Yasuhiro Matsumoto) Solution: Block garbage collection when executing a timer. Add test_garbagecollect_soon(). Add "no_wait_return" to test_override(). (closes vim/vim#4571) https://github.com/vim/vim/commit/adc6714aac20f5462a0ecec50ab4806b2f3ab0db --- test/unit/eval/helpers.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/unit/eval/helpers.lua b/test/unit/eval/helpers.lua index 3d1c42c3a0..bcd7c750c5 100644 --- a/test/unit/eval/helpers.lua +++ b/test/unit/eval/helpers.lua @@ -406,7 +406,7 @@ end local alloc_logging_helpers = { list = function(l) return {func='calloc', args={1, ffi.sizeof('list_T')}, ret=void(l)} end, li = function(li) return {func='malloc', args={ffi.sizeof('listitem_T')}, ret=void(li)} end, - dict = function(d) return {func='malloc', args={ffi.sizeof('dict_T')}, ret=void(d)} end, + dict = function(d) return {func='calloc', args={1, ffi.sizeof('dict_T')}, ret=void(d)} end, di = function(di, size) size = alloc_len(size, function() return di.di_key end) return {func='malloc', args={ffi.offsetof('dictitem_T', 'di_key') + size + 1}, ret=void(di)} -- cgit From 3c764aabb5d4be71a5ea0d50bf8dae0a7285677f Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 5 Jan 2020 22:51:49 -0500 Subject: vim-patch:8.1.1308: the Normal highlight is not defined when compiled with GUI Problem: The Normal highlight is not defined when compiled with GUI. Solution: Always define Normal. (Christian Brabandt, closes vim/vim#4072) https://github.com/vim/vim/commit/f90b6e03a983b62b66564fc449e32724d6456769 --- test/functional/ui/screen_basic_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua index 150ee2a103..ff9f30d0a1 100644 --- a/test/functional/ui/screen_basic_spec.lua +++ b/test/functional/ui/screen_basic_spec.lua @@ -987,7 +987,7 @@ describe('Screen default colors', function() it('can be set to light', function() startup(true, false) screen:expect{condition=function() - eq({rgb_bg=Screen.colors.White, rgb_fg=0, rgb_sp=Screen.colors.Red, + eq({rgb_fg=Screen.colors.White, rgb_bg=0, rgb_sp=Screen.colors.Red, cterm_bg=0, cterm_fg=0}, screen.default_colors) end} end) -- cgit From 831fa45ad84e2f41730db3350289e660006139d6 Mon Sep 17 00:00:00 2001 From: kevinhwang91 Date: Wed, 8 Jan 2020 22:19:23 +0800 Subject: API: nvim_get_hl_by_id: omit hl instead of returning -1 #11685 Problem: When Normal highlight group defines ctermfg/bg, but other highlight group lacks ctermfg/bg, nvim_get_hl_by_id(hl_id, v:false) returns -1 for the missing ctermfg/bg instead of just omitting it. Solution: checking for -1 in hlattrs2dict() fix #11680 --- test/functional/api/highlight_spec.lua | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'test') diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua index b6514a105c..a9d4c72d31 100644 --- a/test/functional/api/highlight_spec.lua +++ b/test/functional/api/highlight_spec.lua @@ -70,6 +70,22 @@ describe('API: highlight',function() eq(false, err) eq('Invalid highlight id: -1', string.match(emsg, 'Invalid.*')) + + -- Test highlight group without ctermbg value. + command('hi Normal ctermfg=red ctermbg=yellow') + command('hi NewConstant ctermfg=green guifg=white guibg=blue') + hl_id = eval("hlID('NewConstant')") + eq({foreground = 10,}, meths.get_hl_by_id(hl_id, false)) + + -- Test highlight group without ctermfg value. + command('hi clear NewConstant') + command('hi NewConstant ctermbg=Magenta guifg=white guibg=blue') + eq({background = 13,}, meths.get_hl_by_id(hl_id, false)) + + -- Test highlight group with ctermfg and ctermbg values. + command('hi clear NewConstant') + command('hi NewConstant ctermfg=green ctermbg=Magenta guifg=white guibg=blue') + eq({foreground = 10, background = 13,}, meths.get_hl_by_id(hl_id, false)) end) it("nvim_get_hl_by_name", function() -- cgit From 844cd9cef12d77fd5d0bb14819dbe201dbf68f0b Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 8 Jan 2020 09:20:53 -0800 Subject: test: just say no to hyper-granularity - Move plugin/lsp/* to plugin/* - Merge lsp/util_spec.lua into lsp_spec.lua --- test/functional/plugin/lsp/lsp_spec.lua | 708 ---------------------------- test/functional/plugin/lsp/util_spec.lua | 76 --- test/functional/plugin/lsp_spec.lua | 776 +++++++++++++++++++++++++++++++ 3 files changed, 776 insertions(+), 784 deletions(-) delete mode 100644 test/functional/plugin/lsp/lsp_spec.lua delete mode 100644 test/functional/plugin/lsp/util_spec.lua create mode 100644 test/functional/plugin/lsp_spec.lua (limited to 'test') diff --git a/test/functional/plugin/lsp/lsp_spec.lua b/test/functional/plugin/lsp/lsp_spec.lua deleted file mode 100644 index e54275e820..0000000000 --- a/test/functional/plugin/lsp/lsp_spec.lua +++ /dev/null @@ -1,708 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) - -local clear = helpers.clear -local exec_lua = helpers.exec_lua -local eq = helpers.eq -local iswin = helpers.iswin -local retry = helpers.retry -local NIL = helpers.NIL - --- Use these to get access to a coroutine so that I can run async tests and use --- yield. -local run, stop = helpers.run, helpers.stop - -if helpers.pending_win32(pending) then return end - -local lsp_test_rpc_server_file = "test/functional/fixtures/lsp-test-rpc-server.lua" -if iswin() then - lsp_test_rpc_server_file = lsp_test_rpc_server_file:gsub("/", "\\") -end - -local function test_rpc_server_setup(test_name, timeout_ms) - exec_lua([=[ - lsp = require('vim.lsp') - local test_name, fixture_filename, timeout = ... - TEST_RPC_CLIENT_ID = lsp.start_client { - cmd = { - vim.api.nvim_get_vvar("progpath"), '-Es', '-u', 'NONE', '--headless', - "-c", string.format("lua TEST_NAME = %q", test_name), - "-c", string.format("lua TIMEOUT = %d", timeout), - "-c", "luafile "..fixture_filename, - }; - callbacks = setmetatable({}, { - __index = function(t, method) - return function(...) - return vim.rpcrequest(1, 'callback', ...) - end - end; - }); - root_dir = vim.loop.cwd(); - on_init = function(client, result) - TEST_RPC_CLIENT = client - vim.rpcrequest(1, "init", result) - end; - on_exit = function(...) - vim.rpcnotify(1, "exit", ...) - end; - } - ]=], test_name, lsp_test_rpc_server_file, timeout_ms or 1e3) -end - -local function test_rpc_server(config) - if config.test_name then - clear() - test_rpc_server_setup(config.test_name, config.timeout_ms or 1e3) - end - local client = setmetatable({}, { - __index = function(_, name) - -- Workaround for not being able to yield() inside __index for Lua 5.1 :( - -- Otherwise I would just return the value here. - return function(...) - return exec_lua([=[ - local name = ... - if type(TEST_RPC_CLIENT[name]) == 'function' then - return TEST_RPC_CLIENT[name](select(2, ...)) - else - return TEST_RPC_CLIENT[name] - end - ]=], name, ...) - end - end; - }) - local code, signal - local function on_request(method, args) - if method == "init" then - if config.on_init then - config.on_init(client, unpack(args)) - end - return NIL - end - if method == 'callback' then - if config.on_callback then - config.on_callback(unpack(args)) - end - end - return NIL - end - local function on_notify(method, args) - if method == 'exit' then - code, signal = unpack(args) - return stop() - end - end - -- TODO specify timeout? - -- run(on_request, on_notify, config.on_setup, 1000) - run(on_request, on_notify, config.on_setup) - if config.on_exit then - config.on_exit(code, signal) - end - stop() - if config.test_name then - exec_lua("lsp._vim_exit_handler()") - end -end - -describe('LSP', function() - describe('server_name specified', function() - before_each(function() - clear() - -- Run an instance of nvim on the file which contains our "scripts". - -- Pass TEST_NAME to pick the script. - local test_name = "basic_init" - exec_lua([=[ - lsp = require('vim.lsp') - local test_name, fixture_filename = ... - function test__start_client() - return lsp.start_client { - cmd = { - vim.api.nvim_get_vvar("progpath"), '-Es', '-u', 'NONE', '--headless', - "-c", string.format("lua TEST_NAME = %q", test_name), - "-c", "luafile "..fixture_filename; - }; - root_dir = vim.loop.cwd(); - } - end - TEST_CLIENT1 = test__start_client() - ]=], test_name, lsp_test_rpc_server_file) - end) - - after_each(function() - exec_lua("lsp._vim_exit_handler()") - -- exec_lua("lsp.stop_all_clients(true)") - end) - - it('start_client(), stop_client()', function() - retry(nil, 4000, function() - eq(1, exec_lua('return #lsp.get_active_clients()')) - end) - eq(2, exec_lua([[ - TEST_CLIENT2 = test__start_client() - return TEST_CLIENT2 - ]])) - eq(3, exec_lua([[ - TEST_CLIENT3 = test__start_client() - return TEST_CLIENT3 - ]])) - retry(nil, 4000, function() - eq(3, exec_lua('return #lsp.get_active_clients()')) - end) - - eq(false, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1) == nil')) - eq(false, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1).is_stopped()')) - exec_lua('return lsp.get_client_by_id(TEST_CLIENT1).stop()') - retry(nil, 4000, function() - eq(2, exec_lua('return #lsp.get_active_clients()')) - end) - eq(true, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1) == nil')) - - exec_lua('lsp.stop_client({TEST_CLIENT2, TEST_CLIENT3})') - retry(nil, 4000, function() - eq(0, exec_lua('return #lsp.get_active_clients()')) - end) - end) - - it('stop_client() also works on client objects', function() - exec_lua([[ - TEST_CLIENT2 = test__start_client() - TEST_CLIENT3 = test__start_client() - ]]) - retry(nil, 4000, function() - eq(3, exec_lua('return #lsp.get_active_clients()')) - end) - -- Stop all clients. - exec_lua('lsp.stop_client(lsp.get_active_clients())') - retry(nil, 4000, function() - eq(0, exec_lua('return #lsp.get_active_clients()')) - end) - end) - end) - - describe('basic_init test', function() - it('should run correctly', function() - local expected_callbacks = { - {NIL, "test", {}, 1}; - } - test_rpc_server { - test_name = "basic_init"; - on_init = function(client, _init_result) - -- client is a dummy object which will queue up commands to be run - -- once the server initializes. It can't accept lua callbacks or - -- other types that may be unserializable for now. - client.stop() - end; - -- If the program timed out, then code will be nil. - on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") - end; - -- Note that NIL must be used here. - -- on_callback(err, method, result, client_id) - on_callback = function(...) - eq(table.remove(expected_callbacks), {...}) - end; - } - end) - - it('should fail', function() - local expected_callbacks = { - {NIL, "test", {}, 1}; - } - test_rpc_server { - test_name = "basic_init"; - on_init = function(client) - client.notify('test') - client.stop() - end; - on_exit = function(code, signal) - eq(1, code, "exit code") eq(0, signal, "exit signal") - end; - on_callback = function(...) - eq(table.remove(expected_callbacks), {...}, "expected callback") - end; - } - end) - - it('should succeed with manual shutdown', function() - local expected_callbacks = { - {NIL, "shutdown", {}, 1}; - {NIL, "test", {}, 1}; - } - test_rpc_server { - test_name = "basic_init"; - on_init = function(client) - eq(0, client.resolved_capabilities().text_document_did_change) - client.request('shutdown') - client.notify('exit') - end; - on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") - end; - on_callback = function(...) - eq(table.remove(expected_callbacks), {...}, "expected callback") - end; - } - end) - - it('should verify capabilities sent', function() - local expected_callbacks = { - {NIL, "shutdown", {}, 1}; - } - test_rpc_server { - test_name = "basic_check_capabilities"; - on_init = function(client) - client.stop() - end; - on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") - end; - on_callback = function(...) - eq(table.remove(expected_callbacks), {...}, "expected callback") - end; - } - end) - - it('should not send didOpen if the buffer closes before init', function() - local expected_callbacks = { - {NIL, "shutdown", {}, 1}; - {NIL, "finish", {}, 1}; - } - local client - test_rpc_server { - test_name = "basic_finish"; - on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; - }) - ]] - eq(1, exec_lua("return TEST_RPC_CLIENT_ID")) - eq(true, exec_lua("return lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)")) - eq(true, exec_lua("return lsp.buf_is_attached(BUFFER, TEST_RPC_CLIENT_ID)")) - exec_lua [[ - vim.api.nvim_command(BUFFER.."bwipeout") - ]] - end; - on_init = function(_client) - client = _client - local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") - eq(full_kind, client.resolved_capabilities().text_document_did_change) - eq(true, client.resolved_capabilities().text_document_open_close) - client.notify('finish') - end; - on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") - end; - on_callback = function(err, method, params, client_id) - eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") - if method == 'finish' then - client.stop() - end - end; - } - end) - - it('should check the body sent attaching before init', function() - local expected_callbacks = { - {NIL, "shutdown", {}, 1}; - {NIL, "finish", {}, 1}; - {NIL, "start", {}, 1}; - } - local client - test_rpc_server { - test_name = "basic_check_buffer_open"; - on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; - }) - ]] - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] - end; - on_init = function(_client) - client = _client - local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") - eq(full_kind, client.resolved_capabilities().text_document_did_change) - eq(true, client.resolved_capabilities().text_document_open_close) - exec_lua [[ - assert(not lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID), "Shouldn't attach twice") - ]] - end; - on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") - end; - on_callback = function(err, method, params, client_id) - if method == 'start' then - client.notify('finish') - end - eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") - if method == 'finish' then - client.stop() - end - end; - } - end) - - it('should check the body sent attaching after init', function() - local expected_callbacks = { - {NIL, "shutdown", {}, 1}; - {NIL, "finish", {}, 1}; - {NIL, "start", {}, 1}; - } - local client - test_rpc_server { - test_name = "basic_check_buffer_open"; - on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; - }) - ]] - end; - on_init = function(_client) - client = _client - local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") - eq(full_kind, client.resolved_capabilities().text_document_did_change) - eq(true, client.resolved_capabilities().text_document_open_close) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] - end; - on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") - end; - on_callback = function(err, method, params, client_id) - if method == 'start' then - client.notify('finish') - end - eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") - if method == 'finish' then - client.stop() - end - end; - } - end) - - it('should check the body and didChange full', function() - local expected_callbacks = { - {NIL, "shutdown", {}, 1}; - {NIL, "finish", {}, 1}; - {NIL, "start", {}, 1}; - } - local client - test_rpc_server { - test_name = "basic_check_buffer_open_and_change"; - on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; - }) - ]] - end; - on_init = function(_client) - client = _client - local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") - eq(full_kind, client.resolved_capabilities().text_document_did_change) - eq(true, client.resolved_capabilities().text_document_open_close) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] - end; - on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") - end; - on_callback = function(err, method, params, client_id) - if method == 'start' then - exec_lua [[ - vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "boop"; - }) - ]] - client.notify('finish') - end - eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") - if method == 'finish' then - client.stop() - end - end; - } - end) - - it('should check the body and didChange full with noeol', function() - local expected_callbacks = { - {NIL, "shutdown", {}, 1}; - {NIL, "finish", {}, 1}; - {NIL, "start", {}, 1}; - } - local client - test_rpc_server { - test_name = "basic_check_buffer_open_and_change_noeol"; - on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; - }) - vim.api.nvim_buf_set_option(BUFFER, 'eol', false) - ]] - end; - on_init = function(_client) - client = _client - local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") - eq(full_kind, client.resolved_capabilities().text_document_did_change) - eq(true, client.resolved_capabilities().text_document_open_close) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] - end; - on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") - end; - on_callback = function(err, method, params, client_id) - if method == 'start' then - exec_lua [[ - vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "boop"; - }) - ]] - client.notify('finish') - end - eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") - if method == 'finish' then - client.stop() - end - end; - } - end) - - -- TODO(askhan) we don't support full for now, so we can disable these tests. - pending('should check the body and didChange incremental', function() - local expected_callbacks = { - {NIL, "shutdown", {}, 1}; - {NIL, "finish", {}, 1}; - {NIL, "start", {}, 1}; - } - local client - test_rpc_server { - test_name = "basic_check_buffer_open_and_change_incremental"; - on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; - }) - ]] - end; - on_init = function(_client) - client = _client - local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental") - eq(sync_kind, client.resolved_capabilities().text_document_did_change) - eq(true, client.resolved_capabilities().text_document_open_close) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] - end; - on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") - end; - on_callback = function(err, method, params, client_id) - if method == 'start' then - exec_lua [[ - vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "boop"; - }) - ]] - client.notify('finish') - end - eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") - if method == 'finish' then - client.stop() - end - end; - } - end) - - -- TODO(askhan) we don't support full for now, so we can disable these tests. - pending('should check the body and didChange incremental normal mode editting', function() - local expected_callbacks = { - {NIL, "shutdown", {}, 1}; - {NIL, "finish", {}, 1}; - {NIL, "start", {}, 1}; - } - local client - test_rpc_server { - test_name = "basic_check_buffer_open_and_change_incremental_editting"; - on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; - }) - ]] - end; - on_init = function(_client) - client = _client - local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental") - eq(sync_kind, client.resolved_capabilities().text_document_did_change) - eq(true, client.resolved_capabilities().text_document_open_close) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] - end; - on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") - end; - on_callback = function(err, method, params, client_id) - if method == 'start' then - helpers.command("normal! 1Go") - client.notify('finish') - end - eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") - if method == 'finish' then - client.stop() - end - end; - } - end) - - it('should check the body and didChange full with 2 changes', function() - local expected_callbacks = { - {NIL, "shutdown", {}, 1}; - {NIL, "finish", {}, 1}; - {NIL, "start", {}, 1}; - } - local client - test_rpc_server { - test_name = "basic_check_buffer_open_and_change_multi"; - on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; - }) - ]] - end; - on_init = function(_client) - client = _client - local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") - eq(sync_kind, client.resolved_capabilities().text_document_did_change) - eq(true, client.resolved_capabilities().text_document_open_close) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] - end; - on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") - end; - on_callback = function(err, method, params, client_id) - if method == 'start' then - exec_lua [[ - vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "321"; - }) - vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "boop"; - }) - ]] - client.notify('finish') - end - eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") - if method == 'finish' then - client.stop() - end - end; - } - end) - - it('should check the body and didChange full lifecycle', function() - local expected_callbacks = { - {NIL, "shutdown", {}, 1}; - {NIL, "finish", {}, 1}; - {NIL, "start", {}, 1}; - } - local client - test_rpc_server { - test_name = "basic_check_buffer_open_and_change_multi_and_close"; - on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; - }) - ]] - end; - on_init = function(_client) - client = _client - local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") - eq(sync_kind, client.resolved_capabilities().text_document_did_change) - eq(true, client.resolved_capabilities().text_document_open_close) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] - end; - on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") - end; - on_callback = function(err, method, params, client_id) - if method == 'start' then - exec_lua [[ - vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "321"; - }) - vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "boop"; - }) - vim.api.nvim_command(BUFFER.."bwipeout") - ]] - client.notify('finish') - end - eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") - if method == 'finish' then - client.stop() - end - end; - } - end) - - end) - - describe("parsing tests", function() - it('should handle invalid content-length correctly', function() - local expected_callbacks = { - {NIL, "shutdown", {}, 1}; - {NIL, "finish", {}, 1}; - {NIL, "start", {}, 1}; - } - local client - test_rpc_server { - test_name = "invalid_header"; - on_setup = function() - end; - on_init = function(_client) - client = _client - client.stop(true) - end; - on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") - end; - on_callback = function(err, method, params, client_id) - eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") - end; - } - end) - - end) -end) diff --git a/test/functional/plugin/lsp/util_spec.lua b/test/functional/plugin/lsp/util_spec.lua deleted file mode 100644 index 1cf0e48be4..0000000000 --- a/test/functional/plugin/lsp/util_spec.lua +++ /dev/null @@ -1,76 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local eq = helpers.eq -local exec_lua = helpers.exec_lua -local dedent = helpers.dedent -local insert = helpers.insert -local clear = helpers.clear - -describe('LSP util', function() - local test_text = dedent([[ - First line of text - Second line of text - Third line of text - Fourth line of text]]) - - local function reset() - clear() - insert(test_text) - end - - before_each(reset) - - local function make_edit(y_0, x_0, y_1, x_1, text) - return { - range = { - start = { line = y_0, character = x_0 }; - ["end"] = { line = y_1, character = x_1 }; - }; - newText = type(text) == 'table' and table.concat(text, '\n') or (text or ""); - } - end - - local function buf_lines(bufnr) - return exec_lua("return vim.api.nvim_buf_get_lines((...), 0, -1, false)", bufnr) - end - - describe('apply_edits', function() - it('should apply simple edits', function() - local edits = { - make_edit(0, 0, 0, 0, {"123"}); - make_edit(1, 0, 1, 1, {"2"}); - make_edit(2, 0, 2, 2, {"3"}); - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) - eq({ - '123First line of text'; - '2econd line of text'; - '3ird line of text'; - 'Fourth line of text'; - }, buf_lines(1)) - end) - - it('should apply complex edits', function() - local edits = { - make_edit(0, 0, 0, 0, {"", "12"}); - make_edit(0, 0, 0, 0, {"3", "foo"}); - make_edit(0, 1, 0, 1, {"bar", "123"}); - make_edit(0, #"First ", 0, #"First line of text", {"guy"}); - make_edit(1, 0, 1, #'Second', {"baz"}); - make_edit(2, #'Th', 2, #"Third", {"e next"}); - make_edit(3, #'', 3, #"Fourth", {"another line of text", "before this"}); - make_edit(3, #'Fourth', 3, #"Fourth line of text", {"!"}); - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) - eq({ - ''; - '123'; - 'fooFbar'; - '123irst guy'; - 'baz line of text'; - 'The next line of text'; - 'another line of text'; - 'before this!'; - }, buf_lines(1)) - end) - end) -end) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua new file mode 100644 index 0000000000..803483c0ef --- /dev/null +++ b/test/functional/plugin/lsp_spec.lua @@ -0,0 +1,776 @@ +local helpers = require('test.functional.helpers')(after_each) + +local clear = helpers.clear +local dedent = helpers.dedent +local exec_lua = helpers.exec_lua +local eq = helpers.eq +local insert = helpers.insert +local iswin = helpers.iswin +local retry = helpers.retry +local NIL = helpers.NIL + +-- Use these to get access to a coroutine so that I can run async tests and use +-- yield. +local run, stop = helpers.run, helpers.stop + +if helpers.pending_win32(pending) then return end + +local lsp_test_rpc_server_file = "test/functional/fixtures/lsp-test-rpc-server.lua" +if iswin() then + lsp_test_rpc_server_file = lsp_test_rpc_server_file:gsub("/", "\\") +end + +local function test_rpc_server_setup(test_name, timeout_ms) + exec_lua([=[ + lsp = require('vim.lsp') + local test_name, fixture_filename, timeout = ... + TEST_RPC_CLIENT_ID = lsp.start_client { + cmd = { + vim.api.nvim_get_vvar("progpath"), '-Es', '-u', 'NONE', '--headless', + "-c", string.format("lua TEST_NAME = %q", test_name), + "-c", string.format("lua TIMEOUT = %d", timeout), + "-c", "luafile "..fixture_filename, + }; + callbacks = setmetatable({}, { + __index = function(t, method) + return function(...) + return vim.rpcrequest(1, 'callback', ...) + end + end; + }); + root_dir = vim.loop.cwd(); + on_init = function(client, result) + TEST_RPC_CLIENT = client + vim.rpcrequest(1, "init", result) + end; + on_exit = function(...) + vim.rpcnotify(1, "exit", ...) + end; + } + ]=], test_name, lsp_test_rpc_server_file, timeout_ms or 1e3) +end + +local function test_rpc_server(config) + if config.test_name then + clear() + test_rpc_server_setup(config.test_name, config.timeout_ms or 1e3) + end + local client = setmetatable({}, { + __index = function(_, name) + -- Workaround for not being able to yield() inside __index for Lua 5.1 :( + -- Otherwise I would just return the value here. + return function(...) + return exec_lua([=[ + local name = ... + if type(TEST_RPC_CLIENT[name]) == 'function' then + return TEST_RPC_CLIENT[name](select(2, ...)) + else + return TEST_RPC_CLIENT[name] + end + ]=], name, ...) + end + end; + }) + local code, signal + local function on_request(method, args) + if method == "init" then + if config.on_init then + config.on_init(client, unpack(args)) + end + return NIL + end + if method == 'callback' then + if config.on_callback then + config.on_callback(unpack(args)) + end + end + return NIL + end + local function on_notify(method, args) + if method == 'exit' then + code, signal = unpack(args) + return stop() + end + end + -- TODO specify timeout? + -- run(on_request, on_notify, config.on_setup, 1000) + run(on_request, on_notify, config.on_setup) + if config.on_exit then + config.on_exit(code, signal) + end + stop() + if config.test_name then + exec_lua("lsp._vim_exit_handler()") + end +end + +describe('LSP', function() + describe('server_name specified', function() + before_each(function() + clear() + -- Run an instance of nvim on the file which contains our "scripts". + -- Pass TEST_NAME to pick the script. + local test_name = "basic_init" + exec_lua([=[ + lsp = require('vim.lsp') + local test_name, fixture_filename = ... + function test__start_client() + return lsp.start_client { + cmd = { + vim.api.nvim_get_vvar("progpath"), '-Es', '-u', 'NONE', '--headless', + "-c", string.format("lua TEST_NAME = %q", test_name), + "-c", "luafile "..fixture_filename; + }; + root_dir = vim.loop.cwd(); + } + end + TEST_CLIENT1 = test__start_client() + ]=], test_name, lsp_test_rpc_server_file) + end) + + after_each(function() + exec_lua("lsp._vim_exit_handler()") + -- exec_lua("lsp.stop_all_clients(true)") + end) + + it('start_client(), stop_client()', function() + retry(nil, 4000, function() + eq(1, exec_lua('return #lsp.get_active_clients()')) + end) + eq(2, exec_lua([[ + TEST_CLIENT2 = test__start_client() + return TEST_CLIENT2 + ]])) + eq(3, exec_lua([[ + TEST_CLIENT3 = test__start_client() + return TEST_CLIENT3 + ]])) + retry(nil, 4000, function() + eq(3, exec_lua('return #lsp.get_active_clients()')) + end) + + eq(false, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1) == nil')) + eq(false, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1).is_stopped()')) + exec_lua('return lsp.get_client_by_id(TEST_CLIENT1).stop()') + retry(nil, 4000, function() + eq(2, exec_lua('return #lsp.get_active_clients()')) + end) + eq(true, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1) == nil')) + + exec_lua('lsp.stop_client({TEST_CLIENT2, TEST_CLIENT3})') + retry(nil, 4000, function() + eq(0, exec_lua('return #lsp.get_active_clients()')) + end) + end) + + it('stop_client() also works on client objects', function() + exec_lua([[ + TEST_CLIENT2 = test__start_client() + TEST_CLIENT3 = test__start_client() + ]]) + retry(nil, 4000, function() + eq(3, exec_lua('return #lsp.get_active_clients()')) + end) + -- Stop all clients. + exec_lua('lsp.stop_client(lsp.get_active_clients())') + retry(nil, 4000, function() + eq(0, exec_lua('return #lsp.get_active_clients()')) + end) + end) + end) + + describe('basic_init test', function() + it('should run correctly', function() + local expected_callbacks = { + {NIL, "test", {}, 1}; + } + test_rpc_server { + test_name = "basic_init"; + on_init = function(client, _init_result) + -- client is a dummy object which will queue up commands to be run + -- once the server initializes. It can't accept lua callbacks or + -- other types that may be unserializable for now. + client.stop() + end; + -- If the program timed out, then code will be nil. + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + -- Note that NIL must be used here. + -- on_callback(err, method, result, client_id) + on_callback = function(...) + eq(table.remove(expected_callbacks), {...}) + end; + } + end) + + it('should fail', function() + local expected_callbacks = { + {NIL, "test", {}, 1}; + } + test_rpc_server { + test_name = "basic_init"; + on_init = function(client) + client.notify('test') + client.stop() + end; + on_exit = function(code, signal) + eq(1, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(...) + eq(table.remove(expected_callbacks), {...}, "expected callback") + end; + } + end) + + it('should succeed with manual shutdown', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "test", {}, 1}; + } + test_rpc_server { + test_name = "basic_init"; + on_init = function(client) + eq(0, client.resolved_capabilities().text_document_did_change) + client.request('shutdown') + client.notify('exit') + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(...) + eq(table.remove(expected_callbacks), {...}, "expected callback") + end; + } + end) + + it('should verify capabilities sent', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + } + test_rpc_server { + test_name = "basic_check_capabilities"; + on_init = function(client) + client.stop() + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(...) + eq(table.remove(expected_callbacks), {...}, "expected callback") + end; + } + end) + + it('should not send didOpen if the buffer closes before init', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_finish"; + on_setup = function() + exec_lua [[ + BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { + "testing"; + "123"; + }) + ]] + eq(1, exec_lua("return TEST_RPC_CLIENT_ID")) + eq(true, exec_lua("return lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)")) + eq(true, exec_lua("return lsp.buf_is_attached(BUFFER, TEST_RPC_CLIENT_ID)")) + exec_lua [[ + vim.api.nvim_command(BUFFER.."bwipeout") + ]] + end; + on_init = function(_client) + client = _client + local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + eq(full_kind, client.resolved_capabilities().text_document_did_change) + eq(true, client.resolved_capabilities().text_document_open_close) + client.notify('finish') + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + it('should check the body sent attaching before init', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open"; + on_setup = function() + exec_lua [[ + BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { + "testing"; + "123"; + }) + ]] + exec_lua [[ + assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) + ]] + end; + on_init = function(_client) + client = _client + local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + eq(full_kind, client.resolved_capabilities().text_document_did_change) + eq(true, client.resolved_capabilities().text_document_open_close) + exec_lua [[ + assert(not lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID), "Shouldn't attach twice") + ]] + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + it('should check the body sent attaching after init', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open"; + on_setup = function() + exec_lua [[ + BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { + "testing"; + "123"; + }) + ]] + end; + on_init = function(_client) + client = _client + local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + eq(full_kind, client.resolved_capabilities().text_document_did_change) + eq(true, client.resolved_capabilities().text_document_open_close) + exec_lua [[ + assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) + ]] + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + it('should check the body and didChange full', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open_and_change"; + on_setup = function() + exec_lua [[ + BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { + "testing"; + "123"; + }) + ]] + end; + on_init = function(_client) + client = _client + local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + eq(full_kind, client.resolved_capabilities().text_document_did_change) + eq(true, client.resolved_capabilities().text_document_open_close) + exec_lua [[ + assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) + ]] + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + exec_lua [[ + vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { + "boop"; + }) + ]] + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + it('should check the body and didChange full with noeol', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open_and_change_noeol"; + on_setup = function() + exec_lua [[ + BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { + "testing"; + "123"; + }) + vim.api.nvim_buf_set_option(BUFFER, 'eol', false) + ]] + end; + on_init = function(_client) + client = _client + local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + eq(full_kind, client.resolved_capabilities().text_document_did_change) + eq(true, client.resolved_capabilities().text_document_open_close) + exec_lua [[ + assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) + ]] + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + exec_lua [[ + vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { + "boop"; + }) + ]] + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + -- TODO(askhan) we don't support full for now, so we can disable these tests. + pending('should check the body and didChange incremental', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open_and_change_incremental"; + on_setup = function() + exec_lua [[ + BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { + "testing"; + "123"; + }) + ]] + end; + on_init = function(_client) + client = _client + local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental") + eq(sync_kind, client.resolved_capabilities().text_document_did_change) + eq(true, client.resolved_capabilities().text_document_open_close) + exec_lua [[ + assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) + ]] + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + exec_lua [[ + vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { + "boop"; + }) + ]] + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + -- TODO(askhan) we don't support full for now, so we can disable these tests. + pending('should check the body and didChange incremental normal mode editting', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open_and_change_incremental_editting"; + on_setup = function() + exec_lua [[ + BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { + "testing"; + "123"; + }) + ]] + end; + on_init = function(_client) + client = _client + local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental") + eq(sync_kind, client.resolved_capabilities().text_document_did_change) + eq(true, client.resolved_capabilities().text_document_open_close) + exec_lua [[ + assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) + ]] + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + helpers.command("normal! 1Go") + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + it('should check the body and didChange full with 2 changes', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open_and_change_multi"; + on_setup = function() + exec_lua [[ + BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { + "testing"; + "123"; + }) + ]] + end; + on_init = function(_client) + client = _client + local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + eq(sync_kind, client.resolved_capabilities().text_document_did_change) + eq(true, client.resolved_capabilities().text_document_open_close) + exec_lua [[ + assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) + ]] + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + exec_lua [[ + vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { + "321"; + }) + vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { + "boop"; + }) + ]] + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + it('should check the body and didChange full lifecycle', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "basic_check_buffer_open_and_change_multi_and_close"; + on_setup = function() + exec_lua [[ + BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { + "testing"; + "123"; + }) + ]] + end; + on_init = function(_client) + client = _client + local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + eq(sync_kind, client.resolved_capabilities().text_document_did_change) + eq(true, client.resolved_capabilities().text_document_open_close) + exec_lua [[ + assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) + ]] + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + if method == 'start' then + exec_lua [[ + vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { + "321"; + }) + vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { + "boop"; + }) + vim.api.nvim_command(BUFFER.."bwipeout") + ]] + client.notify('finish') + end + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'finish' then + client.stop() + end + end; + } + end) + + end) + + describe("parsing tests", function() + it('should handle invalid content-length correctly', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "finish", {}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "invalid_header"; + on_setup = function() + end; + on_init = function(_client) + client = _client + client.stop(true) + end; + on_exit = function(code, signal) + eq(0, code, "exit code") eq(0, signal, "exit signal") + end; + on_callback = function(err, method, params, client_id) + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + end; + } + end) + + end) +end) + +describe('LSP util', function() + before_each(function() + clear() + insert(dedent([[ + First line of text + Second line of text + Third line of text + Fourth line of text]])) + end) + + local function make_edit(y_0, x_0, y_1, x_1, text) + return { + range = { + start = { line = y_0, character = x_0 }; + ["end"] = { line = y_1, character = x_1 }; + }; + newText = type(text) == 'table' and table.concat(text, '\n') or (text or ""); + } + end + + local function buf_lines(bufnr) + return exec_lua("return vim.api.nvim_buf_get_lines((...), 0, -1, false)", bufnr) + end + + describe('apply_edits', function() + it('should apply simple edits', function() + local edits = { + make_edit(0, 0, 0, 0, {"123"}); + make_edit(1, 0, 1, 1, {"2"}); + make_edit(2, 0, 2, 2, {"3"}); + } + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + eq({ + '123First line of text'; + '2econd line of text'; + '3ird line of text'; + 'Fourth line of text'; + }, buf_lines(1)) + end) + + it('should apply complex edits', function() + local edits = { + make_edit(0, 0, 0, 0, {"", "12"}); + make_edit(0, 0, 0, 0, {"3", "foo"}); + make_edit(0, 1, 0, 1, {"bar", "123"}); + make_edit(0, #"First ", 0, #"First line of text", {"guy"}); + make_edit(1, 0, 1, #'Second', {"baz"}); + make_edit(2, #'Th', 2, #"Third", {"e next"}); + make_edit(3, #'', 3, #"Fourth", {"another line of text", "before this"}); + make_edit(3, #'Fourth', 3, #"Fourth line of text", {"!"}); + } + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + eq({ + ''; + '123'; + 'fooFbar'; + '123irst guy'; + 'baz line of text'; + 'The next line of text'; + 'another line of text'; + 'before this!'; + }, buf_lines(1)) + end) + end) +end) -- cgit From 8c8681d594a10c7056d62d09267190b6fab37e85 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 8 Jan 2020 09:32:49 -0800 Subject: test: hoist buf_lines() --- test/functional/helpers.lua | 5 +++++ test/functional/plugin/lsp_spec.lua | 4 ---- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 0fdfcd70ba..e0012c6ced 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -559,6 +559,11 @@ function module.wait() session:request('nvim_eval', '1') end +function module.buf_lines(bufnr) + return module.exec_lua("return vim.api.nvim_buf_get_lines((...), 0, -1, false)", bufnr) +end + +--@see buf_lines() function module.curbuf_contents() module.wait() -- Before inspecting the buffer, process all input. return table.concat(module.curbuf('get_lines', 0, -1, true), '\n') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 803483c0ef..45452c0b20 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -729,10 +729,6 @@ describe('LSP util', function() } end - local function buf_lines(bufnr) - return exec_lua("return vim.api.nvim_buf_get_lines((...), 0, -1, false)", bufnr) - end - describe('apply_edits', function() it('should apply simple edits', function() local edits = { -- cgit From 0a1c6d9a374a0c984515d0af43b1c71af6c55eb2 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 8 Jan 2020 09:46:25 -0800 Subject: LSP: highlight groups test, doc --- test/functional/plugin/lsp_spec.lua | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 45452c0b20..4829a33861 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -1,6 +1,7 @@ local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear +local buf_lines = helpers.buf_lines local dedent = helpers.dedent local exec_lua = helpers.exec_lua local eq = helpers.eq @@ -709,14 +710,9 @@ describe('LSP', function() end) end) -describe('LSP util', function() +describe('LSP', function() before_each(function() clear() - insert(dedent([[ - First line of text - Second line of text - Third line of text - Fourth line of text]])) end) local function make_edit(y_0, x_0, y_1, x_1, text) @@ -729,8 +725,29 @@ describe('LSP util', function() } end + it('highlight groups', function() + eq({'LspDiagnosticsError', + 'LspDiagnosticsHint', + 'LspDiagnosticsInformation', + 'LspDiagnosticsUnderline', + 'LspDiagnosticsUnderlineError', + 'LspDiagnosticsUnderlineHint', + 'LspDiagnosticsUnderlineInformation', + 'LspDiagnosticsUnderlineWarning', + 'LspDiagnosticsWarning', + }, + exec_lua([[require'vim.lsp'; return vim.fn.getcompletion('Lsp', 'highlight')]])) + end) + describe('apply_edits', function() - it('should apply simple edits', function() + before_each(function() + insert(dedent([[ + First line of text + Second line of text + Third line of text + Fourth line of text]])) + end) + it('applies apply simple edits', function() local edits = { make_edit(0, 0, 0, 0, {"123"}); make_edit(1, 0, 1, 1, {"2"}); @@ -744,8 +761,7 @@ describe('LSP util', function() 'Fourth line of text'; }, buf_lines(1)) end) - - it('should apply complex edits', function() + it('applies complex edits', function() local edits = { make_edit(0, 0, 0, 0, {"", "12"}); make_edit(0, 0, 0, 0, {"3", "foo"}); -- cgit From 29b1a4761a9fadfa9de05cfd9c8aad281fc29791 Mon Sep 17 00:00:00 2001 From: butwerenotthereyet <58348703+butwerenotthereyet@users.noreply.github.com> Date: Thu, 9 Jan 2020 07:31:16 -0800 Subject: tabpage: disallow go-to-previous in cmdline-win #11692 After cbc8d72fde4b19176028490934ff7a447afe523c when editing the command in the command editing window (q:, q/, q?) it was possible to switch to the previous tab. Doing so put Nvim in a bad state. Moreover, switching tabs via the other available mechanisms (gt, gT, gt, gT) is not possible when in the command editing window. Here, the behavior is prevented. It is no longer possible to switch to the previous tab when editing the command in the command editing window. The solution is to share code between gt, gT, and g. Specifically, goto_tabpage_lastused now calls through goto_tabpage rather than directly calling goto_tabpage_tp. Doing so works well because all the validation enjoyed by gt and gT is present in goto_tabpage. --- test/functional/autocmd/tabnewentered_spec.lua | 76 +++++++++++++++++++------- 1 file changed, 56 insertions(+), 20 deletions(-) (limited to 'test') diff --git a/test/functional/autocmd/tabnewentered_spec.lua b/test/functional/autocmd/tabnewentered_spec.lua index 6240db2042..949786d8ff 100644 --- a/test/functional/autocmd/tabnewentered_spec.lua +++ b/test/functional/autocmd/tabnewentered_spec.lua @@ -439,32 +439,32 @@ describe('tabpage/previous', function() does_not_switch_to_previous_after_closing_current_tab('')) local function does_not_switch_to_previous_after_entering_operator_pending(characters) - return function() - -- Add three tabs for a total of four - command('tabnew') - command('tabnew') - command('tabnew') + return function() + -- Add three tabs for a total of four + command('tabnew') + command('tabnew') + command('tabnew') - -- The previous tab is now the third. - eq(3, eval('tabpagenr(\'#\')')) + -- The previous tab is now the third. + eq(3, eval('tabpagenr(\'#\')')) - -- Enter operator pending mode. - feed('d') - eq('no', eval('mode(1)')) + -- Enter operator pending mode. + feed('d') + eq('no', eval('mode(1)')) - -- At this point switching to the previous tab should have no effect - -- other than leaving operator pending mode. - feed(characters) + -- At this point switching to the previous tab should have no effect + -- other than leaving operator pending mode. + feed(characters) - -- Attempting to switch tabs returns us to normal mode. - eq('n', eval('mode()')) + -- Attempting to switch tabs returns us to normal mode. + eq('n', eval('mode()')) - -- The current tab is still the fourth. - eq(4, eval('tabpagenr()')) + -- The current tab is still the fourth. + eq(4, eval('tabpagenr()')) - -- The previous tab is still the third. - eq(3, eval('tabpagenr(\'#\')')) - end + -- The previous tab is still the third. + eq(3, eval('tabpagenr(\'#\')')) + end end it('does not switch to previous via g after entering operator pending', does_not_switch_to_previous_after_entering_operator_pending('g')) @@ -480,4 +480,40 @@ describe('tabpage/previous', function() -- does_not_switch_to_previous_after_entering_operator_pending('g')) it('does not switch to previous via after entering operator pending', does_not_switch_to_previous_after_entering_operator_pending('')) + + local function cmdline_win_prevents_tab_switch(characters, completion_visible) + return function() + -- Add three tabs for a total of four + command('tabnew') + command('tabnew') + command('tabnew') + + -- The previous tab is now the third. + eq(3, eval('tabpagenr(\'#\')')) + + -- Edit : command line in command-line window + feed('q:') + + local cmdline_win_id = eval('win_getid()') + + -- At this point switching to the previous tab should have no effect. + feed(characters) + + -- Attempting to switch tabs maintains the current window. + eq(cmdline_win_id, eval('win_getid()')) + eq(completion_visible, eval('complete_info().pum_visible')) + + -- The current tab is still the fourth. + eq(4, eval('tabpagenr()')) + + -- The previous tab is still the third. + eq(3, eval('tabpagenr(\'#\')')) + end + end + it('cmdline-win prevents tab switch via g', + cmdline_win_prevents_tab_switch('g', 0)) + it('cmdline-win prevents tab switch via g', + cmdline_win_prevents_tab_switch('g', 1)) + it('cmdline-win prevents tab switch via ', + cmdline_win_prevents_tab_switch('', 0)) end) -- cgit From dfb676fe0d64c708c0c334b09c947db1bae4736d Mon Sep 17 00:00:00 2001 From: Matthew Malcomson Date: Mon, 13 Jan 2020 01:09:39 +0000 Subject: edit.c: Ensure undo sync when emulating x #11706 After PR #8226 an unmapped META key in insert mode behaves like ESC- (:help i_META). The behaviour does not fully match, since if - is pressed manually then since it were pressed manually `gotchars` would be called on the second after insert-mode had already been left. This would mean that `may_sync_undo` (called from `gotchars`) would call `u_sync(FALSE)` on the second key (since we would be in normal mode). This overall means that behaves differently with respect to undo than [something] when the [something] makes a change. As an example, under `nvim -u NONE`: ihellou leaves the buffer empty, while ihello.u leaves the buffer with one instance of `hello`. - Fix by calling u_sync() manually in the new clause under `normalchar:` in `insert_handle_key`. - Update test in tui_spec.lua that accidentally relied on the old behaviour. --- test/functional/insert/insert_spec.lua | 6 ++++++ test/functional/terminal/tui_spec.lua | 2 ++ 2 files changed, 8 insertions(+) (limited to 'test') diff --git a/test/functional/insert/insert_spec.lua b/test/functional/insert/insert_spec.lua index 427954f5a6..330cfbd830 100644 --- a/test/functional/insert/insert_spec.lua +++ b/test/functional/insert/insert_spec.lua @@ -37,5 +37,11 @@ describe('insert-mode', function() command('iunmap ') feed('0i') eq({ 0, 1, 2, 0, }, funcs.getpos('.')) + -- Unmapped ALT-chord has same `undo` characteristics as ESC+ + command('0,$d') + feed('ahello') + expect('hellohello') + feed('u') + expect('hello') end) end) diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 077e9dc7d5..5d82037f42 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -299,6 +299,8 @@ describe('TUI', function() feed_data('u') expect_child_buf_lines({'"pasted from terminal"'}) feed_data('u') + expect_child_buf_lines({'""'}) + feed_data('u') expect_child_buf_lines({''}) end) -- cgit From 3d1531aee5d92375b69098de8f8c788ea407b066 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Tue, 14 Jan 2020 09:21:10 +0100 Subject: API: include invalid buffer/window/tabpage in error message (#11712) --- test/functional/api/tabpage_spec.lua | 4 ++++ test/functional/api/window_spec.lua | 6 +++--- test/functional/autocmd/autocmd_spec.lua | 4 ++-- test/functional/eval/api_functions_spec.lua | 2 +- test/functional/lua/api_spec.lua | 2 +- test/functional/lua/commands_spec.lua | 2 +- 6 files changed, 12 insertions(+), 8 deletions(-) (limited to 'test') diff --git a/test/functional/api/tabpage_spec.lua b/test/functional/api/tabpage_spec.lua index ed7ce72597..20b3163d95 100644 --- a/test/functional/api/tabpage_spec.lua +++ b/test/functional/api/tabpage_spec.lua @@ -24,6 +24,10 @@ describe('api/tabpage', function() nvim('set_current_win', win3) eq(win3, tabpage('get_win', tab2)) end) + + it('validates args', function() + eq('Invalid tabpage id: 23', pcall_err(tabpage, 'list_wins', 23)) + end) end) describe('{get,set,del}_var', function() diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 17e0d3235c..8c7c3208c0 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -55,8 +55,8 @@ describe('API/win', function() end) it('validates args', function() - eq('Invalid buffer id', pcall_err(window, 'set_buf', nvim('get_current_win'), 23)) - eq('Invalid window id', pcall_err(window, 'set_buf', 23, nvim('get_current_buf'))) + eq('Invalid buffer id: 23', pcall_err(window, 'set_buf', nvim('get_current_win'), 23)) + eq('Invalid window id: 23', pcall_err(window, 'set_buf', 23, nvim('get_current_buf'))) end) end) @@ -73,7 +73,7 @@ describe('API/win', function() it('does not leak memory when using invalid window ID with invalid pos', function() - eq('Invalid window id', pcall_err(meths.win_set_cursor, 1, {"b\na"})) + eq('Invalid window id: 1', pcall_err(meths.win_set_cursor, 1, {"b\na"})) end) it('updates the screen, and also when the window is unfocused', function() diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua index 805db9dd78..43534c9e7e 100644 --- a/test/functional/autocmd/autocmd_spec.lua +++ b/test/functional/autocmd/autocmd_spec.lua @@ -219,7 +219,7 @@ describe('autocmd', function() eq(7, eval('g:test')) -- API calls are blocked when aucmd_win is not in scope - eq('Vim(call):E5555: API call: Invalid window id', + eq('Vim(call):E5555: API call: Invalid window id: 1001', pcall_err(command, "call nvim_set_current_win(g:winid)")) -- second time aucmd_win is needed, a different code path is invoked @@ -257,7 +257,7 @@ describe('autocmd', function() eq(0, eval('g:had_value')) eq(7, eval('g:test')) - eq('Vim(call):E5555: API call: Invalid window id', + eq('Vim(call):E5555: API call: Invalid window id: 1001', pcall_err(command, "call nvim_set_current_win(g:winid)")) end) diff --git a/test/functional/eval/api_functions_spec.lua b/test/functional/eval/api_functions_spec.lua index f527aff33f..ccd97fc8c7 100644 --- a/test/functional/eval/api_functions_spec.lua +++ b/test/functional/eval/api_functions_spec.lua @@ -44,7 +44,7 @@ describe('eval-API', function() eq('Vim(call):E5555: API call: Wrong type for argument 1, expecting Buffer', err) err = exc_exec('call nvim_buf_line_count(17)') - eq('Vim(call):E5555: API call: Invalid buffer id', err) + eq('Vim(call):E5555: API call: Invalid buffer id: 17', err) end) diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua index 23167d3ed9..896554f7a3 100644 --- a/test/functional/lua/api_spec.lua +++ b/test/functional/lua/api_spec.lua @@ -39,7 +39,7 @@ describe('luaeval(vim.api.…)', function() eq({false, 'Argument "pos" must be a [row, col] array'}, funcs.luaeval('{pcall(vim.api.nvim_win_set_cursor, 0, {1, 2, 3})}')) -- Used to produce a memory leak due to a bug in nvim_win_set_cursor - eq({false, 'Invalid window id'}, + eq({false, 'Invalid window id: -1'}, funcs.luaeval('{pcall(vim.api.nvim_win_set_cursor, -1, {1, 2, 3})}')) end) diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index 96eaa7991b..cbc3aee557 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -47,7 +47,7 @@ describe(':lua command', function() pcall_err(command, 'lua ()')) eq([[Vim(lua):E5108: Error executing lua [string ":lua"]:1: TEST]], exc_exec('lua error("TEST")')) - eq([[Vim(lua):E5108: Error executing lua [string ":lua"]:1: Invalid buffer id]], + eq([[Vim(lua):E5108: Error executing lua [string ":lua"]:1: Invalid buffer id: -10]], exc_exec('lua vim.api.nvim_buf_set_lines(-10, 1, 1, false, {"TEST"})')) eq({''}, curbufmeths.get_lines(0, 100, false)) end) -- cgit From 55677ddc4637664c8ef034e5c91f79fae8a97396 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Fri, 15 Nov 2019 18:21:45 +0100 Subject: Add new marktree data structure for storing marks This is inspired by Atom's "marker index" data structure to efficiently adjust marks to text insertions deletions, but uses a wide B-tree (derived from kbtree) to keep the nesting level down. --- test/unit/marktree_spec.lua | 190 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 test/unit/marktree_spec.lua (limited to 'test') diff --git a/test/unit/marktree_spec.lua b/test/unit/marktree_spec.lua new file mode 100644 index 0000000000..56acc0f93e --- /dev/null +++ b/test/unit/marktree_spec.lua @@ -0,0 +1,190 @@ +local helpers = require("test.unit.helpers")(after_each) +local itp = helpers.gen_itp(it) + +local ffi = helpers.ffi +local eq = helpers.eq +local ok = helpers.ok + +local lib = helpers.cimport("./src/nvim/marktree.h") + +local function tablelength(t) + local count = 0 + for _ in pairs(t) do count = count + 1 end + return count +end + +local function pos_leq(a, b) + return a[1] < b[1] or (a[1] == b[1] and a[2] <= b[2]) +end + +-- Checks that shadow and tree is consistent, and optionally +-- return the order +local function shadoworder(tree, shadow, iter, giveorder) + ok(iter ~= nil) + local status = lib.marktree_itr_first(tree, iter) + local count = 0 + local pos2id, id2pos = {}, {} + local last + if not status and next(shadow) == nil then + return pos2id, id2pos + end + repeat + local mark = lib.marktree_itr_current(iter) + local id = tonumber(mark.id) + local spos = shadow[id] + if (mark.row ~= spos[1] or mark.col ~= spos[2]) then + error("invalid pos for "..id..":("..mark.row..", "..mark.col..") instead of ("..spos[1]..", "..spos[2]..")") + end + if mark.right_gravity ~= spos[3] then + error("invalid gravity for "..id..":("..mark.row..", "..mark.col..")") + end + if count > 0 then + if not pos_leq(last, spos) then + error("DISORDER") + end + end + count = count + 1 + last = spos + if giveorder then + pos2id[count] = id + id2pos[id] = count + end + until not lib.marktree_itr_next(tree, iter) + local shadowlen = tablelength(shadow) + if shadowlen ~= count then + error("missed some keys? (shadow "..shadowlen..", tree "..count..")") + end + return id2pos, pos2id +end + +local function shadowsplice(shadow, start, old_extent, new_extent) + local old_end = {start[1] + old_extent[1], + (old_extent[1] == 0 and start[2] or 0) + old_extent[2]} + local new_end = {start[1] + new_extent[1], + (new_extent[1] == 0 and start[2] or 0) + new_extent[2]} + local delta = {new_end[1] - old_end[1], new_end[2] - old_end[2]} + for _, pos in pairs(shadow) do + if pos_leq(start, pos) then + if pos_leq(pos, old_end) then + -- delete region + if pos[3] then -- right gravity + pos[1], pos[2] = new_end[1], new_end[2] + else + pos[1], pos[2] = start[1], start[2] + end + else + if pos[1] == old_end[1] then + pos[2] = pos[2] + delta[2] + end + pos[1] = pos[1] + delta[1] + end + end + end +end + +local function dosplice(tree, shadow, start, old_extent, new_extent) + lib.marktree_splice(tree, start[1], start[2], old_extent[1], old_extent[2], new_extent[1], new_extent[2]) + shadowsplice(shadow, start, old_extent, new_extent) +end + +describe('marktree', function() + itp('works', function() + local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit + local shadow = {} + local iter = ffi.new("MarkTreeIter[1]") + local iter2 = ffi.new("MarkTreeIter[1]") + + for i = 1,100 do + for j = 1,100 do + local gravitate = (i%2) > 0 + local id = tonumber(lib.marktree_put(tree, j, i, gravitate)) + ok(id > 0) + eq(nil, shadow[id]) + shadow[id] = {j,i,gravitate} + end + -- checking every insert is too slow, but this is ok + lib.marktree_check(tree) + end + + -- ss = lib.mt_inspect_rec(tree) + -- io.stdout:write(ffi.string(ss)) + -- io.stdout:flush() + + local id2pos, pos2id = shadoworder(tree, shadow, iter) + eq({}, pos2id) -- not set if not requested + eq({}, id2pos) + + for i,ipos in pairs(shadow) do + local pos = lib.marktree_lookup(tree, i, iter) + eq(ipos[1], pos.row) + eq(ipos[2], pos.col) + local k = lib.marktree_itr_current(iter) + eq(ipos[1], k.row) + eq(ipos[2], k.col, ipos[1]) + lib.marktree_itr_next(tree, iter) + -- TODO(bfredl): use id2pos to check neighbour? + -- local k2 = lib.marktree_itr_current(iter) + end + + for i,ipos in pairs(shadow) do + lib.marktree_itr_get(tree, ipos[1], ipos[2], iter) + local k = lib.marktree_itr_current(iter) + eq(i, tonumber(k.id)) + eq(ipos[1], k.row) + eq(ipos[2], k.col) + end + + ok(lib.marktree_itr_first(tree, iter)) + local del = lib.marktree_itr_current(iter) + + lib.marktree_del_itr(tree, iter, false) + shadow[tonumber(del.id)] = nil + shadoworder(tree, shadow, iter) + + for _, ci in ipairs({0,-1,1,-2,2,-10,10}) do + for i = 1,100 do + lib.marktree_itr_get(tree, i, 50+ci, iter) + local k = lib.marktree_itr_current(iter) + local id = tonumber(k.id) + eq(shadow[id][1], k.row) + eq(shadow[id][2], k.col) + lib.marktree_del_itr(tree, iter, false) + shadow[id] = nil + end + lib.marktree_check(tree) + shadoworder(tree, shadow, iter) + end + + -- NB: this is quite rudimentary. We rely on + -- functional tests exercising splicing quite a bit + lib.marktree_check(tree) + dosplice(tree, shadow, {2,2}, {0,5}, {1, 2}) + lib.marktree_check(tree) + shadoworder(tree, shadow, iter) + dosplice(tree, shadow, {30,2}, {30,5}, {1, 2}) + lib.marktree_check(tree) + shadoworder(tree, shadow, iter) + + dosplice(tree, shadow, {5,3}, {0,2}, {0, 5}) + shadoworder(tree, shadow, iter) + lib.marktree_check(tree) + + -- build then burn (HOORAY! HOORAY!) + while next(shadow) do + lib.marktree_itr_first(tree, iter) + -- delete every other key for fun and profit + while true do + local k = lib.marktree_itr_current(iter) + lib.marktree_del_itr(tree, iter, false) + ok(shadow[tonumber(k.id)] ~= nil) + shadow[tonumber(k.id)] = nil + local stat = lib.marktree_itr_next(tree, iter) + if not stat then + break + end + end + lib.marktree_check(tree) + shadoworder(tree, shadow, iter2) + end + end) +end) -- cgit From ca1a00edd6d6345b848a28d077d6a192528f811e Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Tue, 14 Jan 2020 12:45:09 +0100 Subject: extmarks/bufhl: reimplement using new marktree data structure Add new "splice" interface for tracking buffer changes at the byte level. This will later be reused for byte-resolution buffer updates. (Implementation has been started, but using undocumented "_on_bytes" option now as interface hasn't been finalized). Use this interface to improve many edge cases of extmark adjustment. Changed tests indicate previously incorrect behavior. Adding tests for more edge cases will be follow-up work (overlaps on_bytes tests) Don't consider creation/deletion of marks an undoable event by itself. This behavior was never documented, and imposes complexity for little gain. Add nvim__buf_add_decoration temporary API for direct access to the new implementation. This should be refactored into a proper API for decorations, probably involving a huge dict. fixes #11598 --- test/functional/api/mark_extended_spec.lua | 309 +++++++++++++++++++---------- test/functional/ui/bufhl_spec.lua | 198 +++++++++++++++--- 2 files changed, 373 insertions(+), 134 deletions(-) (limited to 'test') diff --git a/test/functional/api/mark_extended_spec.lua b/test/functional/api/mark_extended_spec.lua index bf910568b1..8aa8ed07c5 100644 --- a/test/functional/api/mark_extended_spec.lua +++ b/test/functional/api/mark_extended_spec.lua @@ -11,6 +11,11 @@ local insert = helpers.insert local feed = helpers.feed local clear = helpers.clear local command = helpers.command +local meths = helpers.meths + +local function expect(contents) + return eq(contents, helpers.curbuf_contents()) +end local function check_undo_redo(ns, mark, sr, sc, er, ec) --s = start, e = end local rv = curbufmeths.get_extmark_by_id(ns, mark) @@ -37,9 +42,36 @@ local function get_extmarks(ns_id, start, end_, opts) return curbufmeths.get_extmarks(ns_id, start, end_, opts) end +local function batch_set(ns_id, positions) + local ids = {} + for _, pos in ipairs(positions) do + table.insert(ids, set_extmark(ns_id, 0, pos[1], pos[2])) + end + return ids +end + +local function batch_check(ns_id, ids, positions) + local actual, expected = {}, {} + for i,id in ipairs(ids) do + expected[id] = positions[i] + end + for _, mark in pairs(get_extmarks(ns_id, 0, -1, {})) do + actual[mark[1]] = {mark[2], mark[3]} + end + eq(expected, actual) +end + +local function batch_check_undo_redo(ns_id, ids, before, after) + batch_check(ns_id, ids, after) + feed("u") + batch_check(ns_id, ids, before) + feed("") + batch_check(ns_id, ids, after) +end + describe('API/extmarks', function() local screen - local marks, positions, ns_string2, ns_string, init_text, row, col + local marks, positions, init_text, row, col local ns, ns2 before_each(function() @@ -47,22 +79,18 @@ describe('API/extmarks', function() marks = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} positions = {{0, 0,}, {0, 2}, {0, 3}} - ns_string = "my-fancy-plugin" - ns_string2 = "my-fancy-plugin2" init_text = "12345" row = 0 col = 2 clear() - screen = Screen.new(15, 10) - screen:attach() insert(init_text) - ns = request('nvim_create_namespace', ns_string) - ns2 = request('nvim_create_namespace', ns_string2) + ns = request('nvim_create_namespace', "my-fancy-plugin") + ns2 = request('nvim_create_namespace', "my-fancy-plugin2") end) - it('adds, updates and deletes marks #extmarks', function() + it('adds, updates and deletes marks', function() local rv = set_extmark(ns, marks[1], positions[1][1], positions[1][2]) eq(marks[1], rv) rv = curbufmeths.get_extmark_by_id(ns, marks[1]) @@ -92,7 +120,7 @@ describe('API/extmarks', function() eq(false, curbufmeths.del_extmark(ns, 1000)) end) - it('can clear a specific namespace range #extmarks', function() + it('can clear a specific namespace range', function() set_extmark(ns, 1, 0, 1) set_extmark(ns2, 1, 0, 1) -- force a new undo buffer @@ -102,13 +130,13 @@ describe('API/extmarks', function() eq({}, get_extmarks(ns2, {0, 0}, {-1, -1})) feed('u') eq({{1, 0, 1}}, get_extmarks(ns, {0, 0}, {-1, -1})) - eq({{1, 0, 1}}, get_extmarks(ns2, {0, 0}, {-1, -1})) + eq({}, get_extmarks(ns2, {0, 0}, {-1, -1})) feed('') eq({{1, 0, 1}}, get_extmarks(ns, {0, 0}, {-1, -1})) eq({}, get_extmarks(ns2, {0, 0}, {-1, -1})) end) - it('can clear a namespace range using 0,-1 #extmarks', function() + it('can clear a namespace range using 0,-1', function() set_extmark(ns, 1, 0, 1) set_extmark(ns2, 1, 0, 1) -- force a new undo buffer @@ -117,14 +145,16 @@ describe('API/extmarks', function() eq({}, get_extmarks(ns, {0, 0}, {-1, -1})) eq({}, get_extmarks(ns2, {0, 0}, {-1, -1})) feed('u') - eq({{1, 0, 1}}, get_extmarks(ns, {0, 0}, {-1, -1})) - eq({{1, 0, 1}}, get_extmarks(ns2, {0, 0}, {-1, -1})) + eq({}, get_extmarks(ns, {0, 0}, {-1, -1})) + eq({}, get_extmarks(ns2, {0, 0}, {-1, -1})) feed('') eq({}, get_extmarks(ns, {0, 0}, {-1, -1})) eq({}, get_extmarks(ns2, {0, 0}, {-1, -1})) end) - it('querying for information and ranges #extmarks', function() + it('querying for information and ranges', function() + --marks = {1, 2, 3} + --positions = {{0, 0,}, {0, 2}, {0, 3}} -- add some more marks for i, m in ipairs(marks) do if positions[i] ~= nil then @@ -242,7 +272,7 @@ describe('API/extmarks', function() eq({{marks[1], positions[1][1], positions[1][2]}}, rv) end) - it('querying for information with limit #extmarks', function() + it('querying for information with limit', function() -- add some more marks for i, m in ipairs(marks) do if positions[i] ~= nil then @@ -267,7 +297,7 @@ describe('API/extmarks', function() eq(3, table.getn(rv)) end) - it('get_marks works when mark col > upper col #extmarks', function() + it('get_marks works when mark col > upper col', function() feed('A12345') feed('A12345') set_extmark(ns, 10, 0, 2) -- this shouldn't be found @@ -281,7 +311,7 @@ describe('API/extmarks', function() get_extmarks(ns, {0, 3}, {2, 0})) end) - it('get_marks works in reverse when mark col < lower col #extmarks', function() + it('get_marks works in reverse when mark col < lower col', function() feed('A12345') feed('A12345') set_extmark(ns, 10, 0, 1) -- this shouldn't be found @@ -296,27 +326,27 @@ describe('API/extmarks', function() rv) end) - it('get_marks limit=0 returns nothing #extmarks', function() + it('get_marks limit=0 returns nothing', function() set_extmark(ns, marks[1], positions[1][1], positions[1][2]) local rv = get_extmarks(ns, {-1, -1}, {-1, -1}, {limit=0}) eq({}, rv) end) - it('marks move with line insertations #extmarks', function() + it('marks move with line insertations', function() set_extmark(ns, marks[1], 0, 0) feed("yyP") check_undo_redo(ns, marks[1], 0, 0, 1, 0) end) - it('marks move with multiline insertations #extmarks', function() + it('marks move with multiline insertations', function() feed("a2233") set_extmark(ns, marks[1], 1, 1) feed('ggVGyP') check_undo_redo(ns, marks[1], 1, 1, 4, 1) end) - it('marks move with line join #extmarks', function() + it('marks move with line join', function() -- do_join in ops.c feed("a222") set_extmark(ns, marks[1], 1, 0) @@ -324,7 +354,9 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[1], 1, 0, 0, 6) end) - it('join works when no marks are present #extmarks', function() + it('join works when no marks are present', function() + screen = Screen.new(15, 10) + screen:attach() feed("a1") feed('kJ') -- This shouldn't seg fault @@ -342,7 +374,7 @@ describe('API/extmarks', function() ]]) end) - it('marks move with multiline join #extmarks', function() + it('marks move with multiline join', function() -- do_join in ops.c feed("a222333444") set_extmark(ns, marks[1], 3, 0) @@ -350,14 +382,14 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[1], 3, 0, 1, 8) end) - it('marks move with line deletes #extmarks', function() + it('marks move with line deletes', function() feed("a222333444") set_extmark(ns, marks[1], 2, 1) feed('ggjdd') check_undo_redo(ns, marks[1], 2, 1, 1, 1) end) - it('marks move with multiline deletes #extmarks', function() + it('marks move with multiline deletes', function() feed("a222333444") set_extmark(ns, marks[1], 3, 0) feed('gg2dd') @@ -367,7 +399,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[1], 3, 0, 0, 0) end) - it('marks move with open line #extmarks', function() + it('marks move with open line', function() -- open_line in misc1.c -- testing marks below are also moved feed("yyP") @@ -381,8 +413,10 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[2], 2, 4, 3, 4) end) - it('marks move with char inserts #extmarks', function() + it('marks move with char inserts', function() -- insertchar in edit.c (the ins_str branch) + screen = Screen.new(15, 10) + screen:attach() set_extmark(ns, marks[1], 0, 3) feed('0') insert('abc') @@ -400,11 +434,11 @@ describe('API/extmarks', function() ]]) local rv = curbufmeths.get_extmark_by_id(ns, marks[1]) eq({0, 6}, rv) - -- check_undo_redo(ns, marks[1], 0, 2, 0, 5) + check_undo_redo(ns, marks[1], 0, 3, 0, 6) end) -- gravity right as definted in tk library - it('marks have gravity right #extmarks', function() + it('marks have gravity right', function() -- insertchar in edit.c (the ins_str branch) set_extmark(ns, marks[1], 0, 2) feed('03l') @@ -417,7 +451,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[1], 0, 2, 0, 2) end) - it('we can insert multibyte chars #extmarks', function() + it('we can insert multibyte chars', function() -- insertchar in edit.c feed('a12345') set_extmark(ns, marks[1], 1, 2) @@ -426,7 +460,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[1], 1, 2, 1, 5) end) - it('marks move with blockwise inserts #extmarks', function() + it('marks move with blockwise inserts', function() -- op_insert in ops.c feed('a12345') set_extmark(ns, marks[1], 1, 2) @@ -434,7 +468,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[1], 1, 2, 1, 3) end) - it('marks move with line splits (using enter) #extmarks', function() + it('marks move with line splits (using enter)', function() -- open_line in misc1.c -- testing marks below are also moved feed("yyP") @@ -445,14 +479,14 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[2], 1, 4, 2, 4) end) - it('marks at last line move on insert new line #extmarks', function() + it('marks at last line move on insert new line', function() -- open_line in misc1.c set_extmark(ns, marks[1], 0, 4) feed('0i') check_undo_redo(ns, marks[1], 0, 4, 1, 4) end) - it('yet again marks move with line splits #extmarks', function() + it('yet again marks move with line splits', function() -- the first test above wasn't catching all errors.. feed("A67890") set_extmark(ns, marks[1], 0, 4) @@ -460,7 +494,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[1], 0, 4, 1, 0) end) - it('and one last time line splits... #extmarks', function() + it('and one last time line splits...', function() set_extmark(ns, marks[1], 0, 1) set_extmark(ns, marks[2], 0, 2) feed("02li") @@ -468,7 +502,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[2], 0, 2, 1, 0) end) - it('multiple marks move with mark splits #extmarks', function() + it('multiple marks move with mark splits', function() set_extmark(ns, marks[1], 0, 1) set_extmark(ns, marks[2], 0, 3) feed("0li") @@ -476,21 +510,21 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[2], 0, 3, 1, 2) end) - it('deleting right before a mark works #extmarks', function() + it('deleting right before a mark works', function() -- op_delete in ops.c set_extmark(ns, marks[1], 0, 2) feed('0lx') check_undo_redo(ns, marks[1], 0, 2, 0, 1) end) - it('deleting on a mark works #extmarks', function() + it('deleting right after a mark works', function() -- op_delete in ops.c set_extmark(ns, marks[1], 0, 2) feed('02lx') check_undo_redo(ns, marks[1], 0, 2, 0, 2) end) - it('marks move with char deletes #extmarks', function() + it('marks move with char deletes', function() -- op_delete in ops.c set_extmark(ns, marks[1], 0, 2) feed('02dl') @@ -500,7 +534,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[1], 0, 0, 0, 0) end) - it('marks move with char deletes over a range #extmarks', function() + it('marks move with char deletes over a range', function() -- op_delete in ops.c set_extmark(ns, marks[1], 0, 2) set_extmark(ns, marks[2], 0, 3) @@ -513,7 +547,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[2], 0, 3, 0, 3) end) - it('deleting marks at end of line works #extmarks', function() + it('deleting marks at end of line works', function() -- mark_extended.c/extmark_col_adjust_delete set_extmark(ns, marks[1], 0, 4) feed('$x') @@ -525,7 +559,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[1], 0, 4, 0, 4) end) - it('marks move with blockwise deletes #extmarks', function() + it('marks move with blockwise deletes', function() -- op_delete in ops.c feed('a12345') set_extmark(ns, marks[1], 1, 4) @@ -533,7 +567,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[1], 1, 4, 1, 1) end) - it('marks move with blockwise deletes over a range #extmarks', function() + it('marks move with blockwise deletes over a range', function() -- op_delete in ops.c feed('a12345') set_extmark(ns, marks[1], 0, 1) @@ -550,7 +584,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[3], 1, 2, 1, 2) end) - it('works with char deletes over multilines #extmarks', function() + it('works with char deletes over multilines', function() feed('a12345test-me') set_extmark(ns, marks[1], 2, 5) feed('gg') @@ -558,7 +592,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[1], 2, 5, 0, 0) end) - it('marks outside of deleted range move with visual char deletes #extmarks', function() + it('marks outside of deleted range move with visual char deletes', function() -- op_delete in ops.c set_extmark(ns, marks[1], 0, 3) feed('0vx') @@ -577,7 +611,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[1], 0, 0, 0, 0) end) - it('marks outside of deleted range move with char deletes #extmarks', function() + it('marks outside of deleted range move with char deletes', function() -- op_delete in ops.c set_extmark(ns, marks[1], 0, 3) feed('0x') @@ -597,7 +631,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[1], 0, 3, 0, 3) end) - it('marks move with P(backward) paste #extmarks', function() + it('marks move with P(backward) paste', function() -- do_put in ops.c feed('0iabc') set_extmark(ns, marks[1], 0, 7) @@ -605,15 +639,15 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[1], 0, 7, 0, 15) end) - it('marks move with p(forward) paste #extmarks', function() + it('marks move with p(forward) paste', function() -- do_put in ops.c feed('0iabc') set_extmark(ns, marks[1], 0, 7) feed('0veyp') - check_undo_redo(ns, marks[1], 0, 7, 0, 14) + check_undo_redo(ns, marks[1], 0, 7, 0, 15) end) - it('marks move with blockwise P(backward) paste #extmarks', function() + it('marks move with blockwise P(backward) paste', function() -- do_put in ops.c feed('a12345') set_extmark(ns, marks[1], 1, 4) @@ -621,42 +655,84 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[1], 1, 4, 1, 7) end) - it('marks move with blockwise p(forward) paste #extmarks', function() + it('marks move with blockwise p(forward) paste', function() -- do_put in ops.c feed('a12345') set_extmark(ns, marks[1], 1, 4) feed('hhkyp') - check_undo_redo(ns, marks[1], 1, 4, 1, 6) + check_undo_redo(ns, marks[1], 1, 4, 1, 7) end) - it('replace works #extmarks', function() + describe('multiline regions', function() + before_each(function() + feed('dd') + -- Achtung: code has been spiced with some unicode, + -- to make life more interesting. + -- luacheck whines about TABs inside strings for whatever reason. + -- luacheck: push ignore 621 + insert([[ + static int nlua_rpcrequest(lua_State *lstate) + { + Ïf (!nlua_is_deferred_safe(lstate)) { + // strictly not allowed + Яetörn luaL_error(lstate, e_luv_api_disabled, "rpcrequest"); + } + return nlua_rpc(lstate, true); + }]]) + -- luacheck: pop + end) + + it('delete', function() + local pos1 = { + {2, 4}, {2, 12}, {2, 13}, {2, 14}, {2, 25}, + {4, 8}, {4, 10}, {4, 20}, + {5, 3}, {6, 10} + } + local ids = batch_set(ns, pos1) + batch_check(ns, ids, pos1) + feed('3Gfiv2+ftd') + batch_check_undo_redo(ns, ids, pos1, { + {2, 4}, {2, 12}, {2, 13}, {2, 13}, {2, 13}, + {2, 13}, {2, 15}, {2, 25}, + {3, 3}, {4, 10} + }) + end) + + -- TODO(bfredl): add more tests! + end) + + it('replace works', function() set_extmark(ns, marks[1], 0, 2) feed('0r2') check_undo_redo(ns, marks[1], 0, 2, 0, 2) end) - it('blockwise replace works #extmarks', function() + it('blockwise replace works', function() feed('a12345') set_extmark(ns, marks[1], 0, 2) feed('0llkr1') - check_undo_redo(ns, marks[1], 0, 2, 0, 2) + check_undo_redo(ns, marks[1], 0, 2, 0, 3) end) - it('shift line #extmarks', function() + it('shift line', function() -- shift_line in ops.c feed(':set shiftwidth=4') set_extmark(ns, marks[1], 0, 2) feed('0>>') check_undo_redo(ns, marks[1], 0, 2, 0, 6) + expect(' 12345') feed('>>') - check_undo_redo(ns, marks[1], 0, 6, 0, 10) + -- this is counter-intuitive. But what happens + -- is that 4 spaces gets extended to one tab (== 8 spaces) + check_undo_redo(ns, marks[1], 0, 6, 0, 3) + expect('\t12345') feed('') -- have to escape, same as << - check_undo_redo(ns, marks[1], 0, 10, 0, 6) + check_undo_redo(ns, marks[1], 0, 3, 0, 6) end) - it('blockwise shift #extmarks', function() + it('blockwise shift', function() -- shift_block in ops.c feed(':set shiftwidth=4') feed('a12345') @@ -664,13 +740,14 @@ describe('API/extmarks', function() feed('0k>') check_undo_redo(ns, marks[1], 1, 2, 1, 6) feed('j>') - check_undo_redo(ns, marks[1], 1, 6, 1, 10) + expect('\t12345\n\t12345') + check_undo_redo(ns, marks[1], 1, 6, 1, 3) feed('j') - check_undo_redo(ns, marks[1], 1, 10, 1, 6) + check_undo_redo(ns, marks[1], 1, 3, 1, 6) end) - it('tab works with expandtab #extmarks', function() + it('tab works with expandtab', function() -- ins_tab in edit.c feed(':set expandtab') feed(':set shiftwidth=2') @@ -679,7 +756,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[1], 0, 2, 0, 6) end) - it('tabs work #extmarks', function() + it('tabs work', function() -- ins_tab in edit.c feed(':set noexpandtab') feed(':set shiftwidth=2') @@ -692,7 +769,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[1], 0, 4, 0, 6) end) - it('marks move when using :move #extmarks', function() + it('marks move when using :move', function() set_extmark(ns, marks[1], 0, 0) feed('A2:1move 2') check_undo_redo(ns, marks[1], 0, 0, 1, 0) @@ -701,7 +778,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[1], 1, 0, 0, 0) end) - it('marks move when using :move part 2 #extmarks', function() + it('marks move when using :move part 2', function() -- make sure we didn't get lucky with the math... feed('A23456') set_extmark(ns, marks[1], 1, 0) @@ -712,7 +789,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[1], 3, 0, 1, 0) end) - it('undo and redo of set and unset marks #extmarks', function() + it('undo and redo of set and unset marks', function() -- Force a new undo head feed('o') set_extmark(ns, marks[1], 0, 1) @@ -722,7 +799,7 @@ describe('API/extmarks', function() feed("u") local rv = get_extmarks(ns, {0, 0}, {-1, -1}) - eq(1, table.getn(rv)) + eq(3, table.getn(rv)) feed("") rv = get_extmarks(ns, {0, 0}, {-1, -1}) @@ -735,20 +812,22 @@ describe('API/extmarks', function() eq(1, table.getn(rv)) feed("u") feed("") - check_undo_redo(ns, marks[1], 0, 1, positions[1][1], positions[1][2]) + -- old value is NOT kept in history + check_undo_redo(ns, marks[1], positions[1][1], positions[1][2], positions[1][1], positions[1][2]) -- Test unset feed('o') curbufmeths.del_extmark(ns, marks[3]) feed("u") rv = get_extmarks(ns, {0, 0}, {-1, -1}) - eq(3, table.getn(rv)) + -- undo does NOT restore deleted marks + eq(2, table.getn(rv)) feed("") rv = get_extmarks(ns, {0, 0}, {-1, -1}) eq(2, table.getn(rv)) end) - it('undo and redo of marks deleted during edits #extmarks', function() + it('undo and redo of marks deleted during edits', function() -- test extmark_adjust feed('A12345') set_extmark(ns, marks[1], 1, 2) @@ -756,7 +835,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[1], 1, 2, 1, 0) end) - it('namespaces work properly #extmarks', function() + it('namespaces work properly', function() local rv = set_extmark(ns, marks[1], positions[1][1], positions[1][2]) eq(1, rv) rv = set_extmark(ns2, marks[1], positions[1][1], positions[1][2]) @@ -802,7 +881,7 @@ describe('API/extmarks', function() eq(2, table.getn(rv)) end) - it('mark set can create unique identifiers #extmarks', function() + it('mark set can create unique identifiers', function() -- create mark with id 1 eq(1, set_extmark(ns, 1, positions[1][1], positions[1][2])) -- ask for unique id, it should be the next one, i e 2 @@ -817,7 +896,7 @@ describe('API/extmarks', function() eq(8, set_extmark(ns, 0, positions[1][1], positions[1][2])) end) - it('auto indenting with enter works #extmarks', function() + it('auto indenting with enter works', function() -- op_reindent in ops.c feed(':set cindent') feed(':set autoindent') @@ -835,7 +914,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[1], 0, 12, 1, 3) end) - it('auto indenting entire line works #extmarks', function() + it('auto indenting entire line works', function() feed(':set cindent') feed(':set autoindent') feed(':set shiftwidth=2') @@ -852,7 +931,7 @@ describe('API/extmarks', function() eq({1, 3}, rv) end) - it('removing auto indenting with works #extmarks', function() + it('removing auto indenting with works', function() feed(':set cindent') feed(':set autoindent') feed(':set shiftwidth=2') @@ -868,7 +947,7 @@ describe('API/extmarks', function() eq({0, 1}, rv) end) - it('indenting multiple lines with = works #extmarks', function() + it('indenting multiple lines with = works', function() feed(':set cindent') feed(':set autoindent') feed(':set shiftwidth=2') @@ -880,7 +959,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[2], 2, 1, 2, 5) end) - it('substitutes by deleting inside the replace matches #extmarks_sub', function() + it('substitutes by deleting inside the replace matches', function() -- do_sub in ex_cmds.c set_extmark(ns, marks[1], 0, 2) set_extmark(ns, marks[2], 0, 3) @@ -889,7 +968,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[2], 0, 3, 0, 4) end) - it('substitutes when insert text > deleted #extmarks_sub', function() + it('substitutes when insert text > deleted', function() -- do_sub in ex_cmds.c set_extmark(ns, marks[1], 0, 2) set_extmark(ns, marks[2], 0, 3) @@ -898,7 +977,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[2], 0, 3, 0, 5) end) - it('substitutes when marks around eol #extmarks_sub', function() + it('substitutes when marks around eol', function() -- do_sub in ex_cmds.c set_extmark(ns, marks[1], 0, 4) set_extmark(ns, marks[2], 0, 5) @@ -907,7 +986,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[2], 0, 5, 0, 7) end) - it('substitutes over range insert text > deleted #extmarks_sub', function() + it('substitutes over range insert text > deleted', function() -- do_sub in ex_cmds.c feed('Ax34xx') feed('Axxx34') @@ -920,7 +999,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[3], 2, 4, 2, 6) end) - it('substitutes multiple matches in a line #extmarks_sub', function() + it('substitutes multiple matches in a line', function() -- do_sub in ex_cmds.c feed('ddi3x3x3') set_extmark(ns, marks[1], 0, 0) @@ -932,7 +1011,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[3], 0, 4, 0, 8) end) - it('substitions over multiple lines with newline in pattern #extmarks_sub', function() + it('substitions over multiple lines with newline in pattern', function() feed('A67890xx') set_extmark(ns, marks[1], 0, 3) set_extmark(ns, marks[2], 0, 4) @@ -947,7 +1026,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[5], 2, 0, 1, 0) end) - it('inserting #extmarks_sub', function() + it('inserting', function() feed('A67890xx') set_extmark(ns, marks[1], 0, 3) set_extmark(ns, marks[2], 0, 4) @@ -964,7 +1043,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[6], 1, 2, 0, 5) end) - it('substitions with multiple newlines in pattern #extmarks_sub', function() + it('substitions with multiple newlines in pattern', function() feed('A67890xx') set_extmark(ns, marks[1], 0, 4) set_extmark(ns, marks[2], 0, 5) @@ -979,7 +1058,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[5], 2, 0, 0, 6) end) - it('substitions over multiple lines with replace in substition #extmarks_sub', function() + it('substitions over multiple lines with replace in substition', function() feed('A67890xx') set_extmark(ns, marks[1], 0, 1) set_extmark(ns, marks[2], 0, 2) @@ -997,7 +1076,7 @@ describe('API/extmarks', function() eq({1, 3}, curbufmeths.get_extmark_by_id(ns, marks[3])) end) - it('substitions over multiple lines with replace in substition #extmarks_sub', function() + it('substitions over multiple lines with replace in substition', function() feed('Ax3xx') set_extmark(ns, marks[1], 1, 0) set_extmark(ns, marks[2], 1, 1) @@ -1008,7 +1087,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[3], 1, 2, 2, 0) end) - it('substitions over multiple lines with replace in substition #extmarks_sub', function() + it('substitions over multiple lines with replace in substition', function() feed('Ax3xx') set_extmark(ns, marks[1], 0, 1) set_extmark(ns, marks[2], 0, 2) @@ -1026,7 +1105,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[3], 0, 4, 1, 3) end) - it('substitions with newline in match and sub, delta is 0 #extmarks_sub', function() + it('substitions with newline in match and sub, delta is 0', function() feed('A67890xx') set_extmark(ns, marks[1], 0, 3) set_extmark(ns, marks[2], 0, 4) @@ -1043,7 +1122,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[6], 2, 0, 2, 0) end) - it('substitions with newline in match and sub, delta > 0 #extmarks_sub', function() + it('substitions with newline in match and sub, delta > 0', function() feed('A67890xx') set_extmark(ns, marks[1], 0, 3) set_extmark(ns, marks[2], 0, 4) @@ -1060,7 +1139,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[6], 2, 0, 3, 0) end) - it('substitions with newline in match and sub, delta < 0 #extmarks_sub', function() + it('substitions with newline in match and sub, delta < 0', function() feed('A67890xxxx') set_extmark(ns, marks[1], 0, 3) set_extmark(ns, marks[2], 0, 4) @@ -1079,7 +1158,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[7], 3, 0, 2, 0) end) - it('substitions with backrefs, newline inserted into sub #extmarks_sub', function() + it('substitions with backrefs, newline inserted into sub', function() feed('A67890xxxx') set_extmark(ns, marks[1], 0, 3) set_extmark(ns, marks[2], 0, 4) @@ -1096,7 +1175,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[6], 2, 0, 3, 0) end) - it('substitions a ^ #extmarks_sub', function() + it('substitions a ^', function() set_extmark(ns, marks[1], 0, 0) set_extmark(ns, marks[2], 0, 1) feed([[:s:^:x]]) @@ -1104,7 +1183,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[2], 0, 1, 0, 2) end) - it('using without increase in order of magnitude #extmarks_inc_dec', function() + it('using without increase in order of magnitude', function() -- do_addsub in ops.c feed('ddiabc998xxxTc') set_extmark(ns, marks[1], 0, 2) @@ -1120,7 +1199,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[5], 0, 7, 0, 7) end) - it('using when increase in order of magnitude #extmarks_inc_dec', function() + it('using when increase in order of magnitude', function() -- do_addsub in ops.c feed('ddiabc999xxxTc') set_extmark(ns, marks[1], 0, 2) @@ -1136,7 +1215,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[5], 0, 7, 0, 8) end) - it('using when negative and without decrease in order of magnitude #extmarks_inc_dec', function() + it('using when negative and without decrease in order of magnitude', function() feed('ddiabc-999xxxT-') set_extmark(ns, marks[1], 0, 2) set_extmark(ns, marks[2], 0, 3) @@ -1151,7 +1230,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[5], 0, 8, 0, 8) end) - it('using when negative and decrease in order of magnitude #extmarks_inc_dec', function() + it('using when negative and decrease in order of magnitude', function() feed('ddiabc-1000xxxT-') set_extmark(ns, marks[1], 0, 2) set_extmark(ns, marks[2], 0, 3) @@ -1166,7 +1245,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[5], 0, 9, 0, 8) end) - it('using without decrease in order of magnitude #extmarks_inc_dec', function() + it('using without decrease in order of magnitude', function() -- do_addsub in ops.c feed('ddiabc999xxxTc') set_extmark(ns, marks[1], 0, 2) @@ -1182,7 +1261,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[5], 0, 7, 0, 7) end) - it('using when decrease in order of magnitude #extmarks_inc_dec', function() + it('using when decrease in order of magnitude', function() -- do_addsub in ops.c feed('ddiabc1000xxxTc') set_extmark(ns, marks[1], 0, 2) @@ -1198,7 +1277,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[5], 0, 8, 0, 7) end) - it('using when negative and without increase in order of magnitude #extmarks_inc_dec', function() + it('using when negative and without increase in order of magnitude', function() feed('ddiabc-998xxxT-') set_extmark(ns, marks[1], 0, 2) set_extmark(ns, marks[2], 0, 3) @@ -1213,7 +1292,7 @@ describe('API/extmarks', function() check_undo_redo(ns, marks[5], 0, 8, 0, 8) end) - it('using when negative and increase in order of magnitude #extmarks_inc_dec', function() + it('using when negative and increase in order of magnitude', function() feed('ddiabc-999xxxT-') set_extmark(ns, marks[1], 0, 2) set_extmark(ns, marks[2], 0, 3) @@ -1236,7 +1315,7 @@ describe('API/extmarks', function() eq("Invalid ns_id", pcall_err(curbufmeths.get_extmark_by_id, ns_invalid, marks[1])) end) - it('when col = line-length, set the mark on eol #extmarks', function() + it('when col = line-length, set the mark on eol', function() set_extmark(ns, marks[1], 0, -1) local rv = curbufmeths.get_extmark_by_id(ns, marks[1]) eq({0, init_text:len()}, rv) @@ -1246,19 +1325,19 @@ describe('API/extmarks', function() eq({0, init_text:len()}, rv) end) - it('when col = line-length, set the mark on eol #extmarks', function() + it('when col = line-length, set the mark on eol', function() local invalid_col = init_text:len() + 1 eq("col value outside range", pcall_err(set_extmark, ns, marks[1], 0, invalid_col)) end) - it('fails when line > line_count #extmarks', function() + it('fails when line > line_count', function() local invalid_col = init_text:len() + 1 local invalid_lnum = 3 eq('line value outside range', pcall_err(set_extmark, ns, marks[1], invalid_lnum, invalid_col)) eq({}, curbufmeths.get_extmark_by_id(ns, marks[1])) end) - it('bug from check_col in extmark_set #extmarks_sub', function() + it('bug from check_col in extmark_set', function() -- This bug was caused by extmark_set always using check_col. check_col -- always uses the current buffer. This wasn't working during undo so we -- now use check_col and check_lnum only when they are required. @@ -1282,6 +1361,16 @@ describe('API/extmarks', function() local id = bufmeths.set_extmark(buf, ns, 0, 1, 0, {}) eq({{id, 1, 0}}, bufmeths.get_extmarks(buf, ns, 0, -1, {})) end) + + it('does not crash with append/delete/undo seqence', function() + meths.exec([[ + let ns = nvim_create_namespace('myplugin') + call nvim_buf_set_extmark(0, ns, 0, 0, 0, {}) + call append(0, '') + %delete + undo]],false) + eq(2, meths.eval('1+1')) -- did not crash + end) end) describe('Extmarks buffer api with many marks', function() @@ -1326,12 +1415,12 @@ describe('Extmarks buffer api with many marks', function() return marks end - it("can get marks #extmarks", function() + it("can get marks", function() eq(ns_marks[ns1], get_marks(ns1)) eq(ns_marks[ns2], get_marks(ns2)) end) - it("can clear all marks in ns #extmarks", function() + it("can clear all marks in ns", function() curbufmeths.clear_namespace(ns1, 0, -1) eq({}, get_marks(ns1)) eq(ns_marks[ns2], get_marks(ns2)) @@ -1340,7 +1429,7 @@ describe('Extmarks buffer api with many marks', function() eq({}, get_marks(ns2)) end) - it("can clear line range #extmarks", function() + it("can clear line range", function() curbufmeths.clear_namespace(ns1, 10, 20) for id, mark in pairs(ns_marks[ns1]) do if 10 <= mark[1] and mark[1] < 20 then @@ -1351,7 +1440,7 @@ describe('Extmarks buffer api with many marks', function() eq(ns_marks[ns2], get_marks(ns2)) end) - it("can delete line #extmarks", function() + it("can delete line", function() feed('10Gdd') for _, marks in pairs(ns_marks) do for id, mark in pairs(marks) do @@ -1366,7 +1455,7 @@ describe('Extmarks buffer api with many marks', function() eq(ns_marks[ns2], get_marks(ns2)) end) - it("can delete lines #extmarks", function() + it("can delete lines", function() feed('10G10dd') for _, marks in pairs(ns_marks) do for id, mark in pairs(marks) do @@ -1381,7 +1470,7 @@ describe('Extmarks buffer api with many marks', function() eq(ns_marks[ns2], get_marks(ns2)) end) - it("can wipe buffer #extmarks", function() + it("can wipe buffer", function() command('bwipe!') eq({}, get_marks(ns1)) eq({}, get_marks(ns2)) diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua index f589bb0e83..3cb592c714 100644 --- a/test/functional/ui/bufhl_spec.lua +++ b/test/functional/ui/bufhl_spec.lua @@ -5,6 +5,7 @@ local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local command, neq = helpers.command, helpers.neq local meths = helpers.meths local curbufmeths, eq = helpers.curbufmeths, helpers.eq +local pcall_err = helpers.pcall_err describe('Buffer highlighting', function() local screen @@ -34,6 +35,7 @@ describe('Buffer highlighting', function() [17] = {foreground = Screen.colors.Magenta, background = Screen.colors.LightRed}, [18] = {background = Screen.colors.LightRed}, [19] = {foreground = Screen.colors.Blue1, background = Screen.colors.LightRed}, + [20] = {underline = true, bold = true, foreground = Screen.colors.Cyan4}, }) end) @@ -205,17 +207,116 @@ describe('Buffer highlighting', function() | ]]) - command(':3move 4') - screen:expect([[ + -- TODO(bfedl): this behaves a bit weirdly due to the highlight on + -- the deleted line wrapping around. we should invalidate + -- highlights when they are completely inside deleted text + command('3move 4') + screen:expect{grid=[[ a {5:longer} example | | + {8:from different sources} | + {8:^in }{20:order}{8: to demonstrate} | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + --screen:expect([[ + -- a {5:longer} example | + -- | + -- {9:from }{8:diff}{7:erent} sources | + -- ^in {6:order} to {7:de}{5:monstr}{7:ate} | + -- {1:~ }| + -- {1:~ }| + -- {1:~ }| + -- | + --]]) + + command('undo') + screen:expect{grid=[[ + a {5:longer} example | + ^ | + in {6:order} to {7:de}{5:monstr}{7:ate} | {9:from }{8:diff}{7:erent} sources | + {1:~ }| + {1:~ }| + {1:~ }| + 1 change; before #4 {MATCH:.*}| + ]]} + + command('undo') + screen:expect{grid=[[ + ^a {5:longer} example | + in {6:order} to {7:de}{5:monstr}{7:ate} | + {9:from }{8:diff}{7:erent} sources | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + 1 line less; before #3 {MATCH:.*}| + ]]} + + command('undo') + screen:expect{grid=[[ + a {5:longer} example | + in {6:order} to {7:de}{5:monstr}{7:ate} | + {7:^combin}{8:ing}{9: hi}ghlights | + {9:from }{8:diff}{7:erent} sources | + {1:~ }| + {1:~ }| + {1:~ }| + 1 more line; before #2 {MATCH:.*}| + ]]} + end) + + it('and moving lines around', function() + command('2move 3') + screen:expect{grid=[[ + a {5:longer} example | + {7:combin}{8:ing}{9: hi}ghlights | ^in {6:order} to {7:de}{5:monstr}{7:ate} | + {9:from }{8:diff}{7:erent} sources | {1:~ }| {1:~ }| {1:~ }| | - ]]) + ]]} + + command('1,2move 4') + screen:expect{grid=[[ + in {6:order} to {7:de}{5:monstr}{7:ate} | + {9:from }{8:diff}{7:erent} sources | + a {5:longer} example | + {7:^combin}{8:ing}{9: hi}ghlights | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + command('undo') + screen:expect{grid=[[ + a {5:longer} example | + {7:combin}{8:ing}{9: hi}ghlights | + ^in {6:order} to {7:de}{5:monstr}{7:ate} | + {9:from }{8:diff}{7:erent} sources | + {1:~ }| + {1:~ }| + {1:~ }| + 2 change3; before #3 {MATCH:.*}| + ]]} + + command('undo') + screen:expect{grid=[[ + a {5:longer} example | + ^in {6:order} to {7:de}{5:monstr}{7:ate} | + {7:combin}{8:ing}{9: hi}ghlights | + {9:from }{8:diff}{7:erent} sources | + {1:~ }| + {1:~ }| + {1:~ }| + 1 change; before #2 {MATCH:.*}| + ]]} end) it('and adjusting columns', function() @@ -272,7 +373,7 @@ describe('Buffer highlighting', function() feed('u') screen:expect{grid=[[ a {5:longer} example | - in {6:ordAAAAr} to^ demonstrate | + in {6:ordAAAAr} to^ {7:de}{5:monstr}{7:ate} | {7:combin}{8:ing}{9: hi}ghlights | {9:from }{8:diff}{7:erent} sources | {1:~ }| @@ -284,7 +385,7 @@ describe('Buffer highlighting', function() feed('u') screen:expect{grid=[[ a {5:longer} example | - in {6:ord^er} to demonstrate | + in {6:ord^er} to {7:de}{5:monstr}{7:ate} | {7:combin}{8:ing}{9: hi}ghlights | {9:from }{8:diff}{7:erent} sources | {1:~ }| @@ -292,14 +393,14 @@ describe('Buffer highlighting', function() {1:~ }| 1 change; before #3 {MATCH:.*}| ]]} - end) + end) it('and joining lines', function() feed('ggJJJ') screen:expect{grid=[[ a {5:longer} example in {6:order} to {7:de}{5:monstr}{7:ate}| - {7: combin}{8:ing hi}{7:ghlights^ }{8:from diff}{7:erent sou}| - {7:rces} | + {7:combin}{8:ing}{9: hi}ghlights^ {9:from }{8:diff}{7:erent} sou| + rces | {1:~ }| {1:~ }| {1:~ }| @@ -307,13 +408,12 @@ describe('Buffer highlighting', function() | ]]} - -- TODO(bfredl): perhaps better undo feed('uuu') screen:expect{grid=[[ - ^a longer example | - in order to demonstrate | - combining highlights | - from different sources | + ^a {5:longer} example | + in {6:order} to {7:de}{5:monstr}{7:ate} | + {7:combin}{8:ing}{9: hi}ghlights | + {9:from }{8:diff}{7:erent} sources | {1:~ }| {1:~ }| {1:~ }| @@ -334,25 +434,23 @@ describe('Buffer highlighting', function() {7:-- INSERT --} | ]]} - -- TODO(bfredl): keep both "parts" after split, requires proper extmark ranges feed('tsi') screen:expect{grid=[[ a {5:longer} example | in {6:order} | to {7:de}{5:mo} | - ^nstrate | + {5:^nstr}{7:ate} | {7:combin}{8:ing}{9: hi}ghlights | {9:from }{8:diff}{7:erent} sources | {1:~ }| {7:-- INSERT --} | ]]} - -- TODO(bfredl): perhaps better undo feed('u') screen:expect{grid=[[ a {5:longer} example | in {6:order} | - to demo{7:^nstrat}{8:e} | + to {7:de}{5:mo^nstr}{7:ate} | {7:combin}{8:ing}{9: hi}ghlights | {9:from }{8:diff}{7:erent} sources | {1:~ }| @@ -363,7 +461,7 @@ describe('Buffer highlighting', function() feed('u') screen:expect{grid=[[ a {5:longer} example | - in order^ to demonstrate | + in {6:order}^ to {7:de}{5:monstr}{7:ate} | {7:combin}{8:ing}{9: hi}ghlights | {9:from }{8:diff}{7:erent} sources | {1:~ }| @@ -374,7 +472,7 @@ describe('Buffer highlighting', function() end) end) - it('prioritizes latest added highlight', function() + pending('prioritizes latest added highlight', function() insert([[ three overlapping colors]]) add_highlight(0, "Identifier", 0, 6, 17) @@ -405,6 +503,37 @@ describe('Buffer highlighting', function() ]]) end) + it('prioritizes earlier highlight groups (TEMP)', function() + insert([[ + three overlapping colors]]) + add_highlight(0, "Identifier", 0, 6, 17) + add_highlight(0, "String", 0, 14, 23) + local id = add_highlight(0, "Special", 0, 0, 9) + + screen:expect{grid=[[ + {4:three }{6:overlapp}{2:ing color}^s | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + clear_namespace(id, 0, 1) + screen:expect{grid=[[ + three {6:overlapp}{2:ing color}^s | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + end) + it('works with multibyte text', function() insert([[ Ta båten över sjön!]]) @@ -451,7 +580,7 @@ describe('Buffer highlighting', function() ]]) end) - describe('virtual text annotations', function() + describe('virtual text decorations', function() local set_virtual_text = curbufmeths.set_virtual_text local id1, id2 before_each(function() @@ -529,16 +658,35 @@ describe('Buffer highlighting', function() ]]) feed("2Gdd") - screen:expect([[ + -- TODO(bfredl): currently decorations get moved from a deleted line + -- to the next one. We might want to add "invalidation" when deleting + -- over a decoration. + screen:expect{grid=[[ 1 + 2 | ^5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| - , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s| + , 5, 5, 5, 5, 5, 5, {12:暗x事zz速野谷質結育}| x = 4 | {1:~ }| {1:~ }| {1:~ }| | - ]]) + ]]} + --screen:expect([[ + -- 1 + 2 | + -- ^5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| + -- , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s| + -- x = 4 | + -- {1:~ }| + -- {1:~ }| + -- {1:~ }| + -- | + --]]) + end) + + it('validates contents', function() + -- this used to leak memory + eq('Chunk is not an array', pcall_err(set_virtual_text, id1, 0, {"texty"}, {})) + eq('Chunk is not an array', pcall_err(set_virtual_text, id1, 0, {{"very"}, "texty"}, {})) end) it('can be retrieved', function() @@ -548,7 +696,9 @@ describe('Buffer highlighting', function() local s1 = {{'Köttbullar', 'Comment'}, {'Kräuterbutter'}} local s2 = {{'こんにちは', 'Comment'}} - set_virtual_text(-1, 0, s1, {}) + -- TODO: only a virtual text from the same ns curretly overrides + -- an existing virtual text. We might add a prioritation system. + set_virtual_text(id1, 0, s1, {}) eq(s1, get_virtual_text(0)) set_virtual_text(-1, line_count(), s2, {}) -- cgit From b4a92aadd274c21a32baa68e2a460910ef9c77f5 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Thu, 16 Jan 2020 15:48:42 +0100 Subject: messages: echo "line1\r\nline2" should not clear line1 --- test/functional/ui/messages_spec.lua | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'test') diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index 25b38b1feb..dfc3d045e8 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -938,6 +938,30 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim {7: 0,0-1 100% }| ]]} end) + + it('supports echo with CRLF line separators', function() + feed(':echo "line 1\\r\\nline 2"') + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {3: }| + line 1 | + line 2 | + {4:Press ENTER or type command to continue}^ | + ]]} + + feed(':echo "abc\\rz"') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + zbc | + ]]} + end) end) describe('ui/ext_messages', function() -- cgit From 757aad92e84709a08320a06870b6acb086bc6876 Mon Sep 17 00:00:00 2001 From: Marcos ALMEIDA Date: Sat, 29 Sep 2018 20:40:53 +0200 Subject: autocmd: add WinClosed event - only fire once, just before freeing mem - trigger when on a different buffer - avoid recursive calls in another tab --- test/functional/autocmd/autocmd_spec.lua | 66 ++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) (limited to 'test') diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua index 43534c9e7e..31c6edb940 100644 --- a/test/functional/autocmd/autocmd_spec.lua +++ b/test/functional/autocmd/autocmd_spec.lua @@ -2,6 +2,7 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local dedent = helpers.dedent +local neq = helpers.neq local eq = helpers.eq local eval = helpers.eval local feed = helpers.feed @@ -40,6 +41,71 @@ describe('autocmd', function() assert.same(expected, eval('g:foo')) end) + it(':close triggers WinClosed event', function() + command('let g:triggered = 0') + command('new') + command('autocmd WinClosed :let g:triggered+=1') + eq(0, eval('g:triggered')) + command('close') + eq(1, eval('g:triggered')) + end) + + it(':bdelete triggers WinClosed event', function() + command('let g:triggered = 0') + command('autocmd WinClosed :let g:triggered+=1') + local first_buffer = eval("bufnr('%')") + command('new') + command('bdelete ' .. first_buffer ) + eq(1, eval('g:triggered')) + end) + + it(':close triggers WinClosed event in another tab', function() + command('let g:triggered = 0') + local current_buffer = eval("bufnr('%')") + command('autocmd WinClosed :let g:triggered+=1') + command('tabnew') + command('bdelete ' .. current_buffer) + eq(1, eval('g:triggered')) + end) + + it('WinClosed events are not recursive in different window', function() + command('let g:triggered = 0') + local first_buffer = eval("bufnr('%')") + command('autocmd WinClosed :let g:triggered+=1') + command('new') + local second_buffer = eval("bufnr('%')") + command('autocmd WinClosed :bdelete ' .. first_buffer) + command('new') + neq(-1, funcs.bufwinnr(first_buffer)) + command('bdelete ' .. second_buffer ) + eq(0, eval('g:triggered')) + + -- first event was triggered, second wasn't + eq(-1, funcs.bufwinnr(first_buffer)) + end) + + it('WinClosed events are not recursive in the same window', function() + command('let g:triggered = 0') + command('new') + local second_buffer = eval("bufnr('%')") + command('autocmd WinClosed :let g:triggered+=1 | bdelete ' .. second_buffer) + neq(-1, funcs.bufwinnr(second_buffer)) + eq(0, eval('g:triggered')) + command('bdelete ' .. second_buffer ) + eq(-1, funcs.bufwinnr(second_buffer)) + eq(1, eval('g:triggered')) + end) + + it('WinClosed events are not recursive in different tab', function() + command('let g:triggered = 0') + command('new') + local second_buffer = eval("bufnr('%')") + command('autocmd WinClosed :let g:triggered+=1 | bdelete ' .. second_buffer) + command('tabnew') + command('bdelete ' .. second_buffer ) + eq(1, eval('g:triggered')) + end) + it('v:vim_did_enter is 1 after VimEnter', function() eq(1, eval('v:vim_did_enter')) end) -- cgit From 2b8e66c6ce0a5ccae09023732c06da90f96ed5f5 Mon Sep 17 00:00:00 2001 From: notomo Date: Tue, 14 Jan 2020 22:34:05 +0900 Subject: autocmd: WinClosed exposes window id as --- test/functional/autocmd/autocmd_spec.lua | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'test') diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua index 31c6edb940..6cb12750a1 100644 --- a/test/functional/autocmd/autocmd_spec.lua +++ b/test/functional/autocmd/autocmd_spec.lua @@ -50,6 +50,13 @@ describe('autocmd', function() eq(1, eval('g:triggered')) end) + it('WinClosed event exposes window id as ', function() + command('new') + local id = meths.get_current_win().id + helpers.nvim('command', 'au! WinClosed * echom "winclosed:".expand("").":".expand("").":".win_getid()') + eq(string.format("winclosed:%s:%s:%s", id, id, id), helpers.nvim('exec', 'close', true)) + end) + it(':bdelete triggers WinClosed event', function() command('let g:triggered = 0') command('autocmd WinClosed :let g:triggered+=1') -- cgit From 156c25e4983d4c106ba70e5e3bcc6bbb012d8065 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 13 Jan 2020 00:19:20 -0800 Subject: WinClosed: sort auevents.lua; improve tests - test: reduce verbosity, condense redundancy, improve readability - auevents.lua: keep events sorted by name. ref afd1d412fa91 --- test/functional/autocmd/autocmd_spec.lua | 148 ++++++++++++++----------------- test/functional/helpers.lua | 13 +++ 2 files changed, 81 insertions(+), 80 deletions(-) (limited to 'test') diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua index 6cb12750a1..e62d3bb66b 100644 --- a/test/functional/autocmd/autocmd_spec.lua +++ b/test/functional/autocmd/autocmd_spec.lua @@ -1,8 +1,8 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') +local assert_visible = helpers.assert_visible local dedent = helpers.dedent -local neq = helpers.neq local eq = helpers.eq local eval = helpers.eval local feed = helpers.feed @@ -19,98 +19,86 @@ local source = helpers.source describe('autocmd', function() before_each(clear) - it(':tabnew triggers events in the correct order', function() + it(':tabnew, :split, :close events order, ', function() local expected = { - 'WinLeave', - 'TabLeave', - 'WinEnter', - 'TabNew', - 'TabEnter', - 'BufLeave', - 'BufEnter' + {'WinLeave', ''}, + {'TabLeave', ''}, + {'WinEnter', ''}, + {'TabNew', 'testfile1'}, -- :tabnew + {'TabEnter', ''}, + {'BufLeave', ''}, + {'BufEnter', 'testfile1'}, -- :split + {'WinLeave', 'testfile1'}, + {'WinEnter', 'testfile1'}, + {'WinLeave', 'testfile1'}, + {'WinClosed', '1002'}, -- :close, WinClosed = window-id + {'WinEnter', 'testfile1'}, + {'WinLeave', 'testfile1'}, -- :bdelete + {'WinEnter', 'testfile1'}, + {'BufLeave', 'testfile1'}, + {'BufEnter', 'testfile2'}, + {'WinClosed', '1000'}, } - command('let g:foo = []') - command('autocmd BufEnter * :call add(g:foo, "BufEnter")') - command('autocmd BufLeave * :call add(g:foo, "BufLeave")') - command('autocmd TabEnter * :call add(g:foo, "TabEnter")') - command('autocmd TabLeave * :call add(g:foo, "TabLeave")') - command('autocmd TabNew * :call add(g:foo, "TabNew")') - command('autocmd WinEnter * :call add(g:foo, "WinEnter")') - command('autocmd WinLeave * :call add(g:foo, "WinLeave")') - command('tabnew') - assert.same(expected, eval('g:foo')) - end) - - it(':close triggers WinClosed event', function() - command('let g:triggered = 0') - command('new') - command('autocmd WinClosed :let g:triggered+=1') - eq(0, eval('g:triggered')) + command('let g:evs = []') + command('autocmd BufEnter * :call add(g:evs, ["BufEnter", expand("")])') + command('autocmd BufLeave * :call add(g:evs, ["BufLeave", expand("")])') + command('autocmd TabEnter * :call add(g:evs, ["TabEnter", expand("")])') + command('autocmd TabLeave * :call add(g:evs, ["TabLeave", expand("")])') + command('autocmd TabNew * :call add(g:evs, ["TabNew", expand("")])') + command('autocmd WinEnter * :call add(g:evs, ["WinEnter", expand("")])') + command('autocmd WinLeave * :call add(g:evs, ["WinLeave", expand("")])') + command('autocmd WinClosed * :call add(g:evs, ["WinClosed", expand("")])') + command('tabnew testfile1') + command('split') command('close') - eq(1, eval('g:triggered')) + command('new testfile2') + command('bdelete 1') + eq(expected, eval('g:evs')) end) - it('WinClosed event exposes window id as ', function() - command('new') - local id = meths.get_current_win().id - helpers.nvim('command', 'au! WinClosed * echom "winclosed:".expand("").":".expand("").":".win_getid()') - eq(string.format("winclosed:%s:%s:%s", id, id, id), helpers.nvim('exec', 'close', true)) - end) - - it(':bdelete triggers WinClosed event', function() + it('WinClosed is non-recursive', function() command('let g:triggered = 0') - command('autocmd WinClosed :let g:triggered+=1') - local first_buffer = eval("bufnr('%')") - command('new') - command('bdelete ' .. first_buffer ) - eq(1, eval('g:triggered')) - end) + command('autocmd WinClosed * :let g:triggered+=1 | :bdelete 2') + command('new testfile2') + command('new testfile3') - it(':close triggers WinClosed event in another tab', function() - command('let g:triggered = 0') - local current_buffer = eval("bufnr('%')") - command('autocmd WinClosed :let g:triggered+=1') - command('tabnew') - command('bdelete ' .. current_buffer) - eq(1, eval('g:triggered')) - end) + -- All 3 buffers are visible. + assert_visible(1, true) + assert_visible(2, true) + assert_visible(3, true) - it('WinClosed events are not recursive in different window', function() - command('let g:triggered = 0') - local first_buffer = eval("bufnr('%')") - command('autocmd WinClosed :let g:triggered+=1') - command('new') - local second_buffer = eval("bufnr('%')") - command('autocmd WinClosed :bdelete ' .. first_buffer) - command('new') - neq(-1, funcs.bufwinnr(first_buffer)) - command('bdelete ' .. second_buffer ) - eq(0, eval('g:triggered')) + -- Trigger WinClosed, which also deletes buffer/window 2. + command('bdelete 1') - -- first event was triggered, second wasn't - eq(-1, funcs.bufwinnr(first_buffer)) - end) - - it('WinClosed events are not recursive in the same window', function() - command('let g:triggered = 0') - command('new') - local second_buffer = eval("bufnr('%')") - command('autocmd WinClosed :let g:triggered+=1 | bdelete ' .. second_buffer) - neq(-1, funcs.bufwinnr(second_buffer)) - eq(0, eval('g:triggered')) - command('bdelete ' .. second_buffer ) - eq(-1, funcs.bufwinnr(second_buffer)) + -- Buffers 1 and 2 were closed but WinClosed was triggered only once. eq(1, eval('g:triggered')) + assert_visible(1, false) + assert_visible(2, false) + assert_visible(3, true) end) - it('WinClosed events are not recursive in different tab', function() - command('let g:triggered = 0') + it('WinClosed from a different tabpage', function() + command('let g:evs = []') + command('edit tesfile1') + command('autocmd WinClosed :call add(g:evs, ["WinClosed", expand("")])') + local buf1 = eval("bufnr('%')") command('new') - local second_buffer = eval("bufnr('%')") - command('autocmd WinClosed :let g:triggered+=1 | bdelete ' .. second_buffer) - command('tabnew') - command('bdelete ' .. second_buffer ) - eq(1, eval('g:triggered')) + local buf2 = eval("bufnr('%')") + command('autocmd WinClosed :call add(g:evs, ["WinClosed", expand("")])' + -- Attempt recursion. + ..' | bdelete '..buf2) + command('tabedit testfile2') + command('tabedit testfile3') + command('bdelete '..buf2) + -- Non-recursive: only triggered once. + eq({ + {'WinClosed', '2'}, + }, eval('g:evs')) + command('bdelete '..buf1) + eq({ + {'WinClosed', '2'}, + {'WinClosed', '1'}, + }, eval('g:evs')) end) it('v:vim_did_enter is 1 after VimEnter', function() diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index e0012c6ced..de61ff9cc8 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -597,6 +597,19 @@ function module.assert_alive() assert(2 == module.eval('1+1'), 'crash? request failed') end +-- Asserts that buffer is loaded and visible in the current tabpage. +function module.assert_visible(bufnr, visible) + assert(type(visible) == 'boolean') + eq(visible, module.bufmeths.is_loaded(bufnr)) + if visible then + assert(-1 ~= module.funcs.bufwinnr(bufnr), + 'expected buffer to be visible in current tabpage: '..tostring(bufnr)) + else + assert(-1 == module.funcs.bufwinnr(bufnr), + 'expected buffer NOT visible in current tabpage: '..tostring(bufnr)) + end +end + local function do_rmdir(path) local mode, errmsg, errcode = lfs.attributes(path, 'mode') if mode == nil then -- cgit From 8e385eb46a8b961a760e05b4cfa053cf713def62 Mon Sep 17 00:00:00 2001 From: We're Yet <58348703+butwerenotthereyet@users.noreply.github.com> Date: Sat, 18 Jan 2020 13:19:56 -0800 Subject: tabpage: :tabs indicates previous tabpage's curwin --- test/functional/autocmd/tabnewentered_spec.lua | 45 +++++++++++++++++++++----- 1 file changed, 37 insertions(+), 8 deletions(-) (limited to 'test') diff --git a/test/functional/autocmd/tabnewentered_spec.lua b/test/functional/autocmd/tabnewentered_spec.lua index 949786d8ff..123dbd0824 100644 --- a/test/functional/autocmd/tabnewentered_spec.lua +++ b/test/functional/autocmd/tabnewentered_spec.lua @@ -85,7 +85,7 @@ describe('tabpage/previous', function() Tab page 3 > [No Name] Tab page 4 - [No Name]]=]), + # [No Name]]=]), redir_exec('tabs') ) @@ -122,7 +122,7 @@ describe('tabpage/previous', function() Tab page 2 > [No Name] Tab page 3 - [No Name] + # [No Name] Tab page 4 [No Name] Tab page 5 @@ -160,7 +160,7 @@ describe('tabpage/previous', function() Tab page 1 - [No Name] + # [No Name] Tab page 2 [No Name] Tab page 3 @@ -208,7 +208,7 @@ describe('tabpage/previous', function() Tab page 3 [No Name] Tab page 4 - [No Name]]=]), + # [No Name]]=]), redir_exec('tabs') ) @@ -246,7 +246,7 @@ describe('tabpage/previous', function() Tab page 2 [No Name] Tab page 3 - [No Name] + # [No Name] Tab page 4 > [No Name]]=]), redir_exec('tabs') @@ -284,7 +284,7 @@ describe('tabpage/previous', function() Tab page 1 - [No Name] + # [No Name] Tab page 2 [No Name] Tab page 3 @@ -326,7 +326,7 @@ describe('tabpage/previous', function() Tab page 1 [No Name] Tab page 2 - [No Name] + # [No Name] Tab page 3 [No Name] Tab page 4 @@ -372,7 +372,7 @@ describe('tabpage/previous', function() Tab page 3 [No Name] Tab page 4 - [No Name]]=]), + # [No Name]]=]), redir_exec('tabs') ) @@ -516,4 +516,33 @@ describe('tabpage/previous', function() cmdline_win_prevents_tab_switch('g', 1)) it('cmdline-win prevents tab switch via ', cmdline_win_prevents_tab_switch('', 0)) + + it(':tabs indicates correct prevtab curwin', function() + -- Add three tabs for a total of four + command('tabnew') + command('tabnew') + command('split') + command('vsplit') + feed('p') + command('tabnew') + + -- The previous tab is now the three. + eq(3, eval('tabpagenr(\'#\')')) + + eq(dedent([=[ + + + Tab page 1 + [No Name] + Tab page 2 + [No Name] + Tab page 3 + [No Name] + # [No Name] + [No Name] + Tab page 4 + > [No Name]]=]), + redir_exec('tabs') + ) + end) end) -- cgit From 48a869dc6d29514e943070da9f22f702f5179826 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Mon, 20 Jan 2020 19:29:12 +0100 Subject: shed biking: it's always extmarks, never marks extended --- test/functional/api/extmark_spec.lua | 1477 +++++++++++++++++++++++++++ test/functional/api/mark_extended_spec.lua | 1478 ---------------------------- 2 files changed, 1477 insertions(+), 1478 deletions(-) create mode 100644 test/functional/api/extmark_spec.lua delete mode 100644 test/functional/api/mark_extended_spec.lua (limited to 'test') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua new file mode 100644 index 0000000000..5bf3fa554f --- /dev/null +++ b/test/functional/api/extmark_spec.lua @@ -0,0 +1,1477 @@ +local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') + +local request = helpers.request +local eq = helpers.eq +local ok = helpers.ok +local curbufmeths = helpers.curbufmeths +local bufmeths = helpers.bufmeths +local pcall_err = helpers.pcall_err +local insert = helpers.insert +local feed = helpers.feed +local clear = helpers.clear +local command = helpers.command +local meths = helpers.meths + +local function expect(contents) + return eq(contents, helpers.curbuf_contents()) +end + +local function check_undo_redo(ns, mark, sr, sc, er, ec) --s = start, e = end + local rv = curbufmeths.get_extmark_by_id(ns, mark) + eq({er, ec}, rv) + feed("u") + rv = curbufmeths.get_extmark_by_id(ns, mark) + eq({sr, sc}, rv) + feed("") + rv = curbufmeths.get_extmark_by_id(ns, mark) + eq({er, ec}, rv) +end + +local function set_extmark(ns_id, id, line, col, opts) + if opts == nil then + opts = {} + end + return curbufmeths.set_extmark(ns_id, id, line, col, opts) +end + +local function get_extmarks(ns_id, start, end_, opts) + if opts == nil then + opts = {} + end + return curbufmeths.get_extmarks(ns_id, start, end_, opts) +end + +local function batch_set(ns_id, positions) + local ids = {} + for _, pos in ipairs(positions) do + table.insert(ids, set_extmark(ns_id, 0, pos[1], pos[2])) + end + return ids +end + +local function batch_check(ns_id, ids, positions) + local actual, expected = {}, {} + for i,id in ipairs(ids) do + expected[id] = positions[i] + end + for _, mark in pairs(get_extmarks(ns_id, 0, -1, {})) do + actual[mark[1]] = {mark[2], mark[3]} + end + eq(expected, actual) +end + +local function batch_check_undo_redo(ns_id, ids, before, after) + batch_check(ns_id, ids, after) + feed("u") + batch_check(ns_id, ids, before) + feed("") + batch_check(ns_id, ids, after) +end + +describe('API/extmarks', function() + local screen + local marks, positions, init_text, row, col + local ns, ns2 + + before_each(function() + -- Initialize some namespaces and insert 12345 into a buffer + marks = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} + positions = {{0, 0,}, {0, 2}, {0, 3}} + + init_text = "12345" + row = 0 + col = 2 + + clear() + + insert(init_text) + ns = request('nvim_create_namespace', "my-fancy-plugin") + ns2 = request('nvim_create_namespace', "my-fancy-plugin2") + end) + + it('adds, updates and deletes marks', function() + local rv = set_extmark(ns, marks[1], positions[1][1], positions[1][2]) + eq(marks[1], rv) + rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + eq({positions[1][1], positions[1][2]}, rv) + -- Test adding a second mark on same row works + rv = set_extmark(ns, marks[2], positions[2][1], positions[2][2]) + eq(marks[2], rv) + + -- Test an update, (same pos) + rv = set_extmark(ns, marks[1], positions[1][1], positions[1][2]) + eq(marks[1], rv) + rv = curbufmeths.get_extmark_by_id(ns, marks[2]) + eq({positions[2][1], positions[2][2]}, rv) + -- Test an update, (new pos) + row = positions[1][1] + col = positions[1][2] + 1 + rv = set_extmark(ns, marks[1], row, col) + eq(marks[1], rv) + rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + eq({row, col}, rv) + + -- remove the test marks + eq(true, curbufmeths.del_extmark(ns, marks[1])) + eq(false, curbufmeths.del_extmark(ns, marks[1])) + eq(true, curbufmeths.del_extmark(ns, marks[2])) + eq(false, curbufmeths.del_extmark(ns, marks[3])) + eq(false, curbufmeths.del_extmark(ns, 1000)) + end) + + it('can clear a specific namespace range', function() + set_extmark(ns, 1, 0, 1) + set_extmark(ns2, 1, 0, 1) + -- force a new undo buffer + feed('o') + curbufmeths.clear_namespace(ns2, 0, -1) + eq({{1, 0, 1}}, get_extmarks(ns, {0, 0}, {-1, -1})) + eq({}, get_extmarks(ns2, {0, 0}, {-1, -1})) + feed('u') + eq({{1, 0, 1}}, get_extmarks(ns, {0, 0}, {-1, -1})) + eq({}, get_extmarks(ns2, {0, 0}, {-1, -1})) + feed('') + eq({{1, 0, 1}}, get_extmarks(ns, {0, 0}, {-1, -1})) + eq({}, get_extmarks(ns2, {0, 0}, {-1, -1})) + end) + + it('can clear a namespace range using 0,-1', function() + set_extmark(ns, 1, 0, 1) + set_extmark(ns2, 1, 0, 1) + -- force a new undo buffer + feed('o') + curbufmeths.clear_namespace(-1, 0, -1) + eq({}, get_extmarks(ns, {0, 0}, {-1, -1})) + eq({}, get_extmarks(ns2, {0, 0}, {-1, -1})) + feed('u') + eq({}, get_extmarks(ns, {0, 0}, {-1, -1})) + eq({}, get_extmarks(ns2, {0, 0}, {-1, -1})) + feed('') + eq({}, get_extmarks(ns, {0, 0}, {-1, -1})) + eq({}, get_extmarks(ns2, {0, 0}, {-1, -1})) + end) + + it('querying for information and ranges', function() + --marks = {1, 2, 3} + --positions = {{0, 0,}, {0, 2}, {0, 3}} + -- add some more marks + for i, m in ipairs(marks) do + if positions[i] ~= nil then + local rv = set_extmark(ns, m, positions[i][1], positions[i][2]) + eq(m, rv) + end + end + + -- {0, 0} and {-1, -1} work as extreme values + eq({{1, 0, 0}}, get_extmarks(ns, {0, 0}, {0, 0})) + eq({}, get_extmarks(ns, {-1, -1}, {-1, -1})) + local rv = get_extmarks(ns, {0, 0}, {-1, -1}) + for i, m in ipairs(marks) do + if positions[i] ~= nil then + eq({m, positions[i][1], positions[i][2]}, rv[i]) + end + end + + -- 0 and -1 works as short hand extreme values + eq({{1, 0, 0}}, get_extmarks(ns, 0, 0)) + eq({}, get_extmarks(ns, -1, -1)) + rv = get_extmarks(ns, 0, -1) + for i, m in ipairs(marks) do + if positions[i] ~= nil then + eq({m, positions[i][1], positions[i][2]}, rv[i]) + end + end + + -- next with mark id + rv = get_extmarks(ns, marks[1], {-1, -1}, {limit=1}) + eq({{marks[1], positions[1][1], positions[1][2]}}, rv) + rv = get_extmarks(ns, marks[2], {-1, -1}, {limit=1}) + eq({{marks[2], positions[2][1], positions[2][2]}}, rv) + -- next with positional when mark exists at position + rv = get_extmarks(ns, positions[1], {-1, -1}, {limit=1}) + eq({{marks[1], positions[1][1], positions[1][2]}}, rv) + -- next with positional index (no mark at position) + rv = get_extmarks(ns, {positions[1][1], positions[1][2] +1}, {-1, -1}, {limit=1}) + eq({{marks[2], positions[2][1], positions[2][2]}}, rv) + -- next with Extremity index + rv = get_extmarks(ns, {0,0}, {-1, -1}, {limit=1}) + eq({{marks[1], positions[1][1], positions[1][2]}}, rv) + + -- nextrange with mark id + rv = get_extmarks(ns, marks[1], marks[3]) + eq({marks[1], positions[1][1], positions[1][2]}, rv[1]) + eq({marks[2], positions[2][1], positions[2][2]}, rv[2]) + -- nextrange with `limit` + rv = get_extmarks(ns, marks[1], marks[3], {limit=2}) + eq(2, table.getn(rv)) + -- nextrange with positional when mark exists at position + rv = get_extmarks(ns, positions[1], positions[3]) + eq({marks[1], positions[1][1], positions[1][2]}, rv[1]) + eq({marks[2], positions[2][1], positions[2][2]}, rv[2]) + rv = get_extmarks(ns, positions[2], positions[3]) + eq(2, table.getn(rv)) + -- nextrange with positional index (no mark at position) + local lower = {positions[1][1], positions[2][2] -1} + local upper = {positions[2][1], positions[3][2] - 1} + rv = get_extmarks(ns, lower, upper) + eq({{marks[2], positions[2][1], positions[2][2]}}, rv) + lower = {positions[3][1], positions[3][2] + 1} + upper = {positions[3][1], positions[3][2] + 2} + rv = get_extmarks(ns, lower, upper) + eq({}, rv) + -- nextrange with extremity index + lower = {positions[2][1], positions[2][2]+1} + upper = {-1, -1} + rv = get_extmarks(ns, lower, upper) + eq({{marks[3], positions[3][1], positions[3][2]}}, rv) + + -- prev with mark id + rv = get_extmarks(ns, marks[3], {0, 0}, {limit=1}) + eq({{marks[3], positions[3][1], positions[3][2]}}, rv) + rv = get_extmarks(ns, marks[2], {0, 0}, {limit=1}) + eq({{marks[2], positions[2][1], positions[2][2]}}, rv) + -- prev with positional when mark exists at position + rv = get_extmarks(ns, positions[3], {0, 0}, {limit=1}) + eq({{marks[3], positions[3][1], positions[3][2]}}, rv) + -- prev with positional index (no mark at position) + rv = get_extmarks(ns, {positions[1][1], positions[1][2] +1}, {0, 0}, {limit=1}) + eq({{marks[1], positions[1][1], positions[1][2]}}, rv) + -- prev with Extremity index + rv = get_extmarks(ns, {-1,-1}, {0,0}, {limit=1}) + eq({{marks[3], positions[3][1], positions[3][2]}}, rv) + + -- prevrange with mark id + rv = get_extmarks(ns, marks[3], marks[1]) + eq({marks[3], positions[3][1], positions[3][2]}, rv[1]) + eq({marks[2], positions[2][1], positions[2][2]}, rv[2]) + eq({marks[1], positions[1][1], positions[1][2]}, rv[3]) + -- prevrange with limit + rv = get_extmarks(ns, marks[3], marks[1], {limit=2}) + eq(2, table.getn(rv)) + -- prevrange with positional when mark exists at position + rv = get_extmarks(ns, positions[3], positions[1]) + eq({{marks[3], positions[3][1], positions[3][2]}, + {marks[2], positions[2][1], positions[2][2]}, + {marks[1], positions[1][1], positions[1][2]}}, rv) + rv = get_extmarks(ns, positions[2], positions[1]) + eq(2, table.getn(rv)) + -- prevrange with positional index (no mark at position) + lower = {positions[2][1], positions[2][2] + 1} + upper = {positions[3][1], positions[3][2] + 1} + rv = get_extmarks(ns, upper, lower) + eq({{marks[3], positions[3][1], positions[3][2]}}, rv) + lower = {positions[3][1], positions[3][2] + 1} + upper = {positions[3][1], positions[3][2] + 2} + rv = get_extmarks(ns, upper, lower) + eq({}, rv) + -- prevrange with extremity index + lower = {0,0} + upper = {positions[2][1], positions[2][2] - 1} + rv = get_extmarks(ns, upper, lower) + eq({{marks[1], positions[1][1], positions[1][2]}}, rv) + end) + + it('querying for information with limit', function() + -- add some more marks + for i, m in ipairs(marks) do + if positions[i] ~= nil then + local rv = set_extmark(ns, m, positions[i][1], positions[i][2]) + eq(m, rv) + end + end + + local rv = get_extmarks(ns, {0, 0}, {-1, -1}, {limit=1}) + eq(1, table.getn(rv)) + rv = get_extmarks(ns, {0, 0}, {-1, -1}, {limit=2}) + eq(2, table.getn(rv)) + rv = get_extmarks(ns, {0, 0}, {-1, -1}, {limit=3}) + eq(3, table.getn(rv)) + + -- now in reverse + rv = get_extmarks(ns, {0, 0}, {-1, -1}, {limit=1}) + eq(1, table.getn(rv)) + rv = get_extmarks(ns, {0, 0}, {-1, -1}, {limit=2}) + eq(2, table.getn(rv)) + rv = get_extmarks(ns, {0, 0}, {-1, -1}, {limit=3}) + eq(3, table.getn(rv)) + end) + + it('get_marks works when mark col > upper col', function() + feed('A12345') + feed('A12345') + set_extmark(ns, 10, 0, 2) -- this shouldn't be found + set_extmark(ns, 11, 2, 1) -- this shouldn't be found + set_extmark(ns, marks[1], 0, 4) -- check col > our upper bound + set_extmark(ns, marks[2], 1, 1) -- check col < lower bound + set_extmark(ns, marks[3], 2, 0) -- check is inclusive + eq({{marks[1], 0, 4}, + {marks[2], 1, 1}, + {marks[3], 2, 0}}, + get_extmarks(ns, {0, 3}, {2, 0})) + end) + + it('get_marks works in reverse when mark col < lower col', function() + feed('A12345') + feed('A12345') + set_extmark(ns, 10, 0, 1) -- this shouldn't be found + set_extmark(ns, 11, 2, 4) -- this shouldn't be found + set_extmark(ns, marks[1], 2, 1) -- check col < our lower bound + set_extmark(ns, marks[2], 1, 4) -- check col > upper bound + set_extmark(ns, marks[3], 0, 2) -- check is inclusive + local rv = get_extmarks(ns, {2, 3}, {0, 2}) + eq({{marks[1], 2, 1}, + {marks[2], 1, 4}, + {marks[3], 0, 2}}, + rv) + end) + + it('get_marks limit=0 returns nothing', function() + set_extmark(ns, marks[1], positions[1][1], positions[1][2]) + local rv = get_extmarks(ns, {-1, -1}, {-1, -1}, {limit=0}) + eq({}, rv) + end) + + + it('marks move with line insertations', function() + set_extmark(ns, marks[1], 0, 0) + feed("yyP") + check_undo_redo(ns, marks[1], 0, 0, 1, 0) + end) + + it('marks move with multiline insertations', function() + feed("a2233") + set_extmark(ns, marks[1], 1, 1) + feed('ggVGyP') + check_undo_redo(ns, marks[1], 1, 1, 4, 1) + end) + + it('marks move with line join', function() + -- do_join in ops.c + feed("a222") + set_extmark(ns, marks[1], 1, 0) + feed('ggJ') + check_undo_redo(ns, marks[1], 1, 0, 0, 6) + end) + + it('join works when no marks are present', function() + screen = Screen.new(15, 10) + screen:attach() + feed("a1") + feed('kJ') + -- This shouldn't seg fault + screen:expect([[ + 12345^ 1 | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + | + ]]) + end) + + it('marks move with multiline join', function() + -- do_join in ops.c + feed("a222333444") + set_extmark(ns, marks[1], 3, 0) + feed('2GVGJ') + check_undo_redo(ns, marks[1], 3, 0, 1, 8) + end) + + it('marks move with line deletes', function() + feed("a222333444") + set_extmark(ns, marks[1], 2, 1) + feed('ggjdd') + check_undo_redo(ns, marks[1], 2, 1, 1, 1) + end) + + it('marks move with multiline deletes', function() + feed("a222333444") + set_extmark(ns, marks[1], 3, 0) + feed('gg2dd') + check_undo_redo(ns, marks[1], 3, 0, 1, 0) + -- regression test, undoing multiline delete when mark is on row 1 + feed('ugg3dd') + check_undo_redo(ns, marks[1], 3, 0, 0, 0) + end) + + it('marks move with open line', function() + -- open_line in misc1.c + -- testing marks below are also moved + feed("yyP") + set_extmark(ns, marks[1], 0, 4) + set_extmark(ns, marks[2], 1, 4) + feed('1G') + check_undo_redo(ns, marks[1], 0, 4, 1, 4) + check_undo_redo(ns, marks[2], 1, 4, 2, 4) + feed('2Go') + check_undo_redo(ns, marks[1], 1, 4, 1, 4) + check_undo_redo(ns, marks[2], 2, 4, 3, 4) + end) + + it('marks move with char inserts', function() + -- insertchar in edit.c (the ins_str branch) + screen = Screen.new(15, 10) + screen:attach() + set_extmark(ns, marks[1], 0, 3) + feed('0') + insert('abc') + screen:expect([[ + ab^c12345 | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + | + ]]) + local rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + eq({0, 6}, rv) + check_undo_redo(ns, marks[1], 0, 3, 0, 6) + end) + + -- gravity right as definted in tk library + it('marks have gravity right', function() + -- insertchar in edit.c (the ins_str branch) + set_extmark(ns, marks[1], 0, 2) + feed('03l') + insert("X") + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + + -- check multibyte chars + feed('03l') + insert("~~") + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + end) + + it('we can insert multibyte chars', function() + -- insertchar in edit.c + feed('a12345') + set_extmark(ns, marks[1], 1, 2) + -- Insert a fullwidth (two col) tilde, NICE + feed('0i~') + check_undo_redo(ns, marks[1], 1, 2, 1, 5) + end) + + it('marks move with blockwise inserts', function() + -- op_insert in ops.c + feed('a12345') + set_extmark(ns, marks[1], 1, 2) + feed('0lkI9') + check_undo_redo(ns, marks[1], 1, 2, 1, 3) + end) + + it('marks move with line splits (using enter)', function() + -- open_line in misc1.c + -- testing marks below are also moved + feed("yyP") + set_extmark(ns, marks[1], 0, 4) + set_extmark(ns, marks[2], 1, 4) + feed('1Gla') + check_undo_redo(ns, marks[1], 0, 4, 1, 2) + check_undo_redo(ns, marks[2], 1, 4, 2, 4) + end) + + it('marks at last line move on insert new line', function() + -- open_line in misc1.c + set_extmark(ns, marks[1], 0, 4) + feed('0i') + check_undo_redo(ns, marks[1], 0, 4, 1, 4) + end) + + it('yet again marks move with line splits', function() + -- the first test above wasn't catching all errors.. + feed("A67890") + set_extmark(ns, marks[1], 0, 4) + feed("04li") + check_undo_redo(ns, marks[1], 0, 4, 1, 0) + end) + + it('and one last time line splits...', function() + set_extmark(ns, marks[1], 0, 1) + set_extmark(ns, marks[2], 0, 2) + feed("02li") + check_undo_redo(ns, marks[1], 0, 1, 0, 1) + check_undo_redo(ns, marks[2], 0, 2, 1, 0) + end) + + it('multiple marks move with mark splits', function() + set_extmark(ns, marks[1], 0, 1) + set_extmark(ns, marks[2], 0, 3) + feed("0li") + check_undo_redo(ns, marks[1], 0, 1, 1, 0) + check_undo_redo(ns, marks[2], 0, 3, 1, 2) + end) + + it('deleting right before a mark works', function() + -- op_delete in ops.c + set_extmark(ns, marks[1], 0, 2) + feed('0lx') + check_undo_redo(ns, marks[1], 0, 2, 0, 1) + end) + + it('deleting right after a mark works', function() + -- op_delete in ops.c + set_extmark(ns, marks[1], 0, 2) + feed('02lx') + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + end) + + it('marks move with char deletes', function() + -- op_delete in ops.c + set_extmark(ns, marks[1], 0, 2) + feed('02dl') + check_undo_redo(ns, marks[1], 0, 2, 0, 0) + -- from the other side (nothing should happen) + feed('$x') + check_undo_redo(ns, marks[1], 0, 0, 0, 0) + end) + + it('marks move with char deletes over a range', function() + -- op_delete in ops.c + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 0, 3) + feed('0l3dl') + check_undo_redo(ns, marks[1], 0, 2, 0, 1) + check_undo_redo(ns, marks[2], 0, 3, 0, 1) + -- delete 1, nothing should happen to our marks + feed('u') + feed('$x') + check_undo_redo(ns, marks[2], 0, 3, 0, 3) + end) + + it('deleting marks at end of line works', function() + set_extmark(ns, marks[1], 0, 4) + feed('$x') + check_undo_redo(ns, marks[1], 0, 4, 0, 4) + -- check the copy happened correctly on delete at eol + feed('$x') + check_undo_redo(ns, marks[1], 0, 4, 0, 3) + feed('u') + check_undo_redo(ns, marks[1], 0, 4, 0, 4) + end) + + it('marks move with blockwise deletes', function() + -- op_delete in ops.c + feed('a12345') + set_extmark(ns, marks[1], 1, 4) + feed('hhhkd') + check_undo_redo(ns, marks[1], 1, 4, 1, 1) + end) + + it('marks move with blockwise deletes over a range', function() + -- op_delete in ops.c + feed('a12345') + set_extmark(ns, marks[1], 0, 1) + set_extmark(ns, marks[2], 0, 3) + set_extmark(ns, marks[3], 1, 2) + feed('0k3lx') + check_undo_redo(ns, marks[1], 0, 1, 0, 0) + check_undo_redo(ns, marks[2], 0, 3, 0, 0) + check_undo_redo(ns, marks[3], 1, 2, 1, 0) + -- delete 1, nothing should happen to our marks + feed('u') + feed('$jx') + check_undo_redo(ns, marks[2], 0, 3, 0, 3) + check_undo_redo(ns, marks[3], 1, 2, 1, 2) + end) + + it('works with char deletes over multilines', function() + feed('a12345test-me') + set_extmark(ns, marks[1], 2, 5) + feed('gg') + feed('dv?-m?') + check_undo_redo(ns, marks[1], 2, 5, 0, 0) + end) + + it('marks outside of deleted range move with visual char deletes', function() + -- op_delete in ops.c + set_extmark(ns, marks[1], 0, 3) + feed('0vx') + check_undo_redo(ns, marks[1], 0, 3, 0, 2) + + feed("u") + feed('0vlx') + check_undo_redo(ns, marks[1], 0, 3, 0, 1) + + feed("u") + feed('0v2lx') + check_undo_redo(ns, marks[1], 0, 3, 0, 0) + + -- from the other side (nothing should happen) + feed('$vx') + check_undo_redo(ns, marks[1], 0, 0, 0, 0) + end) + + it('marks outside of deleted range move with char deletes', function() + -- op_delete in ops.c + set_extmark(ns, marks[1], 0, 3) + feed('0x') + check_undo_redo(ns, marks[1], 0, 3, 0, 2) + + feed("u") + feed('02x') + check_undo_redo(ns, marks[1], 0, 3, 0, 1) + + feed("u") + feed('0v3lx') + check_undo_redo(ns, marks[1], 0, 3, 0, 0) + + -- from the other side (nothing should happen) + feed("u") + feed('$vx') + check_undo_redo(ns, marks[1], 0, 3, 0, 3) + end) + + it('marks move with P(backward) paste', function() + -- do_put in ops.c + feed('0iabc') + set_extmark(ns, marks[1], 0, 7) + feed('0veyP') + check_undo_redo(ns, marks[1], 0, 7, 0, 15) + end) + + it('marks move with p(forward) paste', function() + -- do_put in ops.c + feed('0iabc') + set_extmark(ns, marks[1], 0, 7) + feed('0veyp') + check_undo_redo(ns, marks[1], 0, 7, 0, 15) + end) + + it('marks move with blockwise P(backward) paste', function() + -- do_put in ops.c + feed('a12345') + set_extmark(ns, marks[1], 1, 4) + feed('hhkyP') + check_undo_redo(ns, marks[1], 1, 4, 1, 7) + end) + + it('marks move with blockwise p(forward) paste', function() + -- do_put in ops.c + feed('a12345') + set_extmark(ns, marks[1], 1, 4) + feed('hhkyp') + check_undo_redo(ns, marks[1], 1, 4, 1, 7) + end) + + describe('multiline regions', function() + before_each(function() + feed('dd') + -- Achtung: code has been spiced with some unicode, + -- to make life more interesting. + -- luacheck whines about TABs inside strings for whatever reason. + -- luacheck: push ignore 621 + insert([[ + static int nlua_rpcrequest(lua_State *lstate) + { + Ïf (!nlua_is_deferred_safe(lstate)) { + // strictly not allowed + Яetörn luaL_error(lstate, e_luv_api_disabled, "rpcrequest"); + } + return nlua_rpc(lstate, true); + }]]) + -- luacheck: pop + end) + + it('delete', function() + local pos1 = { + {2, 4}, {2, 12}, {2, 13}, {2, 14}, {2, 25}, + {4, 8}, {4, 10}, {4, 20}, + {5, 3}, {6, 10} + } + local ids = batch_set(ns, pos1) + batch_check(ns, ids, pos1) + feed('3Gfiv2+ftd') + batch_check_undo_redo(ns, ids, pos1, { + {2, 4}, {2, 12}, {2, 13}, {2, 13}, {2, 13}, + {2, 13}, {2, 15}, {2, 25}, + {3, 3}, {4, 10} + }) + end) + + -- TODO(bfredl): add more tests! + end) + + it('replace works', function() + set_extmark(ns, marks[1], 0, 2) + feed('0r2') + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + end) + + it('blockwise replace works', function() + feed('a12345') + set_extmark(ns, marks[1], 0, 2) + feed('0llkr1') + check_undo_redo(ns, marks[1], 0, 2, 0, 3) + end) + + it('shift line', function() + -- shift_line in ops.c + feed(':set shiftwidth=4') + set_extmark(ns, marks[1], 0, 2) + feed('0>>') + check_undo_redo(ns, marks[1], 0, 2, 0, 6) + expect(' 12345') + + feed('>>') + -- this is counter-intuitive. But what happens + -- is that 4 spaces gets extended to one tab (== 8 spaces) + check_undo_redo(ns, marks[1], 0, 6, 0, 3) + expect('\t12345') + + feed('') -- have to escape, same as << + check_undo_redo(ns, marks[1], 0, 3, 0, 6) + end) + + it('blockwise shift', function() + -- shift_block in ops.c + feed(':set shiftwidth=4') + feed('a12345') + set_extmark(ns, marks[1], 1, 2) + feed('0k>') + check_undo_redo(ns, marks[1], 1, 2, 1, 6) + feed('j>') + expect('\t12345\n\t12345') + check_undo_redo(ns, marks[1], 1, 6, 1, 3) + + feed('j') + check_undo_redo(ns, marks[1], 1, 3, 1, 6) + end) + + it('tab works with expandtab', function() + -- ins_tab in edit.c + feed(':set expandtab') + feed(':set shiftwidth=2') + set_extmark(ns, marks[1], 0, 2) + feed('0i') + check_undo_redo(ns, marks[1], 0, 2, 0, 6) + end) + + it('tabs work', function() + -- ins_tab in edit.c + feed(':set noexpandtab') + feed(':set shiftwidth=2') + feed(':set softtabstop=2') + feed(':set tabstop=8') + set_extmark(ns, marks[1], 0, 2) + feed('0i') + check_undo_redo(ns, marks[1], 0, 2, 0, 4) + feed('0iX') + check_undo_redo(ns, marks[1], 0, 4, 0, 6) + end) + + it('marks move when using :move', function() + set_extmark(ns, marks[1], 0, 0) + feed('A2:1move 2') + check_undo_redo(ns, marks[1], 0, 0, 1, 0) + -- test codepath when moving lines up + feed(':2move 0') + check_undo_redo(ns, marks[1], 1, 0, 0, 0) + end) + + it('marks move when using :move part 2', function() + -- make sure we didn't get lucky with the math... + feed('A23456') + set_extmark(ns, marks[1], 1, 0) + feed(':2,3move 5') + check_undo_redo(ns, marks[1], 1, 0, 3, 0) + -- test codepath when moving lines up + feed(':4,5move 1') + check_undo_redo(ns, marks[1], 3, 0, 1, 0) + end) + + it('undo and redo of set and unset marks', function() + -- Force a new undo head + feed('o') + set_extmark(ns, marks[1], 0, 1) + feed('o') + set_extmark(ns, marks[2], 0, -1) + set_extmark(ns, marks[3], 0, -1) + + feed("u") + local rv = get_extmarks(ns, {0, 0}, {-1, -1}) + eq(3, table.getn(rv)) + + feed("") + rv = get_extmarks(ns, {0, 0}, {-1, -1}) + eq(3, table.getn(rv)) + + -- Test updates + feed('o') + set_extmark(ns, marks[1], positions[1][1], positions[1][2]) + rv = get_extmarks(ns, marks[1], marks[1], {limit=1}) + eq(1, table.getn(rv)) + feed("u") + feed("") + -- old value is NOT kept in history + check_undo_redo(ns, marks[1], positions[1][1], positions[1][2], positions[1][1], positions[1][2]) + + -- Test unset + feed('o') + curbufmeths.del_extmark(ns, marks[3]) + feed("u") + rv = get_extmarks(ns, {0, 0}, {-1, -1}) + -- undo does NOT restore deleted marks + eq(2, table.getn(rv)) + feed("") + rv = get_extmarks(ns, {0, 0}, {-1, -1}) + eq(2, table.getn(rv)) + end) + + it('undo and redo of marks deleted during edits', function() + -- test extmark_adjust + feed('A12345') + set_extmark(ns, marks[1], 1, 2) + feed('dd') + check_undo_redo(ns, marks[1], 1, 2, 1, 0) + end) + + it('namespaces work properly', function() + local rv = set_extmark(ns, marks[1], positions[1][1], positions[1][2]) + eq(1, rv) + rv = set_extmark(ns2, marks[1], positions[1][1], positions[1][2]) + eq(1, rv) + rv = get_extmarks(ns, {0, 0}, {-1, -1}) + eq(1, table.getn(rv)) + rv = get_extmarks(ns2, {0, 0}, {-1, -1}) + eq(1, table.getn(rv)) + + -- Set more marks for testing the ranges + set_extmark(ns, marks[2], positions[2][1], positions[2][2]) + set_extmark(ns, marks[3], positions[3][1], positions[3][2]) + set_extmark(ns2, marks[2], positions[2][1], positions[2][2]) + set_extmark(ns2, marks[3], positions[3][1], positions[3][2]) + + -- get_next (limit set) + rv = get_extmarks(ns, {0, 0}, positions[2], {limit=1}) + eq(1, table.getn(rv)) + rv = get_extmarks(ns2, {0, 0}, positions[2], {limit=1}) + eq(1, table.getn(rv)) + -- get_prev (limit set) + rv = get_extmarks(ns, positions[1], {0, 0}, {limit=1}) + eq(1, table.getn(rv)) + rv = get_extmarks(ns2, positions[1], {0, 0}, {limit=1}) + eq(1, table.getn(rv)) + + -- get_next (no limit) + rv = get_extmarks(ns, positions[1], positions[2]) + eq(2, table.getn(rv)) + rv = get_extmarks(ns2, positions[1], positions[2]) + eq(2, table.getn(rv)) + -- get_prev (no limit) + rv = get_extmarks(ns, positions[2], positions[1]) + eq(2, table.getn(rv)) + rv = get_extmarks(ns2, positions[2], positions[1]) + eq(2, table.getn(rv)) + + curbufmeths.del_extmark(ns, marks[1]) + rv = get_extmarks(ns, {0, 0}, {-1, -1}) + eq(2, table.getn(rv)) + curbufmeths.del_extmark(ns2, marks[1]) + rv = get_extmarks(ns2, {0, 0}, {-1, -1}) + eq(2, table.getn(rv)) + end) + + it('mark set can create unique identifiers', function() + -- create mark with id 1 + eq(1, set_extmark(ns, 1, positions[1][1], positions[1][2])) + -- ask for unique id, it should be the next one, i e 2 + eq(2, set_extmark(ns, 0, positions[1][1], positions[1][2])) + eq(3, set_extmark(ns, 3, positions[2][1], positions[2][2])) + eq(4, set_extmark(ns, 0, positions[1][1], positions[1][2])) + + -- mixing manual and allocated id:s are not recommened, but it should + -- do something reasonable + eq(6, set_extmark(ns, 6, positions[2][1], positions[2][2])) + eq(7, set_extmark(ns, 0, positions[1][1], positions[1][2])) + eq(8, set_extmark(ns, 0, positions[1][1], positions[1][2])) + end) + + it('auto indenting with enter works', function() + -- op_reindent in ops.c + feed(':set cindent') + feed(':set autoindent') + feed(':set shiftwidth=2') + feed("0iint A {1M1b") + -- Set the mark on the M, should move.. + set_extmark(ns, marks[1], 0, 12) + -- Set the mark before the cursor, should stay there + set_extmark(ns, marks[2], 0, 10) + feed("i") + local rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + eq({1, 3}, rv) + rv = curbufmeths.get_extmark_by_id(ns, marks[2]) + eq({0, 10}, rv) + check_undo_redo(ns, marks[1], 0, 12, 1, 3) + end) + + it('auto indenting entire line works', function() + feed(':set cindent') + feed(':set autoindent') + feed(':set shiftwidth=2') + -- will force an indent of 2 + feed("0iint A {0i1M1") + set_extmark(ns, marks[1], 1, 1) + feed("0i") + local rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + eq({1, 3}, rv) + check_undo_redo(ns, marks[1], 1, 1, 1, 3) + -- now check when cursor at eol + feed("uA") + rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + eq({1, 3}, rv) + end) + + it('removing auto indenting with works', function() + feed(':set cindent') + feed(':set autoindent') + feed(':set shiftwidth=2') + feed("0i") + set_extmark(ns, marks[1], 0, 3) + feed("bi") + local rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + eq({0, 1}, rv) + check_undo_redo(ns, marks[1], 0, 3, 0, 1) + -- check when cursor at eol + feed("uA") + rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + eq({0, 1}, rv) + end) + + it('indenting multiple lines with = works', function() + feed(':set cindent') + feed(':set autoindent') + feed(':set shiftwidth=2') + feed("0iint A {1M12M2") + set_extmark(ns, marks[1], 1, 1) + set_extmark(ns, marks[2], 2, 1) + feed('=gg') + check_undo_redo(ns, marks[1], 1, 1, 1, 3) + check_undo_redo(ns, marks[2], 2, 1, 2, 5) + end) + + it('substitutes by deleting inside the replace matches', function() + -- do_sub in ex_cmds.c + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 0, 3) + feed(':s/34/xx') + check_undo_redo(ns, marks[1], 0, 2, 0, 4) + check_undo_redo(ns, marks[2], 0, 3, 0, 4) + end) + + it('substitutes when insert text > deleted', function() + -- do_sub in ex_cmds.c + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 0, 3) + feed(':s/34/xxx') + check_undo_redo(ns, marks[1], 0, 2, 0, 5) + check_undo_redo(ns, marks[2], 0, 3, 0, 5) + end) + + it('substitutes when marks around eol', function() + -- do_sub in ex_cmds.c + set_extmark(ns, marks[1], 0, 4) + set_extmark(ns, marks[2], 0, 5) + feed(':s/5/xxx') + check_undo_redo(ns, marks[1], 0, 4, 0, 7) + check_undo_redo(ns, marks[2], 0, 5, 0, 7) + end) + + it('substitutes over range insert text > deleted', function() + -- do_sub in ex_cmds.c + feed('Ax34xx') + feed('Axxx34') + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 1, 1) + set_extmark(ns, marks[3], 2, 4) + feed(':1,3s/34/xxx') + check_undo_redo(ns, marks[1], 0, 2, 0, 5) + check_undo_redo(ns, marks[2], 1, 1, 1, 4) + check_undo_redo(ns, marks[3], 2, 4, 2, 6) + end) + + it('substitutes multiple matches in a line', function() + -- do_sub in ex_cmds.c + feed('ddi3x3x3') + set_extmark(ns, marks[1], 0, 0) + set_extmark(ns, marks[2], 0, 2) + set_extmark(ns, marks[3], 0, 4) + feed(':s/3/yy/g') + check_undo_redo(ns, marks[1], 0, 0, 0, 2) + check_undo_redo(ns, marks[2], 0, 2, 0, 5) + check_undo_redo(ns, marks[3], 0, 4, 0, 8) + end) + + it('substitions over multiple lines with newline in pattern', function() + feed('A67890xx') + set_extmark(ns, marks[1], 0, 3) + set_extmark(ns, marks[2], 0, 4) + set_extmark(ns, marks[3], 1, 0) + set_extmark(ns, marks[4], 1, 5) + set_extmark(ns, marks[5], 2, 0) + feed([[:1,2s:5\n:5 ]]) + check_undo_redo(ns, marks[1], 0, 3, 0, 3) + check_undo_redo(ns, marks[2], 0, 4, 0, 6) + check_undo_redo(ns, marks[3], 1, 0, 0, 6) + check_undo_redo(ns, marks[4], 1, 5, 0, 11) + check_undo_redo(ns, marks[5], 2, 0, 1, 0) + end) + + it('inserting', function() + feed('A67890xx') + set_extmark(ns, marks[1], 0, 3) + set_extmark(ns, marks[2], 0, 4) + set_extmark(ns, marks[3], 1, 0) + set_extmark(ns, marks[4], 1, 5) + set_extmark(ns, marks[5], 2, 0) + set_extmark(ns, marks[6], 1, 2) + feed([[:1,2s:5\n67:X]]) + check_undo_redo(ns, marks[1], 0, 3, 0, 3) + check_undo_redo(ns, marks[2], 0, 4, 0, 5) + check_undo_redo(ns, marks[3], 1, 0, 0, 5) + check_undo_redo(ns, marks[4], 1, 5, 0, 8) + check_undo_redo(ns, marks[5], 2, 0, 1, 0) + check_undo_redo(ns, marks[6], 1, 2, 0, 5) + end) + + it('substitions with multiple newlines in pattern', function() + feed('A67890xx') + set_extmark(ns, marks[1], 0, 4) + set_extmark(ns, marks[2], 0, 5) + set_extmark(ns, marks[3], 1, 0) + set_extmark(ns, marks[4], 1, 5) + set_extmark(ns, marks[5], 2, 0) + feed([[:1,2s:\n.*\n:X]]) + check_undo_redo(ns, marks[1], 0, 4, 0, 4) + check_undo_redo(ns, marks[2], 0, 5, 0, 6) + check_undo_redo(ns, marks[3], 1, 0, 0, 6) + check_undo_redo(ns, marks[4], 1, 5, 0, 6) + check_undo_redo(ns, marks[5], 2, 0, 0, 6) + end) + + it('substitions over multiple lines with replace in substition', function() + feed('A67890xx') + set_extmark(ns, marks[1], 0, 1) + set_extmark(ns, marks[2], 0, 2) + set_extmark(ns, marks[3], 0, 4) + set_extmark(ns, marks[4], 1, 0) + set_extmark(ns, marks[5], 2, 0) + feed([[:1,2s:3:\r]]) + check_undo_redo(ns, marks[1], 0, 1, 0, 1) + check_undo_redo(ns, marks[2], 0, 2, 1, 0) + check_undo_redo(ns, marks[3], 0, 4, 1, 1) + check_undo_redo(ns, marks[4], 1, 0, 2, 0) + check_undo_redo(ns, marks[5], 2, 0, 3, 0) + feed('u') + feed([[:1,2s:3:\rxx]]) + eq({1, 3}, curbufmeths.get_extmark_by_id(ns, marks[3])) + end) + + it('substitions over multiple lines with replace in substition', function() + feed('Ax3xx') + set_extmark(ns, marks[1], 1, 0) + set_extmark(ns, marks[2], 1, 1) + set_extmark(ns, marks[3], 1, 2) + feed([[:2,2s:3:\r]]) + check_undo_redo(ns, marks[1], 1, 0, 1, 0) + check_undo_redo(ns, marks[2], 1, 1, 2, 0) + check_undo_redo(ns, marks[3], 1, 2, 2, 0) + end) + + it('substitions over multiple lines with replace in substition', function() + feed('Ax3xx') + set_extmark(ns, marks[1], 0, 1) + set_extmark(ns, marks[2], 0, 2) + set_extmark(ns, marks[3], 0, 4) + set_extmark(ns, marks[4], 1, 1) + set_extmark(ns, marks[5], 2, 0) + feed([[:1,2s:3:\r]]) + check_undo_redo(ns, marks[1], 0, 1, 0, 1) + check_undo_redo(ns, marks[2], 0, 2, 1, 0) + check_undo_redo(ns, marks[3], 0, 4, 1, 1) + check_undo_redo(ns, marks[4], 1, 1, 3, 0) + check_undo_redo(ns, marks[5], 2, 0, 4, 0) + feed('u') + feed([[:1,2s:3:\rxx]]) + check_undo_redo(ns, marks[3], 0, 4, 1, 3) + end) + + it('substitions with newline in match and sub, delta is 0', function() + feed('A67890xx') + set_extmark(ns, marks[1], 0, 3) + set_extmark(ns, marks[2], 0, 4) + set_extmark(ns, marks[3], 0, 5) + set_extmark(ns, marks[4], 1, 0) + set_extmark(ns, marks[5], 1, 5) + set_extmark(ns, marks[6], 2, 0) + feed([[:1,1s:5\n:\r]]) + check_undo_redo(ns, marks[1], 0, 3, 0, 3) + check_undo_redo(ns, marks[2], 0, 4, 1, 0) + check_undo_redo(ns, marks[3], 0, 5, 1, 0) + check_undo_redo(ns, marks[4], 1, 0, 1, 0) + check_undo_redo(ns, marks[5], 1, 5, 1, 5) + check_undo_redo(ns, marks[6], 2, 0, 2, 0) + end) + + it('substitions with newline in match and sub, delta > 0', function() + feed('A67890xx') + set_extmark(ns, marks[1], 0, 3) + set_extmark(ns, marks[2], 0, 4) + set_extmark(ns, marks[3], 0, 5) + set_extmark(ns, marks[4], 1, 0) + set_extmark(ns, marks[5], 1, 5) + set_extmark(ns, marks[6], 2, 0) + feed([[:1,1s:5\n:\r\r]]) + check_undo_redo(ns, marks[1], 0, 3, 0, 3) + check_undo_redo(ns, marks[2], 0, 4, 2, 0) + check_undo_redo(ns, marks[3], 0, 5, 2, 0) + check_undo_redo(ns, marks[4], 1, 0, 2, 0) + check_undo_redo(ns, marks[5], 1, 5, 2, 5) + check_undo_redo(ns, marks[6], 2, 0, 3, 0) + end) + + it('substitions with newline in match and sub, delta < 0', function() + feed('A67890xxxx') + set_extmark(ns, marks[1], 0, 3) + set_extmark(ns, marks[2], 0, 4) + set_extmark(ns, marks[3], 0, 5) + set_extmark(ns, marks[4], 1, 0) + set_extmark(ns, marks[5], 1, 5) + set_extmark(ns, marks[6], 2, 1) + set_extmark(ns, marks[7], 3, 0) + feed([[:1,2s:5\n.*\n:\r]]) + check_undo_redo(ns, marks[1], 0, 3, 0, 3) + check_undo_redo(ns, marks[2], 0, 4, 1, 0) + check_undo_redo(ns, marks[3], 0, 5, 1, 0) + check_undo_redo(ns, marks[4], 1, 0, 1, 0) + check_undo_redo(ns, marks[5], 1, 5, 1, 0) + check_undo_redo(ns, marks[6], 2, 1, 1, 1) + check_undo_redo(ns, marks[7], 3, 0, 2, 0) + end) + + it('substitions with backrefs, newline inserted into sub', function() + feed('A67890xxxx') + set_extmark(ns, marks[1], 0, 3) + set_extmark(ns, marks[2], 0, 4) + set_extmark(ns, marks[3], 0, 5) + set_extmark(ns, marks[4], 1, 0) + set_extmark(ns, marks[5], 1, 5) + set_extmark(ns, marks[6], 2, 0) + feed([[:1,1s:5\(\n\):\0\1]]) + check_undo_redo(ns, marks[1], 0, 3, 0, 3) + check_undo_redo(ns, marks[2], 0, 4, 2, 0) + check_undo_redo(ns, marks[3], 0, 5, 2, 0) + check_undo_redo(ns, marks[4], 1, 0, 2, 0) + check_undo_redo(ns, marks[5], 1, 5, 2, 5) + check_undo_redo(ns, marks[6], 2, 0, 3, 0) + end) + + it('substitions a ^', function() + set_extmark(ns, marks[1], 0, 0) + set_extmark(ns, marks[2], 0, 1) + feed([[:s:^:x]]) + check_undo_redo(ns, marks[1], 0, 0, 0, 1) + check_undo_redo(ns, marks[2], 0, 1, 0, 2) + end) + + it('using without increase in order of magnitude', function() + -- do_addsub in ops.c + feed('ddiabc998xxxTc') + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 0, 3) + set_extmark(ns, marks[3], 0, 5) + set_extmark(ns, marks[4], 0, 6) + set_extmark(ns, marks[5], 0, 7) + feed('') + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + check_undo_redo(ns, marks[2], 0, 3, 0, 6) + check_undo_redo(ns, marks[3], 0, 5, 0, 6) + check_undo_redo(ns, marks[4], 0, 6, 0, 6) + check_undo_redo(ns, marks[5], 0, 7, 0, 7) + end) + + it('using when increase in order of magnitude', function() + -- do_addsub in ops.c + feed('ddiabc999xxxTc') + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 0, 3) + set_extmark(ns, marks[3], 0, 5) + set_extmark(ns, marks[4], 0, 6) + set_extmark(ns, marks[5], 0, 7) + feed('') + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + check_undo_redo(ns, marks[2], 0, 3, 0, 7) + check_undo_redo(ns, marks[3], 0, 5, 0, 7) + check_undo_redo(ns, marks[4], 0, 6, 0, 7) + check_undo_redo(ns, marks[5], 0, 7, 0, 8) + end) + + it('using when negative and without decrease in order of magnitude', function() + feed('ddiabc-999xxxT-') + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 0, 3) + set_extmark(ns, marks[3], 0, 6) + set_extmark(ns, marks[4], 0, 7) + set_extmark(ns, marks[5], 0, 8) + feed('') + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + check_undo_redo(ns, marks[2], 0, 3, 0, 7) + check_undo_redo(ns, marks[3], 0, 6, 0, 7) + check_undo_redo(ns, marks[4], 0, 7, 0, 7) + check_undo_redo(ns, marks[5], 0, 8, 0, 8) + end) + + it('using when negative and decrease in order of magnitude', function() + feed('ddiabc-1000xxxT-') + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 0, 3) + set_extmark(ns, marks[3], 0, 7) + set_extmark(ns, marks[4], 0, 8) + set_extmark(ns, marks[5], 0, 9) + feed('') + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + check_undo_redo(ns, marks[2], 0, 3, 0, 7) + check_undo_redo(ns, marks[3], 0, 7, 0, 7) + check_undo_redo(ns, marks[4], 0, 8, 0, 7) + check_undo_redo(ns, marks[5], 0, 9, 0, 8) + end) + + it('using without decrease in order of magnitude', function() + -- do_addsub in ops.c + feed('ddiabc999xxxTc') + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 0, 3) + set_extmark(ns, marks[3], 0, 5) + set_extmark(ns, marks[4], 0, 6) + set_extmark(ns, marks[5], 0, 7) + feed('') + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + check_undo_redo(ns, marks[2], 0, 3, 0, 6) + check_undo_redo(ns, marks[3], 0, 5, 0, 6) + check_undo_redo(ns, marks[4], 0, 6, 0, 6) + check_undo_redo(ns, marks[5], 0, 7, 0, 7) + end) + + it('using when decrease in order of magnitude', function() + -- do_addsub in ops.c + feed('ddiabc1000xxxTc') + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 0, 3) + set_extmark(ns, marks[3], 0, 6) + set_extmark(ns, marks[4], 0, 7) + set_extmark(ns, marks[5], 0, 8) + feed('') + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + check_undo_redo(ns, marks[2], 0, 3, 0, 6) + check_undo_redo(ns, marks[3], 0, 6, 0, 6) + check_undo_redo(ns, marks[4], 0, 7, 0, 6) + check_undo_redo(ns, marks[5], 0, 8, 0, 7) + end) + + it('using when negative and without increase in order of magnitude', function() + feed('ddiabc-998xxxT-') + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 0, 3) + set_extmark(ns, marks[3], 0, 6) + set_extmark(ns, marks[4], 0, 7) + set_extmark(ns, marks[5], 0, 8) + feed('') + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + check_undo_redo(ns, marks[2], 0, 3, 0, 7) + check_undo_redo(ns, marks[3], 0, 6, 0, 7) + check_undo_redo(ns, marks[4], 0, 7, 0, 7) + check_undo_redo(ns, marks[5], 0, 8, 0, 8) + end) + + it('using when negative and increase in order of magnitude', function() + feed('ddiabc-999xxxT-') + set_extmark(ns, marks[1], 0, 2) + set_extmark(ns, marks[2], 0, 3) + set_extmark(ns, marks[3], 0, 6) + set_extmark(ns, marks[4], 0, 7) + set_extmark(ns, marks[5], 0, 8) + feed('') + check_undo_redo(ns, marks[1], 0, 2, 0, 2) + check_undo_redo(ns, marks[2], 0, 3, 0, 8) + check_undo_redo(ns, marks[3], 0, 6, 0, 8) + check_undo_redo(ns, marks[4], 0, 7, 0, 8) + check_undo_redo(ns, marks[5], 0, 8, 0, 9) + end) + + it('throws consistent error codes', function() + local ns_invalid = ns2 + 1 + eq("Invalid ns_id", pcall_err(set_extmark, ns_invalid, marks[1], positions[1][1], positions[1][2])) + eq("Invalid ns_id", pcall_err(curbufmeths.del_extmark, ns_invalid, marks[1])) + eq("Invalid ns_id", pcall_err(get_extmarks, ns_invalid, positions[1], positions[2])) + eq("Invalid ns_id", pcall_err(curbufmeths.get_extmark_by_id, ns_invalid, marks[1])) + end) + + it('when col = line-length, set the mark on eol', function() + set_extmark(ns, marks[1], 0, -1) + local rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + eq({0, init_text:len()}, rv) + -- Test another + set_extmark(ns, marks[1], 0, -1) + rv = curbufmeths.get_extmark_by_id(ns, marks[1]) + eq({0, init_text:len()}, rv) + end) + + it('when col = line-length, set the mark on eol', function() + local invalid_col = init_text:len() + 1 + eq("col value outside range", pcall_err(set_extmark, ns, marks[1], 0, invalid_col)) + end) + + it('fails when line > line_count', function() + local invalid_col = init_text:len() + 1 + local invalid_lnum = 3 + eq('line value outside range', pcall_err(set_extmark, ns, marks[1], invalid_lnum, invalid_col)) + eq({}, curbufmeths.get_extmark_by_id(ns, marks[1])) + end) + + it('bug from check_col in extmark_set', function() + -- This bug was caused by extmark_set always using check_col. check_col + -- always uses the current buffer. This wasn't working during undo so we + -- now use check_col and check_lnum only when they are required. + feed('A67890xx') + feed('A1234567890xx') + set_extmark(ns, marks[1], 3, 4) + feed([[:1,5s:5\n:5 ]]) + check_undo_redo(ns, marks[1], 3, 4, 2, 6) + end) + + it('in read-only buffer', function() + command("view! runtime/doc/help.txt") + eq(true, curbufmeths.get_option('ro')) + local id = set_extmark(ns, 0, 0, 2) + eq({{id, 0, 2}}, get_extmarks(ns,0, -1)) + end) + + it('can set a mark to other buffer', function() + local buf = request('nvim_create_buf', 0, 1) + request('nvim_buf_set_lines', buf, 0, -1, 1, {"", ""}) + local id = bufmeths.set_extmark(buf, ns, 0, 1, 0, {}) + eq({{id, 1, 0}}, bufmeths.get_extmarks(buf, ns, 0, -1, {})) + end) + + it('does not crash with append/delete/undo seqence', function() + meths.exec([[ + let ns = nvim_create_namespace('myplugin') + call nvim_buf_set_extmark(0, ns, 0, 0, 0, {}) + call append(0, '') + %delete + undo]],false) + eq(2, meths.eval('1+1')) -- did not crash + end) +end) + +describe('Extmarks buffer api with many marks', function() + local ns1 + local ns2 + local ns_marks = {} + before_each(function() + clear() + ns1 = request('nvim_create_namespace', "ns1") + ns2 = request('nvim_create_namespace', "ns2") + ns_marks = {[ns1]={}, [ns2]={}} + local lines = {} + for i = 1,30 do + lines[#lines+1] = string.rep("x ",i) + end + curbufmeths.set_lines(0, -1, true, lines) + local ns = ns1 + local q = 0 + for i = 0,29 do + for j = 0,i do + local id = set_extmark(ns,0, i,j) + eq(nil, ns_marks[ns][id]) + ok(id > 0) + ns_marks[ns][id] = {i,j} + ns = ns1+ns2-ns + q = q + 1 + end + end + eq(233, #ns_marks[ns1]) + eq(232, #ns_marks[ns2]) + + end) + + local function get_marks(ns) + local mark_list = get_extmarks(ns, 0, -1) + local marks = {} + for _, mark in ipairs(mark_list) do + local id, row, col = unpack(mark) + eq(nil, marks[id], "duplicate mark") + marks[id] = {row,col} + end + return marks + end + + it("can get marks", function() + eq(ns_marks[ns1], get_marks(ns1)) + eq(ns_marks[ns2], get_marks(ns2)) + end) + + it("can clear all marks in ns", function() + curbufmeths.clear_namespace(ns1, 0, -1) + eq({}, get_marks(ns1)) + eq(ns_marks[ns2], get_marks(ns2)) + curbufmeths.clear_namespace(ns2, 0, -1) + eq({}, get_marks(ns1)) + eq({}, get_marks(ns2)) + end) + + it("can clear line range", function() + curbufmeths.clear_namespace(ns1, 10, 20) + for id, mark in pairs(ns_marks[ns1]) do + if 10 <= mark[1] and mark[1] < 20 then + ns_marks[ns1][id] = nil + end + end + eq(ns_marks[ns1], get_marks(ns1)) + eq(ns_marks[ns2], get_marks(ns2)) + end) + + it("can delete line", function() + feed('10Gdd') + for _, marks in pairs(ns_marks) do + for id, mark in pairs(marks) do + if mark[1] == 9 then + marks[id] = {9,0} + elseif mark[1] >= 10 then + mark[1] = mark[1] - 1 + end + end + end + eq(ns_marks[ns1], get_marks(ns1)) + eq(ns_marks[ns2], get_marks(ns2)) + end) + + it("can delete lines", function() + feed('10G10dd') + for _, marks in pairs(ns_marks) do + for id, mark in pairs(marks) do + if 9 <= mark[1] and mark[1] < 19 then + marks[id] = {9,0} + elseif mark[1] >= 19 then + mark[1] = mark[1] - 10 + end + end + end + eq(ns_marks[ns1], get_marks(ns1)) + eq(ns_marks[ns2], get_marks(ns2)) + end) + + it("can wipe buffer", function() + command('bwipe!') + eq({}, get_marks(ns1)) + eq({}, get_marks(ns2)) + end) +end) diff --git a/test/functional/api/mark_extended_spec.lua b/test/functional/api/mark_extended_spec.lua deleted file mode 100644 index 8aa8ed07c5..0000000000 --- a/test/functional/api/mark_extended_spec.lua +++ /dev/null @@ -1,1478 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local Screen = require('test.functional.ui.screen') - -local request = helpers.request -local eq = helpers.eq -local ok = helpers.ok -local curbufmeths = helpers.curbufmeths -local bufmeths = helpers.bufmeths -local pcall_err = helpers.pcall_err -local insert = helpers.insert -local feed = helpers.feed -local clear = helpers.clear -local command = helpers.command -local meths = helpers.meths - -local function expect(contents) - return eq(contents, helpers.curbuf_contents()) -end - -local function check_undo_redo(ns, mark, sr, sc, er, ec) --s = start, e = end - local rv = curbufmeths.get_extmark_by_id(ns, mark) - eq({er, ec}, rv) - feed("u") - rv = curbufmeths.get_extmark_by_id(ns, mark) - eq({sr, sc}, rv) - feed("") - rv = curbufmeths.get_extmark_by_id(ns, mark) - eq({er, ec}, rv) -end - -local function set_extmark(ns_id, id, line, col, opts) - if opts == nil then - opts = {} - end - return curbufmeths.set_extmark(ns_id, id, line, col, opts) -end - -local function get_extmarks(ns_id, start, end_, opts) - if opts == nil then - opts = {} - end - return curbufmeths.get_extmarks(ns_id, start, end_, opts) -end - -local function batch_set(ns_id, positions) - local ids = {} - for _, pos in ipairs(positions) do - table.insert(ids, set_extmark(ns_id, 0, pos[1], pos[2])) - end - return ids -end - -local function batch_check(ns_id, ids, positions) - local actual, expected = {}, {} - for i,id in ipairs(ids) do - expected[id] = positions[i] - end - for _, mark in pairs(get_extmarks(ns_id, 0, -1, {})) do - actual[mark[1]] = {mark[2], mark[3]} - end - eq(expected, actual) -end - -local function batch_check_undo_redo(ns_id, ids, before, after) - batch_check(ns_id, ids, after) - feed("u") - batch_check(ns_id, ids, before) - feed("") - batch_check(ns_id, ids, after) -end - -describe('API/extmarks', function() - local screen - local marks, positions, init_text, row, col - local ns, ns2 - - before_each(function() - -- Initialize some namespaces and insert 12345 into a buffer - marks = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} - positions = {{0, 0,}, {0, 2}, {0, 3}} - - init_text = "12345" - row = 0 - col = 2 - - clear() - - insert(init_text) - ns = request('nvim_create_namespace', "my-fancy-plugin") - ns2 = request('nvim_create_namespace', "my-fancy-plugin2") - end) - - it('adds, updates and deletes marks', function() - local rv = set_extmark(ns, marks[1], positions[1][1], positions[1][2]) - eq(marks[1], rv) - rv = curbufmeths.get_extmark_by_id(ns, marks[1]) - eq({positions[1][1], positions[1][2]}, rv) - -- Test adding a second mark on same row works - rv = set_extmark(ns, marks[2], positions[2][1], positions[2][2]) - eq(marks[2], rv) - - -- Test an update, (same pos) - rv = set_extmark(ns, marks[1], positions[1][1], positions[1][2]) - eq(marks[1], rv) - rv = curbufmeths.get_extmark_by_id(ns, marks[2]) - eq({positions[2][1], positions[2][2]}, rv) - -- Test an update, (new pos) - row = positions[1][1] - col = positions[1][2] + 1 - rv = set_extmark(ns, marks[1], row, col) - eq(marks[1], rv) - rv = curbufmeths.get_extmark_by_id(ns, marks[1]) - eq({row, col}, rv) - - -- remove the test marks - eq(true, curbufmeths.del_extmark(ns, marks[1])) - eq(false, curbufmeths.del_extmark(ns, marks[1])) - eq(true, curbufmeths.del_extmark(ns, marks[2])) - eq(false, curbufmeths.del_extmark(ns, marks[3])) - eq(false, curbufmeths.del_extmark(ns, 1000)) - end) - - it('can clear a specific namespace range', function() - set_extmark(ns, 1, 0, 1) - set_extmark(ns2, 1, 0, 1) - -- force a new undo buffer - feed('o') - curbufmeths.clear_namespace(ns2, 0, -1) - eq({{1, 0, 1}}, get_extmarks(ns, {0, 0}, {-1, -1})) - eq({}, get_extmarks(ns2, {0, 0}, {-1, -1})) - feed('u') - eq({{1, 0, 1}}, get_extmarks(ns, {0, 0}, {-1, -1})) - eq({}, get_extmarks(ns2, {0, 0}, {-1, -1})) - feed('') - eq({{1, 0, 1}}, get_extmarks(ns, {0, 0}, {-1, -1})) - eq({}, get_extmarks(ns2, {0, 0}, {-1, -1})) - end) - - it('can clear a namespace range using 0,-1', function() - set_extmark(ns, 1, 0, 1) - set_extmark(ns2, 1, 0, 1) - -- force a new undo buffer - feed('o') - curbufmeths.clear_namespace(-1, 0, -1) - eq({}, get_extmarks(ns, {0, 0}, {-1, -1})) - eq({}, get_extmarks(ns2, {0, 0}, {-1, -1})) - feed('u') - eq({}, get_extmarks(ns, {0, 0}, {-1, -1})) - eq({}, get_extmarks(ns2, {0, 0}, {-1, -1})) - feed('') - eq({}, get_extmarks(ns, {0, 0}, {-1, -1})) - eq({}, get_extmarks(ns2, {0, 0}, {-1, -1})) - end) - - it('querying for information and ranges', function() - --marks = {1, 2, 3} - --positions = {{0, 0,}, {0, 2}, {0, 3}} - -- add some more marks - for i, m in ipairs(marks) do - if positions[i] ~= nil then - local rv = set_extmark(ns, m, positions[i][1], positions[i][2]) - eq(m, rv) - end - end - - -- {0, 0} and {-1, -1} work as extreme values - eq({{1, 0, 0}}, get_extmarks(ns, {0, 0}, {0, 0})) - eq({}, get_extmarks(ns, {-1, -1}, {-1, -1})) - local rv = get_extmarks(ns, {0, 0}, {-1, -1}) - for i, m in ipairs(marks) do - if positions[i] ~= nil then - eq({m, positions[i][1], positions[i][2]}, rv[i]) - end - end - - -- 0 and -1 works as short hand extreme values - eq({{1, 0, 0}}, get_extmarks(ns, 0, 0)) - eq({}, get_extmarks(ns, -1, -1)) - rv = get_extmarks(ns, 0, -1) - for i, m in ipairs(marks) do - if positions[i] ~= nil then - eq({m, positions[i][1], positions[i][2]}, rv[i]) - end - end - - -- next with mark id - rv = get_extmarks(ns, marks[1], {-1, -1}, {limit=1}) - eq({{marks[1], positions[1][1], positions[1][2]}}, rv) - rv = get_extmarks(ns, marks[2], {-1, -1}, {limit=1}) - eq({{marks[2], positions[2][1], positions[2][2]}}, rv) - -- next with positional when mark exists at position - rv = get_extmarks(ns, positions[1], {-1, -1}, {limit=1}) - eq({{marks[1], positions[1][1], positions[1][2]}}, rv) - -- next with positional index (no mark at position) - rv = get_extmarks(ns, {positions[1][1], positions[1][2] +1}, {-1, -1}, {limit=1}) - eq({{marks[2], positions[2][1], positions[2][2]}}, rv) - -- next with Extremity index - rv = get_extmarks(ns, {0,0}, {-1, -1}, {limit=1}) - eq({{marks[1], positions[1][1], positions[1][2]}}, rv) - - -- nextrange with mark id - rv = get_extmarks(ns, marks[1], marks[3]) - eq({marks[1], positions[1][1], positions[1][2]}, rv[1]) - eq({marks[2], positions[2][1], positions[2][2]}, rv[2]) - -- nextrange with `limit` - rv = get_extmarks(ns, marks[1], marks[3], {limit=2}) - eq(2, table.getn(rv)) - -- nextrange with positional when mark exists at position - rv = get_extmarks(ns, positions[1], positions[3]) - eq({marks[1], positions[1][1], positions[1][2]}, rv[1]) - eq({marks[2], positions[2][1], positions[2][2]}, rv[2]) - rv = get_extmarks(ns, positions[2], positions[3]) - eq(2, table.getn(rv)) - -- nextrange with positional index (no mark at position) - local lower = {positions[1][1], positions[2][2] -1} - local upper = {positions[2][1], positions[3][2] - 1} - rv = get_extmarks(ns, lower, upper) - eq({{marks[2], positions[2][1], positions[2][2]}}, rv) - lower = {positions[3][1], positions[3][2] + 1} - upper = {positions[3][1], positions[3][2] + 2} - rv = get_extmarks(ns, lower, upper) - eq({}, rv) - -- nextrange with extremity index - lower = {positions[2][1], positions[2][2]+1} - upper = {-1, -1} - rv = get_extmarks(ns, lower, upper) - eq({{marks[3], positions[3][1], positions[3][2]}}, rv) - - -- prev with mark id - rv = get_extmarks(ns, marks[3], {0, 0}, {limit=1}) - eq({{marks[3], positions[3][1], positions[3][2]}}, rv) - rv = get_extmarks(ns, marks[2], {0, 0}, {limit=1}) - eq({{marks[2], positions[2][1], positions[2][2]}}, rv) - -- prev with positional when mark exists at position - rv = get_extmarks(ns, positions[3], {0, 0}, {limit=1}) - eq({{marks[3], positions[3][1], positions[3][2]}}, rv) - -- prev with positional index (no mark at position) - rv = get_extmarks(ns, {positions[1][1], positions[1][2] +1}, {0, 0}, {limit=1}) - eq({{marks[1], positions[1][1], positions[1][2]}}, rv) - -- prev with Extremity index - rv = get_extmarks(ns, {-1,-1}, {0,0}, {limit=1}) - eq({{marks[3], positions[3][1], positions[3][2]}}, rv) - - -- prevrange with mark id - rv = get_extmarks(ns, marks[3], marks[1]) - eq({marks[3], positions[3][1], positions[3][2]}, rv[1]) - eq({marks[2], positions[2][1], positions[2][2]}, rv[2]) - eq({marks[1], positions[1][1], positions[1][2]}, rv[3]) - -- prevrange with limit - rv = get_extmarks(ns, marks[3], marks[1], {limit=2}) - eq(2, table.getn(rv)) - -- prevrange with positional when mark exists at position - rv = get_extmarks(ns, positions[3], positions[1]) - eq({{marks[3], positions[3][1], positions[3][2]}, - {marks[2], positions[2][1], positions[2][2]}, - {marks[1], positions[1][1], positions[1][2]}}, rv) - rv = get_extmarks(ns, positions[2], positions[1]) - eq(2, table.getn(rv)) - -- prevrange with positional index (no mark at position) - lower = {positions[2][1], positions[2][2] + 1} - upper = {positions[3][1], positions[3][2] + 1} - rv = get_extmarks(ns, upper, lower) - eq({{marks[3], positions[3][1], positions[3][2]}}, rv) - lower = {positions[3][1], positions[3][2] + 1} - upper = {positions[3][1], positions[3][2] + 2} - rv = get_extmarks(ns, upper, lower) - eq({}, rv) - -- prevrange with extremity index - lower = {0,0} - upper = {positions[2][1], positions[2][2] - 1} - rv = get_extmarks(ns, upper, lower) - eq({{marks[1], positions[1][1], positions[1][2]}}, rv) - end) - - it('querying for information with limit', function() - -- add some more marks - for i, m in ipairs(marks) do - if positions[i] ~= nil then - local rv = set_extmark(ns, m, positions[i][1], positions[i][2]) - eq(m, rv) - end - end - - local rv = get_extmarks(ns, {0, 0}, {-1, -1}, {limit=1}) - eq(1, table.getn(rv)) - rv = get_extmarks(ns, {0, 0}, {-1, -1}, {limit=2}) - eq(2, table.getn(rv)) - rv = get_extmarks(ns, {0, 0}, {-1, -1}, {limit=3}) - eq(3, table.getn(rv)) - - -- now in reverse - rv = get_extmarks(ns, {0, 0}, {-1, -1}, {limit=1}) - eq(1, table.getn(rv)) - rv = get_extmarks(ns, {0, 0}, {-1, -1}, {limit=2}) - eq(2, table.getn(rv)) - rv = get_extmarks(ns, {0, 0}, {-1, -1}, {limit=3}) - eq(3, table.getn(rv)) - end) - - it('get_marks works when mark col > upper col', function() - feed('A12345') - feed('A12345') - set_extmark(ns, 10, 0, 2) -- this shouldn't be found - set_extmark(ns, 11, 2, 1) -- this shouldn't be found - set_extmark(ns, marks[1], 0, 4) -- check col > our upper bound - set_extmark(ns, marks[2], 1, 1) -- check col < lower bound - set_extmark(ns, marks[3], 2, 0) -- check is inclusive - eq({{marks[1], 0, 4}, - {marks[2], 1, 1}, - {marks[3], 2, 0}}, - get_extmarks(ns, {0, 3}, {2, 0})) - end) - - it('get_marks works in reverse when mark col < lower col', function() - feed('A12345') - feed('A12345') - set_extmark(ns, 10, 0, 1) -- this shouldn't be found - set_extmark(ns, 11, 2, 4) -- this shouldn't be found - set_extmark(ns, marks[1], 2, 1) -- check col < our lower bound - set_extmark(ns, marks[2], 1, 4) -- check col > upper bound - set_extmark(ns, marks[3], 0, 2) -- check is inclusive - local rv = get_extmarks(ns, {2, 3}, {0, 2}) - eq({{marks[1], 2, 1}, - {marks[2], 1, 4}, - {marks[3], 0, 2}}, - rv) - end) - - it('get_marks limit=0 returns nothing', function() - set_extmark(ns, marks[1], positions[1][1], positions[1][2]) - local rv = get_extmarks(ns, {-1, -1}, {-1, -1}, {limit=0}) - eq({}, rv) - end) - - - it('marks move with line insertations', function() - set_extmark(ns, marks[1], 0, 0) - feed("yyP") - check_undo_redo(ns, marks[1], 0, 0, 1, 0) - end) - - it('marks move with multiline insertations', function() - feed("a2233") - set_extmark(ns, marks[1], 1, 1) - feed('ggVGyP') - check_undo_redo(ns, marks[1], 1, 1, 4, 1) - end) - - it('marks move with line join', function() - -- do_join in ops.c - feed("a222") - set_extmark(ns, marks[1], 1, 0) - feed('ggJ') - check_undo_redo(ns, marks[1], 1, 0, 0, 6) - end) - - it('join works when no marks are present', function() - screen = Screen.new(15, 10) - screen:attach() - feed("a1") - feed('kJ') - -- This shouldn't seg fault - screen:expect([[ - 12345^ 1 | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - | - ]]) - end) - - it('marks move with multiline join', function() - -- do_join in ops.c - feed("a222333444") - set_extmark(ns, marks[1], 3, 0) - feed('2GVGJ') - check_undo_redo(ns, marks[1], 3, 0, 1, 8) - end) - - it('marks move with line deletes', function() - feed("a222333444") - set_extmark(ns, marks[1], 2, 1) - feed('ggjdd') - check_undo_redo(ns, marks[1], 2, 1, 1, 1) - end) - - it('marks move with multiline deletes', function() - feed("a222333444") - set_extmark(ns, marks[1], 3, 0) - feed('gg2dd') - check_undo_redo(ns, marks[1], 3, 0, 1, 0) - -- regression test, undoing multiline delete when mark is on row 1 - feed('ugg3dd') - check_undo_redo(ns, marks[1], 3, 0, 0, 0) - end) - - it('marks move with open line', function() - -- open_line in misc1.c - -- testing marks below are also moved - feed("yyP") - set_extmark(ns, marks[1], 0, 4) - set_extmark(ns, marks[2], 1, 4) - feed('1G') - check_undo_redo(ns, marks[1], 0, 4, 1, 4) - check_undo_redo(ns, marks[2], 1, 4, 2, 4) - feed('2Go') - check_undo_redo(ns, marks[1], 1, 4, 1, 4) - check_undo_redo(ns, marks[2], 2, 4, 3, 4) - end) - - it('marks move with char inserts', function() - -- insertchar in edit.c (the ins_str branch) - screen = Screen.new(15, 10) - screen:attach() - set_extmark(ns, marks[1], 0, 3) - feed('0') - insert('abc') - screen:expect([[ - ab^c12345 | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - | - ]]) - local rv = curbufmeths.get_extmark_by_id(ns, marks[1]) - eq({0, 6}, rv) - check_undo_redo(ns, marks[1], 0, 3, 0, 6) - end) - - -- gravity right as definted in tk library - it('marks have gravity right', function() - -- insertchar in edit.c (the ins_str branch) - set_extmark(ns, marks[1], 0, 2) - feed('03l') - insert("X") - check_undo_redo(ns, marks[1], 0, 2, 0, 2) - - -- check multibyte chars - feed('03l') - insert("~~") - check_undo_redo(ns, marks[1], 0, 2, 0, 2) - end) - - it('we can insert multibyte chars', function() - -- insertchar in edit.c - feed('a12345') - set_extmark(ns, marks[1], 1, 2) - -- Insert a fullwidth (two col) tilde, NICE - feed('0i~') - check_undo_redo(ns, marks[1], 1, 2, 1, 5) - end) - - it('marks move with blockwise inserts', function() - -- op_insert in ops.c - feed('a12345') - set_extmark(ns, marks[1], 1, 2) - feed('0lkI9') - check_undo_redo(ns, marks[1], 1, 2, 1, 3) - end) - - it('marks move with line splits (using enter)', function() - -- open_line in misc1.c - -- testing marks below are also moved - feed("yyP") - set_extmark(ns, marks[1], 0, 4) - set_extmark(ns, marks[2], 1, 4) - feed('1Gla') - check_undo_redo(ns, marks[1], 0, 4, 1, 2) - check_undo_redo(ns, marks[2], 1, 4, 2, 4) - end) - - it('marks at last line move on insert new line', function() - -- open_line in misc1.c - set_extmark(ns, marks[1], 0, 4) - feed('0i') - check_undo_redo(ns, marks[1], 0, 4, 1, 4) - end) - - it('yet again marks move with line splits', function() - -- the first test above wasn't catching all errors.. - feed("A67890") - set_extmark(ns, marks[1], 0, 4) - feed("04li") - check_undo_redo(ns, marks[1], 0, 4, 1, 0) - end) - - it('and one last time line splits...', function() - set_extmark(ns, marks[1], 0, 1) - set_extmark(ns, marks[2], 0, 2) - feed("02li") - check_undo_redo(ns, marks[1], 0, 1, 0, 1) - check_undo_redo(ns, marks[2], 0, 2, 1, 0) - end) - - it('multiple marks move with mark splits', function() - set_extmark(ns, marks[1], 0, 1) - set_extmark(ns, marks[2], 0, 3) - feed("0li") - check_undo_redo(ns, marks[1], 0, 1, 1, 0) - check_undo_redo(ns, marks[2], 0, 3, 1, 2) - end) - - it('deleting right before a mark works', function() - -- op_delete in ops.c - set_extmark(ns, marks[1], 0, 2) - feed('0lx') - check_undo_redo(ns, marks[1], 0, 2, 0, 1) - end) - - it('deleting right after a mark works', function() - -- op_delete in ops.c - set_extmark(ns, marks[1], 0, 2) - feed('02lx') - check_undo_redo(ns, marks[1], 0, 2, 0, 2) - end) - - it('marks move with char deletes', function() - -- op_delete in ops.c - set_extmark(ns, marks[1], 0, 2) - feed('02dl') - check_undo_redo(ns, marks[1], 0, 2, 0, 0) - -- from the other side (nothing should happen) - feed('$x') - check_undo_redo(ns, marks[1], 0, 0, 0, 0) - end) - - it('marks move with char deletes over a range', function() - -- op_delete in ops.c - set_extmark(ns, marks[1], 0, 2) - set_extmark(ns, marks[2], 0, 3) - feed('0l3dl') - check_undo_redo(ns, marks[1], 0, 2, 0, 1) - check_undo_redo(ns, marks[2], 0, 3, 0, 1) - -- delete 1, nothing should happen to our marks - feed('u') - feed('$x') - check_undo_redo(ns, marks[2], 0, 3, 0, 3) - end) - - it('deleting marks at end of line works', function() - -- mark_extended.c/extmark_col_adjust_delete - set_extmark(ns, marks[1], 0, 4) - feed('$x') - check_undo_redo(ns, marks[1], 0, 4, 0, 4) - -- check the copy happened correctly on delete at eol - feed('$x') - check_undo_redo(ns, marks[1], 0, 4, 0, 3) - feed('u') - check_undo_redo(ns, marks[1], 0, 4, 0, 4) - end) - - it('marks move with blockwise deletes', function() - -- op_delete in ops.c - feed('a12345') - set_extmark(ns, marks[1], 1, 4) - feed('hhhkd') - check_undo_redo(ns, marks[1], 1, 4, 1, 1) - end) - - it('marks move with blockwise deletes over a range', function() - -- op_delete in ops.c - feed('a12345') - set_extmark(ns, marks[1], 0, 1) - set_extmark(ns, marks[2], 0, 3) - set_extmark(ns, marks[3], 1, 2) - feed('0k3lx') - check_undo_redo(ns, marks[1], 0, 1, 0, 0) - check_undo_redo(ns, marks[2], 0, 3, 0, 0) - check_undo_redo(ns, marks[3], 1, 2, 1, 0) - -- delete 1, nothing should happen to our marks - feed('u') - feed('$jx') - check_undo_redo(ns, marks[2], 0, 3, 0, 3) - check_undo_redo(ns, marks[3], 1, 2, 1, 2) - end) - - it('works with char deletes over multilines', function() - feed('a12345test-me') - set_extmark(ns, marks[1], 2, 5) - feed('gg') - feed('dv?-m?') - check_undo_redo(ns, marks[1], 2, 5, 0, 0) - end) - - it('marks outside of deleted range move with visual char deletes', function() - -- op_delete in ops.c - set_extmark(ns, marks[1], 0, 3) - feed('0vx') - check_undo_redo(ns, marks[1], 0, 3, 0, 2) - - feed("u") - feed('0vlx') - check_undo_redo(ns, marks[1], 0, 3, 0, 1) - - feed("u") - feed('0v2lx') - check_undo_redo(ns, marks[1], 0, 3, 0, 0) - - -- from the other side (nothing should happen) - feed('$vx') - check_undo_redo(ns, marks[1], 0, 0, 0, 0) - end) - - it('marks outside of deleted range move with char deletes', function() - -- op_delete in ops.c - set_extmark(ns, marks[1], 0, 3) - feed('0x') - check_undo_redo(ns, marks[1], 0, 3, 0, 2) - - feed("u") - feed('02x') - check_undo_redo(ns, marks[1], 0, 3, 0, 1) - - feed("u") - feed('0v3lx') - check_undo_redo(ns, marks[1], 0, 3, 0, 0) - - -- from the other side (nothing should happen) - feed("u") - feed('$vx') - check_undo_redo(ns, marks[1], 0, 3, 0, 3) - end) - - it('marks move with P(backward) paste', function() - -- do_put in ops.c - feed('0iabc') - set_extmark(ns, marks[1], 0, 7) - feed('0veyP') - check_undo_redo(ns, marks[1], 0, 7, 0, 15) - end) - - it('marks move with p(forward) paste', function() - -- do_put in ops.c - feed('0iabc') - set_extmark(ns, marks[1], 0, 7) - feed('0veyp') - check_undo_redo(ns, marks[1], 0, 7, 0, 15) - end) - - it('marks move with blockwise P(backward) paste', function() - -- do_put in ops.c - feed('a12345') - set_extmark(ns, marks[1], 1, 4) - feed('hhkyP') - check_undo_redo(ns, marks[1], 1, 4, 1, 7) - end) - - it('marks move with blockwise p(forward) paste', function() - -- do_put in ops.c - feed('a12345') - set_extmark(ns, marks[1], 1, 4) - feed('hhkyp') - check_undo_redo(ns, marks[1], 1, 4, 1, 7) - end) - - describe('multiline regions', function() - before_each(function() - feed('dd') - -- Achtung: code has been spiced with some unicode, - -- to make life more interesting. - -- luacheck whines about TABs inside strings for whatever reason. - -- luacheck: push ignore 621 - insert([[ - static int nlua_rpcrequest(lua_State *lstate) - { - Ïf (!nlua_is_deferred_safe(lstate)) { - // strictly not allowed - Яetörn luaL_error(lstate, e_luv_api_disabled, "rpcrequest"); - } - return nlua_rpc(lstate, true); - }]]) - -- luacheck: pop - end) - - it('delete', function() - local pos1 = { - {2, 4}, {2, 12}, {2, 13}, {2, 14}, {2, 25}, - {4, 8}, {4, 10}, {4, 20}, - {5, 3}, {6, 10} - } - local ids = batch_set(ns, pos1) - batch_check(ns, ids, pos1) - feed('3Gfiv2+ftd') - batch_check_undo_redo(ns, ids, pos1, { - {2, 4}, {2, 12}, {2, 13}, {2, 13}, {2, 13}, - {2, 13}, {2, 15}, {2, 25}, - {3, 3}, {4, 10} - }) - end) - - -- TODO(bfredl): add more tests! - end) - - it('replace works', function() - set_extmark(ns, marks[1], 0, 2) - feed('0r2') - check_undo_redo(ns, marks[1], 0, 2, 0, 2) - end) - - it('blockwise replace works', function() - feed('a12345') - set_extmark(ns, marks[1], 0, 2) - feed('0llkr1') - check_undo_redo(ns, marks[1], 0, 2, 0, 3) - end) - - it('shift line', function() - -- shift_line in ops.c - feed(':set shiftwidth=4') - set_extmark(ns, marks[1], 0, 2) - feed('0>>') - check_undo_redo(ns, marks[1], 0, 2, 0, 6) - expect(' 12345') - - feed('>>') - -- this is counter-intuitive. But what happens - -- is that 4 spaces gets extended to one tab (== 8 spaces) - check_undo_redo(ns, marks[1], 0, 6, 0, 3) - expect('\t12345') - - feed('') -- have to escape, same as << - check_undo_redo(ns, marks[1], 0, 3, 0, 6) - end) - - it('blockwise shift', function() - -- shift_block in ops.c - feed(':set shiftwidth=4') - feed('a12345') - set_extmark(ns, marks[1], 1, 2) - feed('0k>') - check_undo_redo(ns, marks[1], 1, 2, 1, 6) - feed('j>') - expect('\t12345\n\t12345') - check_undo_redo(ns, marks[1], 1, 6, 1, 3) - - feed('j') - check_undo_redo(ns, marks[1], 1, 3, 1, 6) - end) - - it('tab works with expandtab', function() - -- ins_tab in edit.c - feed(':set expandtab') - feed(':set shiftwidth=2') - set_extmark(ns, marks[1], 0, 2) - feed('0i') - check_undo_redo(ns, marks[1], 0, 2, 0, 6) - end) - - it('tabs work', function() - -- ins_tab in edit.c - feed(':set noexpandtab') - feed(':set shiftwidth=2') - feed(':set softtabstop=2') - feed(':set tabstop=8') - set_extmark(ns, marks[1], 0, 2) - feed('0i') - check_undo_redo(ns, marks[1], 0, 2, 0, 4) - feed('0iX') - check_undo_redo(ns, marks[1], 0, 4, 0, 6) - end) - - it('marks move when using :move', function() - set_extmark(ns, marks[1], 0, 0) - feed('A2:1move 2') - check_undo_redo(ns, marks[1], 0, 0, 1, 0) - -- test codepath when moving lines up - feed(':2move 0') - check_undo_redo(ns, marks[1], 1, 0, 0, 0) - end) - - it('marks move when using :move part 2', function() - -- make sure we didn't get lucky with the math... - feed('A23456') - set_extmark(ns, marks[1], 1, 0) - feed(':2,3move 5') - check_undo_redo(ns, marks[1], 1, 0, 3, 0) - -- test codepath when moving lines up - feed(':4,5move 1') - check_undo_redo(ns, marks[1], 3, 0, 1, 0) - end) - - it('undo and redo of set and unset marks', function() - -- Force a new undo head - feed('o') - set_extmark(ns, marks[1], 0, 1) - feed('o') - set_extmark(ns, marks[2], 0, -1) - set_extmark(ns, marks[3], 0, -1) - - feed("u") - local rv = get_extmarks(ns, {0, 0}, {-1, -1}) - eq(3, table.getn(rv)) - - feed("") - rv = get_extmarks(ns, {0, 0}, {-1, -1}) - eq(3, table.getn(rv)) - - -- Test updates - feed('o') - set_extmark(ns, marks[1], positions[1][1], positions[1][2]) - rv = get_extmarks(ns, marks[1], marks[1], {limit=1}) - eq(1, table.getn(rv)) - feed("u") - feed("") - -- old value is NOT kept in history - check_undo_redo(ns, marks[1], positions[1][1], positions[1][2], positions[1][1], positions[1][2]) - - -- Test unset - feed('o') - curbufmeths.del_extmark(ns, marks[3]) - feed("u") - rv = get_extmarks(ns, {0, 0}, {-1, -1}) - -- undo does NOT restore deleted marks - eq(2, table.getn(rv)) - feed("") - rv = get_extmarks(ns, {0, 0}, {-1, -1}) - eq(2, table.getn(rv)) - end) - - it('undo and redo of marks deleted during edits', function() - -- test extmark_adjust - feed('A12345') - set_extmark(ns, marks[1], 1, 2) - feed('dd') - check_undo_redo(ns, marks[1], 1, 2, 1, 0) - end) - - it('namespaces work properly', function() - local rv = set_extmark(ns, marks[1], positions[1][1], positions[1][2]) - eq(1, rv) - rv = set_extmark(ns2, marks[1], positions[1][1], positions[1][2]) - eq(1, rv) - rv = get_extmarks(ns, {0, 0}, {-1, -1}) - eq(1, table.getn(rv)) - rv = get_extmarks(ns2, {0, 0}, {-1, -1}) - eq(1, table.getn(rv)) - - -- Set more marks for testing the ranges - set_extmark(ns, marks[2], positions[2][1], positions[2][2]) - set_extmark(ns, marks[3], positions[3][1], positions[3][2]) - set_extmark(ns2, marks[2], positions[2][1], positions[2][2]) - set_extmark(ns2, marks[3], positions[3][1], positions[3][2]) - - -- get_next (limit set) - rv = get_extmarks(ns, {0, 0}, positions[2], {limit=1}) - eq(1, table.getn(rv)) - rv = get_extmarks(ns2, {0, 0}, positions[2], {limit=1}) - eq(1, table.getn(rv)) - -- get_prev (limit set) - rv = get_extmarks(ns, positions[1], {0, 0}, {limit=1}) - eq(1, table.getn(rv)) - rv = get_extmarks(ns2, positions[1], {0, 0}, {limit=1}) - eq(1, table.getn(rv)) - - -- get_next (no limit) - rv = get_extmarks(ns, positions[1], positions[2]) - eq(2, table.getn(rv)) - rv = get_extmarks(ns2, positions[1], positions[2]) - eq(2, table.getn(rv)) - -- get_prev (no limit) - rv = get_extmarks(ns, positions[2], positions[1]) - eq(2, table.getn(rv)) - rv = get_extmarks(ns2, positions[2], positions[1]) - eq(2, table.getn(rv)) - - curbufmeths.del_extmark(ns, marks[1]) - rv = get_extmarks(ns, {0, 0}, {-1, -1}) - eq(2, table.getn(rv)) - curbufmeths.del_extmark(ns2, marks[1]) - rv = get_extmarks(ns2, {0, 0}, {-1, -1}) - eq(2, table.getn(rv)) - end) - - it('mark set can create unique identifiers', function() - -- create mark with id 1 - eq(1, set_extmark(ns, 1, positions[1][1], positions[1][2])) - -- ask for unique id, it should be the next one, i e 2 - eq(2, set_extmark(ns, 0, positions[1][1], positions[1][2])) - eq(3, set_extmark(ns, 3, positions[2][1], positions[2][2])) - eq(4, set_extmark(ns, 0, positions[1][1], positions[1][2])) - - -- mixing manual and allocated id:s are not recommened, but it should - -- do something reasonable - eq(6, set_extmark(ns, 6, positions[2][1], positions[2][2])) - eq(7, set_extmark(ns, 0, positions[1][1], positions[1][2])) - eq(8, set_extmark(ns, 0, positions[1][1], positions[1][2])) - end) - - it('auto indenting with enter works', function() - -- op_reindent in ops.c - feed(':set cindent') - feed(':set autoindent') - feed(':set shiftwidth=2') - feed("0iint A {1M1b") - -- Set the mark on the M, should move.. - set_extmark(ns, marks[1], 0, 12) - -- Set the mark before the cursor, should stay there - set_extmark(ns, marks[2], 0, 10) - feed("i") - local rv = curbufmeths.get_extmark_by_id(ns, marks[1]) - eq({1, 3}, rv) - rv = curbufmeths.get_extmark_by_id(ns, marks[2]) - eq({0, 10}, rv) - check_undo_redo(ns, marks[1], 0, 12, 1, 3) - end) - - it('auto indenting entire line works', function() - feed(':set cindent') - feed(':set autoindent') - feed(':set shiftwidth=2') - -- will force an indent of 2 - feed("0iint A {0i1M1") - set_extmark(ns, marks[1], 1, 1) - feed("0i") - local rv = curbufmeths.get_extmark_by_id(ns, marks[1]) - eq({1, 3}, rv) - check_undo_redo(ns, marks[1], 1, 1, 1, 3) - -- now check when cursor at eol - feed("uA") - rv = curbufmeths.get_extmark_by_id(ns, marks[1]) - eq({1, 3}, rv) - end) - - it('removing auto indenting with works', function() - feed(':set cindent') - feed(':set autoindent') - feed(':set shiftwidth=2') - feed("0i") - set_extmark(ns, marks[1], 0, 3) - feed("bi") - local rv = curbufmeths.get_extmark_by_id(ns, marks[1]) - eq({0, 1}, rv) - check_undo_redo(ns, marks[1], 0, 3, 0, 1) - -- check when cursor at eol - feed("uA") - rv = curbufmeths.get_extmark_by_id(ns, marks[1]) - eq({0, 1}, rv) - end) - - it('indenting multiple lines with = works', function() - feed(':set cindent') - feed(':set autoindent') - feed(':set shiftwidth=2') - feed("0iint A {1M12M2") - set_extmark(ns, marks[1], 1, 1) - set_extmark(ns, marks[2], 2, 1) - feed('=gg') - check_undo_redo(ns, marks[1], 1, 1, 1, 3) - check_undo_redo(ns, marks[2], 2, 1, 2, 5) - end) - - it('substitutes by deleting inside the replace matches', function() - -- do_sub in ex_cmds.c - set_extmark(ns, marks[1], 0, 2) - set_extmark(ns, marks[2], 0, 3) - feed(':s/34/xx') - check_undo_redo(ns, marks[1], 0, 2, 0, 4) - check_undo_redo(ns, marks[2], 0, 3, 0, 4) - end) - - it('substitutes when insert text > deleted', function() - -- do_sub in ex_cmds.c - set_extmark(ns, marks[1], 0, 2) - set_extmark(ns, marks[2], 0, 3) - feed(':s/34/xxx') - check_undo_redo(ns, marks[1], 0, 2, 0, 5) - check_undo_redo(ns, marks[2], 0, 3, 0, 5) - end) - - it('substitutes when marks around eol', function() - -- do_sub in ex_cmds.c - set_extmark(ns, marks[1], 0, 4) - set_extmark(ns, marks[2], 0, 5) - feed(':s/5/xxx') - check_undo_redo(ns, marks[1], 0, 4, 0, 7) - check_undo_redo(ns, marks[2], 0, 5, 0, 7) - end) - - it('substitutes over range insert text > deleted', function() - -- do_sub in ex_cmds.c - feed('Ax34xx') - feed('Axxx34') - set_extmark(ns, marks[1], 0, 2) - set_extmark(ns, marks[2], 1, 1) - set_extmark(ns, marks[3], 2, 4) - feed(':1,3s/34/xxx') - check_undo_redo(ns, marks[1], 0, 2, 0, 5) - check_undo_redo(ns, marks[2], 1, 1, 1, 4) - check_undo_redo(ns, marks[3], 2, 4, 2, 6) - end) - - it('substitutes multiple matches in a line', function() - -- do_sub in ex_cmds.c - feed('ddi3x3x3') - set_extmark(ns, marks[1], 0, 0) - set_extmark(ns, marks[2], 0, 2) - set_extmark(ns, marks[3], 0, 4) - feed(':s/3/yy/g') - check_undo_redo(ns, marks[1], 0, 0, 0, 2) - check_undo_redo(ns, marks[2], 0, 2, 0, 5) - check_undo_redo(ns, marks[3], 0, 4, 0, 8) - end) - - it('substitions over multiple lines with newline in pattern', function() - feed('A67890xx') - set_extmark(ns, marks[1], 0, 3) - set_extmark(ns, marks[2], 0, 4) - set_extmark(ns, marks[3], 1, 0) - set_extmark(ns, marks[4], 1, 5) - set_extmark(ns, marks[5], 2, 0) - feed([[:1,2s:5\n:5 ]]) - check_undo_redo(ns, marks[1], 0, 3, 0, 3) - check_undo_redo(ns, marks[2], 0, 4, 0, 6) - check_undo_redo(ns, marks[3], 1, 0, 0, 6) - check_undo_redo(ns, marks[4], 1, 5, 0, 11) - check_undo_redo(ns, marks[5], 2, 0, 1, 0) - end) - - it('inserting', function() - feed('A67890xx') - set_extmark(ns, marks[1], 0, 3) - set_extmark(ns, marks[2], 0, 4) - set_extmark(ns, marks[3], 1, 0) - set_extmark(ns, marks[4], 1, 5) - set_extmark(ns, marks[5], 2, 0) - set_extmark(ns, marks[6], 1, 2) - feed([[:1,2s:5\n67:X]]) - check_undo_redo(ns, marks[1], 0, 3, 0, 3) - check_undo_redo(ns, marks[2], 0, 4, 0, 5) - check_undo_redo(ns, marks[3], 1, 0, 0, 5) - check_undo_redo(ns, marks[4], 1, 5, 0, 8) - check_undo_redo(ns, marks[5], 2, 0, 1, 0) - check_undo_redo(ns, marks[6], 1, 2, 0, 5) - end) - - it('substitions with multiple newlines in pattern', function() - feed('A67890xx') - set_extmark(ns, marks[1], 0, 4) - set_extmark(ns, marks[2], 0, 5) - set_extmark(ns, marks[3], 1, 0) - set_extmark(ns, marks[4], 1, 5) - set_extmark(ns, marks[5], 2, 0) - feed([[:1,2s:\n.*\n:X]]) - check_undo_redo(ns, marks[1], 0, 4, 0, 4) - check_undo_redo(ns, marks[2], 0, 5, 0, 6) - check_undo_redo(ns, marks[3], 1, 0, 0, 6) - check_undo_redo(ns, marks[4], 1, 5, 0, 6) - check_undo_redo(ns, marks[5], 2, 0, 0, 6) - end) - - it('substitions over multiple lines with replace in substition', function() - feed('A67890xx') - set_extmark(ns, marks[1], 0, 1) - set_extmark(ns, marks[2], 0, 2) - set_extmark(ns, marks[3], 0, 4) - set_extmark(ns, marks[4], 1, 0) - set_extmark(ns, marks[5], 2, 0) - feed([[:1,2s:3:\r]]) - check_undo_redo(ns, marks[1], 0, 1, 0, 1) - check_undo_redo(ns, marks[2], 0, 2, 1, 0) - check_undo_redo(ns, marks[3], 0, 4, 1, 1) - check_undo_redo(ns, marks[4], 1, 0, 2, 0) - check_undo_redo(ns, marks[5], 2, 0, 3, 0) - feed('u') - feed([[:1,2s:3:\rxx]]) - eq({1, 3}, curbufmeths.get_extmark_by_id(ns, marks[3])) - end) - - it('substitions over multiple lines with replace in substition', function() - feed('Ax3xx') - set_extmark(ns, marks[1], 1, 0) - set_extmark(ns, marks[2], 1, 1) - set_extmark(ns, marks[3], 1, 2) - feed([[:2,2s:3:\r]]) - check_undo_redo(ns, marks[1], 1, 0, 1, 0) - check_undo_redo(ns, marks[2], 1, 1, 2, 0) - check_undo_redo(ns, marks[3], 1, 2, 2, 0) - end) - - it('substitions over multiple lines with replace in substition', function() - feed('Ax3xx') - set_extmark(ns, marks[1], 0, 1) - set_extmark(ns, marks[2], 0, 2) - set_extmark(ns, marks[3], 0, 4) - set_extmark(ns, marks[4], 1, 1) - set_extmark(ns, marks[5], 2, 0) - feed([[:1,2s:3:\r]]) - check_undo_redo(ns, marks[1], 0, 1, 0, 1) - check_undo_redo(ns, marks[2], 0, 2, 1, 0) - check_undo_redo(ns, marks[3], 0, 4, 1, 1) - check_undo_redo(ns, marks[4], 1, 1, 3, 0) - check_undo_redo(ns, marks[5], 2, 0, 4, 0) - feed('u') - feed([[:1,2s:3:\rxx]]) - check_undo_redo(ns, marks[3], 0, 4, 1, 3) - end) - - it('substitions with newline in match and sub, delta is 0', function() - feed('A67890xx') - set_extmark(ns, marks[1], 0, 3) - set_extmark(ns, marks[2], 0, 4) - set_extmark(ns, marks[3], 0, 5) - set_extmark(ns, marks[4], 1, 0) - set_extmark(ns, marks[5], 1, 5) - set_extmark(ns, marks[6], 2, 0) - feed([[:1,1s:5\n:\r]]) - check_undo_redo(ns, marks[1], 0, 3, 0, 3) - check_undo_redo(ns, marks[2], 0, 4, 1, 0) - check_undo_redo(ns, marks[3], 0, 5, 1, 0) - check_undo_redo(ns, marks[4], 1, 0, 1, 0) - check_undo_redo(ns, marks[5], 1, 5, 1, 5) - check_undo_redo(ns, marks[6], 2, 0, 2, 0) - end) - - it('substitions with newline in match and sub, delta > 0', function() - feed('A67890xx') - set_extmark(ns, marks[1], 0, 3) - set_extmark(ns, marks[2], 0, 4) - set_extmark(ns, marks[3], 0, 5) - set_extmark(ns, marks[4], 1, 0) - set_extmark(ns, marks[5], 1, 5) - set_extmark(ns, marks[6], 2, 0) - feed([[:1,1s:5\n:\r\r]]) - check_undo_redo(ns, marks[1], 0, 3, 0, 3) - check_undo_redo(ns, marks[2], 0, 4, 2, 0) - check_undo_redo(ns, marks[3], 0, 5, 2, 0) - check_undo_redo(ns, marks[4], 1, 0, 2, 0) - check_undo_redo(ns, marks[5], 1, 5, 2, 5) - check_undo_redo(ns, marks[6], 2, 0, 3, 0) - end) - - it('substitions with newline in match and sub, delta < 0', function() - feed('A67890xxxx') - set_extmark(ns, marks[1], 0, 3) - set_extmark(ns, marks[2], 0, 4) - set_extmark(ns, marks[3], 0, 5) - set_extmark(ns, marks[4], 1, 0) - set_extmark(ns, marks[5], 1, 5) - set_extmark(ns, marks[6], 2, 1) - set_extmark(ns, marks[7], 3, 0) - feed([[:1,2s:5\n.*\n:\r]]) - check_undo_redo(ns, marks[1], 0, 3, 0, 3) - check_undo_redo(ns, marks[2], 0, 4, 1, 0) - check_undo_redo(ns, marks[3], 0, 5, 1, 0) - check_undo_redo(ns, marks[4], 1, 0, 1, 0) - check_undo_redo(ns, marks[5], 1, 5, 1, 0) - check_undo_redo(ns, marks[6], 2, 1, 1, 1) - check_undo_redo(ns, marks[7], 3, 0, 2, 0) - end) - - it('substitions with backrefs, newline inserted into sub', function() - feed('A67890xxxx') - set_extmark(ns, marks[1], 0, 3) - set_extmark(ns, marks[2], 0, 4) - set_extmark(ns, marks[3], 0, 5) - set_extmark(ns, marks[4], 1, 0) - set_extmark(ns, marks[5], 1, 5) - set_extmark(ns, marks[6], 2, 0) - feed([[:1,1s:5\(\n\):\0\1]]) - check_undo_redo(ns, marks[1], 0, 3, 0, 3) - check_undo_redo(ns, marks[2], 0, 4, 2, 0) - check_undo_redo(ns, marks[3], 0, 5, 2, 0) - check_undo_redo(ns, marks[4], 1, 0, 2, 0) - check_undo_redo(ns, marks[5], 1, 5, 2, 5) - check_undo_redo(ns, marks[6], 2, 0, 3, 0) - end) - - it('substitions a ^', function() - set_extmark(ns, marks[1], 0, 0) - set_extmark(ns, marks[2], 0, 1) - feed([[:s:^:x]]) - check_undo_redo(ns, marks[1], 0, 0, 0, 1) - check_undo_redo(ns, marks[2], 0, 1, 0, 2) - end) - - it('using without increase in order of magnitude', function() - -- do_addsub in ops.c - feed('ddiabc998xxxTc') - set_extmark(ns, marks[1], 0, 2) - set_extmark(ns, marks[2], 0, 3) - set_extmark(ns, marks[3], 0, 5) - set_extmark(ns, marks[4], 0, 6) - set_extmark(ns, marks[5], 0, 7) - feed('') - check_undo_redo(ns, marks[1], 0, 2, 0, 2) - check_undo_redo(ns, marks[2], 0, 3, 0, 6) - check_undo_redo(ns, marks[3], 0, 5, 0, 6) - check_undo_redo(ns, marks[4], 0, 6, 0, 6) - check_undo_redo(ns, marks[5], 0, 7, 0, 7) - end) - - it('using when increase in order of magnitude', function() - -- do_addsub in ops.c - feed('ddiabc999xxxTc') - set_extmark(ns, marks[1], 0, 2) - set_extmark(ns, marks[2], 0, 3) - set_extmark(ns, marks[3], 0, 5) - set_extmark(ns, marks[4], 0, 6) - set_extmark(ns, marks[5], 0, 7) - feed('') - check_undo_redo(ns, marks[1], 0, 2, 0, 2) - check_undo_redo(ns, marks[2], 0, 3, 0, 7) - check_undo_redo(ns, marks[3], 0, 5, 0, 7) - check_undo_redo(ns, marks[4], 0, 6, 0, 7) - check_undo_redo(ns, marks[5], 0, 7, 0, 8) - end) - - it('using when negative and without decrease in order of magnitude', function() - feed('ddiabc-999xxxT-') - set_extmark(ns, marks[1], 0, 2) - set_extmark(ns, marks[2], 0, 3) - set_extmark(ns, marks[3], 0, 6) - set_extmark(ns, marks[4], 0, 7) - set_extmark(ns, marks[5], 0, 8) - feed('') - check_undo_redo(ns, marks[1], 0, 2, 0, 2) - check_undo_redo(ns, marks[2], 0, 3, 0, 7) - check_undo_redo(ns, marks[3], 0, 6, 0, 7) - check_undo_redo(ns, marks[4], 0, 7, 0, 7) - check_undo_redo(ns, marks[5], 0, 8, 0, 8) - end) - - it('using when negative and decrease in order of magnitude', function() - feed('ddiabc-1000xxxT-') - set_extmark(ns, marks[1], 0, 2) - set_extmark(ns, marks[2], 0, 3) - set_extmark(ns, marks[3], 0, 7) - set_extmark(ns, marks[4], 0, 8) - set_extmark(ns, marks[5], 0, 9) - feed('') - check_undo_redo(ns, marks[1], 0, 2, 0, 2) - check_undo_redo(ns, marks[2], 0, 3, 0, 7) - check_undo_redo(ns, marks[3], 0, 7, 0, 7) - check_undo_redo(ns, marks[4], 0, 8, 0, 7) - check_undo_redo(ns, marks[5], 0, 9, 0, 8) - end) - - it('using without decrease in order of magnitude', function() - -- do_addsub in ops.c - feed('ddiabc999xxxTc') - set_extmark(ns, marks[1], 0, 2) - set_extmark(ns, marks[2], 0, 3) - set_extmark(ns, marks[3], 0, 5) - set_extmark(ns, marks[4], 0, 6) - set_extmark(ns, marks[5], 0, 7) - feed('') - check_undo_redo(ns, marks[1], 0, 2, 0, 2) - check_undo_redo(ns, marks[2], 0, 3, 0, 6) - check_undo_redo(ns, marks[3], 0, 5, 0, 6) - check_undo_redo(ns, marks[4], 0, 6, 0, 6) - check_undo_redo(ns, marks[5], 0, 7, 0, 7) - end) - - it('using when decrease in order of magnitude', function() - -- do_addsub in ops.c - feed('ddiabc1000xxxTc') - set_extmark(ns, marks[1], 0, 2) - set_extmark(ns, marks[2], 0, 3) - set_extmark(ns, marks[3], 0, 6) - set_extmark(ns, marks[4], 0, 7) - set_extmark(ns, marks[5], 0, 8) - feed('') - check_undo_redo(ns, marks[1], 0, 2, 0, 2) - check_undo_redo(ns, marks[2], 0, 3, 0, 6) - check_undo_redo(ns, marks[3], 0, 6, 0, 6) - check_undo_redo(ns, marks[4], 0, 7, 0, 6) - check_undo_redo(ns, marks[5], 0, 8, 0, 7) - end) - - it('using when negative and without increase in order of magnitude', function() - feed('ddiabc-998xxxT-') - set_extmark(ns, marks[1], 0, 2) - set_extmark(ns, marks[2], 0, 3) - set_extmark(ns, marks[3], 0, 6) - set_extmark(ns, marks[4], 0, 7) - set_extmark(ns, marks[5], 0, 8) - feed('') - check_undo_redo(ns, marks[1], 0, 2, 0, 2) - check_undo_redo(ns, marks[2], 0, 3, 0, 7) - check_undo_redo(ns, marks[3], 0, 6, 0, 7) - check_undo_redo(ns, marks[4], 0, 7, 0, 7) - check_undo_redo(ns, marks[5], 0, 8, 0, 8) - end) - - it('using when negative and increase in order of magnitude', function() - feed('ddiabc-999xxxT-') - set_extmark(ns, marks[1], 0, 2) - set_extmark(ns, marks[2], 0, 3) - set_extmark(ns, marks[3], 0, 6) - set_extmark(ns, marks[4], 0, 7) - set_extmark(ns, marks[5], 0, 8) - feed('') - check_undo_redo(ns, marks[1], 0, 2, 0, 2) - check_undo_redo(ns, marks[2], 0, 3, 0, 8) - check_undo_redo(ns, marks[3], 0, 6, 0, 8) - check_undo_redo(ns, marks[4], 0, 7, 0, 8) - check_undo_redo(ns, marks[5], 0, 8, 0, 9) - end) - - it('throws consistent error codes', function() - local ns_invalid = ns2 + 1 - eq("Invalid ns_id", pcall_err(set_extmark, ns_invalid, marks[1], positions[1][1], positions[1][2])) - eq("Invalid ns_id", pcall_err(curbufmeths.del_extmark, ns_invalid, marks[1])) - eq("Invalid ns_id", pcall_err(get_extmarks, ns_invalid, positions[1], positions[2])) - eq("Invalid ns_id", pcall_err(curbufmeths.get_extmark_by_id, ns_invalid, marks[1])) - end) - - it('when col = line-length, set the mark on eol', function() - set_extmark(ns, marks[1], 0, -1) - local rv = curbufmeths.get_extmark_by_id(ns, marks[1]) - eq({0, init_text:len()}, rv) - -- Test another - set_extmark(ns, marks[1], 0, -1) - rv = curbufmeths.get_extmark_by_id(ns, marks[1]) - eq({0, init_text:len()}, rv) - end) - - it('when col = line-length, set the mark on eol', function() - local invalid_col = init_text:len() + 1 - eq("col value outside range", pcall_err(set_extmark, ns, marks[1], 0, invalid_col)) - end) - - it('fails when line > line_count', function() - local invalid_col = init_text:len() + 1 - local invalid_lnum = 3 - eq('line value outside range', pcall_err(set_extmark, ns, marks[1], invalid_lnum, invalid_col)) - eq({}, curbufmeths.get_extmark_by_id(ns, marks[1])) - end) - - it('bug from check_col in extmark_set', function() - -- This bug was caused by extmark_set always using check_col. check_col - -- always uses the current buffer. This wasn't working during undo so we - -- now use check_col and check_lnum only when they are required. - feed('A67890xx') - feed('A1234567890xx') - set_extmark(ns, marks[1], 3, 4) - feed([[:1,5s:5\n:5 ]]) - check_undo_redo(ns, marks[1], 3, 4, 2, 6) - end) - - it('in read-only buffer', function() - command("view! runtime/doc/help.txt") - eq(true, curbufmeths.get_option('ro')) - local id = set_extmark(ns, 0, 0, 2) - eq({{id, 0, 2}}, get_extmarks(ns,0, -1)) - end) - - it('can set a mark to other buffer', function() - local buf = request('nvim_create_buf', 0, 1) - request('nvim_buf_set_lines', buf, 0, -1, 1, {"", ""}) - local id = bufmeths.set_extmark(buf, ns, 0, 1, 0, {}) - eq({{id, 1, 0}}, bufmeths.get_extmarks(buf, ns, 0, -1, {})) - end) - - it('does not crash with append/delete/undo seqence', function() - meths.exec([[ - let ns = nvim_create_namespace('myplugin') - call nvim_buf_set_extmark(0, ns, 0, 0, 0, {}) - call append(0, '') - %delete - undo]],false) - eq(2, meths.eval('1+1')) -- did not crash - end) -end) - -describe('Extmarks buffer api with many marks', function() - local ns1 - local ns2 - local ns_marks = {} - before_each(function() - clear() - ns1 = request('nvim_create_namespace', "ns1") - ns2 = request('nvim_create_namespace', "ns2") - ns_marks = {[ns1]={}, [ns2]={}} - local lines = {} - for i = 1,30 do - lines[#lines+1] = string.rep("x ",i) - end - curbufmeths.set_lines(0, -1, true, lines) - local ns = ns1 - local q = 0 - for i = 0,29 do - for j = 0,i do - local id = set_extmark(ns,0, i,j) - eq(nil, ns_marks[ns][id]) - ok(id > 0) - ns_marks[ns][id] = {i,j} - ns = ns1+ns2-ns - q = q + 1 - end - end - eq(233, #ns_marks[ns1]) - eq(232, #ns_marks[ns2]) - - end) - - local function get_marks(ns) - local mark_list = get_extmarks(ns, 0, -1) - local marks = {} - for _, mark in ipairs(mark_list) do - local id, row, col = unpack(mark) - eq(nil, marks[id], "duplicate mark") - marks[id] = {row,col} - end - return marks - end - - it("can get marks", function() - eq(ns_marks[ns1], get_marks(ns1)) - eq(ns_marks[ns2], get_marks(ns2)) - end) - - it("can clear all marks in ns", function() - curbufmeths.clear_namespace(ns1, 0, -1) - eq({}, get_marks(ns1)) - eq(ns_marks[ns2], get_marks(ns2)) - curbufmeths.clear_namespace(ns2, 0, -1) - eq({}, get_marks(ns1)) - eq({}, get_marks(ns2)) - end) - - it("can clear line range", function() - curbufmeths.clear_namespace(ns1, 10, 20) - for id, mark in pairs(ns_marks[ns1]) do - if 10 <= mark[1] and mark[1] < 20 then - ns_marks[ns1][id] = nil - end - end - eq(ns_marks[ns1], get_marks(ns1)) - eq(ns_marks[ns2], get_marks(ns2)) - end) - - it("can delete line", function() - feed('10Gdd') - for _, marks in pairs(ns_marks) do - for id, mark in pairs(marks) do - if mark[1] == 9 then - marks[id] = {9,0} - elseif mark[1] >= 10 then - mark[1] = mark[1] - 1 - end - end - end - eq(ns_marks[ns1], get_marks(ns1)) - eq(ns_marks[ns2], get_marks(ns2)) - end) - - it("can delete lines", function() - feed('10G10dd') - for _, marks in pairs(ns_marks) do - for id, mark in pairs(marks) do - if 9 <= mark[1] and mark[1] < 19 then - marks[id] = {9,0} - elseif mark[1] >= 19 then - mark[1] = mark[1] - 10 - end - end - end - eq(ns_marks[ns1], get_marks(ns1)) - eq(ns_marks[ns2], get_marks(ns2)) - end) - - it("can wipe buffer", function() - command('bwipe!') - eq({}, get_marks(ns1)) - eq({}, get_marks(ns2)) - end) -end) -- cgit From f245c0218adc9ff3452660dff97e62cea8e9a411 Mon Sep 17 00:00:00 2001 From: butwerenotthereyet <58348703+butwerenotthereyet@users.noreply.github.com> Date: Mon, 20 Jan 2020 15:14:51 -0800 Subject: tabpage: "tabnext #" switches to previous tab #11734 --- test/functional/autocmd/tabnewentered_spec.lua | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'test') diff --git a/test/functional/autocmd/tabnewentered_spec.lua b/test/functional/autocmd/tabnewentered_spec.lua index 123dbd0824..dc2fd3e97d 100644 --- a/test/functional/autocmd/tabnewentered_spec.lua +++ b/test/functional/autocmd/tabnewentered_spec.lua @@ -97,6 +97,7 @@ describe('tabpage/previous', function() switches_to_previous_after_new_tab_creation_at_end('g')) it('switches to previous via g. after new tab creation at end', switches_to_previous_after_new_tab_creation_at_end('g')) it('switches to previous via . after new tab creation at end', switches_to_previous_after_new_tab_creation_at_end('')) + it('switches to previous via :tabn #. after new tab creation at end', switches_to_previous_after_new_tab_creation_at_end(':tabn #')) local function switches_to_previous_after_new_tab_creation_in_middle(characters) return function() @@ -140,6 +141,8 @@ describe('tabpage/previous', function() switches_to_previous_after_new_tab_creation_in_middle('g')) it('switches to previous via after new tab creation in middle', switches_to_previous_after_new_tab_creation_in_middle('')) + it('switches to previous via :tabn # after new tab creation in middle', + switches_to_previous_after_new_tab_creation_in_middle(':tabn #')) local function switches_to_previous_after_switching_to_next_tab(characters) return function() @@ -180,6 +183,8 @@ describe('tabpage/previous', function() switches_to_previous_after_switching_to_next_tab('g')) it('switches to previous via after switching to next tab', switches_to_previous_after_switching_to_next_tab('')) + it('switches to previous via :tabn # after switching to next tab', + switches_to_previous_after_switching_to_next_tab(':tabn #')) local function switches_to_previous_after_switching_to_last_tab(characters) return function() @@ -222,6 +227,8 @@ describe('tabpage/previous', function() switches_to_previous_after_switching_to_last_tab('g')) it('switches to previous after switching to last tab', switches_to_previous_after_switching_to_last_tab('')) + it('switches to previous after switching to last tab', + switches_to_previous_after_switching_to_last_tab(':tabn #')) local function switches_to_previous_after_switching_to_previous_tab(characters) return function() @@ -262,6 +269,8 @@ describe('tabpage/previous', function() switches_to_previous_after_switching_to_previous_tab('g')) it('switches to previous via after switching to previous tab', switches_to_previous_after_switching_to_previous_tab('')) + it('switches to previous via :tabn # after switching to previous tab', + switches_to_previous_after_switching_to_previous_tab(':tabn #')) local function switches_to_previous_after_switching_to_first_tab(characters) return function() @@ -304,6 +313,8 @@ describe('tabpage/previous', function() switches_to_previous_after_switching_to_first_tab('g')) it('switches to previous via after switching to first tab', switches_to_previous_after_switching_to_first_tab('')) + it('switches to previous via :tabn # after switching to first tab', + switches_to_previous_after_switching_to_first_tab(':tabn #')) local function switches_to_previous_after_numbered_tab_switch(characters) return function() @@ -344,6 +355,8 @@ describe('tabpage/previous', function() switches_to_previous_after_numbered_tab_switch('g')) it('switches to previous via after numbered tab switch', switches_to_previous_after_numbered_tab_switch('')) + it('switches to previous via :tabn # after numbered tab switch', + switches_to_previous_after_numbered_tab_switch(':tabn #')) local function switches_to_previous_after_switching_to_previous(characters1, characters2) return function() @@ -386,18 +399,32 @@ describe('tabpage/previous', function() switches_to_previous_after_switching_to_previous('g', 'g')) it('switches to previous via after switching to previous via g', switches_to_previous_after_switching_to_previous('g', '')) + it('switches to previous via :tabn # after switching to previous via g', + switches_to_previous_after_switching_to_previous('g', ':tabn #')) it('switches to previous via g after switching to previous via g', switches_to_previous_after_switching_to_previous('g', 'g')) it('switches to previous via g after switching to previous via g', switches_to_previous_after_switching_to_previous('g', 'g')) it('switches to previous via after switching to previous via g', switches_to_previous_after_switching_to_previous('g', '')) + it('switches to previous via :tabn # after switching to previous via g', + switches_to_previous_after_switching_to_previous('g', ':tabn #')) it('switches to previous via g after switching to previous via ', switches_to_previous_after_switching_to_previous('', 'g')) it('switches to previous via g after switching to previous via ', switches_to_previous_after_switching_to_previous('', 'g')) it('switches to previous via after switching to previous via ', switches_to_previous_after_switching_to_previous('', '')) + it('switches to previous via :tabn # after switching to previous via ', + switches_to_previous_after_switching_to_previous('', ':tabn #')) + it('switches to previous via g after switching to previous via :tabn #', + switches_to_previous_after_switching_to_previous(':tabn #', 'g')) + it('switches to previous via g after switching to previous via :tabn #', + switches_to_previous_after_switching_to_previous(':tabn #', 'g')) + it('switches to previous via after switching to previous via ', + switches_to_previous_after_switching_to_previous(':tabn #', '')) + it('switches to previous via :tabn # after switching to previous via :tabn #', + switches_to_previous_after_switching_to_previous(':tabn #', ':tabn #')) local function does_not_switch_to_previous_after_closing_current_tab(characters) return function() @@ -437,6 +464,8 @@ describe('tabpage/previous', function() does_not_switch_to_previous_after_closing_current_tab('g')) it('does not switch to previous via after closing current tab', does_not_switch_to_previous_after_closing_current_tab('')) + it('does not switch to previous via :tabn # after closing current tab', + does_not_switch_to_previous_after_closing_current_tab(':tabn #')) local function does_not_switch_to_previous_after_entering_operator_pending(characters) return function() @@ -480,6 +509,11 @@ describe('tabpage/previous', function() -- does_not_switch_to_previous_after_entering_operator_pending('g')) it('does not switch to previous via after entering operator pending', does_not_switch_to_previous_after_entering_operator_pending('')) + -- NOTE: When in operator pending mode, pressing : leaves operator pending + -- mode and enters command mode, so :tabn # does in fact switch + -- tabs. + -- it('does not switch to previous via :tabn # after entering operator pending', + -- does_not_switch_to_previous_after_entering_operator_pending(':tabn #')) local function cmdline_win_prevents_tab_switch(characters, completion_visible) return function() @@ -516,6 +550,8 @@ describe('tabpage/previous', function() cmdline_win_prevents_tab_switch('g', 1)) it('cmdline-win prevents tab switch via ', cmdline_win_prevents_tab_switch('', 0)) + it('cmdline-win prevents tab switch via :tabn #', + cmdline_win_prevents_tab_switch(':tabn #', 0)) it(':tabs indicates correct prevtab curwin', function() -- Add three tabs for a total of four -- cgit From 3420bd21e19cf5feaeca1524e0dfcbabaac5d7c5 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Mon, 13 Jan 2020 19:48:59 -0500 Subject: provider/perl: add basic tests --- test/functional/helpers.lua | 2 +- test/functional/provider/perl_spec.lua | 75 ++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 test/functional/provider/perl_spec.lua (limited to 'test') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index de61ff9cc8..3ffc6137d6 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -768,7 +768,7 @@ function module.new_pipename() end function module.missing_provider(provider) - if provider == 'ruby' or provider == 'node' then + if provider == 'ruby' or provider == 'node' or provider == 'perl' then local prog = module.funcs['provider#' .. provider .. '#Detect']() return prog == '' and (provider .. ' not detected') or false elseif provider == 'python' or provider == 'python3' then diff --git a/test/functional/provider/perl_spec.lua b/test/functional/provider/perl_spec.lua new file mode 100644 index 0000000000..640fe0f622 --- /dev/null +++ b/test/functional/provider/perl_spec.lua @@ -0,0 +1,75 @@ +local helpers = require('test.functional.helpers')(after_each) +local eq, clear = helpers.eq, helpers.clear +local missing_provider = helpers.missing_provider +local command = helpers.command +local write_file = helpers.write_file +local eval = helpers.eval +local retry = helpers.retry + +do + clear() + local reason = missing_provider('perl') + if reason then + pending(string.format("Missing perl host, or perl version is too old (%s)", reason), function() end) + return + end +end + +before_each(function() + clear() +end) + +describe('perl host', function() + teardown(function () + os.remove('Xtest-perl-hello.pl') + os.remove('Xtest-perl-hello-plugin.pl') + end) + + it('works', function() + local fname = 'Xtest-perl-hello.pl' + write_file(fname, [[ + package main; + use v5.22.1; + use Neovim::Ext; + use Neovim::Ext::MsgPack::RPC; + + my $session = Neovim::Ext::MsgPack::RPC::socket_session($ENV{NVIM_LISTEN_ADDRESS}); + my $nvim = Neovim::Ext::from_session($session); + $nvim->command('let g:job_out = "hello"'); + 1; + ]]) + command('let g:job_id = jobstart(["perl", "'..fname..'"])') + retry(nil, 3000, function() eq('hello', eval('g:job_out')) end) + end) + + it('plugin works', function() + local fname = 'Xtest-perl-hello-plugin.pl' + write_file(fname, [[ + package TestPlugin; + use parent qw(Neovim::Ext::Plugin); + + __PACKAGE__->register; + + @{TestPlugin::commands} = (); + @{TestPlugin::specs} = (); + sub test_command :nvim_command('TestCommand') + { + my ($this) = @_; + $this->nvim->command('let g:job_out = "hello-plugin"'); + } + + package main; + use v5.22.1; + use Neovim::Ext; + use Neovim::Ext::MsgPack::RPC; + + my $session = Neovim::Ext::MsgPack::RPC::socket_session($ENV{NVIM_LISTEN_ADDRESS}); + my $nvim = Neovim::Ext::from_session($session); + my $plugin = TestPlugin->new($nvim); + $plugin->test_command(); + 1; + ]]) + command('let g:job_id = jobstart(["perl", "'..fname..'"])') + retry(nil, 3000, function() eq('hello-plugin', eval('g:job_out')) end) + end) +end) -- cgit From ff9f70a6bfe3206c258c5c25e3148fbe1afd6ed2 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 18 Jan 2020 10:39:12 -0500 Subject: provider/perl: skip tests on Windows It worked for MINGW builds at one point but it keeps failing now because of perl dependencies or nvim session issues for tests (named pipes as sockets on Windows?). --- test/functional/provider/perl_spec.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'test') diff --git a/test/functional/provider/perl_spec.lua b/test/functional/provider/perl_spec.lua index 640fe0f622..38cecae35c 100644 --- a/test/functional/provider/perl_spec.lua +++ b/test/functional/provider/perl_spec.lua @@ -20,6 +20,7 @@ before_each(function() end) describe('perl host', function() + if helpers.pending_win32(pending) then return end teardown(function () os.remove('Xtest-perl-hello.pl') os.remove('Xtest-perl-hello-plugin.pl') -- cgit From 7853b6178612f471fb0c580538294fda41555614 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 19 Jan 2020 22:50:11 -0500 Subject: provider/perl: test older versions --- test/functional/provider/perl_spec.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/functional/provider/perl_spec.lua b/test/functional/provider/perl_spec.lua index 38cecae35c..7b446e4ab3 100644 --- a/test/functional/provider/perl_spec.lua +++ b/test/functional/provider/perl_spec.lua @@ -30,7 +30,8 @@ describe('perl host', function() local fname = 'Xtest-perl-hello.pl' write_file(fname, [[ package main; - use v5.22.1; + use strict; + use warnings; use Neovim::Ext; use Neovim::Ext::MsgPack::RPC; @@ -47,6 +48,8 @@ describe('perl host', function() local fname = 'Xtest-perl-hello-plugin.pl' write_file(fname, [[ package TestPlugin; + use strict; + use warnings; use parent qw(Neovim::Ext::Plugin); __PACKAGE__->register; @@ -60,7 +63,8 @@ describe('perl host', function() } package main; - use v5.22.1; + use strict; + use warnings; use Neovim::Ext; use Neovim::Ext::MsgPack::RPC; -- cgit From 97dcc48c998ccecaa37a3cbea568d85c2f1407f9 Mon Sep 17 00:00:00 2001 From: akovaski Date: Tue, 21 Jan 2020 02:35:01 -0600 Subject: wildmode: fix wildmode=longest,full with pum #11690 With "wildmode=longest,full" + wildoptions=pum, wildmode should show popupmenu after Tab-Tab, not the horizontal wildmenu. Fixes #11622 --- test/functional/ui/popupmenu_spec.lua | 59 +++++++++++++++----- test/functional/ui/wildmode_spec.lua | 100 ++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+), 13 deletions(-) (limited to 'test') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index a0e5c3ca63..b2ebf7af19 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -640,7 +640,7 @@ describe('builtin popupmenu', function() }) end) - it('works with preview-window above', function() + it('with preview-window above', function() feed(':ped4+') feed('iaa bb cc dd ee ff gg hh ii jj') feed('') @@ -668,7 +668,7 @@ describe('builtin popupmenu', function() ]]) end) - it('works with preview-window below', function() + it('with preview-window below', function() feed(':ped4+r') feed('iaa bb cc dd ee ff gg hh ii jj') feed('') @@ -696,7 +696,7 @@ describe('builtin popupmenu', function() ]]) end) - it('works with preview-window above and tall and inverted', function() + it('with preview-window above and tall and inverted', function() feed(':ped8+') feed('iaabbccddee') feed('ffgghhiijj') @@ -726,7 +726,7 @@ describe('builtin popupmenu', function() ]]) end) - it('works with preview-window above and short and inverted', function() + it('with preview-window above and short and inverted', function() feed(':ped4+') feed('iaabbccddee') feed('ffgghhiijj') @@ -755,7 +755,7 @@ describe('builtin popupmenu', function() ]]) end) - it('works with preview-window below and inverted', function() + it('with preview-window below and inverted', function() feed(':ped4+r') feed('iaabbccddee') feed('ffgghhiijj') @@ -784,7 +784,7 @@ describe('builtin popupmenu', function() ]]) end) - it('works with vsplits', function() + it('with vsplits', function() insert('aaa aab aac\n') feed(':vsplit') screen:expect([[ @@ -859,7 +859,7 @@ describe('builtin popupmenu', function() ]]) end) - it('works with split and scroll', function() + it('with split and scroll', function() screen:try_resize(60,14) command("split") command("set completeopt+=noinsert") @@ -1293,7 +1293,7 @@ describe('builtin popupmenu', function() ]]) end) - it('behaves correcty with VimResized autocmd', function() + it('with VimResized autocmd', function() feed('isome long prefix before the ') command("set completeopt+=noinsert,noselect") command("autocmd VimResized * redraw!") @@ -1337,7 +1337,7 @@ describe('builtin popupmenu', function() ]]) end) - it('works with rightleft window', function() + it('with rightleft window', function() command("set rl") feed('isome rightleft ') screen:expect([[ @@ -1437,7 +1437,7 @@ describe('builtin popupmenu', function() ]]) end) - it('works with multiline messages', function() + it('with multiline messages', function() screen:try_resize(40,8) feed('ixx') command('imap echoerr "very"\\|echoerr "much"\\|echoerr "error"') @@ -1514,7 +1514,7 @@ describe('builtin popupmenu', function() ]], unchanged=true} end) - it('works with kind, menu and abbr attributes', function() + it('with kind, menu and abbr attributes', function() screen:try_resize(40,8) feed('ixx ') funcs.complete(4, {{word='wordey', kind= 'x', menu='extrainfo'}, 'thing', {word='secret', abbr='sneaky', menu='bar'}}) @@ -1566,7 +1566,7 @@ describe('builtin popupmenu', function() ]]) end) - it('works with wildoptions=pum', function() + it('wildoptions=pum', function() screen:try_resize(32,10) command('set wildmenu') command('set wildoptions=pum') @@ -1738,7 +1738,7 @@ describe('builtin popupmenu', function() ]]) end) - it('works with wildoptions=pum with scrolled mesages ', function() + it('wildoptions=pum with scrolled mesages ', function() screen:try_resize(40,10) command('set wildmenu') command('set wildoptions=pum') @@ -1786,6 +1786,39 @@ describe('builtin popupmenu', function() ]]} end) + it('wildoptions=pum and wildmode=longest,full #11622', function() + screen:try_resize(30,8) + command('set wildmenu') + command('set wildoptions=pum') + command('set wildmode=longest,full') + + feed(':sign u') + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign un^ | + ]]} + eq(0, funcs.wildmenumode()) + + feed('') + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }{s: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign undefine^ | + ]]} + eq(1, funcs.wildmenumode()) + end) + it("'pumblend' RGB-color", function() screen:try_resize(60,14) screen:set_default_attr_ids({ diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua index f3fa711fb1..56987d7bc2 100644 --- a/test/functional/ui/wildmode_spec.lua +++ b/test/functional/ui/wildmode_spec.lua @@ -221,6 +221,106 @@ describe("'wildmenu'", function() ]]) end) + it('wildmode=longest,list', function() + -- Need more than 5 rows, else tabline is covered and will be redrawn. + screen:try_resize(25, 7) + + command('set wildmenu wildmode=longest,list') + + -- give wildmode-longest something to expand to + feed(':sign u') + screen:expect([[ + | + ~ | + ~ | + ~ | + ~ | + ~ | + :sign un^ | + ]]) + feed('') -- trigger wildmode list + screen:expect([[ + | + ~ | + ~ | + | + :sign un | + undefine unplace | + :sign un^ | + ]]) + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + ~ | + ~ | + | + ]]) + + -- give wildmode-longest something it cannot expand, use list + feed(':sign un') + screen:expect([[ + | + ~ | + ~ | + | + :sign un | + undefine unplace | + :sign un^ | + ]]) + feed('') + screen:expect_unchanged() + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + ~ | + ~ | + | + ]]) + end) + + it('wildmode=list,longest', function() + -- Need more than 5 rows, else tabline is covered and will be redrawn. + screen:try_resize(25, 7) + + command('set wildmenu wildmode=list,longest') + feed(':sign u') + screen:expect([[ + | + ~ | + ~ | + | + :sign u | + undefine unplace | + :sign u^ | + ]]) + feed('') -- trigger wildmode longest + screen:expect([[ + | + ~ | + ~ | + | + :sign u | + undefine unplace | + :sign un^ | + ]]) + feed('') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + ~ | + ~ | + | + ]]) + end) + it('multiple renders correctly', function() screen:try_resize(25, 7) -- cgit From 041ec8997a7f613f2ca13bf339c652f117fcb809 Mon Sep 17 00:00:00 2001 From: Billy Su Date: Mon, 20 Jan 2020 20:06:38 +0800 Subject: Fix f_jobstop() failed loudly The return value of jobstop() @return 1 for valid job id 0 for invalid id, including jobs have exited or stopped --- test/functional/core/job_spec.lua | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'test') diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index b63b868127..57e6f4fd63 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -306,16 +306,16 @@ describe('jobs', function() end)) end) - it('disallows jobsend/stop on a non-existent job', function() + it('disallows jobsend on a non-existent job', function() eq(false, pcall(eval, "jobsend(-1, 'lol')")) - eq(false, pcall(eval, "jobstop(-1)")) + eq(0, eval('jobstop(-1)')) end) - it('disallows jobstop twice on the same job', function() + it('jobstop twice on the stopped or exited job return 0', function() nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)") neq(0, eval('j')) - eq(true, pcall(eval, "jobstop(j)")) - eq(false, pcall(eval, "jobstop(j)")) + eq(1, eval("jobstop(j)")) + eq(0, eval("jobstop(j)")) end) it('will not leak memory if we leave a job running', function() @@ -919,6 +919,13 @@ describe('jobs', function() end) end) + it('jobstop on same id before stopped', function() + nvim('command', 'let j = jobstart(["cat", "-"], g:job_opts)') + neq(0, eval('j')) + + eq({1, 0}, eval('[jobstop(j), jobstop(j)]')) + end) + describe('running tty-test program', function() if helpers.pending_win32(pending) then return end local function next_chunk() -- cgit From 961c528afc7f3a21a8c4b118a2c585dbe670c5c5 Mon Sep 17 00:00:00 2001 From: Billy Su Date: Wed, 22 Jan 2020 17:50:33 +0800 Subject: ex_getln.c: wildmenu add cancel and apply ops --- test/functional/ui/wildmode_spec.lua | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'test') diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua index f3fa711fb1..d655ab20d3 100644 --- a/test/functional/ui/wildmode_spec.lua +++ b/test/functional/ui/wildmode_spec.lua @@ -16,6 +16,44 @@ describe("'wildmenu'", function() screen:attach() end) + it('C-E to cancel wildmenu completion restore original input', function() + feed(':sign ') + screen:expect([[ + | + ~ | + ~ | + define jump list > | + :sign define^ | + ]]) + feed('') + screen:expect([[ + | + ~ | + ~ | + ~ | + :sign ^ | + ]]) + end) + + it('C-Y to apply selection and end wildmenu completion', function() + feed(':sign ') + screen:expect([[ + | + ~ | + ~ | + define jump list > | + :sign define^ | + ]]) + feed('') + screen:expect([[ + | + ~ | + ~ | + ~ | + :sign jump^ | + ]]) + end) + it(':sign shows wildmenu completions', function() command('set wildmenu wildmode=full') feed(':sign ') -- cgit From c6ff23d7a0d5ccf0d8995e3204c18df55d28fc7f Mon Sep 17 00:00:00 2001 From: Chris LaRose Date: Sun, 26 Jan 2020 00:24:42 -0800 Subject: terminal: absolute CWD in term:// URI #11289 This makes it possible to restore the working directory of :terminal buffers when reading those buffers from a session file. Fixes #11288 Co-authored-by: Justin M. Keyes --- test/functional/ex_cmds/mksession_spec.lua | 23 ++++++++++++++++++++++- test/functional/terminal/edit_spec.lua | 6 +++++- 2 files changed, 27 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/functional/ex_cmds/mksession_spec.lua b/test/functional/ex_cmds/mksession_spec.lua index 0f7860740e..855f8105aa 100644 --- a/test/functional/ex_cmds/mksession_spec.lua +++ b/test/functional/ex_cmds/mksession_spec.lua @@ -6,6 +6,8 @@ local command = helpers.command local get_pathsep = helpers.get_pathsep local eq = helpers.eq local funcs = helpers.funcs +local matches = helpers.matches +local pesc = helpers.pesc local rmdir = helpers.rmdir local file_prefix = 'Xtest-functional-ex_cmds-mksession_spec' @@ -48,7 +50,7 @@ describe(':mksession', function() eq(cwd_dir .. get_pathsep() .. tab_dir, funcs.getcwd()) end) - it('restores buffers when using tab-local working directories', function() + it('restores buffers with tab-local CWD', function() local tmpfile_base = file_prefix .. '-tmpfile' local cwd_dir = funcs.getcwd() local session_path = cwd_dir .. get_pathsep() .. session_file @@ -70,4 +72,23 @@ describe(':mksession', function() command('tabnext 2') eq(cwd_dir .. get_pathsep() .. tmpfile_base .. '2', funcs.expand('%:p')) end) + + it('restores CWD for :terminal buffers #11288', function() + local cwd_dir = funcs.fnamemodify('.', ':p:~'):gsub([[[\/]*$]], '') + local session_path = cwd_dir..get_pathsep()..session_file + + command('cd '..tab_dir) + command('terminal echo $PWD') + command('cd '..cwd_dir) + command('mksession '..session_path) + command('qall!') + + -- Create a new test instance of Nvim. + clear() + command('silent source '..session_path) + + local expected_cwd = cwd_dir..get_pathsep()..tab_dir + matches('^term://'..pesc(expected_cwd)..'//%d+:', funcs.expand('%')) + command('qall!') + end) end) diff --git a/test/functional/terminal/edit_spec.lua b/test/functional/terminal/edit_spec.lua index d213bae7b3..fabc5524ed 100644 --- a/test/functional/terminal/edit_spec.lua +++ b/test/functional/terminal/edit_spec.lua @@ -5,9 +5,12 @@ local curbufmeths = helpers.curbufmeths local curwinmeths = helpers.curwinmeths local nvim_dir = helpers.nvim_dir local command = helpers.command +local funcs = helpers.funcs local meths = helpers.meths local clear = helpers.clear local eq = helpers.eq +local matches = helpers.matches +local pesc = helpers.pesc describe(':edit term://*', function() local get_screen = function(columns, lines) @@ -28,7 +31,8 @@ describe(':edit term://*', function() command('edit term://') local termopen_runs = meths.get_var('termopen_runs') eq(1, #termopen_runs) - eq(termopen_runs[1], termopen_runs[1]:match('^term://.//%d+:$')) + local cwd = funcs.fnamemodify('.', ':p:~'):gsub([[[\/]*$]], '') + matches('^term://'..pesc(cwd)..'//%d+:$', termopen_runs[1]) end) it("runs TermOpen early enough to set buffer-local 'scrollback'", function() -- cgit From 687fc527de5262133991c5721c349328c9a58d3d Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Fri, 24 Jan 2020 10:52:17 +0100 Subject: screen: add missing redraws after a message --- test/functional/ui/messages_spec.lua | 86 ++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) (limited to 'test') diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index dfc3d045e8..0b822bc2f2 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -811,6 +811,8 @@ describe('ui/builtin messages', function() [5] = {foreground = Screen.colors.Blue1}, [6] = {bold = true, foreground = Screen.colors.Magenta}, [7] = {background = Screen.colors.Grey20}, + [8] = {reverse = true}, + [9] = {background = Screen.colors.LightRed} }) end) @@ -962,6 +964,90 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim zbc | ]]} end) + + it('redraws NOT_VALID correctly after message', function() + -- edge case: only one window was set NOT_VALID. Orginal report + -- used :make, but fake it using one command to set the current + -- window NOT_VALID and another to show a long message. + feed(':new') + screen:expect{grid=[[ + | + {1:~ }| + {8:[No Name] }| + ^ | + {1:~ }| + {3:[No Name] }| + :new | + ]]} + + feed(':set colorcolumn=10 | digraphs') + screen:expect{grid=[[ + er {5:ㄦ} 12582 i4 {5:ㄧ} 12583 u4 {5:ㄨ} 12584 iu {5:ㄩ} 12585 | + v4 {5:ㄪ} 12586 nG {5:ㄫ} 12587 gn {5:ㄬ} 12588 1c {5:㈠} 12832 | + 2c {5:㈡} 12833 3c {5:㈢} 12834 4c {5:㈣} 12835 5c {5:㈤} 12836 | + 6c {5:㈥} 12837 7c {5:㈦} 12838 8c {5:㈧} 12839 9c {5:㈨} 12840 | + ff {5:ff} 64256 fi {5:fi} 64257 fl {5:fl} 64258 ft {5:ſt} 64261 | + st {5:st} 64262 | + {4:Press ENTER or type command to continue}^ | + ]]} + + feed('') + screen:expect{grid=[[ + | + {1:~ }| + {8:[No Name] }| + ^ {9: } | + {1:~ }| + {3:[No Name] }| + | + ]]} + + -- edge case: just covers statusline + feed(':set colorcolumn=5 | lua error("x\\n\\nx")') + screen:expect{grid=[[ + | + {1:~ }| + {3: }| + {2:E5108: Error executing lua [string ":lua"]:1: x} | + | + {2:x} | + {4:Press ENTER or type command to continue}^ | + ]]} + + feed('') + screen:expect{grid=[[ + | + {1:~ }| + {8:[No Name] }| + ^ {9: } | + {1:~ }| + {3:[No Name] }| + | + ]]} + + -- edge case: just covers lowest window line + feed(':set colorcolumn=5 | lua error("x\\n\\n\\nx")') + screen:expect{grid=[[ + | + {3: }| + {2:E5108: Error executing lua [string ":lua"]:1: x} | + | + | + {2:x} | + {4:Press ENTER or type command to continue}^ | + ]]} + + feed('') + screen:expect{grid=[[ + | + {1:~ }| + {8:[No Name] }| + ^ {9: } | + {1:~ }| + {3:[No Name] }| + | + ]]} + end) end) describe('ui/ext_messages', function() -- cgit From 08c5a874ab97d52e215025ccd010d68fcdf14731 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 26 Jan 2020 08:17:08 -0500 Subject: vim-patch:8.1.1143: may pass weird strings to file name expansion Problem: May pass weird strings to file name expansion. Solution: Check for matching characters. Disallow control characters. https://github.com/vim/vim/commit/8f130eda4747e4a4d68353cdb650f359fd01469b --- test/functional/legacy/097_glob_path_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/legacy/097_glob_path_spec.lua b/test/functional/legacy/097_glob_path_spec.lua index ccd93fed60..dd5a26ad3b 100644 --- a/test/functional/legacy/097_glob_path_spec.lua +++ b/test/functional/legacy/097_glob_path_spec.lua @@ -52,7 +52,7 @@ describe('glob() and globpath()', function() command([[$put =glob('Xxx\{')]]) command([[$put =glob('Xxx\$')]]) - command('silent w! Xxx{') + command('silent w! Xxx\\{') command([[w! Xxx\$]]) command([[$put =glob('Xxx\{')]]) command([[$put =glob('Xxx\$')]]) -- cgit From cf67f19ac2104ece76d040c8184bc287428299b3 Mon Sep 17 00:00:00 2001 From: Alexandre Dubray Date: Tue, 9 Jan 2018 12:01:02 +0100 Subject: mksession: restore same :term buf in split windows Problem: When session-restore creates a terminal buffer with command like `:edit term://.//16450:/bin/bash`, the buffer gets a different name (depends on PID). Thus the later call to `bufexists('term://.//16450:/bin/bash)` will return false. Solution: Force the buffer name with :file. This as least ensures the same buffer will show in multiple windows correctly, as expected when saving the session. But it still has problems: 1. the PID in the buffer name is bogus 2. redundant :terminal buffers still hang around fix #5250 --- test/functional/ex_cmds/mksession_spec.lua | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'test') diff --git a/test/functional/ex_cmds/mksession_spec.lua b/test/functional/ex_cmds/mksession_spec.lua index 855f8105aa..726cfe7fe5 100644 --- a/test/functional/ex_cmds/mksession_spec.lua +++ b/test/functional/ex_cmds/mksession_spec.lua @@ -91,4 +91,23 @@ describe(':mksession', function() matches('^term://'..pesc(expected_cwd)..'//%d+:', funcs.expand('%')) command('qall!') end) + + it('restores multiple windows with same terminal instances', function() + -- Create a view with two buffers referencing the same terminal instance + command('terminal') + command('split') + command('mksession ' .. session_file) + + clear() + + command('source ' .. session_file) + -- Getting the name of the buffer shown to compare with the other window + local eval = helpers.eval + + command('exe 1 . "wincmd w"') + local expected_pid = eval('b:terminal_job_pid') + + command('exe 2 . "wincmd w"') + eq(expected_pid, eval('b:terminal_job_pid')) + end) end) -- cgit From 1e103b3c12597a9dd2f20d45686822ab6ee089b0 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 26 Jan 2020 02:43:12 -0800 Subject: mksession: simplify generated commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Doing ":file …" immediately after is enough to fixup the :terminal buffer name. ref #5250 --- test/functional/ex_cmds/mksession_spec.lua | 40 ++++++++++++++++-------------- 1 file changed, 21 insertions(+), 19 deletions(-) (limited to 'test') diff --git a/test/functional/ex_cmds/mksession_spec.lua b/test/functional/ex_cmds/mksession_spec.lua index 726cfe7fe5..305850a09e 100644 --- a/test/functional/ex_cmds/mksession_spec.lua +++ b/test/functional/ex_cmds/mksession_spec.lua @@ -26,6 +26,27 @@ describe(':mksession', function() rmdir(tab_dir) end) + it('restores same :terminal buf in splits', function() + -- If the same :terminal is displayed in multiple windows, :mksession + -- should restore it as such. + + -- Create two windows showing the same :terminal buffer. + command('terminal') + command('split') + command('terminal') + command('split') + command('mksession '..session_file) + + -- Create a new test instance of Nvim. + command('qall!') + clear() + -- Restore session. + command('source '..session_file) + + eq({3,3,2}, + {funcs.winbufnr(1), funcs.winbufnr(2), funcs.winbufnr(3)}) + end) + it('restores tab-local working directories', function() local tmpfile_base = file_prefix .. '-tmpfile' local cwd_dir = funcs.getcwd() @@ -91,23 +112,4 @@ describe(':mksession', function() matches('^term://'..pesc(expected_cwd)..'//%d+:', funcs.expand('%')) command('qall!') end) - - it('restores multiple windows with same terminal instances', function() - -- Create a view with two buffers referencing the same terminal instance - command('terminal') - command('split') - command('mksession ' .. session_file) - - clear() - - command('source ' .. session_file) - -- Getting the name of the buffer shown to compare with the other window - local eval = helpers.eval - - command('exe 1 . "wincmd w"') - local expected_pid = eval('b:terminal_job_pid') - - command('exe 2 . "wincmd w"') - eq(expected_pid, eval('b:terminal_job_pid')) - end) end) -- cgit From 1c3ca4f18fdc403813d8959b49626ac1c99e2c59 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 26 Jan 2020 14:26:01 -0800 Subject: mksession: always unix slashes "/" for filepaths --- test/functional/ex_cmds/mksession_spec.lua | 5 +++-- test/functional/helpers.lua | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/test/functional/ex_cmds/mksession_spec.lua b/test/functional/ex_cmds/mksession_spec.lua index 305850a09e..949724bb53 100644 --- a/test/functional/ex_cmds/mksession_spec.lua +++ b/test/functional/ex_cmds/mksession_spec.lua @@ -96,7 +96,8 @@ describe(':mksession', function() it('restores CWD for :terminal buffers #11288', function() local cwd_dir = funcs.fnamemodify('.', ':p:~'):gsub([[[\/]*$]], '') - local session_path = cwd_dir..get_pathsep()..session_file + cwd_dir = cwd_dir:gsub([[\]], '/') -- :mksession always uses unix slashes. + local session_path = cwd_dir..'/'..session_file command('cd '..tab_dir) command('terminal echo $PWD') @@ -108,7 +109,7 @@ describe(':mksession', function() clear() command('silent source '..session_path) - local expected_cwd = cwd_dir..get_pathsep()..tab_dir + local expected_cwd = cwd_dir..'/'..tab_dir matches('^term://'..pesc(expected_cwd)..'//%d+:', funcs.expand('%')) command('qall!') end) diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 3ffc6137d6..53c4d140b6 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -794,7 +794,7 @@ function module.alter_slashes(obj) end return ret else - assert(false, 'Could only alter slashes for tables of strings and strings') + assert(false, 'expected string or table of strings, got '..type(obj)) end end -- cgit From bfe84adb5a097488fa723f9917253bd6f0fbf662 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Tue, 28 Jan 2020 12:49:29 +0100 Subject: options: winhighlight: fix incorrect string equality test --- test/functional/ui/highlight_spec.lua | 42 +++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'test') diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index d7791a3107..28e4e88326 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -1186,6 +1186,7 @@ describe("'winhighlight' highlight", function() [25] = {bold = true, foreground = Screen.colors.Green1}, [26] = {background = Screen.colors.Red}, [27] = {background = Screen.colors.DarkBlue, bold = true, foreground = Screen.colors.Green1}, + [28] = {bold = true, foreground = Screen.colors.Brown}, }) command("hi Background1 guibg=DarkBlue") command("hi Background2 guibg=DarkGreen") @@ -1598,4 +1599,45 @@ describe("'winhighlight' highlight", function() {21:-- }{22:match 1 of 3} | ]]) end) + + it('can override CursorLine and CursorLineNr', function() + -- CursorLine used to be parsed as CursorLineNr, because strncmp + command('set cursorline number') + command('split') + command('set winhl=CursorLine:Background1') + screen:expect{grid=[[ + {28: 1 }{1:^ }| + {0:~ }| + {0:~ }| + {3:[No Name] }| + {28: 1 }{18: }| + {0:~ }| + {4:[No Name] }| + | + ]]} + + command('set winhl=CursorLineNr:Background2,CursorLine:Background1') + screen:expect{grid=[[ + {5: 1 }{1:^ }| + {0:~ }| + {0:~ }| + {3:[No Name] }| + {28: 1 }{18: }| + {0:~ }| + {4:[No Name] }| + | + ]]} + + feed('w') + screen:expect{grid=[[ + {5: 1 }{1: }| + {0:~ }| + {0:~ }| + {4:[No Name] }| + {28: 1 }{18:^ }| + {0:~ }| + {3:[No Name] }| + | + ]]} + end) end) -- cgit From 2538e615130c7f4baa1029d0be2bc2d7f66cdd7e Mon Sep 17 00:00:00 2001 From: Axel Forsman Date: Thu, 30 Jan 2020 07:34:34 +0100 Subject: Fix shift change callbacks reading bad cursor (#11782) Sloppy code inherited from Vim caused user scripts to be able to observe the cursor line in an invalid intermediary state, due to Neovim change callbacks being unbuffered unlike Vim listeners. Manifested in Vimscript executed from the callback possibly erroring when `:call`:ing any function, due to the implicit range `curwin->w_cursor.lnum,curwin->w_cursor.lnum` failing validation. Fixed by deferring the call to `changed_lines()` until after `curwin->w_cursor.lnum` gets its correct value. --- test/functional/lua/buffer_updates_spec.lua | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'test') diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index 990cb97fec..7d3ecbf912 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -203,4 +203,17 @@ describe('lua: buffer event callbacks', function() { "test1", "lines", 1, tick+1, 5, 6, 5, 27, 20, 20 }}, exec_lua("return get_events(...)" )) end) + it('has valid cursor position while shifting', function() + meths.buf_set_lines(0, 0, -1, true, {'line1'}) + exec_lua([[ + vim.api.nvim_buf_attach(0, false, { + on_lines = function() + vim.api.nvim_set_var('listener_cursor_line', vim.api.nvim_win_get_cursor(0)[1]) + end, + }) + ]]) + feed('>>') + eq(1, meths.get_var('listener_cursor_line')) + end) + end) -- cgit From 14a8b3b98c245087ef431070195f3a2fa3db16c0 Mon Sep 17 00:00:00 2001 From: Hye Sung Jung Date: Fri, 31 Jan 2020 00:56:34 -0600 Subject: doc: fix typos [ci skip] #11787 --- test/functional/legacy/021_control_wi_spec.lua | 2 +- test/functional/legacy/eval_spec.lua | 4 ++-- test/functional/lua/buffer_updates_spec.lua | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'test') diff --git a/test/functional/legacy/021_control_wi_spec.lua b/test/functional/legacy/021_control_wi_spec.lua index 87d9deed7a..94871433cd 100644 --- a/test/functional/legacy/021_control_wi_spec.lua +++ b/test/functional/legacy/021_control_wi_spec.lua @@ -18,7 +18,7 @@ describe('CTRL-W CTRL-I', function() start found wrong line test text]]) - -- Search for the second occurence of start and append to register + -- Search for the second occurrence of start and append to register feed_command('/start') feed('2[') feed_command('yank A') diff --git a/test/functional/legacy/eval_spec.lua b/test/functional/legacy/eval_spec.lua index c5d38d6d05..4198ea8bfe 100644 --- a/test/functional/legacy/eval_spec.lua +++ b/test/functional/legacy/eval_spec.lua @@ -360,7 +360,7 @@ describe('eval', function() abcD3b]]) -- From now on we delete the buffer contents after each expect() to make - -- the next expect() easier to write. This is neccessary because null + -- the next expect() easier to write. This is necessary because null -- bytes on a line by itself don't play well together with the dedent -- function used in expect(). command('%delete') @@ -416,7 +416,7 @@ describe('eval', function() ' abcD3b50') end) - -- The tests for setting lists with NLs are split into seperate it() blocks + -- The tests for setting lists with NLs are split into separate it() blocks -- to make the expect() calls easier to write. Otherwise the null byte can -- make trouble on a line on its own. it('setting lists with NLs with setreg(), part 1', function() diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index 7d3ecbf912..77f8189bb9 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -98,7 +98,7 @@ describe('lua: buffer event callbacks', function() command('undo') -- plugins can opt in to receive changedtick events, or choose - -- to only recieve actual changes. + -- to only receive actual changes. check_events({{ "test1", "lines", 1, tick, 3, 4, 5, 13 }, { "test2", "lines", 1, tick, 3, 4, 5, 13 }, { "test2", "changedtick", 1, tick+1 } }) @@ -111,7 +111,7 @@ describe('lua: buffer event callbacks', function() tick = tick + 1 -- plugins can opt in to receive changedtick events, or choose - -- to only recieve actual changes. + -- to only receive actual changes. check_events({{ "test1", "lines", 1, tick, 6, 7, 9, 16 }, { "test2", "lines", 1, tick, 6, 7, 9, 16 }}) -- cgit From 459a362cc140644d104de326258f9dfe75dbdcdf Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 1 Feb 2020 16:16:36 +0100 Subject: extmarks: fix crash due to invalid column values in inccommand preview This used to use -1 and MAXCOL values. Make sure in range values are used. --- test/functional/ui/inccommand_spec.lua | 72 ++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'test') diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua index b841574643..afb0c9cfa6 100644 --- a/test/functional/ui/inccommand_spec.lua +++ b/test/functional/ui/inccommand_spec.lua @@ -18,6 +18,7 @@ local wait = helpers.wait local nvim = helpers.nvim local sleep = helpers.sleep local nvim_dir = helpers.nvim_dir +local assert_alive = helpers.assert_alive local default_text = [[ Inc substitution on @@ -84,6 +85,7 @@ local function common_setup(screen, inccommand, text) [14] = {foreground = Screen.colors.White, background = Screen.colors.Red}, [15] = {bold=true, foreground=Screen.colors.Blue}, [16] = {background=Screen.colors.Grey90}, -- cursorline + [17] = {foreground = Screen.colors.Blue1}, vis = {background=Screen.colors.LightGrey} }) end @@ -2291,6 +2293,76 @@ describe(":substitute", function() ]]) end) + it("inccommand=split, contraction of two subsequent NL chars", function() + -- luacheck: push ignore 611 + local text = [[ + AAA AA + + BBB BB + + CCC CC + +]] + -- luacheck: pop + + -- This used to crash, but more than 20 highlight entries are required + -- to reproduce it (so that the marktree has multiple nodes) + common_setup(screen, "split", string.rep(text,10)) + feed(":%s/\\n\\n//g") + screen:expect{grid=[[ + CCC CC | + AAA AA | + BBB BB | + CCC CC | + | + {11:[No Name] [+] }| + | 1| AAA AA | + | 2|{12: }BBB BB | + | 3|{12: }CCC CC | + | 4|{12: }AAA AA | + | 5|{12: }BBB BB | + | 6|{12: }CCC CC | + | 7|{12: }AAA AA | + {10:[Preview] }| + :%s/\n\n/{17:^M}/g^ | + ]]} + assert_alive() + end) + + it("inccommand=nosplit, contraction of two subsequent NL chars", function() + -- luacheck: push ignore 611 + local text = [[ + AAA AA + + BBB BB + + CCC CC + +]] + -- luacheck: pop + + common_setup(screen, "nosplit", string.rep(text,10)) + feed(":%s/\\n\\n//g") + screen:expect{grid=[[ + CCC CC | + AAA AA | + BBB BB | + CCC CC | + AAA AA | + BBB BB | + CCC CC | + AAA AA | + BBB BB | + CCC CC | + AAA AA | + BBB BB | + CCC CC | + | + :%s/\n\n/{17:^M}/g^ | + ]]} + assert_alive() + end) + it("inccommand=split, multibyte text", function() common_setup(screen, "split", multibyte_text) feed(":%s/£.*ѫ/X¥¥") -- cgit From 7ce9a5c7da0fb5d6117cf9526c39e01faf7e908d Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 25 Jan 2020 13:29:52 +0100 Subject: api: add nvim_get_runtime_file for finding runtime files --- test/functional/api/vim_spec.lua | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'test') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index d901a5e2eb..fb3755cb8e 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -23,6 +23,7 @@ local pcall_err = helpers.pcall_err local format_string = helpers.format_string local intchar2lua = helpers.intchar2lua local mergedicts_copy = helpers.mergedicts_copy +local endswith = helpers.endswith describe('API', function() before_each(clear) @@ -1853,4 +1854,27 @@ describe('API', function() command('silent! call nvim_create_buf(0, 1)') end) end) + + describe('nvim_get_runtime_file', function() + it('works', function() + eq({}, meths.get_runtime_file("bork.borkbork", false)) + eq({}, meths.get_runtime_file("bork.borkbork", true)) + eq(1, #meths.get_runtime_file("autoload/msgpack.vim", false)) + eq(1, #meths.get_runtime_file("autoload/msgpack.vim", true)) + local val = meths.get_runtime_file("autoload/remote/*.vim", true) + eq(2, #val) + local p = helpers.alter_slashes + if endswith(val[1], "define.vim") then + ok(endswith(val[1], p("autoload/remote/define.vim"))) + ok(endswith(val[2], p("autoload/remote/host.vim"))) + else + ok(endswith(val[1], p("autoload/remote/host.vim"))) + ok(endswith(val[2], p("autoload/remote/define.vim"))) + end + val = meths.get_runtime_file("autoload/remote/*.vim", false) + eq(1, #val) + ok(endswith(val[1], p("autoload/remote/define.vim")) + or endswith(val[1], p("autoload/remote/host.vim"))) + end) + end) end) -- cgit From c5b812c9eab5397f4c898fe4b0a7a1f186fae82c Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 2 Feb 2020 23:29:33 +0100 Subject: env: try find library dir (like /usr[/local]/lib/nvim) and add it to &rtp --- test/functional/options/defaults_spec.lua | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) (limited to 'test') diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua index 57e5077989..6de8017434 100644 --- a/test/functional/options/defaults_spec.lua +++ b/test/functional/options/defaults_spec.lua @@ -293,6 +293,12 @@ describe('XDG-based defaults', function() -- TODO(jkeyes): tests below fail on win32 because of path separator. if helpers.pending_win32(pending) then return end + local function vimruntime_and_libdir() + local vimruntime = eval('$VIMRUNTIME') + local libdir = string.gsub(vimruntime, "share/nvim/runtime$", "lib/nvim") + return vimruntime, libdir + end + describe('with too long XDG variables', function() before_each(function() clear({env={ @@ -308,6 +314,8 @@ describe('XDG-based defaults', function() end) it('are correctly set', function() + local vimruntime, libdir = vimruntime_and_libdir() + eq((('/x'):rep(4096) .. '/nvim' .. ',' .. ('/a'):rep(2048) .. '/nvim' .. ',' .. ('/b'):rep(2048) .. '/nvim' @@ -316,7 +324,8 @@ describe('XDG-based defaults', function() .. ',' .. ('/A'):rep(2048) .. '/nvim/site' .. ',' .. ('/B'):rep(2048) .. '/nvim/site' .. (',' .. '/C/nvim/site'):rep(512) - .. ',' .. eval('$VIMRUNTIME') + .. ',' .. vimruntime + .. ',' .. libdir .. (',' .. '/C/nvim/site/after'):rep(512) .. ',' .. ('/B'):rep(2048) .. '/nvim/site/after' .. ',' .. ('/A'):rep(2048) .. '/nvim/site/after' @@ -339,7 +348,8 @@ describe('XDG-based defaults', function() .. ',' .. ('/A'):rep(2048) .. '/nvim/site' .. ',' .. ('/B'):rep(2048) .. '/nvim/site' .. (',' .. '/C/nvim/site'):rep(512) - .. ',' .. eval('$VIMRUNTIME') + .. ',' .. vimruntime + .. ',' .. libdir .. (',' .. '/C/nvim/site/after'):rep(512) .. ',' .. ('/B'):rep(2048) .. '/nvim/site/after' .. ',' .. ('/A'):rep(2048) .. '/nvim/site/after' @@ -368,11 +378,13 @@ describe('XDG-based defaults', function() end) it('are not expanded', function() + local vimruntime, libdir = vimruntime_and_libdir() eq(('$XDG_DATA_HOME/nvim' .. ',$XDG_DATA_DIRS/nvim' .. ',$XDG_CONFIG_HOME/nvim/site' .. ',$XDG_CONFIG_DIRS/nvim/site' - .. ',' .. eval('$VIMRUNTIME') + .. ',' .. vimruntime + .. ',' .. libdir .. ',$XDG_CONFIG_DIRS/nvim/site/after' .. ',$XDG_CONFIG_HOME/nvim/site/after' .. ',$XDG_DATA_DIRS/nvim/after' @@ -387,7 +399,8 @@ describe('XDG-based defaults', function() .. ',$XDG_DATA_DIRS/nvim' .. ',$XDG_CONFIG_HOME/nvim/site' .. ',$XDG_CONFIG_DIRS/nvim/site' - .. ',' .. eval('$VIMRUNTIME') + .. ',' .. vimruntime + .. ',' .. libdir .. ',$XDG_CONFIG_DIRS/nvim/site/after' .. ',$XDG_CONFIG_HOME/nvim/site/after' .. ',$XDG_DATA_DIRS/nvim/after' @@ -402,7 +415,8 @@ describe('XDG-based defaults', function() .. ',$XDG_DATA_DIRS/nvim' .. ',$XDG_CONFIG_HOME/nvim/site' .. ',$XDG_CONFIG_DIRS/nvim/site' - .. ',' .. eval('$VIMRUNTIME') + .. ',' .. vimruntime + .. ',' .. libdir .. ',$XDG_CONFIG_DIRS/nvim/site/after' .. ',$XDG_CONFIG_HOME/nvim/site/after' .. ',$XDG_DATA_DIRS/nvim/after' @@ -426,13 +440,15 @@ describe('XDG-based defaults', function() end) it('are escaped properly', function() + local vimruntime, libdir = vimruntime_and_libdir() eq(('\\, \\, \\,/nvim' .. ',\\,-\\,-\\,/nvim' .. ',-\\,-\\,-/nvim' .. ',\\,=\\,=\\,/nvim/site' .. ',\\,≡\\,≡\\,/nvim/site' .. ',≡\\,≡\\,≡/nvim/site' - .. ',' .. eval('$VIMRUNTIME') + .. ',' .. vimruntime + .. ',' .. libdir .. ',≡\\,≡\\,≡/nvim/site/after' .. ',\\,≡\\,≡\\,/nvim/site/after' .. ',\\,=\\,=\\,/nvim/site/after' @@ -451,7 +467,8 @@ describe('XDG-based defaults', function() .. ',\\,=\\,=\\,/nvim/site' .. ',\\,≡\\,≡\\,/nvim/site' .. ',≡\\,≡\\,≡/nvim/site' - .. ',' .. eval('$VIMRUNTIME') + .. ',' .. vimruntime + .. ',' .. libdir .. ',≡\\,≡\\,≡/nvim/site/after' .. ',\\,≡\\,≡\\,/nvim/site/after' .. ',\\,=\\,=\\,/nvim/site/after' -- cgit From 00c57c98dfb2df58875a3d9ad8fc557ec9a24cba Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 25 Jan 2020 13:43:41 +0100 Subject: treesitter: add standard &rtp/parser/ search path for parsers --- test/functional/lua/treesitter_spec.lua | 107 +++++++++++++++++--------------- 1 file changed, 56 insertions(+), 51 deletions(-) (limited to 'test') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index 76e9899d34..494d6c84bb 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -6,7 +6,6 @@ local clear = helpers.clear local eq = helpers.eq local insert = helpers.insert local exec_lua = helpers.exec_lua -local iswin = helpers.iswin local feed = helpers.feed local pcall_err = helpers.pcall_err local matches = helpers.matches @@ -16,37 +15,35 @@ before_each(clear) describe('treesitter API', function() -- error tests not requiring a parser library it('handles missing language', function() - eq('Error executing lua: .../treesitter.lua: no such language: borklang', + eq("Error executing lua: .../treesitter.lua: no parser for 'borklang' language", pcall_err(exec_lua, "parser = vim.treesitter.create_parser(0, 'borklang')")) -- actual message depends on platform - matches('Error executing lua: Failed to load parser: uv_dlopen: .+', - pcall_err(exec_lua, "parser = vim.treesitter.add_language('borkbork.so', 'borklang')")) + matches("Error executing lua: Failed to load parser: uv_dlopen: .+", + pcall_err(exec_lua, "parser = vim.treesitter.require_language('borklang', 'borkbork.so')")) - eq('Error executing lua: [string ""]:1: no such language: borklang', + eq("Error executing lua: .../treesitter.lua: no parser for 'borklang' language", pcall_err(exec_lua, "parser = vim.treesitter.inspect_language('borklang')")) end) end) describe('treesitter API with C parser', function() - local ts_path = os.getenv("TREE_SITTER_DIR") - - -- The tests after this requires an actual parser - if ts_path == nil then - it("works", function() pending("TREE_SITTER_PATH not set, skipping treesitter parser tests") end) - return + local function check_parser() + local status, msg = unpack(exec_lua([[ return {pcall(vim.treesitter.require_language, 'c')} ]])) + if not status then + if helpers.isCI() then + error("treesitter C parser not found, required on CI: " .. msg) + else + pending('no C parser, skipping') + end + end + return status end - before_each(function() - local path = ts_path .. '/bin/c'..(iswin() and '.dll' or '.so') - exec_lua([[ - local path = ... - vim.treesitter.add_language(path,'c') - ]], path) - end) - it('parses buffer', function() + if not check_parser() then return end + insert([[ int main() { int x = 3; @@ -138,6 +135,8 @@ void ui_refresh(void) ]] it('support query and iter by capture', function() + if not check_parser() then return end + insert(test_text) local res = exec_lua([[ @@ -167,6 +166,8 @@ void ui_refresh(void) end) it('support query and iter by match', function() + if not check_parser() then return end + insert(test_text) local res = exec_lua([[ @@ -198,6 +199,8 @@ void ui_refresh(void) end) it('supports highlighting', function() + if not check_parser() then return end + local hl_text = [[ /// Schedule Lua callback on main loop's event queue static int nlua_schedule(lua_State *const lstate) @@ -357,41 +360,43 @@ static int nlua_schedule(lua_State *const lstate) end) it('inspects language', function() - local keys, fields, symbols = unpack(exec_lua([[ - local lang = vim.treesitter.inspect_language('c') - local keys, symbols = {}, {} - for k,_ in pairs(lang) do - keys[k] = true - end + if not check_parser() then return end - -- symbols array can have "holes" and is thus not a valid msgpack array - -- but we don't care about the numbers here (checked in the parser test) - for _, v in pairs(lang.symbols) do - table.insert(symbols, v) - end - return {keys, lang.fields, symbols} - ]])) - - eq({fields=true, symbols=true}, keys) + local keys, fields, symbols = unpack(exec_lua([[ + local lang = vim.treesitter.inspect_language('c') + local keys, symbols = {}, {} + for k,_ in pairs(lang) do + keys[k] = true + end - local fset = {} - for _,f in pairs(fields) do - eq("string", type(f)) - fset[f] = true + -- symbols array can have "holes" and is thus not a valid msgpack array + -- but we don't care about the numbers here (checked in the parser test) + for _, v in pairs(lang.symbols) do + table.insert(symbols, v) end - eq(true, fset["directive"]) - eq(true, fset["initializer"]) - - local has_named, has_anonymous - for _,s in pairs(symbols) do - eq("string", type(s[1])) - eq("boolean", type(s[2])) - if s[1] == "for_statement" and s[2] == true then - has_named = true - elseif s[1] == "|=" and s[2] == false then - has_anonymous = true - end + return {keys, lang.fields, symbols} + ]])) + + eq({fields=true, symbols=true}, keys) + + local fset = {} + for _,f in pairs(fields) do + eq("string", type(f)) + fset[f] = true + end + eq(true, fset["directive"]) + eq(true, fset["initializer"]) + + local has_named, has_anonymous + for _,s in pairs(symbols) do + eq("string", type(s[1])) + eq("boolean", type(s[2])) + if s[1] == "for_statement" and s[2] == true then + has_named = true + elseif s[1] == "|=" and s[2] == false then + has_anonymous = true end - eq({true,true}, {has_named,has_anonymous}) + end + eq({true,true}, {has_named,has_anonymous}) end) end) -- cgit From ef2e6522c53d562928060a4872020fb8f32c8ff8 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Thu, 6 Feb 2020 13:41:57 +0100 Subject: tests: bail out on libdir just like $VIMRUNTIME, it cannot be calculated --- test/functional/options/defaults_spec.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua index 6de8017434..11ce26410d 100644 --- a/test/functional/options/defaults_spec.lua +++ b/test/functional/options/defaults_spec.lua @@ -295,7 +295,9 @@ describe('XDG-based defaults', function() local function vimruntime_and_libdir() local vimruntime = eval('$VIMRUNTIME') - local libdir = string.gsub(vimruntime, "share/nvim/runtime$", "lib/nvim") + -- libdir is hard to calculate reliably across various ci platforms + -- local libdir = string.gsub(vimruntime, "share/nvim/runtime$", "lib/nvim") + local libdir = meths._get_lib_dir() return vimruntime, libdir end -- cgit From 70c212e4808ca36279c65b630ff1d231e75349d3 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 8 Feb 2020 20:48:22 +0100 Subject: vim-patch:8.2.0235: draw error when an empty group is removed from 'statusline' Problem: Draw error when an empty group is removed from 'statusline'. Solution: Do not use highlighting from a removed group. https://github.com/vim/vim/commit/dbe5d361feb65137099644329cf0ecfd4a945a14 --- test/functional/ui/multibyte_spec.lua | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) (limited to 'test') diff --git a/test/functional/ui/multibyte_spec.lua b/test/functional/ui/multibyte_spec.lua index 8122cb08a3..e6a79feadc 100644 --- a/test/functional/ui/multibyte_spec.lua +++ b/test/functional/ui/multibyte_spec.lua @@ -123,6 +123,10 @@ describe('multibyte rendering: statusline', function() before_each(function() clear() screen = Screen.new(40, 4) + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {bold = true, reverse = true}, + }) screen:attach() command('set laststatus=2') end) @@ -131,8 +135,8 @@ describe('multibyte rendering: statusline', function() command('set statusline=你好') screen:expect([[ ^ | - ~ | - 你好 | + {1:~ }| + {2:你好 }| | ]]) end) @@ -140,8 +144,8 @@ describe('multibyte rendering: statusline', function() command('set statusline=abc') screen:expect([[ ^ | - ~ | - abc | + {1:~ }| + {2:abc }| | ]]) end) @@ -149,8 +153,8 @@ describe('multibyte rendering: statusline', function() command('set statusline=Ÿ') screen:expect([[ ^ | - ~ | - <9f> | + {1:~ }| + {2:<9f> }| | ]]) end) @@ -159,8 +163,8 @@ describe('multibyte rendering: statusline', function() -- o + U+1DF0 + U+20EF + U+0338 + U+20D0 + U+20E7 + U+20DD screen:expect([[ ^ | - ~ | - o̸⃯ᷰ⃐⃧⃝ | + {1:~ }| + {2:o̸⃯ᷰ⃐⃧⃝ }| | ]]) end) @@ -169,9 +173,19 @@ describe('multibyte rendering: statusline', function() -- U+9F + U+1DF0 + U+20EF + U+0338 + U+20D0 + U+20E7 + U+20DD screen:expect([[ ^ | - ~ | - <9f><1df0><20ef><0338><20d0><20e7><20dd>| + {1:~ }| + {2:<9f><1df0><20ef><0338><20d0><20e7><20dd>}| | ]]) end) + + it('hidden group %( %) does not cause invalid unicode', function() + command("let &statusline = '%#StatColorHi2#%(✓%#StatColorHi2#%) Q≡'") + screen:expect{grid=[[ + ^ | + {1:~ }| + {2: Q≡ }| + | + ]]} + end) end) -- cgit From 4813ad48cd12a03ca50c01ac1b20518bf4df57f2 Mon Sep 17 00:00:00 2001 From: erw7 Date: Mon, 20 May 2019 11:57:45 +0900 Subject: vim-patch:8.1.0027: difficult to make a plugin that feeds a line to a job Problem: Difficult to make a plugin that feeds a line to a job. Solution: Add the nitial code for the "prompt" buftype. https://github.com/vim/vim/commit/f273245f6433d5d43a5671306b520a3230c35787 --- test/functional/legacy/prompt_buffer_spec.lua | 84 +++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 test/functional/legacy/prompt_buffer_spec.lua (limited to 'test') diff --git a/test/functional/legacy/prompt_buffer_spec.lua b/test/functional/legacy/prompt_buffer_spec.lua new file mode 100644 index 0000000000..749e65a985 --- /dev/null +++ b/test/functional/legacy/prompt_buffer_spec.lua @@ -0,0 +1,84 @@ +local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') +local feed= helpers.feed +local source = helpers.source +local clear = helpers.clear +local feed_command = helpers.feed_command + +describe('prompt buffer', function() + local screen + + before_each(function() + clear() + screen = Screen.new(25, 10) + screen:attach() + source([[ + func TextEntered(text) + if a:text == "exit" + stopinsert + close + else + call append(line("$") - 1, 'Command: "' . a:text . '"') + set nomodfied + call timer_start(20, {id -> TimerFunc(a:text)}) + endif + endfunc + + func TimerFunc(text) + call append(line("$") - 1, 'Result: "' . a:text .'"') + endfunc + ]]) + end) + + after_each(function() + screen:detach() + end) + + it('works', function() + feed_command("set noshowmode | set laststatus=0") + feed_command("call setline(1, 'other buffer')") + feed_command("new") + feed_command("set buftype=prompt") + feed_command("call prompt_setcallback(bufnr(''), function('TextEntered'))") + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + [Scratch] | + other buffer | + ~ | + ~ | + ~ | + | + ]]) + feed_command("startinsert") + feed("hello\n") + screen:expect([[ + % hello | + Command: "hello" | + Result: "hello" | + % ^ | + [Scratch] | + other buffer | + ~ | + ~ | + ~ | + | + ]]) + feed("exit\n") + screen:expect([[ + ^other buffer | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + | + ]]) + end) + +end) -- cgit From 3ca0343fb99b7f7412fca73be6f94df252b6f0a3 Mon Sep 17 00:00:00 2001 From: erw7 Date: Thu, 23 May 2019 01:47:56 +0900 Subject: vim-patch:8.1.0032: BS in prompt buffer starts new line Problem: BS in prompt buffer starts new line. Solution: Do not allows BS over the prompt. Make term_sendkeys() handle special keys. Add a test. https://github.com/vim/vim/commit/6b810d92a9cd9378ab46ea0db07079cb789f9faa --- test/functional/legacy/prompt_buffer_spec.lua | 80 +++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 6 deletions(-) (limited to 'test') diff --git a/test/functional/legacy/prompt_buffer_spec.lua b/test/functional/legacy/prompt_buffer_spec.lua index 749e65a985..d494bb5a81 100644 --- a/test/functional/legacy/prompt_buffer_spec.lua +++ b/test/functional/legacy/prompt_buffer_spec.lua @@ -28,6 +28,11 @@ describe('prompt buffer', function() call append(line("$") - 1, 'Result: "' . a:text .'"') endfunc ]]) + feed_command("set noshowmode | set laststatus=0") + feed_command("call setline(1, 'other buffer')") + feed_command("new") + feed_command("set buftype=prompt") + feed_command("call prompt_setcallback(bufnr(''), function('TextEntered'))") end) after_each(function() @@ -35,11 +40,6 @@ describe('prompt buffer', function() end) it('works', function() - feed_command("set noshowmode | set laststatus=0") - feed_command("call setline(1, 'other buffer')") - feed_command("new") - feed_command("set buftype=prompt") - feed_command("call prompt_setcallback(bufnr(''), function('TextEntered'))") screen:expect([[ ^ | ~ | @@ -52,7 +52,7 @@ describe('prompt buffer', function() ~ | | ]]) - feed_command("startinsert") + feed("i") feed("hello\n") screen:expect([[ % hello | @@ -81,4 +81,72 @@ describe('prompt buffer', function() ]]) end) + it('editing', function() + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + [Scratch] | + other buffer | + ~ | + ~ | + ~ | + | + ]]) + feed("i") + feed("hello") + screen:expect([[ + % hel^ | + ~ | + ~ | + ~ | + [Scratch] | + other buffer | + ~ | + ~ | + ~ | + | + ]]) + feed("-") + screen:expect([[ + % -^hel | + ~ | + ~ | + ~ | + [Scratch] | + other buffer | + ~ | + ~ | + ~ | + | + ]]) + feed("x") + screen:expect([[ + % -helx^ | + ~ | + ~ | + ~ | + [Scratch] | + other buffer | + ~ | + ~ | + ~ | + | + ]]) + feed("exit\n") + screen:expect([[ + ^other buffer | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + | + ]]) + end) + end) -- cgit From 783aecd501de2719f3059252e8444ef00c7c3d4a Mon Sep 17 00:00:00 2001 From: erw7 Date: Thu, 23 May 2019 05:15:04 +0900 Subject: vim-patch:8.1.0036: not restoring Insert mode if leaving prompt buffer with mouse Problem: Not restoring Insert mode if leaving a prompt buffer by using a mouse click. Solution: Set b_prompt_insert appropriately. Also correct cursor position when moving cursor to last line. https://github.com/vim/vim/commit/891e1fd894720d0b99a9daefa41e8181844f819a --- test/functional/legacy/prompt_buffer_spec.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'test') diff --git a/test/functional/legacy/prompt_buffer_spec.lua b/test/functional/legacy/prompt_buffer_spec.lua index d494bb5a81..d5b315a0c7 100644 --- a/test/functional/legacy/prompt_buffer_spec.lua +++ b/test/functional/legacy/prompt_buffer_spec.lua @@ -45,7 +45,7 @@ describe('prompt buffer', function() ~ | ~ | ~ | - [Scratch] | + [Prompt] | other buffer | ~ | ~ | @@ -59,7 +59,7 @@ describe('prompt buffer', function() Command: "hello" | Result: "hello" | % ^ | - [Scratch] | + [Prompt] | other buffer | ~ | ~ | @@ -87,7 +87,7 @@ describe('prompt buffer', function() ~ | ~ | ~ | - [Scratch] | + [Prompt] | other buffer | ~ | ~ | @@ -101,7 +101,7 @@ describe('prompt buffer', function() ~ | ~ | ~ | - [Scratch] | + [Prompt] | other buffer | ~ | ~ | @@ -114,7 +114,7 @@ describe('prompt buffer', function() ~ | ~ | ~ | - [Scratch] | + [Prompt] | other buffer | ~ | ~ | @@ -127,7 +127,7 @@ describe('prompt buffer', function() ~ | ~ | ~ | - [Scratch] | + [Prompt] | other buffer | ~ | ~ | -- cgit From 3557757a3c410bb5c6a9066b342b4f42b75ec5ed Mon Sep 17 00:00:00 2001 From: erw7 Date: Sat, 25 May 2019 13:15:01 +0900 Subject: vim-patch:8.1.0092: prompt buffer test fails Problem: Prompt buffer test fails. Solution: Set 'nomodified' before closing the window. (Ozaki Kiichi, closes vim/vim#3051 https://github.com/vim/vim/commit/71ef1ba5e996f34d3e0acbe1d89c4c6bfa5e98ba --- test/functional/legacy/prompt_buffer_spec.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/test/functional/legacy/prompt_buffer_spec.lua b/test/functional/legacy/prompt_buffer_spec.lua index d5b315a0c7..513be807be 100644 --- a/test/functional/legacy/prompt_buffer_spec.lua +++ b/test/functional/legacy/prompt_buffer_spec.lua @@ -15,6 +15,7 @@ describe('prompt buffer', function() source([[ func TextEntered(text) if a:text == "exit" + set nomodified stopinsert close else @@ -59,7 +60,7 @@ describe('prompt buffer', function() Command: "hello" | Result: "hello" | % ^ | - [Prompt] | + [Prompt] [+] | other buffer | ~ | ~ | @@ -101,7 +102,7 @@ describe('prompt buffer', function() ~ | ~ | ~ | - [Prompt] | + [Prompt] [+] | other buffer | ~ | ~ | @@ -114,7 +115,7 @@ describe('prompt buffer', function() ~ | ~ | ~ | - [Prompt] | + [Prompt] [+] | other buffer | ~ | ~ | @@ -127,7 +128,7 @@ describe('prompt buffer', function() ~ | ~ | ~ | - [Prompt] | + [Prompt] [+] | other buffer | ~ | ~ | -- cgit From 032ede02036cda1b0caebce46bc31ecf06a70dc2 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Wed, 12 Feb 2020 20:51:15 +0900 Subject: test: add json_encode test for vim.empty_dict() --- test/functional/lua/vim_spec.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'test') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index e879f8b925..339fbd65a0 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -545,6 +545,8 @@ describe('lua stdlib', function() ]])) eq("{ {}, vim.empty_dict() }", exec_lua("return vim.inspect({{}, vim.empty_dict()})")) + eq('{}', exec_lua([[ return vim.fn.json_encode(vim.empty_dict()) ]])) + eq('{"a": {}, "b": []}', exec_lua([[ return vim.fn.json_encode({a=vim.empty_dict(), b={}}) ]])) end) it('vim.validate', function() -- cgit From 417fc6ccf78801aef79a8731c5a85db6b12cd407 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Thu, 13 Feb 2020 11:55:43 +0900 Subject: lua: vim.deepcopy uses empty_dict() instead of {} for empty_dict() fix: https://github.com/neovim/nvim-lsp/issues/94 --- test/functional/lua/vim_spec.lua | 42 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'test') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index e879f8b925..b8edd7b3e0 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -322,6 +322,48 @@ describe('lua stdlib', function() ]]) assert(is_dc) + + local is_empty_list = exec_lua([[ + local a = {} + local b = vim.deepcopy(a) + + local count = 0 + for _ in pairs(b) do count = count + 1 end + + return getmetatable(b) ~= vim._empty_dict_mt + and count == 0 + and tostring(a) ~= tostring(b) + ]]) + + assert(is_empty_list) + + local is_empty_dic = exec_lua([[ + local a = vim.empty_dict() + local b = vim.deepcopy(a) + + local count = 0 + for _ in pairs(b) do count = count + 1 end + + return getmetatable(b) == vim._empty_dict_mt + and count == 0 + ]]) + + assert(is_empty_dic) + + local include_empty_dic = exec_lua([[ + local a = {x = vim.empty_dict(), y = {}} + local b = vim.deepcopy(a) + + local count = 0 + for _ in pairs(b) do count = count + 1 end + + return getmetatable(b.x) == vim._empty_dict_mt + and getmetatable(b.y) ~= vim._empty_dict_mt + and count == 2 + and tostring(a) ~= tostring(b) + ]]) + + assert(include_empty_dic) end) it('vim.pesc', function() -- cgit From cdb729b7462cfef28a0264cb75bffe69182c5275 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Fri, 14 Feb 2020 19:40:02 +0900 Subject: lua: add vim.tbl_extend and vim.deepcopy test --- test/functional/lua/vim_spec.lua | 122 +++++++++++++++++++++++++++++++-------- 1 file changed, 99 insertions(+), 23 deletions(-) (limited to 'test') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index b8edd7b3e0..f549ca2bd1 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -7,6 +7,7 @@ local meths = helpers.meths local command = helpers.command local clear = helpers.clear local eq = helpers.eq +local ok = helpers.ok local eval = helpers.eval local feed = helpers.feed local pcall_err = helpers.pcall_err @@ -310,7 +311,7 @@ describe('lua stdlib', function() end) it("vim.deepcopy", function() - local is_dc = exec_lua([[ + ok(exec_lua([[ local a = { x = { 1, 2 }, y = 5} local b = vim.deepcopy(a) @@ -319,51 +320,39 @@ describe('lua stdlib', function() return b.x[1] == 1 and b.x[2] == 2 and b.y == 5 and count == 2 and tostring(a) ~= tostring(b) - ]]) - - assert(is_dc) + ]])) - local is_empty_list = exec_lua([[ + ok(exec_lua([[ local a = {} local b = vim.deepcopy(a) local count = 0 for _ in pairs(b) do count = count + 1 end - return getmetatable(b) ~= vim._empty_dict_mt - and count == 0 - and tostring(a) ~= tostring(b) - ]]) - - assert(is_empty_list) + return vim.tbl_islist(b) and count == 0 and tostring(a) ~= tostring(b) + ]])) - local is_empty_dic = exec_lua([[ + ok(exec_lua([[ local a = vim.empty_dict() local b = vim.deepcopy(a) local count = 0 for _ in pairs(b) do count = count + 1 end - return getmetatable(b) == vim._empty_dict_mt - and count == 0 - ]]) - - assert(is_empty_dic) + return not vim.tbl_islist(b) and count == 0 + ]])) - local include_empty_dic = exec_lua([[ + ok(exec_lua([[ local a = {x = vim.empty_dict(), y = {}} local b = vim.deepcopy(a) local count = 0 for _ in pairs(b) do count = count + 1 end - return getmetatable(b.x) == vim._empty_dict_mt - and getmetatable(b.y) ~= vim._empty_dict_mt + return not vim.tbl_islist(b.x) and vim.tbl_islist(b.y) and count == 2 and tostring(a) ~= tostring(b) - ]]) - - assert(include_empty_dic) + ]])) end) it('vim.pesc', function() @@ -411,6 +400,93 @@ describe('lua stdlib', function() eq(false, exec_lua("return vim.tbl_isempty({a=1, b=2, c=3})")) end) + it('vim.tbl_extend', function() + ok(exec_lua([[ + local a = {x = 1} + local b = {y = 2} + local c = vim.tbl_extend("keep", a, b) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return c.x == 1 and b.y == 2 and count == 2 + ]])) + + ok(exec_lua([[ + local a = {x = 1} + local b = {y = 2} + local c = {z = 3} + local d = vim.tbl_extend("keep", a, b, c) + + local count = 0 + for _ in pairs(d) do count = count + 1 end + + return d.x == 1 and d.y == 2 and d.z == 3 and count == 3 + ]])) + + ok(exec_lua([[ + local a = {x = 1} + local b = {x = 3} + local c = vim.tbl_extend("keep", a, b) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return c.x == 1 and count == 1 + ]])) + + ok(exec_lua([[ + local a = {x = 1} + local b = {x = 3} + local c = vim.tbl_extend("force", a, b) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return c.x == 3 and count == 1 + ]])) + + ok(exec_lua([[ + local a = vim.empty_dict() + local b = {} + local c = vim.tbl_extend("keep", a, b) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return not vim.tbl_islist(c) and count == 0 + ]])) + + ok(exec_lua([[ + local a = {} + local b = vim.empty_dict() + local c = vim.tbl_extend("keep", a, b) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return vim.tbl_islist(c) and count == 0 + ]])) + + eq('Error executing lua: .../shared.lua: invalid "behavior": nil', + pcall_err(exec_lua, [[ + return vim.tbl_extend() + ]]) + ) + + eq('Error executing lua: .../shared.lua: wrong number of arguments (given 1, expected at least 3)', + pcall_err(exec_lua, [[ + return vim.tbl_extend("keep") + ]]) + ) + + eq('Error executing lua: .../shared.lua: wrong number of arguments (given 2, expected at least 3)', + pcall_err(exec_lua, [[ + return vim.tbl_extend("keep", {}) + ]]) + ) + end) + it('vim.deep_equal', function() eq(true, exec_lua [[ return vim.deep_equal({a=1}, {a=1}) ]]) eq(true, exec_lua [[ return vim.deep_equal({a={b=1}}, {a={b=1}}) ]]) -- cgit From bb331a9b31c441d47fc2cb3dcb87e0573f519dd9 Mon Sep 17 00:00:00 2001 From: Matthieu Coudron Date: Fri, 14 Feb 2020 16:42:00 +0100 Subject: mouse.c: can click on multibyte foldopen/foldclose (#11863) would previously only work with ascii fillchars. Added a test. --- test/functional/ui/fold_spec.lua | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua index 0b788e7afb..f178ed1ac7 100644 --- a/test/functional/ui/fold_spec.lua +++ b/test/functional/ui/fold_spec.lua @@ -96,8 +96,20 @@ describe("folded lines", function() {1: ~}| :set rightleft | ]]} - end) + feed_command("set norightleft") + meths.input_mouse('left', 'press', '', 0, 0, 1) + screen:expect{grid=[[ + {7:▾▸}{5:^+--- 5 lines: aa··························}| + {7:│ }ff | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :set norightleft | + ]]} + end) it("works with multibyte text", function() -- Currently the only allowed value of 'maxcombine' -- cgit From b04165859d0c11e2bdcacd50efb0ec6c2b2a6c0c Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 8 Feb 2020 15:35:28 -0800 Subject: test: style --- test/functional/plugin/lsp_spec.lua | 62 +++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 24 deletions(-) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 4829a33861..1db9bf306d 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -16,18 +16,18 @@ local run, stop = helpers.run, helpers.stop if helpers.pending_win32(pending) then return end -local lsp_test_rpc_server_file = "test/functional/fixtures/lsp-test-rpc-server.lua" +local fake_lsp_server_file = "test/functional/fixtures/lsp-test-rpc-server.lua" if iswin() then - lsp_test_rpc_server_file = lsp_test_rpc_server_file:gsub("/", "\\") + fake_lsp_server_file = fake_lsp_server_file:gsub("/", "\\") end -local function test_rpc_server_setup(test_name, timeout_ms) +local function fake_lsp_server_setup(test_name, timeout_ms) exec_lua([=[ lsp = require('vim.lsp') local test_name, fixture_filename, timeout = ... TEST_RPC_CLIENT_ID = lsp.start_client { cmd = { - vim.api.nvim_get_vvar("progpath"), '-Es', '-u', 'NONE', '--headless', + vim.v.progpath, '-Es', '-u', 'NONE', '--headless', "-c", string.format("lua TEST_NAME = %q", test_name), "-c", string.format("lua TIMEOUT = %d", timeout), "-c", "luafile "..fixture_filename, @@ -48,13 +48,13 @@ local function test_rpc_server_setup(test_name, timeout_ms) vim.rpcnotify(1, "exit", ...) end; } - ]=], test_name, lsp_test_rpc_server_file, timeout_ms or 1e3) + ]=], test_name, fake_lsp_server_file, timeout_ms or 1e3) end local function test_rpc_server(config) if config.test_name then clear() - test_rpc_server_setup(config.test_name, config.timeout_ms or 1e3) + fake_lsp_server_setup(config.test_name, config.timeout_ms or 1e3) end local client = setmetatable({}, { __index = function(_, name) @@ -118,7 +118,7 @@ describe('LSP', function() function test__start_client() return lsp.start_client { cmd = { - vim.api.nvim_get_vvar("progpath"), '-Es', '-u', 'NONE', '--headless', + vim.v.progpath, '-Es', '-u', 'NONE', '--headless', "-c", string.format("lua TEST_NAME = %q", test_name), "-c", "luafile "..fixture_filename; }; @@ -126,7 +126,7 @@ describe('LSP', function() } end TEST_CLIENT1 = test__start_client() - ]=], test_name, lsp_test_rpc_server_file) + ]=], test_name, fake_lsp_server_file) end) after_each(function() @@ -195,7 +195,8 @@ describe('LSP', function() end; -- If the program timed out, then code will be nil. on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") + eq(0, code, "exit code") + eq(0, signal, "exit signal") end; -- Note that NIL must be used here. -- on_callback(err, method, result, client_id) @@ -216,7 +217,8 @@ describe('LSP', function() client.stop() end; on_exit = function(code, signal) - eq(1, code, "exit code") eq(0, signal, "exit signal") + eq(1, code, "exit code") + eq(0, signal, "exit signal") end; on_callback = function(...) eq(table.remove(expected_callbacks), {...}, "expected callback") @@ -237,7 +239,8 @@ describe('LSP', function() client.notify('exit') end; on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") + eq(0, code, "exit code") + eq(0, signal, "exit signal") end; on_callback = function(...) eq(table.remove(expected_callbacks), {...}, "expected callback") @@ -255,7 +258,8 @@ describe('LSP', function() client.stop() end; on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") + eq(0, code, "exit code") + eq(0, signal, "exit signal") end; on_callback = function(...) eq(table.remove(expected_callbacks), {...}, "expected callback") @@ -294,7 +298,8 @@ describe('LSP', function() client.notify('finish') end; on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") + eq(0, code, "exit code") + eq(0, signal, "exit signal") end; on_callback = function(err, method, params, client_id) eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") @@ -336,7 +341,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") + eq(0, code, "exit code") + eq(0, signal, "exit signal") end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -378,7 +384,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") + eq(0, code, "exit code") + eq(0, signal, "exit signal") end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -420,7 +427,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") + eq(0, code, "exit code") + eq(0, signal, "exit signal") end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -468,7 +476,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") + eq(0, code, "exit code") + eq(0, signal, "exit signal") end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -516,7 +525,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") + eq(0, code, "exit code") + eq(0, signal, "exit signal") end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -536,7 +546,7 @@ describe('LSP', function() end) -- TODO(askhan) we don't support full for now, so we can disable these tests. - pending('should check the body and didChange incremental normal mode editting', function() + pending('should check the body and didChange incremental normal mode editing', function() local expected_callbacks = { {NIL, "shutdown", {}, 1}; {NIL, "finish", {}, 1}; @@ -544,7 +554,7 @@ describe('LSP', function() } local client test_rpc_server { - test_name = "basic_check_buffer_open_and_change_incremental_editting"; + test_name = "basic_check_buffer_open_and_change_incremental_editing"; on_setup = function() exec_lua [[ BUFFER = vim.api.nvim_create_buf(false, true) @@ -564,7 +574,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") + eq(0, code, "exit code") + eq(0, signal, "exit signal") end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -607,7 +618,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") + eq(0, code, "exit code") + eq(0, signal, "exit signal") end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -657,7 +669,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") + eq(0, code, "exit code") + eq(0, signal, "exit signal") end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -699,7 +712,8 @@ describe('LSP', function() client.stop(true) end; on_exit = function(code, signal) - eq(0, code, "exit code") eq(0, signal, "exit signal") + eq(0, code, "exit code") + eq(0, signal, "exit signal") end; on_callback = function(err, method, params, client_id) eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") -- cgit From c15bd6cd279dbed5d246af05c4c0625387be02af Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 8 Feb 2020 17:16:43 -0800 Subject: test/LSP: use less-generic exit code - os.exit(1) is too generic, since code 1 may be caused by Nvim exiting for some other reason. Change it to os.exit(101). - style: de-architect json_encode/json_decode calls. Failure seen in travis macOS job: https://travis-ci.org/neovim/neovim/jobs/647849133 [ FAILED ] test/functional/plugin/lsp_spec.lua@ 266 SP basic_init test should not send didOpen if the buffer closes before init test/functional/plugin/lsp_spec.lua:297: exit code Expected objects to be the same. Passed in: (number) 1 Expected: (number) 0 stack traceback: test/functional/plugin/lsp_spec.lua:297: in function 'on_exit' test/functional/plugin/lsp_spec.lua:100: in function 'test_rpc_server' test/functional/plugin/lsp_spec.lua:272: in function --- test/functional/fixtures/lsp-test-rpc-server.lua | 27 +++--------------------- test/functional/plugin/lsp_spec.lua | 2 +- 2 files changed, 4 insertions(+), 25 deletions(-) (limited to 'test') diff --git a/test/functional/fixtures/lsp-test-rpc-server.lua b/test/functional/fixtures/lsp-test-rpc-server.lua index 798883ced0..44117bea30 100644 --- a/test/functional/fixtures/lsp-test-rpc-server.lua +++ b/test/functional/fixtures/lsp-test-rpc-server.lua @@ -1,24 +1,5 @@ local protocol = require 'vim.lsp.protocol' --- Internal utility methods. - --- TODO replace with a better implementation. -local function json_encode(data) - local status, result = pcall(vim.fn.json_encode, data) - if status then - return result - else - return nil, result - end -end -local function json_decode(data) - local status, result = pcall(vim.fn.json_decode, data) - if status then - return result - else - return nil, result - end -end local function message_parts(sep, ...) local parts = {} @@ -49,16 +30,14 @@ local function format_message_with_content_length(encoded_message) } end --- Server utility methods. - local function read_message() local line = io.read("*l") local length = line:lower():match("content%-length:%s*(%d+)") - return assert(json_decode(io.read(2 + length):sub(2)), "read_message.json_decode") + return vim.fn.json_decode(io.read(2 + length):sub(2)) end local function send(payload) - io.stdout:write(format_message_with_content_length(json_encode(payload))) + io.stdout:write(format_message_with_content_length(vim.fn.json_encode(payload))) end local function respond(id, err, result) @@ -454,6 +433,6 @@ kill_timer:stop() kill_timer:close() if not status then io.stderr:write(err) - os.exit(1) + os.exit(101) end os.exit(0) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 1db9bf306d..cab1fb0d79 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -217,7 +217,7 @@ describe('LSP', function() client.stop() end; on_exit = function(code, signal) - eq(1, code, "exit code") + eq(101, code, "exit code") eq(0, signal, "exit signal") end; on_callback = function(...) -- cgit From 1eb0f5371ae8cee90b97f586a99505cfa5913504 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 8 Feb 2020 17:25:53 -0800 Subject: LSP: fix validate_client_config - `cmd_env` is a table not a function. - tests: Set $NVIM_LOG_FILE for fake LSP server. --- test/functional/fixtures/fake-lsp-server.lua | 438 +++++++++++++++++++++++ test/functional/fixtures/lsp-test-rpc-server.lua | 438 ----------------------- test/functional/plugin/lsp_spec.lua | 13 +- 3 files changed, 446 insertions(+), 443 deletions(-) create mode 100644 test/functional/fixtures/fake-lsp-server.lua delete mode 100644 test/functional/fixtures/lsp-test-rpc-server.lua (limited to 'test') diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua new file mode 100644 index 0000000000..44117bea30 --- /dev/null +++ b/test/functional/fixtures/fake-lsp-server.lua @@ -0,0 +1,438 @@ +local protocol = require 'vim.lsp.protocol' + + +local function message_parts(sep, ...) + local parts = {} + for i = 1, select("#", ...) do + local arg = select(i, ...) + if arg ~= nil then + table.insert(parts, arg) + end + end + return table.concat(parts, sep) +end + +-- Assert utility methods + +local function assert_eq(a, b, ...) + if not vim.deep_equal(a, b) then + error(message_parts(": ", + ..., "assert_eq failed", + string.format("left == %q, right == %q", vim.inspect(a), vim.inspect(b)) + )) + end +end + +local function format_message_with_content_length(encoded_message) + return table.concat { + 'Content-Length: '; tostring(#encoded_message); '\r\n\r\n'; + encoded_message; + } +end + +local function read_message() + local line = io.read("*l") + local length = line:lower():match("content%-length:%s*(%d+)") + return vim.fn.json_decode(io.read(2 + length):sub(2)) +end + +local function send(payload) + io.stdout:write(format_message_with_content_length(vim.fn.json_encode(payload))) +end + +local function respond(id, err, result) + assert(type(id) == 'number', "id must be a number") + send { jsonrpc = "2.0"; id = id, error = err, result = result } +end + +local function notify(method, params) + assert(type(method) == 'string', "method must be a string") + send { method = method, params = params or {} } +end + +local function expect_notification(method, params, ...) + local message = read_message() + assert_eq(method, message.method, + ..., "expect_notification", "method") + assert_eq(params, message.params, + ..., "expect_notification", method, "params") + assert_eq({jsonrpc = "2.0"; method=method, params=params}, message, + ..., "expect_notification", "message") +end + +local function expect_request(method, callback, ...) + local req = read_message() + assert_eq(method, req.method, + ..., "expect_request", "method") + local err, result = callback(req.params) + respond(req.id, err, result) +end + +io.stderr:setvbuf("no") + +local function skeleton(config) + local on_init = assert(config.on_init) + local body = assert(config.body) + expect_request("initialize", function(params) + return nil, on_init(params) + end) + expect_notification("initialized", {}) + body() + expect_request("shutdown", function() + return nil, {} + end) + expect_notification("exit", nil) +end + +-- The actual tests. + +local tests = {} + +function tests.basic_init() + skeleton { + on_init = function(_params) + return { capabilities = {} } + end; + body = function() + notify('test') + end; + } +end + +function tests.basic_check_capabilities() + skeleton { + on_init = function(params) + local expected_capabilities = protocol.make_client_capabilities() + assert_eq(params.capabilities, expected_capabilities) + return { + capabilities = { + textDocumentSync = protocol.TextDocumentSyncKind.Full; + } + } + end; + body = function() + end; + } +end + +function tests.basic_finish() + skeleton { + on_init = function(params) + local expected_capabilities = protocol.make_client_capabilities() + assert_eq(params.capabilities, expected_capabilities) + return { + capabilities = { + textDocumentSync = protocol.TextDocumentSyncKind.Full; + } + } + end; + body = function() + expect_notification("finish") + notify('finish') + end; + } +end + +function tests.basic_check_buffer_open() + skeleton { + on_init = function(params) + local expected_capabilities = protocol.make_client_capabilities() + assert_eq(params.capabilities, expected_capabilities) + return { + capabilities = { + textDocumentSync = protocol.TextDocumentSyncKind.Full; + } + } + end; + body = function() + notify('start') + expect_notification('textDocument/didOpen', { + textDocument = { + languageId = ""; + text = table.concat({"testing"; "123"}, "\n") .. '\n'; + uri = "file://"; + version = 0; + }; + }) + expect_notification("finish") + notify('finish') + end; + } +end + +function tests.basic_check_buffer_open_and_change() + skeleton { + on_init = function(params) + local expected_capabilities = protocol.make_client_capabilities() + assert_eq(params.capabilities, expected_capabilities) + return { + capabilities = { + textDocumentSync = protocol.TextDocumentSyncKind.Full; + } + } + end; + body = function() + notify('start') + expect_notification('textDocument/didOpen', { + textDocument = { + languageId = ""; + text = table.concat({"testing"; "123"}, "\n") .. '\n'; + uri = "file://"; + version = 0; + }; + }) + expect_notification('textDocument/didChange', { + textDocument = { + uri = "file://"; + version = 3; + }; + contentChanges = { + { text = table.concat({"testing"; "boop"}, "\n") .. '\n'; }; + } + }) + expect_notification("finish") + notify('finish') + end; + } +end + +function tests.basic_check_buffer_open_and_change_noeol() + skeleton { + on_init = function(params) + local expected_capabilities = protocol.make_client_capabilities() + assert_eq(params.capabilities, expected_capabilities) + return { + capabilities = { + textDocumentSync = protocol.TextDocumentSyncKind.Full; + } + } + end; + body = function() + notify('start') + expect_notification('textDocument/didOpen', { + textDocument = { + languageId = ""; + text = table.concat({"testing"; "123"}, "\n"); + uri = "file://"; + version = 0; + }; + }) + expect_notification('textDocument/didChange', { + textDocument = { + uri = "file://"; + version = 3; + }; + contentChanges = { + { text = table.concat({"testing"; "boop"}, "\n"); }; + } + }) + expect_notification("finish") + notify('finish') + end; + } +end +function tests.basic_check_buffer_open_and_change_multi() + skeleton { + on_init = function(params) + local expected_capabilities = protocol.make_client_capabilities() + assert_eq(params.capabilities, expected_capabilities) + return { + capabilities = { + textDocumentSync = protocol.TextDocumentSyncKind.Full; + } + } + end; + body = function() + notify('start') + expect_notification('textDocument/didOpen', { + textDocument = { + languageId = ""; + text = table.concat({"testing"; "123"}, "\n") .. '\n'; + uri = "file://"; + version = 0; + }; + }) + expect_notification('textDocument/didChange', { + textDocument = { + uri = "file://"; + version = 3; + }; + contentChanges = { + { text = table.concat({"testing"; "321"}, "\n") .. '\n'; }; + } + }) + expect_notification('textDocument/didChange', { + textDocument = { + uri = "file://"; + version = 4; + }; + contentChanges = { + { text = table.concat({"testing"; "boop"}, "\n") .. '\n'; }; + } + }) + expect_notification("finish") + notify('finish') + end; + } +end + +function tests.basic_check_buffer_open_and_change_multi_and_close() + skeleton { + on_init = function(params) + local expected_capabilities = protocol.make_client_capabilities() + assert_eq(params.capabilities, expected_capabilities) + return { + capabilities = { + textDocumentSync = protocol.TextDocumentSyncKind.Full; + } + } + end; + body = function() + notify('start') + expect_notification('textDocument/didOpen', { + textDocument = { + languageId = ""; + text = table.concat({"testing"; "123"}, "\n") .. '\n'; + uri = "file://"; + version = 0; + }; + }) + expect_notification('textDocument/didChange', { + textDocument = { + uri = "file://"; + version = 3; + }; + contentChanges = { + { text = table.concat({"testing"; "321"}, "\n") .. '\n'; }; + } + }) + expect_notification('textDocument/didChange', { + textDocument = { + uri = "file://"; + version = 4; + }; + contentChanges = { + { text = table.concat({"testing"; "boop"}, "\n") .. '\n'; }; + } + }) + expect_notification('textDocument/didClose', { + textDocument = { + uri = "file://"; + }; + }) + expect_notification("finish") + notify('finish') + end; + } +end + +function tests.basic_check_buffer_open_and_change_incremental() + skeleton { + on_init = function(params) + local expected_capabilities = protocol.make_client_capabilities() + assert_eq(params.capabilities, expected_capabilities) + return { + capabilities = { + textDocumentSync = protocol.TextDocumentSyncKind.Incremental; + } + } + end; + body = function() + notify('start') + expect_notification('textDocument/didOpen', { + textDocument = { + languageId = ""; + text = table.concat({"testing"; "123"}, "\n") .. '\n'; + uri = "file://"; + version = 0; + }; + }) + expect_notification('textDocument/didChange', { + textDocument = { + uri = "file://"; + version = 3; + }; + contentChanges = { + { + range = { + start = { line = 1; character = 0; }; + ["end"] = { line = 2; character = 0; }; + }; + rangeLength = 4; + text = "boop\n"; + }; + } + }) + expect_notification("finish") + notify('finish') + end; + } +end + +function tests.basic_check_buffer_open_and_change_incremental_editting() + skeleton { + on_init = function(params) + local expected_capabilities = protocol.make_client_capabilities() + assert_eq(params.capabilities, expected_capabilities) + return { + capabilities = { + textDocumentSync = protocol.TextDocumentSyncKind.Incremental; + } + } + end; + body = function() + notify('start') + expect_notification('textDocument/didOpen', { + textDocument = { + languageId = ""; + text = table.concat({"testing"; "123"}, "\n"); + uri = "file://"; + version = 0; + }; + }) + expect_notification('textDocument/didChange', { + textDocument = { + uri = "file://"; + version = 3; + }; + contentChanges = { + { + range = { + start = { line = 0; character = 0; }; + ["end"] = { line = 1; character = 0; }; + }; + rangeLength = 4; + text = "testing\n\n"; + }; + } + }) + expect_notification("finish") + notify('finish') + end; + } +end + +function tests.invalid_header() + io.stdout:write("Content-length: \r\n") +end + +-- Tests will be indexed by TEST_NAME + +local kill_timer = vim.loop.new_timer() +kill_timer:start(_G.TIMEOUT or 1e3, 0, function() + kill_timer:stop() + kill_timer:close() + io.stderr:write("TIMEOUT") + os.exit(100) +end) + +local test_name = _G.TEST_NAME -- lualint workaround +assert(type(test_name) == 'string', 'TEST_NAME must be specified.') +local status, err = pcall(assert(tests[test_name], "Test not found")) +kill_timer:stop() +kill_timer:close() +if not status then + io.stderr:write(err) + os.exit(101) +end +os.exit(0) diff --git a/test/functional/fixtures/lsp-test-rpc-server.lua b/test/functional/fixtures/lsp-test-rpc-server.lua deleted file mode 100644 index 44117bea30..0000000000 --- a/test/functional/fixtures/lsp-test-rpc-server.lua +++ /dev/null @@ -1,438 +0,0 @@ -local protocol = require 'vim.lsp.protocol' - - -local function message_parts(sep, ...) - local parts = {} - for i = 1, select("#", ...) do - local arg = select(i, ...) - if arg ~= nil then - table.insert(parts, arg) - end - end - return table.concat(parts, sep) -end - --- Assert utility methods - -local function assert_eq(a, b, ...) - if not vim.deep_equal(a, b) then - error(message_parts(": ", - ..., "assert_eq failed", - string.format("left == %q, right == %q", vim.inspect(a), vim.inspect(b)) - )) - end -end - -local function format_message_with_content_length(encoded_message) - return table.concat { - 'Content-Length: '; tostring(#encoded_message); '\r\n\r\n'; - encoded_message; - } -end - -local function read_message() - local line = io.read("*l") - local length = line:lower():match("content%-length:%s*(%d+)") - return vim.fn.json_decode(io.read(2 + length):sub(2)) -end - -local function send(payload) - io.stdout:write(format_message_with_content_length(vim.fn.json_encode(payload))) -end - -local function respond(id, err, result) - assert(type(id) == 'number', "id must be a number") - send { jsonrpc = "2.0"; id = id, error = err, result = result } -end - -local function notify(method, params) - assert(type(method) == 'string', "method must be a string") - send { method = method, params = params or {} } -end - -local function expect_notification(method, params, ...) - local message = read_message() - assert_eq(method, message.method, - ..., "expect_notification", "method") - assert_eq(params, message.params, - ..., "expect_notification", method, "params") - assert_eq({jsonrpc = "2.0"; method=method, params=params}, message, - ..., "expect_notification", "message") -end - -local function expect_request(method, callback, ...) - local req = read_message() - assert_eq(method, req.method, - ..., "expect_request", "method") - local err, result = callback(req.params) - respond(req.id, err, result) -end - -io.stderr:setvbuf("no") - -local function skeleton(config) - local on_init = assert(config.on_init) - local body = assert(config.body) - expect_request("initialize", function(params) - return nil, on_init(params) - end) - expect_notification("initialized", {}) - body() - expect_request("shutdown", function() - return nil, {} - end) - expect_notification("exit", nil) -end - --- The actual tests. - -local tests = {} - -function tests.basic_init() - skeleton { - on_init = function(_params) - return { capabilities = {} } - end; - body = function() - notify('test') - end; - } -end - -function tests.basic_check_capabilities() - skeleton { - on_init = function(params) - local expected_capabilities = protocol.make_client_capabilities() - assert_eq(params.capabilities, expected_capabilities) - return { - capabilities = { - textDocumentSync = protocol.TextDocumentSyncKind.Full; - } - } - end; - body = function() - end; - } -end - -function tests.basic_finish() - skeleton { - on_init = function(params) - local expected_capabilities = protocol.make_client_capabilities() - assert_eq(params.capabilities, expected_capabilities) - return { - capabilities = { - textDocumentSync = protocol.TextDocumentSyncKind.Full; - } - } - end; - body = function() - expect_notification("finish") - notify('finish') - end; - } -end - -function tests.basic_check_buffer_open() - skeleton { - on_init = function(params) - local expected_capabilities = protocol.make_client_capabilities() - assert_eq(params.capabilities, expected_capabilities) - return { - capabilities = { - textDocumentSync = protocol.TextDocumentSyncKind.Full; - } - } - end; - body = function() - notify('start') - expect_notification('textDocument/didOpen', { - textDocument = { - languageId = ""; - text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "file://"; - version = 0; - }; - }) - expect_notification("finish") - notify('finish') - end; - } -end - -function tests.basic_check_buffer_open_and_change() - skeleton { - on_init = function(params) - local expected_capabilities = protocol.make_client_capabilities() - assert_eq(params.capabilities, expected_capabilities) - return { - capabilities = { - textDocumentSync = protocol.TextDocumentSyncKind.Full; - } - } - end; - body = function() - notify('start') - expect_notification('textDocument/didOpen', { - textDocument = { - languageId = ""; - text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "file://"; - version = 0; - }; - }) - expect_notification('textDocument/didChange', { - textDocument = { - uri = "file://"; - version = 3; - }; - contentChanges = { - { text = table.concat({"testing"; "boop"}, "\n") .. '\n'; }; - } - }) - expect_notification("finish") - notify('finish') - end; - } -end - -function tests.basic_check_buffer_open_and_change_noeol() - skeleton { - on_init = function(params) - local expected_capabilities = protocol.make_client_capabilities() - assert_eq(params.capabilities, expected_capabilities) - return { - capabilities = { - textDocumentSync = protocol.TextDocumentSyncKind.Full; - } - } - end; - body = function() - notify('start') - expect_notification('textDocument/didOpen', { - textDocument = { - languageId = ""; - text = table.concat({"testing"; "123"}, "\n"); - uri = "file://"; - version = 0; - }; - }) - expect_notification('textDocument/didChange', { - textDocument = { - uri = "file://"; - version = 3; - }; - contentChanges = { - { text = table.concat({"testing"; "boop"}, "\n"); }; - } - }) - expect_notification("finish") - notify('finish') - end; - } -end -function tests.basic_check_buffer_open_and_change_multi() - skeleton { - on_init = function(params) - local expected_capabilities = protocol.make_client_capabilities() - assert_eq(params.capabilities, expected_capabilities) - return { - capabilities = { - textDocumentSync = protocol.TextDocumentSyncKind.Full; - } - } - end; - body = function() - notify('start') - expect_notification('textDocument/didOpen', { - textDocument = { - languageId = ""; - text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "file://"; - version = 0; - }; - }) - expect_notification('textDocument/didChange', { - textDocument = { - uri = "file://"; - version = 3; - }; - contentChanges = { - { text = table.concat({"testing"; "321"}, "\n") .. '\n'; }; - } - }) - expect_notification('textDocument/didChange', { - textDocument = { - uri = "file://"; - version = 4; - }; - contentChanges = { - { text = table.concat({"testing"; "boop"}, "\n") .. '\n'; }; - } - }) - expect_notification("finish") - notify('finish') - end; - } -end - -function tests.basic_check_buffer_open_and_change_multi_and_close() - skeleton { - on_init = function(params) - local expected_capabilities = protocol.make_client_capabilities() - assert_eq(params.capabilities, expected_capabilities) - return { - capabilities = { - textDocumentSync = protocol.TextDocumentSyncKind.Full; - } - } - end; - body = function() - notify('start') - expect_notification('textDocument/didOpen', { - textDocument = { - languageId = ""; - text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "file://"; - version = 0; - }; - }) - expect_notification('textDocument/didChange', { - textDocument = { - uri = "file://"; - version = 3; - }; - contentChanges = { - { text = table.concat({"testing"; "321"}, "\n") .. '\n'; }; - } - }) - expect_notification('textDocument/didChange', { - textDocument = { - uri = "file://"; - version = 4; - }; - contentChanges = { - { text = table.concat({"testing"; "boop"}, "\n") .. '\n'; }; - } - }) - expect_notification('textDocument/didClose', { - textDocument = { - uri = "file://"; - }; - }) - expect_notification("finish") - notify('finish') - end; - } -end - -function tests.basic_check_buffer_open_and_change_incremental() - skeleton { - on_init = function(params) - local expected_capabilities = protocol.make_client_capabilities() - assert_eq(params.capabilities, expected_capabilities) - return { - capabilities = { - textDocumentSync = protocol.TextDocumentSyncKind.Incremental; - } - } - end; - body = function() - notify('start') - expect_notification('textDocument/didOpen', { - textDocument = { - languageId = ""; - text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "file://"; - version = 0; - }; - }) - expect_notification('textDocument/didChange', { - textDocument = { - uri = "file://"; - version = 3; - }; - contentChanges = { - { - range = { - start = { line = 1; character = 0; }; - ["end"] = { line = 2; character = 0; }; - }; - rangeLength = 4; - text = "boop\n"; - }; - } - }) - expect_notification("finish") - notify('finish') - end; - } -end - -function tests.basic_check_buffer_open_and_change_incremental_editting() - skeleton { - on_init = function(params) - local expected_capabilities = protocol.make_client_capabilities() - assert_eq(params.capabilities, expected_capabilities) - return { - capabilities = { - textDocumentSync = protocol.TextDocumentSyncKind.Incremental; - } - } - end; - body = function() - notify('start') - expect_notification('textDocument/didOpen', { - textDocument = { - languageId = ""; - text = table.concat({"testing"; "123"}, "\n"); - uri = "file://"; - version = 0; - }; - }) - expect_notification('textDocument/didChange', { - textDocument = { - uri = "file://"; - version = 3; - }; - contentChanges = { - { - range = { - start = { line = 0; character = 0; }; - ["end"] = { line = 1; character = 0; }; - }; - rangeLength = 4; - text = "testing\n\n"; - }; - } - }) - expect_notification("finish") - notify('finish') - end; - } -end - -function tests.invalid_header() - io.stdout:write("Content-length: \r\n") -end - --- Tests will be indexed by TEST_NAME - -local kill_timer = vim.loop.new_timer() -kill_timer:start(_G.TIMEOUT or 1e3, 0, function() - kill_timer:stop() - kill_timer:close() - io.stderr:write("TIMEOUT") - os.exit(100) -end) - -local test_name = _G.TEST_NAME -- lualint workaround -assert(type(test_name) == 'string', 'TEST_NAME must be specified.') -local status, err = pcall(assert(tests[test_name], "Test not found")) -kill_timer:stop() -kill_timer:close() -if not status then - io.stderr:write(err) - os.exit(101) -end -os.exit(0) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index cab1fb0d79..c384fdedf3 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -16,16 +16,16 @@ local run, stop = helpers.run, helpers.stop if helpers.pending_win32(pending) then return end -local fake_lsp_server_file = "test/functional/fixtures/lsp-test-rpc-server.lua" -if iswin() then - fake_lsp_server_file = fake_lsp_server_file:gsub("/", "\\") -end +local fake_lsp_server_file = 'test/functional/fixtures/fake-lsp-server.lua' local function fake_lsp_server_setup(test_name, timeout_ms) exec_lua([=[ lsp = require('vim.lsp') local test_name, fixture_filename, timeout = ... TEST_RPC_CLIENT_ID = lsp.start_client { + cmd_env = { + NVIM_LOG_FILE = 'Xtest-fake-lsp-server.log' + }; cmd = { vim.v.progpath, '-Es', '-u', 'NONE', '--headless', "-c", string.format("lua TEST_NAME = %q", test_name), @@ -117,6 +117,9 @@ describe('LSP', function() local test_name, fixture_filename = ... function test__start_client() return lsp.start_client { + cmd_env = { + NVIM_LOG_FILE = 'Xtest-fake-lsp-server.log' + }; cmd = { vim.v.progpath, '-Es', '-u', 'NONE', '--headless', "-c", string.format("lua TEST_NAME = %q", test_name), @@ -217,7 +220,7 @@ describe('LSP', function() client.stop() end; on_exit = function(code, signal) - eq(101, code, "exit code") + eq(101, code, "exit code") -- See fake-lsp-server.lua eq(0, signal, "exit signal") end; on_callback = function(...) -- cgit From 4cf48dc329e3e3f451ecf902af9af6317d44bb40 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 8 Feb 2020 18:08:02 -0800 Subject: test/LSP: dump logs on error This will help debug CI flakey failures. TODO: helpers.assert_log() -- Explicitly check contents of the logfile. --- test/functional/plugin/lsp_spec.lua | 79 ++++++++++++++++++++----------------- test/helpers.lua | 14 +++++-- 2 files changed, 54 insertions(+), 39 deletions(-) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index c384fdedf3..b2d00a400a 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -5,8 +5,8 @@ local buf_lines = helpers.buf_lines local dedent = helpers.dedent local exec_lua = helpers.exec_lua local eq = helpers.eq +local eq_dumplog = helpers.eq_dumplog local insert = helpers.insert -local iswin = helpers.iswin local retry = helpers.retry local NIL = helpers.NIL @@ -14,17 +14,24 @@ local NIL = helpers.NIL -- yield. local run, stop = helpers.run, helpers.stop +-- TODO(justinmk): hangs on Windows https://github.com/neovim/neovim/pull/11837 if helpers.pending_win32(pending) then return end -local fake_lsp_server_file = 'test/functional/fixtures/fake-lsp-server.lua' +-- Fake LSP server. +local fake_lsp_code = 'test/functional/fixtures/fake-lsp-server.lua' +local fake_lsp_logfile = 'Xtest-fake-lsp.log' + +teardown(function() + os.remove(fake_lsp_logfile) +end) local function fake_lsp_server_setup(test_name, timeout_ms) exec_lua([=[ lsp = require('vim.lsp') - local test_name, fixture_filename, timeout = ... + local test_name, fixture_filename, logfile, timeout = ... TEST_RPC_CLIENT_ID = lsp.start_client { cmd_env = { - NVIM_LOG_FILE = 'Xtest-fake-lsp-server.log' + NVIM_LOG_FILE = logfile; }; cmd = { vim.v.progpath, '-Es', '-u', 'NONE', '--headless', @@ -48,7 +55,7 @@ local function fake_lsp_server_setup(test_name, timeout_ms) vim.rpcnotify(1, "exit", ...) end; } - ]=], test_name, fake_lsp_server_file, timeout_ms or 1e3) + ]=], test_name, fake_lsp_code, fake_lsp_logfile, timeout_ms or 1e3) end local function test_rpc_server(config) @@ -114,11 +121,11 @@ describe('LSP', function() local test_name = "basic_init" exec_lua([=[ lsp = require('vim.lsp') - local test_name, fixture_filename = ... + local test_name, fixture_filename, logfile = ... function test__start_client() return lsp.start_client { cmd_env = { - NVIM_LOG_FILE = 'Xtest-fake-lsp-server.log' + NVIM_LOG_FILE = logfile; }; cmd = { vim.v.progpath, '-Es', '-u', 'NONE', '--headless', @@ -129,7 +136,7 @@ describe('LSP', function() } end TEST_CLIENT1 = test__start_client() - ]=], test_name, fake_lsp_server_file) + ]=], test_name, fake_lsp_code, fake_lsp_logfile) end) after_each(function() @@ -198,8 +205,8 @@ describe('LSP', function() end; -- If the program timed out, then code will be nil. on_exit = function(code, signal) - eq(0, code, "exit code") - eq(0, signal, "exit signal") + eq_dumplog(fake_lsp_logfile, 0, code, "exit code") + eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") end; -- Note that NIL must be used here. -- on_callback(err, method, result, client_id) @@ -220,8 +227,8 @@ describe('LSP', function() client.stop() end; on_exit = function(code, signal) - eq(101, code, "exit code") -- See fake-lsp-server.lua - eq(0, signal, "exit signal") + eq_dumplog(fake_lsp_logfile, 101, code, "exit code") -- See fake-lsp-server.lua + eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") end; on_callback = function(...) eq(table.remove(expected_callbacks), {...}, "expected callback") @@ -242,8 +249,8 @@ describe('LSP', function() client.notify('exit') end; on_exit = function(code, signal) - eq(0, code, "exit code") - eq(0, signal, "exit signal") + eq_dumplog(fake_lsp_logfile, 0, code, "exit code") + eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") end; on_callback = function(...) eq(table.remove(expected_callbacks), {...}, "expected callback") @@ -261,8 +268,8 @@ describe('LSP', function() client.stop() end; on_exit = function(code, signal) - eq(0, code, "exit code") - eq(0, signal, "exit signal") + eq_dumplog(fake_lsp_logfile, 0, code, "exit code") + eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") end; on_callback = function(...) eq(table.remove(expected_callbacks), {...}, "expected callback") @@ -301,8 +308,8 @@ describe('LSP', function() client.notify('finish') end; on_exit = function(code, signal) - eq(0, code, "exit code") - eq(0, signal, "exit signal") + eq_dumplog(fake_lsp_logfile, 0, code, "exit code") + eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") end; on_callback = function(err, method, params, client_id) eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") @@ -344,8 +351,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq(0, code, "exit code") - eq(0, signal, "exit signal") + eq_dumplog(fake_lsp_logfile, 0, code, "exit code") + eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -387,8 +394,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq(0, code, "exit code") - eq(0, signal, "exit signal") + eq_dumplog(fake_lsp_logfile, 0, code, "exit code") + eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -430,8 +437,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq(0, code, "exit code") - eq(0, signal, "exit signal") + eq_dumplog(fake_lsp_logfile, 0, code, "exit code") + eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -479,8 +486,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq(0, code, "exit code") - eq(0, signal, "exit signal") + eq_dumplog(fake_lsp_logfile, 0, code, "exit code") + eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -528,8 +535,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq(0, code, "exit code") - eq(0, signal, "exit signal") + eq_dumplog(fake_lsp_logfile, 0, code, "exit code") + eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -577,8 +584,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq(0, code, "exit code") - eq(0, signal, "exit signal") + eq_dumplog(fake_lsp_logfile, 0, code, "exit code") + eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -621,8 +628,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq(0, code, "exit code") - eq(0, signal, "exit signal") + eq_dumplog(fake_lsp_logfile, 0, code, "exit code") + eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -672,8 +679,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq(0, code, "exit code") - eq(0, signal, "exit signal") + eq_dumplog(fake_lsp_logfile, 0, code, "exit code") + eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -715,8 +722,8 @@ describe('LSP', function() client.stop(true) end; on_exit = function(code, signal) - eq(0, code, "exit code") - eq(0, signal, "exit signal") + eq_dumplog(fake_lsp_logfile, 0, code, "exit code") + eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") end; on_callback = function(err, method, params, client_id) eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") diff --git a/test/helpers.lua b/test/helpers.lua index 98f003f208..d9e1f4a963 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -58,6 +58,14 @@ local check_logs_useless_lines = { function module.eq(expected, actual, context) return assert.are.same(expected, actual, context) end +-- Like eq(), but includes tail of `logfile` in failure message. +function module.eq_dumplog(logfile, expected, actual, context) + local status, rv = pcall(module.eq, expected, actual, context) + if not status then + local logtail = module.read_nvim_log(logfile) + error(string.format('%s\n%s', rv, logtail)) + end +end function module.neq(expected, actual, context) return assert.are_not.same(expected, actual, context) end @@ -737,10 +745,10 @@ function module.isCI(name) end --- Gets the contents of $NVIM_LOG_FILE for printing to the build log. +-- Gets the contents of `logfile` for printing to the build log. -- Also moves the file to "${NVIM_LOG_FILE}.displayed" on CI environments. -function module.read_nvim_log() - local logfile = os.getenv('NVIM_LOG_FILE') or '.nvimlog' +function module.read_nvim_log(logfile) + logfile = logfile or os.getenv('NVIM_LOG_FILE') or '.nvimlog' local is_ci = module.isCI() local keep = is_ci and 999 or 10 local lines = module.read_file_list(logfile, -keep) or {} -- cgit From a446fbc8fa278d9c1e4144dc9767c9dc0b184583 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 9 Feb 2020 00:05:48 -0800 Subject: lsp/rpc.lua: fix `env` application function Env vars must be merged with the current env. --- test/functional/fixtures/fake-lsp-server.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua index 44117bea30..cac590fd14 100644 --- a/test/functional/fixtures/fake-lsp-server.lua +++ b/test/functional/fixtures/fake-lsp-server.lua @@ -369,7 +369,7 @@ function tests.basic_check_buffer_open_and_change_incremental() } end -function tests.basic_check_buffer_open_and_change_incremental_editting() +function tests.basic_check_buffer_open_and_change_incremental_editing() skeleton { on_init = function(params) local expected_capabilities = protocol.make_client_capabilities() @@ -422,6 +422,7 @@ local kill_timer = vim.loop.new_timer() kill_timer:start(_G.TIMEOUT or 1e3, 0, function() kill_timer:stop() kill_timer:close() + -- TODO: log('TIMEOUT') io.stderr:write("TIMEOUT") os.exit(100) end) @@ -432,6 +433,7 @@ local status, err = pcall(assert(tests[test_name], "Test not found")) kill_timer:stop() kill_timer:close() if not status then + -- TODO: log(err) io.stderr:write(err) os.exit(101) end -- cgit From 6e13b9d26134210f0963341bd77c64a4437f37ec Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 16 Feb 2020 19:02:09 -0800 Subject: test/LSP: assert contents of log file --- test/busted/outputHandlers/TAP.lua | 2 +- test/busted/outputHandlers/nvim.lua | 2 +- test/functional/fixtures/fake-lsp-server.lua | 14 ++++++++++++-- test/functional/plugin/lsp_spec.lua | 4 ++++ test/helpers.lua | 22 +++++++++++++++++++--- 5 files changed, 37 insertions(+), 7 deletions(-) (limited to 'test') diff --git a/test/busted/outputHandlers/TAP.lua b/test/busted/outputHandlers/TAP.lua index 8dc4ff55b6..5de48c0ad3 100644 --- a/test/busted/outputHandlers/TAP.lua +++ b/test/busted/outputHandlers/TAP.lua @@ -7,7 +7,7 @@ return function(options) local handler = require 'busted.outputHandlers.TAP'(options) local suiteEnd = function() - io.write(global_helpers.read_nvim_log()) + io.write(global_helpers.read_nvim_log(nil, true)) return nil, true end busted.subscribe({ 'suite', 'end' }, suiteEnd) diff --git a/test/busted/outputHandlers/nvim.lua b/test/busted/outputHandlers/nvim.lua index 8f3aad776e..5456e9ca98 100644 --- a/test/busted/outputHandlers/nvim.lua +++ b/test/busted/outputHandlers/nvim.lua @@ -196,7 +196,7 @@ return function(options) local tests = (testCount == 1 and 'test' or 'tests') local files = (fileCount == 1 and 'file' or 'files') io.write(globalTeardown) - io.write(global_helpers.read_nvim_log()) + io.write(global_helpers.read_nvim_log(nil, true)) io.write(suiteEndString:format(testCount, tests, fileCount, files, elapsedTime_ms)) io.write(getSummaryString()) io.flush() diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua index cac590fd14..dca7f35923 100644 --- a/test/functional/fixtures/fake-lsp-server.lua +++ b/test/functional/fixtures/fake-lsp-server.lua @@ -1,6 +1,16 @@ local protocol = require 'vim.lsp.protocol' +-- Logs to $NVIM_LOG_FILE. +-- +-- TODO(justinmk): remove after https://github.com/neovim/neovim/pull/7062 +local function log(loglevel, area, msg) + vim.fn.writefile( + {string.format('%s %s: %s', loglevel, area, msg)}, + vim.env.NVIM_LOG_FILE, + 'a') +end + local function message_parts(sep, ...) local parts = {} for i = 1, select("#", ...) do @@ -422,7 +432,7 @@ local kill_timer = vim.loop.new_timer() kill_timer:start(_G.TIMEOUT or 1e3, 0, function() kill_timer:stop() kill_timer:close() - -- TODO: log('TIMEOUT') + log('ERROR', 'LSP', 'TIMEOUT') io.stderr:write("TIMEOUT") os.exit(100) end) @@ -433,7 +443,7 @@ local status, err = pcall(assert(tests[test_name], "Test not found")) kill_timer:stop() kill_timer:close() if not status then - -- TODO: log(err) + log('ERROR', 'LSP', tostring(err)) io.stderr:write(err) os.exit(101) end diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index b2d00a400a..03e516d6f6 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -1,11 +1,13 @@ local helpers = require('test.functional.helpers')(after_each) +local assert_log = helpers.assert_log local clear = helpers.clear local buf_lines = helpers.buf_lines local dedent = helpers.dedent local exec_lua = helpers.exec_lua local eq = helpers.eq local eq_dumplog = helpers.eq_dumplog +local pesc = helpers.pesc local insert = helpers.insert local retry = helpers.retry local NIL = helpers.NIL @@ -229,6 +231,8 @@ describe('LSP', function() on_exit = function(code, signal) eq_dumplog(fake_lsp_logfile, 101, code, "exit code") -- See fake-lsp-server.lua eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") + assert_log(pesc([[assert_eq failed: left == "\"shutdown\"", right == "\"test\""]]), + fake_lsp_logfile) end; on_callback = function(...) eq(table.remove(expected_callbacks), {...}, "expected callback") diff --git a/test/helpers.lua b/test/helpers.lua index d9e1f4a963..a31a7733bf 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -82,6 +82,22 @@ function module.matches(pat, actual) error(string.format('Pattern does not match.\nPattern:\n%s\nActual:\n%s', pat, actual)) end +--- Asserts that `pat` matches one or more lines in the tail of $NVIM_LOG_FILE. +--- +--@param pat (string) Lua pattern to search for in the log file. +--@param logfile (string, default=$NVIM_LOG_FILE) full path to log file. +function module.assert_log(pat, logfile) + logfile = logfile or os.getenv('NVIM_LOG_FILE') or '.nvimlog' + local nrlines = 10 + local lines = module.read_file_list(logfile, -nrlines) or {} + for _,line in ipairs(lines) do + if line:match(pat) then return end + end + local logtail = module.read_nvim_log(logfile) + error(string.format('Pattern %q not found in log (last %d lines): %s:\n%s', + pat, nrlines, logfile, logtail)) +end + -- Invokes `fn` and returns the error string (may truncate full paths), or -- raises an error if `fn` succeeds. -- @@ -745,9 +761,9 @@ function module.isCI(name) end --- Gets the contents of `logfile` for printing to the build log. +-- Gets the (tail) contents of `logfile`. -- Also moves the file to "${NVIM_LOG_FILE}.displayed" on CI environments. -function module.read_nvim_log(logfile) +function module.read_nvim_log(logfile, ci_rename) logfile = logfile or os.getenv('NVIM_LOG_FILE') or '.nvimlog' local is_ci = module.isCI() local keep = is_ci and 999 or 10 @@ -759,7 +775,7 @@ function module.read_nvim_log(logfile) log = log..line..'\n' end log = log..('-'):rep(78)..'\n' - if is_ci then + if is_ci and ci_rename then os.rename(logfile, logfile .. '.displayed') end return log -- cgit From b353a5c05f026f46aeef0843007ba9c553533248 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 16 Feb 2020 23:30:24 -0800 Subject: test: always dump logs on failure #11886 Whenever `eq()`, `ok()`, etc. fails, include log tail in the failure message. This helps to correlate log messages with a particular test failure. --- test/functional/plugin/lsp_spec.lua | 57 ++++++++++++++++++------------------- test/helpers.lua | 33 ++++++++++++--------- 2 files changed, 48 insertions(+), 42 deletions(-) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 03e516d6f6..ba1eb2113e 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -6,7 +6,6 @@ local buf_lines = helpers.buf_lines local dedent = helpers.dedent local exec_lua = helpers.exec_lua local eq = helpers.eq -local eq_dumplog = helpers.eq_dumplog local pesc = helpers.pesc local insert = helpers.insert local retry = helpers.retry @@ -207,8 +206,8 @@ describe('LSP', function() end; -- If the program timed out, then code will be nil. on_exit = function(code, signal) - eq_dumplog(fake_lsp_logfile, 0, code, "exit code") - eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") + eq(0, code, "exit code", fake_lsp_logfile) + eq(0, signal, "exit signal", fake_lsp_logfile) end; -- Note that NIL must be used here. -- on_callback(err, method, result, client_id) @@ -229,8 +228,8 @@ describe('LSP', function() client.stop() end; on_exit = function(code, signal) - eq_dumplog(fake_lsp_logfile, 101, code, "exit code") -- See fake-lsp-server.lua - eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") + eq(101, code, "exit code", fake_lsp_logfile) -- See fake-lsp-server.lua + eq(0, signal, "exit signal", fake_lsp_logfile) assert_log(pesc([[assert_eq failed: left == "\"shutdown\"", right == "\"test\""]]), fake_lsp_logfile) end; @@ -253,8 +252,8 @@ describe('LSP', function() client.notify('exit') end; on_exit = function(code, signal) - eq_dumplog(fake_lsp_logfile, 0, code, "exit code") - eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") + eq(0, code, "exit code", fake_lsp_logfile) + eq(0, signal, "exit signal", fake_lsp_logfile) end; on_callback = function(...) eq(table.remove(expected_callbacks), {...}, "expected callback") @@ -272,8 +271,8 @@ describe('LSP', function() client.stop() end; on_exit = function(code, signal) - eq_dumplog(fake_lsp_logfile, 0, code, "exit code") - eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") + eq(0, code, "exit code", fake_lsp_logfile) + eq(0, signal, "exit signal", fake_lsp_logfile) end; on_callback = function(...) eq(table.remove(expected_callbacks), {...}, "expected callback") @@ -312,8 +311,8 @@ describe('LSP', function() client.notify('finish') end; on_exit = function(code, signal) - eq_dumplog(fake_lsp_logfile, 0, code, "exit code") - eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") + eq(0, code, "exit code", fake_lsp_logfile) + eq(0, signal, "exit signal", fake_lsp_logfile) end; on_callback = function(err, method, params, client_id) eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") @@ -355,8 +354,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq_dumplog(fake_lsp_logfile, 0, code, "exit code") - eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") + eq(0, code, "exit code", fake_lsp_logfile) + eq(0, signal, "exit signal", fake_lsp_logfile) end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -398,8 +397,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq_dumplog(fake_lsp_logfile, 0, code, "exit code") - eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") + eq(0, code, "exit code", fake_lsp_logfile) + eq(0, signal, "exit signal", fake_lsp_logfile) end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -441,8 +440,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq_dumplog(fake_lsp_logfile, 0, code, "exit code") - eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") + eq(0, code, "exit code", fake_lsp_logfile) + eq(0, signal, "exit signal", fake_lsp_logfile) end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -490,8 +489,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq_dumplog(fake_lsp_logfile, 0, code, "exit code") - eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") + eq(0, code, "exit code", fake_lsp_logfile) + eq(0, signal, "exit signal", fake_lsp_logfile) end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -539,8 +538,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq_dumplog(fake_lsp_logfile, 0, code, "exit code") - eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") + eq(0, code, "exit code", fake_lsp_logfile) + eq(0, signal, "exit signal", fake_lsp_logfile) end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -588,8 +587,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq_dumplog(fake_lsp_logfile, 0, code, "exit code") - eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") + eq(0, code, "exit code", fake_lsp_logfile) + eq(0, signal, "exit signal", fake_lsp_logfile) end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -632,8 +631,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq_dumplog(fake_lsp_logfile, 0, code, "exit code") - eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") + eq(0, code, "exit code", fake_lsp_logfile) + eq(0, signal, "exit signal", fake_lsp_logfile) end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -683,8 +682,8 @@ describe('LSP', function() ]] end; on_exit = function(code, signal) - eq_dumplog(fake_lsp_logfile, 0, code, "exit code") - eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") + eq(0, code, "exit code", fake_lsp_logfile) + eq(0, signal, "exit signal", fake_lsp_logfile) end; on_callback = function(err, method, params, client_id) if method == 'start' then @@ -726,8 +725,8 @@ describe('LSP', function() client.stop(true) end; on_exit = function(code, signal) - eq_dumplog(fake_lsp_logfile, 0, code, "exit code") - eq_dumplog(fake_lsp_logfile, 0, signal, "exit signal") + eq(0, code, "exit code", fake_lsp_logfile) + eq(0, signal, "exit signal", fake_lsp_logfile) end; on_callback = function(err, method, params, client_id) eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") diff --git a/test/helpers.lua b/test/helpers.lua index a31a7733bf..72b1bdcadd 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -55,25 +55,32 @@ local check_logs_useless_lines = { ['See README_MISSING_SYSCALL_OR_IOCTL for guidance']=3, } -function module.eq(expected, actual, context) - return assert.are.same(expected, actual, context) -end --- Like eq(), but includes tail of `logfile` in failure message. -function module.eq_dumplog(logfile, expected, actual, context) - local status, rv = pcall(module.eq, expected, actual, context) - if not status then +--- Invokes `fn` and includes the tail of `logfile` in the error message if it +--- fails. +--- +--@param logfile Log file, defaults to $NVIM_LOG_FILE or '.nvimlog' +--@param fn Function to invoke +--@param ... Function arguments +local function dumplog(logfile, fn, ...) + -- module.validate({ + -- logfile={logfile,'s',true}, + -- fn={fn,'f',false}, + -- }) + local status, rv = pcall(fn, ...) + if status == false then + logfile = logfile or os.getenv('NVIM_LOG_FILE') or '.nvimlog' local logtail = module.read_nvim_log(logfile) error(string.format('%s\n%s', rv, logtail)) end end -function module.neq(expected, actual, context) - return assert.are_not.same(expected, actual, context) +function module.eq(expected, actual, context, logfile) + return dumplog(logfile, assert.are.same, expected, actual, context) end -function module.ok(res, msg) - return assert.is_true(res, msg) +function module.neq(expected, actual, context, logfile) + return dumplog(logfile, assert.are_not.same, expected, actual, context) end -function module.near(actual, expected, tolerance) - return assert.is.near(actual, expected, tolerance) +function module.ok(res, msg, logfile) + return dumplog(logfile, assert.is_true, res, msg) end function module.matches(pat, actual) if nil ~= string.match(actual, pat) then -- cgit From e2ed8053bf722d4d111fac7dcdb07179fdea8752 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Tue, 18 Feb 2020 17:41:29 +0900 Subject: lua: move test helper function, map and filter, to vim.shared module --- test/functional/eval/ctx_functions_spec.lua | 2 +- test/functional/helpers.lua | 4 ++-- test/functional/lua/vim_spec.lua | 24 ++++++++++++++++++++++++ test/functional/normal/put_spec.lua | 4 ++-- test/helpers.lua | 18 ------------------ test/unit/eval/typval_spec.lua | 2 +- test/unit/helpers.lua | 2 +- 7 files changed, 31 insertions(+), 25 deletions(-) (limited to 'test') diff --git a/test/functional/eval/ctx_functions_spec.lua b/test/functional/eval/ctx_functions_spec.lua index c81dad9645..f23adbc556 100644 --- a/test/functional/eval/ctx_functions_spec.lua +++ b/test/functional/eval/ctx_functions_spec.lua @@ -6,7 +6,7 @@ local command = helpers.command local eq = helpers.eq local eval = helpers.eval local feed = helpers.feed -local map = helpers.map +local map = helpers.tbl_map local nvim = helpers.nvim local parse_context = helpers.parse_context local redir_exec = helpers.redir_exec diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 53c4d140b6..e8435cd3b7 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -15,9 +15,9 @@ 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 filter = global_helpers.filter +local filter = global_helpers.tbl_filter local is_os = global_helpers.is_os -local map = global_helpers.map +local map = global_helpers.tbl_map local ok = global_helpers.ok local sleep = global_helpers.sleep local tbl_contains = global_helpers.tbl_contains diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index ca7c5301ed..2f459145f5 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -384,6 +384,30 @@ describe('lua stdlib', function() end end) + it('vim.tbl_map', function() + eq({}, exec_lua([[ + return vim.tbl_map(function(v) return v * 2 end, {}) + ]])) + eq({2, 4, 6}, exec_lua([[ + return vim.tbl_map(function(v) return v * 2 end, {1, 2, 3}) + ]])) + eq({{i=2}, {i=4}, {i=6}}, exec_lua([[ + return vim.tbl_map(function(v) return { i = v.i * 2 } end, {{i=1}, {i=2}, {i=3}}) + ]])) + end) + + it('vim.tbl_filter', function() + eq({}, exec_lua([[ + return vim.tbl_filter(function(v) return (v % 2) == 0 end, {}) + ]])) + eq({2}, exec_lua([[ + return vim.tbl_filter(function(v) return (v % 2) == 0 end, {1, 2, 3}) + ]])) + eq({{i=2}}, exec_lua([[ + return vim.tbl_filter(function(v) return (v.i % 2) == 0 end, {{i=1}, {i=2}, {i=3}}) + ]])) + end) + it('vim.tbl_islist', function() eq(true, exec_lua("return vim.tbl_islist({})")) eq(false, exec_lua("return vim.tbl_islist(vim.empty_dict())")) diff --git a/test/functional/normal/put_spec.lua b/test/functional/normal/put_spec.lua index 357fafec44..26967ecbba 100644 --- a/test/functional/normal/put_spec.lua +++ b/test/functional/normal/put_spec.lua @@ -6,8 +6,8 @@ local insert = helpers.insert local feed = helpers.feed local expect = helpers.expect local eq = helpers.eq -local map = helpers.map -local filter = helpers.filter +local map = helpers.tbl_map +local filter = helpers.tbl_filter local feed_command = helpers.feed_command local curbuf_contents = helpers.curbuf_contents local funcs = helpers.funcs diff --git a/test/helpers.lua b/test/helpers.lua index 72b1bdcadd..40b93d9935 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -290,24 +290,6 @@ module.tmpname = (function() end) end)() -function module.map(func, tab) - local rettab = {} - for k, v in pairs(tab) do - rettab[k] = func(v) - end - return rettab -end - -function module.filter(filter_func, tab) - local rettab = {} - for _, entry in pairs(tab) do - if filter_func(entry) then - table.insert(rettab, entry) - end - end - return rettab -end - function module.hasenv(name) local env = os.getenv(name) if env and env ~= '' then diff --git a/test/unit/eval/typval_spec.lua b/test/unit/eval/typval_spec.lua index 4535d6a0b2..1651eb9bcc 100644 --- a/test/unit/eval/typval_spec.lua +++ b/test/unit/eval/typval_spec.lua @@ -14,7 +14,7 @@ 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 map = helpers.tbl_map local a = eval_helpers.alloc_logging_helpers local int = eval_helpers.int diff --git a/test/unit/helpers.lua b/test/unit/helpers.lua index bacdc54416..a77a089763 100644 --- a/test/unit/helpers.lua +++ b/test/unit/helpers.lua @@ -13,7 +13,7 @@ local syscall = nil local check_cores = global_helpers.check_cores local dedent = global_helpers.dedent local neq = global_helpers.neq -local map = global_helpers.map +local map = global_helpers.tbl_map local eq = global_helpers.eq local trim = global_helpers.trim -- cgit From a380526c0fb9db18fd2c6743bf851e1df617c3d3 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 19 Feb 2020 13:08:12 +0100 Subject: test: always use "set more" with :digraph test otherwise we risk the same issue as with ex_cmds/digraphs_spec.lua --- test/functional/ui/messages_spec.lua | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'test') diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index 0b822bc2f2..efc02db159 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -969,6 +969,7 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim -- edge case: only one window was set NOT_VALID. Orginal report -- used :make, but fake it using one command to set the current -- window NOT_VALID and another to show a long message. + command("set more") feed(':new') screen:expect{grid=[[ | @@ -982,16 +983,16 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim feed(':set colorcolumn=10 | digraphs') screen:expect{grid=[[ - er {5:ㄦ} 12582 i4 {5:ㄧ} 12583 u4 {5:ㄨ} 12584 iu {5:ㄩ} 12585 | - v4 {5:ㄪ} 12586 nG {5:ㄫ} 12587 gn {5:ㄬ} 12588 1c {5:㈠} 12832 | - 2c {5:㈡} 12833 3c {5:㈢} 12834 4c {5:㈣} 12835 5c {5:㈤} 12836 | - 6c {5:㈥} 12837 7c {5:㈦} 12838 8c {5:㈧} 12839 9c {5:㈨} 12840 | - ff {5:ff} 64256 fi {5:fi} 64257 fl {5:fl} 64258 ft {5:ſt} 64261 | - st {5:st} 64262 | - {4:Press ENTER or type command to continue}^ | + :set colorcolumn=10 | digraphs | + NU {5:^@} 10 SH {5:^A} 1 SX {5:^B} 2 EX {5:^C} 3 | + ET {5:^D} 4 EQ {5:^E} 5 AK {5:^F} 6 BL {5:^G} 7 | + BS {5:^H} 8 HT {5:^I} 9 LF {5:^@} 10 VT {5:^K} 11 | + FF {5:^L} 12 CR {5:^M} 13 SO {5:^N} 14 SI {5:^O} 15 | + DL {5:^P} 16 D1 {5:^Q} 17 D2 {5:^R} 18 D3 {5:^S} 19 | + {4:-- More --}^ | ]]} - feed('') + feed('q') screen:expect{grid=[[ | {1:~ }| -- cgit From 9c00fea585ccab56a6044a174ce8d9a2c605c6cd Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Mon, 4 Nov 2019 20:40:30 +0100 Subject: lua: add regex support, and `@match` support in treesitter queries --- test/functional/lua/treesitter_spec.lua | 19 ++++++++++++------- test/functional/lua/vim_spec.lua | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) (limited to 'test') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index 494d6c84bb..f93185d1f6 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -245,6 +245,11 @@ static int nlua_schedule(lua_State *const lstate) (primitive_type) @type (sized_type_specifier) @type +; defaults to very magic syntax, for best compatibility +((identifier) @Identifier (match? @Identifier "^l(u)a_")) +; still support \M etc prefixes +((identifier) @Constant (match? @Constant "\M^\[A-Z_]\+$")) + ((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right) (eq? @WarningMsg.left @WarningMsg.right)) (comment) @comment @@ -263,7 +268,7 @@ static int nlua_schedule(lua_State *const lstate) [8] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, [9] = {foreground = Screen.colors.Magenta, background = Screen.colors.Red}, [10] = {foreground = Screen.colors.Red, background = Screen.colors.Red}, - + [11] = {foreground = Screen.colors.Cyan4}, }) insert(hl_text) @@ -297,10 +302,10 @@ static int nlua_schedule(lua_State *const lstate) {2:/// Schedule Lua callback on main loop's event queue} | {3:static} {3:int} nlua_schedule(lua_State *{3:const} lstate) | { | - {4:if} (lua_type(lstate, {5:1}) != LUA_TFUNCTION | + {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | || {6:lstate} != {6:lstate}) { | - lua_pushliteral(lstate, {5:"vim.schedule: expected function"}); | - {4:return} lua_error(lstate); | + {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); | + {4:return} {11:lua_error}(lstate); | } | | {7:LuaRef} cb = nlua_ref(lstate, {5:1}); | @@ -319,10 +324,10 @@ static int nlua_schedule(lua_State *const lstate) {2:/// Schedule Lua callback on main loop's event queue} | {3:static} {3:int} nlua_schedule(lua_State *{3:const} lstate) | { | - {4:if} (lua_type(lstate, {5:1}) != LUA_TFUNCTION | + {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | || {6:lstate} != {6:lstate}) { | - lua_pushliteral(lstate, {5:"vim.schedule: expected function"}); | - {4:return} lua_error(lstate); | + {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); | + {4:return} {11:lua_error}(lstate); | {8:*^/} | } | | diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 2f459145f5..532368c37c 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -844,4 +844,22 @@ describe('lua stdlib', function() eq('2', funcs.luaeval "BUF") eq(2, funcs.luaeval "#vim.api.nvim_list_bufs()") end) + + it('vim.regex', function() + exec_lua [[ + re1 = vim.regex"ab\\+c" + vim.cmd "set nomagic ignorecase" + re2 = vim.regex"xYz" + ]] + eq({}, exec_lua[[return {re1:match_str("x ac")}]]) + eq({3,7}, exec_lua[[return {re1:match_str("ac abbc")}]]) + + meths.buf_set_lines(0, 0, -1, true, {"yy", "abc abbc"}) + eq({}, exec_lua[[return {re1:match_line(0, 0)}]]) + eq({0,3}, exec_lua[[return {re1:match_line(0, 1)}]]) + eq({3,7}, exec_lua[[return {re1:match_line(0, 1, 1)}]]) + eq({3,7}, exec_lua[[return {re1:match_line(0, 1, 1, 8)}]]) + eq({}, exec_lua[[return {re1:match_line(0, 1, 1, 7)}]]) + eq({0,3}, exec_lua[[return {re1:match_line(0, 1, 0, 7)}]]) + end) end) -- cgit From 1a2be57da3f7e33af4e4eb3e0d36569feea71253 Mon Sep 17 00:00:00 2001 From: Matthieu Coudron Date: Tue, 14 Jan 2020 19:50:30 +0100 Subject: foldcolumn: allow auto:X Similar to signcolumn, allow foldcolumn to adapt itself to the number of folds. Regression: vim supports a maximum fdc of 12, this limits it to 9. --- test/functional/options/num_options_spec.lua | 2 +- test/functional/ui/fold_spec.lua | 60 ++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/options/num_options_spec.lua b/test/functional/options/num_options_spec.lua index deda5c9118..abb90b3b7c 100644 --- a/test/functional/options/num_options_spec.lua +++ b/test/functional/options/num_options_spec.lua @@ -72,7 +72,7 @@ describe(':set validation', function() should_fail('updatetime', -1, 'E487') should_fail('foldlevel', -5, 'E487') - should_fail('foldcolumn', 13, 'E474') + should_fail('foldcolumn', '13', 'E474') should_fail('conceallevel', 4, 'E474') should_fail('numberwidth', 21, 'E474') should_fail('numberwidth', 0, 'E487') diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua index f178ed1ac7..6ec45064da 100644 --- a/test/functional/ui/fold_spec.lua +++ b/test/functional/ui/fold_spec.lua @@ -295,4 +295,64 @@ describe("folded lines", function() ]]) end) + + it("work with autoresize", function() + + funcs.setline(1, 'line 1') + funcs.setline(2, 'line 2') + funcs.setline(3, 'line 3') + funcs.setline(4, 'line 4') + + feed("zfj") + command("set foldcolumn=0") + screen:expect{grid=[[ + {5:^+-- 2 lines: line 1·························}| + line 3 | + line 4 | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + -- should adapt to the current nesting of folds (e.g., 1) + command("set foldcolumn=auto:1") + screen:expect{grid=[[ + {7:+}{5:^+-- 2 lines: line 1························}| + {7: }line 3 | + {7: }line 4 | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + -- fdc should not change with a new fold as the maximum is 1 + feed("zf3j") + + screen:expect{grid=[[ + {7:+}{5:^+-- 4 lines: line 1························}| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + -- relax the maximum fdc thus fdc should expand to + -- accomodate the current number of folds + command("set foldcolumn=auto:4") + screen:expect{grid=[[ + {7:+ }{5:^+-- 4 lines: line 1·······················}| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + end) end) -- cgit From 3c12ee333a519c5be1d8f63d7978b483a51a3da7 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 2 Feb 2020 15:55:15 -0500 Subject: vim-patch:8.1.0619: :echomsg and :echoerr do not handle List and Dict Problem: :echomsg and :echoerr do not handle List and Dict like :echo does. (Daniel Hahler) Solution: Be more tolerant about the expression result type. https://github.com/vim/vim/commit/461a7fcfce3cd6414f990037e6468af3b5ccf119 Add lua functional tests for :echo,:echon,:echomsg,:echoerr because nvim did not port "test_" functions from Vim that modify internal state. Testing :echoerr via try/catch is sufficient. --- test/functional/ex_cmds/echo_spec.lua | 167 ++++++++++++++++++++++++---------- 1 file changed, 119 insertions(+), 48 deletions(-) (limited to 'test') diff --git a/test/functional/ex_cmds/echo_spec.lua b/test/functional/ex_cmds/echo_spec.lua index 10c7230896..408ce52b8c 100644 --- a/test/functional/ex_cmds/echo_spec.lua +++ b/test/functional/ex_cmds/echo_spec.lua @@ -11,31 +11,57 @@ local dedent = helpers.dedent local command = helpers.command local exc_exec = helpers.exc_exec local redir_exec = helpers.redir_exec +local matches = helpers.matches + +describe(':echo :echon :echomsg :echoerr', function() + local fn_tbl = {'String', 'StringN', 'StringMsg', 'StringErr'} + local function assert_same_echo_dump(expected, input, use_eval) + for _,v in pairs(fn_tbl) do + eq(expected, use_eval and eval(v..'('..input..')') or funcs[v](input)) + end + end + local function assert_matches_echo_dump(expected, input, use_eval) + for _,v in pairs(fn_tbl) do + matches(expected, use_eval and eval(v..'('..input..')') or funcs[v](input)) + end + end -describe(':echo', function() before_each(function() clear() source([[ function String(s) return execute('echo a:s')[1:] endfunction + function StringMsg(s) + return execute('echomsg a:s')[1:] + endfunction + function StringN(s) + return execute('echon a:s') + endfunction + function StringErr(s) + try + execute 'echoerr a:s' + catch + return substitute(v:exception, '^Vim(echoerr):', '', '') + endtry + endfunction ]]) end) describe('used to represent floating-point values', function() it('dumps NaN values', function() - eq('str2float(\'nan\')', eval('String(str2float(\'nan\'))')) + assert_same_echo_dump("str2float('nan')", "str2float('nan')", true) end) it('dumps infinite values', function() - eq('str2float(\'inf\')', eval('String(str2float(\'inf\'))')) - eq('-str2float(\'inf\')', eval('String(str2float(\'-inf\'))')) + assert_same_echo_dump("str2float('inf')", "str2float('inf')", true) + assert_same_echo_dump("-str2float('inf')", "str2float('-inf')", true) end) it('dumps regular values', function() - eq('1.5', funcs.String(1.5)) - eq('1.56e-20', funcs.String(1.56000e-020)) - eq('0.0', eval('String(0.0)')) + assert_same_echo_dump('1.5', 1.5) + assert_same_echo_dump('1.56e-20', 1.56000e-020) + assert_same_echo_dump('0.0', '0.0', true) end) it('dumps special v: values', function() @@ -45,69 +71,81 @@ describe(':echo', function() eq('v:true', funcs.String(true)) eq('v:false', funcs.String(false)) eq('v:null', funcs.String(NIL)) + eq('true', eval('StringMsg(v:true)')) + eq('false', eval('StringMsg(v:false)')) + eq('null', eval('StringMsg(v:null)')) + eq('true', funcs.StringMsg(true)) + eq('false', funcs.StringMsg(false)) + eq('null', funcs.StringMsg(NIL)) + eq('true', eval('StringErr(v:true)')) + eq('false', eval('StringErr(v:false)')) + eq('null', eval('StringErr(v:null)')) + eq('true', funcs.StringErr(true)) + eq('false', funcs.StringErr(false)) + eq('null', funcs.StringErr(NIL)) end) it('dumps values with at most six digits after the decimal point', function() - eq('1.234568e-20', funcs.String(1.23456789123456789123456789e-020)) - eq('1.234568', funcs.String(1.23456789123456789123456789)) + assert_same_echo_dump('1.234568e-20', 1.23456789123456789123456789e-020) + assert_same_echo_dump('1.234568', 1.23456789123456789123456789) end) it('dumps values with at most seven digits before the decimal point', function() - eq('1234567.891235', funcs.String(1234567.89123456789123456789)) - eq('1.234568e7', funcs.String(12345678.9123456789123456789)) + assert_same_echo_dump('1234567.891235', 1234567.89123456789123456789) + assert_same_echo_dump('1.234568e7', 12345678.9123456789123456789) end) it('dumps negative values', function() - eq('-1.5', funcs.String(-1.5)) - eq('-1.56e-20', funcs.String(-1.56000e-020)) - eq('-1.234568e-20', funcs.String(-1.23456789123456789123456789e-020)) - eq('-1.234568', funcs.String(-1.23456789123456789123456789)) - eq('-1234567.891235', funcs.String(-1234567.89123456789123456789)) - eq('-1.234568e7', funcs.String(-12345678.9123456789123456789)) + assert_same_echo_dump('-1.5', -1.5) + assert_same_echo_dump('-1.56e-20', -1.56000e-020) + assert_same_echo_dump('-1.234568e-20', -1.23456789123456789123456789e-020) + assert_same_echo_dump('-1.234568', -1.23456789123456789123456789) + assert_same_echo_dump('-1234567.891235', -1234567.89123456789123456789) + assert_same_echo_dump('-1.234568e7', -12345678.9123456789123456789) end) end) describe('used to represent numbers', function() it('dumps regular values', function() - eq('0', funcs.String(0)) - eq('-1', funcs.String(-1)) - eq('1', funcs.String(1)) + assert_same_echo_dump('0', 0) + assert_same_echo_dump('-1', -1) + assert_same_echo_dump('1', 1) end) it('dumps large values', function() - eq('2147483647', funcs.String(2^31-1)) - eq('-2147483648', funcs.String(-2^31)) + assert_same_echo_dump('2147483647', 2^31-1) + assert_same_echo_dump('-2147483648', -2^31) end) end) describe('used to represent strings', function() it('dumps regular strings', function() - eq('test', funcs.String('test')) + assert_same_echo_dump('test', 'test') end) it('dumps empty strings', function() - eq('', funcs.String('')) + assert_same_echo_dump('', '') end) - it('dumps strings with \' inside', function() - eq('\'\'\'', funcs.String('\'\'\'')) - eq('a\'b\'\'', funcs.String('a\'b\'\'')) - eq('\'b\'\'d', funcs.String('\'b\'\'d')) - eq('a\'b\'c\'d', funcs.String('a\'b\'c\'d')) + it("dumps strings with ' inside", function() + assert_same_echo_dump("'''", "'''") + assert_same_echo_dump("a'b''", "a'b''") + assert_same_echo_dump("'b''d", "'b''d") + assert_same_echo_dump("a'b'c'd", "a'b'c'd") end) it('dumps NULL strings', function() - eq('', eval('String($XXX_UNEXISTENT_VAR_XXX)')) + assert_same_echo_dump('', '$XXX_UNEXISTENT_VAR_XXX', true) end) it('dumps NULL lists', function() - eq('[]', eval('String(v:_null_list)')) + assert_same_echo_dump('[]', 'v:_null_list', true) end) it('dumps NULL dictionaries', function() - eq('{}', eval('String(v:_null_dict)')) + assert_same_echo_dump('{}', 'v:_null_dict', true) end) end) @@ -129,15 +167,27 @@ describe(':echo', function() it('dumps references to built-in functions', function() eq('function', eval('String(function("function"))')) + eq("function('function')", eval('StringMsg(function("function"))')) + eq("function('function')", eval('StringErr(function("function"))')) end) it('dumps references to user functions', function() eq('Test1', eval('String(function("Test1"))')) eq('g:Test3', eval('String(function("g:Test3"))')) + eq("function('Test1')", eval("StringMsg(function('Test1'))")) + eq("function('g:Test3')", eval("StringMsg(function('g:Test3'))")) + eq("function('Test1')", eval("StringErr(function('Test1'))")) + eq("function('g:Test3')", eval("StringErr(function('g:Test3'))")) end) it('dumps references to script functions', function() eq('2_Test2', eval('String(Test2_f)')) + eq("function('2_Test2')", eval('StringMsg(Test2_f)')) + eq("function('2_Test2')", eval('StringErr(Test2_f)')) + end) + + it('dump references to lambdas', function() + assert_matches_echo_dump("function%('%d+'%)", '{-> 1234}', true) end) it('dumps partials with self referencing a partial', function() @@ -156,19 +206,23 @@ describe(':echo', function() end) it('dumps automatically created partials', function() - eq('function(\'2_Test2\', {\'f\': function(\'2_Test2\')})', - eval('String({"f": Test2_f}.f)')) - eq('function(\'2_Test2\', [1], {\'f\': function(\'2_Test2\', [1])})', - eval('String({"f": function(Test2_f, [1])}.f)')) + assert_same_echo_dump( + "function('2_Test2', {'f': function('2_Test2')})", + '{"f": Test2_f}.f', + true) + assert_same_echo_dump( + "function('2_Test2', [1], {'f': function('2_Test2', [1])})", + '{"f": function(Test2_f, [1])}.f', + true) end) it('dumps manually created partials', function() - eq('function(\'Test3\', [1, 2], {})', - eval('String(function("Test3", [1, 2], {}))')) - eq('function(\'Test3\', {})', - eval('String(function("Test3", {}))')) - eq('function(\'Test3\', [1, 2])', - eval('String(function("Test3", [1, 2]))')) + assert_same_echo_dump("function('Test3', [1, 2], {})", + "function('Test3', [1, 2], {})", true) + assert_same_echo_dump("function('Test3', [1, 2])", + "function('Test3', [1, 2])", true) + assert_same_echo_dump("function('Test3', {})", + "function('Test3', {})", true) end) it('does not crash or halt when dumping partials with reference cycles in self', @@ -225,15 +279,19 @@ describe(':echo', function() describe('used to represent lists', function() it('dumps empty list', function() - eq('[]', funcs.String({})) + assert_same_echo_dump('[]', {}) + end) + + it('dumps non-empty list', function() + assert_same_echo_dump('[1, 2]', {1,2}) end) it('dumps nested lists', function() - eq('[[[[[]]]]]', funcs.String({{{{{}}}}})) + assert_same_echo_dump('[[[[[]]]]]', {{{{{}}}}}) end) it('dumps nested non-empty lists', function() - eq('[1, [[3, [[5], 4]], 2]]', funcs.String({1, {{3, {{5}, 4}}, 2}})) + assert_same_echo_dump('[1, [[3, [[5], 4]], 2]]', {1, {{3, {{5}, 4}}, 2}}) end) it('does not error when dumping recursive lists', function() @@ -252,18 +310,18 @@ describe(':echo', function() describe('used to represent dictionaries', function() it('dumps empty dictionary', function() - eq('{}', eval('String({})')) + assert_same_echo_dump('{}', '{}', true) end) it('dumps list with two same empty dictionaries, also in partials', function() command('let d = {}') - eq('[{}, {}]', eval('String([d, d])')) + assert_same_echo_dump('[{}, {}]', '[d, d]', true) eq('[function(\'tr\', {}), {}]', eval('String([function("tr", d), d])')) eq('[{}, function(\'tr\', {})]', eval('String([d, function("tr", d)])')) end) it('dumps non-empty dictionary', function() - eq('{\'t\'\'est\': 1}', funcs.String({['t\'est']=1})) + assert_same_echo_dump("{'t''est': 1}", {["t'est"]=1}) end) it('does not error when dumping recursive dictionaries', function() @@ -297,11 +355,20 @@ describe(':echo', function() eq('<8e>', funcs.String(chr(0x8e))) eq('', funcs.String(('«'):sub(1, 1))) eq('«', funcs.String(('«'):sub(1, 2))) + + eq('<80>', funcs.StringMsg(chr(0x80))) + eq('<81>', funcs.StringMsg(chr(0x81))) + eq('<8e>', funcs.StringMsg(chr(0x8e))) + eq('', funcs.StringMsg(('«'):sub(1, 1))) + eq('«', funcs.StringMsg(('«'):sub(1, 2))) end) it('displays ASCII control characters using ^X notation', function() eq('^C', funcs.String(ctrl('c'))) eq('^A', funcs.String(ctrl('a'))) eq('^F', funcs.String(ctrl('f'))) + eq('^C', funcs.StringMsg(ctrl('c'))) + eq('^A', funcs.StringMsg(ctrl('a'))) + eq('^F', funcs.StringMsg(ctrl('f'))) end) it('prints CR, NL and tab as-is', function() eq('\n', funcs.String('\n')) @@ -311,11 +378,15 @@ describe(':echo', function() it('prints non-printable UTF-8 in <> notation', function() -- SINGLE SHIFT TWO, unicode control eq('<8e>', funcs.String(funcs.nr2char(0x8E))) + eq('<8e>', funcs.StringMsg(funcs.nr2char(0x8E))) -- Surrogate pair: U+1F0A0 PLAYING CARD BACK is represented in UTF-16 as -- 0xD83C 0xDCA0. This is not valid in UTF-8. eq('', funcs.String(funcs.nr2char(0xD83C))) eq('', funcs.String(funcs.nr2char(0xDCA0))) eq('', funcs.String(funcs.nr2char(0xD83C) .. funcs.nr2char(0xDCA0))) + eq('', funcs.StringMsg(funcs.nr2char(0xD83C))) + eq('', funcs.StringMsg(funcs.nr2char(0xDCA0))) + eq('', funcs.StringMsg(funcs.nr2char(0xD83C) .. funcs.nr2char(0xDCA0))) end) end) end) -- cgit From 16262472cda88d0a4dc5c6729cfef36264569324 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Sat, 22 Feb 2020 21:20:38 +0900 Subject: lsp: add 'textDocument/documentSymbol’ callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Spec: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol --- test/functional/plugin/lsp_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index ba1eb2113e..369b826adf 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -241,7 +241,7 @@ describe('LSP', function() it('should succeed with manual shutdown', function() local expected_callbacks = { - {NIL, "shutdown", {}, 1}; + {NIL, "shutdown", {}, 1, NIL}; {NIL, "test", {}, 1}; } test_rpc_server { -- cgit From eba8a9ca1d94f43b7fe2e92d5a2caa144dd68d0d Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Fri, 21 Feb 2020 22:05:59 -0500 Subject: vim-patch:8.1.1510: a plugin cannot easily expand a command like done internally Problem: A plugin cannot easily expand a command like done internally. Solution: Add the expandcmd() function. (Yegappan Lakshmanan, closes vim/vim#4514) https://github.com/vim/vim/commit/80dad48c5095d30873a42ec82628bdb213125d8e --- test/functional/legacy/expand_spec.lua | 39 ++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'test') diff --git a/test/functional/legacy/expand_spec.lua b/test/functional/legacy/expand_spec.lua index 1b735080f4..f238128b31 100644 --- a/test/functional/legacy/expand_spec.lua +++ b/test/functional/legacy/expand_spec.lua @@ -70,6 +70,40 @@ describe('expand file name', function() call assert_match('\~', expand('%:p')) bwipe! endfunc + + func Test_expandcmd() + let $FOO = 'Test' + call assert_equal('e x/Test/y', expandcmd('e x/$FOO/y')) + unlet $FOO + + new + edit Xfile1 + call assert_equal('e Xfile1', expandcmd('e %')) + edit Xfile2 + edit Xfile1 + call assert_equal('e Xfile2', expandcmd('e #')) + edit Xfile2 + edit Xfile3 + edit Xfile4 + let bnum = bufnr('Xfile2') + call assert_equal('e Xfile2', expandcmd('e #' . bnum)) + call setline('.', 'Vim!@#') + call assert_equal('e Vim', expandcmd('e ')) + call assert_equal('e Vim!@#', expandcmd('e ')) + enew! + edit Xfile.java + call assert_equal('e Xfile.py', expandcmd('e %:r.py')) + call assert_equal('make abc.java', expandcmd('make abc.%:e')) + call assert_equal('make Xabc.java', expandcmd('make %:s?file?abc?')) + edit a1a2a3.rb + call assert_equal('make b1b2b3.rb a1a2a3 Xfile.o', expandcmd('make %:gs?a?b? %< #<.o')) + + call assert_fails('call expandcmd("make ")', 'E495:') + call assert_fails('call expandcmd("make ")', 'E495:') + enew + call assert_fails('call expandcmd("make %")', 'E499:') + close + endfunc ]]) end) @@ -87,4 +121,9 @@ describe('expand file name', function() call('Test_expand_tilde_filename') expected_empty() end) + + it('works with expandcmd()', function() + call('Test_expandcmd') + expected_empty() + end) end) -- cgit From e35ff7371f4a61621587744a7620200380abbbe9 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Mon, 2 Mar 2020 16:38:43 +0900 Subject: lua: add vim.tbl_len() #11889 --- test/functional/lua/vim_spec.lua | 63 +++++++++++++++------------------------- 1 file changed, 23 insertions(+), 40 deletions(-) (limited to 'test') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 532368c37c..5ce4bf2973 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -315,10 +315,7 @@ describe('lua stdlib', function() local a = { x = { 1, 2 }, y = 5} local b = vim.deepcopy(a) - local count = 0 - for _ in pairs(b) do count = count + 1 end - - return b.x[1] == 1 and b.x[2] == 2 and b.y == 5 and count == 2 + return b.x[1] == 1 and b.x[2] == 2 and b.y == 5 and vim.tbl_count(b) == 2 and tostring(a) ~= tostring(b) ]])) @@ -326,31 +323,22 @@ describe('lua stdlib', function() local a = {} local b = vim.deepcopy(a) - local count = 0 - for _ in pairs(b) do count = count + 1 end - - return vim.tbl_islist(b) and count == 0 and tostring(a) ~= tostring(b) + return vim.tbl_islist(b) and vim.tbl_count(b) == 0 and tostring(a) ~= tostring(b) ]])) ok(exec_lua([[ local a = vim.empty_dict() local b = vim.deepcopy(a) - local count = 0 - for _ in pairs(b) do count = count + 1 end - - return not vim.tbl_islist(b) and count == 0 + return not vim.tbl_islist(b) and vim.tbl_count(b) == 0 ]])) ok(exec_lua([[ local a = {x = vim.empty_dict(), y = {}} local b = vim.deepcopy(a) - local count = 0 - for _ in pairs(b) do count = count + 1 end - return not vim.tbl_islist(b.x) and vim.tbl_islist(b.y) - and count == 2 + and vim.tbl_count(b) == 2 and tostring(a) ~= tostring(b) ]])) end) @@ -430,10 +418,7 @@ describe('lua stdlib', function() local b = {y = 2} local c = vim.tbl_extend("keep", a, b) - local count = 0 - for _ in pairs(c) do count = count + 1 end - - return c.x == 1 and b.y == 2 and count == 2 + return c.x == 1 and b.y == 2 and vim.tbl_count(c) == 2 ]])) ok(exec_lua([[ @@ -442,10 +427,7 @@ describe('lua stdlib', function() local c = {z = 3} local d = vim.tbl_extend("keep", a, b, c) - local count = 0 - for _ in pairs(d) do count = count + 1 end - - return d.x == 1 and d.y == 2 and d.z == 3 and count == 3 + return d.x == 1 and d.y == 2 and d.z == 3 and vim.tbl_count(d) == 3 ]])) ok(exec_lua([[ @@ -453,10 +435,7 @@ describe('lua stdlib', function() local b = {x = 3} local c = vim.tbl_extend("keep", a, b) - local count = 0 - for _ in pairs(c) do count = count + 1 end - - return c.x == 1 and count == 1 + return c.x == 1 and vim.tbl_count(c) == 1 ]])) ok(exec_lua([[ @@ -464,10 +443,7 @@ describe('lua stdlib', function() local b = {x = 3} local c = vim.tbl_extend("force", a, b) - local count = 0 - for _ in pairs(c) do count = count + 1 end - - return c.x == 3 and count == 1 + return c.x == 3 and vim.tbl_count(c) == 1 ]])) ok(exec_lua([[ @@ -475,10 +451,7 @@ describe('lua stdlib', function() local b = {} local c = vim.tbl_extend("keep", a, b) - local count = 0 - for _ in pairs(c) do count = count + 1 end - - return not vim.tbl_islist(c) and count == 0 + return not vim.tbl_islist(c) and vim.tbl_count(c) == 0 ]])) ok(exec_lua([[ @@ -486,10 +459,7 @@ describe('lua stdlib', function() local b = vim.empty_dict() local c = vim.tbl_extend("keep", a, b) - local count = 0 - for _ in pairs(c) do count = count + 1 end - - return vim.tbl_islist(c) and count == 0 + return vim.tbl_islist(c) and vim.tbl_count(c) == 0 ]])) eq('Error executing lua: .../shared.lua: invalid "behavior": nil', @@ -511,6 +481,19 @@ describe('lua stdlib', function() ) end) + it('vim.tbl_count', function() + eq(0, exec_lua [[ return vim.tbl_count({}) ]]) + eq(0, exec_lua [[ return vim.tbl_count(vim.empty_dict()) ]]) + eq(0, exec_lua [[ return vim.tbl_count({nil}) ]]) + eq(0, exec_lua [[ return vim.tbl_count({a=nil}) ]]) + eq(1, exec_lua [[ return vim.tbl_count({1}) ]]) + eq(2, exec_lua [[ return vim.tbl_count({1, 2}) ]]) + eq(2, exec_lua [[ return vim.tbl_count({1, nil, 3}) ]]) + eq(1, exec_lua [[ return vim.tbl_count({a=1}) ]]) + eq(2, exec_lua [[ return vim.tbl_count({a=1, b=2}) ]]) + eq(2, exec_lua [[ return vim.tbl_count({a=1, b=nil, c=3}) ]]) + end) + it('vim.deep_equal', function() eq(true, exec_lua [[ return vim.deep_equal({a=1}, {a=1}) ]]) eq(true, exec_lua [[ return vim.deep_equal({a={b=1}}, {a={b=1}}) ]]) -- cgit From 87d892afa0475644e91d9c8a57b7c35491c4dc32 Mon Sep 17 00:00:00 2001 From: Will Eccles Date: Tue, 17 Mar 2020 15:05:34 -0400 Subject: vim-patch:8.1.0864 Make 'scrolloff' and 'sidescrolloff' options window local (#11854) Problem: cannot have a local value for 'scrolloff' and 'sidescrolloff' Author: Bram Moolenar https://github.com/vim/vim/commit/375e3390078e740d3c83b0c118c50d9a920036c7 --- test/functional/options/num_options_spec.lua | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/functional/options/num_options_spec.lua b/test/functional/options/num_options_spec.lua index abb90b3b7c..4754c14f5b 100644 --- a/test/functional/options/num_options_spec.lua +++ b/test/functional/options/num_options_spec.lua @@ -65,8 +65,6 @@ describe(':set validation', function() should_succeed('regexpengine', 2) should_fail('report', -1, 'E487') should_succeed('report', 0) - should_fail('scrolloff', -1, 'E49') - should_fail('sidescrolloff', -1, 'E487') should_fail('sidescroll', -1, 'E487') should_fail('cmdwinheight', 0, 'E487') should_fail('updatetime', -1, 'E487') @@ -82,6 +80,22 @@ describe(':set validation', function() meths.set_option('window', -10) eq(23, meths.get_option('window')) eq('', eval("v:errmsg")) + + -- 'scrolloff' and 'sidescrolloff' can have a -1 value when + -- set for the current window, but not globally + feed_command('setglobal scrolloff=-1') + eq('E487', eval("v:errmsg"):match("E%d*")) + + feed_command('setglobal sidescrolloff=-1') + eq('E487', eval("v:errmsg"):match("E%d*")) + + feed_command('let v:errmsg=""') + + feed_command('setlocal scrolloff=-1') + eq('', eval("v:errmsg")) + + feed_command('setlocal sidescrolloff=-1') + eq('', eval("v:errmsg")) end) it('set wmh/wh wmw/wiw checks', function() -- cgit From 9333f86ab7d0e85d9f658bfe455860771de9b997 Mon Sep 17 00:00:00 2001 From: erw7 Date: Fri, 20 Mar 2020 03:31:10 +0900 Subject: TUI: do not use "nvim_get_option" in tui thread Since "nvim_get_option" is executed on the tui thread as a C function instead of msgpack-rpc, it accesses global variables that may change on the main thread. --- test/functional/ui/options_spec.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'test') diff --git a/test/functional/ui/options_spec.lua b/test/functional/ui/options_spec.lua index 581e196bbb..9646c3fdad 100644 --- a/test/functional/ui/options_spec.lua +++ b/test/functional/ui/options_spec.lua @@ -20,6 +20,8 @@ describe('UI receives option updates', function() pumblend=0, showtabline=1, termguicolors=false, + ttimeout=true, + ttimeoutlen=50, ext_cmdline=false, ext_popupmenu=false, ext_tabline=false, @@ -108,6 +110,18 @@ describe('UI receives option updates', function() eq(expected, screen.options) end) + command("set nottimeout") + expected.ttimeout = false + screen:expect(function() + eq(expected, screen.options) + end) + + command("set ttimeoutlen=100") + expected.ttimeoutlen = 100 + screen:expect(function() + eq(expected, screen.options) + end) + command("set all&") screen:expect(function() eq(defaults, screen.options) -- cgit From 4dabbc19d43f5832b2941bcac832f93e25534264 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Mon, 23 Mar 2020 18:53:40 +0100 Subject: popupmenu: don't use 'rightleft' option in cmdline mode Cmdline is always drawn from the left to right, so using rightleft popupmenu is not useful here --- test/functional/ui/popupmenu_spec.lua | 51 ++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index b2ebf7af19..11c3f4123e 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -1338,7 +1338,7 @@ describe('builtin popupmenu', function() end) it('with rightleft window', function() - command("set rl") + command("set rl wildoptions+=pum") feed('isome rightleft ') screen:expect([[ ^ tfelthgir emos| @@ -1435,6 +1435,55 @@ describe('builtin popupmenu', function() {1: ~}| {2:-- INSERT --} | ]]) + + -- not rightleft on the cmdline + feed(':sign ') + screen:expect{grid=[[ + drow tfelthgir emos| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + :sign ^ | + ]]} + + feed('') + screen:expect{grid=[[ + drow tfelthgir emos| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {1: ~}| + {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^ | + ]]} end) it('with multiline messages', function() -- cgit From 4139678f97ee556ab142031a1ed5c7580278b64f Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Mon, 30 Mar 2020 21:30:24 +0900 Subject: vim.uri: fix uri_to_fname (#12059) fix: #12056 If the colon of the drive letter of windows is URI encoded, it doesn't match the expected pattern, so decode it first. --- test/functional/lua/uri_spec.lua | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'test') diff --git a/test/functional/lua/uri_spec.lua b/test/functional/lua/uri_spec.lua index 19b1eb1f61..128c7c6137 100644 --- a/test/functional/lua/uri_spec.lua +++ b/test/functional/lua/uri_spec.lua @@ -85,6 +85,15 @@ describe('URI methods', function() eq('C:\\Foo\\Bar\\Baz.txt', exec_lua(test_case)) end) + it('file path includes only ascii charactors with encoded colon character', function() + local test_case = [[ + local uri = 'file:///C%3A/Foo/Bar/Baz.txt' + return vim.uri_to_fname(uri) + ]] + + eq('C:\\Foo\\Bar\\Baz.txt', exec_lua(test_case)) + end) + it('file path including white space', function() local test_case = [[ local uri = 'file:///C:/Foo%20/Bar/Baz.txt' -- cgit From 1fe0b329fe1d40e5837a43f53da0e0fff38477bc Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Thu, 23 Jan 2020 18:05:04 +0100 Subject: api/ui: win_viewport event for visible range and cursor position in window --- test/functional/ui/float_spec.lua | 22 ++++ test/functional/ui/multigrid_spec.lua | 187 ++++++++++++++++++++++++++++++++++ test/functional/ui/screen.lua | 67 ++++++++---- 3 files changed, 259 insertions(+), 17 deletions(-) (limited to 'test') diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 7a5569c14b..639e311ae6 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -976,6 +976,28 @@ describe('floatwin', function() {2:~ }| ]], float_pos={ [5] = {{id = 1002}, "NE", 4, 0, 50, true} + }, win_viewport = { + [2] = { + topline = 0, + botline = 3, + curline = 0, + curcol = 3, + win = { id = 1000 } + }, + [4] = { + topline = 0, + botline = 3, + curline = 0, + curcol = 3, + win = { id = 1001 } + }, + [5] = { + topline = 0, + botline = 2, + curline = 0, + curcol = 0, + win = { id = 1002 } + } }} else screen:expect([[ diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua index 01ffe80be3..e4d1187dea 100644 --- a/test/functional/ui/multigrid_spec.lua +++ b/test/functional/ui/multigrid_spec.lua @@ -1962,4 +1962,191 @@ describe('ext_multigrid', function() {1:~ }| ]]} end) + + it('has viewport information', function() + screen:try_resize(48, 8) + screen:expect{grid=[[ + ## grid 1 + [2:------------------------------------------------]| + [2:------------------------------------------------]| + [2:------------------------------------------------]| + [2:------------------------------------------------]| + [2:------------------------------------------------]| + [2:------------------------------------------------]| + {11:[No Name] }| + [3:------------------------------------------------]| + ## grid 2 + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ]], win_viewport={ + [2] = {win = { id = 1000 }, topline = 0, botline = 2, curline = 0, curcol = 0} + }} + insert([[ + Lorem ipsum dolor sit amet, consectetur + adipisicing elit, sed do eiusmod tempor + incididunt ut labore et dolore magna aliqua. + Ut enim ad minim veniam, quis nostrud + exercitation ullamco laboris nisi ut aliquip ex + ea commodo consequat. Duis aute irure dolor in + reprehenderit in voluptate velit esse cillum + dolore eu fugiat nulla pariatur. Excepteur sint + occaecat cupidatat non proident, sunt in culpa + qui officia deserunt mollit anim id est + laborum.]]) + + screen:expect{grid=[[ + ## grid 1 + [2:------------------------------------------------]| + [2:------------------------------------------------]| + [2:------------------------------------------------]| + [2:------------------------------------------------]| + [2:------------------------------------------------]| + [2:------------------------------------------------]| + {11:[No Name] [+] }| + [3:------------------------------------------------]| + ## grid 2 + ea commodo consequat. Duis aute irure dolor in | + reprehenderit in voluptate velit esse cillum | + dolore eu fugiat nulla pariatur. Excepteur sint | + occaecat cupidatat non proident, sunt in culpa | + qui officia deserunt mollit anim id est | + laborum^. | + ## grid 3 + | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 5, botline = 11, curline = 10, curcol = 7}, + }} + + + feed('') + screen:expect{grid=[[ + ## grid 1 + [2:------------------------------------------------]| + [2:------------------------------------------------]| + [2:------------------------------------------------]| + [2:------------------------------------------------]| + [2:------------------------------------------------]| + [2:------------------------------------------------]| + {11:[No Name] [+] }| + [3:------------------------------------------------]| + ## grid 2 + incididunt ut labore et dolore magna aliqua. | + Ut enim ad minim veniam, quis nostrud | + exercitation ullamco laboris nisi ut aliquip ex | + ea commodo consequat. Duis aute irure dolor in | + reprehenderit in voluptate velit esse cillum | + ^dolore eu fugiat nulla pariatur. Excepteur sint | + ## grid 3 + | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 2, botline = 9, curline = 7, curcol = 0}, + }} + + command("split") + screen:expect{grid=[[ + ## grid 1 + [4:------------------------------------------------]| + [4:------------------------------------------------]| + [4:------------------------------------------------]| + {11:[No Name] [+] }| + [2:------------------------------------------------]| + [2:------------------------------------------------]| + {12:[No Name] [+] }| + [3:------------------------------------------------]| + ## grid 2 + reprehenderit in voluptate velit esse cillum | + dolore eu fugiat nulla pariatur. Excepteur sint | + ## grid 3 + | + ## grid 4 + ea commodo consequat. Duis aute irure dolor in | + reprehenderit in voluptate velit esse cillum | + ^dolore eu fugiat nulla pariatur. Excepteur sint | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0}, + [4] = {win = {id = 1001}, topline = 5, botline = 9, curline = 7, curcol = 0}, + }} + + feed("b") + screen:expect{grid=[[ + ## grid 1 + [4:------------------------------------------------]| + [4:------------------------------------------------]| + [4:------------------------------------------------]| + {11:[No Name] [+] }| + [2:------------------------------------------------]| + [2:------------------------------------------------]| + {12:[No Name] [+] }| + [3:------------------------------------------------]| + ## grid 2 + reprehenderit in voluptate velit esse cillum | + dolore eu fugiat nulla pariatur. Excepteur sint | + ## grid 3 + | + ## grid 4 + ea commodo consequat. Duis aute irure dolor in | + reprehenderit in voluptate velit esse ^cillum | + dolore eu fugiat nulla pariatur. Excepteur sint | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0}, + [4] = {win = {id = 1001}, topline = 5, botline = 9, curline = 6, curcol = 38}, + }} + + feed("2k") + screen:expect{grid=[[ + ## grid 1 + [4:------------------------------------------------]| + [4:------------------------------------------------]| + [4:------------------------------------------------]| + {11:[No Name] [+] }| + [2:------------------------------------------------]| + [2:------------------------------------------------]| + {12:[No Name] [+] }| + [3:------------------------------------------------]| + ## grid 2 + reprehenderit in voluptate velit esse cillum | + dolore eu fugiat nulla pariatur. Excepteur sint | + ## grid 3 + | + ## grid 4 + exercitation ullamco laboris nisi ut a^liquip ex | + ea commodo consequat. Duis aute irure dolor in | + reprehenderit in voluptate velit esse cillum | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0}, + [4] = {win = {id = 1001}, topline = 4, botline = 8, curline = 4, curcol = 38}, + }} + + -- handles non-current window + meths.win_set_cursor(1000, {1, 10}) + screen:expect{grid=[[ + ## grid 1 + [4:------------------------------------------------]| + [4:------------------------------------------------]| + [4:------------------------------------------------]| + {11:[No Name] [+] }| + [2:------------------------------------------------]| + [2:------------------------------------------------]| + {12:[No Name] [+] }| + [3:------------------------------------------------]| + ## grid 2 + Lorem ipsum dolor sit amet, consectetur | + adipisicing elit, sed do eiusmod tempor | + ## grid 3 + | + ## grid 4 + exercitation ullamco laboris nisi ut a^liquip ex | + ea commodo consequat. Duis aute irure dolor in | + reprehenderit in voluptate velit esse cillum | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 10}, + [4] = {win = {id = 1001}, topline = 4, botline = 8, curline = 4, curcol = 38}, + }} + end) end) diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 64f784afe3..bf979e89f4 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -158,6 +158,7 @@ function Screen.new(width, height) wildmenu_items = nil, wildmenu_selected = nil, win_position = {}, + win_viewport = {}, float_pos = {}, msg_grid = nil, msg_grid_pos = nil, @@ -254,7 +255,7 @@ end -- canonical order of ext keys, used to generate asserts local ext_keys = { 'popupmenu', 'cmdline', 'cmdline_block', 'wildmenu_items', 'wildmenu_pos', - 'messages', 'showmode', 'showcmd', 'ruler', 'float_pos', + 'messages', 'showmode', 'showcmd', 'ruler', 'float_pos', 'win_viewport' } -- Asserts that the screen state eventually matches an expected state. @@ -421,6 +422,9 @@ screen:redraw_debug() to show all intermediate screen states. ]]) if expected.mode ~= nil then extstate.mode = self.mode end + if expected.win_viewport == nil then + extstate.win_viewport = nil + end -- Convert assertion errors into invalid screen state descriptions. for _, k in ipairs(concat_tables(ext_keys, {'mode'})) do @@ -726,6 +730,7 @@ function Screen:_handle_grid_destroy(grid) self._grids[grid] = nil if self._options.ext_multigrid then self.win_position[grid] = nil + self.win_viewport[grid] = nil end end @@ -746,14 +751,24 @@ function Screen:_handle_grid_cursor_goto(grid, row, col) end function Screen:_handle_win_pos(grid, win, startrow, startcol, width, height) - self.win_position[grid] = { - win = win, - startrow = startrow, - startcol = startcol, - width = width, - height = height - } - self.float_pos[grid] = nil + self.win_position[grid] = { + win = win, + startrow = startrow, + startcol = startcol, + width = width, + height = height + } + self.float_pos[grid] = nil +end + +function Screen:_handle_win_viewport(grid, win, topline, botline, curline, curcol) + self.win_viewport[grid] = { + win = win, + topline = topline, + botline = botline, + curline = curline, + curcol = curcol + } end function Screen:_handle_win_float_pos(grid, ...) @@ -1130,6 +1145,8 @@ function Screen:_extstate_repr(attr_state) messages[i] = {kind=entry[1], content=self:_chunks_repr(entry[2], attr_state)} end + local win_viewport = (next(self.win_viewport) and self.win_viewport) or nil + return { popupmenu=self.popupmenu, cmdline=cmdline, @@ -1141,7 +1158,8 @@ function Screen:_extstate_repr(attr_state) showcmd=self:_chunks_repr(self.showcmd, attr_state), ruler=self:_chunks_repr(self.ruler, attr_state), msg_history=msg_history, - float_pos=self.float_pos + float_pos=self.float_pos, + win_viewport=win_viewport, } end @@ -1216,10 +1234,6 @@ function Screen:render(headers, attr_state, preview) return rv end -local remove_all_metatables = function(item, path) - if path[#path] ~= inspect.METATABLE then return item end -end - -- Returns the current screen state in the form of a screen:expect() -- keyword-args map. function Screen:get_snapshot(attrs, ignore) @@ -1269,6 +1283,26 @@ function Screen:get_snapshot(attrs, ignore) return kwargs, ext_state, attr_state end +local function fmt_ext_state(name, state) + if name == "win_viewport" then + local str = "{\n" + for k,v in pairs(state) do + str = (str.." ["..k.."] = {win = {id = "..v.win.id.."}, topline = " + ..v.topline..", botline = "..v.botline..", curline = "..v.curline + ..", curcol = "..v.curcol.."},\n") + end + return str .. "}" + else + -- TODO(bfredl): improve formatting of more states + local function remove_all_metatables(item, path) + if path[#path] ~= inspect.METATABLE then + return item + end + end + return inspect(state,{process=remove_all_metatables}) + end +end + function Screen:print_snapshot(attrs, ignore) local kwargs, ext_state, attr_state = self:get_snapshot(attrs, ignore) local attrstr = "" @@ -1291,9 +1325,8 @@ function Screen:print_snapshot(attrs, ignore) print(kwargs.grid) io.stdout:write( "]]"..attrstr) for _, k in ipairs(ext_keys) do - if ext_state[k] ~= nil then - -- TODO(bfredl): improve formatting - io.stdout:write(", "..k.."="..inspect(ext_state[k],{process=remove_all_metatables})) + if ext_state[k] ~= nil and not (k == "win_viewport" and not self.options.ext_multigrid) then + io.stdout:write(", "..k.."="..fmt_ext_state(k, ext_state[k])) end end print("}\n") -- cgit From bf0f74586153dfa8d550e1cfefd83ca9e0354171 Mon Sep 17 00:00:00 2001 From: Tristan Konolige Date: Sat, 18 Apr 2020 17:04:37 -0600 Subject: lua: allow deepcopy of functions (#12136) --- test/functional/lua/vim_spec.lua | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'test') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 5ce4bf2973..ca74d185cd 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -341,6 +341,22 @@ describe('lua stdlib', function() and vim.tbl_count(b) == 2 and tostring(a) ~= tostring(b) ]])) + + ok(exec_lua([[ + local f1 = function() return 1 end + local f2 = function() return 2 end + local t1 = {f = f1} + local t2 = vim.deepcopy(t1) + t1.f = f2 + return t1.f() ~= t2.f() + ]])) + + eq('Error executing lua: .../shared.lua: Cannot deepcopy object of type thread', + pcall_err(exec_lua, [[ + local thread = coroutine.create(function () return 0 end) + local t = {thr = thread} + vim.deepcopy(t) + ]])) end) it('vim.pesc', function() -- cgit From 9d59f066cbbe8893559586eee5bfca9378cf6385 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sun, 22 Mar 2020 21:23:33 +0000 Subject: vim-patch:8.0.1651: cannot filter :ls output for terminal buffers Problem: Cannot filter :ls output for terminal buffers. Solution: Add flags for terminal buffers. (Marcin Szamotulski, closes vim/vim#2751) https://github.com/vim/vim/commit/0751f51a5b428805a8c1e9fe529693d032bec991 --- test/functional/ex_cmds/ls_spec.lua | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'test') diff --git a/test/functional/ex_cmds/ls_spec.lua b/test/functional/ex_cmds/ls_spec.lua index f7bacd7386..9853084c47 100644 --- a/test/functional/ex_cmds/ls_spec.lua +++ b/test/functional/ex_cmds/ls_spec.lua @@ -31,6 +31,18 @@ describe(':ls', function() -- Terminal buffer [F]inished. eq('\n 3 %aF', string.match(ls_output, '\n *3....')) end) + + retry(nil, 5000, function() + local ls_output = eval('execute("ls R")') + -- Just the [R]unning terminal buffer. + eq('\n 2 #aR ', string.match(ls_output, '^\n *2 ... ')) + end) + + retry(nil, 5000, function() + local ls_output = eval('execute("ls F")') + -- Just the [F]inished terminal buffer. + eq('\n 3 %aF ', string.match(ls_output, '^\n *3 ... ')) + end) end) end) -- cgit From a0d2bfeeb5c5b344bbddf496c3259e26f0974203 Mon Sep 17 00:00:00 2001 From: Andrey Avramenko Date: Mon, 20 Apr 2020 18:35:54 +0300 Subject: test: add get_completion_word test for text_doc... ...ument_completion_list_to_complete_items --- test/functional/plugin/lsp_spec.lua | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 369b826adf..7e9abaac2b 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -813,3 +813,35 @@ describe('LSP', function() end) end) end) + +describe('LSP', function() + describe('completion_list_to_complete_items', function() + it('should choose right completion option ', function () + local prefix = 'foo' + local completion_list = { + -- resolves into label + { label='foobar' }, + { label='foobar', textEdit={} }, + -- resolves into insertText + { label='foocar', insertText='foobar' }, + { label='foocar', insertText='foobar', textEdit={} }, + -- resolves into textEdit.newText + { label='foocar', insertText='foodar', textEdit={newText='foobar'} }, + { label='foocar', textEdit={newText='foobar'} } + } + local completion_list_items = {items=completion_list} + local expected = { + { abbr = 'foobar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'}, + { abbr = 'foobar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'}, + { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'}, + { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'}, + { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'}, + { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'}, + } + + eq(expected, exec_lua([[return vim.lsp.util.text_document_completion_list_to_complete_items(...)]], completion_list, prefix)) + eq(expected, exec_lua([[return vim.lsp.util.text_document_completion_list_to_complete_items(...)]], completion_list_items, prefix)) + eq({}, exec_lua([[return vim.lsp.util.text_document_completion_list_to_complete_items(...)]], {}, prefix)) + end) + end) +end) -- cgit From 49045b173e0d67a2d140cf914513dc99d2d0d51b Mon Sep 17 00:00:00 2001 From: Andrey Avramenko Date: Mon, 20 Apr 2020 20:20:14 +0300 Subject: test: add docs for get_completion_word test --- test/functional/plugin/lsp_spec.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 7e9abaac2b..b21e344acd 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -812,11 +812,12 @@ describe('LSP', function() }, buf_lines(1)) end) end) -end) -describe('LSP', function() describe('completion_list_to_complete_items', function() - it('should choose right completion option ', function () + -- Completion option precedence: + -- textEdit.newText > insertText > label + -- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion + it('should choose right completion option', function () local prefix = 'foo' local completion_list = { -- resolves into label -- cgit From 68546805790b5fd50e5e520a42dcf2e68c8fa4de Mon Sep 17 00:00:00 2001 From: erw7 Date: Tue, 21 Apr 2020 22:44:39 +0900 Subject: terminal: Fix mouse coordinates issue (#12158) Offsets of window were not taken into account when sending mouse coordinates to the terminal. Therefore, when nu or rnu is set, the mouse coordinates sent to the terminal were not correct. Change it to send the correct coordinates by subtract window offset from col. --- test/functional/terminal/mouse_spec.lua | 34 +++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/functional/terminal/mouse_spec.lua b/test/functional/terminal/mouse_spec.lua index ee3db7ae97..0eb5901b3b 100644 --- a/test/functional/terminal/mouse_spec.lua +++ b/test/functional/terminal/mouse_spec.lua @@ -87,6 +87,36 @@ describe(':terminal mouse', function() {3:-- TERMINAL --} | ]]) end) + + it('will forward mouse clicks to the program with the correct even if set nu', function() + if helpers.pending_win32(pending) then return end + nvim('command', 'set number') + -- When the display area such as a number is clicked, it returns to the + -- normal mode. + feed('<3,0>') + eq('n', eval('mode()')) + screen:expect([[ + {7: 11 }^line28 | + {7: 12 }line29 | + {7: 13 }line30 | + {7: 14 }mouse enabled | + {7: 15 }rows: 6, cols: 46 | + {7: 16 }{2: } | + | + ]]) + -- If click on the coordinate (0,1) of the region of the terminal + -- (i.e. the coordinate (4,1) of vim), 'CSI !"' is sent to the terminal. + feed('i<4,1>') + screen:expect([[ + {7: 11 }line28 | + {7: 12 }line29 | + {7: 13 }line30 | + {7: 14 }mouse enabled | + {7: 15 }rows: 6, cols: 46 | + {7: 16 } !"{1: } | + {3:-- TERMINAL --} | + ]]) + end) end) describe('with a split window and other buffer', function() @@ -148,7 +178,7 @@ describe(':terminal mouse', function() end) it('wont lose focus if another window is scrolled', function() - feed('<0,0><0,0>') + feed('<4,0><4,0>') screen:expect([[ {7: 21 }line │line30 | {7: 22 }line │rows: 5, cols: 25 | @@ -158,7 +188,7 @@ describe(':terminal mouse', function() ========== ========== | {3:-- TERMINAL --} | ]]) - feed('<0,0>') + feed('<4,0>') screen:expect([[ {7: 26 }line │line30 | {7: 27 }line │rows: 5, cols: 25 | -- cgit From ef0398fe88e6cc74f33fb20519997774168d7832 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Sat, 25 Apr 2020 15:46:58 +0200 Subject: LSP: Expose diagnostics grouped by bufnr (#11932) Expose `vim.lsp.buf.diagnostics_by_buf` This makes it easier to customize the diagnostics behavior. For example to defer the update they can override the `textDocument/publishDiagnostics` callback to only call `buf_diagnostics_save_positions` and then defer the other actions to a autocmd event. --- test/functional/plugin/lsp_spec.lua | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index b21e344acd..a57443f909 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -845,4 +845,20 @@ describe('LSP', function() eq({}, exec_lua([[return vim.lsp.util.text_document_completion_list_to_complete_items(...)]], {}, prefix)) end) end) + describe('buf_diagnostics_save_positions', function() + it('stores the diagnostics in diagnostics_by_buf', function () + local diagnostics = { + { range = {}; message = "diag1" }, + { range = {}; message = "diag2" }, + } + exec_lua([[ + vim.lsp.util.buf_diagnostics_save_positions(...)]], 0, diagnostics) + eq(1, exec_lua [[ return #vim.lsp.util.diagnostics_by_buf ]]) + eq(diagnostics, exec_lua [[ + for _, diagnostics in pairs(vim.lsp.util.diagnostics_by_buf) do + return diagnostics + end + ]]) + end) + end) end) -- cgit From 50ff37308abde6c33c2800529cd58f1d7413d7b3 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Sun, 26 Apr 2020 23:56:30 +0200 Subject: LSP: Fix show_line_diagnostics #12186 Messed this up in ef0398fe88e6cc74f33fb20519997774168d7832 --- test/functional/plugin/lsp_spec.lua | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index a57443f909..e53fb5b9e2 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -861,4 +861,29 @@ describe('LSP', function() ]]) end) end) + describe('lsp.util.show_line_diagnostics', function() + it('creates floating window and returns popup bufnr and winnr if current line contains diagnostics', function() + eq(3, exec_lua [[ + local buffer = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(buffer, 0, -1, false, { + "testing"; + "123"; + }) + local diagnostics = { + { + range = { + start = { line = 0; character = 1; }; + ["end"] = { line = 0; character = 3; }; + }; + severity = vim.lsp.protocol.DiagnosticSeverity.Error; + message = "Syntax error"; + }, + } + vim.api.nvim_win_set_buf(0, buffer) + vim.lsp.util.buf_diagnostics_save_positions(vim.fn.bufnr(buffer), diagnostics) + local popup_bufnr, winnr = vim.lsp.util.show_line_diagnostics() + return popup_bufnr + ]]) + end) + end) end) -- cgit From ed6230434b2b0a07ece03272b871412929bfcb53 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Thu, 5 Mar 2020 15:51:02 +0800 Subject: gen_api_dispatch.lua: allow msgpack int for Float args; test: add ui_pum_set_bounds and tv_dict_add_float tests --- test/functional/ui/popupmenu_spec.lua | 86 +++++++++++++++++++++++++++++++++-- test/unit/eval/typval_spec.lua | 20 ++++++++ 2 files changed, 101 insertions(+), 5 deletions(-) (limited to 'test') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 11c3f4123e..9b6ca8032a 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -382,7 +382,7 @@ describe('ui/ext_popupmenu', function() end describe('pum_set_height', function() - it('can be set pum height', function() + it('can set pum height', function() source_complete_month() local month_expected = { {'January', '', '', ''}, @@ -423,23 +423,99 @@ describe('ui/ext_popupmenu', function() it('an error occurs if set 0 or less', function() local ok, err, _ ok, _ = pcall(meths.ui_pum_set_height, 1) - eq(ok, true) + eq(true, ok) ok, err = pcall(meths.ui_pum_set_height, 0) - eq(ok, false) + eq(false, ok) matches('.*: Expected pum height > 0', err) end) it('an error occurs when ext_popupmenu is false', function() local ok, err, _ ok, _ = pcall(meths.ui_pum_set_height, 1) - eq(ok, true) + eq(true, ok) screen:set_option('ext_popupmenu', false) ok, err = pcall(meths.ui_pum_set_height, 1) - eq(ok, false) + eq(false, ok) matches('.*: It must support the ext_popupmenu option', err) end) end) + describe('pum_set_bounds', function() + it('can set pum bounds', function() + source_complete_month() + local month_expected = { + {'January', '', '', ''}, + {'February', '', '', ''}, + {'March', '', '', ''}, + {'April', '', '', ''}, + {'May', '', '', ''}, + {'June', '', '', ''}, + {'July', '', '', ''}, + {'August', '', '', ''}, + {'September', '', '', ''}, + {'October', '', '', ''}, + {'November', '', '', ''}, + {'December', '', '', ''}, + } + local pum_height = 6 + feed('o=TestCompleteMonth()') + meths.ui_pum_set_height(pum_height) + -- set bounds w h r c + meths.ui_pum_set_bounds(10.5, 5.2, 6.3, 7.4) + feed('') + -- pos becomes pum_height-2 because it is subtracting 2 to keep some + -- context in ins_compl_key2count() + screen:expect{grid=[[ + | + January^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]], popupmenu={ + items=month_expected, + pos=pum_height-2, + anchor={1,1,0}, + }} + end) + + it('an error occurs if row or col set less than 0', function() + local ok, err, _ + ok, _ = pcall(meths.ui_pum_set_bounds, 1.0, 1.0, 0.0, 1.5) + eq(true, ok) + ok, err = pcall(meths.ui_pum_set_bounds, 1.0, 1.0, -1.0, 0.0) + eq(false, ok) + matches('.*: Expected pumpos row >= 0', err) + ok, err = pcall(meths.ui_pum_set_bounds, 1.0, 1.0, 0.0, -1.0) + eq(false, ok) + matches('.*: Expected pumpos col >= 0', err) + end) + + it('an error occurs if width or height set 0 or less', function() + local ok, err, _ + ok, _ = pcall(meths.ui_pum_set_bounds, 1.0, 1.0, 0.0, 1.5) + eq(true, ok) + ok, err = pcall(meths.ui_pum_set_bounds, 0.0, 1.0, 1.0, 0.0) + eq(false, ok) + matches('.*: Expected pumpos width > 0', err) + ok, err = pcall(meths.ui_pum_set_bounds, 1.0, 0.0, 1.0, 0.0) + eq(false, ok) + matches('.*: Expected pumpos height > 0', err) + end) + + it('an error occurs when ext_popupmenu is false', function() + local ok, err, _ + ok, _ = pcall(meths.ui_pum_set_bounds, 1.0, 1.0, 0.0, 1.5) + eq(true, ok) + screen:set_option('ext_popupmenu', false) + ok, err = pcall(meths.ui_pum_set_bounds, 1.0, 1.0, 0.0, 1.5) + eq(false, ok) + matches('.*: UI must support the ext_popupmenu option', err) + end) + end) + it(', works without ui_pum_set_height', function() source_complete_month() local month_expected = { diff --git a/test/unit/eval/typval_spec.lua b/test/unit/eval/typval_spec.lua index 1651eb9bcc..ea86ccbf1c 100644 --- a/test/unit/eval/typval_spec.lua +++ b/test/unit/eval/typval_spec.lua @@ -2026,6 +2026,26 @@ describe('typval.c', function() alloc_log:check({}) end) end) + describe('float()', function() + itp('works', function() + local d = dict({test=10}) + alloc_log:clear() + eq({test=10}, dct2tbl(d)) + eq(OK, lib.tv_dict_add_float(d, 'testt', 3, 1.5)) + local dis = dict_items(d) + alloc_log:check({a.di(dis.tes, 'tes')}) + eq({test=10, tes=1.5}, dct2tbl(d)) + eq(FAIL, check_emsg(function() return lib.tv_dict_add_float(d, 'testt', 3, 1.5) end, + 'E685: Internal error: hash_add()')) + alloc_log:clear() + lib.emsg_skip = lib.emsg_skip + 1 + eq(FAIL, check_emsg(function() return lib.tv_dict_add_float(d, 'testt', 3, 1.5) end, + nil)) + lib.emsg_skip = lib.emsg_skip - 1 + alloc_log:clear_tmp_allocs() + alloc_log:check({}) + end) + end) describe('str()', function() itp('works', function() local d = dict({test=10}) -- cgit From d372c804aa33a272f6659f6d08d5dfee704d30d9 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Sun, 22 Mar 2020 17:27:49 +0800 Subject: api/ui: allow set bounds row and col to be less than 0; ui_pum_get_pos: return first extui bounds information instead of reducing --- test/functional/ui/popupmenu_spec.lua | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'test') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 9b6ca8032a..3108d21508 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -481,16 +481,14 @@ describe('ui/ext_popupmenu', function() }} end) - it('an error occurs if row or col set less than 0', function() + it('no error occurs if row or col set less than 0', function() local ok, err, _ ok, _ = pcall(meths.ui_pum_set_bounds, 1.0, 1.0, 0.0, 1.5) eq(true, ok) - ok, err = pcall(meths.ui_pum_set_bounds, 1.0, 1.0, -1.0, 0.0) - eq(false, ok) - matches('.*: Expected pumpos row >= 0', err) - ok, err = pcall(meths.ui_pum_set_bounds, 1.0, 1.0, 0.0, -1.0) - eq(false, ok) - matches('.*: Expected pumpos col >= 0', err) + ok, _ = pcall(meths.ui_pum_set_bounds, 1.0, 1.0, -1.0, 0.0) + eq(true, ok) + ok, _ = pcall(meths.ui_pum_set_bounds, 1.0, 1.0, 0.0, -1.0) + eq(true, ok) end) it('an error occurs if width or height set 0 or less', function() -- cgit From e34684b2ad02e759dec39c0f0958c7882120ecdc Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Sun, 22 Mar 2020 17:53:45 +0800 Subject: api/ui: simplify popup menu position get/set logic; fix test --- test/functional/ui/popupmenu_spec.lua | 53 ++++++++++++----------------------- 1 file changed, 18 insertions(+), 35 deletions(-) (limited to 'test') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 3108d21508..c1c5d1ce2e 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -8,7 +8,7 @@ local command = helpers.command local funcs = helpers.funcs local get_pathsep = helpers.get_pathsep local eq = helpers.eq -local matches = helpers.matches +local pcall_err = helpers.pcall_err describe('ui/ext_popupmenu', function() local screen @@ -421,22 +421,16 @@ describe('ui/ext_popupmenu', function() end) it('an error occurs if set 0 or less', function() - local ok, err, _ - ok, _ = pcall(meths.ui_pum_set_height, 1) - eq(true, ok) - ok, err = pcall(meths.ui_pum_set_height, 0) - eq(false, ok) - matches('.*: Expected pum height > 0', err) + meths.ui_pum_set_height(1) + eq('Expected pum height > 0', + pcall_err(meths.ui_pum_set_height, 0)) end) it('an error occurs when ext_popupmenu is false', function() - local ok, err, _ - ok, _ = pcall(meths.ui_pum_set_height, 1) - eq(true, ok) + meths.ui_pum_set_height(1) screen:set_option('ext_popupmenu', false) - ok, err = pcall(meths.ui_pum_set_height, 1) - eq(false, ok) - matches('.*: It must support the ext_popupmenu option', err) + eq('It must support the ext_popupmenu option', + pcall_err(meths.ui_pum_set_height, 1)) end) end) @@ -482,35 +476,24 @@ describe('ui/ext_popupmenu', function() end) it('no error occurs if row or col set less than 0', function() - local ok, err, _ - ok, _ = pcall(meths.ui_pum_set_bounds, 1.0, 1.0, 0.0, 1.5) - eq(true, ok) - ok, _ = pcall(meths.ui_pum_set_bounds, 1.0, 1.0, -1.0, 0.0) - eq(true, ok) - ok, _ = pcall(meths.ui_pum_set_bounds, 1.0, 1.0, 0.0, -1.0) - eq(true, ok) + meths.ui_pum_set_bounds(1.0, 1.0, 0.0, 1.5) + meths.ui_pum_set_bounds(1.0, 1.0, -1.0, 0.0) + meths.ui_pum_set_bounds(1.0, 1.0, 0.0, -1.0) end) it('an error occurs if width or height set 0 or less', function() - local ok, err, _ - ok, _ = pcall(meths.ui_pum_set_bounds, 1.0, 1.0, 0.0, 1.5) - eq(true, ok) - ok, err = pcall(meths.ui_pum_set_bounds, 0.0, 1.0, 1.0, 0.0) - eq(false, ok) - matches('.*: Expected pumpos width > 0', err) - ok, err = pcall(meths.ui_pum_set_bounds, 1.0, 0.0, 1.0, 0.0) - eq(false, ok) - matches('.*: Expected pumpos height > 0', err) + meths.ui_pum_set_bounds(1.0, 1.0, 0.0, 1.5) + eq('Expected width > 0', + pcall_err(meths.ui_pum_set_bounds, 0.0, 1.0, 1.0, 0.0)) + eq('Expected height > 0', + pcall_err(meths.ui_pum_set_bounds, 1.0, -1.0, 1.0, 0.0)) end) it('an error occurs when ext_popupmenu is false', function() - local ok, err, _ - ok, _ = pcall(meths.ui_pum_set_bounds, 1.0, 1.0, 0.0, 1.5) - eq(true, ok) + meths.ui_pum_set_bounds(1.0, 1.0, 0.0, 1.5) screen:set_option('ext_popupmenu', false) - ok, err = pcall(meths.ui_pum_set_bounds, 1.0, 1.0, 0.0, 1.5) - eq(false, ok) - matches('.*: UI must support the ext_popupmenu option', err) + eq('UI must support the ext_popupmenu option', + pcall_err(meths.ui_pum_set_bounds, 1.0, 1.0, 0.0, 1.5)) end) end) -- cgit From e4a1be779b9a6bb9a47700ebf92f8dd934bb1712 Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Wed, 29 Apr 2020 10:32:34 +0900 Subject: lsp/completion: Expose completion_item under completed_items.user_data. By passing through completion_item it's now possible for snippet plugins to add LSP snippet support. --- test/functional/plugin/lsp_spec.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index e53fb5b9e2..5e4f768e7f 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -832,12 +832,12 @@ describe('LSP', function() } local completion_list_items = {items=completion_list} local expected = { - { abbr = 'foobar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'}, - { abbr = 'foobar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'}, - { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'}, - { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'}, - { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'}, - { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'}, + { abbr = 'foobar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label = 'foobar' } } } } }, + { abbr = 'foobar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foobar', textEdit={} } } } } }, + { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foobar' } } } } }, + { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foobar', textEdit={} } } } } }, + { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foodar', textEdit={newText='foobar'} } } } } }, + { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', textEdit={newText='foobar'} } } } } }, } eq(expected, exec_lua([[return vim.lsp.util.text_document_completion_list_to_complete_items(...)]], completion_list, prefix)) -- cgit From f9055c585f597fe4ea8ecb990927a2826234393c Mon Sep 17 00:00:00 2001 From: Ghjuvan Lacambre Date: Wed, 29 Apr 2020 16:53:13 +0200 Subject: LSP: enable using different highlighting rules for LSP signs (#12176) This commit creates 4 new highlight groups: - LspDiagnosticsErrorSign - LspDiagnosticsWarningSign - LspDiagnosticsInformationSign - LspDiagnosticsHintSign These highlight groups are linked to their corresponding LspDiagnostics highlight groups by default. This lets users choose a different color for their sign columns and virtualtext diagnostics. --- test/functional/plugin/lsp_spec.lua | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index e53fb5b9e2..b73da12ae8 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -754,14 +754,18 @@ describe('LSP', function() it('highlight groups', function() eq({'LspDiagnosticsError', + 'LspDiagnosticsErrorSign', 'LspDiagnosticsHint', + 'LspDiagnosticsHintSign', 'LspDiagnosticsInformation', + 'LspDiagnosticsInformationSign', 'LspDiagnosticsUnderline', 'LspDiagnosticsUnderlineError', 'LspDiagnosticsUnderlineHint', 'LspDiagnosticsUnderlineInformation', 'LspDiagnosticsUnderlineWarning', 'LspDiagnosticsWarning', + 'LspDiagnosticsWarningSign', }, exec_lua([[require'vim.lsp'; return vim.fn.getcompletion('Lsp', 'highlight')]])) end) -- cgit From 6dc8398944fd86038b07d77fcab92cd282555dee Mon Sep 17 00:00:00 2001 From: ckipp01 Date: Mon, 27 Apr 2020 10:55:06 +0200 Subject: [LSP] check for vim.NIL and add apply_text_document_edit tests --- test/functional/plugin/lsp_spec.lua | 56 +++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index fdbe45c09a..53530eb513 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -817,6 +817,62 @@ describe('LSP', function() end) end) + describe('apply_text_document_edit', function() + before_each(function() + insert(dedent([[ + First line of text + Second line of text]])) + end) + it('correctly goes ahead with the edit when all is normal', function() + local text_document_edit = { + edits = { + make_edit(0, 0, 0, 0, "hi") + }, + textDocument = { + uri = "file://fake/uri"; + version = 5 + } + } + exec_lua('vim.lsp.util.apply_text_document_edit(...)', text_document_edit, 1) + eq({ + 'hiline of text'; + 'Second line of text'; + }, buf_lines(1)) + end) + it('correctly goes ahead with the edit whe the version is nil', function() + local text_document_edit = { + edits = { + make_edit(0, 0, 0, 0, "hi") + }, + textDocument = { + uri = "file://fake/uri"; + version = vim.NIL + } + } + exec_lua('vim.lsp.util.apply_text_document_edit(...)', text_document_edit, 1) + eq({ + 'hiline of text'; + 'Second line of text'; + }, buf_lines(1)) + end) + it('skips the edit if the version of the edit is behind the local buffer ', function() + local text_document_edit = { + edits = { + make_edit(0, 0, 0, 0, "hi") + }, + textDocument = { + uri = "file://fake/uri"; + version = 1 + } + } + exec_lua('vim.lsp.util.apply_text_document_edit(...)', text_document_edit, 1) + eq({ + 'First line of text'; + 'Second line of text'; + }, buf_lines(1)) + end) + end) + describe('completion_list_to_complete_items', function() -- Completion option precedence: -- textEdit.newText > insertText > label -- cgit From 3eae7d52c526ae72324145a8cc096856022cc42d Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Sat, 2 May 2020 15:09:49 +0900 Subject: lsp: add lsp.util.symbols_to_items test --- test/functional/plugin/lsp_spec.lua | 251 ++++++++++++++++++++++++++++++++++++ 1 file changed, 251 insertions(+) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index fdbe45c09a..1a0063b43e 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -890,4 +890,255 @@ describe('LSP', function() ]]) end) end) + describe('lsp.util.symbols_to_items', function() + describe('convert DocumentSymbol[] to items', function() + it('DocumentSymbol has children', function() + local expected = { + { + col = 1, + filename = '', + kind = 'File', + lnum = 2, + text = '[File] TestA' + }, + { + col = 1, + filename = '', + kind = 'Module', + lnum = 4, + text = '[Module] TestB' + }, + { + col = 1, + filename = '', + kind = 'Namespace', + lnum = 6, + text = '[Namespace] TestC' + } + } + eq(expected, exec_lua [[ + local doc_syms = { + { + deprecated = false, + detail = "A", + kind = 1, + name = "TestA", + range = { + start = { + character = 0, + line = 1 + }, + ["end"] = { + character = 0, + line = 2 + } + }, + selectionRange = { + start = { + character = 0, + line = 1 + }, + ["end"] = { + character = 4, + line = 1 + } + }, + children = { + { + children = {}, + deprecated = false, + detail = "B", + kind = 2, + name = "TestB", + range = { + start = { + character = 0, + line = 3 + }, + ["end"] = { + character = 0, + line = 4 + } + }, + selectionRange = { + start = { + character = 0, + line = 3 + }, + ["end"] = { + character = 4, + line = 3 + } + } + } + } + }, + { + deprecated = false, + detail = "C", + kind = 3, + name = "TestC", + range = { + start = { + character = 0, + line = 5 + }, + ["end"] = { + character = 0, + line = 6 + } + }, + selectionRange = { + start = { + character = 0, + line = 5 + }, + ["end"] = { + character = 4, + line = 5 + } + } + } + } + return vim.lsp.util.symbols_to_items(doc_syms, nil) + ]]) + end) + it('DocumentSymbol has no children', function() + local expected = { + { + col = 1, + filename = '', + kind = 'File', + lnum = 2, + text = '[File] TestA' + }, + { + col = 1, + filename = '', + kind = 'Namespace', + lnum = 6, + text = '[Namespace] TestC' + } + } + eq(expected, exec_lua [[ + local doc_syms = { + { + deprecated = false, + detail = "A", + kind = 1, + name = "TestA", + range = { + start = { + character = 0, + line = 1 + }, + ["end"] = { + character = 0, + line = 2 + } + }, + selectionRange = { + start = { + character = 0, + line = 1 + }, + ["end"] = { + character = 4, + line = 1 + } + }, + }, + { + deprecated = false, + detail = "C", + kind = 3, + name = "TestC", + range = { + start = { + character = 0, + line = 5 + }, + ["end"] = { + character = 0, + line = 6 + } + }, + selectionRange = { + start = { + character = 0, + line = 5 + }, + ["end"] = { + character = 4, + line = 5 + } + } + } + } + return vim.lsp.util.symbols_to_items(doc_syms, nil) + ]]) + end) + end) + describe('convert SymbolInformation[] to items', function() + local expected = { + { + col = 1, + filename = 'test_a', + kind = 'File', + lnum = 2, + text = '[File] TestA' + }, + { + col = 1, + filename = 'test_b', + kind = 'Module', + lnum = 4, + text = '[Module] TestB' + } + } + eq(expected, exec_lua [[ + local sym_info = { + { + deprecated = false, + kind = 1, + name = "TestA", + location = { + range = { + start = { + character = 0, + line = 1 + }, + ["end"] = { + character = 0, + line = 2 + } + }, + uri = "file://test_a" + }, + contanerName = "TestAContainer" + }, + { + deprecated = false, + kind = 2, + name = "TestB", + location = { + range = { + start = { + character = 0, + line = 3 + }, + ["end"] = { + character = 0, + line = 4 + } + }, + uri = "file://test_b" + }, + contanerName = "TestBContainer" + } + } + return vim.lsp.util.symbols_to_items(sym_info, nil) + ]]) + end) + end) end) -- cgit From 0107a194fa6a82c3d919af2e2b606eeb74bc2352 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Sun, 3 May 2020 13:01:00 +0900 Subject: lsp: fix apply_text_document_edit test lsp.util.buf_versions must be set in advance. Use helper.insert to create an anonymous buffer, so create a named buffer for testing without using insert. --- test/functional/plugin/lsp_spec.lua | 67 +++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 21 deletions(-) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 53530eb513..94e85d6fe6 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -818,58 +818,83 @@ describe('LSP', function() end) describe('apply_text_document_edit', function() + local target_bufnr before_each(function() - insert(dedent([[ - First line of text - Second line of text]])) + target_bufnr = exec_lua [[ + local bufnr = vim.fn.bufadd("fake/uri") + local lines = {"1st line of text", "2nd line of text"} + vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) + return bufnr + ]] end) - it('correctly goes ahead with the edit when all is normal', function() + it('correctly goes ahead with the edit if all is normal', function() local text_document_edit = { edits = { - make_edit(0, 0, 0, 0, "hi") + make_edit(0, 0, 0, 3, "First") }, textDocument = { uri = "file://fake/uri"; version = 5 } } - exec_lua('vim.lsp.util.apply_text_document_edit(...)', text_document_edit, 1) + exec_lua([[ + local args = {...} + local target_bufnr = args[2] + vim.lsp.util.buf_versions[target_bufnr] = 4 + vim.lsp.util.apply_text_document_edit(...) + ]], text_document_edit, target_bufnr) eq({ - 'hiline of text'; - 'Second line of text'; - }, buf_lines(1)) + 'First line of text'; + '2nd line of text'; + }, buf_lines(target_bufnr)) end) - it('correctly goes ahead with the edit whe the version is nil', function() + it('correctly goes ahead with the edit if the version is vim.NIL', function() + -- we get vim.NIL when we decode json null value. + local json = exec_lua[[ + return vim.fn.json_decode("{ \"a\": 1, \"b\": null }") + ]] + eq(json.b, exec_lua("return vim.NIL")) + local text_document_edit = { edits = { - make_edit(0, 0, 0, 0, "hi") + make_edit(0, 0, 0, 3, "First") }, textDocument = { uri = "file://fake/uri"; - version = vim.NIL + version = exec_lua("return vim.NIL") } } - exec_lua('vim.lsp.util.apply_text_document_edit(...)', text_document_edit, 1) + exec_lua([[ + local args = {...} + local target_bufnr = args[2] + vim.lsp.util.buf_versions[target_bufnr] = vim.NIL + vim.lsp.util.apply_text_document_edit(...) + ]], text_document_edit, target_bufnr) eq({ - 'hiline of text'; - 'Second line of text'; - }, buf_lines(1)) + 'First line of text'; + '2nd line of text'; + }, buf_lines(target_bufnr)) end) it('skips the edit if the version of the edit is behind the local buffer ', function() local text_document_edit = { edits = { - make_edit(0, 0, 0, 0, "hi") + make_edit(0, 0, 0, 3, "First") }, textDocument = { uri = "file://fake/uri"; version = 1 } } - exec_lua('vim.lsp.util.apply_text_document_edit(...)', text_document_edit, 1) + exec_lua([[ + local args = {...} + local target_bufnr = args[2] + vim.lsp.util.buf_versions[target_bufnr] = 2 + vim.lsp.util.apply_text_document_edit(...) + ]], text_document_edit, target_bufnr) eq({ - 'First line of text'; - 'Second line of text'; - }, buf_lines(1)) + '1st line of text'; + '2nd line of text'; + }, buf_lines(target_bufnr)) end) end) -- cgit From 67634da71403737bd3f0c4c037b9ccf3382903ae Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Mon, 4 May 2020 09:05:16 +0900 Subject: lsp: add a lsp.util.apply_text_edits test(pending) We don't handle non-ASCII characters well in UTF-16. So I add a non-ASCII characters test case. --- test/functional/plugin/lsp_spec.lua | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 94e85d6fe6..63188a9b09 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -770,13 +770,14 @@ describe('LSP', function() exec_lua([[require'vim.lsp'; return vim.fn.getcompletion('Lsp', 'highlight')]])) end) - describe('apply_edits', function() + describe('apply_text_edits', function() before_each(function() insert(dedent([[ First line of text Second line of text Third line of text - Fourth line of text]])) + Fourth line of text + å å ɧ 汉语 ↥ 🤦 🦄]])) end) it('applies apply simple edits', function() local edits = { @@ -790,6 +791,7 @@ describe('LSP', function() '2econd line of text'; '3ird line of text'; 'Fourth line of text'; + 'å å ɧ 汉语 ↥ 🤦 🦄'; }, buf_lines(1)) end) it('applies complex edits', function() @@ -813,6 +815,21 @@ describe('LSP', function() 'The next line of text'; 'another line of text'; 'before this!'; + 'å å ɧ 汉语 ↥ 🤦 🦄'; + }, buf_lines(1)) + end) + pending('applies non-ASCII characters edits', function() + -- FIXME: We don't handle non-ASCII characters well in UTF-16 + local edits = { + make_edit(4, 0, 4, 14, {"a a h"}); + } + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + eq({ + 'First line of text'; + 'Second line of text'; + 'Third line of text'; + 'Fourth line of text'; + 'a a h'; }, buf_lines(1)) end) end) -- cgit From 2c40a38b39a944a3e1a90302c1061b4e6e3ba6ac Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Tue, 5 May 2020 05:06:40 +0200 Subject: LSP: Avoid URI-to-fname conversion for non-file URIs #12243 Fixes https://github.com/neovim/neovim/issues/12210 --- test/functional/lua/uri_spec.lua | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'test') diff --git a/test/functional/lua/uri_spec.lua b/test/functional/lua/uri_spec.lua index 128c7c6137..a3b8e685e1 100644 --- a/test/functional/lua/uri_spec.lua +++ b/test/functional/lua/uri_spec.lua @@ -113,4 +113,15 @@ describe('URI methods', function() end) end) end) + + describe('uri to bufnr', function() + it('uri_to_bufnr & uri_from_bufnr returns original uri for non-file uris', function() + local uri = 'jdt://contents/java.base/java.util/List.class?=sql/%5C/home%5C/user%5C/.jabba%5C/jdk%5C/openjdk%5C@1.14.0%5C/lib%5C/jrt-fs.jar%60java.base=/javadoc_location=/https:%5C/%5C/docs.oracle.com%5C/en%5C/java%5C/javase%5C/14%5C/docs%5C/api%5C/=/%3Cjava.util(List.class' + local test_case = string.format([[ + local uri = '%s' + return vim.uri_from_bufnr(vim.uri_to_bufnr(uri)) + ]], uri) + eq(uri, exec_lua(test_case)) + end) + end) end) -- cgit From 7b764bb43d9c45e04a8dbb0146b3529991007949 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 4 May 2020 21:04:47 -0700 Subject: terminal: disable 'scrolloff' (fixes flicker) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Besides the special-case in get_scrolloff_value(), it makes sense for 'scrolloff' and 'sidescrolloff' to reflect the correct values (for plugins, scripts, …). ref 53d607af9c53accfd634435908fb79061f1212b9 ref #11915 ref #12230 --- test/functional/terminal/buffer_spec.lua | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'test') diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index d40baca871..f79aceaddf 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -17,6 +17,18 @@ describe(':terminal buffer', function() screen = thelpers.screen_setup() end) + it('terminal-mode forces various options', function() + feed([[]]) + command('setlocal cursorline cursorcolumn scrolloff=4 sidescrolloff=7') + eq({ 1, 1, 4, 7 }, eval('[&l:cursorline, &l:cursorcolumn, &l:scrolloff, &l:sidescrolloff]')) + eq('n', eval('mode()')) + + -- Enter terminal-mode ("insert" mode in :terminal). + feed('i') + eq('t', eval('mode()')) + eq({ 0, 0, 0, 0 }, eval('[&l:cursorline, &l:cursorcolumn, &l:scrolloff, &l:sidescrolloff]')) + end) + describe('when a new file is edited', function() before_each(function() feed(':set bufhidden=wipe:enew') -- cgit From 48c219829786c14b6e511229a59e2fda32ffe352 Mon Sep 17 00:00:00 2001 From: Jesse Date: Tue, 5 May 2020 13:18:41 +0200 Subject: paste: support replace mode (#11945) * paste: support replace mode * Clean up Co-authored-by: Jesse Bakker --- test/functional/api/vim_spec.lua | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'test') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index fb3755cb8e..2e9d0f57ac 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -571,6 +571,28 @@ describe('API', function() eq({0,7,1,0}, funcs.getpos('.')) eq(false, nvim('get_option', 'paste')) end) + it('Replace-mode', function() + -- Within single line + nvim('put', {'aabbccdd', 'eeffgghh', 'iijjkkll'}, "c", true, false) + command('normal l') + command('startreplace') + nvim('paste', '123456', true, -1) + expect([[ + a123456d + eeffgghh + iijjkkll]]) + command('%delete _') + -- Across lines + nvim('put', {'aabbccdd', 'eeffgghh', 'iijjkkll'}, "c", true, false) + command('normal l') + command('startreplace') + nvim('paste', '123\n456', true, -1) + expect([[ + a123 + 456d + eeffgghh + iijjkkll]]) + end) it('crlf=false does not break lines at CR, CRLF', function() nvim('paste', 'line 1\r\n\r\rline 2\nline 3\rline 4\r', false, -1) expect('line 1\r\n\r\rline 2\nline 3\rline 4\r') -- cgit From 1212390254c5de90513c0314efa94df7b9218590 Mon Sep 17 00:00:00 2001 From: erw7 Date: Sun, 1 Sep 2019 18:44:14 +0900 Subject: vim-patch:8.1.1007: using closure may consume a lot of memory Problem: Using closure may consume a lot of memory. Solution: unreference items that are no longer needed. Add a test. (Ozaki Kiichi, closes vim/vim#3961) https://github.com/vim/vim/commit/209b8e3e3bf7a4a3d102134124120f6c7f57d560 --- test/functional/legacy/memory_usage_spec.lua | 151 +++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 test/functional/legacy/memory_usage_spec.lua (limited to 'test') diff --git a/test/functional/legacy/memory_usage_spec.lua b/test/functional/legacy/memory_usage_spec.lua new file mode 100644 index 0000000000..14a7f2dbdd --- /dev/null +++ b/test/functional/legacy/memory_usage_spec.lua @@ -0,0 +1,151 @@ +local helpers = require('test.functional.helpers')(after_each) +local clear = helpers.clear +local eval = helpers.eval +local eq = helpers.eq +local feed_command = helpers.feed_command +local iswin = helpers.iswin +local retry = helpers.retry +local ok = helpers.ok +local source = helpers.source + +local monitor_memory_usage = { + memory_usage = function(self) + local handle + if iswin() then + handle = io.popen('wmic process where processid=' ..self.pid..' get WorkingSetSize') + else + handle = io.popen('ps -o rss= -p '..self.pid) + end + return tonumber(handle:read('*a'):match('%d+')) + end, + op = function(self) + retry(nil, 10000, function() + local val = self.memory_usage(self) + if self.min > val then + self.min = val + elseif self.max < val then + self.max = val + end + table.insert(self.hist, val) + ok(#self.hist > 20) + local result = {} + for key,value in ipairs(self.hist) do + if value ~= self.hist[key + 1] then + table.insert(result, value) + end + end + table.remove(self.hist, 1) + self.last = self.hist[#self.hist] + eq(#result, 1) + end) + end, + dump = function(self) + return 'max: '..self.max ..', last: '..self.last + end, + monitor_memory_usage = function(self, pid) + local obj = { + pid = pid, + min = 0, + max = 0, + last = 0, + hist = {}, + } + setmetatable(obj, { __index = self }) + obj:op() + return obj + end +} +setmetatable(monitor_memory_usage, +{__call = function(self, pid) + return monitor_memory_usage.monitor_memory_usage(self, pid) +end}) + +describe('memory usage', function() + local function check_result(tbl, status, result) + if not status then + print('') + for key, val in pairs(tbl) do + print(key, val:dump()) + end + error(result) + end + end + + local function isasan() + local version = eval('execute("version")') + return version:match('-fsanitize=[a-z,]*address') + end + + before_each(clear) + + --[[ + Case: if a local variable captures a:000, funccall object will be free + just after it finishes. + ]]-- + it('function capture vargs', function() + if isasan() then + pending('ASAN build is difficult to estimate memory usage') + end + if iswin() and eval("executable('wmic')") == 0 then + pending('missing "wmic" command') + elseif eval("executable('ps')") == 0 then + pending('missing "ps" command') + end + + local pid = eval('getpid()') + local before = monitor_memory_usage(pid) + source([[ + func s:f(...) + let x = a:000 + endfunc + for _ in range(10000) + call s:f(0) + endfor + ]]) + local after = monitor_memory_usage(pid) + -- Estimate the limit of max usage as 2x initial usage. + check_result({before=before, after=after}, pcall(ok, before.last < after.max)) + check_result({before=before, after=after}, pcall(ok, before.last * 2 > after.max)) + -- In this case, garbase collecting is not needed. + check_result({before=before, after=after}, pcall(eq, after.last, after.max)) + end) + + --[[ + Case: if a local variable captures l: dict, funccall object will not be + free until garbage collector runs, but after that memory usage doesn't + increase so much even when rerun Xtest.vim since system memory caches. + ]]-- + it('function capture lvars', function() + if isasan() then + pending('ASAN build is difficult to estimate memory usage') + end + if iswin() and eval("executable('wmic')") == 0 then + pending('missing "wmic" command') + elseif eval("executable('ps')") == 0 then + pending('missing "ps" command') + end + + local pid = eval('getpid()') + local before = monitor_memory_usage(pid) + local fname = source([[ + if !exists('s:defined_func') + func s:f() + let x = l: + endfunc + endif + let s:defined_func = 1 + for _ in range(10000) + call s:f() + endfor + ]]) + local after = monitor_memory_usage(pid) + for _ = 1, 3 do + feed_command('so '..fname) + end + local last = monitor_memory_usage(pid) + check_result({before=before, after=after, last=last}, + pcall(ok, before.last < last.last)) + check_result({before=before, after=after, last=last}, + pcall(ok, last.last < after.max + (after.last - before.last))) + end) +end) -- cgit From 9ad2ba1c5cde229265f6ca560c5925724d1cf58f Mon Sep 17 00:00:00 2001 From: erw7 Date: Fri, 6 Sep 2019 00:19:02 +0900 Subject: vim-patch:8.1.1027: memory usage test sometimes fails Problem: Memory usage test sometimes fails. Solution: Use 80% of before.last as the lower limit. (Christian Brabandt) https://github.com/vim/vim/commit/08cda65ddfbb4bce8cef43726a0c00817fc47327 --- test/functional/legacy/memory_usage_spec.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/legacy/memory_usage_spec.lua b/test/functional/legacy/memory_usage_spec.lua index 14a7f2dbdd..2b4f8ea15e 100644 --- a/test/functional/legacy/memory_usage_spec.lua +++ b/test/functional/legacy/memory_usage_spec.lua @@ -143,8 +143,10 @@ describe('memory usage', function() feed_command('so '..fname) end local last = monitor_memory_usage(pid) + -- The usage may be a bit less than the last value + local lower = before.last * 8 / 10 check_result({before=before, after=after, last=last}, - pcall(ok, before.last < last.last)) + pcall(ok, lower < last.last)) check_result({before=before, after=after, last=last}, pcall(ok, last.last < after.max + (after.last - before.last))) end) -- cgit From 6175d974c26e57cec1b83079681f9bfb5adc5683 Mon Sep 17 00:00:00 2001 From: erw7 Date: Fri, 6 Sep 2019 00:22:10 +0900 Subject: vim-patch:8.1.1031: memory usage test may still fail Problem: Memory usage test may still fail. Solution: Drop the unused min value. (Christian Brabandt) https://github.com/vim/vim/commit/f7e47af7760fe054cb645dac9a1e96b23c85804d --- test/functional/legacy/memory_usage_spec.lua | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'test') diff --git a/test/functional/legacy/memory_usage_spec.lua b/test/functional/legacy/memory_usage_spec.lua index 2b4f8ea15e..08caf4449d 100644 --- a/test/functional/legacy/memory_usage_spec.lua +++ b/test/functional/legacy/memory_usage_spec.lua @@ -21,9 +21,7 @@ local monitor_memory_usage = { op = function(self) retry(nil, 10000, function() local val = self.memory_usage(self) - if self.min > val then - self.min = val - elseif self.max < val then + if self.max < val then self.max = val end table.insert(self.hist, val) @@ -45,7 +43,6 @@ local monitor_memory_usage = { monitor_memory_usage = function(self, pid) local obj = { pid = pid, - min = 0, max = 0, last = 0, hist = {}, @@ -106,8 +103,13 @@ describe('memory usage', function() -- Estimate the limit of max usage as 2x initial usage. check_result({before=before, after=after}, pcall(ok, before.last < after.max)) check_result({before=before, after=after}, pcall(ok, before.last * 2 > after.max)) - -- In this case, garbase collecting is not needed. - check_result({before=before, after=after}, pcall(eq, after.last, after.max)) + -- In this case, garbage collecting is not needed. + -- The value might fluctuate + -- a bit, allow for 3% tolerance. + local lower = after.last * 97 / 100 + local upper = after.last * 103 / 100 + check_result({before=before, after=after}, pcall(ok, lower < after.max)) + check_result({before=before, after=after}, pcall(ok, after.max < upper)) end) --[[ @@ -143,11 +145,13 @@ describe('memory usage', function() feed_command('so '..fname) end local last = monitor_memory_usage(pid) - -- The usage may be a bit less than the last value + -- The usage may be a bit less than the last value, use 80%. + -- Allow for 1% tolerance at the upper limit. local lower = before.last * 8 / 10 + local upper = (after.max + (after.last - before.last)) * 101 / 100 check_result({before=before, after=after, last=last}, pcall(ok, lower < last.last)) check_result({before=before, after=after, last=last}, - pcall(ok, last.last < after.max + (after.last - before.last))) + pcall(ok, last.last < upper)) end) end) -- cgit From 7acdc9da1dec4306818302a3d2518fc2caf02963 Mon Sep 17 00:00:00 2001 From: erw7 Date: Fri, 6 Sep 2019 00:28:58 +0900 Subject: vim-patch:8.1.1033: memory usage test may still fail on some systems Problem: Memory usage test may still fail on some systems. (Elimar Riesebieter) Solution: Increase tolerance from 1% to 3%. https://github.com/vim/vim/commit/ba64ba093520e85d6bed2595960edb693bdb4c51 --- test/functional/legacy/memory_usage_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/functional/legacy/memory_usage_spec.lua b/test/functional/legacy/memory_usage_spec.lua index 08caf4449d..e2e5277acb 100644 --- a/test/functional/legacy/memory_usage_spec.lua +++ b/test/functional/legacy/memory_usage_spec.lua @@ -146,9 +146,9 @@ describe('memory usage', function() end local last = monitor_memory_usage(pid) -- The usage may be a bit less than the last value, use 80%. - -- Allow for 1% tolerance at the upper limit. + -- Allow for 3% tolerance at the upper limit. local lower = before.last * 8 / 10 - local upper = (after.max + (after.last - before.last)) * 101 / 100 + local upper = (after.max + (after.last - before.last)) * 103 / 100 check_result({before=before, after=after, last=last}, pcall(ok, lower < last.last)) check_result({before=before, after=after, last=last}, -- cgit From 6b3399338f831c69f8b9da63d8277860d3a302d6 Mon Sep 17 00:00:00 2001 From: erw7 Date: Fri, 6 Sep 2019 00:30:30 +0900 Subject: vim-patch:8.1.1037: memory usage test may still fail on some systems Problem: Memory usage test may still fail on some systems. Solution: Increase tolerance from 3% to 20%. https://github.com/vim/vim/commit/6b6f7aae4a3329d685e512699287605540257b40 --- test/functional/legacy/memory_usage_spec.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/functional/legacy/memory_usage_spec.lua b/test/functional/legacy/memory_usage_spec.lua index e2e5277acb..b52742eaac 100644 --- a/test/functional/legacy/memory_usage_spec.lua +++ b/test/functional/legacy/memory_usage_spec.lua @@ -146,9 +146,10 @@ describe('memory usage', function() end local last = monitor_memory_usage(pid) -- The usage may be a bit less than the last value, use 80%. - -- Allow for 3% tolerance at the upper limit. + -- Allow for 20% tolerance at the upper limit. That's very permissive, but + -- otherwise the test fails sometimes. local lower = before.last * 8 / 10 - local upper = (after.max + (after.last - before.last)) * 103 / 100 + local upper = (after.max + (after.last - before.last)) * 12 / 10 check_result({before=before, after=after, last=last}, pcall(ok, lower < last.last)) check_result({before=before, after=after, last=last}, -- cgit From a32bac0c04215a867b941957c2dac89a719261cf Mon Sep 17 00:00:00 2001 From: erw7 Date: Fri, 6 Sep 2019 00:32:43 +0900 Subject: vim-patch:8.1.1058: memory usage test may still fail on some systems Problem: Memory usage test may still fail on some systems. Solution: Use 98% of the lower limit. (Christian Brabandt) https://github.com/vim/vim/commit/3a731ee0c2dd34792c1b21fc4c699a84129f1b86 --- test/functional/legacy/memory_usage_spec.lua | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/test/functional/legacy/memory_usage_spec.lua b/test/functional/legacy/memory_usage_spec.lua index b52742eaac..d665c6c35c 100644 --- a/test/functional/legacy/memory_usage_spec.lua +++ b/test/functional/legacy/memory_usage_spec.lua @@ -101,11 +101,13 @@ describe('memory usage', function() ]]) local after = monitor_memory_usage(pid) -- Estimate the limit of max usage as 2x initial usage. - check_result({before=before, after=after}, pcall(ok, before.last < after.max)) - check_result({before=before, after=after}, pcall(ok, before.last * 2 > after.max)) + -- The lower limit can fluctuate a bit, use 98%. + check_result({before=before, after=after}, + pcall(ok, before.last * 98 / 100 < after.max)) + check_result({before=before, after=after}, + pcall(ok, before.last * 2 > after.max)) -- In this case, garbage collecting is not needed. - -- The value might fluctuate - -- a bit, allow for 3% tolerance. + -- The value might fluctuate a bit, allow for 3% tolerance. local lower = after.last * 97 / 100 local upper = after.last * 103 / 100 check_result({before=before, after=after}, pcall(ok, lower < after.max)) -- cgit From 7ac46b5d37ae04d30031a217dafed5f6f8c733ac Mon Sep 17 00:00:00 2001 From: erw7 Date: Fri, 6 Sep 2019 00:37:03 +0900 Subject: vim-patch:8.1.1435: memory usage test is a bit too flaky Problem: Memory usage test is a bit too flaky. Solution: Adjust the tolerances a bit. (Christian Brabandt) https://github.com/vim/vim/commit/5d508dd39e810d446f29dfd4f4e745b802875001 --- test/functional/legacy/memory_usage_spec.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/test/functional/legacy/memory_usage_spec.lua b/test/functional/legacy/memory_usage_spec.lua index d665c6c35c..28ca749749 100644 --- a/test/functional/legacy/memory_usage_spec.lua +++ b/test/functional/legacy/memory_usage_spec.lua @@ -101,15 +101,16 @@ describe('memory usage', function() ]]) local after = monitor_memory_usage(pid) -- Estimate the limit of max usage as 2x initial usage. - -- The lower limit can fluctuate a bit, use 98%. + -- The lower limit can fluctuate a bit, use 97%. check_result({before=before, after=after}, - pcall(ok, before.last * 98 / 100 < after.max)) + pcall(ok, before.last * 97 / 100 < after.max)) check_result({before=before, after=after}, pcall(ok, before.last * 2 > after.max)) -- In this case, garbage collecting is not needed. - -- The value might fluctuate a bit, allow for 3% tolerance. + -- The value might fluctuate a bit, allow for 3% tolerance below and 5% above. + -- Based on various test runs. local lower = after.last * 97 / 100 - local upper = after.last * 103 / 100 + local upper = after.last * 105 / 100 check_result({before=before, after=after}, pcall(ok, lower < after.max)) check_result({before=before, after=after}, pcall(ok, after.max < upper)) end) -- cgit From 1407899c32018f1988936adfddc1dede73c559cb Mon Sep 17 00:00:00 2001 From: TJ DeVries Date: Thu, 7 May 2020 15:22:24 -0400 Subject: lua: Add buffer, window and tab accessors (#12268) * Add buffer, window and tab accessors * Fix deletion and add tests --- test/functional/lua/vim_spec.lua | 86 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) (limited to 'test') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index ca74d185cd..79d523b5c6 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -769,10 +769,96 @@ describe('lua stdlib', function() exec_lua [[ vim.api.nvim_set_var("testing", "hi") vim.api.nvim_set_var("other", 123) + vim.api.nvim_set_var("to_delete", {hello="world"}) ]] + eq('hi', funcs.luaeval "vim.g.testing") eq(123, funcs.luaeval "vim.g.other") eq(NIL, funcs.luaeval "vim.g.nonexistant") + + eq({hello="world"}, funcs.luaeval "vim.g.to_delete") + exec_lua [[ + vim.g.to_delete = nil + ]] + eq(NIL, funcs.luaeval "vim.g.to_delete") + end) + + it('vim.b', function() + exec_lua [[ + vim.api.nvim_buf_set_var(0, "testing", "hi") + vim.api.nvim_buf_set_var(0, "other", 123) + vim.api.nvim_buf_set_var(0, "to_delete", {hello="world"}) + ]] + + eq('hi', funcs.luaeval "vim.b.testing") + eq(123, funcs.luaeval "vim.b.other") + eq(NIL, funcs.luaeval "vim.b.nonexistant") + + eq({hello="world"}, funcs.luaeval "vim.b.to_delete") + exec_lua [[ + vim.b.to_delete = nil + ]] + eq(NIL, funcs.luaeval "vim.b.to_delete") + + exec_lua [[ + vim.cmd "vnew" + ]] + + eq(NIL, funcs.luaeval "vim.b.testing") + eq(NIL, funcs.luaeval "vim.b.other") + eq(NIL, funcs.luaeval "vim.b.nonexistant") + end) + + it('vim.w', function() + exec_lua [[ + vim.api.nvim_win_set_var(0, "testing", "hi") + vim.api.nvim_win_set_var(0, "other", 123) + vim.api.nvim_win_set_var(0, "to_delete", {hello="world"}) + ]] + + eq('hi', funcs.luaeval "vim.w.testing") + eq(123, funcs.luaeval "vim.w.other") + eq(NIL, funcs.luaeval "vim.w.nonexistant") + + eq({hello="world"}, funcs.luaeval "vim.w.to_delete") + exec_lua [[ + vim.w.to_delete = nil + ]] + eq(NIL, funcs.luaeval "vim.w.to_delete") + + exec_lua [[ + vim.cmd "vnew" + ]] + + eq(NIL, funcs.luaeval "vim.w.testing") + eq(NIL, funcs.luaeval "vim.w.other") + eq(NIL, funcs.luaeval "vim.w.nonexistant") + end) + + it('vim.t', function() + exec_lua [[ + vim.api.nvim_tabpage_set_var(0, "testing", "hi") + vim.api.nvim_tabpage_set_var(0, "other", 123) + vim.api.nvim_tabpage_set_var(0, "to_delete", {hello="world"}) + ]] + + eq('hi', funcs.luaeval "vim.t.testing") + eq(123, funcs.luaeval "vim.t.other") + eq(NIL, funcs.luaeval "vim.t.nonexistant") + + eq({hello="world"}, funcs.luaeval "vim.t.to_delete") + exec_lua [[ + vim.t.to_delete = nil + ]] + eq(NIL, funcs.luaeval "vim.t.to_delete") + + exec_lua [[ + vim.cmd "tabnew" + ]] + + eq(NIL, funcs.luaeval "vim.t.testing") + eq(NIL, funcs.luaeval "vim.t.other") + eq(NIL, funcs.luaeval "vim.t.nonexistant") end) it('vim.env', function() -- cgit From 9a67b030d9a054648296b45b615684dee768582d Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Fri, 8 May 2020 05:23:25 +0900 Subject: lsp: Handle unknown CompletionItemKind and SymbolKind (#12257) * lsp: handle kinds not specified in protocol fix: #12200 If the client set "symbolKind.valueSet", the client must handle it properly even if it receives a value outside the specification. * test: add lsp.util.{get_completion_item_kind_name, get_symbol_kind_name} test case * lsp: make lsp.util.{get_completion_item_kind_name, get_symbol_kind_name} private --- test/functional/plugin/lsp_spec.lua | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 79f6ef9dd2..372c6ef451 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -934,12 +934,12 @@ describe('LSP', function() } local completion_list_items = {items=completion_list} local expected = { - { abbr = 'foobar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label = 'foobar' } } } } }, - { abbr = 'foobar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foobar', textEdit={} } } } } }, - { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foobar' } } } } }, - { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foobar', textEdit={} } } } } }, - { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foodar', textEdit={newText='foobar'} } } } } }, - { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', textEdit={newText='foobar'} } } } } }, + { abbr = 'foobar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label = 'foobar' } } } } }, + { abbr = 'foobar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foobar', textEdit={} } } } } }, + { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foobar' } } } } }, + { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foobar', textEdit={} } } } } }, + { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foodar', textEdit={newText='foobar'} } } } } }, + { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', textEdit={newText='foobar'} } } } } }, } eq(expected, exec_lua([[return vim.lsp.util.text_document_completion_list_to_complete_items(...)]], completion_list, prefix)) @@ -1239,4 +1239,28 @@ describe('LSP', function() ]]) end) end) + + describe('lsp.util._get_completion_item_kind_name', function() + describe('returns the name specified by protocol', function() + eq("Text", exec_lua("return vim.lsp.util._get_completion_item_kind_name(1)")) + eq("TypeParameter", exec_lua("return vim.lsp.util._get_completion_item_kind_name(25)")) + end) + describe('returns the name not specified by protocol', function() + eq("Unknown", exec_lua("return vim.lsp.util._get_completion_item_kind_name(nil)")) + eq("Unknown", exec_lua("return vim.lsp.util._get_completion_item_kind_name(vim.NIL)")) + eq("Unknown", exec_lua("return vim.lsp.util._get_completion_item_kind_name(1000)")) + end) + end) + + describe('lsp.util._get_symbol_kind_name', function() + describe('returns the name specified by protocol', function() + eq("File", exec_lua("return vim.lsp.util._get_symbol_kind_name(1)")) + eq("TypeParameter", exec_lua("return vim.lsp.util._get_symbol_kind_name(26)")) + end) + describe('returns the name not specified by protocol', function() + eq("Unknown", exec_lua("return vim.lsp.util._get_symbol_kind_name(nil)")) + eq("Unknown", exec_lua("return vim.lsp.util._get_symbol_kind_name(vim.NIL)")) + eq("Unknown", exec_lua("return vim.lsp.util._get_symbol_kind_name(1000)")) + end) + end) end) -- cgit From 281e44f7bb24866d4a580d32aaeab8c8033f1fb0 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Fri, 8 May 2020 16:04:41 +0200 Subject: lsp: Make apply_text_edits non-ASCII safe (#12223) * Make apply_text_edits non-ASCII safe Use `vim.str_byteindex` to correct starting and ending positions for text edits if the line contains non-ASCII characters. Fixes #12221 * text_edit may be applied to other buffers * make sure the buffer is loaded * add comments * add test for non-ASCII edits --- test/functional/plugin/lsp_spec.lua | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 372c6ef451..a263c6527d 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -779,7 +779,7 @@ describe('LSP', function() Fourth line of text å å ɧ 汉语 ↥ 🤦 🦄]])) end) - it('applies apply simple edits', function() + it('applies simple edits', function() local edits = { make_edit(0, 0, 0, 0, {"123"}); make_edit(1, 0, 1, 1, {"2"}); @@ -818,10 +818,9 @@ describe('LSP', function() 'å å ɧ 汉语 ↥ 🤦 🦄'; }, buf_lines(1)) end) - pending('applies non-ASCII characters edits', function() - -- FIXME: We don't handle non-ASCII characters well in UTF-16 + it('applies non-ASCII characters edits', function() local edits = { - make_edit(4, 0, 4, 14, {"a a h"}); + make_edit(4, 3, 4, 4, {"ä"}); } exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) eq({ @@ -829,7 +828,7 @@ describe('LSP', function() 'Second line of text'; 'Third line of text'; 'Fourth line of text'; - 'a a h'; + 'å ä ɧ 汉语 ↥ 🤦 🦄'; }, buf_lines(1)) end) end) -- cgit From 7872877ce537389df6fb461bfda23c823acca5fe Mon Sep 17 00:00:00 2001 From: erw7 Date: Sat, 9 May 2020 11:57:59 +0900 Subject: test: add more profile tests - Add a test to make sure that 'profile dump' does not reset the profile. - Add a test to make sure that 'profile stop' does reset the profile. --- test/functional/ex_cmds/profile_spec.lua | 76 ++++++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 13 deletions(-) (limited to 'test') diff --git a/test/functional/ex_cmds/profile_spec.lua b/test/functional/ex_cmds/profile_spec.lua index f185db192a..2b92f8d0de 100644 --- a/test/functional/ex_cmds/profile_spec.lua +++ b/test/functional/ex_cmds/profile_spec.lua @@ -6,6 +6,9 @@ local eval = helpers.eval local command = helpers.command local eq, neq = helpers.eq, helpers.neq local tempfile = helpers.tmpname() +local source = helpers.source +local matches = helpers.matches +local read_file = helpers.read_file -- tmpname() also creates the file on POSIX systems. Remove it again. -- We just need the name, ignoring any race conditions. @@ -32,20 +35,67 @@ describe(':profile', function() end end) - it('dump', function() - eq(0, eval('v:profiling')) - command('profile start ' .. tempfile) - eq(1, eval('v:profiling')) - assert_file_exists_not(tempfile) - command('profile dump') - assert_file_exists(tempfile) + describe('dump', function() + it('works', function() + eq(0, eval('v:profiling')) + command('profile start ' .. tempfile) + eq(1, eval('v:profiling')) + assert_file_exists_not(tempfile) + command('profile dump') + assert_file_exists(tempfile) + end) + + it('not resetting the profile', function() + source([[ + function! Test() + endfunction + ]]) + command('profile start ' .. tempfile) + assert_file_exists_not(tempfile) + command('profile func Test') + command('call Test()') + command('profile dump') + assert_file_exists(tempfile) + local profile = read_file(tempfile) + matches('Called 1 time', profile) + command('call Test()') + command('profile dump') + assert_file_exists(tempfile) + profile = read_file(tempfile) + matches('Called 2 time', profile) + command('profile stop') + end) end) - it('stop', function() - command('profile start ' .. tempfile) - assert_file_exists_not(tempfile) - command('profile stop') - assert_file_exists(tempfile) - eq(0, eval('v:profiling')) + describe('stop', function() + it('works', function() + command('profile start ' .. tempfile) + assert_file_exists_not(tempfile) + command('profile stop') + assert_file_exists(tempfile) + eq(0, eval('v:profiling')) + end) + + it('resetting the profile', function() + source([[ + function! Test() + endfunction + ]]) + command('profile start ' .. tempfile) + assert_file_exists_not(tempfile) + command('profile func Test') + command('call Test()') + command('profile stop') + assert_file_exists(tempfile) + local profile = read_file(tempfile) + matches('Called 1 time', profile) + command('profile start ' .. tempfile) + command('profile func Test') + command('call Test()') + command('profile stop') + assert_file_exists(tempfile) + profile = read_file(tempfile) + matches('Called 1 time', profile) + end) end) end) -- cgit From 55b62a937c27715f7e6c299ae312c38edf08fa74 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Mon, 11 May 2020 16:56:35 +0200 Subject: LSP: Make applyEdit return a response (#12270) According to the specification workspace/applyEdit needs to respond with a `ApplyWorkspaceEditResponse` See https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit This is a subset of https://github.com/neovim/neovim/pull/11607 --- test/functional/plugin/lsp_spec.lua | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index a263c6527d..e48d50ff47 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -913,7 +913,21 @@ describe('LSP', function() }, buf_lines(target_bufnr)) end) end) - + describe('workspace_apply_edit', function() + it('workspace/applyEdit returns ApplyWorkspaceEditResponse', function() + local expected = { + applied = true; + failureReason = nil; + } + eq(expected, exec_lua [[ + local apply_edit = { + label = nil; + edit = {}; + } + return vim.lsp.callbacks['workspace/applyEdit'](nil, nil, apply_edit) + ]]) + end) + end) describe('completion_list_to_complete_items', function() -- Completion option precedence: -- textEdit.newText > insertText > label -- cgit From 02155f5c102539d5052912956606a452a78ad78c Mon Sep 17 00:00:00 2001 From: landerlo Date: Thu, 14 May 2020 04:14:52 +0100 Subject: lsp: fix bug when documentEdit version=null for unattached buffer (#12272) --- test/functional/plugin/lsp_spec.lua | 94 +++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 52 deletions(-) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index e48d50ff47..62dee7df90 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -835,33 +835,30 @@ describe('LSP', function() describe('apply_text_document_edit', function() local target_bufnr + local text_document_edit = function(editVersion) + return { + edits = { + make_edit(0, 0, 0, 3, "First ↥ 🤦 🦄") + }, + textDocument = { + uri = "file://fake/uri"; + version = editVersion + } + } + end before_each(function() target_bufnr = exec_lua [[ - local bufnr = vim.fn.bufadd("fake/uri") - local lines = {"1st line of text", "2nd line of text"} + local bufnr = vim.uri_to_bufnr("file://fake/uri") + local lines = {"1st line of text", "2nd line of 语text"} vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) return bufnr ]] end) it('correctly goes ahead with the edit if all is normal', function() - local text_document_edit = { - edits = { - make_edit(0, 0, 0, 3, "First") - }, - textDocument = { - uri = "file://fake/uri"; - version = 5 - } - } - exec_lua([[ - local args = {...} - local target_bufnr = args[2] - vim.lsp.util.buf_versions[target_bufnr] = 4 - vim.lsp.util.apply_text_document_edit(...) - ]], text_document_edit, target_bufnr) + exec_lua('vim.lsp.util.apply_text_document_edit(...)', text_document_edit(5)) eq({ - 'First line of text'; - '2nd line of text'; + 'First ↥ 🤦 🦄 line of text'; + '2nd line of 语text'; }, buf_lines(target_bufnr)) end) it('correctly goes ahead with the edit if the version is vim.NIL', function() @@ -871,45 +868,38 @@ describe('LSP', function() ]] eq(json.b, exec_lua("return vim.NIL")) - local text_document_edit = { - edits = { - make_edit(0, 0, 0, 3, "First") - }, - textDocument = { - uri = "file://fake/uri"; - version = exec_lua("return vim.NIL") - } - } - exec_lua([[ - local args = {...} - local target_bufnr = args[2] - vim.lsp.util.buf_versions[target_bufnr] = vim.NIL - vim.lsp.util.apply_text_document_edit(...) - ]], text_document_edit, target_bufnr) + exec_lua('vim.lsp.util.apply_text_document_edit(...)', text_document_edit(exec_lua("return vim.NIL"))) eq({ - 'First line of text'; - '2nd line of text'; + 'First ↥ 🤦 🦄 line of text'; + '2nd line of 语text'; }, buf_lines(target_bufnr)) end) it('skips the edit if the version of the edit is behind the local buffer ', function() - local text_document_edit = { - edits = { - make_edit(0, 0, 0, 3, "First") - }, - textDocument = { - uri = "file://fake/uri"; - version = 1 - } + local apply_edit_mocking_current_version = function(edit, versionedBuf) + exec_lua([[ + local args = {...} + local versionedBuf = args[2] + vim.lsp.util.buf_versions[versionedBuf.bufnr] = versionedBuf.currentVersion + vim.lsp.util.apply_text_document_edit(...) + ]], edit, versionedBuf) + end + + local baseText = { + '1st line of text'; + '2nd line of 语text'; } - exec_lua([[ - local args = {...} - local target_bufnr = args[2] - vim.lsp.util.buf_versions[target_bufnr] = 2 - vim.lsp.util.apply_text_document_edit(...) - ]], text_document_edit, target_bufnr) + + eq(baseText, buf_lines(target_bufnr)) + + -- Apply an edit for an old version, should skip + apply_edit_mocking_current_version(text_document_edit(2), {currentVersion=7; bufnr=target_bufnr}) + eq(baseText, buf_lines(target_bufnr)) -- no change + + -- Sanity check that next version to current does apply change + apply_edit_mocking_current_version(text_document_edit(8), {currentVersion=7; bufnr=target_bufnr}) eq({ - '1st line of text'; - '2nd line of text'; + 'First ↥ 🤦 🦄 line of text'; + '2nd line of 语text'; }, buf_lines(target_bufnr)) end) end) -- cgit From ae5bd0454ee4ed3bdbf22e953a216449ca34dd46 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Mon, 18 May 2020 02:24:34 +0900 Subject: lua: add tbl_deep_extend (#11969) --- test/functional/lua/vim_spec.lua | 99 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) (limited to 'test') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 79d523b5c6..46ae56955b 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -478,6 +478,17 @@ describe('lua stdlib', function() return vim.tbl_islist(c) and vim.tbl_count(c) == 0 ]])) + ok(exec_lua([[ + local a = {x = {a = 1, b = 2}} + local b = {x = {a = 2, c = {y = 3}}} + local c = vim.tbl_extend("keep", a, b) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return c.x.a == 1 and c.x.b == 2 and c.x.c == nil and count == 1 + ]])) + eq('Error executing lua: .../shared.lua: invalid "behavior": nil', pcall_err(exec_lua, [[ return vim.tbl_extend() @@ -497,6 +508,94 @@ describe('lua stdlib', function() ) end) + it('vim.tbl_deep_extend', function() + ok(exec_lua([[ + local a = {x = {a = 1, b = 2}} + local b = {x = {a = 2, c = {y = 3}}} + local c = vim.tbl_deep_extend("keep", a, b) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return c.x.a == 1 and c.x.b == 2 and c.x.c.y == 3 and count == 1 + ]])) + + ok(exec_lua([[ + local a = {x = {a = 1, b = 2}} + local b = {x = {a = 2, c = {y = 3}}} + local c = vim.tbl_deep_extend("force", a, b) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return c.x.a == 2 and c.x.b == 2 and c.x.c.y == 3 and count == 1 + ]])) + + ok(exec_lua([[ + local a = {x = {a = 1, b = 2}} + local b = {x = {a = 2, c = {y = 3}}} + local c = {x = {c = 4, d = {y = 4}}} + local d = vim.tbl_deep_extend("keep", a, b, c) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return d.x.a == 1 and d.x.b == 2 and d.x.c.y == 3 and d.x.d.y == 4 and count == 1 + ]])) + + ok(exec_lua([[ + local a = {x = {a = 1, b = 2}} + local b = {x = {a = 2, c = {y = 3}}} + local c = {x = {c = 4, d = {y = 4}}} + local d = vim.tbl_deep_extend("force", a, b, c) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return d.x.a == 2 and d.x.b == 2 and d.x.c == 4 and d.x.d.y == 4 and count == 1 + ]])) + + ok(exec_lua([[ + local a = vim.empty_dict() + local b = {} + local c = vim.tbl_deep_extend("keep", a, b) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return not vim.tbl_islist(c) and count == 0 + ]])) + + ok(exec_lua([[ + local a = {} + local b = vim.empty_dict() + local c = vim.tbl_deep_extend("keep", a, b) + + local count = 0 + for _ in pairs(c) do count = count + 1 end + + return vim.tbl_islist(c) and count == 0 + ]])) + + eq('Error executing lua: .../shared.lua: invalid "behavior": nil', + pcall_err(exec_lua, [[ + return vim.tbl_deep_extend() + ]]) + ) + + eq('Error executing lua: .../shared.lua: wrong number of arguments (given 1, expected at least 3)', + pcall_err(exec_lua, [[ + return vim.tbl_deep_extend("keep") + ]]) + ) + + eq('Error executing lua: .../shared.lua: wrong number of arguments (given 2, expected at least 3)', + pcall_err(exec_lua, [[ + return vim.tbl_deep_extend("keep", {}) + ]]) + ) + end) + it('vim.tbl_count', function() eq(0, exec_lua [[ return vim.tbl_count({}) ]]) eq(0, exec_lua [[ return vim.tbl_count(vim.empty_dict()) ]]) -- cgit From 4fbbe1c957509393563be9492d03b9e95bb08e6a Mon Sep 17 00:00:00 2001 From: Andreas Johansson Date: Sun, 17 May 2020 19:47:14 +0200 Subject: lsp: Handle end lines in apply_text_edits (#12314) If the LSP sends an end line that is larger than what nvim considers to be the last line, you get an Index out of bounds error when fetching the line from nvim, a change that was introduced in #12223. This change removes the strict indexing and checks the return value from nvim_buf_get_lines. --- test/functional/plugin/lsp_spec.lua | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 62dee7df90..f41a5323a8 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -831,6 +831,30 @@ describe('LSP', function() 'å ä ɧ 汉语 ↥ 🤦 🦄'; }, buf_lines(1)) end) + + describe('with LSP end line after what Vim considers to be the end line', function() + it('applies edits when the last linebreak is considered a new line', function() + local edits = { + make_edit(0, 0, 5, 0, {"All replaced"}); + } + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + eq({'All replaced'}, buf_lines(1)) + end) + it('applies edits when the end line is 2 larger than vim\'s', function() + local edits = { + make_edit(0, 0, 6, 0, {"All replaced"}); + } + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + eq({'All replaced'}, buf_lines(1)) + end) + it('applies edits with a column offset', function() + local edits = { + make_edit(0, 0, 5, 2, {"All replaced"}); + } + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) + eq({'All replaced'}, buf_lines(1)) + end) + end) end) describe('apply_text_document_edit', function() -- cgit From f2894bffb024b712e69158d7914e9d9d3d495f72 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Mon, 18 May 2020 15:49:50 +0200 Subject: lua: Add highlight.on_yank (#12279) * add lua function to highlight yanked region * extract namespace, better naming, default values * add default for event argument * free timer * factor out mark to position calculation * d'oh * make sure timer stops before callback (cf. luv example) * factor out timer, more documentation * fixup * validate function argument for schedule * fix block selection past eol * correct handling of multibyte characters * move arguments around, some cleanup * move utility functions to vim.lua * use anonymous namespaces, avoid local api * rename function * add test for schedule_fn * fix indent * turn hl-yank into proper (hightlight) module * factor out position-to-region function mark extraction now part of highlight.on_yank * rename schedule_fn to defer_fn * add test for vim.region * todo: handle double-width characters * remove debug printout * do not shadow arguments * defer also callable table * whitespace change * move highlight to vim/highlight.lua * add documentation * add @return documentation * test: add check before vim.defer fires * doc: fixup --- test/functional/lua/vim_spec.lua | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 46ae56955b..2ea51e7b0b 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1046,4 +1046,24 @@ describe('lua stdlib', function() eq({}, exec_lua[[return {re1:match_line(0, 1, 1, 7)}]]) eq({0,3}, exec_lua[[return {re1:match_line(0, 1, 0, 7)}]]) end) -end) + + it('vim.defer_fn', function() + exec_lua [[ + vim.g.test = 0 + vim.defer_fn(function() vim.g.test = 1 end, 10) + ]] + eq(0, exec_lua[[return vim.g.test]]) + exec_lua [[vim.cmd("sleep 10m")]] + eq(1, exec_lua[[return vim.g.test]]) + end) + + it('vim.region', function() + helpers.insert(helpers.dedent( [[ + text tααt tααt text + text tαxt txtα tex + text tαxt tαxt + ]])) + eq({5,15}, exec_lua[[ return vim.region(0,{1,5},{1,14},'v',true)[1] ]]) + end) + + end) -- cgit From eabf1803cd9432ff85f9b8310e8d6262eff93ec9 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Tue, 19 May 2020 00:02:14 +0900 Subject: test: fix flaky vim.defer_fn test --- test/functional/lua/vim_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 2ea51e7b0b..c68c05dffa 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1050,10 +1050,10 @@ describe('lua stdlib', function() it('vim.defer_fn', function() exec_lua [[ vim.g.test = 0 - vim.defer_fn(function() vim.g.test = 1 end, 10) + vim.defer_fn(function() vim.g.test = 1 end, 50) ]] eq(0, exec_lua[[return vim.g.test]]) - exec_lua [[vim.cmd("sleep 10m")]] + exec_lua [[vim.cmd("sleep 1000m")]] eq(1, exec_lua[[return vim.g.test]]) end) -- cgit From 67eb3bfbc38b8d46dfb458698f1dc5f952229d4a Mon Sep 17 00:00:00 2001 From: Andreas Johansson Date: Tue, 19 May 2020 08:51:10 +0200 Subject: Add tests for jump_to_location --- test/functional/plugin/lsp_spec.lua | 61 +++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index f41a5323a8..5fe44d1bf2 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -1290,4 +1290,65 @@ describe('LSP', function() eq("Unknown", exec_lua("return vim.lsp.util._get_symbol_kind_name(1000)")) end) end) + + describe('lsp.util.jump_to_location', function() + local target_bufnr + + before_each(function() + target_bufnr = exec_lua [[ + local bufnr = vim.uri_to_bufnr("file://fake/uri") + local lines = {"1st line of text", "å å ɧ 汉语 ↥ 🤦 🦄"} + vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) + return bufnr + ]] + end) + + local location = function(start_line, start_char, end_line, end_char) + return { + uri = "file://fake/uri", + range = { + start = { line = start_line, character = start_char }, + ["end"] = { line = end_line, character = end_char }, + }, + } + end + + local jump = function(msg) + eq(true, exec_lua('return vim.lsp.util.jump_to_location(...)', msg)) + eq(target_bufnr, exec_lua[[return vim.fn.bufnr('%')]]) + return { + line = exec_lua[[return vim.fn.line('.')]], + col = exec_lua[[return vim.fn.col('.')]], + } + end + + it('jumps to a Location', function() + local pos = jump(location(0, 9, 0, 9)) + eq(1, pos.line) + eq(10, pos.col) + end) + + it('jumps to a LocationLink', function() + local pos = jump({ + targetUri = "file://fake/uri", + targetSelectionRange = { + start = { line = 0, character = 4 }, + ["end"] = { line = 0, character = 4 }, + }, + targetRange = { + start = { line = 1, character = 5 }, + ["end"] = { line = 1, character = 5 }, + }, + }) + eq(1, pos.line) + eq(5, pos.col) + end) + + it('jumps to the correct multibyte column', function() + local pos = jump(location(1, 2, 1, 2)) + eq(2, pos.line) + eq(4, pos.col) + eq('å', exec_lua[[return vim.fn.expand('')]]) + end) + end) end) -- cgit From c6dc397801d0566b583d4916220a60f17e609e25 Mon Sep 17 00:00:00 2001 From: Kei Kamikawa Date: Wed, 20 May 2020 23:32:02 +0900 Subject: fixed hang issue with --headless and -r option specified (#12209) * fixed hang issue with --headless and -r option specified Calling the do_more_prompt function in headless mode will freeze neovim because it is eventally in the input-accepting state (the same as waiting for --more--). * fixed "Press ENTER or type command to continue" to be suppressed If in headless mode, we need to exit at this point. If we continue, we will enter the normal mode and the message "Press ENTER or type command to continue" will be displayed and we will be in the input waiting state. * fixed functional ex_cmds tests * Revert "fixed "Press ENTER or type command to continue" to be suppressed" This reverts commit a02dc40e3b3fad69cedcde6abe1bd4efe39ab102. * Revert "fixed functional ex_cmds tests" This reverts commit 3bdb8da20acf34673b2c2028d15e7ce6da4c792a. * fixed conditional again * added test for fixed hang issue with --headless (#11386) --- test/functional/core/startup_spec.lua | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'test') diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua index cc10d36a10..96822803bf 100644 --- a/test/functional/core/startup_spec.lua +++ b/test/functional/core/startup_spec.lua @@ -277,6 +277,24 @@ describe('startup', function() [4] = {bold = true, foreground = Screen.colors.Blue1}, }}) end) + + it('fixed hang issue with --headless (#11386)', function() + local expected = '' + local period = 100 + for i = 1, period - 1 do + expected = expected .. i .. '\r\n' + end + expected = expected .. period + eq( + expected, + -- FIXME(codehex): We should really set a timeout for the system function. + -- If this test fails, there will be a waiting input state. + funcs.system({nvim_prog, '-u', 'NONE', '-c', + 'for i in range(1, 100) | echo i | endfor | quit', + '--headless' + }) + ) + end) end) describe('sysinit', function() -- cgit From 04a0486c66e2ae6d67cad990f95283863dbe28fd Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Thu, 21 May 2020 18:17:21 +0200 Subject: Change uri_to_fname to not convert non-file URIs (#12351) * Change uri_to_fname to not convert non-file URIs A URI with a scheme other than file doesn't have a local file path. * fixup! Change uri_to_fname to not convert non-file URIs * fixup! fixup! Change uri_to_fname to not convert non-file URIs --- test/functional/lua/uri_spec.lua | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'test') diff --git a/test/functional/lua/uri_spec.lua b/test/functional/lua/uri_spec.lua index a3b8e685e1..f782769935 100644 --- a/test/functional/lua/uri_spec.lua +++ b/test/functional/lua/uri_spec.lua @@ -112,6 +112,29 @@ describe('URI methods', function() eq('C:\\xy\\åäö\\ɧ\\汉语\\↥\\🤦\\🦄\\å\\بِيَّ.txt', exec_lua(test_case)) end) end) + + describe('decode non-file URI', function() + it('uri_to_fname returns non-file URI unchanged', function() + eq('jdt1.23+x-z://content/%5C/', exec_lua [[ + return vim.uri_to_fname('jdt1.23+x-z://content/%5C/') + ]]) + end) + + it('uri_to_fname returns non-file upper-case scheme URI unchanged', function() + eq('JDT://content/%5C/', exec_lua [[ + return vim.uri_to_fname('JDT://content/%5C/') + ]]) + end) + end) + + describe('decode URI without scheme', function() + it('fails because URI must have a scheme', function() + eq(false, exec_lua [[ + return pcall(vim.uri_to_fname, 'not_an_uri.txt') + ]]) + end) + end) + end) describe('uri to bufnr', function() -- cgit From e89462d9855eef7718d482df7f92da4279a1c5c3 Mon Sep 17 00:00:00 2001 From: kuuote <36663503+kuuote@users.noreply.github.com> Date: Mon, 25 May 2020 03:45:25 +0900 Subject: vim-patch:8.1.2233: cannot get the Vim command line arguments (#12117) Problem: Cannot get the Vim command line arguments. Solution: Add v:argv. (Dmitri Vereshchagin, closes vim/vim#1322) https://github.com/vim/vim/commit/69bf634858a2a75f2984e42b1e4017bc529a040a --- test/functional/core/startup_spec.lua | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'test') diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua index 96822803bf..3269fbc68d 100644 --- a/test/functional/core/startup_spec.lua +++ b/test/functional/core/startup_spec.lua @@ -295,6 +295,14 @@ describe('startup', function() }) ) end) + + it("get command line arguments from v:argv", function() + local out = funcs.system({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--headless', + '--cmd', nvim_set, + '-c', [[echo v:argv[-1:] len(v:argv) > 1]], + '+q' }) + eq('[\'+q\'] 1', out) + end) end) describe('sysinit', function() -- cgit From e6e6affc0ee675861f3b1f093ae3e6572cd3b4a0 Mon Sep 17 00:00:00 2001 From: erw7 Date: Mon, 25 May 2020 14:57:44 +0900 Subject: nvim_input: add test --- test/functional/api/vim_spec.lua | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'test') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 2e9d0f57ac..bd39413e60 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -482,6 +482,11 @@ describe('API', function() eq(true, status) -- nvim_input() did not fail. eq("E117:", v_errnum) -- v:errmsg was updated. end) + + it('does not crash even if trans_special result is largest #11788, #12287', function() + command("call nvim_input('')") + eq(1, eval('1')) + end) end) describe('nvim_paste', function() -- cgit From 15b762761ad966f91d452fdd28c718f2fd3e45be Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Tue, 26 May 2020 21:55:45 +0900 Subject: lsp: make the command error message more detailed (#11633) * lsp.lua: make the error message more detailed * test: add lsp._cmd_part test --- test/functional/plugin/lsp_spec.lua | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index f41a5323a8..e39511d0ea 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -6,6 +6,7 @@ local buf_lines = helpers.buf_lines local dedent = helpers.dedent local exec_lua = helpers.exec_lua local eq = helpers.eq +local pcall_err = helpers.pcall_err local pesc = helpers.pesc local insert = helpers.insert local retry = helpers.retry @@ -705,7 +706,6 @@ describe('LSP', function() end; } end) - end) describe("parsing tests", function() @@ -733,7 +733,23 @@ describe('LSP', function() end; } end) + end) + describe('lsp._cmd_parts test', function() + local function _cmd_parts(input) + return exec_lua([[ + lsp = require('vim.lsp') + return lsp._cmd_parts(...) + ]], input) + end + it('should valid cmd argument', function() + eq(true, pcall(_cmd_parts, {"nvim"})) + eq(true, pcall(_cmd_parts, {"nvim", "--head"})) + end) + it('should invalid cmd argument', function() + eq('Error executing lua: .../shared.lua: cmd: expected list, got nvim', pcall_err(_cmd_parts, "nvim")) + eq('Error executing lua: .../shared.lua: cmd argument: expected string, got number', pcall_err(_cmd_parts, {"nvim", 1})) + end) end) end) -- cgit From 5a9226c800d3075821203952da7c38626180680d Mon Sep 17 00:00:00 2001 From: Viktor Kojouharov Date: Thu, 28 May 2020 14:31:56 +0200 Subject: lua: simple snippet support in the completion items (#12118) Old behavior is: foo(${placeholder: bar, ...) with lots of random garbage you'd never want inserted. New behavior is: foo(bar, baz) (which maybe is good, maybe is bad [depends on user], but definitely better than it was). ----- * Implement rudimentary snippet parsing Add support for parsing and discarding snippet tokens from the completion items. Fixes #11982 * Enable snippet support * Functional tests for snippet parsing Add simplified real-world snippet text examples to the completion items test * Add a test for nested snippet tokens * Remove TODO comment * Return the unmodified item if the format is plain text * Add a plain text completion item --- test/functional/plugin/lsp_spec.lua | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index e39511d0ea..f1478c782d 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -973,7 +973,14 @@ describe('LSP', function() { label='foocar', insertText='foobar', textEdit={} }, -- resolves into textEdit.newText { label='foocar', insertText='foodar', textEdit={newText='foobar'} }, - { label='foocar', textEdit={newText='foobar'} } + { label='foocar', textEdit={newText='foobar'} }, + -- real-world snippet text + { label='foocar', insertText='foodar', textEdit={newText='foobar(${1:place holder}, ${2:more ...holder{\\}})'} }, + { label='foocar', insertText='foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}', textEdit={} }, + -- nested snippet tokens + { label='foocar', insertText='foodar(${1:var1 ${2|typ2,typ3|} ${3:tail}}) {$0\\}', textEdit={} }, + -- plain text + { label='foocar', insertText='foodar(${1:var1})', insertTextFormat=1, textEdit={} }, } local completion_list_items = {items=completion_list} local expected = { @@ -983,6 +990,10 @@ describe('LSP', function() { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foobar', textEdit={} } } } } }, { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foodar', textEdit={newText='foobar'} } } } } }, { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', textEdit={newText='foobar'} } } } } }, + { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar(place holder, more ...holder{})', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foodar', textEdit={newText='foobar(${1:place holder}, ${2:more ...holder{\\}})'} } } } } }, + { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(var1 typ1, var2 *typ2) {}', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}', textEdit={} } } } } }, + { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(var1 typ2,typ3 tail) {}', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foodar(${1:var1 ${2|typ2,typ3|} ${3:tail}}) {$0\\}', textEdit={} } } } } }, + { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(${1:var1})', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foodar(${1:var1})', insertTextFormat=1, textEdit={} } } } } }, } eq(expected, exec_lua([[return vim.lsp.util.text_document_completion_list_to_complete_items(...)]], completion_list, prefix)) -- cgit From 977c0f292fe155dbf1748d6a0ff020f89cf7a894 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 29 May 2020 18:45:32 +0200 Subject: API: nvim_create_buf: unset 'modeline' in scratch-buffer #12379 Although 'nomodeline' is not strictly part of the definition of a "scratch-buffer" it is obviously the right default. --- test/functional/api/vim_spec.lua | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 2e9d0f57ac..debdfb9e9a 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1808,7 +1808,7 @@ describe('API', function() eq({id=1}, meths.get_current_buf()) end) - it("doesn't cause BufEnter or BufWinEnter autocmds", function() + it("does not trigger BufEnter, BufWinEnter", function() command("let g:fired = v:false") command("au BufEnter,BufWinEnter * let g:fired = v:true") @@ -1818,7 +1818,7 @@ describe('API', function() eq(false, eval('g:fired')) end) - it('|scratch-buffer|', function() + it('scratch-buffer', function() eq({id=2}, meths.create_buf(false, true)) eq({id=3}, meths.create_buf(true, true)) eq({id=4}, meths.create_buf(true, true)) @@ -1845,6 +1845,7 @@ describe('API', function() eq('nofile', meths.buf_get_option(b, 'buftype')) eq('hide', meths.buf_get_option(b, 'bufhidden')) eq(false, meths.buf_get_option(b, 'swapfile')) + eq(false, meths.buf_get_option(b, 'modeline')) end -- @@ -1860,8 +1861,9 @@ describe('API', function() eq('nofile', meths.buf_get_option(edited_buf, 'buftype')) eq('hide', meths.buf_get_option(edited_buf, 'bufhidden')) eq(false, meths.buf_get_option(edited_buf, 'swapfile')) + eq(false, meths.buf_get_option(edited_buf, 'modeline')) - -- scratch buffer can be wiped without error + -- Scratch buffer can be wiped without error. command('bwipe') screen:expect([[ ^ | -- cgit From be662fe5c7d06ee63377dd7defb72aea88134305 Mon Sep 17 00:00:00 2001 From: TJ DeVries Date: Wed, 20 May 2020 11:08:19 -0400 Subject: lua: vim.wait implementation --- test/functional/lua/vim_spec.lua | 186 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 179 insertions(+), 7 deletions(-) (limited to 'test') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index c68c05dffa..596b960419 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1048,13 +1048,13 @@ describe('lua stdlib', function() end) it('vim.defer_fn', function() - exec_lua [[ - vim.g.test = 0 - vim.defer_fn(function() vim.g.test = 1 end, 50) - ]] - eq(0, exec_lua[[return vim.g.test]]) - exec_lua [[vim.cmd("sleep 1000m")]] - eq(1, exec_lua[[return vim.g.test]]) + eq(false, exec_lua [[ + vim.g.test = false + vim.defer_fn(function() vim.g.test = true end, 150) + return vim.g.test + ]]) + exec_lua [[vim.wait(1000, function() return vim.g.test end)]] + eq(true, exec_lua[[return vim.g.test]]) end) it('vim.region', function() @@ -1066,4 +1066,176 @@ describe('lua stdlib', function() eq({5,15}, exec_lua[[ return vim.region(0,{1,5},{1,14},'v',true)[1] ]]) end) + describe('vim.wait', function() + before_each(function() + exec_lua[[ + -- high precision timer + get_time = function() + return vim.fn.reltimefloat(vim.fn.reltime()) + end + ]] + end) + + it('should run from lua', function() + exec_lua[[vim.wait(100, function() return true end)]] + end) + + it('should wait the expected time if false', function() + eq({time = true, wait_result = {false, -1}}, exec_lua[[ + start_time = get_time() + wait_succeed, wait_fail_val = vim.wait(200, function() return false end) + + return { + -- 150ms waiting or more results in true. Flaky tests are bad. + time = (start_time + 0.15) < get_time(), + wait_result = {wait_succeed, wait_fail_val} + } + ]]) + end) + + + it('should not block other events', function() + eq({time = true, wait_result = true}, exec_lua[[ + start_time = get_time() + + vim.g.timer_result = false + timer = vim.loop.new_timer() + timer:start(100, 0, vim.schedule_wrap(function() + vim.g.timer_result = true + end)) + + -- Would wait ten seconds if results blocked. + wait_result = vim.wait(10000, function() return vim.g.timer_result end) + + return { + time = (start_time + 5) > get_time(), + wait_result = wait_result, + } + ]]) + end) + + it('should work with vim.defer_fn', function() + eq({time = true, wait_result = true}, exec_lua[[ + start_time = get_time() + + vim.defer_fn(function() vim.g.timer_result = true end, 100) + wait_result = vim.wait(10000, function() return vim.g.timer_result end) + + return { + time = (start_time + 5) > get_time(), + wait_result = wait_result, + } + ]]) + end) + + it('should require functions to be passed', function() + local pcall_result = exec_lua [[ + return {pcall(function() vim.wait(1000, 13) end)} + ]] + + eq(pcall_result[1], false) + matches('condition must be a function', pcall_result[2]) + end) + + it('should not crash when callback errors', function() + local pcall_result = exec_lua [[ + return {pcall(function() vim.wait(1000, function() error("As Expected") end) end)} + ]] + + eq(pcall_result[1], false) + matches('As Expected', pcall_result[2]) + end) + + it('should call callbacks exactly once if they return true immediately', function() + eq(true, exec_lua [[ + vim.g.wait_count = 0 + vim.wait(1000, function() + vim.g.wait_count = vim.g.wait_count + 1 + return true + end, 20) + return vim.g.wait_count == 1 + ]]) + end) + + it('should call callbacks few times with large `interval`', function() + eq(true, exec_lua [[ + vim.g.wait_count = 0 + vim.wait(50, function() vim.g.wait_count = vim.g.wait_count + 1 end, 200) + return vim.g.wait_count < 5 + ]]) + end) + + it('should call callbacks more times with small `interval`', function() + eq(true, exec_lua [[ + vim.g.wait_count = 0 + vim.wait(50, function() vim.g.wait_count = vim.g.wait_count + 1 end, 5) + return vim.g.wait_count > 5 + ]]) + end) + + it('should play nice with `not` when fails', function() + eq(true, exec_lua [[ + if not vim.wait(50, function() end) then + return true + end + + return false + ]]) + end) + + it('should play nice with `if` when success', function() + eq(true, exec_lua [[ + if vim.wait(50, function() return true end) then + return true + end + + return false + ]]) + end) + + it('should return immediately with false if timeout is 0', function() + eq({false, -1}, exec_lua [[ + return { + vim.wait(0, function() return false end) + } + ]]) + end) + + it('should work with tables with __call', function() + eq(true, exec_lua [[ + local t = setmetatable({}, {__call = function(...) return true end}) + return vim.wait(100, t, 10) + ]]) + end) + + it('should work with tables with __call that change', function() + eq(true, exec_lua [[ + local t = {count = 0} + setmetatable(t, { + __call = function() + t.count = t.count + 1 + return t.count > 3 + end + }) + + return vim.wait(1000, t, 10) + ]]) + end) + + it('should not work with negative intervals', function() + local pcall_result = exec_lua [[ + return pcall(function() vim.wait(1000, function() return false end, -1) end) + ]] + + eq(false, pcall_result) + end) + + it('should not work with weird intervals', function() + local pcall_result = exec_lua [[ + return pcall(function() vim.wait(1000, function() return false end, 'a string value') end) + ]] + + eq(false, pcall_result) + end) end) +end) -- cgit From 7124c0e5acde38957af7621afd1d92fb2b6d1d58 Mon Sep 17 00:00:00 2001 From: kuuote Date: Sun, 31 May 2020 20:21:58 +0900 Subject: runtime: fix remote plugin command fails at some case fixes #12410 --- test/functional/provider/define_spec.lua | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'test') diff --git a/test/functional/provider/define_spec.lua b/test/functional/provider/define_spec.lua index 51a8831274..c04dcd47b9 100644 --- a/test/functional/provider/define_spec.lua +++ b/test/functional/provider/define_spec.lua @@ -89,6 +89,21 @@ local function command_specs_for(fn, sync, first_arg_factory, init) runx(sync, handler, on_setup) end) + it('with nargs/double-quote', function() + call(fn, args..', {"nargs": "*"}') + local function on_setup() + command('RpcCommand "arg"') + end + + local function handler(method, arguments) + eq('test-handler', method) + eq({'"arg"'}, arguments[1]) + return '' + end + + runx(sync, handler, on_setup) + end) + it('with range', function() call(fn,args..', {"range": ""}') local function on_setup() -- cgit From 89123017b8148569bafb34d03304358cf1411a7f Mon Sep 17 00:00:00 2001 From: kuuote Date: Mon, 1 Jun 2020 00:10:17 +0900 Subject: test: rewrite to multiple arguments --- test/functional/provider/define_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/functional/provider/define_spec.lua b/test/functional/provider/define_spec.lua index c04dcd47b9..1d50ce0a56 100644 --- a/test/functional/provider/define_spec.lua +++ b/test/functional/provider/define_spec.lua @@ -92,12 +92,12 @@ local function command_specs_for(fn, sync, first_arg_factory, init) it('with nargs/double-quote', function() call(fn, args..', {"nargs": "*"}') local function on_setup() - command('RpcCommand "arg"') + command('RpcCommand "arg1" "arg2" "arg3"') end local function handler(method, arguments) eq('test-handler', method) - eq({'"arg"'}, arguments[1]) + eq({'"arg1"', '"arg2"', '"arg3"'}, arguments[1]) return '' end -- cgit From 8349192503450d645bad6a2b30a72c67fd97f7c8 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Fri, 15 May 2020 12:23:26 +0200 Subject: treesitter: update runtime Since tree-sitter PR 615, predicates are not parsed the same. "Old" way of writing predicates is still supported. --- test/functional/lua/treesitter_spec.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index f93185d1f6..cb0e46b9eb 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -240,15 +240,15 @@ static int nlua_schedule(lua_State *const lstate) ; TODO(bfredl): overlapping matches are unreliable, ; we need a proper priority mechanism ;(type_identifier) @type -((type_identifier) @Special (eq? @Special "LuaRef")) +((type_identifier) @Special (#eq? @Special "LuaRef")) (primitive_type) @type (sized_type_specifier) @type ; defaults to very magic syntax, for best compatibility -((identifier) @Identifier (match? @Identifier "^l(u)a_")) +((identifier) @Identifier (#match? @Identifier "^l(u)a_")) ; still support \M etc prefixes -((identifier) @Constant (match? @Constant "\M^\[A-Z_]\+$")) +((identifier) @Constant (#match? @Constant "\M^\[A-Z_]\+$")) ((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right) (eq? @WarningMsg.left @WarningMsg.right)) -- cgit From 60c581b35db439dd6b32cdc2ebe1a5aed933b44c Mon Sep 17 00:00:00 2001 From: notomo Date: Wed, 3 Jun 2020 08:31:43 +0900 Subject: lua: fix infinite loop for vim.split on empty string (#12420) --- test/functional/lua/vim_spec.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'test') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 596b960419..61bc3e1e3c 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -243,6 +243,7 @@ describe('lua stdlib', function() { "here be dragons", " ", false, { "here", "be", "dragons"} }, { "axaby", "ab?", false, { '', 'x', 'y' } }, { "f v2v v3v w2w ", "([vw])2%1", false, { 'f ', ' v3v ', ' ' } }, + { "", "", false, {} }, { "x*yz*oo*l", "*", true, { 'x', 'yz', 'oo', 'l' } }, } -- cgit From 8a1276005a1099187710bdcc19284de51a0aa89a Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Wed, 3 Jun 2020 16:51:25 +0200 Subject: Add v:event.visual during `TextYankPost` (#12382) * propagate visual selection to textyankpost event * adapt tests * add docs * also adapt oldtest --- test/functional/autocmd/textyankpost_spec.lua | 48 ++++++++++++++++++--------- 1 file changed, 32 insertions(+), 16 deletions(-) (limited to 'test') diff --git a/test/functional/autocmd/textyankpost_spec.lua b/test/functional/autocmd/textyankpost_spec.lua index 8c23b72cff..3898d59e58 100644 --- a/test/functional/autocmd/textyankpost_spec.lua +++ b/test/functional/autocmd/textyankpost_spec.lua @@ -27,7 +27,8 @@ describe('TextYankPost', function() operator = 'y', regcontents = { 'foo\nbar' }, regname = '', - regtype = 'V' + regtype = 'V', + visual = false }, eval('g:event')) eq(1, eval('g:count')) @@ -40,7 +41,8 @@ describe('TextYankPost', function() operator = 'y', regcontents = { 'baz ' }, regname = '', - regtype = 'v' + regtype = 'v', + visual = false }, eval('g:event')) eq(2, eval('g:count')) @@ -50,7 +52,8 @@ describe('TextYankPost', function() operator = 'y', regcontents = { 'foo', 'baz' }, regname = '', - regtype = "\0223" -- ^V + block width + regtype = "\0223", -- ^V + block width + visual = true }, eval('g:event')) eq(3, eval('g:count')) end) @@ -62,7 +65,8 @@ describe('TextYankPost', function() operator = 'y', regcontents = { 'foo\nbar' }, regname = '', - regtype = 'V' + regtype = 'V', + visual = false }, eval('g:event')) command('set debug=msg') @@ -92,7 +96,8 @@ describe('TextYankPost', function() operator = 'y', regcontents = { 'foo\nbar' }, regname = '', - regtype = 'V' + regtype = 'V', + visual = false }, eval('g:event')) eq(1, eval('g:count')) eq({ 'foo\nbar' }, funcs.getreg('+',1,1)) @@ -105,7 +110,8 @@ describe('TextYankPost', function() operator = 'd', regcontents = { 'foo' }, regname = '', - regtype = 'v' + regtype = 'v', + visual = false }, eval('g:event')) eq(1, eval('g:count')) @@ -115,7 +121,8 @@ describe('TextYankPost', function() operator = 'd', regcontents = { '\nbar' }, regname = '', - regtype = 'V' + regtype = 'V', + visual = false }, eval('g:event')) eq(2, eval('g:count')) @@ -125,7 +132,8 @@ describe('TextYankPost', function() operator = 'c', regcontents = { 'baz' }, regname = '', - regtype = 'v' + regtype = 'v', + visual = false }, eval('g:event')) eq(3, eval('g:count')) end) @@ -153,7 +161,8 @@ describe('TextYankPost', function() operator = 'y', regcontents = { 'bar' }, regname = 'b', - regtype = 'v' + regtype = 'v', + visual = false }, eval('g:event')) feed('"*yy') @@ -162,7 +171,8 @@ describe('TextYankPost', function() operator = 'y', regcontents = { 'foo\nbar' }, regname = '*', - regtype = 'V' + regtype = 'V', + visual = false }, eval('g:event')) command("set clipboard=unnamed") @@ -174,7 +184,8 @@ describe('TextYankPost', function() operator = 'y', regcontents = { 'foo\nbar' }, regname = '', - regtype = 'V' + regtype = 'V', + visual = false }, eval('g:event')) feed('"*yy') @@ -183,7 +194,8 @@ describe('TextYankPost', function() operator = 'y', regcontents = { 'foo\nbar' }, regname = '*', - regtype = 'V' + regtype = 'V', + visual = false }, eval('g:event')) end) @@ -194,7 +206,8 @@ describe('TextYankPost', function() operator = 'd', regcontents = { 'foo\nbar' }, regname = '+', - regtype = 'V' + regtype = 'V', + visual = false }, eval('g:event')) eq(1, eval('g:count')) @@ -204,7 +217,8 @@ describe('TextYankPost', function() operator = 'y', regcontents = { 'baz text' }, regname = '', - regtype = 'V' + regtype = 'V', + visual = false }, eval('g:event')) eq(2, eval('g:count')) @@ -214,7 +228,8 @@ describe('TextYankPost', function() operator = 'y', regcontents = { 'baz ' }, regname = '', - regtype = 'v' + regtype = 'v', + visual = false }, eval('g:event')) eq(3, eval('g:count')) @@ -224,7 +239,8 @@ describe('TextYankPost', function() operator = 'd', regcontents = { 'baz text' }, regname = '', - regtype = 'V' + regtype = 'V', + visual = false }, eval('g:event')) eq(4, eval('g:count')) end) -- cgit From 6a93077475d298f46ac19c8030ed5b4a723685dc Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Wed, 3 Jun 2020 19:58:02 +0200 Subject: treesitter: fix tests --- test/functional/lua/treesitter_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index cb0e46b9eb..ecee471386 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -250,7 +250,7 @@ static int nlua_schedule(lua_State *const lstate) ; still support \M etc prefixes ((identifier) @Constant (#match? @Constant "\M^\[A-Z_]\+$")) -((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right) (eq? @WarningMsg.left @WarningMsg.right)) +((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right) (#eq? @WarningMsg.left @WarningMsg.right)) (comment) @comment ]] -- cgit From ac5a3f2c56775040a1b7de438cfd592c0dc26400 Mon Sep 17 00:00:00 2001 From: notomo Date: Thu, 4 Jun 2020 21:48:48 +0900 Subject: lua: fix behavior when split empty string (#12429) * lua: fix behavior when split empty string * test: lsp.util.apply_text_edits with an empty edit --- test/functional/lua/vim_spec.lua | 1 + test/functional/plugin/lsp_spec.lua | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 61bc3e1e3c..aa0b3d822b 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -244,6 +244,7 @@ describe('lua stdlib', function() { "axaby", "ab?", false, { '', 'x', 'y' } }, { "f v2v v3v w2w ", "([vw])2%1", false, { 'f ', ' v3v ', ' ' } }, { "", "", false, {} }, + { "", "a", false, { '' } }, { "x*yz*oo*l", "*", true, { 'x', 'yz', 'oo', 'l' } }, } diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index ea0f52c85b..479741d717 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -800,13 +800,14 @@ describe('LSP', function() make_edit(0, 0, 0, 0, {"123"}); make_edit(1, 0, 1, 1, {"2"}); make_edit(2, 0, 2, 2, {"3"}); + make_edit(3, 2, 3, 4, {""}); } exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1) eq({ '123First line of text'; '2econd line of text'; '3ird line of text'; - 'Fourth line of text'; + 'Foth line of text'; 'å å ɧ 汉语 ↥ 🤦 🦄'; }, buf_lines(1)) end) -- cgit From b7f3f11049c6847a2b0c4bbd89e8339036e00da6 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Thu, 4 Jun 2020 20:23:03 +0200 Subject: lsp: compute height of floating preview correctly for wrapped lines (#12380) * take wrapping into account when computing float height * factor out size calculation * add test * accept and pass through opts.wrap_at in floating_preview * make padding configurable * slightly refactor fancy_floating_markdown to make use of make_position * padding using string.format * move trim and pad to separate function * nit Co-authored-by: Hirokazu Hata * remove mention of backward compat * make lint happy Co-authored-by: Hirokazu Hata --- test/functional/plugin/lsp_spec.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'test') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 479741d717..ae436360c3 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -1379,4 +1379,14 @@ describe('LSP', function() eq('å', exec_lua[[return vim.fn.expand('')]]) end) end) + + describe('lsp.util._make_floating_popup_size', function() + exec_lua [[ contents = + {"text tαxt txtα tex", + "text tααt tααt text", + "text tαxt tαxt"} + ]] + eq({19,3}, exec_lua[[ return {vim.lsp.util._make_floating_popup_size(contents)} ]]) + eq({15,5}, exec_lua[[ return {vim.lsp.util._make_floating_popup_size(contents,{width = 15, wrap_at = 14})} ]]) + end) end) -- cgit From 909af2f3f10b49faf5f56ca866d316dbb0a94384 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Wed, 3 Jun 2020 01:36:26 -0400 Subject: vim-patch:8.2.0491: cannot recognize a